mirror of
https://github.com/viliusle/miniPaint.git
synced 2026-02-06 13:36:45 +00:00
Start undo work
This commit is contained in:
parent
fcf53cf71a
commit
0a6d3fe874
92
src/js/actions/autoresize-canvas.js
Normal file
92
src/js/actions/autoresize-canvas.js
Normal file
@ -0,0 +1,92 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Autoresize_canvas_action extends Base_action {
|
||||
/**
|
||||
* autoresize canvas to layer size, based on dimensions, up - always, if 1 layer - down.
|
||||
*
|
||||
* @param {int} width
|
||||
* @param {int} height
|
||||
* @param {int} layer_id
|
||||
* @param {boolean} can_automate
|
||||
*/
|
||||
constructor(width, height, layer_id, can_automate = true) {
|
||||
super('autoresize_canvas', 'Auto-resize Canvas');
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.layer_id = layer_id;
|
||||
this.can_automate = can_automate;
|
||||
this.old_config_width = null;
|
||||
this.old_config_height = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
const width = this.width;
|
||||
const height = this.height;
|
||||
const can_automate = this.can_automate;
|
||||
let need_fit = false;
|
||||
let new_config_width = config.WIDTH;
|
||||
let new_config_height = config.HEIGHT;
|
||||
|
||||
// Resize up
|
||||
if (width > new_config_width || height > new_config_height) {
|
||||
const wrapper = document.getElementById('main_wrapper');
|
||||
const page_w = wrapper.clientWidth;
|
||||
const page_h = wrapper.clientHeight;
|
||||
|
||||
if (width > page_w || height > page_h) {
|
||||
need_fit = true;
|
||||
}
|
||||
if (width > new_config_width)
|
||||
new_config_width = parseInt(width);
|
||||
if (height > new_config_height)
|
||||
new_config_height = parseInt(height);
|
||||
}
|
||||
|
||||
// Resize down
|
||||
if (config.layers.length == 1 && can_automate !== false) {
|
||||
if (width < new_config_width)
|
||||
new_config_width = parseInt(width);
|
||||
if (height < new_config_height)
|
||||
new_config_height = parseInt(height);
|
||||
}
|
||||
|
||||
if (new_config_width !== config.WIDTH || new_config_height !== height) {
|
||||
this.old_config_width = config.WIDTH;
|
||||
this.old_config_height = config.HEIGHT;
|
||||
config.WIDTH = new_config_width;
|
||||
config.HEIGHT = new_config_height;
|
||||
app.GUI.prepare_canvas();
|
||||
} else {
|
||||
throw new Error('Aborted - Resize not necessary')
|
||||
}
|
||||
|
||||
// Fit zoom when after short pause
|
||||
// @todo - remove setTimeout
|
||||
if (need_fit == true) {
|
||||
await new Promise((resolve) => {
|
||||
window.setTimeout(() => {
|
||||
app.GUI.GUI_preview.zoom_auto();
|
||||
resolve();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
if (this.old_config_width != null) {
|
||||
config.WIDTH = this.old_config_width;
|
||||
}
|
||||
if (this.old_config_height != null) {
|
||||
config.HEIGHT = this.old_config_height;
|
||||
}
|
||||
if (this.old_config_width != null || this.old_config_height != null) {
|
||||
app.GUI.prepare_canvas();
|
||||
}
|
||||
this.old_config_width = null;
|
||||
this.old_config_height = null;
|
||||
}
|
||||
}
|
||||
17
src/js/actions/base.js
Normal file
17
src/js/actions/base.js
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
export class Base_action {
|
||||
constructor(action_id, action_description) {
|
||||
this.action_id = action_id;
|
||||
this.action_description = action_description;
|
||||
this.is_done = false;
|
||||
}
|
||||
do() {
|
||||
this.is_done = true;
|
||||
}
|
||||
undo() {
|
||||
this.is_done = false;
|
||||
}
|
||||
free() {
|
||||
// Override if need to run tasks to free memory when action is discarded from history
|
||||
}
|
||||
}
|
||||
46
src/js/actions/bundle.js
Normal file
46
src/js/actions/bundle.js
Normal file
@ -0,0 +1,46 @@
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Bundle_action extends Base_action {
|
||||
/**
|
||||
* Groups multiple actions together in the undo/redo history, runs them all at once.
|
||||
*/
|
||||
constructor(bundle_id, bundle_name, actions_to_do) {
|
||||
super(bundle_id, bundle_name);
|
||||
this.actions_to_do = actions_to_do;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
let error = null;
|
||||
let i = 0;
|
||||
for (i = 0; i < this.actions_to_do.length; i++) {
|
||||
try {
|
||||
await this.actions_to_do[i].do();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// One of the actions aborted, undo all previous actions.
|
||||
if (error) {
|
||||
for (i--; i >= 0; i--) {
|
||||
await this.actions_to_do[i].undo();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
for (let i = this.actions_to_do.length - 1; i >= 0; i--) {
|
||||
await this.actions_to_do[i].undo();
|
||||
}
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
free() {
|
||||
this.actions_to_do = null;
|
||||
}
|
||||
}
|
||||
98
src/js/actions/delete-layer.js
Normal file
98
src/js/actions/delete-layer.js
Normal file
@ -0,0 +1,98 @@
|
||||
import config from '../config.js';
|
||||
import app from './../app.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Delete_layer_action extends Base_action {
|
||||
/**
|
||||
* removes layer
|
||||
*
|
||||
* @param {int} id
|
||||
* @param {boolean} force - Force to delete first layer?
|
||||
*/
|
||||
constructor(layer_id, force) {
|
||||
super('delete_layer', 'Delete Layer');
|
||||
this.layer_id = parseInt(layer_id);
|
||||
this.force = force || false;
|
||||
this.insert_layer_action = null;
|
||||
this.select_layer_action = null;
|
||||
this.delete_index = null;
|
||||
this.deleted_layer = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
const id = this.layer_id;
|
||||
const force = this.force;
|
||||
|
||||
// Determine if there is a layer to delete, abort if not
|
||||
for (var i in config.layers) {
|
||||
if (config.layers[i].id == id) {
|
||||
this.delete_index = i;
|
||||
}
|
||||
}
|
||||
if (this.delete_index === null) {
|
||||
throw new Error('Aborted - Layer to delete not found');
|
||||
}
|
||||
|
||||
if (config.layers.length == 1 && (force == undefined || force == false)) {
|
||||
// Only 1 layer left
|
||||
if (config.layer.type == null) {
|
||||
//STOP
|
||||
throw new Error('Aborted - Will not delete last layer');
|
||||
}
|
||||
else {
|
||||
// Delete it, but before that - create new empty layer
|
||||
this.insert_layer_action = new app.Actions.Insert_layer_action();
|
||||
this.insert_layer_action.do();
|
||||
}
|
||||
}
|
||||
|
||||
if (config.layers.length > 1 && config.layer.id == id) {
|
||||
// Select next or previous layer
|
||||
try {
|
||||
const select_action = new app.Actions.Select_next_layer_action(id);
|
||||
await select_action.do();
|
||||
this.select_layer_action = select_action;
|
||||
} catch (error) {
|
||||
const select_action = new app.Actions.Select_previous_layer_action(id);
|
||||
await select_action.do();
|
||||
this.select_layer_action = select_action;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove layer from list
|
||||
this.deleted_layer = config.layers.splice(this.delete_index, 1)[0];
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
if (this.deleted_layer) {
|
||||
config.layers.splice(this.delete_index, 0, this.deleted_layer);
|
||||
this.delete_index = null;
|
||||
this.deleted_layer = null;
|
||||
}
|
||||
if (this.select_layer_action) {
|
||||
await this.select_layer_action.undo();
|
||||
this.select_layer_action = null;
|
||||
}
|
||||
if (this.insert_layer_action) {
|
||||
await this.insert_layer_action.undo();
|
||||
this.insert_layer_action = null;
|
||||
}
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
free() {
|
||||
if (this.deleted_layer) {
|
||||
delete this.deleted_layer.link;
|
||||
}
|
||||
this.insert_layer_action = null;
|
||||
this.select_layer_action = null;
|
||||
this.deleted_layer = null;
|
||||
}
|
||||
}
|
||||
14
src/js/actions/index.js
Normal file
14
src/js/actions/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
export { Autoresize_canvas_action } from './autoresize-canvas.js';
|
||||
export { Bundle_action } from './bundle.js';
|
||||
export { Delete_layer_action } from './delete-layer.js';
|
||||
export { Init_canvas_zoom_action } from './init-canvas-zoom.js';
|
||||
export { Insert_layer_action } from './insert-layer.js';
|
||||
export { Prepare_canvas_action } from './prepare-canvas.js';
|
||||
export { Reset_layers_action } from './reset-layers.js';
|
||||
export { Reset_selection_action } from './reset-selection.js';
|
||||
export { Select_layer_action } from './select-layer.js';
|
||||
export { Select_next_layer_action } from './select-next-layer.js';
|
||||
export { Select_previous_layer_action } from './select-previous-layer.js';
|
||||
export { Toggle_layer_visibility_action } from './toggle-layer-visibility.js';
|
||||
export { Update_config_action } from './update-config.js';
|
||||
export { Update_layer_action } from './update-layer.js';
|
||||
45
src/js/actions/init-canvas-zoom.js
Normal file
45
src/js/actions/init-canvas-zoom.js
Normal file
@ -0,0 +1,45 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import zoomView from '../libs/zoomView.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Init_canvas_zoom_action extends Base_action {
|
||||
/**
|
||||
* Resets the canvas
|
||||
*/
|
||||
constructor() {
|
||||
super('init_canvas_zoom', 'Initialize Canvas Zoom');
|
||||
this.old_bounds = null;
|
||||
this.old_context = null;
|
||||
this.old_stable_dimensions = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
this.old_bounds = zoomView.getBounds();
|
||||
this.old_context = zoomView.getContext();
|
||||
this.old_stable_dimensions = app.Layers.stable_dimensions;
|
||||
zoomView.setBounds(0, 0, config.WIDTH, config.HEIGHT);
|
||||
zoomView.setContext(app.Layers.ctx);
|
||||
app.Layers.stable_dimensions = [
|
||||
config.WIDTH,
|
||||
config.HEIGHT
|
||||
];
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
zoomView.setBounds(this.old_bounds.top, this.old_bounds.left, this.old_bounds.right, this.old_bounds.bottom);
|
||||
zoomView.setContext(this.old_context);
|
||||
app.Layers.stable_dimensions = this.old_stable_dimensions;
|
||||
this.old_bounds = null;
|
||||
this.old_context = null;
|
||||
this.old_stable_dimensions = null;
|
||||
}
|
||||
|
||||
free() {
|
||||
this.old_bounds = null;
|
||||
this.old_context = null;
|
||||
this.old_stable_dimensions = null;
|
||||
}
|
||||
}
|
||||
205
src/js/actions/insert-layer.js
Normal file
205
src/js/actions/insert-layer.js
Normal file
@ -0,0 +1,205 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Insert_layer_action extends Base_action {
|
||||
/**
|
||||
* Creates new layer
|
||||
*
|
||||
* @param {object} settings
|
||||
* @param {boolean} can_automate
|
||||
*/
|
||||
constructor(settings, can_automate = true) {
|
||||
super('insert_layer', 'Insert Layer');
|
||||
this.settings = settings;
|
||||
this.can_automate = can_automate;
|
||||
this.previous_auto_increment = null;
|
||||
this.previous_selected_layer = null;
|
||||
this.inserted_layer_id = null;
|
||||
this.update_layer_action = null;
|
||||
this.delete_layer_action = null;
|
||||
this.autoresize_canvas_action = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
this.previous_auto_increment = app.Layers.auto_increment;
|
||||
this.previous_selected_layer = config.layer;
|
||||
let autoresize_as = null;
|
||||
|
||||
// Default data
|
||||
const layer = {
|
||||
id: app.Layers.auto_increment,
|
||||
parent_id: 0,
|
||||
name: config.TOOL.name.charAt(0).toUpperCase() + config.TOOL.name.slice(1) + ' #' + app.Layers.auto_increment,
|
||||
type: null,
|
||||
link: null,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
width_original: null,
|
||||
height: 0,
|
||||
height_original: null,
|
||||
visible: true,
|
||||
is_vector: false,
|
||||
hide_selection_if_active: false,
|
||||
opacity: 100,
|
||||
order: app.Layers.auto_increment,
|
||||
composition: 'source-over',
|
||||
rotate: 0,
|
||||
data: null,
|
||||
params: {},
|
||||
status: null,
|
||||
color: config.COLOR,
|
||||
filters: [],
|
||||
render_function: null,
|
||||
};
|
||||
|
||||
// Build data
|
||||
for (let i in this.settings) {
|
||||
if (typeof layer[i] == "undefined") {
|
||||
alertify.error('Error: wrong key: ' + i);
|
||||
continue;
|
||||
}
|
||||
layer[i] = this.settings[i];
|
||||
}
|
||||
|
||||
// Prepare image
|
||||
let image_load_promise;
|
||||
if (layer.type == 'image') {
|
||||
|
||||
if(layer.name.toLowerCase().indexOf('.svg') == layer.name.length - 4){
|
||||
// We have svg
|
||||
layer.is_vector = true;
|
||||
}
|
||||
|
||||
if (config.layers.length == 1 && config.layer.width == 0
|
||||
&& config.layer.height == 0 && config.layer.data == null) {
|
||||
// Remove first empty layer
|
||||
|
||||
this.delete_layer_action = new app.Actions.Delete_layer_action(config.layer.id, true);
|
||||
this.delete_layer_action.do();
|
||||
}
|
||||
|
||||
if (layer.link == null) {
|
||||
if (typeof layer.data == 'object') {
|
||||
// Load actual image
|
||||
if (layer.width == 0)
|
||||
layer.width = layer.data.width;
|
||||
if (layer.height == 0)
|
||||
layer.height = layer.data.height;
|
||||
layer.link = layer.data.cloneNode(true);
|
||||
layer.link.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
layer.data = null;
|
||||
autoresize_as = [config.layer.width, config.layer.height];
|
||||
need_autoresize = true;
|
||||
}
|
||||
else if (typeof layer.data == 'string') {
|
||||
image_load_promise = new Promise((resolve, reject) => {
|
||||
// Try loading as imageData
|
||||
layer.link = new Image();
|
||||
layer.link.onload = () => {
|
||||
// Update dimensions
|
||||
if (layer.width == 0)
|
||||
layer.width = layer.link.width;
|
||||
if (layer.height == 0)
|
||||
layer.height = layer.link.height;
|
||||
if (layer.width_original == null)
|
||||
layer.width_original = layer.width;
|
||||
if (layer.height_original == null)
|
||||
layer.height_original = layer.height;
|
||||
// Free data
|
||||
layer.data = null;
|
||||
autoresize_as = [layer.width, layer.height, layer.id, this.can_automate];
|
||||
config.need_render = true;
|
||||
resolve();
|
||||
};
|
||||
layer.link.onerror = (error) => {
|
||||
resolve(error);
|
||||
alertify.error('Sorry, image could not be loaded.');
|
||||
};
|
||||
layer.link.src = layer.data;
|
||||
layer.link.crossOrigin = "Anonymous";
|
||||
});
|
||||
}
|
||||
else {
|
||||
alertify.error('Error: can not load image.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.settings != undefined && config.layers.length > 0
|
||||
&& config.layer.width == 0 && config.layer.height == 0
|
||||
&& config.layer.data == null && layer.type != 'image' && this.can_automate !== false) {
|
||||
// Update existing layer, because it's empty
|
||||
delete layer.name;
|
||||
this.update_layer_action = new app.Actions.Update_layer_action(config.layer.id, layer);
|
||||
await this.update_layer_action.do();
|
||||
}
|
||||
else {
|
||||
// Create new layer
|
||||
config.layers.push(layer);
|
||||
config.layer = app.Layers.get_layer(layer.id);
|
||||
app.Layers.auto_increment++;
|
||||
|
||||
if (config.layer == null) {
|
||||
config.layer = config.layers[0];
|
||||
}
|
||||
|
||||
this.inserted_layer_id = layer.id;
|
||||
}
|
||||
|
||||
if (layer.id >= app.Layers.auto_increment)
|
||||
app.Layers.auto_increment = layer.id + 1;
|
||||
|
||||
if (image_load_promise) {
|
||||
await image_load_promise;
|
||||
}
|
||||
|
||||
if (autoresize_as) {
|
||||
this.autoresize_canvas_action = new app.Actions.Autoresize_canvas_action(...autoresize_as);
|
||||
try {
|
||||
await this.autoresize_canvas_action.do();
|
||||
} catch(error) {
|
||||
this.autoresize_canvas_action = null;
|
||||
}
|
||||
}
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
app.Layers.auto_increment = this.previous_auto_increment;
|
||||
if (this.autoresize_canvas_action) {
|
||||
await this.autoresize_canvas_action.undo();
|
||||
this.autoresize_canvas_action = null;
|
||||
}
|
||||
if (this.inserted_layer_id) {
|
||||
await new app.Actions.Delete_layer_action(this.inserted_layer_id, true).do();
|
||||
this.inserted_layer_id = null;
|
||||
}
|
||||
if (this.update_layer_action) {
|
||||
await this.update_layer_action.undo();
|
||||
this.update_layer_action = null;
|
||||
}
|
||||
if (this.delete_layer_action) {
|
||||
await this.delete_layer_action.undo();
|
||||
this.delete_layer_action = null;
|
||||
}
|
||||
config.layer = this.previous_selected_layer;
|
||||
this.previous_selected_layer = null;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
free() {
|
||||
this.delete_layer_action = null;
|
||||
this.update_layer_action = null;
|
||||
this.previous_selected_layer = null;
|
||||
}
|
||||
}
|
||||
29
src/js/actions/prepare-canvas.js
Normal file
29
src/js/actions/prepare-canvas.js
Normal file
@ -0,0 +1,29 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Prepare_canvas_action extends Base_action {
|
||||
/**
|
||||
* Resizes/renders the canvas at the specified step. Usually used on both sides of a config update action.
|
||||
*
|
||||
* @param {boolean} call_when
|
||||
*/
|
||||
constructor(call_when = 'undo') {
|
||||
super('prepare_canvas', 'Prepare Canvas');
|
||||
this.call_when = call_when;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
if (this.call_when === 'do') {
|
||||
app.GUI.prepare_canvas();
|
||||
}
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
if (this.call_when === 'undo') {
|
||||
app.GUI.prepare_canvas();
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/js/actions/reset-layers.js
Normal file
53
src/js/actions/reset-layers.js
Normal file
@ -0,0 +1,53 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Reset_layers_action extends Base_action {
|
||||
/*
|
||||
* removes all layers
|
||||
*/
|
||||
constructor(auto_insert) {
|
||||
super('reset_layers', 'Reset Layers');
|
||||
this.auto_insert = auto_insert;
|
||||
this.previous_auto_increment = null;
|
||||
this.delete_actions = null;
|
||||
this.insert_action = null;
|
||||
}
|
||||
async do() {
|
||||
super.do();
|
||||
const auto_insert = this.auto_insert;
|
||||
this.previous_auto_increment = app.Layers.auto_increment;
|
||||
|
||||
this.delete_actions = [];
|
||||
for (let i = config.layers.length - 1; i >= 0; i--) {
|
||||
const delete_action = new app.Actions.Delete_layer_action(config.layers[i].id, true);
|
||||
await delete_action.do();
|
||||
this.delete_actions.push(delete_action);
|
||||
}
|
||||
app.Layers.auto_increment = 1;
|
||||
|
||||
if (auto_insert != undefined && auto_insert === true) {
|
||||
const settings = {};
|
||||
this.insert_action = new app.Actions.Insert_layer_action(settings);
|
||||
await this.insert_action.do();
|
||||
}
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
async undo() {
|
||||
super.undo();
|
||||
if (this.insert_action) {
|
||||
await this.insert_action.undo();
|
||||
this.insert_action = null;
|
||||
}
|
||||
for (let i = this.delete_actions.length - 1; i >= 0; i--) {
|
||||
await this.delete_actions[i].undo();
|
||||
}
|
||||
app.Layers.auto_increment = this.previous_auto_increment;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
}
|
||||
40
src/js/actions/reset-selection.js
Normal file
40
src/js/actions/reset-selection.js
Normal file
@ -0,0 +1,40 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Reset_selection_action extends Base_action {
|
||||
/**
|
||||
* Sets the selection to empty
|
||||
*/
|
||||
constructor() {
|
||||
super('reset_selection', 'Reset Selection');
|
||||
this.settings_reference = null;
|
||||
this.old_settings_data = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
this.settings_reference = app.Layers.Base_selection.find_settings();
|
||||
this.old_settings_data = this.settings_reference.data;
|
||||
this.settings_reference.data = {
|
||||
x: null,
|
||||
y: null,
|
||||
width: null,
|
||||
height: null
|
||||
};
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
this.settings_reference.data = this.old_settings_data;
|
||||
this.settings_reference = null;
|
||||
this.old_settings_data = null;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
free() {
|
||||
this.settings_reference = null;
|
||||
this.old_settings_data = null;
|
||||
}
|
||||
}
|
||||
57
src/js/actions/select-layer.js
Normal file
57
src/js/actions/select-layer.js
Normal file
@ -0,0 +1,57 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Select_layer_action extends Base_action {
|
||||
/**
|
||||
* marks layer as selected, active
|
||||
*
|
||||
* @param {int} layer_id
|
||||
*/
|
||||
constructor(layer_id, ignore_same_selection = false) {
|
||||
super('select_layer', 'Select Layer');
|
||||
this.reset_selection_action = null;
|
||||
this.layer_id = parseInt(layer_id);
|
||||
this.ignore_same_selection = ignore_same_selection;
|
||||
this.old_layer = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
|
||||
let old_layer = config.layer;
|
||||
let new_layer = app.Layers.get_layer(this.layer_id);
|
||||
|
||||
if (old_layer !== new_layer) {
|
||||
this.old_layer = old_layer;
|
||||
config.layer = new_layer;
|
||||
} else if (!this.ignore_same_selection) {
|
||||
throw new Error('Aborted - Layer already selected');
|
||||
}
|
||||
|
||||
this.reset_selection_action = new app.Actions.Reset_selection_action();
|
||||
await this.reset_selection_action.do();
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
|
||||
if (this.reset_selection_action) {
|
||||
await this.reset_selection_action.undo();
|
||||
this.reset_selection_action = null;
|
||||
}
|
||||
|
||||
config.layer = this.old_layer;
|
||||
this.old_layer = null;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
free() {
|
||||
this.old_layer = null;
|
||||
}
|
||||
}
|
||||
33
src/js/actions/select-next-layer.js
Normal file
33
src/js/actions/select-next-layer.js
Normal file
@ -0,0 +1,33 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Select_next_layer_action extends Base_action {
|
||||
constructor(reference_layer_id) {
|
||||
super('select_next_layer', 'Select Next Layer');
|
||||
this.reference_layer_id = reference_layer_id;
|
||||
this.old_config_layer = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
const next_layer = app.Layers.find_next(this.reference_layer_id);
|
||||
if (!next_layer) {
|
||||
throw new Error('Aborted - Next layer to select not found');
|
||||
}
|
||||
this.old_config_layer = config.layer;
|
||||
config.layer = next_layer;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
config.layer = this.old_config_layer;
|
||||
this.old_config_layer = null;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
}
|
||||
33
src/js/actions/select-previous-layer.js
Normal file
33
src/js/actions/select-previous-layer.js
Normal file
@ -0,0 +1,33 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Select_previous_layer_action extends Base_action {
|
||||
constructor(reference_layer_id) {
|
||||
super('select_previous_layer', 'Select Previous Layer');
|
||||
this.reference_layer_id = reference_layer_id;
|
||||
this.old_config_layer = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
const previous_layer = app.Layers.find_previous(this.reference_layer_id);
|
||||
if (!previous_layer) {
|
||||
throw new Error('Aborted - Previous layer to select not found');
|
||||
}
|
||||
this.old_config_layer = config.layer;
|
||||
config.layer = previous_layer;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
config.layer = this.old_config_layer;
|
||||
this.old_config_layer = null;
|
||||
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
}
|
||||
37
src/js/actions/toggle-layer-visibility.js
Normal file
37
src/js/actions/toggle-layer-visibility.js
Normal file
@ -0,0 +1,37 @@
|
||||
import app from '../app.js';
|
||||
import config from '../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Toggle_layer_visibility_action extends Base_action {
|
||||
/**
|
||||
* toggle layer visibility
|
||||
*
|
||||
* @param {int} layer_id
|
||||
*/
|
||||
constructor(layer_id) {
|
||||
super('toggle_layer_visibility', 'Toggle Layer Visibility');
|
||||
this.layer_id = parseInt(layer_id);
|
||||
this.old_visible = null;
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
const layer = app.Layers.get_layer(this.layer_id);
|
||||
this.old_visible = layer.visible;
|
||||
if (layer.visible == false)
|
||||
layer.visible = true;
|
||||
else
|
||||
layer.visible = false;
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
const layer = app.Layers.get_layer(this.layer_id);
|
||||
layer.visible = this.old_visible;
|
||||
this.old_visible = null;
|
||||
app.Layers.render();
|
||||
app.GUI.GUI_layers.render_layers();
|
||||
}
|
||||
}
|
||||
37
src/js/actions/update-config.js
Normal file
37
src/js/actions/update-config.js
Normal file
@ -0,0 +1,37 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Update_config_action extends Base_action {
|
||||
/**
|
||||
* Updates the app config with the provided settings
|
||||
*
|
||||
* @param {object} settings
|
||||
*/
|
||||
constructor(settings) {
|
||||
super('update_config', 'Update Config');
|
||||
this.settings = settings;
|
||||
this.old_settings = {};
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
for (let i in this.settings) {
|
||||
this.old_settings[i] = config[i];
|
||||
config[i] = this.settings[i];
|
||||
}
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
for (let i in this.old_settings) {
|
||||
config[i] = this.old_settings[i];
|
||||
}
|
||||
this.old_settings = {};
|
||||
}
|
||||
|
||||
free() {
|
||||
this.settings = null;
|
||||
this.old_settings = null;
|
||||
}
|
||||
}
|
||||
54
src/js/actions/update-layer.js
Normal file
54
src/js/actions/update-layer.js
Normal file
@ -0,0 +1,54 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import { Base_action } from './base.js';
|
||||
|
||||
export class Update_layer_action extends Base_action {
|
||||
/**
|
||||
* Updates an existing layer with the provided settings
|
||||
*
|
||||
* @param {string} layer_id
|
||||
* @param {object} settings
|
||||
*/
|
||||
constructor(layer_id, settings) {
|
||||
super('update_layer', 'Update Layer');
|
||||
this.layer_id = layer_id;
|
||||
this.settings = settings;
|
||||
this.reference_layer = null;
|
||||
this.old_settings = {};
|
||||
}
|
||||
|
||||
async do() {
|
||||
super.do();
|
||||
this.reference_layer = app.Layers.get_layer(this.layer_id);
|
||||
|
||||
if (!this.reference_layer) {
|
||||
throw new Error('Aborted - layer with specified id doesn\'t exist');
|
||||
}
|
||||
|
||||
for (let i in this.settings) {
|
||||
if (i == 'id')
|
||||
continue;
|
||||
if (i == 'order')
|
||||
continue;
|
||||
this.old_settings[i] = this.reference_layer[i];
|
||||
this.reference_layer[i] = this.settings[i];
|
||||
}
|
||||
}
|
||||
|
||||
async undo() {
|
||||
super.undo();
|
||||
if (this.reference_layer) {
|
||||
for (let i in this.old_settings) {
|
||||
this.reference_layer[i] = this.old_settings[i];
|
||||
}
|
||||
this.old_settings = {};
|
||||
}
|
||||
this.reference_layer = null;
|
||||
}
|
||||
|
||||
free() {
|
||||
this.settings = null;
|
||||
this.old_settings = null;
|
||||
this.reference_layer = null;
|
||||
}
|
||||
}
|
||||
11
src/js/app.js
Normal file
11
src/js/app.js
Normal file
@ -0,0 +1,11 @@
|
||||
// Store singletons for easy access
|
||||
export default {
|
||||
GUI: null,
|
||||
Tools: null,
|
||||
Layers: null,
|
||||
Config: null,
|
||||
State: null,
|
||||
FileOpen: null,
|
||||
FileSave: null,
|
||||
Actions: null
|
||||
};
|
||||
@ -3,6 +3,7 @@
|
||||
* author: Vilius L.
|
||||
*/
|
||||
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_gui_class from './base-gui.js';
|
||||
import Base_selection_class from './base-selection.js';
|
||||
@ -66,7 +67,8 @@ class Base_layers_class {
|
||||
*/
|
||||
init() {
|
||||
this.init_zoom_lib();
|
||||
this.insert({});
|
||||
|
||||
new app.Actions.Insert_layer_action({}).do();
|
||||
|
||||
var sel_config = {
|
||||
enable_background: false,
|
||||
@ -315,151 +317,9 @@ class Base_layers_class {
|
||||
* @param {boolean} can_automate
|
||||
*/
|
||||
async insert(settings, can_automate = true) {
|
||||
var _this = this;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var resolvable = false;
|
||||
var need_autoresize = false;
|
||||
|
||||
//default data
|
||||
var layer = {
|
||||
id: _this.auto_increment,
|
||||
parent_id: 0,
|
||||
name: _this.Helper.ucfirst(config.TOOL.name) + ' #' + _this.auto_increment,
|
||||
type: null,
|
||||
link: null,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
width_original: null,
|
||||
height: 0,
|
||||
height_original: null,
|
||||
visible: true,
|
||||
is_vector: false,
|
||||
hide_selection_if_active: false,
|
||||
opacity: 100,
|
||||
order: _this.auto_increment,
|
||||
composition: 'source-over',
|
||||
rotate: 0,
|
||||
data: null,
|
||||
params: {},
|
||||
status: null,
|
||||
color: config.COLOR,
|
||||
filters: [],
|
||||
render_function: null,
|
||||
};
|
||||
|
||||
//build data
|
||||
for (var i in settings) {
|
||||
if (typeof layer[i] == "undefined") {
|
||||
alertify.error('Error: wrong key: ' + i);
|
||||
continue;
|
||||
}
|
||||
layer[i] = settings[i];
|
||||
}
|
||||
|
||||
//prepare image
|
||||
if (layer.type == 'image') {
|
||||
|
||||
if(layer.name.toLowerCase().indexOf('.svg') == layer.name.length - 4){
|
||||
//we have svg
|
||||
layer.is_vector = true;
|
||||
}
|
||||
|
||||
if (config.layers.length == 1 && config.layer.width == 0
|
||||
&& config.layer.height == 0 && config.layer.data == null) {
|
||||
//remove first empty layer?
|
||||
_this.delete(config.layer.id, true);
|
||||
}
|
||||
|
||||
if (layer.link == null) {
|
||||
if (typeof layer.data == 'object') {
|
||||
//load actual image
|
||||
if (layer.width == 0)
|
||||
layer.width = layer.data.width;
|
||||
if (layer.height == 0)
|
||||
layer.height = layer.data.height;
|
||||
layer.link = layer.data.cloneNode(true);
|
||||
layer.link.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
layer.data = null;
|
||||
need_autoresize = true;
|
||||
}
|
||||
else if (typeof layer.data == 'string') {
|
||||
//try loading as imageData
|
||||
resolvable = true;
|
||||
layer.link = new Image();
|
||||
layer.link.onload = function () {
|
||||
//update dimensions
|
||||
if (layer.width == 0)
|
||||
layer.width = layer.link.width;
|
||||
if (layer.height == 0)
|
||||
layer.height = layer.link.height;
|
||||
if (layer.width_original == null)
|
||||
layer.width_original = layer.width;
|
||||
if (layer.height_original == null)
|
||||
layer.height_original = layer.height;
|
||||
//free data
|
||||
|
||||
layer.data = null;
|
||||
_this.autoresize(layer.width, layer.height, layer.id, can_automate);
|
||||
_this.render();
|
||||
layer.link.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
resolve(true);
|
||||
};
|
||||
layer.link.onerror = function () {
|
||||
alertify.error('Sorry, image could not be loaded.');
|
||||
};
|
||||
layer.link.src = layer.data;
|
||||
layer.link.crossOrigin = "Anonymous";
|
||||
}
|
||||
else {
|
||||
alertify.error('Error: can not load image.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings != undefined && config.layers.length > 0
|
||||
&& config.layer.width == 0 && config.layer.height == 0
|
||||
&& config.layer.data == null && layer.type != 'image' && can_automate !== false) {
|
||||
//update existing layer, because its empty
|
||||
for (var i in layer) {
|
||||
if (i == 'id')
|
||||
continue;
|
||||
if (i == 'name')
|
||||
continue;
|
||||
if (i == 'order')
|
||||
continue;
|
||||
config.layer[i] = layer[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
//create new layer
|
||||
config.layers.push(layer);
|
||||
config.layer = _this.get_layer(layer.id);
|
||||
_this.auto_increment++;
|
||||
|
||||
if (config.layer == null) {
|
||||
config.layer = config.layers[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (layer.id >= _this.auto_increment)
|
||||
_this.auto_increment = layer.id + 1;
|
||||
|
||||
if (need_autoresize == true) {
|
||||
_this.autoresize(config.layer.width, config.layer.height);
|
||||
}
|
||||
|
||||
_this.render();
|
||||
_this.Base_gui.GUI_layers.render_layers();
|
||||
if(resolvable == false){
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
return app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(settings, can_automate)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -470,44 +330,10 @@ class Base_layers_class {
|
||||
* @param {int} layer_id
|
||||
* @param {boolean} can_automate
|
||||
*/
|
||||
autoresize(width, height, layer_id, can_automate = true) {
|
||||
var _this = this;
|
||||
var need_fit = false;
|
||||
|
||||
//resize up
|
||||
if (width > config.WIDTH || height > config.HEIGHT) {
|
||||
|
||||
var wrapper = document.getElementById('main_wrapper');
|
||||
var page_w = wrapper.clientWidth;
|
||||
var page_h = wrapper.clientHeight;
|
||||
|
||||
if (width > page_w || height > page_h) {
|
||||
need_fit = true;
|
||||
}
|
||||
if (width > config.WIDTH)
|
||||
config.WIDTH = parseInt(width);
|
||||
if (height > config.HEIGHT)
|
||||
config.HEIGHT = parseInt(height);
|
||||
}
|
||||
|
||||
//resize down
|
||||
if (config.layers.length == 1 && can_automate !== false) {
|
||||
if (width < config.WIDTH)
|
||||
config.WIDTH = parseInt(width);
|
||||
if (height < config.HEIGHT)
|
||||
config.HEIGHT = parseInt(height);
|
||||
}
|
||||
|
||||
this.Base_gui.prepare_canvas();
|
||||
|
||||
//fit zoom when after short pause
|
||||
//@todo - remove setTimeout
|
||||
if (need_fit == true) {
|
||||
window.setTimeout(myCallback, 100);
|
||||
function myCallback() {
|
||||
_this.Base_gui.GUI_preview.zoom_auto();
|
||||
}
|
||||
}
|
||||
async autoresize(width, height, layer_id, can_automate = true) {
|
||||
return app.State.do_action(
|
||||
new app.Actions.Autoresize_canvas_action(width, height, layer_id, can_automate)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -535,60 +361,19 @@ class Base_layers_class {
|
||||
* @param {int} id
|
||||
* @param {boolean} force - Force to delete first layer?
|
||||
*/
|
||||
delete(id, force) {
|
||||
id = parseInt(id);
|
||||
if (config.layers.length == 1 && (force == undefined || force == false)) {
|
||||
//only 1 layer left
|
||||
if (config.layer.type == null) {
|
||||
//STOP
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//delete it, but before that - create new empty layer
|
||||
this.insert();
|
||||
}
|
||||
}
|
||||
|
||||
if (config.layer.id == id) {
|
||||
//select previous layer
|
||||
config.layer = this.find_next(id);
|
||||
if (config.layer == null)
|
||||
config.layer = this.find_previous(id);
|
||||
}
|
||||
|
||||
for (var i in config.layers) {
|
||||
if (config.layers[i].id == id) {
|
||||
//delete
|
||||
|
||||
if (config.layers[i].type == 'image') {
|
||||
//clean image
|
||||
config.layers[i].link = null;
|
||||
}
|
||||
|
||||
config.layers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.Base_gui.GUI_layers.render_layers();
|
||||
async delete(id, force) {
|
||||
return app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(id, force)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* removes all layers
|
||||
*/
|
||||
reset_layers(auto_insert) {
|
||||
for (var i = config.layers.length - 1; i >= 0; i--) {
|
||||
this.delete(config.layers[i].id, true);
|
||||
}
|
||||
this.auto_increment = 1;
|
||||
|
||||
if (auto_insert != undefined && auto_insert === true) {
|
||||
var settings = {};
|
||||
this.insert(settings);
|
||||
}
|
||||
|
||||
this.render();
|
||||
this.Base_gui.GUI_layers.render_layers();
|
||||
async reset_layers(auto_insert) {
|
||||
return app.State.do_action(
|
||||
new app.Actions.Reset_layers_action(auto_insert)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -596,17 +381,10 @@ class Base_layers_class {
|
||||
*
|
||||
* @param {int} id
|
||||
*/
|
||||
toggle_visibility(id) {
|
||||
id = parseInt(id);
|
||||
var link = this.get_layer(id);
|
||||
|
||||
if (link.visible == false)
|
||||
link.visible = true;
|
||||
else
|
||||
link.visible = false;
|
||||
|
||||
this.render();
|
||||
this.Base_gui.GUI_layers.render_layers();
|
||||
async toggle_visibility(id) {
|
||||
return app.State.do_action(
|
||||
new app.Actions.Toggle_layer_visibility_action(id)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -621,13 +399,10 @@ class Base_layers_class {
|
||||
*
|
||||
* @param {int} id
|
||||
*/
|
||||
select(id) {
|
||||
id = parseInt(id);
|
||||
config.layer = this.get_layer(id);
|
||||
this.Base_selection.reset_selection();
|
||||
|
||||
this.render();
|
||||
this.Base_gui.GUI_layers.render_layers();
|
||||
async select(id) {
|
||||
return app.State.do_action(
|
||||
new app.Actions.Select_layer_action(id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -10,6 +10,9 @@ import Helper_class from './../libs/helpers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
var instance = null;
|
||||
let action_history = [];
|
||||
let action_history_index = 0;
|
||||
let action_history_max = 50;
|
||||
|
||||
/**
|
||||
* Undo state class. Supports multiple levels undo.
|
||||
@ -36,18 +39,71 @@ class Base_state_class {
|
||||
|
||||
set_events() {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
var code = event.code;
|
||||
const key = event.key;
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
|
||||
if (code == "KeyZ" && (event.ctrlKey == true || event.metaKey)) {
|
||||
//undo
|
||||
if (key == "z" && (event.ctrlKey == true || event.metaKey)) {
|
||||
// Undo
|
||||
this.undo();
|
||||
event.preventDefault();
|
||||
}
|
||||
if (key == "y" && (event.ctrlKey == true || event.metaKey)) {
|
||||
// Redo
|
||||
this.redo();
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
async do_action(action) {
|
||||
try {
|
||||
await action.do();
|
||||
} catch (error) {
|
||||
// Action aborted. This could be expected behavior if detected that the action shouldn't run.
|
||||
return { status: 'aborted', reason: error };
|
||||
}
|
||||
// Remove all redo actions from history
|
||||
if (action_history_index < action_history.length) {
|
||||
action_history = action_history.slice(0, action_history_index);
|
||||
const freed_actions = action_history.slice(action_history_index, action_history.length);
|
||||
for (let freed_action of freed_actions) {
|
||||
freed_action.free();
|
||||
}
|
||||
}
|
||||
// Add the new action to history
|
||||
action_history.push(action);
|
||||
if (action_history.length > action_history_max) {
|
||||
action_history.shift();
|
||||
} else {
|
||||
action_history_index++;
|
||||
}
|
||||
return { status: 'completed' };
|
||||
}
|
||||
|
||||
can_redo() {
|
||||
return action_history_index < action_history.length;
|
||||
}
|
||||
|
||||
can_undo() {
|
||||
return action_history_index > 0;
|
||||
}
|
||||
|
||||
async redo_action() {
|
||||
if (this.can_redo()) {
|
||||
const action = action_history[action_history_index];
|
||||
await action.do();
|
||||
action_history_index++;
|
||||
}
|
||||
}
|
||||
|
||||
async undo_action() {
|
||||
if (this.can_undo()) {
|
||||
action_history_index--;
|
||||
await action_history[action_history_index].undo();
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
|
||||
this.optimize();
|
||||
@ -105,6 +161,8 @@ class Base_state_class {
|
||||
* supports multiple levels undo system
|
||||
*/
|
||||
undo() {
|
||||
this.undo_action();
|
||||
/*
|
||||
if (this.enabled == false || this.layers_archive[0] == undefined) {
|
||||
//not saved yet
|
||||
alertify.error('Undo is not available.');
|
||||
@ -145,6 +203,11 @@ class Base_state_class {
|
||||
|
||||
this.Base_layers.select(data.layer_active);
|
||||
this.layers_archive.shift(); //remove used state
|
||||
*/
|
||||
}
|
||||
|
||||
redo() {
|
||||
this.redo_action();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
* author: Vilius L.
|
||||
*/
|
||||
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
@ -43,8 +44,9 @@ class GUI_layers_class {
|
||||
var target = event.target;
|
||||
if (target.id == 'insert_layer') {
|
||||
//new layer
|
||||
window.State.save();
|
||||
_this.Base_layers.insert();
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action()
|
||||
);
|
||||
}
|
||||
else if (target.id == 'layer_up') {
|
||||
//move layer up
|
||||
@ -58,18 +60,23 @@ class GUI_layers_class {
|
||||
}
|
||||
else if (target.id == 'visibility') {
|
||||
//change visibility
|
||||
_this.Base_layers.toggle_visibility(target.dataset.id);
|
||||
return app.State.do_action(
|
||||
new app.Actions.Toggle_layer_visibility_action(target.dataset.id)
|
||||
);
|
||||
}
|
||||
else if (target.id == 'delete') {
|
||||
//delete layer
|
||||
window.State.save();
|
||||
_this.Base_layers.delete(target.dataset.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(target.dataset.id)
|
||||
);
|
||||
}
|
||||
else if (target.id == 'layer_name') {
|
||||
//select layer
|
||||
if (target.dataset.id == config.layer.id)
|
||||
return;
|
||||
_this.Base_layers.select(target.dataset.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Select_layer_action(target.dataset.id)
|
||||
);
|
||||
}
|
||||
else if (target.id == 'delete_filter') {
|
||||
//delete filter
|
||||
|
||||
@ -7,7 +7,7 @@ const zoomView = (() => {
|
||||
var im = invMatrix; // alias
|
||||
var scale = 1; // current scale
|
||||
const bounds = {
|
||||
topLeft: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 200,
|
||||
bottom: 200,
|
||||
@ -39,6 +39,9 @@ const zoomView = (() => {
|
||||
getPosition() {
|
||||
return { x: pos.x, y: pos.y };
|
||||
},
|
||||
getContext() {
|
||||
return ctx;
|
||||
},
|
||||
getBounds() {
|
||||
return bounds;
|
||||
},
|
||||
|
||||
@ -12,6 +12,7 @@ import './../css/menu.css';
|
||||
import './../css/print.css';
|
||||
import './../../node_modules/alertifyjs/build/css/alertify.min.css';
|
||||
//js
|
||||
import app from './app.js';
|
||||
import config from './config.js';
|
||||
import './core/components/index.js';
|
||||
import Base_gui_class from './core/base-gui.js';
|
||||
@ -20,9 +21,10 @@ import Base_tools_class from './core/base-tools.js';
|
||||
import Base_state_class from './core/base-state.js';
|
||||
import File_open_class from './modules/file/open.js';
|
||||
import File_save_class from './modules/file/save.js';
|
||||
import * as Actions from './actions/index.js';
|
||||
|
||||
window.addEventListener('load', function (e) {
|
||||
//initiate app
|
||||
// Initiate app
|
||||
var Layers = new Base_layers_class();
|
||||
var Base_tools = new Base_tools_class(true);
|
||||
var GUI = new Base_gui_class();
|
||||
@ -30,14 +32,24 @@ window.addEventListener('load', function (e) {
|
||||
var File_open = new File_open_class();
|
||||
var File_save = new File_save_class();
|
||||
|
||||
//register as global for quick or external access
|
||||
// Register singletons in app module
|
||||
app.Actions = Actions;
|
||||
app.Config = config;
|
||||
app.FileOpen = File_open;
|
||||
app.FileSave = File_save;
|
||||
app.GUI = GUI;
|
||||
app.Layers = Layers;
|
||||
app.State = Base_state;
|
||||
app.Tools = Base_tools;
|
||||
|
||||
// Register as global for quick or external access
|
||||
window.Layers = Layers;
|
||||
window.AppConfig = config;
|
||||
window.State = Base_state; // window.State.save();
|
||||
window.FileOpen = File_open;
|
||||
window.FileSave = File_save;
|
||||
|
||||
//render all
|
||||
// Render all
|
||||
GUI.load_modules();
|
||||
GUI.load_default_values();
|
||||
GUI.render_main_gui();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_gui_class from './../../core/base-gui.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
@ -87,39 +88,40 @@ class File_new_class {
|
||||
width = dim[0];
|
||||
height = dim[1];
|
||||
}
|
||||
if (transparency == true)
|
||||
config.TRANSPARENCY = true;
|
||||
else
|
||||
config.TRANSPARENCY = false;
|
||||
|
||||
config.WIDTH = parseInt(width);
|
||||
config.HEIGHT = parseInt(height);
|
||||
config.ALPHA = 255;
|
||||
config.COLOR = '#008000';
|
||||
config.mouse = {};
|
||||
config.visible_width = null;
|
||||
config.visible_height = null;
|
||||
this.Base_gui.prepare_canvas();
|
||||
// Prepare layers
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_file', 'New File', [
|
||||
new app.Actions.Prepare_canvas_action('undo'),
|
||||
new app.Actions.Update_config_action({
|
||||
TRANSPARENCY: !!transparency,
|
||||
WIDTH: parseInt(width),
|
||||
HEIGHT: parseInt(height),
|
||||
ALPHA: 255,
|
||||
COLOR: '#008000',
|
||||
mouse: {},
|
||||
visible_width: null,
|
||||
visible_height: null
|
||||
}),
|
||||
new app.Actions.Prepare_canvas_action('do'),
|
||||
new app.Actions.Reset_layers_action(),
|
||||
new app.Actions.Init_canvas_zoom_action(),
|
||||
new app.Actions.Insert_layer_action({})
|
||||
])
|
||||
);
|
||||
|
||||
//prepare layers
|
||||
this.Base_layers.reset_layers();
|
||||
this.Base_layers.init_zoom_lib();
|
||||
this.Base_layers.insert({});
|
||||
config.need_render = true;
|
||||
|
||||
//last resolution
|
||||
// Last resolution
|
||||
var last_resolution = JSON.stringify([config.WIDTH, config.HEIGHT]);
|
||||
this.Helper.setCookie('last_resolution', last_resolution);
|
||||
|
||||
//save_resolution
|
||||
// Save resolution
|
||||
if (save_resolution) {
|
||||
this.Helper.setCookie('save_resolution', 1);
|
||||
}
|
||||
else {
|
||||
this.Helper.setCookie('save_resolution', 0);
|
||||
}
|
||||
|
||||
//transparency
|
||||
// Save transparency
|
||||
if (transparency) {
|
||||
this.Helper.setCookie('transparency', 1);
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Base_gui_class from './../../core/base-gui.js';
|
||||
@ -58,7 +59,9 @@ class File_open_class {
|
||||
type: 'image',
|
||||
data: data,
|
||||
};
|
||||
this.Base_layers.insert(new_layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(new_layer)
|
||||
);
|
||||
}
|
||||
|
||||
open_file() {
|
||||
@ -125,8 +128,12 @@ class File_open_class {
|
||||
width_original: width,
|
||||
height_original: height,
|
||||
};
|
||||
this.Base_layers.insert(new_layer);
|
||||
_this.Base_layers.autoresize(width, height);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_webcam', 'Open File Webcam', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(width, height)
|
||||
])
|
||||
);
|
||||
|
||||
//destroy
|
||||
if(track != null){
|
||||
@ -207,8 +214,12 @@ class File_open_class {
|
||||
width_original: img.width,
|
||||
height_original: img.height,
|
||||
};
|
||||
_this.Base_layers.insert(new_layer);
|
||||
_this.Base_layers.autoresize(img.width, img.height);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_data_url', 'Open File Data URL', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(img.width, img.height)
|
||||
])
|
||||
);
|
||||
img.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
@ -280,7 +291,9 @@ class File_open_class {
|
||||
data: event.target.result,
|
||||
order: order,
|
||||
};
|
||||
_this.Base_layers.insert(new_layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(new_layer)
|
||||
);
|
||||
_this.extract_exif(this.file);
|
||||
}
|
||||
else {
|
||||
@ -365,8 +378,12 @@ class File_open_class {
|
||||
img.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
_this.Base_layers.insert(new_layer);
|
||||
_this.Base_layers.autoresize(img.width, img.height);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_url', 'Open File URL', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(img.width, img.height)
|
||||
])
|
||||
);
|
||||
};
|
||||
img.onerror = function (ex) {
|
||||
alertify.error('Sorry, image could not be loaded. Try copy image and paste it.');
|
||||
@ -415,12 +432,19 @@ class File_open_class {
|
||||
}
|
||||
}
|
||||
|
||||
const actions = [];
|
||||
|
||||
//set attributes
|
||||
config.ZOOM = 1;
|
||||
config.WIDTH = parseInt(json.info.width);
|
||||
config.HEIGHT = parseInt(json.info.height);
|
||||
this.Base_layers.reset_layers();
|
||||
this.Base_gui.prepare_canvas();
|
||||
actions.push(
|
||||
new app.Actions.Prepare_canvas_action('undo'),
|
||||
new app.Actions.Update_config_action({
|
||||
ZOOM: 1,
|
||||
WIDTH: parseInt(json.info.width),
|
||||
HEIGHT: parseInt(json.info.height)
|
||||
}),
|
||||
new app.Actions.Reset_layers_action(),
|
||||
new app.Actions.Prepare_canvas_action('do'),
|
||||
);
|
||||
|
||||
for (var i in json.layers) {
|
||||
var value = json.layers[i];
|
||||
@ -434,12 +458,18 @@ class File_open_class {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Base_layers.insert(value, false);
|
||||
actions.push(
|
||||
new app.Actions.Insert_layer_action(value, false)
|
||||
);
|
||||
}
|
||||
if(json.info.layer_active != undefined) {
|
||||
this.Base_layers.select(json.info.layer_active);
|
||||
if (json.info.layer_active != undefined) {
|
||||
actions.push(
|
||||
new app.Actions.Select_layer_action(json.info.layer_active, true)
|
||||
);
|
||||
}
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_json_file', 'Open JSON File', actions)
|
||||
);
|
||||
}
|
||||
|
||||
extract_exif(object) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
@ -112,10 +113,10 @@ class File_save_class {
|
||||
if (config.layers[i].visible == false)
|
||||
continue;
|
||||
|
||||
this.Base_layers.select(config.layers[i].id);
|
||||
new app.Actions.Select_layer_action(config.layers[i].id, true).do();
|
||||
_this.save_action(params, true);
|
||||
}
|
||||
this.Base_layers.select(active_layer);
|
||||
new app.Actions.Select_layer_action(active_layer, true).do();
|
||||
}
|
||||
else {
|
||||
_this.save_action(params);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
@ -8,8 +9,9 @@ class Layer_delete_class {
|
||||
}
|
||||
|
||||
delete() {
|
||||
window.State.save();
|
||||
this.Base_layers.delete(config.layer.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Dialog_class from './../../libs/popup.js';
|
||||
@ -79,12 +80,13 @@ class Layer_differences_class {
|
||||
//show
|
||||
if (canvas_preview == undefined) {
|
||||
//main
|
||||
window.State.save();
|
||||
var params = [];
|
||||
params.type = 'image';
|
||||
params.name = 'Differences';
|
||||
params.data = canvas.toDataURL("image/png");
|
||||
this.Base_layers.insert(params);
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(params)
|
||||
);
|
||||
}
|
||||
else {
|
||||
//preview
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
@ -56,7 +57,11 @@ class Layer_duplicate_class {
|
||||
params.link = config.layer.link.cloneNode(true);
|
||||
}
|
||||
|
||||
this.Base_layers.insert(params);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('duplicate_layer', 'Duplicate Layer', [
|
||||
new app.Actions.Insert_layer_action(params)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
@ -39,15 +40,20 @@ class Layer_flatten_class {
|
||||
params.type = 'image';
|
||||
params.name = 'Merged';
|
||||
params.data = canvas.toDataURL("image/png");
|
||||
this.Base_layers.insert(params);
|
||||
|
||||
//remove all layers
|
||||
//remove rest of layers
|
||||
let delete_actions = [];
|
||||
for (var i = config.layers.length - 1; i >= 0; i--) {
|
||||
if (config.layers[i].id == config.layer.id)
|
||||
continue;
|
||||
|
||||
this.Base_layers.delete(config.layers[i].id);
|
||||
delete_actions.push(new app.Actions.Delete_layer_action(config.layers[i].id));
|
||||
}
|
||||
console.log(delete_actions);
|
||||
// Run actions
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('flatten_image', 'Flatten Image', [
|
||||
new app.Actions.Insert_layer_action(params),
|
||||
...delete_actions
|
||||
])
|
||||
);
|
||||
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
@ -42,11 +43,13 @@ class Layer_merge_class {
|
||||
params.name = config.layer.name + ' + merged';
|
||||
params.order = current_order;
|
||||
params.data = canvas.toDataURL("image/png");
|
||||
this.Base_layers.insert(params);
|
||||
|
||||
//remove old layer
|
||||
this.Base_layers.delete(current_id);
|
||||
this.Base_layers.delete(previous_id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('merge_layers', 'Merge Layers', [
|
||||
new app.Actions.Insert_layer_action(params),
|
||||
new app.Actions.Delete_layer_action(current_id),
|
||||
new app.Actions.Delete_layer_action(previous_id)
|
||||
])
|
||||
);
|
||||
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import GUI_tools_class from './../../core/gui/gui-tools.js';
|
||||
@ -31,9 +32,10 @@ class Layer_new_class {
|
||||
}, false);
|
||||
}
|
||||
|
||||
new () {
|
||||
window.State.save();
|
||||
this.Base_layers.insert();
|
||||
new() {
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action()
|
||||
);
|
||||
}
|
||||
|
||||
new_selection() {
|
||||
@ -83,7 +85,9 @@ class Layer_new_class {
|
||||
type: 'image',
|
||||
data: canvas.toDataURL("image/png"),
|
||||
};
|
||||
this.Base_layers.insert(params, false);
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(params, false)
|
||||
);
|
||||
|
||||
this.Selection.on_leave();
|
||||
this.GUI_tools.activate_tool('select');
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
@ -13,8 +14,6 @@ class Layer_raster_class {
|
||||
var current_layer = config.layer;
|
||||
var current_id = current_layer.id;
|
||||
|
||||
window.State.save();
|
||||
|
||||
//show
|
||||
var params = {
|
||||
type: 'image',
|
||||
@ -26,9 +25,12 @@ class Layer_raster_class {
|
||||
height: canvas.height,
|
||||
opacity: current_layer.opacity,
|
||||
};
|
||||
this.Base_layers.insert(params, false);
|
||||
|
||||
this.Base_layers.delete(current_id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('convert_to_raster', 'Convert to Raster', [
|
||||
new app.Actions.Insert_layer_action(params, false),
|
||||
new app.Actions.Delete_layer_action(current_id)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Dialog_class from './../../libs/popup.js';
|
||||
@ -60,8 +61,6 @@ class Tools_borders_class {
|
||||
}
|
||||
|
||||
add_borders(params) {
|
||||
window.State.save();
|
||||
|
||||
//create borders layer
|
||||
this.layer = {
|
||||
name: 'Borders',
|
||||
@ -75,7 +74,11 @@ class Tools_borders_class {
|
||||
height: config.HEIGHT,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('add_borders', 'Add Borders', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
@ -158,7 +159,11 @@ class Tools_keypoints_class {
|
||||
params.y = parseInt(clone.dataset.y);
|
||||
params.width = clone.width;
|
||||
params.height = clone.height;
|
||||
this.Base_layers.insert(params);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('keypoints', 'Key-Points', [
|
||||
new app.Actions.Insert_layer_action(params)
|
||||
])
|
||||
);
|
||||
|
||||
clone.width = 1;
|
||||
clone.height = 1;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -18,6 +19,7 @@ class Animation_class extends Base_tools_class {
|
||||
this.name = 'animation';
|
||||
this.intervalID = null;
|
||||
this.index = 0;
|
||||
this.toggle_layer_visibility_action = new app.Actions.Toggle_layer_visibility_action();
|
||||
|
||||
this.disable_selection(ctx);
|
||||
}
|
||||
@ -102,7 +104,8 @@ class Animation_class extends Base_tools_class {
|
||||
|
||||
//show 1
|
||||
if (config.layers[this.index] != undefined) {
|
||||
_this.Base_layers.toggle_visibility(config.layers[this.index].id);
|
||||
this.toggle_layer_visibility_action.layer_id = config.layers[this.index].id;
|
||||
this.toggle_layer_visibility_action.do();
|
||||
}
|
||||
|
||||
//change index
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -98,8 +99,6 @@ class Brush_class extends Base_tools_class {
|
||||
if (mouse.valid == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
window.State.save();
|
||||
|
||||
var params_hash = this.get_params_hash();
|
||||
|
||||
if (config.layer.type != this.name || params_hash != this.params_hash) {
|
||||
@ -118,7 +117,11 @@ class Brush_class extends Base_tools_class {
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_brush_layer', 'New Brush Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -65,8 +66,6 @@ class Circle_class extends Base_tools_class {
|
||||
if (mouse.valid == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
window.State.save();
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
@ -85,7 +84,11 @@ class Circle_class extends Base_tools_class {
|
||||
//disable rotate
|
||||
this.layer.rotate = null;
|
||||
}
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_circle_layer', 'New Circle Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
@ -131,7 +134,9 @@ class Circle_class extends Base_tools_class {
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
this.Base_layers.delete(config.layer.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -117,7 +118,11 @@ class Fill_class extends Base_tools_class {
|
||||
params.y = parseInt(canvas.dataset.y) || 0;
|
||||
params.width = canvas.width;
|
||||
params.height = canvas.height;
|
||||
this.Base_layers.insert(params);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('fill', 'Fill', [
|
||||
new app.Actions.Insert_layer_action(params)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//prevent crash bug on touch screen - hard to explain and debug
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -74,8 +75,6 @@ class Gradient_class extends Base_tools_class {
|
||||
is_vector = true;
|
||||
}
|
||||
|
||||
window.State.save();
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
@ -93,7 +92,11 @@ class Gradient_class extends Base_tools_class {
|
||||
center_y: mouse.y,
|
||||
},
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('gradient', 'Gradient', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
@ -135,7 +138,9 @@ class Gradient_class extends Base_tools_class {
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
this.Base_layers.delete(config.layer.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -64,8 +65,6 @@ class Line_class extends Base_tools_class {
|
||||
if (mouse.valid == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
window.State.save();
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
@ -77,7 +76,11 @@ class Line_class extends Base_tools_class {
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('line', 'Line', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
@ -116,7 +119,9 @@ class Line_class extends Base_tools_class {
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
this.Base_layers.delete(config.layer.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -95,7 +96,11 @@ class Pencil_class extends Base_tools_class {
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_pencil_layer', 'New Pencil Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -64,8 +65,6 @@ class Rectangle_class extends Base_tools_class {
|
||||
if (mouse.valid == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
window.State.save();
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
@ -76,7 +75,11 @@ class Rectangle_class extends Base_tools_class {
|
||||
y: mouse.y,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(this.layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('rectangle', 'Rectangle', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
@ -142,7 +145,9 @@ class Rectangle_class extends Base_tools_class {
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
this.Base_layers.delete(config.layer.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
@ -64,9 +65,9 @@ class Select_tool_class extends Base_tools_class {
|
||||
|
||||
//keyboard actions
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (config.TOOL.name != _this.name)
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (_this.POP.active == true)
|
||||
if (this.POP.active == true)
|
||||
return;
|
||||
if (this.Helper.is_input(e.target))
|
||||
return;
|
||||
@ -74,24 +75,26 @@ class Select_tool_class extends Base_tools_class {
|
||||
|
||||
//up
|
||||
if (k == 38) {
|
||||
_this.move(0, -1, e);
|
||||
this.move(0, -1, e);
|
||||
}
|
||||
//down
|
||||
else if (k == 40) {
|
||||
_this.move(0, 1, e);
|
||||
this.move(0, 1, e);
|
||||
}
|
||||
//right
|
||||
else if (k == 39) {
|
||||
_this.move(1, 0, e);
|
||||
this.move(1, 0, e);
|
||||
}
|
||||
//left
|
||||
else if (k == 37) {
|
||||
_this.move(-1, 0, e);
|
||||
this.move(-1, 0, e);
|
||||
}
|
||||
if (k == 46) {
|
||||
//delete
|
||||
if (config.TOOL.name == _this.name) {
|
||||
_this.Base_layers.delete(config.layer.id);
|
||||
if (config.TOOL.name == this.name) {
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -166,7 +169,9 @@ class Select_tool_class extends Base_tools_class {
|
||||
var canvas = this.Base_layers.convert_layer_to_canvas(value.id, null, false);
|
||||
|
||||
if (this.check_hit_region(e, canvas.getContext("2d")) == true) {
|
||||
this.Base_layers.select(value.id);
|
||||
app.State.do_action(
|
||||
new app.Actions.Select_layer_action(value.id)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import zoomView from './../libs/zoomView.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
@ -2037,14 +2038,17 @@ class Text_class extends Base_tools_class {
|
||||
this.selecting = true;
|
||||
this.layer = existingLayer;
|
||||
const editor = this.get_editor(this.layer);
|
||||
this.Base_layers.select(existingLayer.id);
|
||||
editor.trigger_cursor_start(this.layer, -1 + mouse.x - this.layer.x, mouse.y - this.layer.y);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('select_text_layer', 'Select Text Layer', [
|
||||
new app.Actions.Select_layer_action(existingLayer.id)
|
||||
])
|
||||
);
|
||||
this.Base_selection.set_selection(this.layer.x, this.layer.y, this.layer.width, this.layer.height);
|
||||
}
|
||||
else {
|
||||
// Create a new text layer
|
||||
this.creating = true;
|
||||
window.State.save();
|
||||
const layer = {
|
||||
type: this.name,
|
||||
params: {
|
||||
@ -2062,7 +2066,11 @@ class Text_class extends Base_tools_class {
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
};
|
||||
this.Base_layers.insert(layer);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_text_layer', 'New Text Layer', [
|
||||
new app.Actions.Insert_layer_action(layer)
|
||||
])
|
||||
);
|
||||
this.layer = config.layer;
|
||||
this.Base_selection.set_selection(mouse.x, mouse.y, 0, 0);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user