diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx index 172b78f0..4ed6cfca 100644 --- a/src/containers/paint-editor.jsx +++ b/src/containers/paint-editor.jsx @@ -6,7 +6,7 @@ import {changeMode} from '../reducers/modes'; import {undo, redo, undoSnapshot} from '../reducers/undo'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; -import {getGuideLayer} from '../helper/layer'; +import {getGuideLayer, getBackgroundGuideLayer} from '../helper/layer'; import {performUndo, performRedo, performSnapshot} from '../helper/undo'; import {bringToFront, sendBackward, sendToBack, bringForward} from '../helper/order'; import {groupSelection, ungroupSelection} from '../helper/group'; @@ -41,7 +41,9 @@ class PaintEditor extends React.Component { handleUpdateSvg (skipSnapshot) { // Hide guide layer const guideLayer = getGuideLayer(); + const backgroundGuideLayer = getBackgroundGuideLayer(); guideLayer.remove(); + backgroundGuideLayer.remove(); const bounds = paper.project.activeLayer.bounds; this.props.onUpdateSvg( paper.project.exportSVG({ @@ -53,6 +55,8 @@ class PaintEditor extends React.Component { if (!skipSnapshot) { performSnapshot(this.props.undoSnapshot); } + paper.project.addLayer(backgroundGuideLayer); + backgroundGuideLayer.sendToBack(); paper.project.addLayer(guideLayer); } handleUndo () { diff --git a/src/containers/paper-canvas.jsx b/src/containers/paper-canvas.jsx index beb0d8d7..5548db6b 100644 --- a/src/containers/paper-canvas.jsx +++ b/src/containers/paper-canvas.jsx @@ -7,6 +7,7 @@ import paper from '@scratch/paper'; import {performSnapshot} from '../helper/undo'; import {undoSnapshot, clearUndoState} from '../reducers/undo'; import {isGroup, ungroupItems} from '../helper/group'; +import {setupLayers} from '../helper/layer'; import styles from './paper-canvas.css'; @@ -22,6 +23,8 @@ class PaperCanvas extends React.Component { paper.setup(this.canvas); // Don't show handles by default paper.settings.handleSize = 0; + // Make layers. + setupLayers(); if (this.props.svg) { this.importSvg(this.props.svg, this.props.rotationCenterX, this.props.rotationCenterY); } else { @@ -31,7 +34,9 @@ class PaperCanvas extends React.Component { componentWillReceiveProps (newProps) { if (this.props.svgId === newProps.svgId) return; for (const layer of paper.project.layers) { - layer.removeChildren(); + if (!layer.data.isBackgroundGuideLayer) { + layer.removeChildren(); + } } this.props.clearUndo(); if (newProps.svg) { diff --git a/src/helper/blob-tools/blob.js b/src/helper/blob-tools/blob.js index 0ed06d6e..d19c9276 100644 --- a/src/helper/blob-tools/blob.js +++ b/src/helper/blob-tools/blob.js @@ -3,7 +3,7 @@ import log from '../../log/log'; import BroadBrushHelper from './broad-brush-helper'; import SegmentBrushHelper from './segment-brush-helper'; import {MIXED, styleCursorPreview} from '../../helper/style-path'; -import {clearSelection} from '../../helper/selection'; +import {clearSelection, getItems} from '../../helper/selection'; import {getGuideLayer} from '../../helper/layer'; /** @@ -193,7 +193,7 @@ class Blobbiness { const blob = this; // Get all path items to merge with - const paths = paper.project.getItems({ + const paths = getItems({ match: function (item) { return blob.isMergeable(lastPath, item) && item.parent instanceof paper.Layer; // don't merge with nested in group @@ -245,7 +245,7 @@ class Blobbiness { // Get all path items to merge with // If there are selected items, try to erase from amongst those. - let items = paper.project.getItems({ + let items = getItems({ match: function (item) { return item.selected && blob.isMergeable(lastPath, item) && blob.touches(lastPath, item); } @@ -254,7 +254,7 @@ class Blobbiness { // and deselect the selection if (items.length === 0) { clearSelection(this.clearSelectedItems); - items = paper.project.getItems({ + items = getItems({ match: function (item) { return blob.isMergeable(lastPath, item) && blob.touches(lastPath, item); } diff --git a/src/helper/layer.js b/src/helper/layer.js index 2cd811ab..40d197b6 100644 --- a/src/helper/layer.js +++ b/src/helper/layer.js @@ -15,4 +15,70 @@ const getGuideLayer = function () { return guideLayer; }; -export {getGuideLayer}; +const getBackgroundGuideLayer = function () { + for (let i = 0; i < paper.project.layers.length; i++) { + const layer = paper.project.layers[i]; + if (layer.data && layer.data.isBackgroundGuideLayer) { + return layer; + } + } +}; + +const _makePaintingLayer = function () { + const paintingLayer = new paper.Layer(); + paintingLayer.data.isPaintingLayer = true; + return paintingLayer; +}; + +const _makeBackgroundGuideLayer = function () { + const BLOCK_WIDTH = 4; + const guideLayer = new paper.Layer(); + guideLayer.locked = true; + for (let i = 0; i < 500 / BLOCK_WIDTH; i += 2) { + for (let j = 0; j < 400 / BLOCK_WIDTH; j++) { + const rect = new paper.Shape.Rectangle( + new paper.Point((i + (j % 2)) * BLOCK_WIDTH, j * BLOCK_WIDTH), + new paper.Point((i + (j % 2) + 1) * BLOCK_WIDTH, (j + 1) * BLOCK_WIDTH) + ); + rect.fillColor = '#E5E5E5'; + rect.guide = true; + rect.locked = true; + } + } + + const vLine = new paper.Path.Line(new paper.Point(0, -7), new paper.Point(0, 7)); + vLine.strokeWidth = 2; + vLine.strokeColor = '#ccc'; + vLine.position = paper.view.center; + vLine.guide = true; + vLine.locked = true; + + const hLine = new paper.Path.Line(new paper.Point(-7, 0), new paper.Point(7, 0)); + hLine.strokeWidth = 2; + hLine.strokeColor = '#ccc'; + hLine.position = paper.view.center; + hLine.guide = true; + hLine.locked = true; + + const circle = new paper.Shape.Circle(new paper.Point(0, 0), 5); + circle.strokeWidth = 2; + circle.strokeColor = '#ccc'; + circle.position = paper.view.center; + circle.guide = true; + circle.locked = true; + + guideLayer.data.isBackgroundGuideLayer = true; + guideLayer.sendToBack(); + return guideLayer; +}; + +const setupLayers = function () { + _makeBackgroundGuideLayer(); + _makePaintingLayer().activate(); +}; + +export { + getGuideLayer, + getBackgroundGuideLayer, + setupLayers +}; diff --git a/src/helper/selection-tools/scale-tool.js b/src/helper/selection-tools/scale-tool.js index 5b85db13..6cc585d7 100644 --- a/src/helper/selection-tools/scale-tool.js +++ b/src/helper/selection-tools/scale-tool.js @@ -1,4 +1,5 @@ import paper from '@scratch/paper'; +import {getItems} from '../selection'; /** * Tool to handle scaling items by pulling on the handles around the edges of the bounding @@ -55,9 +56,9 @@ class ScaleTool { const modOrigSize = this.origSize; // get item to insert below so that scaled items stay in same z position - const items = paper.project.getItems({ + const items = getItems({ match: function (item) { - if (item instanceof paper.Layer || item.data.isHelperItem) { + if (item instanceof paper.Layer) { return false; } for (const scaleItem of scaleTool.scaleItems) { diff --git a/src/helper/selection.js b/src/helper/selection.js index 7c810559..a5a403b0 100644 --- a/src/helper/selection.js +++ b/src/helper/selection.js @@ -5,6 +5,21 @@ import {getItemsGroup, isGroup} from './group'; import {getRootItem, isCompoundPathItem, isBoundsItem, isPathItem, isPGTextItem} from './item'; import {getItemsCompoundPath, isCompoundPath, isCompoundPathChild} from './compound-path'; +/** + * Wrapper for paper.project.getItems that excludes our helper items + * @param {?object} options See paper.js docs for paper.Item.getItems + * @return {Array} items that match options + */ +const getItems = function (options) { + const newMatcher = function (item) { + return !item.locked && + !(item.data && item.data.isHelperItem) && + (!options.match || options.match(item)); + }; + const newOptions = {...options, match: newMatcher}; + return paper.project.getItems(newOptions); +}; + /** * @param {boolean} includeGuides True if guide layer items like the bounding box should * be included in the returned items. @@ -389,6 +404,7 @@ const shouldShowSelectAll = function () { }; export { + getItems, getAllRootItems, selectAllItems, selectAllSegments, diff --git a/src/helper/snapping.js b/src/helper/snapping.js index 595bab6a..95d00401 100644 --- a/src/helper/snapping.js +++ b/src/helper/snapping.js @@ -1,4 +1,5 @@ import paper from '@scratch/paper'; +import {getItems} from './selection'; /** * @param {paper.Point} point1 point 1 @@ -19,7 +20,7 @@ const touching = function (point1, point2, tolerance) { * tolerance distance of the given point, or null if none exists. */ const endPointHit = function (point, tolerance, excludePath) { - const lines = paper.project.getItems({ + const lines = getItems({ class: paper.Path }); // Prefer more recent lines