mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 21:42:30 -05:00
Get undo/redo working
This commit is contained in:
parent
15053d15f0
commit
6e4ab3191a
5 changed files with 60 additions and 21 deletions
|
@ -1,5 +1,6 @@
|
||||||
import paper from '@scratch/paper';
|
import paper from '@scratch/paper';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PaintEditorComponent from '../components/paint-editor/paint-editor.jsx';
|
import PaintEditorComponent from '../components/paint-editor/paint-editor.jsx';
|
||||||
|
|
||||||
|
@ -11,7 +12,8 @@ import {deactivateEyeDropper} from '../reducers/eye-dropper';
|
||||||
import {setTextEditTarget} from '../reducers/text-edit-target';
|
import {setTextEditTarget} from '../reducers/text-edit-target';
|
||||||
import {updateViewBounds} from '../reducers/view-bounds';
|
import {updateViewBounds} from '../reducers/view-bounds';
|
||||||
|
|
||||||
import {hideGuideLayers, showGuideLayers} from '../helper/layer';
|
import {getRaster, hideGuideLayers, showGuideLayers} from '../helper/layer';
|
||||||
|
import {trim} from '../helper/bitmap';
|
||||||
import {performUndo, performRedo, performSnapshot, shouldShowUndo, shouldShowRedo} from '../helper/undo';
|
import {performUndo, performRedo, performSnapshot, shouldShowUndo, shouldShowRedo} from '../helper/undo';
|
||||||
import {bringToFront, sendBackward, sendToBack, bringForward} from '../helper/order';
|
import {bringToFront, sendBackward, sendToBack, bringForward} from '../helper/order';
|
||||||
import {groupSelection, ungroupSelection} from '../helper/group';
|
import {groupSelection, ungroupSelection} from '../helper/group';
|
||||||
|
@ -90,9 +92,20 @@ class PaintEditor extends React.Component {
|
||||||
const oldCenter = paper.project.view.center.clone();
|
const oldCenter = paper.project.view.center.clone();
|
||||||
resetZoom();
|
resetZoom();
|
||||||
|
|
||||||
const guideLayers = hideGuideLayers();
|
let raster;
|
||||||
|
if (this.props.format === Formats.BITMAP) {
|
||||||
|
// @todo export bitmap here
|
||||||
|
raster = trim(getRaster());
|
||||||
|
if (raster.width === 0 || raster.height === 0) {
|
||||||
|
raster.remove();
|
||||||
|
} else {
|
||||||
|
paper.project.activeLayer.addChild(raster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const guideLayers = hideGuideLayers(true /* includeRaster */);
|
||||||
const bounds = paper.project.activeLayer.bounds;
|
const bounds = paper.project.activeLayer.bounds;
|
||||||
|
|
||||||
this.props.onUpdateSvg(
|
this.props.onUpdateSvg(
|
||||||
paper.project.exportSVG({
|
paper.project.exportSVG({
|
||||||
asString: true,
|
asString: true,
|
||||||
|
@ -108,6 +121,8 @@ class PaintEditor extends React.Component {
|
||||||
performSnapshot(this.props.undoSnapshot);
|
performSnapshot(this.props.undoSnapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (raster) raster.remove();
|
||||||
|
|
||||||
// Restore old zoom
|
// Restore old zoom
|
||||||
paper.project.view.zoom = oldZoom;
|
paper.project.view.zoom = oldZoom;
|
||||||
paper.project.view.center = oldCenter;
|
paper.project.view.center = oldCenter;
|
||||||
|
|
|
@ -79,15 +79,17 @@ class PaperCanvas extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convertToBitmap () {
|
convertToBitmap () {
|
||||||
|
this.props.clearSelectedItems();
|
||||||
const raster = paper.project.activeLayer.rasterize(72, false /* insert */);
|
const raster = paper.project.activeLayer.rasterize(72, false /* insert */);
|
||||||
raster.onLoad = function () {
|
raster.onLoad = function () {
|
||||||
const subCanvas = raster.canvas;
|
const subCanvas = raster.canvas;
|
||||||
getRaster().drawImage(subCanvas, raster.bounds.topLeft);
|
getRaster().drawImage(subCanvas, raster.bounds.topLeft);
|
||||||
};
|
|
||||||
paper.project.activeLayer.removeChildren();
|
paper.project.activeLayer.removeChildren();
|
||||||
performSnapshot(this.props.undoSnapshot);
|
this.props.onUpdateSvg();
|
||||||
|
}.bind(this);
|
||||||
}
|
}
|
||||||
convertToVector () {
|
convertToVector () {
|
||||||
|
this.props.clearSelectedItems();
|
||||||
const raster = trim(getRaster());
|
const raster = trim(getRaster());
|
||||||
if (raster.width === 0 || raster.height === 0) {
|
if (raster.width === 0 || raster.height === 0) {
|
||||||
raster.remove();
|
raster.remove();
|
||||||
|
@ -95,7 +97,7 @@ class PaperCanvas extends React.Component {
|
||||||
paper.project.activeLayer.addChild(raster);
|
paper.project.activeLayer.addChild(raster);
|
||||||
}
|
}
|
||||||
clearRaster();
|
clearRaster();
|
||||||
performSnapshot(this.props.undoSnapshot);
|
this.props.onUpdateSvg();
|
||||||
}
|
}
|
||||||
switchCostume (svg, rotationCenterX, rotationCenterY) {
|
switchCostume (svg, rotationCenterX, rotationCenterY) {
|
||||||
for (const layer of paper.project.layers) {
|
for (const layer of paper.project.layers) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ const _getLayer = function (layerString) {
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.error(`Didn't find layer ${layerString}`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const _getPaintingLayer = function () {
|
const _getPaintingLayer = function () {
|
||||||
|
@ -36,22 +35,40 @@ const _getBackgroundGuideLayer = function () {
|
||||||
return _getLayer('isBackgroundGuideLayer');
|
return _getLayer('isBackgroundGuideLayer');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const _makeGuideLayer = function () {
|
||||||
|
const guideLayer = new paper.Layer();
|
||||||
|
guideLayer.data.isGuideLayer = true;
|
||||||
|
return guideLayer;
|
||||||
|
};
|
||||||
|
|
||||||
const getGuideLayer = function () {
|
const getGuideLayer = function () {
|
||||||
return _getLayer('isGuideLayer');
|
let layer = _getLayer('isGuideLayer');
|
||||||
|
if (!layer) {
|
||||||
|
layer = _makeGuideLayer();
|
||||||
|
_getPaintingLayer().activate();
|
||||||
|
}
|
||||||
|
return layer;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the guide layers, e.g. for purposes of exporting the image. Must call showGuideLayers to re-add them.
|
* Removes the guide layers, e.g. for purposes of exporting the image. Must call showGuideLayers to re-add them.
|
||||||
|
* @param {boolean} includeRaster true if the raster layer should also be hidden
|
||||||
* @return {object} an object of the removed layers, which should be passed to showGuideLayers to re-add them.
|
* @return {object} an object of the removed layers, which should be passed to showGuideLayers to re-add them.
|
||||||
*/
|
*/
|
||||||
const hideGuideLayers = function () {
|
const hideGuideLayers = function (includeRaster) {
|
||||||
const backgroundGuideLayer = _getBackgroundGuideLayer();
|
const backgroundGuideLayer = _getBackgroundGuideLayer();
|
||||||
const guideLayer = getGuideLayer();
|
const guideLayer = getGuideLayer();
|
||||||
guideLayer.remove();
|
guideLayer.remove();
|
||||||
backgroundGuideLayer.remove();
|
backgroundGuideLayer.remove();
|
||||||
|
let rasterLayer;
|
||||||
|
if (includeRaster) {
|
||||||
|
rasterLayer = _getLayer('isRasterLayer');
|
||||||
|
rasterLayer.remove();
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
guideLayer: guideLayer,
|
guideLayer: guideLayer,
|
||||||
backgroundGuideLayer: backgroundGuideLayer
|
backgroundGuideLayer: backgroundGuideLayer,
|
||||||
|
rasterLayer: rasterLayer
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +80,11 @@ const hideGuideLayers = function () {
|
||||||
const showGuideLayers = function (guideLayers) {
|
const showGuideLayers = function (guideLayers) {
|
||||||
const backgroundGuideLayer = guideLayers.backgroundGuideLayer;
|
const backgroundGuideLayer = guideLayers.backgroundGuideLayer;
|
||||||
const guideLayer = guideLayers.guideLayer;
|
const guideLayer = guideLayers.guideLayer;
|
||||||
|
const rasterLayer = guideLayers.rasterLayer;
|
||||||
|
if (rasterLayer && !rasterLayer.index) {
|
||||||
|
paper.project.addLayer(rasterLayer);
|
||||||
|
rasterLayer.sendToBack();
|
||||||
|
}
|
||||||
if (!backgroundGuideLayer.index) {
|
if (!backgroundGuideLayer.index) {
|
||||||
paper.project.addLayer(backgroundGuideLayer);
|
paper.project.addLayer(backgroundGuideLayer);
|
||||||
backgroundGuideLayer.sendToBack();
|
backgroundGuideLayer.sendToBack();
|
||||||
|
@ -77,12 +99,6 @@ const showGuideLayers = function (guideLayers) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _makeGuideLayer = function () {
|
|
||||||
const guideLayer = new paper.Layer();
|
|
||||||
guideLayer.data.isGuideLayer = true;
|
|
||||||
return guideLayer;
|
|
||||||
};
|
|
||||||
|
|
||||||
const _makePaintingLayer = function () {
|
const _makePaintingLayer = function () {
|
||||||
const paintingLayer = new paper.Layer();
|
const paintingLayer = new paper.Layer();
|
||||||
paintingLayer.data.isPaintingLayer = true;
|
paintingLayer.data.isPaintingLayer = true;
|
||||||
|
|
|
@ -54,7 +54,7 @@ class BoundingBoxTool {
|
||||||
* @param {Array<paper.Item>} selectedItems Array of selected items.
|
* @param {Array<paper.Item>} selectedItems Array of selected items.
|
||||||
*/
|
*/
|
||||||
onSelectionChanged (selectedItems) {
|
onSelectionChanged (selectedItems) {
|
||||||
if (selectedItems) {
|
if (selectedItems && selectedItems.length) {
|
||||||
this.setSelectionBounds();
|
this.setSelectionBounds();
|
||||||
} else {
|
} else {
|
||||||
this.removeBoundsPath();
|
this.removeBoundsPath();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// undo functionality
|
// undo functionality
|
||||||
// modifed from https://github.com/memononen/stylii
|
// modifed from https://github.com/memononen/stylii
|
||||||
import paper from '@scratch/paper';
|
import paper from '@scratch/paper';
|
||||||
import {hideGuideLayers, showGuideLayers} from '../helper/layer';
|
import {hideGuideLayers, showGuideLayers, getRaster} from '../helper/layer';
|
||||||
|
|
||||||
const performSnapshot = function (dispatchPerformSnapshot) {
|
const performSnapshot = function (dispatchPerformSnapshot) {
|
||||||
const guideLayers = hideGuideLayers();
|
const guideLayers = hideGuideLayers();
|
||||||
|
@ -12,7 +12,8 @@ const performSnapshot = function (dispatchPerformSnapshot) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const _restore = function (entry, setSelectedItems, onUpdateSvg) {
|
const _restore = function (entry, setSelectedItems, onUpdateSvg) {
|
||||||
for (const layer of paper.project.layers) {
|
for (let i = paper.project.layers.length - 1; i >= 0; i--) {
|
||||||
|
const layer = paper.project.layers[i];
|
||||||
if (!layer.data.isBackgroundGuideLayer) {
|
if (!layer.data.isBackgroundGuideLayer) {
|
||||||
layer.removeChildren();
|
layer.removeChildren();
|
||||||
layer.remove();
|
layer.remove();
|
||||||
|
@ -21,8 +22,13 @@ const _restore = function (entry, setSelectedItems, onUpdateSvg) {
|
||||||
paper.project.importJSON(entry.json);
|
paper.project.importJSON(entry.json);
|
||||||
|
|
||||||
setSelectedItems();
|
setSelectedItems();
|
||||||
|
getRaster().onLoad = function () {
|
||||||
onUpdateSvg(true /* skipSnapshot */);
|
onUpdateSvg(true /* skipSnapshot */);
|
||||||
};
|
};
|
||||||
|
if (getRaster().loaded) {
|
||||||
|
getRaster().onLoad();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const performUndo = function (undoState, dispatchPerformUndo, setSelectedItems, onUpdateSvg) {
|
const performUndo = function (undoState, dispatchPerformUndo, setSelectedItems, onUpdateSvg) {
|
||||||
if (undoState.pointer > 0) {
|
if (undoState.pointer > 0) {
|
||||||
|
|
Loading…
Reference in a new issue