From 0ac7789bf9bd43eaabfeb472e8954a4b445f1545 Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com> Date: Fri, 5 Apr 2024 18:02:46 +0300 Subject: [PATCH] Store image data in undo/redo of the move tool, reverts 4f5f37a52286cb68899e29d6505ebe065d4880f5 This fixes an issue where, if the user moves pixels outside the canvas and then undos, those cut pixels will not be restored. --- src/Autoload/Global.gd | 14 +++--------- src/Tools/UtilityTools/Move.gd | 39 ++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index a87352672..1fc1b9c34 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -1012,6 +1012,8 @@ func set_locale(locale: String) -> void: ## Used by undo/redo operations to store compressed images in memory. +## [param redo_data] and [param undo_data] are Dictionaries, +## with keys of type [Image] and [Dictionary] values, coming from [member Image.data]. func undo_redo_compress_images( redo_data: Dictionary, undo_data: Dictionary, project := current_project ) -> void: @@ -1038,7 +1040,7 @@ func undo_redo_compress_images( ## Decompresses the [param compressed_image_data] with [param buffer_size] to the [param image] -## This is an optimization method used while performing undo/redo drawing operations. +## This is a memory optimization method used while performing undo/redo drawing operations. func undo_redo_draw_op( image: Image, new_size: Vector2i, compressed_image_data: PackedByteArray, buffer_size: int ) -> void: @@ -1046,16 +1048,6 @@ func undo_redo_draw_op( image.set_data(new_size.x, new_size.y, image.has_mipmaps(), image.get_format(), decompressed) -## Used by the Move tool for undo/redo, moves all of the [Image]s in [param images] -## by [param diff] pixels. -func undo_redo_move(diff: Vector2i, images: Array[Image]) -> void: - for image in images: - var image_copy := Image.new() - image_copy.copy_from(image) - image.fill(Color(0, 0, 0, 0)) - image.blit_rect(image_copy, Rect2i(Vector2i.ZERO, image.get_size()), diff) - - func create_ui_for_shader_uniforms( shader: Shader, params: Dictionary, diff --git a/src/Tools/UtilityTools/Move.gd b/src/Tools/UtilityTools/Move.gd index c0945982c..4918e90f3 100644 --- a/src/Tools/UtilityTools/Move.gd +++ b/src/Tools/UtilityTools/Move.gd @@ -2,11 +2,11 @@ extends BaseTool var _start_pos: Vector2i var _offset: Vector2i - ## Used to check if the state of content transformation has been changed ## while draw_move() is being called. For example, pressing Enter while still moving content var _content_transformation_check := false var _snap_to_grid := false ## Mouse Click + Ctrl +var _undo_data := {} @onready var selection_node: Node2D = Global.canvas.selection @@ -40,6 +40,7 @@ func draw_start(pos: Vector2i) -> void: return _start_pos = pos _offset = pos + _undo_data = _get_undo_data() if Global.current_project.has_selection: selection_node.transform_content_start() _content_transformation_check = selection_node.is_moving_content @@ -82,8 +83,13 @@ func draw_end(pos: Vector2i) -> void: else: var pixel_diff := pos - _start_pos Global.canvas.move_preview_location = Vector2i.ZERO - - _commit_undo("Draw", pixel_diff) + var images := _get_selected_draw_images() + for image in images: + var image_copy := Image.new() + image_copy.copy_from(image) + image.fill(Color(0, 0, 0, 0)) + image.blit_rect(image_copy, Rect2i(Vector2i.ZERO, project.size), pixel_diff) + _commit_undo("Draw") _start_pos = Vector2.INF _snap_to_grid = false @@ -115,7 +121,8 @@ func _snap_position(pos: Vector2) -> Vector2: return pos -func _commit_undo(action: String, diff: Vector2i) -> void: +func _commit_undo(action: String) -> void: + var redo_data := _get_undo_data() var project := Global.current_project var frame := -1 var layer := -1 @@ -123,11 +130,29 @@ func _commit_undo(action: String, diff: Vector2i) -> void: frame = project.current_frame layer = project.current_layer - var images := _get_selected_draw_images() project.undos += 1 project.undo_redo.create_action(action) - project.undo_redo.add_do_method(Global.undo_redo_move.bind(diff, images)) + Global.undo_redo_compress_images(redo_data, _undo_data, project) project.undo_redo.add_do_method(Global.undo_or_redo.bind(false, frame, layer)) - project.undo_redo.add_undo_method(Global.undo_redo_move.bind(-diff, images)) project.undo_redo.add_undo_method(Global.undo_or_redo.bind(true, frame, layer)) project.undo_redo.commit_action() + _undo_data.clear() + + +func _get_undo_data() -> Dictionary: + var data := {} + var project := Global.current_project + var cels: Array[BaseCel] = [] + if Global.animation_timer.is_stopped(): + for cel_index in project.selected_cels: + cels.append(project.frames[cel_index[0]].cels[cel_index[1]]) + else: + for frame in project.frames: + var cel := frame.cels[project.current_layer] + cels.append(cel) + for cel in cels: + if not cel is PixelCel: + continue + var image: Image = cel.image + data[image] = image.data + return data