diff --git a/src/helper/selection-tools/point-tool.js b/src/helper/selection-tools/point-tool.js index 9a9ddd4b..4cbdfe7c 100644 --- a/src/helper/selection-tools/point-tool.js +++ b/src/helper/selection-tools/point-tool.js @@ -1,6 +1,6 @@ import paper from '@scratch/paper'; import {snapDeltaToAngle} from '../math'; -import {clearSelection, getSelectedLeafItems} from '../selection'; +import {clearSelection, getSelectedLeafItems, getSelectedSegments} from '../selection'; import {HANDLE_RATIO} from '../math'; /** Subtool of ReshapeTool for moving control points. */ @@ -146,39 +146,30 @@ class PointTool { const dragVector = event.point.subtract(event.downPoint); - for (const item of this.selectedItems) { - if (!item.segments) { - return; + const selectedSegments = getSelectedSegments(); + for (const seg of selectedSegments) { + // add the point of the segment before the drag started + // for later use in the snap calculation + if (!seg.origPoint) { + seg.origPoint = seg.point.clone(); } - for (const seg of item.segments) { - // add the point of the segment before the drag started - // for later use in the snap calculation - if (!seg.origPoint) { - seg.origPoint = seg.point.clone(); - } - if (seg.selected) { - if (event.modifiers.shift) { - seg.point = seg.origPoint.add(snapDeltaToAngle(dragVector, Math.PI / 4)); - } else { - seg.point = seg.point.add(event.delta); - } - } + + if (event.modifiers.shift) { + seg.point = seg.origPoint.add(snapDeltaToAngle(dragVector, Math.PI / 4)); + } else { + seg.point = seg.point.add(event.delta); } } } onMouseUp () { // resetting the items and segments origin points for the next usage let moved = false; - for (const item of this.selectedItems) { - if (!item.segments) { - return; - } - for (const seg of item.segments) { - if (seg.origPoint && !seg.equals(seg.origPoint)) { - moved = true; - } - seg.origPoint = null; + const selectedSegments = getSelectedSegments(); + for (const seg of selectedSegments) { + if (seg.origPoint && !seg.equals(seg.origPoint)) { + moved = true; } + seg.origPoint = null; } // If no drag occurred between mouse down and mouse up, then we can go through with deselect diff --git a/src/helper/selection-tools/reshape-tool.js b/src/helper/selection-tools/reshape-tool.js index 7ca0eefc..0ebfb433 100644 --- a/src/helper/selection-tools/reshape-tool.js +++ b/src/helper/selection-tools/reshape-tool.js @@ -5,6 +5,7 @@ import keyMirror from 'keymirror'; import Modes from '../../lib/modes'; import {getHoveredItem} from '../hover'; import {getRootItem, isPGTextItem} from '../item'; +import {getSelectedLeafItems, getSelectedSegments} from '../selection'; import MoveTool from './move-tool'; import PointTool from './point-tool'; import HandleTool from './handle-tool'; @@ -67,6 +68,8 @@ class ReshapeTool extends paper.Tool { this.onMouseMove = this.handleMouseMove; this.onMouseDrag = this.handleMouseDrag; this.onMouseUp = this.handleMouseUp; + this.onKeyUp = this.handleKeyUp; + this.onKeyDown = this.handleKeyDown; paper.settings.handleSize = 8; } @@ -228,6 +231,44 @@ class ReshapeTool extends paper.Tool { this.mode = ReshapeModes.SELECTION_BOX; this.active = false; } + handleKeyDown (event) { + const nudgeAmount = 1 / paper.view.zoom; + const selected = getSelectedLeafItems(); + if (selected.length === 0) return; + + let translation; + if (event.key === 'up') { + translation = new paper.Point(0, -nudgeAmount); + } else if (event.key === 'down') { + translation = new paper.Point(0, nudgeAmount); + } else if (event.key === 'left') { + translation = new paper.Point(-nudgeAmount, 0); + } else if (event.key === 'right') { + translation = new paper.Point(nudgeAmount, 0); + } + + if (translation) { + const segments = getSelectedSegments(); + // If no segments are selected, translate selected paths + if (segments.length === 0) { + for (const item of selected) { + item.translate(translation); + } + } else { // Translate segments + for (const seg of segments) { + seg.point = seg.point.add(translation); + } + } + } + } + handleKeyUp (event) { + const selected = getSelectedLeafItems(); + if (selected.length === 0) return; + + if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') { + this.onUpdateSvg(); + } + } deactivateTool () { paper.settings.handleSize = 0; this.clearHoveredItem(); diff --git a/src/helper/selection-tools/select-tool.js b/src/helper/selection-tools/select-tool.js index 4f71ff0f..e3cb2c29 100644 --- a/src/helper/selection-tools/select-tool.js +++ b/src/helper/selection-tools/select-tool.js @@ -1,7 +1,7 @@ import Modes from '../../lib/modes'; import {getHoveredItem} from '../hover'; -import {selectRootItem} from '../selection'; +import {getSelectedRootItems, selectRootItem} from '../selection'; import BoundingBoxTool from './bounding-box-tool'; import SelectionBoxTool from './selection-box-tool'; import paper from '@scratch/paper'; @@ -42,6 +42,8 @@ class SelectTool extends paper.Tool { this.onMouseMove = this.handleMouseMove; this.onMouseDrag = this.handleMouseDrag; this.onMouseUp = this.handleMouseUp; + this.onKeyUp = this.handleKeyUp; + this.onKeyDown = this.handleKeyDown; selectRootItem(); setSelectedItems(); @@ -131,6 +133,37 @@ class SelectTool extends paper.Tool { this.selectionBoxMode = false; this.active = false; } + handleKeyDown (event) { + const nudgeAmount = 1 / paper.view.zoom; + const selected = getSelectedRootItems(); + if (selected.length === 0) return; + + let translation; + if (event.key === 'up') { + translation = new paper.Point(0, -nudgeAmount); + } else if (event.key === 'down') { + translation = new paper.Point(0, nudgeAmount); + } else if (event.key === 'left') { + translation = new paper.Point(-nudgeAmount, 0); + } else if (event.key === 'right') { + translation = new paper.Point(nudgeAmount, 0); + } + + if (translation) { + for (const item of selected) { + item.translate(translation); + } + } + this.boundingBoxTool.setSelectionBounds(); + } + handleKeyUp (event) { + const selected = getSelectedRootItems(); + if (selected.length === 0) return; + + if (event.key === 'up' || event.key === 'down' || event.key === 'left' || event.key === 'right') { + this.onUpdateSvg(); + } + } deactivateTool () { this.clearHoveredItem(); this.boundingBoxTool.removeBoundsPath(); diff --git a/src/helper/selection.js b/src/helper/selection.js index fb157375..32b067bd 100644 --- a/src/helper/selection.js +++ b/src/helper/selection.js @@ -175,6 +175,26 @@ const getSelectedLeafItems = function () { return items; }; +/** + * This gets all selected path segments. + * @return {Array} selected segments + */ +const getSelectedSegments = function () { + const selected = getSelectedLeafItems(); + const segments = []; + for (const item of selected) { + if (!item.segments) { + continue; + } + for (const seg of item.segments) { + if (seg.selected) { + segments.push(seg); + } + } + } + return segments; +}; + const _deleteItemSelection = function (items, onUpdateSvg) { // @todo: Update toolbar state on change if (items.length === 0) { @@ -408,6 +428,7 @@ export { setItemSelection, getSelectedLeafItems, getSelectedRootItems, + getSelectedSegments, processRectangularSelection, selectRootItem, shouldShowSelectAll