From f9772e90ed0b649de114212b18ee6ddaaac48e57 Mon Sep 17 00:00:00 2001 From: DD Date: Thu, 19 Oct 2017 12:00:21 -0400 Subject: [PATCH 1/7] Remove hover. Why did I leave hover in all of these --- src/containers/rect-mode.jsx | 19 +------------------ src/helper/tools/rect-tool.js | 16 +--------------- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/src/containers/rect-mode.jsx b/src/containers/rect-mode.jsx index 4e75c3bf..daed7954 100644 --- a/src/containers/rect-mode.jsx +++ b/src/containers/rect-mode.jsx @@ -5,7 +5,6 @@ import bindAll from 'lodash.bindall'; import Modes from '../modes/modes'; import {changeMode} from '../reducers/modes'; -import {clearHoveredItem, setHoveredItem} from '../reducers/hover'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; import {getSelectedLeafItems} from '../helper/selection'; @@ -26,10 +25,6 @@ class RectMode extends React.Component { } } componentWillReceiveProps (nextProps) { - if (this.tool && nextProps.hoveredItemId !== this.props.hoveredItemId) { - this.tool.setPrevHoveredItemId(nextProps.hoveredItemId); - } - if (nextProps.isRectModeActive && !this.props.isRectModeActive) { this.activateTool(); } else if (!nextProps.isRectModeActive && this.props.isRectModeActive) { @@ -41,8 +36,6 @@ class RectMode extends React.Component { } activateTool () { this.tool = new RectTool( - this.props.setHoveredItem, - this.props.clearHoveredItem, this.props.setSelectedItems, this.props.clearSelectedItems, this.props.onUpdateSvg @@ -65,27 +58,17 @@ class RectMode extends React.Component { } RectMode.propTypes = { - clearHoveredItem: PropTypes.func.isRequired, clearSelectedItems: PropTypes.func.isRequired, handleMouseDown: PropTypes.func.isRequired, - hoveredItemId: PropTypes.number, isRectModeActive: PropTypes.bool.isRequired, onUpdateSvg: PropTypes.func.isRequired, - setHoveredItem: PropTypes.func.isRequired, setSelectedItems: PropTypes.func.isRequired }; const mapStateToProps = state => ({ - isRectModeActive: state.scratchPaint.mode === Modes.RECT, - hoveredItemId: state.scratchPaint.hoveredItemId + isRectModeActive: state.scratchPaint.mode === Modes.RECT }); const mapDispatchToProps = dispatch => ({ - setHoveredItem: hoveredItemId => { - dispatch(setHoveredItem(hoveredItemId)); - }, - clearHoveredItem: () => { - dispatch(clearHoveredItem()); - }, clearSelectedItems: () => { dispatch(clearSelectedItems()); }, diff --git a/src/helper/tools/rect-tool.js b/src/helper/tools/rect-tool.js index 03d15449..feb662b8 100644 --- a/src/helper/tools/rect-tool.js +++ b/src/helper/tools/rect-tool.js @@ -6,16 +6,12 @@ import log from '../../log/log'; */ class RectTool extends paper.Tool { /** - * @param {function} setHoveredItem Callback to set the hovered item - * @param {function} clearHoveredItem Callback to clear the hovered item * @param {function} setSelectedItems Callback to set the set of selected items in the Redux state * @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state * @param {!function} onUpdateSvg A callback to call when the image visibly changes */ - constructor (setHoveredItem, clearHoveredItem, setSelectedItems, clearSelectedItems, onUpdateSvg) { + constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) { super(); - this.setHoveredItem = setHoveredItem; - this.clearHoveredItem = clearHoveredItem; this.setSelectedItems = setSelectedItems; this.clearSelectedItems = clearSelectedItems; this.onUpdateSvg = onUpdateSvg; @@ -28,16 +24,6 @@ class RectTool extends paper.Tool { this.onMouseDrag = this.handleMouseDrag; this.onMouseUp = this.handleMouseUp; } - /** - * To be called when the hovered item changes. When the select tool hovers over a - * new item, it compares against this to see if a hover item change event needs to - * be fired. - * @param {paper.Item} prevHoveredItemId ID of the highlight item that indicates the mouse is - * over a given item currently - */ - setPrevHoveredItemId (prevHoveredItemId) { - this.prevHoveredItemId = prevHoveredItemId; - } handleMouseDown () { log.warn('Rectangle tool not yet implemented'); } From f95bbe2ca5f98d845182f60c1c34a83abc4ffa8a Mon Sep 17 00:00:00 2001 From: DD Date: Thu, 19 Oct 2017 16:52:24 -0400 Subject: [PATCH 2/7] Basic rectangle tool --- src/components/paint-editor/paint-editor.jsx | 4 -- src/containers/rect-mode.jsx | 12 +++++ src/helper/style-path.js | 7 +++ src/helper/tools/rect-tool.js | 48 +++++++++++++++----- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/components/paint-editor/paint-editor.jsx b/src/components/paint-editor/paint-editor.jsx index 651253d0..43a4b7bc 100644 --- a/src/components/paint-editor/paint-editor.jsx +++ b/src/components/paint-editor/paint-editor.jsx @@ -11,7 +11,6 @@ import SelectMode from '../../containers/select-mode.jsx'; import LineMode from '../../containers/line-mode.jsx'; import PenMode from '../../containers/pen-mode.jsx'; import RectMode from '../../containers/rect-mode.jsx'; -import RoundedRectMode from '../../containers/rounded-rect-mode.jsx'; import OvalMode from '../../containers/oval-mode.jsx'; import FillColorIndicatorComponent from '../../containers/fill-color-indicator.jsx'; @@ -159,9 +158,6 @@ class PaintEditorComponent extends React.Component { - ) : null} diff --git a/src/containers/rect-mode.jsx b/src/containers/rect-mode.jsx index daed7954..5c1fe557 100644 --- a/src/containers/rect-mode.jsx +++ b/src/containers/rect-mode.jsx @@ -25,6 +25,10 @@ class RectMode extends React.Component { } } componentWillReceiveProps (nextProps) { + if (this.tool && nextProps.colorState !== this.props.colorState) { + this.tool.setColorState(nextProps.colorState); + } + if (nextProps.isRectModeActive && !this.props.isRectModeActive) { this.activateTool(); } else if (!nextProps.isRectModeActive && this.props.isRectModeActive) { @@ -35,11 +39,13 @@ class RectMode extends React.Component { return nextProps.isRectModeActive !== this.props.isRectModeActive; } activateTool () { + this.props.clearSelectedItems(); this.tool = new RectTool( this.props.setSelectedItems, this.props.clearSelectedItems, this.props.onUpdateSvg ); + this.tool.setColorState(this.props.colorState); this.tool.activate(); } deactivateTool () { @@ -59,6 +65,11 @@ class RectMode extends React.Component { RectMode.propTypes = { clearSelectedItems: PropTypes.func.isRequired, + colorState: PropTypes.shape({ + fillColor: PropTypes.string, + strokeColor: PropTypes.string, + strokeWidth: PropTypes.number + }).isRequired, handleMouseDown: PropTypes.func.isRequired, isRectModeActive: PropTypes.bool.isRequired, onUpdateSvg: PropTypes.func.isRequired, @@ -66,6 +77,7 @@ RectMode.propTypes = { }; const mapStateToProps = state => ({ + colorState: state.scratchPaint.color, isRectModeActive: state.scratchPaint.mode === Modes.RECT }); const mapDispatchToProps = dispatch => ({ diff --git a/src/helper/style-path.js b/src/helper/style-path.js index 7fea6770..48111b68 100644 --- a/src/helper/style-path.js +++ b/src/helper/style-path.js @@ -230,6 +230,12 @@ const styleCursorPreview = function (path, options) { } }; +const styleShape = function (path, options) { + path.fillColor = options.fillColor; + path.strokeColor = options.strokeColor; + path.strokeWidth = options.strokeWidth; +}; + export { applyFillColorToSelection, applyStrokeColorToSelection, @@ -237,6 +243,7 @@ export { getColorsFromSelection, MIXED, styleBlob, + styleShape, stylePath, styleCursorPreview }; diff --git a/src/helper/tools/rect-tool.js b/src/helper/tools/rect-tool.js index feb662b8..c6a451d4 100644 --- a/src/helper/tools/rect-tool.js +++ b/src/helper/tools/rect-tool.js @@ -1,5 +1,7 @@ import paper from '@scratch/paper'; -import log from '../../log/log'; +import Modes from '../../modes/modes'; +import {styleShape} from '../style-path'; +import BoundingBoxTool from '../selection-tools/bounding-box-tool'; /** * Tool for drawing rectangles. @@ -12,28 +14,52 @@ class RectTool extends paper.Tool { */ constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) { super(); - this.setSelectedItems = setSelectedItems; - this.clearSelectedItems = clearSelectedItems; this.onUpdateSvg = onUpdateSvg; this.prevHoveredItemId = null; + this.boundingBoxTool = new BoundingBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems, onUpdateSvg); // We have to set these functions instead of just declaring them because // paper.js tools hook up the listeners in the setter functions. - this.onMouseDown = this.handleMouseDown; - this.onMouseMove = this.handleMouseMove; this.onMouseDrag = this.handleMouseDrag; this.onMouseUp = this.handleMouseUp; + + this.downPoint = null; + this.rect = null; + this.colorState = null; } - handleMouseDown () { - log.warn('Rectangle tool not yet implemented'); + setColorState (colorState) { + this.colorState = colorState; } - handleMouseMove () { + handleMouseDrag (event) { + if (event.event.button > 0) return; // only first mouse button + + if (this.rect) { + this.rect.remove(); + } + this.rect = new paper.Path.Rectangle(event.downPoint, event.point); + + if (event.modifiers.shift) { + this.rect.height = this.rect.width; + } + + if (event.modifiers.alt) { + this.rect.position = event.downPoint; + } + + styleShape(this.rect, this.colorState); } - handleMouseDrag () { - } - handleMouseUp () { + handleMouseUp (event) { + if (event.event.button > 0) return; // only first mouse button + + if (this.rect) { + this.onUpdateSvg(); + this.rect = null; + } } deactivateTool () { + this.downPoint = null; + this.rect = null; + this.colorState = null; } } From 6732483d80333788532b3a2d3765fe6ab1ac466e Mon Sep 17 00:00:00 2001 From: DD Date: Thu, 19 Oct 2017 18:29:32 -0400 Subject: [PATCH 3/7] Add selection tool to rect --- .../selection-tools/bounding-box-tool.js | 4 +- src/helper/tools/rect-tool.js | 55 +++++++++++++++++-- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/helper/selection-tools/bounding-box-tool.js b/src/helper/selection-tools/bounding-box-tool.js index 54145d0b..1bbdd25b 100644 --- a/src/helper/selection-tools/bounding-box-tool.js +++ b/src/helper/selection-tools/bounding-box-tool.js @@ -84,8 +84,8 @@ class BoundingBoxTool { const hitProperties = { hitResult: hitResult, - clone: event.modifiers.alt, - multiselect: event.modifiers.shift + clone: clone, + multiselect: multiselect }; if (this.mode === BoundingBoxModes.MOVE) { this._modeMap[this.mode].onMouseDown(hitProperties); diff --git a/src/helper/tools/rect-tool.js b/src/helper/tools/rect-tool.js index c6a451d4..8ec0dfec 100644 --- a/src/helper/tools/rect-tool.js +++ b/src/helper/tools/rect-tool.js @@ -1,12 +1,16 @@ import paper from '@scratch/paper'; import Modes from '../../modes/modes'; import {styleShape} from '../style-path'; +import {clearSelection} from '../selection'; import BoundingBoxTool from '../selection-tools/bounding-box-tool'; /** * Tool for drawing rectangles. */ class RectTool extends paper.Tool { + static get TOLERANCE () { + return 6; + } /** * @param {function} setSelectedItems Callback to set the set of selected items in the Redux state * @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state @@ -14,33 +18,66 @@ class RectTool extends paper.Tool { */ constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) { super(); + this.clearSelectedItems = clearSelectedItems; this.onUpdateSvg = onUpdateSvg; this.prevHoveredItemId = null; this.boundingBoxTool = new BoundingBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems, onUpdateSvg); // We have to set these functions instead of just declaring them because // paper.js tools hook up the listeners in the setter functions. + this.onMouseDown = this.handleMouseDown; this.onMouseDrag = this.handleMouseDrag; this.onMouseUp = this.handleMouseUp; this.downPoint = null; this.rect = null; this.colorState = null; + this.isBoundingBoxMode = null; + } + getHitOptions () { + return { + segments: true, + stroke: true, + curves: true, + fill: true, + guide: false, + match: hitResult => + (hitResult.item.data && hitResult.item.data.isHelperItem) || + hitResult.item.selected, // Allow hits on bounding box and selected only + tolerance: RectTool.TOLERANCE / paper.view.zoom + }; } setColorState (colorState) { this.colorState = colorState; } + handleMouseDown (event) { + const clickedItem = paper.project.hitTest(event.point, this.getHitOptions()); + if (clickedItem) { + this.isBoundingBoxMode = true; + this.boundingBoxTool.onMouseDown(event, false /* clone */, false /* multiselect */, this.getHitOptions()); + } else { + this.isBoundingBoxMode = false; + this.boundingBoxTool.removeBoundsPath(); + clearSelection(this.clearSelectedItems); + } + } handleMouseDrag (event) { if (event.event.button > 0) return; // only first mouse button + if (this.isBoundingBoxMode) { + this.boundingBoxTool.onMouseDrag(event); + return; + } + if (this.rect) { this.rect.remove(); } - this.rect = new paper.Path.Rectangle(event.downPoint, event.point); - + + const rect = new paper.Rectangle(event.downPoint, event.point); if (event.modifiers.shift) { - this.rect.height = this.rect.width; + rect.height = rect.width; } + this.rect = new paper.Path.Rectangle(rect); if (event.modifiers.alt) { this.rect.position = event.downPoint; @@ -51,15 +88,21 @@ class RectTool extends paper.Tool { handleMouseUp (event) { if (event.event.button > 0) return; // only first mouse button + if (this.isBoundingBoxMode) { + this.boundingBoxTool.onMouseUp(event); + this.isBoundingBoxMode = null; + return; + } + if (this.rect) { + this.rect.selected = true; + this.boundingBoxTool.setSelectionBounds(); this.onUpdateSvg(); this.rect = null; } } deactivateTool () { - this.downPoint = null; - this.rect = null; - this.colorState = null; + this.boundingBoxTool.removeBoundsPath(); } } From dbe24ed50c0a1d1fec8f1492788182c306992d40 Mon Sep 17 00:00:00 2001 From: DD Liu Date: Thu, 19 Oct 2017 20:43:28 -0400 Subject: [PATCH 4/7] lint and clean up some things --- src/containers/rect-mode.jsx | 4 ++-- src/helper/tools/rect-tool.js | 23 +++++++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/containers/rect-mode.jsx b/src/containers/rect-mode.jsx index 5c1fe557..59a2faee 100644 --- a/src/containers/rect-mode.jsx +++ b/src/containers/rect-mode.jsx @@ -7,7 +7,7 @@ import Modes from '../modes/modes'; import {changeMode} from '../reducers/modes'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; -import {getSelectedLeafItems} from '../helper/selection'; +import {clearSelection, getSelectedLeafItems} from '../helper/selection'; import RectTool from '../helper/tools/rect-tool'; import RectModeComponent from '../components/rect-mode/rect-mode.jsx'; @@ -39,7 +39,7 @@ class RectMode extends React.Component { return nextProps.isRectModeActive !== this.props.isRectModeActive; } activateTool () { - this.props.clearSelectedItems(); + clearSelection(this.props.clearSelectedItems); this.tool = new RectTool( this.props.setSelectedItems, this.props.clearSelectedItems, diff --git a/src/helper/tools/rect-tool.js b/src/helper/tools/rect-tool.js index 8ec0dfec..db0368c9 100644 --- a/src/helper/tools/rect-tool.js +++ b/src/helper/tools/rect-tool.js @@ -51,18 +51,15 @@ class RectTool extends paper.Tool { this.colorState = colorState; } handleMouseDown (event) { - const clickedItem = paper.project.hitTest(event.point, this.getHitOptions()); - if (clickedItem) { + if (this.boundingBoxTool.onMouseDown(event, false /* clone */, false /* multiselect */, this.getHitOptions())) { this.isBoundingBoxMode = true; - this.boundingBoxTool.onMouseDown(event, false /* clone */, false /* multiselect */, this.getHitOptions()); } else { this.isBoundingBoxMode = false; - this.boundingBoxTool.removeBoundsPath(); clearSelection(this.clearSelectedItems); } } handleMouseDrag (event) { - if (event.event.button > 0) return; // only first mouse button + if (event.event.button > 0) return; // only first mouse button if (this.isBoundingBoxMode) { this.boundingBoxTool.onMouseDrag(event); @@ -86,7 +83,7 @@ class RectTool extends paper.Tool { styleShape(this.rect, this.colorState); } handleMouseUp (event) { - if (event.event.button > 0) return; // only first mouse button + if (event.event.button > 0) return; // only first mouse button if (this.isBoundingBoxMode) { this.boundingBoxTool.onMouseUp(event); @@ -95,10 +92,16 @@ class RectTool extends paper.Tool { } if (this.rect) { - this.rect.selected = true; - this.boundingBoxTool.setSelectionBounds(); - this.onUpdateSvg(); - this.rect = null; + if (this.rect.area < RectTool.TOLERANCE / paper.view.zoom) { + // Tiny rectangle created unintentionally? + this.rect.remove(); + this.rect = null; + } else { + this.rect.selected = true; + this.boundingBoxTool.setSelectionBounds(); + this.onUpdateSvg(); + this.rect = null; + } } } deactivateTool () { From d6fc2383593f62d17aafdc0204d64ee8418fce59 Mon Sep 17 00:00:00 2001 From: DD Date: Fri, 20 Oct 2017 11:05:55 -0400 Subject: [PATCH 5/7] Fix an issue where undoing when there is a bounding box would cause the whole layer to be selected --- src/helper/selection-tools/move-tool.js | 1 + src/helper/selection.js | 18 +++++++----------- src/helper/tools/rect-tool.js | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/helper/selection-tools/move-tool.js b/src/helper/selection-tools/move-tool.js index 778c47c9..6331d0ec 100644 --- a/src/helper/selection-tools/move-tool.js +++ b/src/helper/selection-tools/move-tool.js @@ -33,6 +33,7 @@ class MoveTool { * select the whole group. */ onMouseDown (hitProperties) { + debugger; let item = hitProperties.hitResult.item; if (!hitProperties.subselect) { const root = getRootItem(hitProperties.hitResult.item); diff --git a/src/helper/selection.js b/src/helper/selection.js index dde6802f..5fbe0f96 100644 --- a/src/helper/selection.js +++ b/src/helper/selection.js @@ -126,22 +126,18 @@ const clearSelection = function (dispatchClearSelect) { * @return {Array} in increasing Z order. */ const getSelectedRootItems = function () { - const allItems = paper.project.selectedItems; - const itemsAndGroups = []; + const allItems = getAllSelectableRootItems(); + const items = []; - 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); - } + for (const item of allItems) { + if (item.selected) { + items.push(item); } } // sort items by index (0 at bottom) - itemsAndGroups.sort((a, b) => parseFloat(a.index) - parseFloat(b.index)); - return itemsAndGroups; + items.sort((a, b) => parseFloat(a.index) - parseFloat(b.index)); + return items; }; /** diff --git a/src/helper/tools/rect-tool.js b/src/helper/tools/rect-tool.js index db0368c9..20a18b40 100644 --- a/src/helper/tools/rect-tool.js +++ b/src/helper/tools/rect-tool.js @@ -21,7 +21,7 @@ class RectTool extends paper.Tool { this.clearSelectedItems = clearSelectedItems; this.onUpdateSvg = onUpdateSvg; this.prevHoveredItemId = null; - this.boundingBoxTool = new BoundingBoxTool(Modes.SELECT, setSelectedItems, clearSelectedItems, onUpdateSvg); + this.boundingBoxTool = new BoundingBoxTool(Modes.RECT, setSelectedItems, clearSelectedItems, onUpdateSvg); // We have to set these functions instead of just declaring them because // paper.js tools hook up the listeners in the setter functions. From 7f4812ad55f2bbe5ccccccfd579a16cb06a151cd Mon Sep 17 00:00:00 2001 From: DD Date: Fri, 20 Oct 2017 13:40:47 -0400 Subject: [PATCH 6/7] remove debug --- src/helper/selection-tools/move-tool.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helper/selection-tools/move-tool.js b/src/helper/selection-tools/move-tool.js index 6331d0ec..778c47c9 100644 --- a/src/helper/selection-tools/move-tool.js +++ b/src/helper/selection-tools/move-tool.js @@ -33,7 +33,6 @@ class MoveTool { * select the whole group. */ onMouseDown (hitProperties) { - debugger; let item = hitProperties.hitResult.item; if (!hitProperties.subselect) { const root = getRootItem(hitProperties.hitResult.item); From 4fcb908ad5b667bc8544db555834283f6704a5b9 Mon Sep 17 00:00:00 2001 From: DD Date: Fri, 20 Oct 2017 14:54:21 -0400 Subject: [PATCH 7/7] Fix another issue caused by undo causing layers to be selected --- src/helper/selection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/selection.js b/src/helper/selection.js index 5fbe0f96..7c810559 100644 --- a/src/helper/selection.js +++ b/src/helper/selection.js @@ -151,7 +151,7 @@ const getSelectedLeafItems = function () { for (let i = 0; i < allItems.length; i++) { const item = allItems[i]; - if (!isGroup(item) && item.data && !item.data.isSelectionBound) { + if (!(item instanceof paper.Layer) && !isGroup(item) && item.data && !item.data.isSelectionBound) { items.push(item); } }