Skip to content
Browse files

New: Buggy undo support!

  • Loading branch information...
1 parent 7ae5eea commit b6d8d6fe55c74f0c14629c9151249eea1fd5a043 @trethaller committed Aug 12, 2013
Showing with 189 additions and 4 deletions.
  1. +61 −0 js/app.coffee
  2. +72 −2 js/app.js
  3. +27 −2 js/core.coffee
  4. +29 −0 js/core.js
View
61 js/app.coffee
@@ -2,6 +2,50 @@
class Document
constructor: (@width,@height)->
@layer = new Layer(@width,@height)
+ @backup = new Layer(@width,@height)
+ @history = []
+ @histIndex = -1
+
+ afterEdit: (rect)->
+ if @histIndex > 0
+ @history.splice 0, @histIndex
+
+ @history.splice 0, 0, {
+ data: @backup.getCopy(rect)
+ rect: rect
+ }
+ @backup.getBuffer().set(@layer.getBuffer())
+ histSize = 10
+ if @history.length > histSize
+ @history.splice(histSize)
+
+ @histIndex = -1
+ console.log "History len: #{this.history.length}"
+
+ undo: ->
+ if @histIndex >= @history.length - 1
+ return
+
+ if @histIndex is -1
+ @afterEdit(@history[0].rect)
+ @histIndex = 1
+ else
+ @histIndex++
+
+ console.log "History idx: #{this.histIndex}"
+ @restore( @history[ @histIndex ] )
+
+ redo: ->
+ if @histIndex <= 0
+ return
+ @histIndex--
+ console.log "History idx: #{this.histIndex}"
+ @restore( @history[ @histIndex ] )
+
+
+ restore: (histItem)->
+ @layer.setData(histItem.data, histItem.rect)
+
Renderers = [GammaRenderer, NormalRenderer, GradientRenderer]
Tools = [RoundBrush, Picker]
@@ -110,6 +154,7 @@ class DocumentView
e.preventDefault()
if e.which is 1
@drawing = true
+ @actionDirtyRect = null
coords = getCanvasCoords(e)
editor.getToolObject().beginDraw(coords)
@onDraw(coords)
@@ -124,6 +169,8 @@ class DocumentView
if e.which is 1
editor.getToolObject().endDraw(getCanvasCoords(e))
@drawing = false
+ if @actionDirtyRect?
+ doc.afterEdit(@actionDirtyRect)
if e.which is 2
@panning = false
@@ -181,6 +228,12 @@ class DocumentView
.map((r)->r.intersect(layerRect))
.filter((r)->not r.isEmpty())
+ dirtyRects.forEach (r)=>
+ if not @actionDirtyRect?
+ @actionDirtyRect = r.clone()
+ else
+ @actionDirtyRect.extend(r)
+
if false # Log dirty rects
totalArea = dirtyRects
.map((r)-> r.width * r.height)
@@ -401,6 +454,14 @@ $(window).keyup (e)->
if e.key is 'Control'
editor.set('altkeyDown', false)
+ if e.ctrlKey
+ switch e.keyCode
+ when 90
+ editor.get('doc').undo()
+ editor.refresh()
+ when 89
+ editor.get('doc').redo()
+ editor.refresh()
$(document).ready ()->
View
74 js/app.js
@@ -8,8 +8,56 @@ Document = (function() {
this.width = width;
this.height = height;
this.layer = new Layer(this.width, this.height);
+ this.backup = new Layer(this.width, this.height);
+ this.history = [];
+ this.histIndex = -1;
}
+ Document.prototype.afterEdit = function(rect) {
+ var histSize;
+ if (this.histIndex > 0) {
+ this.history.splice(0, this.histIndex);
+ }
+ this.history.splice(0, 0, {
+ data: this.backup.getCopy(rect),
+ rect: rect
+ });
+ this.backup.getBuffer().set(this.layer.getBuffer());
+ histSize = 10;
+ if (this.history.length > histSize) {
+ this.history.splice(histSize);
+ }
+ this.histIndex = -1;
+ return console.log("History len: " + this.history.length);
+ };
+
+ Document.prototype.undo = function() {
+ if (this.histIndex >= this.history.length - 1) {
+ return;
+ }
+ if (this.histIndex === -1) {
+ this.afterEdit(this.history[0].rect);
+ this.histIndex = 1;
+ } else {
+ this.histIndex++;
+ }
+ console.log("History idx: " + this.histIndex);
+ return this.restore(this.history[this.histIndex]);
+ };
+
+ Document.prototype.redo = function() {
+ if (this.histIndex <= 0) {
+ return;
+ }
+ this.histIndex--;
+ console.log("History idx: " + this.histIndex);
+ return this.restore(this.history[this.histIndex]);
+ };
+
+ Document.prototype.restore = function(histItem) {
+ return this.layer.setData(histItem.data, histItem.rect);
+ };
+
return Document;
})();
@@ -146,6 +194,7 @@ DocumentView = (function() {
e.preventDefault();
if (e.which === 1) {
_this.drawing = true;
+ _this.actionDirtyRect = null;
coords = getCanvasCoords(e);
editor.getToolObject().beginDraw(coords);
_this.onDraw(coords);
@@ -161,6 +210,9 @@ DocumentView = (function() {
if (e.which === 1) {
editor.getToolObject().endDraw(getCanvasCoords(e));
_this.drawing = false;
+ if (_this.actionDirtyRect != null) {
+ doc.afterEdit(_this.actionDirtyRect);
+ }
}
if (e.which === 2) {
return _this.panning = false;
@@ -207,7 +259,8 @@ DocumentView = (function() {
};
DocumentView.prototype.onDraw = function(pos) {
- var dirtyRects, layer, layerRect, pressure, r, tool, totalArea, xoff, yoff, _i, _j, _len, _len1, _ref, _ref1;
+ var dirtyRects, layer, layerRect, pressure, r, tool, totalArea, xoff, yoff, _i, _j, _len, _len1, _ref, _ref1,
+ _this = this;
pressure = getPenPressure();
dirtyRects = [];
layer = this.doc.layer;
@@ -232,6 +285,13 @@ DocumentView = (function() {
}).filter(function(r) {
return !r.isEmpty();
});
+ dirtyRects.forEach(function(r) {
+ if (_this.actionDirtyRect == null) {
+ return _this.actionDirtyRect = r.clone();
+ } else {
+ return _this.actionDirtyRect.extend(r);
+ }
+ });
if (false) {
totalArea = dirtyRects.map(function(r) {
return r.width * r.height;
@@ -520,7 +580,17 @@ $(window).keydown(function(e) {
$(window).keyup(function(e) {
if (e.key === 'Control') {
- return editor.set('altkeyDown', false);
+ editor.set('altkeyDown', false);
+ }
+ if (e.ctrlKey) {
+ switch (e.keyCode) {
+ case 90:
+ editor.get('doc').undo();
+ return editor.refresh();
+ case 89:
+ editor.get('doc').redo();
+ return editor.refresh();
+ }
}
});
View
29 js/core.coffee
@@ -64,6 +64,9 @@ class Rect
ret.extend(rect.bottomRight())
return ret
+ clone: ->
+ return new Rect(@x, @y, @width, @height)
+
offset: (vec)->
return new Rect(@x+vec.x, @y+vec.y, @width, @height)
@@ -110,10 +113,10 @@ class Layer
constructor: (@width, @height) ->
@data = new FloatBuffer(@width, @height)
- getRect: () ->
+ getRect: ->
return new Rect(0,0,@width,@height)
- getBuffer: () ->
+ getBuffer: ->
return @data.fbuffer
getAt: (pos)->
@@ -124,6 +127,28 @@ class Layer
p = pos.round()
fb = @data.fbuffer
+ getCopy: (rect)->
+ srcData = @data.buffer
+ dstData = new ArrayBuffer(rect.width * rect.height * 4)
+ `
+ for(var iy=0; iy<rect.height; ++iy) {
+ var src = new Uint32Array(srcData, 4 * ((iy + rect.y) * this.width + rect.x), rect.width);
+ var dst = new Uint32Array(dstData, 4 * iy * rect.width, rect.width);
+ dst.set(src);
+ }`
+ return dstData
+
+ setData: (buffer, rect)->
+ dstData = @data.buffer
+ `
+ for(var iy=0; iy<rect.height; ++iy) {
+ var src = new Uint32Array(buffer, 4 * iy * rect.width, rect.width);
+ var dstOff = 4 * ((iy + rect.y) * this.width + rect.x);
+ var dst = new Uint32Array(dstData, dstOff, rect.width);
+ dst.set(src);
+ }`
+ return
+
Bezier =
quadratic: (pts, t)->
lerp = (a, b, t) ->
View
29 js/core.js
@@ -126,6 +126,10 @@ Rect = (function() {
return ret;
};
+ Rect.prototype.clone = function() {
+ return new Rect(this.x, this.y, this.width, this.height);
+ };
+
Rect.prototype.offset = function(vec) {
return new Rect(this.x + vec.x, this.y + vec.y, this.width, this.height);
};
@@ -211,6 +215,31 @@ Layer = (function() {
return fb = this.data.fbuffer;
};
+ Layer.prototype.getCopy = function(rect) {
+ var dstData, srcData;
+ srcData = this.data.buffer;
+ dstData = new ArrayBuffer(rect.width * rect.height * 4);
+
+ for(var iy=0; iy<rect.height; ++iy) {
+ var src = new Uint32Array(srcData, 4 * ((iy + rect.y) * this.width + rect.x), rect.width);
+ var dst = new Uint32Array(dstData, 4 * iy * rect.width, rect.width);
+ dst.set(src);
+ };
+ return dstData;
+ };
+
+ Layer.prototype.setData = function(buffer, rect) {
+ var dstData;
+ dstData = this.data.buffer;
+
+ for(var iy=0; iy<rect.height; ++iy) {
+ var src = new Uint32Array(buffer, 4 * iy * rect.width, rect.width);
+ var dstOff = 4 * ((iy + rect.y) * this.width + rect.x);
+ var dst = new Uint32Array(dstData, dstOff, rect.width);
+ dst.set(src);
+ };
+ };
+
return Layer;
})();

0 comments on commit b6d8d6f

Please sign in to comment.
Something went wrong with that request. Please try again.