From cadd72793b8d9c21d0b70bdef6427125fd008a40 Mon Sep 17 00:00:00 2001 From: Marcelo Fernandez Date: Fri, 25 May 2018 13:59:05 -0300 Subject: [PATCH] Improve TileMap undo operations, second try --- editor/plugins/tile_map_editor_plugin.cpp | 94 +++++++++++++++-------- editor/plugins/tile_map_editor_plugin.h | 6 ++ scene/2d/tile_map.cpp | 6 ++ scene/2d/tile_map.h | 1 + 4 files changed, 77 insertions(+), 30 deletions(-) diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 72b3af5a096..ac2efe7acb7 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -132,16 +132,14 @@ void TileMapEditor::_menu_option(int p_option) { if (!selection_active) return; - undo_redo->create_action(TTR("Erase Selection")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Erase Selection")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); selection_active = false; copydata.clear(); @@ -200,6 +198,46 @@ void TileMapEditor::set_selected_tile(int p_tile) { } } +void TileMapEditor::_create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { + + Dictionary cell_old; + Dictionary cell_new; + + cell_old["id"] = p_cell_old.idx; + cell_old["flip_h"] = p_cell_old.xf; + cell_old["flip_y"] = p_cell_old.yf; + cell_old["transpose"] = p_cell_old.tr; + cell_old["auto_coord"] = p_cell_old.ac; + + cell_new["id"] = p_cell_new.idx; + cell_new["flip_h"] = p_cell_new.xf; + cell_new["flip_y"] = p_cell_new.yf; + cell_new["transpose"] = p_cell_new.tr; + cell_new["auto_coord"] = p_cell_new.ac; + + undo_redo->add_undo_method(node, "set_celld", p_vec, cell_old); + undo_redo->add_do_method(node, "set_celld", p_vec, cell_new); +} + +void TileMapEditor::_start_undo(const String &p_action) { + + undo_data.clear(); + undo_redo->create_action(p_action); +} + +void TileMapEditor::_finish_undo() { + + if (undo_data.size()) { + for (Map::Element *E = undo_data.front(); E; E = E->next()) { + _create_set_cell_undo(E->key(), E->get(), _get_op_from_cell(E->key())); + } + + undo_data.clear(); + } + + undo_redo->commit_action(); +} + void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) { ERR_FAIL_COND(!node); @@ -213,6 +251,15 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose) return; //check that it's actually different + for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { + for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { + Point2i p = Point2i(x, y); + if (!undo_data.has(p)) { + undo_data[p] = _get_op_from_cell(p); + } + } + } + node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); node->update_bitmask_area(Point2(p_pos)); } @@ -760,8 +807,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { tool = TOOL_PAINTING; - undo_redo->create_action(TTR("Paint TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Paint TileMap")); } } else if (tool == TOOL_PICKING) { @@ -785,8 +831,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { if (id != TileMap::INVALID_CELL) { _set_cell(over_tile, id, flip_h, flip_v, transpose); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); paint_undo.clear(); } @@ -796,14 +841,12 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { if (id != TileMap::INVALID_CELL) { - undo_redo->create_action(TTR("Line Draw")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Line Draw")); for (Map::Element *E = paint_undo.front(); E; E = E->next()) { _set_cell(E->key(), id, flip_h, flip_v, transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); paint_undo.clear(); @@ -815,16 +858,14 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { if (id != TileMap::INVALID_CELL) { - undo_redo->create_action(TTR("Rectangle Paint")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Rectangle Paint")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); canvas_item_editor->update(); } @@ -832,14 +873,12 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { Point2 ofs = over_tile - rectangle.position; - undo_redo->create_action(TTR("Duplicate")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Duplicate")); for (List::Element *E = copydata.front(); E; E = E->next()) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); copydata.clear(); @@ -848,8 +887,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { Point2 ofs = over_tile - rectangle.position; - undo_redo->create_action(TTR("Move")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Move")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { @@ -860,8 +898,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); copydata.clear(); selection_active = false; @@ -880,7 +917,6 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { return false; undo_redo->create_action(TTR("Bucket Fill")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); Dictionary op; op["id"] = get_selected_tile(); @@ -890,7 +926,6 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { _fill_points(points, op); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); // We want to keep the bucket-tool active @@ -942,8 +977,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); - undo_redo->create_action(TTR("Erase TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); + _start_undo(TTR("Erase TileMap")); if (mb->get_shift()) { #ifdef APPLE_STYLE_KEYS @@ -970,8 +1004,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { } else { if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); - undo_redo->commit_action(); + _finish_undo(); if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { canvas_item_editor->update(); @@ -1534,6 +1567,7 @@ TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) { op.yf = true; if (node->is_cell_transposed(p_pos.x, p_pos.y)) op.tr = true; + op.ac = node->get_cell_autotile_coord(p_pos.x, p_pos.y); } return op; } diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 642870aec09..292271c4f9e 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -124,6 +124,7 @@ class TileMapEditor : public VBoxContainer { bool xf; bool yf; bool tr; + Vector2 ac; CellOp() : idx(TileMap::INVALID_CELL), @@ -150,6 +151,8 @@ class TileMapEditor : public VBoxContainer { List copydata; + Map undo_data; + void _pick_tile(const Point2 &p_pos); PoolVector _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false); @@ -174,6 +177,9 @@ class TileMapEditor : public VBoxContainer { void _update_palette(); void _menu_option(int p_option); + void _start_undo(const String &p_action); + void _finish_undo(); + void _create_set_cell_undo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new); void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false); void _canvas_mouse_enter(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index d88e148b2c0..a6283502cb4 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -725,6 +725,11 @@ void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_ set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose); } +void TileMap::set_celld(const Vector2 &p_pos, const Dictionary &p_data) { + + set_cell(p_pos.x, p_pos.y, p_data["id"], p_data["flip_h"], p_data["flip_y"], p_data["transpose"], p_data["auto_coord"]); +} + void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose, Vector2 p_autotile_coord) { PosKey pk(p_x, p_y); @@ -1602,6 +1607,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_celld", "data"), &TileMap::set_celld); ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell); ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv); ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 07947004b32..01c92c5c250 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -241,6 +241,7 @@ public: void set_cell_autotile_coord(int p_x, int p_y, const Vector2 &p_coord); Vector2 get_cell_autotile_coord(int p_x, int p_y) const; + void set_celld(const Vector2 &p_pos, const Dictionary &p_data); void set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x = false, bool p_flip_y = false, bool p_transpose = false); int get_cellv(const Vector2 &p_pos) const;