diff --git a/src/containers/blob/blob.js b/src/containers/blob/blob.js index 22606723..3025be8d 100644 --- a/src/containers/blob/blob.js +++ b/src/containers/blob/blob.js @@ -56,7 +56,7 @@ class Blobbiness { const oldStrokeColor = this.options ? this.options.strokeColor : null; const oldStrokeWidth = this.options ? this.options.strokeWidth : null; // If values are mixed, it means the color was set by a selection contained multiple values. - // In this case keep drawing with the previous values if any. (For stroke width, null indicates) + // In this case keep drawing with the previous values if any. (For stroke width, null indicates // mixed, because stroke width is required to be a number) this.options = { ...options, diff --git a/src/containers/line-mode.jsx b/src/containers/line-mode.jsx index e1ba1c36..69356d62 100644 --- a/src/containers/line-mode.jsx +++ b/src/containers/line-mode.jsx @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import bindAll from 'lodash.bindall'; import Modes from '../modes/modes'; import {changeStrokeWidth} from '../reducers/stroke-width'; -import {clearSelection, getSelectedItems} from '../helper/selection'; +import {clearSelection, getSelectedLeafItems} from '../helper/selection'; import {MIXED} from '../helper/style-path'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; import LineModeComponent from '../components/line-mode.jsx'; @@ -299,7 +299,7 @@ const mapDispatchToProps = dispatch => ({ dispatch(clearSelectedItems()); }, setSelectedItems: () => { - dispatch(setSelectedItems(getSelectedItems(true /* recursive */))); + dispatch(setSelectedItems(getSelectedLeafItems())); }, handleMouseDown: () => { dispatch(changeMode(Modes.LINE)); diff --git a/src/containers/reshape-mode.jsx b/src/containers/reshape-mode.jsx index 392989f9..1683874c 100644 --- a/src/containers/reshape-mode.jsx +++ b/src/containers/reshape-mode.jsx @@ -7,7 +7,7 @@ import Modes from '../modes/modes'; import {changeMode} from '../reducers/modes'; import {clearHoveredItem, setHoveredItem} from '../reducers/hover'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; -import {getSelectedItems} from '../helper/selection'; +import {getSelectedLeafItems} from '../helper/selection'; import ReshapeTool from '../helper/selection-tools/reshape-tool'; import ReshapeModeComponent from '../components/reshape-mode.jsx'; @@ -88,7 +88,7 @@ const mapDispatchToProps = dispatch => ({ dispatch(clearSelectedItems()); }, setSelectedItems: () => { - dispatch(setSelectedItems(getSelectedItems(true /* recursive */))); + dispatch(setSelectedItems(getSelectedLeafItems())); }, handleMouseDown: () => { dispatch(changeMode(Modes.RESHAPE)); diff --git a/src/containers/select-mode.jsx b/src/containers/select-mode.jsx index b3b43e0c..505bf412 100644 --- a/src/containers/select-mode.jsx +++ b/src/containers/select-mode.jsx @@ -8,7 +8,7 @@ import {changeMode} from '../reducers/modes'; import {clearHoveredItem, setHoveredItem} from '../reducers/hover'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; -import {getSelectedItems} from '../helper/selection'; +import {getSelectedLeafItems} from '../helper/selection'; import SelectTool from '../helper/selection-tools/select-tool'; import SelectModeComponent from '../components/select-mode.jsx'; @@ -86,7 +86,7 @@ const mapDispatchToProps = dispatch => ({ dispatch(clearSelectedItems()); }, setSelectedItems: () => { - dispatch(setSelectedItems(getSelectedItems(true /* recursive */))); + dispatch(setSelectedItems(getSelectedLeafItems())); }, handleMouseDown: () => { dispatch(changeMode(Modes.SELECT)); diff --git a/src/helper/group.js b/src/helper/group.js index 20bac775..792753c0 100644 --- a/src/helper/group.js +++ b/src/helper/group.js @@ -1,13 +1,13 @@ import paper from 'paper'; import {getRootItem, isGroupItem} from './item'; -import {clearSelection, getSelectedItems, setItemSelection} from './selection'; +import {clearSelection, getSelectedRootItems, setItemSelection} from './selection'; const isGroup = function (item) { return isGroupItem(item); }; const groupSelection = function (clearSelectedItems) { - const items = getSelectedItems(); + const items = getSelectedRootItems(); if (items.length > 0) { const group = new paper.Group(items); clearSelection(clearSelectedItems); @@ -71,7 +71,7 @@ const ungroupItems = function (items, clearSelectedItems) { }; const ungroupSelection = function () { - const items = getSelectedItems(); + const items = getSelectedRootItems(); ungroupItems(items); }; @@ -102,12 +102,12 @@ const isGroupChild = function (item) { }; const shouldShowGroup = function () { - const items = getSelectedItems(); + const items = getSelectedRootItems(); return items.length > 1; }; const shouldShowUngroup = function () { - const items = getSelectedItems(); + const items = getSelectedRootItems(); for (let i = 0; i < items.length; i++) { const item = items[i]; if (isGroup(item) && !item.data.isPGTextItem && item.children && item.children.length > 0) { diff --git a/src/helper/guides.js b/src/helper/guides.js index c6f917b8..ae5c569e 100644 --- a/src/helper/guides.js +++ b/src/helper/guides.js @@ -1,6 +1,6 @@ import paper from 'paper'; import {getGuideLayer} from './layer'; -import {getAllPaperItems} from './selection'; +import {getAllRootItems} from './selection'; const GUIDE_BLUE = '#009dec'; const GUIDE_GREY = '#aaaaaa'; @@ -66,7 +66,7 @@ const getGuideColor = function (colorName) { }; const _removePaperItemsByDataTags = function (tags) { - const allItems = getAllPaperItems(true); + const allItems = getAllRootItems(true); for (const item of allItems) { for (const tag of tags) { if (item.data && item.data[tag]) { @@ -77,7 +77,7 @@ const _removePaperItemsByDataTags = function (tags) { }; const _removePaperItemsByTags = function (tags) { - const allItems = getAllPaperItems(true); + const allItems = getAllRootItems(true); for (const item of allItems) { for (const tag of tags) { if (item[tag]) { diff --git a/src/helper/selection-tools/bounding-box-tool.js b/src/helper/selection-tools/bounding-box-tool.js index 842319dd..1826f365 100644 --- a/src/helper/selection-tools/bounding-box-tool.js +++ b/src/helper/selection-tools/bounding-box-tool.js @@ -1,7 +1,7 @@ import paper from 'paper'; import keyMirror from 'keymirror'; -import {getSelectedItems} from '../selection'; +import {getSelectedRootItems} from '../selection'; import {getGuideColor, removeHelperItems} from '../guides'; import {getGuideLayer} from '../layer'; @@ -90,9 +90,9 @@ class BoundingBoxTool { this._modeMap[this.mode].onMouseDown(hitProperties); } else if (this.mode === Modes.SCALE) { this._modeMap[this.mode].onMouseDown( - hitResult, this.boundsPath, this.boundsScaleHandles, this.boundsRotHandles, getSelectedItems()); + hitResult, this.boundsPath, this.boundsScaleHandles, this.boundsRotHandles, getSelectedRootItems()); } else if (this.mode === Modes.ROTATE) { - this._modeMap[this.mode].onMouseDown(hitResult, this.boundsPath, getSelectedItems()); + this._modeMap[this.mode].onMouseDown(hitResult, this.boundsPath, getSelectedRootItems()); } // while transforming object, never show the bounds stuff @@ -113,7 +113,7 @@ class BoundingBoxTool { setSelectionBounds () { this.removeBoundsPath(); - const items = getSelectedItems(true /* recursive */); + const items = getSelectedRootItems(); if (items.length <= 0) return; let rect = null; diff --git a/src/helper/selection-tools/handle-tool.js b/src/helper/selection-tools/handle-tool.js index 4636116d..c3d26a1d 100644 --- a/src/helper/selection-tools/handle-tool.js +++ b/src/helper/selection-tools/handle-tool.js @@ -1,4 +1,4 @@ -import {clearSelection, getSelectedItems} from '../selection'; +import {clearSelection, getSelectedLeafItems} from '../selection'; /** Sub tool of the Reshape tool for moving handles, which adjust bezier curves. */ class HandleTool { @@ -28,7 +28,7 @@ class HandleTool { this.hitType = hitProperties.hitResult.type; } onMouseDrag (event) { - const selectedItems = getSelectedItems(true /* recursive */); + const selectedItems = getSelectedLeafItems(); for (const item of selectedItems) { for (const seg of item.segments) { diff --git a/src/helper/selection-tools/move-tool.js b/src/helper/selection-tools/move-tool.js index 34212708..0a16277b 100644 --- a/src/helper/selection-tools/move-tool.js +++ b/src/helper/selection-tools/move-tool.js @@ -1,7 +1,7 @@ import {isGroup} from '../group'; import {isCompoundPathItem, getRootItem} from '../item'; import {snapDeltaToAngle} from '../math'; -import {clearSelection, cloneSelection, getSelectedItems, setItemSelection} from '../selection'; +import {clearSelection, cloneSelection, getSelectedLeafItems, setItemSelection} from '../selection'; /** * Tool to handle dragging an item to reposition it in a selection mode. @@ -52,7 +52,7 @@ class MoveTool { this._select(item, true, hitProperties.subselect); } if (hitProperties.clone) cloneSelection(hitProperties.subselect); - this.selectedItems = getSelectedItems(true /* subselect */); + this.selectedItems = getSelectedLeafItems(); } /** * Sets the selection state of an item. diff --git a/src/helper/selection-tools/point-tool.js b/src/helper/selection-tools/point-tool.js index 20eb4da2..9b54cb7e 100644 --- a/src/helper/selection-tools/point-tool.js +++ b/src/helper/selection-tools/point-tool.js @@ -1,6 +1,6 @@ import paper from 'paper'; import {snapDeltaToAngle} from '../math'; -import {clearSelection, getSelectedItems} from '../selection'; +import {clearSelection, getSelectedLeafItems} from '../selection'; /** Subtool of ReshapeTool for moving control points. */ class PointTool { @@ -58,7 +58,7 @@ class PointTool { hitProperties.hitResult.segment.selected = true; } - this.selectedItems = getSelectedItems(true /* recursive */); + this.selectedItems = getSelectedLeafItems(); } /** * @param {!object} hitProperties Describes the mouse event diff --git a/src/helper/selection.js b/src/helper/selection.js index 443fa5cb..2c12b161 100644 --- a/src/helper/selection.js +++ b/src/helper/selection.js @@ -10,7 +10,7 @@ import {getItemsCompoundPath, isCompoundPath, isCompoundPathChild} from './compo * be included in the returned items. * @return {Array} all top-level (direct descendants of a paper.Layer) items */ -const getAllPaperItems = function (includeGuides) { +const getAllRootItems = function (includeGuides) { includeGuides = includeGuides || false; const allItems = []; for (const layer of paper.project.layers) { @@ -29,8 +29,8 @@ const getAllPaperItems = function (includeGuides) { * @return {Array} all top-level (direct descendants of a paper.Layer) items * that aren't guide items or helper items. */ -const getAllSelectableItems = function () { - const allItems = getAllPaperItems(); +const getAllSelectableRootItems = function () { + const allItems = getAllRootItems(); const selectables = []; for (let i = 0; i < allItems.length; i++) { if (allItems[i].data && !allItems[i].data.isHelperItem) { @@ -97,7 +97,7 @@ const setItemSelection = function (item, state, fullySelected) { }; const selectAllItems = function () { - const items = getAllSelectableItems(); + const items = getAllSelectableRootItems(); for (let i = 0; i < items.length; i++) { setItemSelection(items[i], true); @@ -105,7 +105,7 @@ const selectAllItems = function () { }; const selectAllSegments = function () { - const items = getAllSelectableItems(); + const items = getAllSelectableRootItems(); for (let i = 0; i < items.length; i++) { selectItemSegments(items[i], true); @@ -119,39 +119,53 @@ const clearSelection = function (dispatchClearSelect) { dispatchClearSelect(); }; -// This gets all selected non-grouped items and groups -// (alternative to paper.project.selectedItems, which includes -// group children in addition to the group) -// Returns in increasing Z order -const getSelectedItems = function (recursive) { +/** + * This gets all selected non-grouped items and groups + * (alternative to paper.project.selectedItems, which includes + * group children in addition to the group) + * @return {Array} in increasing Z order. + */ +const getSelectedRootItems = function () { const allItems = paper.project.selectedItems; const itemsAndGroups = []; - if (recursive) { - for (let i = 0; i < allItems.length; i++) { - const item = allItems[i]; + for (let i = 0; i < allItems.length; i++) { + const item = allItems[i]; + if ((isGroup(item) && !isGroup(item.parent)) || + !isGroup(item.parent)) { if (item.data && !item.data.isSelectionBound) { itemsAndGroups.push(item); } } - } else { - for (let i = 0; i < allItems.length; i++) { - const item = allItems[i]; - if ((isGroup(item) && !isGroup(item.parent)) || - !isGroup(item.parent)) { - if (item.data && !item.data.isSelectionBound) { - itemsAndGroups.push(item); - } - } - } } + // sort items by index (0 at bottom) itemsAndGroups.sort((a, b) => parseFloat(a.index) - parseFloat(b.index)); return itemsAndGroups; }; -const deleteItemSelection = function (recursive) { - const items = getSelectedItems(recursive); +/** + * This gets all selected items that are as deeply nested as possible. Does not + * return the parent groups. + * @return {Array} in increasing Z order. + */ +const getSelectedLeafItems = function () { + const allItems = paper.project.selectedItems; + const items = []; + + for (let i = 0; i < allItems.length; i++) { + const item = allItems[i]; + if (!isGroup(item) && item.data && !item.data.isSelectionBound) { + items.push(item); + } + } + + // sort items by index (0 at bottom) + items.sort((a, b) => parseFloat(a.index) - parseFloat(b.index)); + return items; +}; + +const deleteItemSelection = function (items) { for (let i = 0; i < items.length; i++) { items[i].remove(); } @@ -162,11 +176,10 @@ const deleteItemSelection = function (recursive) { // pg.undo.snapshot('deleteItemSelection'); }; -const removeSelectedSegments = function (recursive) { +const removeSelectedSegments = function (items) { // @todo add back undo // pg.undo.snapshot('removeSelectedSegments'); - const items = getSelectedItems(recursive); const segmentsToRemove = []; for (let i = 0; i < items.length; i++) { @@ -190,12 +203,14 @@ const removeSelectedSegments = function (recursive) { const deleteSelection = function (mode) { if (mode === Modes.RESHAPE) { + const selectedItems = getSelectedLeafItems(); // If there are points selected remove them. If not delete the item selected. - if (!removeSelectedSegments(true /* recursive */)) { - deleteItemSelection(true /* recursive */); + if (!removeSelectedSegments(selectedItems)) { + deleteItemSelection(selectedItems); } } else { - deleteItemSelection(); + const selectedItems = getSelectedRootItems(); + deleteItemSelection(selectedItems); } }; @@ -245,7 +260,7 @@ const splitPathRetainSelection = function (path, index, deselectSplitSegments) { }; const splitPathAtSelectedSegments = function () { - const items = getSelectedItems(); + const items = getSelectedRootItems(); for (let i = 0; i < items.length; i++) { const item = items[i]; const segments = item.segments; @@ -301,9 +316,7 @@ const deleteSegments = function (item) { } }; -const deleteSegmentSelection = function () { - - const items = getSelectedItems(); +const deleteSegmentSelection = function (items) { for (let i = 0; i < items.length; i++) { deleteSegments(items[i]); } @@ -315,7 +328,7 @@ const deleteSegmentSelection = function () { }; const cloneSelection = function (recursive) { - const selectedItems = getSelectedItems(recursive); + const selectedItems = recursive ? getSelectedLeafItems() : getSelectedRootItems(); for (let i = 0; i < selectedItems.length; i++) { const item = selectedItems[i]; item.clone(); @@ -327,7 +340,7 @@ const cloneSelection = function (recursive) { // Only returns paths, no compound paths, groups or any other stuff const getSelectedPaths = function () { - const allPaths = getSelectedItems(); + const allPaths = getSelectedRootItems(); const paths = []; for (let i = 0; i < allPaths.length; i++) { @@ -458,7 +471,7 @@ const _rectangularSelectionGroupLoop = function (group, rect, root, event, mode) * @param {Modes} mode The mode of the paint editor when drawing the rectangle */ const processRectangularSelection = function (event, rect, mode) { - const allItems = getAllSelectableItems(); + const allItems = getAllSelectableRootItems(); for (let i = 0; i < allItems.length; i++) { const item = allItems[i]; @@ -480,7 +493,7 @@ const processRectangularSelection = function (event, rect, mode) { * instead. (otherwise the compound path breaks because of scale-grouping) */ const selectRootItem = function () { - const items = getSelectedItems(true /* recursive */); + const items = getSelectedLeafItems(); for (const item of items) { if (isCompoundPathChild(item)) { const cp = getItemsCompoundPath(item); @@ -494,11 +507,11 @@ const selectRootItem = function () { }; const shouldShowIfSelection = function () { - return getSelectedItems().length > 0; + return getSelectedRootItems().length > 0; }; const shouldShowIfSelectionRecursive = function () { - return getSelectedItems(true /* recursive */).length > 0; + return getSelectedRootItems().length > 0; }; const shouldShowSelectAll = function () { @@ -506,7 +519,7 @@ const shouldShowSelectAll = function () { }; export { - getAllPaperItems, + getAllRootItems, selectAllItems, selectAllSegments, clearSelection, @@ -517,8 +530,9 @@ export { cloneSelection, setItemSelection, setGroupSelection, - getSelectedItems, + getSelectedLeafItems, getSelectedPaths, + getSelectedRootItems, removeSelectedSegments, processRectangularSelection, selectRootItem, diff --git a/src/helper/style-path.js b/src/helper/style-path.js index 2e27713f..aab1aee1 100644 --- a/src/helper/style-path.js +++ b/src/helper/style-path.js @@ -1,4 +1,4 @@ -import {getSelectedItems} from './selection'; +import {getSelectedLeafItems} from './selection'; import {isPGTextItem, isPointTextItem} from './item'; import {isGroup} from './group'; @@ -9,7 +9,7 @@ const MIXED = 'scratch-paint/style-path/mixed'; * @param {string} colorString New color, css format */ const applyFillColorToSelection = function (colorString) { - const items = getSelectedItems(true /* recursive */); + const items = getSelectedLeafItems; for (const item of items) { if (isPGTextItem(item)) { for (const child of item.children) { @@ -38,7 +38,7 @@ const applyFillColorToSelection = function (colorString) { * @param {string} colorString New color, css format */ const applyStrokeColorToSelection = function (colorString) { - const items = getSelectedItems(true /* recursive */); + const items = getSelectedLeafItems(); for (const item of items) { if (isPGTextItem(item)) { @@ -69,7 +69,7 @@ const applyStrokeColorToSelection = function (colorString) { * @param {number} value New stroke width */ const applyStrokeWidthToSelection = function (value) { - const items = getSelectedItems(true /* recursive */); + const items = getSelectedLeafItems(); for (const item of items) { if (isGroup(item)) { continue;