2019-03-27 02:20:54 +03:00
|
|
|
var undoStates = [];
|
|
|
|
var redoStates = [];
|
|
|
|
|
|
|
|
const undoLogStyle = 'background: #87ff1c; color: black; padding: 5px;';
|
|
|
|
|
2020-06-25 14:19:31 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-06-27 14:29:28 +03:00
|
|
|
function HistoryStateFlattenTwoVisibles(belowImageData, afterAbove, layerIndex, aboveLayer, belowLayer) {
|
2020-06-25 14:19:31 +03:00
|
|
|
this.aboveLayer = aboveLayer;
|
|
|
|
this.belowLayer = belowLayer;
|
|
|
|
this.belowImageData = belowImageData;
|
|
|
|
|
|
|
|
this.undo = function() {
|
2020-06-27 14:29:28 +03:00
|
|
|
console.log(afterAbove.menuEntry);
|
2020-06-25 14:19:31 +03:00
|
|
|
canvasView.append(aboveLayer.canvas);
|
2020-06-27 14:29:28 +03:00
|
|
|
layerList.insertBefore(aboveLayer.menuEntry, afterAbove);
|
2020-06-25 14:19:31 +03:00
|
|
|
|
|
|
|
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);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2020-06-25 13:10:34 +03:00
|
|
|
function HistoryStateFlattenAll(nFlattened) {
|
|
|
|
this.nFlattened = nFlattened;
|
|
|
|
|
|
|
|
this.undo = function() {
|
2020-06-25 14:19:31 +03:00
|
|
|
for (let i=0; i<this.nFlattened - 2; i++) {
|
2020-06-25 13:10:34 +03:00
|
|
|
undo();
|
|
|
|
}
|
|
|
|
|
|
|
|
redoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function() {
|
2020-06-25 14:19:31 +03:00
|
|
|
for (let i=0; i<this.nFlattened - 2; i++) {
|
2020-06-25 13:10:34 +03:00
|
|
|
redo();
|
|
|
|
}
|
|
|
|
|
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
saveHistoryState(this);
|
2020-06-25 00:40:49 +03:00
|
|
|
}
|
2020-06-23 19:10:10 +03:00
|
|
|
|
2020-06-25 12:40:47 +03:00
|
|
|
function HistoryStateMergeLayer(aboveIndex, aboveLayer, belowData, belowLayer) {
|
|
|
|
this.aboveIndex = aboveIndex;
|
|
|
|
this.belowData = belowData;
|
|
|
|
this.aboveLayer = aboveLayer;
|
|
|
|
this.belowLayer = belowLayer;
|
2020-06-25 13:10:34 +03:00
|
|
|
|
2020-06-25 12:40:47 +03:00
|
|
|
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);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2020-06-24 23:34:21 +03:00
|
|
|
function HistoryStateRenameLayer(oldName, newName, layer) {
|
|
|
|
this.edited = layer;
|
|
|
|
this.oldName = oldName;
|
|
|
|
this.newName = newName;
|
2020-06-23 19:10:10 +03:00
|
|
|
|
2020-06-24 23:34:21 +03:00
|
|
|
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);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2020-06-25 00:40:49 +03:00
|
|
|
function HistoryStateDeleteLayer(layerData, before, index) {
|
2020-06-24 23:34:21 +03:00
|
|
|
this.deleted = layerData;
|
2020-06-25 00:40:49 +03:00
|
|
|
this.before = before;
|
|
|
|
this.index = index;
|
2020-06-23 19:10:10 +03:00
|
|
|
|
2020-06-24 23:34:21 +03:00
|
|
|
this.undo = function() {
|
2020-06-25 00:40:49 +03:00
|
|
|
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);
|
|
|
|
|
2020-06-24 23:34:21 +03:00
|
|
|
redoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function() {
|
2020-06-25 00:40:49 +03:00
|
|
|
this.deleted.selectLayer();
|
|
|
|
deleteLayer(false);
|
|
|
|
|
2020-06-24 23:34:21 +03:00
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
saveHistoryState(this);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2020-06-26 18:38:39 +03:00
|
|
|
function HistoryStateMoveTwoLayers(layer, oldIndex, newIndex) {
|
|
|
|
this.layer = layer;
|
|
|
|
this.oldIndex = oldIndex;
|
|
|
|
this.newIndex = newIndex;
|
2020-06-23 19:10:10 +03:00
|
|
|
|
2020-06-24 14:30:24 +03:00
|
|
|
this.undo = function() {
|
2020-06-26 18:38:39 +03:00
|
|
|
layer.canvas.style.zIndex = oldIndex;
|
2020-06-24 14:30:24 +03:00
|
|
|
redoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function() {
|
2020-06-26 18:38:39 +03:00
|
|
|
layer.canvas.style.zIndex = newIndex;
|
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
saveHistoryState(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
function HistoryStateMoveLayer(afterToDrop, toDrop, static, 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, static.menuEntry.id, true);
|
2020-06-24 14:30:24 +03:00
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
saveHistoryState(this);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2020-06-25 00:40:49 +03:00
|
|
|
function HistoryStateAddLayer(layerData, index) {
|
2020-06-24 13:51:09 +03:00
|
|
|
this.added = layerData;
|
2020-06-25 00:40:49 +03:00
|
|
|
this.index = index;
|
2020-06-23 19:10:10 +03:00
|
|
|
|
2020-06-24 13:51:09 +03:00
|
|
|
this.undo = function() {
|
|
|
|
redoStates.push(this);
|
2020-06-24 23:34:21 +03:00
|
|
|
|
2020-06-25 00:40:49 +03:00
|
|
|
this.added.canvas.remove();
|
|
|
|
this.added.menuEntry.remove();
|
|
|
|
layers.splice(index, 1);
|
2020-06-24 13:51:09 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function() {
|
2020-06-25 00:40:49 +03:00
|
|
|
undoStates.push(this);
|
|
|
|
|
|
|
|
canvasView.append(this.added.canvas);
|
|
|
|
layerList.prepend(this.added.menuEntry);
|
|
|
|
layers.splice(this.index, 0, this.added);
|
2020-06-24 13:51:09 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
saveHistoryState(this);
|
2020-06-23 19:10:10 +03:00
|
|
|
}
|
|
|
|
|
2019-03-27 02:20:54 +03:00
|
|
|
//prototype for undoing canvas changes
|
|
|
|
function HistoryStateEditCanvas () {
|
2020-06-24 00:29:13 +03:00
|
|
|
this.canvasState = currentLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]);
|
|
|
|
this.layerID = currentLayer.id;
|
2020-04-04 10:41:56 +03:00
|
|
|
|
|
|
|
this.undo = function () {
|
2020-06-24 00:29:13 +03:00
|
|
|
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;
|
2020-04-04 10:41:56 +03:00
|
|
|
redoStates.push(this);
|
2020-06-19 16:16:22 +03:00
|
|
|
|
2020-06-24 00:29:13 +03:00
|
|
|
stateLayer.updateLayerPreview();
|
2020-04-04 10:41:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function () {
|
2020-06-24 14:30:24 +03:00
|
|
|
console.log("YEET");
|
2020-06-24 00:29:13 +03:00
|
|
|
var stateLayer = getLayerByID(this.layerID);
|
|
|
|
var currentCanvas = stateLayer.context.getImageData(0, 0, canvasSize[0], canvasSize[1]);
|
|
|
|
|
|
|
|
stateLayer.context.putImageData(this.canvasState, 0, 0);
|
2020-04-04 10:41:56 +03:00
|
|
|
|
2020-06-24 00:29:13 +03:00
|
|
|
this.canvasState = currentCanvas;
|
2020-04-04 10:41:56 +03:00
|
|
|
undoStates.push(this);
|
2020-06-19 16:16:22 +03:00
|
|
|
|
2020-06-24 14:30:24 +03:00
|
|
|
stateLayer.updateLayerPreview();
|
2020-04-04 10:41:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
//add self to undo array
|
|
|
|
saveHistoryState(this);
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//prototype for undoing added colors
|
|
|
|
function HistoryStateAddColor (colorValue) {
|
2020-04-04 10:41:56 +03:00
|
|
|
this.colorValue = colorValue;
|
|
|
|
|
|
|
|
this.undo = function () {
|
|
|
|
redoStates.push(this);
|
|
|
|
deleteColor(this.colorValue);
|
|
|
|
};
|
|
|
|
|
|
|
|
this.redo = function () {
|
|
|
|
addColor(this.colorValue);
|
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
//add self to undo array
|
|
|
|
saveHistoryState(this);
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//prototype for undoing deleted colors
|
|
|
|
function HistoryStateDeleteColor (colorValue) {
|
2020-04-04 10:41:56 +03:00
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
deleteColor(this.colorValue);
|
|
|
|
|
|
|
|
this.canvas = currentCanvas;
|
|
|
|
undoStates.push(this);
|
|
|
|
};
|
|
|
|
|
|
|
|
//add self to undo array
|
|
|
|
saveHistoryState(this);
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//prototype for undoing colors edits
|
|
|
|
function HistoryStateEditColor (newColorValue, oldColorValue) {
|
2020-04-04 10:41:56 +03:00
|
|
|
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++) {
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log(newColorValue, '==', colors[i].jscolor.toString());
|
2020-04-04 10:41:56 +03:00
|
|
|
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++) {
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log(oldColorValue, '==', colors[i].jscolor.toString());
|
2020-04-04 10:41:56 +03:00
|
|
|
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);
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//rename to add undo state
|
|
|
|
function saveHistoryState (state) {
|
2020-04-04 10:41:56 +03:00
|
|
|
//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 = [];
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function undo () {
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log('%cundo', undoLogStyle);
|
2020-04-04 10:41:56 +03:00
|
|
|
|
|
|
|
//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];
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log(undoState);
|
2020-04-04 10:41:56 +03:00
|
|
|
|
|
|
|
//remove from the undo list
|
|
|
|
undoStates.splice(undoStates.length-1,1);
|
|
|
|
|
2020-06-25 13:10:34 +03:00
|
|
|
//restore the state
|
|
|
|
undoState.undo();
|
|
|
|
|
2020-04-04 10:41:56 +03:00
|
|
|
//if theres none left to undo, disable the option
|
|
|
|
if (undoStates.length == 0)
|
|
|
|
document.getElementById('undo-button').classList.add('disabled');
|
|
|
|
}
|
2019-03-27 02:20:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function redo () {
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log('%credo', undoLogStyle);
|
2019-03-27 02:20:54 +03:00
|
|
|
|
2020-04-04 10:41:56 +03:00
|
|
|
if (redoStates.length > 0) {
|
2019-03-27 02:20:54 +03:00
|
|
|
|
2020-04-04 10:41:56 +03:00
|
|
|
//enable undo button
|
|
|
|
document.getElementById('undo-button').classList.remove('disabled');
|
|
|
|
|
|
|
|
//get state
|
|
|
|
var redoState = redoStates[redoStates.length-1];
|
2020-06-25 13:10:34 +03:00
|
|
|
|
|
|
|
//remove from redo array (do this before restoring the state, else the flatten state will break)
|
|
|
|
redoStates.splice(redoStates.length-1,1);
|
2020-04-04 10:41:56 +03:00
|
|
|
|
|
|
|
//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');
|
|
|
|
}
|
2020-06-06 22:44:52 +03:00
|
|
|
//console.log(undoStates);
|
|
|
|
//console.log(redoStates);
|
2020-04-04 10:41:56 +03:00
|
|
|
}
|