From e218819edd4038c28eca7ea2c0b18f39ce5b550e Mon Sep 17 00:00:00 2001 From: abakkk Date: Sun, 4 Oct 2020 17:20:03 +0200 Subject: [PATCH] make transformations undoable/redoable --- area.js | 26 ++++++++++++++++++++++++-- elements.js | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/area.js b/area.js index 2956c0c..eaf318a 100644 --- a/area.js +++ b/area.js @@ -546,6 +546,10 @@ var DrawingArea = new Lang.Class({ this._redisplay(); } + if (duplicate) + // For undo, ignore both the transformations inherited from the duplicated element + // and the current transformation. + this.grabbedElement.makeAllTransformationsNotUndoable(); this.motionHandler = this.connect('motion-event', (actor, event) => { if (this.spaceKeyPressed) @@ -907,18 +911,36 @@ var DrawingArea = new Lang.Class({ deleteLastElement: function() { this._stopAll(); this.elements.pop(); + + if (this.elements.length) + this.elements[this.elements.length - 1].resetUndoneTransformations(); + this._redisplay(); }, undo: function() { - if (this.elements.length > 0) + if (!this.elements.length) + return; + + let success = this.elements[this.elements.length - 1].undoTransformation(); + if (!success) { this.undoneElements.push(this.elements.pop()); + if (this.elements.length) + this.elements[this.elements.length - 1].resetUndoneTransformations(); + } + this._redisplay(); }, redo: function() { - if (this.undoneElements.length > 0) + let success = false; + + if (this.elements.length) + success = this.elements[this.elements.length - 1].redoTransformation(); + + if (!success && this.undoneElements.length > 0) this.elements.push(this.undoneElements.pop()); + this._redisplay(); }, diff --git a/elements.js b/elements.js index c750025..ad80509 100644 --- a/elements.js +++ b/elements.js @@ -458,7 +458,7 @@ const _DrawingElement = new Lang.Class({ return; let center = this._getOriginalCenter(); - this.transformations[0] = { type: Transformations.ROTATION, + this.transformations[0] = { type: Transformations.ROTATION, notUndoable: true, angle: getAngle(center[0], center[1], points[points.length - 1][0], points[points.length - 1][1], x, y) }; } else if (this.shape == Shapes.ELLIPSE && transform) { @@ -467,7 +467,7 @@ const _DrawingElement = new Lang.Class({ points[2] = [x, y]; let center = this._getOriginalCenter(); - this.transformations[0] = { type: Transformations.ROTATION, + this.transformations[0] = { type: Transformations.ROTATION, notUndoable: true, angle: getAngle(center[0], center[1], center[0] + 1, center[1], x, y) }; } else if (this.shape == Shapes.POLYGON || this.shape == Shapes.POLYLINE) { @@ -586,6 +586,42 @@ const _DrawingElement = new Lang.Class({ } }, + undoTransformation: function() { + if (this.transformations && this.transformations.length) { + // Do not undo initial transformations (transformations made during the drawing step). + if (this.lastTransformation.notUndoable) + return false; + + if (!this._undoneTransformations) + this._undoneTransformations = []; + this._undoneTransformations.push(this.transformations.pop()); + + return true; + } + + return false; + }, + + redoTransformation: function() { + if (this._undoneTransformations && this._undoneTransformations.length) { + if (!this.transformations) + this.transformations = []; + this.transformations.push(this._undoneTransformations.pop()); + + return true; + } + + return false; + }, + + resetUndoneTransformations: function() { + delete this._undoneTransformations; + }, + + makeAllTransformationsNotUndoable: function() { + this.transformations.forEach(transformation => transformation.notUndoable = true); + }, + // The figure rotation center before transformations (original). // this.textWidth is computed during Cairo building. _getOriginalCenter: function() {