From c1028131a1d73d47bd289cc1d035503939535d1f Mon Sep 17 00:00:00 2001 From: Emmanouil Papadeas <35376950+OverloadedOrama@users.noreply.github.com> Date: Sun, 24 Nov 2024 22:23:05 +0200 Subject: [PATCH] Undo/redo now removes tiles and re-indexes tilemap tiles --- src/Autoload/Global.gd | 6 +++++- src/Classes/Cels/BaseCel.gd | 2 +- src/Classes/Cels/CelTileMap.gd | 11 +++++++---- src/Classes/TileSetCustom.gd | 28 ++++++++++++++++------------ src/Tools/BaseTool.gd | 7 ------- src/Tools/DesignTools/Pencil.gd | 21 +++++++++++---------- src/Tools/UtilityTools/Text.gd | 1 - src/UI/Canvas/Selection.gd | 2 -- src/UI/Timeline/AnimationTimeline.gd | 2 +- 9 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index 49a0caa16..7977d45d4 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -954,7 +954,7 @@ func general_redo(project := current_project) -> void: ## Performs actions done after an undo or redo is done. this takes [member general_undo] and ## [member general_redo] a step further. Does further work if the current action requires it ## like refreshing textures, redraw UI elements etc...[br] -## [param frame_index] and [param layer_index] are there for optimizzation. if the undo or redo +## [param frame_index] and [param layer_index] are there for optimization. if the undo or redo ## happens only in one cel then the cel's frame and layer should be passed to [param frame_index] ## and [param layer_index] respectively, otherwise the entire timeline will be refreshed. func undo_or_redo( @@ -981,10 +981,14 @@ func undo_or_redo( ): if layer_index > -1 and frame_index > -1: canvas.update_texture(layer_index, frame_index, project) + var cel := project.frames[frame_index].cels[layer_index] + cel.on_undo_redo(undo) else: for i in project.frames.size(): for j in project.layers.size(): canvas.update_texture(j, i, project) + var cel := project.frames[i].cels[j] + cel.on_undo_redo(undo) canvas.selection.queue_redraw() if action_name == "Scale": diff --git a/src/Classes/Cels/BaseCel.gd b/src/Classes/Cels/BaseCel.gd index 313544956..f5ccc7b73 100644 --- a/src/Classes/Cels/BaseCel.gd +++ b/src/Classes/Cels/BaseCel.gd @@ -77,7 +77,7 @@ func update_texture() -> void: cel.texture_changed.emit() -func tool_finished_drawing() -> void: +func on_undo_redo(undo: bool) -> void: pass diff --git a/src/Classes/Cels/CelTileMap.gd b/src/Classes/Cels/CelTileMap.gd index e9610901e..3f0fa576d 100644 --- a/src/Classes/Cels/CelTileMap.gd +++ b/src/Classes/Cels/CelTileMap.gd @@ -36,11 +36,11 @@ func update_texture() -> void: super.update_texture() -func tool_finished_drawing() -> void: - update_tileset() +func on_undo_redo(undo: bool) -> void: + update_tileset(undo) -func update_tileset() -> void: +func update_tileset(undo: bool) -> void: for i in indices.size(): var coords := get_tile_coords(i) var rect := Rect2i(coords, tileset.tile_size) @@ -74,6 +74,10 @@ func update_tileset() -> void: if not found_tile: tileset.add_tile(image_portion, TileSetPanel.tile_editing_mode) indices[i] = tileset.tiles.size() - 1 + if undo: + var tile_removed := tileset.remove_unused_tiles() + if tile_removed: + re_index_tiles() ## Cases:[br] @@ -209,7 +213,6 @@ func get_tile_position(coords: Vector2i) -> int: return x + y -## Unused, should delete. func re_index_tiles() -> void: for i in indices.size(): var x_coord := float(tileset.tile_size.x) * (i % indices_x) diff --git a/src/Classes/TileSetCustom.gd b/src/Classes/TileSetCustom.gd index 8d5867a30..8fb9b3849 100644 --- a/src/Classes/TileSetCustom.gd +++ b/src/Classes/TileSetCustom.gd @@ -3,6 +3,7 @@ extends RefCounted signal updated +var project: Project var name := "" var tile_size: Vector2i var tiles: Array[Tile] = [] @@ -12,40 +13,44 @@ class Tile: var image: Image var mode_added: TileSetPanel.TileEditingMode var times_used := 1 + var undo_step_added := 0 - func _init(_image: Image, _mode_added: TileSetPanel.TileEditingMode) -> void: + func _init( + _image: Image, _mode_added: TileSetPanel.TileEditingMode, _undo_step_added := 0 + ) -> void: image = _image mode_added = _mode_added + undo_step_added = _undo_step_added - func can_be_removed() -> bool: + func can_be_removed(project: Project) -> bool: + if project.undos < undo_step_added: + return true return mode_added != TileSetPanel.TileEditingMode.STACK and times_used <= 0 -func _init(_tile_size: Vector2i, _name := "") -> void: +func _init(_tile_size: Vector2i, _project: Project, _name := "") -> void: tile_size = _tile_size + project = _project name = _name - #var indices_x := ceili(float(_project_size.x) / tile_size.x) - #var indices_y := ceili(float(_project_size.y) / tile_size.y) - #tiles.resize(indices_x * indices_y + 1) var empty_image := Image.create_empty(tile_size.x, tile_size.y, false, Image.FORMAT_RGBA8) tiles.append(Tile.new(empty_image, TileSetPanel.tile_editing_mode)) func add_tile(image: Image, edit_mode: TileSetPanel.TileEditingMode) -> void: - var tile := Tile.new(image, edit_mode) + var tile := Tile.new(image, edit_mode, project.undos) tiles.append(tile) updated.emit() func insert_tile(image: Image, position: int, edit_mode: TileSetPanel.TileEditingMode) -> void: - var tile := Tile.new(image, edit_mode) + var tile := Tile.new(image, edit_mode, project.undos) tiles.insert(position, tile) updated.emit() func unuse_tile_at_index(index: int) -> bool: tiles[index].times_used -= 1 - if tiles[index].can_be_removed(): + if tiles[index].can_be_removed(project): remove_tile_at_index(index) return true return false @@ -69,12 +74,11 @@ func find_tile(image: Image) -> int: return -1 -## Unused, should delete. func remove_unused_tiles() -> bool: var tile_removed := false for i in range(tiles.size() - 1, 0, -1): var tile := tiles[i] - if tile.can_be_removed(): - tile_removed = true + if tile.can_be_removed(project): remove_tile_at_index(i) + tile_removed = true return tile_removed diff --git a/src/Tools/BaseTool.gd b/src/Tools/BaseTool.gd index 0d60398ff..4e173e7fc 100644 --- a/src/Tools/BaseTool.gd +++ b/src/Tools/BaseTool.gd @@ -76,16 +76,9 @@ func draw_end(_pos: Vector2i) -> void: is_moving = false _draw_cache = [] var project := Global.current_project - update_cels(project) project.can_undo = true -func update_cels(project := Global.current_project) -> void: - for cel_index in project.selected_cels: - var cel := project.frames[cel_index[0]].cels[cel_index[1]] as BaseCel - cel.tool_finished_drawing() - - func is_placing_tiles() -> bool: return Global.current_project.get_current_cel() is CelTileMap and TileSetPanel.placing_tiles diff --git a/src/Tools/DesignTools/Pencil.gd b/src/Tools/DesignTools/Pencil.gd index f373d7dda..3a47716a1 100644 --- a/src/Tools/DesignTools/Pencil.gd +++ b/src/Tools/DesignTools/Pencil.gd @@ -96,9 +96,6 @@ func draw_start(pos: Vector2i) -> void: _old_spacing_mode = _spacing_mode pos = snap_position(pos) super.draw_start(pos) - if is_placing_tiles(): - draw_tile(pos, TileSetPanel.selected_tile_index) - return if Input.is_action_pressed(&"draw_color_picker", true): _picking_color = true _pick_color(pos) @@ -106,6 +103,10 @@ func draw_start(pos: Vector2i) -> void: _picking_color = false Global.canvas.selection.transform_content_confirm() + prepare_undo("Draw") + if is_placing_tiles(): + draw_tile(pos, TileSetPanel.selected_tile_index) + return var can_skip_mask := true if tool_slot.color.a < 1 and !_overwrite: can_skip_mask = false @@ -115,7 +116,6 @@ func draw_start(pos: Vector2i) -> void: _drawer.color_op.overwrite = _overwrite _draw_points = [] - prepare_undo("Draw") _drawer.reset() _draw_line = Input.is_action_pressed("draw_create_line") @@ -141,13 +141,13 @@ func draw_move(pos_i: Vector2i) -> void: var pos := _get_stabilized_position(pos_i) pos = snap_position(pos) super.draw_move(pos) - if is_placing_tiles(): - draw_tile(pos, TileSetPanel.selected_tile_index) - return if _picking_color: # Still return even if we released Alt if Input.is_action_pressed(&"draw_color_picker", true): _pick_color(pos) return + if is_placing_tiles(): + draw_tile(pos, TileSetPanel.selected_tile_index) + return if _draw_line: _spacing_mode = false # spacing mode is disabled during line mode @@ -170,12 +170,13 @@ func draw_move(pos_i: Vector2i) -> void: func draw_end(pos: Vector2i) -> void: pos = snap_position(pos) + if _picking_color: + super.draw_end(pos) + return if is_placing_tiles(): super.draw_end(pos) draw_tile(pos, TileSetPanel.selected_tile_index) - return - if _picking_color: - super.draw_end(pos) + commit_undo() return if _draw_line: diff --git a/src/Tools/UtilityTools/Text.gd b/src/Tools/UtilityTools/Text.gd index f267254bb..b3ce7a3e2 100644 --- a/src/Tools/UtilityTools/Text.gd +++ b/src/Tools/UtilityTools/Text.gd @@ -158,7 +158,6 @@ func text_to_pixels() -> void: if image is ImageExtended: image.convert_rgb_to_indexed() commit_undo("Draw", undo_data) - update_cels(project) func commit_undo(action: String, undo_data: Dictionary) -> void: diff --git a/src/UI/Canvas/Selection.gd b/src/UI/Canvas/Selection.gd index 9f12b69b2..f28fd7cd7 100644 --- a/src/UI/Canvas/Selection.gd +++ b/src/UI/Canvas/Selection.gd @@ -517,7 +517,6 @@ func transform_content_confirm() -> void: big_bounding_rectangle.position ) cel_image.convert_rgb_to_indexed() - cel.tool_finished_drawing() project.selection_map.move_bitmap_values(project) commit_undo("Move Selection", undo_data) @@ -553,7 +552,6 @@ func transform_content_cancel() -> void: big_bounding_rectangle.position ) cel.transformed_content = null - cel.tool_finished_drawing() for cel_index in project.selected_cels: canvas.update_texture(cel_index[1]) original_preview_image = Image.new() diff --git a/src/UI/Timeline/AnimationTimeline.gd b/src/UI/Timeline/AnimationTimeline.gd index dea3d6c52..a6255ffa6 100644 --- a/src/UI/Timeline/AnimationTimeline.gd +++ b/src/UI/Timeline/AnimationTimeline.gd @@ -847,7 +847,7 @@ func add_layer(type := 0) -> void: l = Layer3D.new(project) SteamManager.set_achievement("ACH_3D_LAYER") Global.LayerTypes.TILEMAP: - l = LayerTileMap.new(project, TileSetCustom.new(Vector2i(16, 16))) + l = LayerTileMap.new(project, TileSetCustom.new(Vector2i(16, 16), project)) var cels := [] for f in project.frames: