diff --git a/js/ColorModule.js b/js/ColorModule.js index 884c24e..80fdfb3 100644 --- a/js/ColorModule.js +++ b/js/ColorModule.js @@ -41,7 +41,7 @@ const ColorModule = (() => { newColor.a = 255; //save undo state - new HistoryStateEditColor(hexElementValue.toLowerCase(), Color.rgbToHex(oldColor)); + new HistoryStates.EditColor(hexElementValue.toLowerCase(), Color.rgbToHex(oldColor)); //get the currently selected color const currentlyEditedColor = document.getElementsByClassName('jscolor-active')[0]; @@ -138,7 +138,7 @@ const ColorModule = (() => { currentLayer.context.fillStyle = '#' + newColor; //add history state - new HistoryStateAddColor(addedColor.firstElementChild.jscolor.toString()); + new HistoryStates.AddColor(addedColor.firstElementChild.jscolor.toString()); //show color picker addedColor.firstElementChild.jscolor.show(); diff --git a/js/History.js b/js/History.js new file mode 100644 index 0000000..2fd6dd6 --- /dev/null +++ b/js/History.js @@ -0,0 +1,484 @@ +/** How the history works + * - undoStates stores the states that can be undone + * - redoStates stores the states that can be redone + * - undo() undoes an action and adds it to the redoStates + * - redo() redoes an action and adds it to the undoStates + * - Each HistoryState must implement an undo() and redo() function + * Those functions actually implement the undo and redo mechanism for that action, + * so you'll need to save the data you need as attributes in the constructor. For example, + * for the HistoryStateAddColour, the added colour is saved so that it can be removed in + * undo() or added back in redo(). + * - Each HistoryState must call saveHistoryState(this) so that it gets added to the stack + * + */ + +const History = (() => { + + const undoLogStyle = 'background: #87ff1c; color: black; padding: 5px;'; + let undoStates = []; + let redoStates = []; + + //rename to add undo state + function saveHistoryState (state) { + //get current canvas data and save to undoStates array + undoStates.push(state); + + //limit the number of states to settings.numberOfHistoryStates + if (undoStates.length > settings.numberOfHistoryStates) { + undoStates = undoStates.splice(-settings.numberOfHistoryStates, settings.numberOfHistoryStates); + } + + //there is now definitely at least 1 undo state, so the button shouldnt be disabled + document.getElementById('undo-button').classList.remove('disabled'); + + //there should be no redoStates after an undoState is saved + redoStates = []; + } + + function undo () { + //if there are any states saved to undo + if (undoStates.length > 0) { + document.getElementById('redo-button').classList.remove('disabled'); + + // get state + var undoState = undoStates[undoStates.length-1]; + // add it to redo states + redoStates.push(undoState); + + //remove from the undo list + undoStates.splice(undoStates.length-1,1); + + //restore the state + undoState.undo(); + + //if theres none left to undo, disable the option + if (undoStates.length == 0) + document.getElementById('undo-button').classList.add('disabled'); + } + } + + function redo () { + console.log("Redo"); + if (redoStates.length > 0) { + + //enable undo button + document.getElementById('undo-button').classList.remove('disabled'); + + //get state + var redoState = redoStates[redoStates.length-1]; + // Add it to undo states + undoStates.push(redoState); + + //remove from redo array (do this before restoring the state, else the flatten state will break) + redoStates.splice(redoStates.length-1,1); + + //restore the state + redoState.redo(); + + //if theres none left to redo, disable the option + if (redoStates.length == 0) + document.getElementById('redo-button').classList.add('disabled'); + } + } + + return { + redo, + undo, + saveHistoryState + } +})(); + +const HistoryStates = { + ResizeSprite: function(xRatio, yRatio, algo, oldData) { + this.xRatio = xRatio; + this.yRatio = yRatio; + this.algo = algo; + this.oldData = oldData; + + this.undo = function() { + let layerIndex = 0; + + currentAlgo = algo; + resizeSprite(null, [1 / this.xRatio, 1 / this.yRatio]); + + // Also putting the old data + for (let i=0; i this.index + 1) { + layers[this.index + 1].selectLayer(); + } + else { + layers[this.index - 1].selectLayer(); + } + + this.added.canvas.remove(); + this.added.menuEntry.remove(); + + layers.splice(index, 1); + }; + + this.redo = function() { + canvasView.append(this.added.canvas); + layerList.prepend(this.added.menuEntry); + layers.splice(this.index, 0, this.added); + }; + + History.saveHistoryState(this); + }, + + //prototype for undoing canvas changes + EditCanvas: function() { + this.canvasState = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + this.layerID = currentLayer.id; + + this.undo = function () { + var stateLayer = getLayerByID(this.layerID); + var currentCanvas = stateLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + stateLayer.context.putImageData(this.canvasState, 0, 0); + + this.canvasState = currentCanvas; + + stateLayer.updateLayerPreview(); + }; + + this.redo = function () { + var stateLayer = getLayerByID(this.layerID); + var currentCanvas = stateLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + + stateLayer.context.putImageData(this.canvasState, 0, 0); + + this.canvasState = currentCanvas; + + stateLayer.updateLayerPreview(); + }; + + //add self to undo array + History.saveHistoryState(this); + }, + + //prototype for undoing added colors + AddColor: function(colorValue) { + this.colorValue = colorValue; + + this.undo = function () { + ColorModule.deleteColor(this.colorValue); + }; + + this.redo = function () { + ColorModule.addColor(this.colorValue); + }; + + //add self to undo array + History.saveHistoryState(this); + }, + + //prototype for undoing deleted colors + DeleteColor: function(colorValue) { + this.colorValue = colorValue; + this.canvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + + this.undo = function () { + var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + currentLayer.context.putImageData(this.canvas, 0, 0); + + ColorModule.addColor(this.colorValue); + + this.canvas = currentCanvas; + }; + + this.redo = function () { + var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + currentLayer.context.putImageData(this.canvas, 0, 0); + + ColorModule.deleteColor(this.colorValue); + + this.canvas = currentCanvas; + }; + + //add self to undo array + History.saveHistoryState(this); + }, + + //prototype for undoing colors edits + EditColor: function(newColorValue, oldColorValue) { + this.newColorValue = newColorValue; + this.oldColorValue = oldColorValue; + this.canvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + + this.undo = function () { + var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + currentLayer.context.putImageData(this.canvas, 0, 0); + + //find new color in palette and change it back to old color + var colors = document.getElementsByClassName('color-button'); + for (var i = 0; i < colors.length; i++) { + //console.log(newColorValue, '==', colors[i].jscolor.toString()); + if (newColorValue == colors[i].jscolor.toString()) { + colors[i].jscolor.fromString(oldColorValue); + break; + } + } + + this.canvas = currentCanvas; + }; + + this.redo = function () { + var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); + currentLayer.context.putImageData(this.canvas, 0, 0); + + //find old color in palette and change it back to new color + var colors = document.getElementsByClassName('color-button'); + for (var i = 0; i < colors.length; i++) { + //console.log(oldColorValue, '==', colors[i].jscolor.toString()); + if (oldColorValue == colors[i].jscolor.toString()) { + colors[i].jscolor.fromString(newColorValue); + break; + } + } + + this.canvas = currentCanvas; + }; + + //add self to undo array + History.saveHistoryState(this); + } +} \ No newline at end of file diff --git a/js/_fileMenu.js b/js/_fileMenu.js index 912c917..144b15d 100644 --- a/js/_fileMenu.js +++ b/js/_fileMenu.js @@ -139,10 +139,10 @@ for (var i = 1; i < mainMenuItems.length; i++) { break; //Edit Menu case 'Undo': - undo(); + History.undo(); break; case 'Redo': - redo(); + History.redo(); break; //Palette Menu diff --git a/js/_fill.js b/js/_fill.js index 266c364..e46a89b 100644 --- a/js/_fill.js +++ b/js/_fill.js @@ -22,7 +22,7 @@ function fill(cursorLocation) { } //save history state - new HistoryStateEditCanvas(); + new HistoryStates.EditCanvas(); //saveHistoryState({type: 'canvas', canvas: context.getImageData(0, 0, canvasSize[0], canvasSize[1])}); //console.log('filling at '+ Math.floor(cursorLocation[0]/zoom) + ','+ Math.floor(cursorLocation[1]/zoom)); diff --git a/js/_history.js b/js/_history.js deleted file mode 100644 index 52d6bfb..0000000 --- a/js/_history.js +++ /dev/null @@ -1,529 +0,0 @@ -/** How the history works - * - undoStates stores the states that can be undone - * - redoStates stores the states that can be redone - * - undo() undoes an action and adds it to the redoStates - * - redo() redoes an action and adds it to the undoStates - * - Each HistoryState must implement an undo() and redo() function - * Those functions actually implement the undo and redo mechanism for that action, - * so you'll need to save the data you need as attributes in the constructor. For example, - * for the HistoryStateAddColour, the added colour is saved so that it can be removed in - * undo() or added back in redo(). - * - Each HistoryState must call saveHistoryState(this) so that it gets added to the stack - * - */ - -var undoStates = []; -var redoStates = []; - -const undoLogStyle = 'background: #87ff1c; color: black; padding: 5px;'; - -function HistoryStateResizeSprite(xRatio, yRatio, algo, oldData) { - this.xRatio = xRatio; - this.yRatio = yRatio; - this.algo = algo; - this.oldData = oldData; - - this.undo = function() { - let layerIndex = 0; - - currentAlgo = algo; - resizeSprite(null, [1 / this.xRatio, 1 / this.yRatio]); - - // Also putting the old data - for (let i=0; i this.index + 1) { - layers[this.index + 1].selectLayer(); - } - else { - layers[this.index - 1].selectLayer(); - } - - - this.added.canvas.remove(); - this.added.menuEntry.remove(); - - layers.splice(index, 1); - }; - - this.redo = function() { - undoStates.push(this); - - canvasView.append(this.added.canvas); - layerList.prepend(this.added.menuEntry); - layers.splice(this.index, 0, this.added); - }; - - saveHistoryState(this); -} - -//prototype for undoing canvas changes -function HistoryStateEditCanvas () { - this.canvasState = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - this.layerID = currentLayer.id; - - this.undo = function () { - var stateLayer = getLayerByID(this.layerID); - var currentCanvas = stateLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - stateLayer.context.putImageData(this.canvasState, 0, 0); - - this.canvasState = currentCanvas; - redoStates.push(this); - - stateLayer.updateLayerPreview(); - }; - - this.redo = function () { - console.log("YEET"); - var stateLayer = getLayerByID(this.layerID); - var currentCanvas = stateLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - - stateLayer.context.putImageData(this.canvasState, 0, 0); - - this.canvasState = currentCanvas; - undoStates.push(this); - - stateLayer.updateLayerPreview(); - }; - - //add self to undo array - saveHistoryState(this); -} - -//prototype for undoing added colors -function HistoryStateAddColor (colorValue) { - this.colorValue = colorValue; - - this.undo = function () { - redoStates.push(this); - ColorModule.deleteColor(this.colorValue); - }; - - this.redo = function () { - ColorModule.addColor(this.colorValue); - undoStates.push(this); - }; - - //add self to undo array - saveHistoryState(this); -} - -//prototype for undoing deleted colors -function HistoryStateDeleteColor (colorValue) { - this.colorValue = colorValue; - this.canvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - - this.undo = function () { - var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - currentLayer.context.putImageData(this.canvas, 0, 0); - - ColorModule.addColor(this.colorValue); - - this.canvas = currentCanvas; - redoStates.push(this); - }; - - this.redo = function () { - var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - currentLayer.context.putImageData(this.canvas, 0, 0); - - ColorModule.deleteColor(this.colorValue); - - this.canvas = currentCanvas; - undoStates.push(this); - }; - - //add self to undo array - saveHistoryState(this); -} - -//prototype for undoing colors edits -function HistoryStateEditColor (newColorValue, oldColorValue) { - this.newColorValue = newColorValue; - this.oldColorValue = oldColorValue; - this.canvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - - this.undo = function () { - var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - currentLayer.context.putImageData(this.canvas, 0, 0); - - //find new color in palette and change it back to old color - var colors = document.getElementsByClassName('color-button'); - for (var i = 0; i < colors.length; i++) { - //console.log(newColorValue, '==', colors[i].jscolor.toString()); - if (newColorValue == colors[i].jscolor.toString()) { - colors[i].jscolor.fromString(oldColorValue); - break; - } - } - - this.canvas = currentCanvas; - redoStates.push(this); - }; - - this.redo = function () { - var currentCanvas = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]); - currentLayer.context.putImageData(this.canvas, 0, 0); - - //find old color in palette and change it back to new color - var colors = document.getElementsByClassName('color-button'); - for (var i = 0; i < colors.length; i++) { - //console.log(oldColorValue, '==', colors[i].jscolor.toString()); - if (oldColorValue == colors[i].jscolor.toString()) { - colors[i].jscolor.fromString(newColorValue); - break; - } - } - - this.canvas = currentCanvas; - undoStates.push(this); - }; - - //add self to undo array - saveHistoryState(this); -} - - -//rename to add undo state -function saveHistoryState (state) { - //get current canvas data and save to undoStates array - undoStates.push(state); - - //limit the number of states to settings.numberOfHistoryStates - if (undoStates.length > settings.numberOfHistoryStates) { - undoStates = undoStates.splice(-settings.numberOfHistoryStates, settings.numberOfHistoryStates); - } - - //there is now definitely at least 1 undo state, so the button shouldnt be disabled - document.getElementById('undo-button').classList.remove('disabled'); - - //there should be no redoStates after an undoState is saved - redoStates = []; -} - -function undo () { - //if there are any states saved to undo - if (undoStates.length > 0) { - document.getElementById('redo-button').classList.remove('disabled'); - - //get state - var undoState = undoStates[undoStates.length-1]; - //console.log(undoState); - - //remove from the undo list - undoStates.splice(undoStates.length-1,1); - - //restore the state - undoState.undo(); - - //if theres none left to undo, disable the option - if (undoStates.length == 0) - document.getElementById('undo-button').classList.add('disabled'); - } -} - -function redo () { - if (redoStates.length > 0) { - - //enable undo button - document.getElementById('undo-button').classList.remove('disabled'); - - //get state - var redoState = redoStates[redoStates.length-1]; - - //remove from redo array (do this before restoring the state, else the flatten state will break) - redoStates.splice(redoStates.length-1,1); - - //restore the state - redoState.redo(); - - //if theres none left to redo, disable the option - if (redoStates.length == 0) - document.getElementById('redo-button').classList.add('disabled'); - } - //console.log(undoStates); - //console.log(redoStates); -} diff --git a/js/_hotkeyListener.js b/js/_hotkeyListener.js index ecb74b8..8331ce2 100644 --- a/js/_hotkeyListener.js +++ b/js/_hotkeyListener.js @@ -90,13 +90,13 @@ function KeyPress(e) { case 90: //CTRL+ALT+Z redo if (keyboardEvent.altKey && keyboardEvent.ctrlKey) - redo(); + History.redo(); if (!selectionCanceled) { tool.pencil.switchTo() } //CTRL+Z undo else if (keyboardEvent.ctrlKey) { - undo(); + History.undo(); if (!selectionCanceled) { tool.pencil.switchTo() } @@ -107,9 +107,9 @@ function KeyPress(e) { break; //redo - ctrl y case 89: - if (keyboardEvent.ctrlKey) - redo(); - break; + if (keyboardEvent.ctrlKey) + History.redo(); + break; case 32: spacePressed=true; break; diff --git a/js/_jscolor.js b/js/_jscolor.js index e201f0a..7bcf99a 100644 --- a/js/_jscolor.js +++ b/js/_jscolor.js @@ -551,7 +551,7 @@ if (!window.jscolor) { window.jscolor = (function () { //if they clicked on the delete button [lospec] if (e.target.className == 'delete-color-button') { //saveHistoryState({type: 'deletecolor', colorValue: jsc.picker.owner.toString(), canvas: canvas.context.getImageData(0, 0, canvasSize[0], canvasSize[1])}); - new HistoryStateDeleteColor(jsc.picker.owner.toString()); + new HistoryStates.DeleteColor(jsc.picker.owner.toString()); ColorModule.deleteColor(jsc.picker.owner.styleElement); } diff --git a/js/_layer.js b/js/_layer.js index 0787620..b08e0d3 100644 --- a/js/_layer.js +++ b/js/_layer.js @@ -189,7 +189,7 @@ class Layer { let name = this.menuEntry.getElementsByTagName("p")[0].innerHTML; this.name = name; - new HistoryStateRenameLayer(oldLayerName, name, currentLayer); + new HistoryStates.RenameLayer(oldLayerName, name, currentLayer); oldLayerName = null; } } @@ -310,7 +310,7 @@ function flatten(onlyVisible) { merge(); } - new HistoryStateFlattenAll(nToFlatten); + new HistoryStates.FlattenAll(nToFlatten); } else { // Getting all the visible layers @@ -332,7 +332,7 @@ function flatten(onlyVisible) { for (let i=0; i