|
|
|
function undo(state, context, event, options) {
|
|
|
|
let need_draw = false;
|
|
|
|
|
|
|
|
// Remove effect of latest own event, in a way that is recoverable
|
|
|
|
|
|
|
|
// Iterate back to front to find the _latest_ event
|
|
|
|
for (let i = state.events.length - 1; i >=0; --i) {
|
|
|
|
const other_event = state.events[i];
|
|
|
|
let skipped = false;
|
|
|
|
|
|
|
|
// Users can only undo their own, undeleted (not already undone) events
|
|
|
|
if (other_event.user_id === event.user_id && !other_event.deleted) {
|
|
|
|
// All "persistent" events (those that are pushed using SYN messages) should be handled here
|
|
|
|
// "Transient" events are by design droppable, and should not be undone, nor saved in state.events at all
|
|
|
|
switch (other_event.type) {
|
|
|
|
case EVENT.STROKE: {
|
|
|
|
other_event.deleted = true;
|
|
|
|
if (other_event.bvh_node && !options.skip_bvh) {
|
|
|
|
bvh_delete_stroke(state, other_event);
|
|
|
|
}
|
|
|
|
need_draw = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EVENT.UNDO: {
|
|
|
|
// do not undo an undo, we are not Notepad
|
|
|
|
skipped = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EVENT.IMAGE: {
|
|
|
|
other_event.deleted = true;
|
|
|
|
const image = get_image(context, other_event.image_id);
|
|
|
|
if (image !== null) {
|
|
|
|
image.deleted = true;
|
|
|
|
}
|
|
|
|
need_draw = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EVENT.IMAGE_MOVE: {
|
|
|
|
other_event.deleted = true;
|
|
|
|
const image = get_image(context, other_event.image_id);
|
|
|
|
if (image !== null) {
|
|
|
|
pop_image_transform(image);
|
|
|
|
need_draw = true;
|
|
|
|
} else {
|
|
|
|
console.warning('Undo image move for a non-existent image');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EVENT.IMAGE_SCALE: {
|
|
|
|
other_event.deleted = true;
|
|
|
|
const image = get_image(context, other_event.image_id);
|
|
|
|
if (image !== null) {
|
|
|
|
pop_image_transform(image);
|
|
|
|
need_draw = true;
|
|
|
|
} else {
|
|
|
|
console.warning('Undo image scale for a non-existent image');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EVENT.ERASER: {
|
|
|
|
other_event.deleted = true;
|
|
|
|
const stroke = state.events[other_event.stroke_id];
|
|
|
|
stroke.deleted = false;
|
|
|
|
if (!options.skip_bvh) {
|
|
|
|
bvh_undelete_stroke(state, stroke);
|
|
|
|
}
|
|
|
|
need_draw = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
console.error('cant undo event type', other_event.type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!skipped) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return need_draw;
|
|
|
|
}
|
|
|
|
|
|
|
|
function redo() {
|
|
|
|
console.log('TODO');
|
|
|
|
}
|
|
|
|
|
|
|
|
function push_image_move(image, x, y) {
|
|
|
|
if (image.transform_head < image.transform_history.length) {
|
|
|
|
image.transform_history[image.transform_head] = image.at.x;
|
|
|
|
image.transform_history[image.transform_head + 1] = image.at.y;
|
|
|
|
image.transform_history[image.transform_head + 2] = image.width;
|
|
|
|
image.transform_history[image.transform_head + 3] = image.height;
|
|
|
|
} else {
|
|
|
|
image.transform_history.push(image.at.x, image.at.y, image.width, image.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
image.at.x = x;
|
|
|
|
image.at.y = y;
|
|
|
|
|
|
|
|
image.transform_head += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
function push_image_scale(image, corner, x, y) {
|
|
|
|
if (image.transform_head < image.transform_history.length) {
|
|
|
|
image.transform_history[image.transform_head] = image.at.x;
|
|
|
|
image.transform_history[image.transform_head + 1] = image.at.y;
|
|
|
|
image.transform_history[image.transform_head + 2] = image.width;
|
|
|
|
image.transform_history[image.transform_head + 3] = image.height;
|
|
|
|
} else {
|
|
|
|
image.transform_history.push(image.at.x, image.at.y, image.width, image.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
scale_image(image, corner, {'x': x, 'y': y});
|
|
|
|
|
|
|
|
image.transform_head += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
function pop_image_transform(image, corner, x, y) {
|
|
|
|
image.transform_head -= 4;
|
|
|
|
image.at.x = image.transform_history[image.transform_head - 4];
|
|
|
|
image.at.y = image.transform_history[image.transform_head - 3];
|
|
|
|
image.width = image.transform_history[image.transform_head - 2];
|
|
|
|
image.height = image.transform_history[image.transform_head - 1];
|
|
|
|
}
|