Browse Source

Merge pull request #109878 from ryevdokimov/fix-grid-map-move

Fix `GridMap` Move Action Undo/Redo/Cancel
Rémi Verschelde 1 tuần trước cách đây
mục cha
commit
ff610712f5

+ 77 - 18
modules/gridmap/editor/grid_map_editor_plugin.cpp

@@ -150,33 +150,38 @@ void GridMapEditor::_menu_option(int p_option) {
 			options->get_popup()->set_item_checked(idx, !options->get_popup()->is_item_checked(idx));
 		} break;
 
-		case MENU_OPTION_SELECTION_DUPLICATE:
-		case MENU_OPTION_SELECTION_CUT: {
+		case MENU_OPTION_SELECTION_DUPLICATE: {
 			if (!(selection.active && input_action == INPUT_NONE)) {
 				break;
 			}
 
 			_set_clipboard_data();
+			clipboard_is_move = false;
 
-			if (p_option == MENU_OPTION_SELECTION_CUT) {
-				_delete_selection();
+			if (!clipboard_items.is_empty()) {
+				_setup_paste_mode();
 			}
+		} break;
 
-			input_action = INPUT_PASTE;
-			paste_indicator.click = selection.click;
-			paste_indicator.current = cursor_gridpos;
-			paste_indicator.begin = selection.begin;
-			paste_indicator.end = selection.end;
-			paste_indicator.distance_from_cursor = cursor_gridpos - paste_indicator.begin;
-			paste_indicator.orientation = 0;
-			_update_paste_indicator();
+		case MENU_OPTION_SELECTION_MOVE: {
+			if (!(selection.active && input_action == INPUT_NONE)) {
+				break;
+			}
+
+			_set_clipboard_data();
+			clipboard_is_move = true;
+
+			if (!clipboard_items.is_empty()) {
+				_delete_selection();
+				_setup_paste_mode();
+			}
 		} break;
 		case MENU_OPTION_SELECTION_CLEAR: {
 			if (!selection.active) {
 				break;
 			}
 
-			_delete_selection();
+			_delete_selection_with_undo();
 
 		} break;
 		case MENU_OPTION_SELECTION_FILL: {
@@ -506,6 +511,21 @@ void GridMapEditor::_delete_selection() {
 		return;
 	}
 
+	for (int i = selection.begin.x; i <= selection.end.x; i++) {
+		for (int j = selection.begin.y; j <= selection.end.y; j++) {
+			for (int k = selection.begin.z; k <= selection.end.z; k++) {
+				Vector3i selected = Vector3i(i, j, k);
+				node->set_cell_item(selected, GridMap::INVALID_CELL_ITEM);
+			}
+		}
+	}
+}
+
+void GridMapEditor::_delete_selection_with_undo() {
+	if (!selection.active) {
+		return;
+	}
+
 	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 	undo_redo->create_action(TTR("GridMap Delete Selection"));
 	for (int i = selection.begin.x; i <= selection.end.x; i++) {
@@ -522,6 +542,17 @@ void GridMapEditor::_delete_selection() {
 	undo_redo->commit_action();
 }
 
+void GridMapEditor::_setup_paste_mode() {
+	input_action = INPUT_PASTE;
+	paste_indicator.click = selection.click;
+	paste_indicator.current = cursor_gridpos;
+	paste_indicator.begin = selection.begin;
+	paste_indicator.end = selection.end;
+	paste_indicator.distance_from_cursor = cursor_gridpos - paste_indicator.begin;
+	paste_indicator.orientation = 0;
+	_update_paste_indicator();
+}
+
 void GridMapEditor::_fill_selection() {
 	if (!selection.active) {
 		return;
@@ -552,6 +583,7 @@ void GridMapEditor::_clear_clipboard_data() {
 	}
 
 	clipboard_items.clear();
+	clipboard_is_move = false;
 }
 
 void GridMapEditor::_set_clipboard_data() {
@@ -624,6 +656,20 @@ void GridMapEditor::_update_paste_indicator() {
 	}
 }
 
+void GridMapEditor::_cancel_pending_move() {
+	if (input_action == INPUT_PASTE) {
+		if (clipboard_is_move) {
+			for (const ClipboardItem &item : clipboard_items) {
+				Vector3 original_position = paste_indicator.begin + item.grid_offset;
+				node->set_cell_item(Vector3i(original_position), item.cell_item, item.orientation);
+			}
+		}
+		_clear_clipboard_data();
+		input_action = INPUT_NONE;
+		_update_paste_indicator();
+	}
+}
+
 void GridMapEditor::_do_paste() {
 	int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);
 	bool reselect = options->get_popup()->is_item_checked(idx);
@@ -632,7 +678,18 @@ void GridMapEditor::_do_paste() {
 	rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
 
 	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
-	undo_redo->create_action(TTR("GridMap Paste Selection"));
+
+	if (clipboard_is_move) {
+		undo_redo->create_action(TTR("GridMap Move Selection"));
+
+		for (const ClipboardItem &item : clipboard_items) {
+			Vector3 original_position = paste_indicator.begin + item.grid_offset;
+			undo_redo->add_undo_method(node, "set_cell_item", original_position, item.cell_item, item.orientation);
+			undo_redo->add_do_method(node, "set_cell_item", original_position, GridMap::INVALID_CELL_ITEM);
+		}
+	} else {
+		undo_redo->create_action(TTR("GridMap Paste Selection"));
+	}
 
 	for (const ClipboardItem &item : clipboard_items) {
 		Vector3 position = rot.xform(item.grid_offset) + paste_indicator.current - paste_indicator.distance_from_cursor;
@@ -715,9 +772,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
 		// Hard key actions:
 		if (k->get_keycode() == Key::ESCAPE) {
 			if (input_action == INPUT_PASTE) {
-				_clear_clipboard_data();
-				input_action = INPUT_NONE;
-				_update_paste_indicator();
+				_cancel_pending_move();
 				return EditorPlugin::AFTER_GUI_INPUT_STOP;
 			} else if (selection.active) {
 				_set_selection(false);
@@ -1058,6 +1113,8 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
 		}
 	}
 
+	_cancel_pending_move();
+
 	node = p_gridmap;
 
 	input_action = INPUT_NONE;
@@ -1208,6 +1265,7 @@ void GridMapEditor::_notification(int p_what) {
 		} break;
 
 		case NOTIFICATION_EXIT_TREE: {
+			_cancel_pending_move();
 			_clear_clipboard_data();
 
 			for (int i = 0; i < 3; i++) {
@@ -1467,7 +1525,7 @@ GridMapEditor::GridMapEditor() {
 	move_action_button->set_shortcut(ED_SHORTCUT("grid_map/move_tool", TTRC("Move"), Key::X, true));
 	fill_action_button->set_accessibility_name(TTRC("Move"));
 	move_action_button->connect(SceneStringName(pressed),
-			callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CUT));
+			callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_MOVE));
 	action_buttons->add_child(move_action_button);
 	viewport_shortcut_buttons.push_back(move_action_button);
 
@@ -1844,6 +1902,7 @@ void GridMapEditorPlugin::make_visible(bool p_visible) {
 		EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);
 		grid_map_editor->set_process(true);
 	} else {
+		grid_map_editor->_cancel_pending_move();
 		grid_map_editor->_show_viewports_transform_gizmo(true);
 		panel_button->hide();
 		if (grid_map_editor->is_visible_in_tree()) {

+ 5 - 1
modules/gridmap/editor/grid_map_editor_plugin.h

@@ -138,6 +138,7 @@ class GridMapEditor : public VBoxContainer {
 	};
 
 	LocalVector<ClipboardItem> clipboard_items;
+	bool clipboard_is_move = false;
 
 	Color default_color;
 	Color erase_color;
@@ -196,7 +197,7 @@ class GridMapEditor : public VBoxContainer {
 		MENU_OPTION_CURSOR_CLEAR_ROTATION,
 		MENU_OPTION_PASTE_SELECTS,
 		MENU_OPTION_SELECTION_DUPLICATE,
-		MENU_OPTION_SELECTION_CUT,
+		MENU_OPTION_SELECTION_MOVE,
 		MENU_OPTION_SELECTION_CLEAR,
 		MENU_OPTION_SELECTION_FILL,
 		MENU_OPTION_GRIDMAP_SETTINGS
@@ -236,6 +237,7 @@ class GridMapEditor : public VBoxContainer {
 	void _set_clipboard_data();
 	void _update_paste_indicator();
 	void _do_paste();
+	void _cancel_pending_move();
 	void _show_viewports_transform_gizmo(bool p_value);
 	void _update_selection_transform();
 	void _validate_selection();
@@ -248,7 +250,9 @@ class GridMapEditor : public VBoxContainer {
 	void _floor_mouse_exited();
 
 	void _delete_selection();
+	void _delete_selection_with_undo();
 	void _fill_selection();
+	void _setup_paste_mode();
 
 	bool do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click);