mirror of
https://github.com/lospec/pixel-editor.git
synced 2023-08-10 21:12:51 +03:00
Refactored History into an IIFE
Divided History states and actual History management, refactored all occurrences of history-related functions to use the new version.
This commit is contained in:
parent
e4ecc3d607
commit
6c8ec8e7a9
@ -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();
|
||||
|
484
js/History.js
Normal file
484
js/History.js
Normal file
@ -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<layers.length; i++) {
|
||||
if (layers[i].menuEntry != null) {
|
||||
layers[i].context.putImageData(this.oldData[layerIndex], 0, 0);
|
||||
layerIndex++;
|
||||
layers[i].updateLayerPreview();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
currentAlgo = algo;
|
||||
resizeSprite(null, [this.xRatio, this.yRatio]);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
ResizeCanvas: function (newSize, oldSize, imageDatas, trim) {
|
||||
this.oldSize = oldSize;
|
||||
this.newSize = newSize;
|
||||
this.imageDatas = imageDatas;
|
||||
this.trim = trim;
|
||||
|
||||
this.undo = function() {
|
||||
let dataIndex = 0;
|
||||
// Resizing the canvas
|
||||
resizeCanvas(null, oldSize, null, false);
|
||||
// Putting the image datas
|
||||
for (let i=0; i<layers.length; i++) {
|
||||
if (layers[i].menuEntry != null) {
|
||||
layers[i].context.putImageData(this.imageDatas[dataIndex], 0, 0);
|
||||
dataIndex++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
if (!this.trim) {
|
||||
resizeCanvas(null, newSize, null, false);
|
||||
}
|
||||
else {
|
||||
trimCanvas(null, false);
|
||||
}
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
FlattenVisible: function(flattened) {
|
||||
this.nFlattened = flattened;
|
||||
|
||||
this.undo = function() {
|
||||
for (let i=0; i<this.nFlattened; i++) {
|
||||
undo();
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
for (let i=0; i<this.nFlattened; i++) {
|
||||
redo();
|
||||
}
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
FlattenTwoVisibles: function(belowImageData, afterAbove, layerIndex, aboveLayer, belowLayer) {
|
||||
this.aboveLayer = aboveLayer;
|
||||
this.belowLayer = belowLayer;
|
||||
this.belowImageData = belowImageData;
|
||||
|
||||
this.undo = function() {
|
||||
canvasView.append(aboveLayer.canvas);
|
||||
layerList.insertBefore(aboveLayer.menuEntry, afterAbove);
|
||||
|
||||
belowLayer.context.clearRect(0, 0, belowLayer.canvasSize[0], belowLayer.canvasSize[1]);
|
||||
belowLayer.context.putImageData(this.belowImageData, 0, 0);
|
||||
belowLayer.updateLayerPreview();
|
||||
|
||||
layers.splice(layerIndex, 0, aboveLayer);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
mergeLayers(belowLayer.context, aboveLayer.context);
|
||||
|
||||
// Deleting the above layer
|
||||
aboveLayer.canvas.remove();
|
||||
aboveLayer.menuEntry.remove();
|
||||
layers.splice(layers.indexOf(aboveLayer), 1);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
FlattenAll: function(nFlattened) {
|
||||
this.nFlattened = nFlattened;
|
||||
|
||||
this.undo = function() {
|
||||
for (let i=0; i<this.nFlattened - nAppLayers; i++) {
|
||||
undo();
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
for (let i=0; i<this.nFlattened - nAppLayers; i++) {
|
||||
redo();
|
||||
}
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
MergeLayer: function(aboveIndex, aboveLayer, belowData, belowLayer) {
|
||||
this.aboveIndex = aboveIndex;
|
||||
this.belowData = belowData;
|
||||
this.aboveLayer = aboveLayer;
|
||||
this.belowLayer = belowLayer;
|
||||
|
||||
this.undo = function() {
|
||||
layerList.insertBefore(this.aboveLayer.menuEntry, this.belowLayer.menuEntry);
|
||||
canvasView.append(this.aboveLayer.canvas);
|
||||
|
||||
belowLayer.context.clearRect(0, 0, this.belowLayer.canvasSize[0], this.belowLayer.canvasSize[1]);
|
||||
belowLayer.context.putImageData(this.belowData, 0, 0);
|
||||
belowLayer.updateLayerPreview();
|
||||
|
||||
layers.splice(this.aboveIndex, 0, this.aboveLayer);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
aboveLayer.selectLayer();
|
||||
merge(false);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
RenameLayer: function(oldName, newName, layer) {
|
||||
this.edited = layer;
|
||||
this.oldName = oldName;
|
||||
this.newName = newName;
|
||||
|
||||
this.undo = function() {
|
||||
layer.menuEntry.getElementsByTagName("p")[0].innerHTML = oldName;
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
layer.menuEntry.getElementsByTagName("p")[0].innerHTML = newName;
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
DuplicateLayer: function(addedLayer, copiedLayer) {
|
||||
this.addedLayer = addedLayer;
|
||||
this.copiedLayer = copiedLayer;
|
||||
|
||||
this.undo = function() {
|
||||
addedLayer.selectLayer();
|
||||
deleteLayer(false);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
copiedLayer.selectLayer();
|
||||
duplicateLayer(null, false);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
DeleteLayer: function(layerData, before, index) {
|
||||
this.deleted = layerData;
|
||||
this.before = before;
|
||||
this.index = index;
|
||||
|
||||
this.undo = function() {
|
||||
canvasView.append(this.deleted.canvas);
|
||||
if (this.before != null) {
|
||||
layerList.insertBefore(this.deleted.menuEntry, this.before);
|
||||
}
|
||||
else {
|
||||
layerList.prepend(this.deleted.menuEntry);
|
||||
}
|
||||
layers.splice(this.index, 0, this.deleted);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
this.deleted.selectLayer();
|
||||
deleteLayer(false);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
MoveTwoLayers: function(layer, oldIndex, newIndex) {
|
||||
this.layer = layer;
|
||||
this.oldIndex = oldIndex;
|
||||
this.newIndex = newIndex;
|
||||
|
||||
this.undo = function() {
|
||||
layer.canvas.style.zIndex = oldIndex;
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
layer.canvas.style.zIndex = newIndex;
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
MoveLayer: function(afterToDrop, toDrop, staticc, nMoved) {
|
||||
this.beforeToDrop = afterToDrop;
|
||||
this.toDrop = toDrop;
|
||||
|
||||
this.undo = function() {
|
||||
toDrop.menuEntry.remove();
|
||||
|
||||
if (afterToDrop != null) {
|
||||
layerList.insertBefore(toDrop.menuEntry, afterToDrop)
|
||||
}
|
||||
else {
|
||||
layerList.append(toDrop.menuEntry);
|
||||
}
|
||||
|
||||
for (let i=0; i<nMoved; i++) {
|
||||
undo();
|
||||
}
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
moveLayers(toDrop.menuEntry.id, staticc.menuEntry.id, true);
|
||||
};
|
||||
|
||||
History.saveHistoryState(this);
|
||||
},
|
||||
|
||||
AddLayer: function(layerData, index) {
|
||||
this.added = layerData;
|
||||
this.index = index;
|
||||
|
||||
this.undo = function() {
|
||||
if (layers.length - nAppLayers > 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
|
||||
|
529
js/_history.js
529
js/_history.js
@ -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<layers.length; i++) {
|
||||
if (layers[i].menuEntry != null) {
|
||||
layers[i].context.putImageData(this.oldData[layerIndex], 0, 0);
|
||||
layerIndex++;
|
||||
layers[i].updateLayerPreview();
|
||||
}
|
||||
}
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
console.log("REDOOOO");
|
||||
console.log("Ratio: " + this.xRatio + "," + this.yRatio);
|
||||
currentAlgo = algo;
|
||||
resizeSprite(null, [this.xRatio, this.yRatio]);
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateResizeCanvas(newSize, oldSize, imageDatas, trim) {
|
||||
this.oldSize = oldSize;
|
||||
this.newSize = newSize;
|
||||
this.imageDatas = imageDatas;
|
||||
this.trim = trim;
|
||||
|
||||
this.undo = function() {
|
||||
let dataIndex = 0;
|
||||
// Resizing the canvas
|
||||
resizeCanvas(null, oldSize, null, false);
|
||||
// Putting the image datas
|
||||
for (let i=0; i<layers.length; i++) {
|
||||
if (layers[i].menuEntry != null) {
|
||||
layers[i].context.putImageData(this.imageDatas[dataIndex], 0, 0);
|
||||
dataIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
if (!this.trim) {
|
||||
resizeCanvas(null, newSize, null, false);
|
||||
}
|
||||
else {
|
||||
trimCanvas(null, false);
|
||||
}
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateFlattenVisible(flattened) {
|
||||
this.nFlattened = flattened;
|
||||
|
||||
this.undo = function() {
|
||||
for (let i=0; i<this.nFlattened; i++) {
|
||||
undo();
|
||||
}
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
for (let i=0; i<this.nFlattened; i++) {
|
||||
redo();
|
||||
}
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateFlattenTwoVisibles(belowImageData, afterAbove, layerIndex, aboveLayer, belowLayer) {
|
||||
this.aboveLayer = aboveLayer;
|
||||
this.belowLayer = belowLayer;
|
||||
this.belowImageData = belowImageData;
|
||||
|
||||
this.undo = function() {
|
||||
canvasView.append(aboveLayer.canvas);
|
||||
layerList.insertBefore(aboveLayer.menuEntry, afterAbove);
|
||||
|
||||
belowLayer.context.clearRect(0, 0, belowLayer.canvasSize[0], belowLayer.canvasSize[1]);
|
||||
belowLayer.context.putImageData(this.belowImageData, 0, 0);
|
||||
belowLayer.updateLayerPreview();
|
||||
|
||||
layers.splice(layerIndex, 0, aboveLayer);
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
mergeLayers(belowLayer.context, aboveLayer.context);
|
||||
|
||||
// Deleting the above layer
|
||||
aboveLayer.canvas.remove();
|
||||
aboveLayer.menuEntry.remove();
|
||||
layers.splice(layers.indexOf(aboveLayer), 1);
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateFlattenAll(nFlattened) {
|
||||
this.nFlattened = nFlattened;
|
||||
|
||||
this.undo = function() {
|
||||
for (let i=0; i<this.nFlattened - nAppLayers; i++) {
|
||||
undo();
|
||||
}
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
for (let i=0; i<this.nFlattened - nAppLayers; i++) {
|
||||
redo();
|
||||
}
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateMergeLayer(aboveIndex, aboveLayer, belowData, belowLayer) {
|
||||
this.aboveIndex = aboveIndex;
|
||||
this.belowData = belowData;
|
||||
this.aboveLayer = aboveLayer;
|
||||
this.belowLayer = belowLayer;
|
||||
|
||||
this.undo = function() {
|
||||
layerList.insertBefore(this.aboveLayer.menuEntry, this.belowLayer.menuEntry);
|
||||
canvasView.append(this.aboveLayer.canvas);
|
||||
|
||||
belowLayer.context.clearRect(0, 0, this.belowLayer.canvasSize[0], this.belowLayer.canvasSize[1]);
|
||||
belowLayer.context.putImageData(this.belowData, 0, 0);
|
||||
belowLayer.updateLayerPreview();
|
||||
|
||||
layers.splice(this.aboveIndex, 0, this.aboveLayer);
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
aboveLayer.selectLayer();
|
||||
merge(false);
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateRenameLayer(oldName, newName, layer) {
|
||||
this.edited = layer;
|
||||
this.oldName = oldName;
|
||||
this.newName = newName;
|
||||
|
||||
this.undo = function() {
|
||||
layer.menuEntry.getElementsByTagName("p")[0].innerHTML = oldName;
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
layer.menuEntry.getElementsByTagName("p")[0].innerHTML = newName;
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateDuplicateLayer(addedLayer, copiedLayer) {
|
||||
this.addedLayer = addedLayer;
|
||||
this.copiedLayer = copiedLayer;
|
||||
|
||||
this.undo = function() {
|
||||
addedLayer.selectLayer();
|
||||
deleteLayer(false);
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
copiedLayer.selectLayer();
|
||||
duplicateLayer(null, false);
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateDeleteLayer(layerData, before, index) {
|
||||
this.deleted = layerData;
|
||||
this.before = before;
|
||||
this.index = index;
|
||||
|
||||
this.undo = function() {
|
||||
canvasView.append(this.deleted.canvas);
|
||||
if (this.before != null) {
|
||||
layerList.insertBefore(this.deleted.menuEntry, this.before);
|
||||
}
|
||||
else {
|
||||
layerList.prepend(this.deleted.menuEntry);
|
||||
}
|
||||
layers.splice(this.index, 0, this.deleted);
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
this.deleted.selectLayer();
|
||||
deleteLayer(false);
|
||||
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateMoveTwoLayers(layer, oldIndex, newIndex) {
|
||||
this.layer = layer;
|
||||
this.oldIndex = oldIndex;
|
||||
this.newIndex = newIndex;
|
||||
|
||||
this.undo = function() {
|
||||
layer.canvas.style.zIndex = oldIndex;
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
layer.canvas.style.zIndex = newIndex;
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateMoveLayer(afterToDrop, toDrop, staticc, nMoved) {
|
||||
this.beforeToDrop = afterToDrop;
|
||||
this.toDrop = toDrop;
|
||||
|
||||
this.undo = function() {
|
||||
toDrop.menuEntry.remove();
|
||||
|
||||
if (afterToDrop != null) {
|
||||
layerList.insertBefore(toDrop.menuEntry, afterToDrop)
|
||||
}
|
||||
else {
|
||||
layerList.append(toDrop.menuEntry);
|
||||
}
|
||||
|
||||
for (let i=0; i<nMoved; i++) {
|
||||
undo();
|
||||
}
|
||||
|
||||
redoStates.push(this);
|
||||
};
|
||||
|
||||
this.redo = function() {
|
||||
moveLayers(toDrop.menuEntry.id, staticc.menuEntry.id, true);
|
||||
undoStates.push(this);
|
||||
};
|
||||
|
||||
saveHistoryState(this);
|
||||
}
|
||||
|
||||
function HistoryStateAddLayer(layerData, index) {
|
||||
this.added = layerData;
|
||||
this.index = index;
|
||||
|
||||
this.undo = function() {
|
||||
|
||||
redoStates.push(this);
|
||||
if (layers.length - nAppLayers > 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
14
js/_layer.js
14
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<visibleLayers.length - 1; i++) {
|
||||
nToFlatten++;
|
||||
console.log(visibleLayers[i].menuEntry.nextElementSibling);
|
||||
new HistoryStateFlattenTwoVisibles(
|
||||
new HistoryStates.FlattenTwoVisibles(
|
||||
visibleLayers[i + 1].context.getImageData(0, 0, visibleLayers[i].canvasSize[0], visibleLayers[i].canvasSize[1]),
|
||||
visibleLayers[i].menuEntry.nextElementSibling,
|
||||
layers.indexOf(visibleLayers[i]),
|
||||
@ -347,7 +347,7 @@ function flatten(onlyVisible) {
|
||||
layers.splice(layers.indexOf(visibleLayers[i]), 1);
|
||||
}
|
||||
|
||||
new HistoryStateFlattenVisible(nToFlatten);
|
||||
new HistoryStates.FlattenVisible(nToFlatten);
|
||||
// Updating the layer preview
|
||||
currentLayer.updateLayerPreview();
|
||||
}
|
||||
@ -410,7 +410,7 @@ function deleteLayer(saveHistory = true) {
|
||||
layers.splice(layerIndex, 1);
|
||||
|
||||
if (saveHistory) {
|
||||
new HistoryStateDeleteLayer(toDelete, previousSibling, layerIndex);
|
||||
new HistoryStates.DeleteLayer(toDelete, previousSibling, layerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,7 +463,7 @@ function duplicateLayer(event, saveHistory = true) {
|
||||
newLayer.updateLayerPreview();
|
||||
// Basically "if I'm not adding a layer because redo() is telling meto do so", then I can save the history
|
||||
if (saveHistory) {
|
||||
new HistoryStateDuplicateLayer(newLayer, currentLayer);
|
||||
new HistoryStates.DuplicateLayer(newLayer, currentLayer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,7 +556,7 @@ function addLayer(id, saveHistory = true) {
|
||||
}
|
||||
// Basically "if I'm not adding a layer because redo() is telling meto do so", then I can save the history
|
||||
if (saveHistory) {
|
||||
new HistoryStateAddLayer(newLayer, index);
|
||||
new HistoryStates.AddLayer(newLayer, index);
|
||||
}
|
||||
|
||||
return newLayer;
|
||||
|
@ -23,7 +23,7 @@ window.addEventListener("mousedown", function (mouseEvent) {
|
||||
currentTool = tool.eyedropper;
|
||||
else if (mouseEvent.target.className == 'drawingCanvas' &&
|
||||
(currentTool.name == 'pencil' || currentTool.name == 'eraser' || currentTool.name == 'rectangle' || currentTool.name == 'ellipse' || currentTool.name === 'line'))
|
||||
new HistoryStateEditCanvas();
|
||||
new HistoryStates.EditCanvas();
|
||||
else if (currentTool.name == 'moveselection') {
|
||||
if (!cursorInSelectedArea() &&
|
||||
((mouseEvent.target.id == 'canvas-view') || mouseEvent.target.className == 'drawingCanvas')) {
|
||||
|
@ -106,5 +106,5 @@ function endSelection() {
|
||||
currentLayer.updateLayerPreview();
|
||||
|
||||
// Saving the history
|
||||
new HistoryStateEditCanvas();
|
||||
new HistoryStates.EditCanvas();
|
||||
}
|
@ -10,7 +10,7 @@ let endY;
|
||||
*/
|
||||
function startRectSelection(mouseEvent) {
|
||||
// Saving the canvas
|
||||
new HistoryStateEditCanvas();
|
||||
new HistoryStates.EditCanvas();
|
||||
// Putting the vfx layer on top of everything
|
||||
VFXCanvas.style.zIndex = MAX_Z_INDEX;
|
||||
|
||||
|
@ -116,7 +116,7 @@ function resizeCanvas(event, size, customData, saveHistory = true) {
|
||||
// Saving the history only if I'm not already undoing or redoing
|
||||
if (saveHistory && event != null) {
|
||||
// Saving history
|
||||
new HistoryStateResizeCanvas(
|
||||
new HistoryStates.ResizeCanvas(
|
||||
{x: parseInt(layers[0].canvasSize[0]) + rcBorders.left + rcBorders.right,
|
||||
y: parseInt(layers[0].canvasSize[1]) + rcBorders.top + rcBorders.bottom},
|
||||
|
||||
|
@ -121,7 +121,7 @@ function resizeSprite(event, ratio) {
|
||||
// Copying the image data
|
||||
imageDatasCopy = rsImageDatas.slice();
|
||||
// Saving the history
|
||||
new HistoryStateResizeSprite(newWidth / oldWidth, newHeight / oldHeight, currentAlgo, imageDatasCopy);
|
||||
new HistoryStates.ResizeSprite(newWidth / oldWidth, newHeight / oldHeight, currentAlgo, imageDatasCopy);
|
||||
}
|
||||
|
||||
// Resizing the canvas
|
||||
|
@ -6,6 +6,7 @@
|
||||
//=include Input.js
|
||||
//=include Color.js
|
||||
//=include Dialogue.js
|
||||
//=include History.js
|
||||
|
||||
/**init**/
|
||||
//=include _consts.js
|
||||
@ -29,7 +30,6 @@
|
||||
//=include _getCursorPosition.js
|
||||
//=include _fill.js
|
||||
//=include _line.js
|
||||
//=include _history.js
|
||||
//=include _checkerboard.js
|
||||
//=include _pixelGrid.js
|
||||
//=include _layer.js
|
||||
|
Loading…
Reference in New Issue
Block a user