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

Fix `GridMap` Move Action Undo/Redo/Cancel
This commit is contained in:
Rémi Verschelde 2025-12-04 13:21:31 +01:00
commit ff610712f5
No known key found for this signature in database
GPG key ID: C3336907360768E1
2 changed files with 82 additions and 19 deletions

View file

@ -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)); options->get_popup()->set_item_checked(idx, !options->get_popup()->is_item_checked(idx));
} break; } break;
case MENU_OPTION_SELECTION_DUPLICATE: case MENU_OPTION_SELECTION_DUPLICATE: {
case MENU_OPTION_SELECTION_CUT: {
if (!(selection.active && input_action == INPUT_NONE)) { if (!(selection.active && input_action == INPUT_NONE)) {
break; break;
} }
_set_clipboard_data(); _set_clipboard_data();
clipboard_is_move = false;
if (p_option == MENU_OPTION_SELECTION_CUT) { if (!clipboard_items.is_empty()) {
_delete_selection(); _setup_paste_mode();
}
} break;
case MENU_OPTION_SELECTION_MOVE: {
if (!(selection.active && input_action == INPUT_NONE)) {
break;
} }
input_action = INPUT_PASTE; _set_clipboard_data();
paste_indicator.click = selection.click; clipboard_is_move = true;
paste_indicator.current = cursor_gridpos;
paste_indicator.begin = selection.begin; if (!clipboard_items.is_empty()) {
paste_indicator.end = selection.end; _delete_selection();
paste_indicator.distance_from_cursor = cursor_gridpos - paste_indicator.begin; _setup_paste_mode();
paste_indicator.orientation = 0; }
_update_paste_indicator();
} break; } break;
case MENU_OPTION_SELECTION_CLEAR: { case MENU_OPTION_SELECTION_CLEAR: {
if (!selection.active) { if (!selection.active) {
break; break;
} }
_delete_selection(); _delete_selection_with_undo();
} break; } break;
case MENU_OPTION_SELECTION_FILL: { case MENU_OPTION_SELECTION_FILL: {
@ -506,6 +511,21 @@ void GridMapEditor::_delete_selection() {
return; 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(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Delete Selection")); undo_redo->create_action(TTR("GridMap Delete Selection"));
for (int i = selection.begin.x; i <= selection.end.x; i++) { for (int i = selection.begin.x; i <= selection.end.x; i++) {
@ -522,6 +542,17 @@ void GridMapEditor::_delete_selection() {
undo_redo->commit_action(); 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() { void GridMapEditor::_fill_selection() {
if (!selection.active) { if (!selection.active) {
return; return;
@ -552,6 +583,7 @@ void GridMapEditor::_clear_clipboard_data() {
} }
clipboard_items.clear(); clipboard_items.clear();
clipboard_is_move = false;
} }
void GridMapEditor::_set_clipboard_data() { 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() { void GridMapEditor::_do_paste() {
int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS); int idx = options->get_popup()->get_item_index(MENU_OPTION_PASTE_SELECTS);
bool reselect = options->get_popup()->is_item_checked(idx); 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); rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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")); undo_redo->create_action(TTR("GridMap Paste Selection"));
}
for (const ClipboardItem &item : clipboard_items) { for (const ClipboardItem &item : clipboard_items) {
Vector3 position = rot.xform(item.grid_offset) + paste_indicator.current - paste_indicator.distance_from_cursor; 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: // Hard key actions:
if (k->get_keycode() == Key::ESCAPE) { if (k->get_keycode() == Key::ESCAPE) {
if (input_action == INPUT_PASTE) { if (input_action == INPUT_PASTE) {
_clear_clipboard_data(); _cancel_pending_move();
input_action = INPUT_NONE;
_update_paste_indicator();
return EditorPlugin::AFTER_GUI_INPUT_STOP; return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (selection.active) { } else if (selection.active) {
_set_selection(false); _set_selection(false);
@ -1058,6 +1113,8 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
} }
} }
_cancel_pending_move();
node = p_gridmap; node = p_gridmap;
input_action = INPUT_NONE; input_action = INPUT_NONE;
@ -1208,6 +1265,7 @@ void GridMapEditor::_notification(int p_what) {
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
_cancel_pending_move();
_clear_clipboard_data(); _clear_clipboard_data();
for (int i = 0; i < 3; i++) { 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)); move_action_button->set_shortcut(ED_SHORTCUT("grid_map/move_tool", TTRC("Move"), Key::X, true));
fill_action_button->set_accessibility_name(TTRC("Move")); fill_action_button->set_accessibility_name(TTRC("Move"));
move_action_button->connect(SceneStringName(pressed), 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); action_buttons->add_child(move_action_button);
viewport_shortcut_buttons.push_back(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); EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);
grid_map_editor->set_process(true); grid_map_editor->set_process(true);
} else { } else {
grid_map_editor->_cancel_pending_move();
grid_map_editor->_show_viewports_transform_gizmo(true); grid_map_editor->_show_viewports_transform_gizmo(true);
panel_button->hide(); panel_button->hide();
if (grid_map_editor->is_visible_in_tree()) { if (grid_map_editor->is_visible_in_tree()) {

View file

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