diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 0df0274495f..fd5b3042cf3 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1274,7 +1274,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b Transform3D gt = spatial_editor->get_gizmo_transform(); - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { + if (spatial_editor->is_select_tool_selected() || spatial_editor->is_move_tool_selected()) { int col_axis = -1; real_t col_d = 1e20; @@ -1340,7 +1340,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b } } - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { + if (spatial_editor->is_select_tool_selected() || spatial_editor->is_rotate_tool_selected()) { int col_axis = -1; Vector3 hit_position; @@ -1394,7 +1394,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b } } - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { + if (spatial_editor->is_scale_tool_selected()) { int col_axis = -1; float col_d = 1e20; @@ -1565,7 +1565,7 @@ bool Node3DEditorViewport::_is_node_locked(const Node *p_node) const { void Node3DEditorViewport::_list_select(Ref b) { Vector<_RayResult> potential_selection_results; - _find_items_at_pos(b->get_position(), potential_selection_results, spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); + _find_items_at_pos(b->get_position(), potential_selection_results, spatial_editor->is_select_tool_selected()); Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); @@ -1596,7 +1596,7 @@ void Node3DEditorViewport::_list_select(Ref b) { selection_results.clear(); if (clicked.is_valid()) { - _select_clicked(spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); + _select_clicked(spatial_editor->is_select_tool_selected()); } } else if (!selection_results.is_empty()) { NodePath root_path = get_tree()->get_edited_scene_root()->get_path(); @@ -1815,7 +1815,7 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { break; } - if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_LIST_SELECT) { + if (spatial_editor->is_list_select_tool_selected()) { _list_select(b); break; } @@ -1920,17 +1920,17 @@ void Node3DEditorViewport::_sinput(const Ref &p_event) { bool node_selected = get_selected_count() > 0; - if (node_selected && ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->is_command_or_control_pressed()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)) { + if (node_selected && ((spatial_editor->is_select_tool_selected() && b->is_command_or_control_pressed()) || spatial_editor->is_rotate_tool_selected())) { begin_transform(TRANSFORM_ROTATE, false); break; } - if (node_selected && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { + if (node_selected && spatial_editor->is_move_tool_selected()) { begin_transform(TRANSFORM_TRANSLATE, false); break; } - if (node_selected && spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { + if (node_selected && spatial_editor->is_scale_tool_selected()) { begin_transform(TRANSFORM_SCALE, false); break; } @@ -3916,7 +3916,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) { clicked = selection_results_menu[p_result]->get_instance_id(); if (clicked.is_valid()) { - _select_clicked(spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT); + _select_clicked(spatial_editor->is_select_tool_selected()); } selection_results_menu.clear(); @@ -4001,15 +4001,15 @@ void Node3DEditorViewport::update_transform_gizmo_view() { axis_angle.basis.scale(scale); axis_angle.origin = xform.origin; RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], axis_angle); - RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); + RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], show_gizmo && (spatial_editor->is_select_tool_selected() || spatial_editor->is_move_tool_selected())); RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], axis_angle); - RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); + RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], show_gizmo && (spatial_editor->is_select_tool_selected() || spatial_editor->is_move_tool_selected())); RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], axis_angle); - RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); + RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], show_gizmo && (spatial_editor->is_select_tool_selected() || spatial_editor->is_rotate_tool_selected())); RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], axis_angle); - RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); + RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], show_gizmo && (spatial_editor->is_scale_tool_selected())); RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], axis_angle); - RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], show_gizmo && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); + RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], show_gizmo && (spatial_editor->is_scale_tool_selected())); RenderingServer::get_singleton()->instance_set_transform(axis_gizmo_instance[i], xform); } @@ -4023,7 +4023,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() { xform.orthonormalize(); xform.basis.scale(scale); RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform); - RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); + RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && !_edit.instant && transform_gizmo_visible && !collision_reposition && (spatial_editor->is_select_tool_selected() || spatial_editor->is_rotate_tool_selected())); } void Node3DEditorViewport::set_state(const Dictionary &p_state) { @@ -6642,19 +6642,8 @@ void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) { void Node3DEditor::_menu_item_pressed(int p_option) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - switch (p_option) { - case MENU_TOOL_SELECT: - case MENU_TOOL_MOVE: - case MENU_TOOL_ROTATE: - case MENU_TOOL_SCALE: - case MENU_TOOL_LIST_SELECT: { - for (int i = 0; i < TOOL_MAX; i++) { - tool_button[i]->set_pressed(i == p_option); - } - tool_mode = (ToolMode)p_option; - update_transform_gizmo(); - } break; + switch (p_option) { case MENU_TRANSFORM_CONFIGURE_SNAP: { snap_dialog->popup_centered(Size2(200, 180)); } break; @@ -7755,15 +7744,15 @@ void Node3DEditor::_refresh_menu_icons() { all_locked = all_locked && has_node3d_item; all_grouped = all_grouped && has_node3d_item; - tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked); - tool_button[TOOL_LOCK_SELECTED]->set_disabled(!has_node3d_item); - tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked); - tool_button[TOOL_UNLOCK_SELECTED]->set_disabled(!has_node3d_item); + lock_selected_button->set_visible(!all_locked); + lock_selected_button->set_disabled(!has_node3d_item); + unlock_selected_button->set_visible(all_locked); + unlock_selected_button->set_disabled(!has_node3d_item); - tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped); - tool_button[TOOL_GROUP_SELECTED]->set_disabled(!has_node3d_item); - tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped); - tool_button[TOOL_UNGROUP_SELECTED]->set_disabled(!has_node3d_item); + group_selected_button->set_visible(!all_grouped); + group_selected_button->set_disabled(!has_node3d_item); + ungroup_selected_button->set_visible(all_grouped); + ungroup_selected_button->set_disabled(!has_node3d_item); } template @@ -8021,15 +8010,15 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) { } void Node3DEditor::_update_theme() { - tool_button[TOOL_MODE_SELECT]->set_icon(get_editor_theme_icon(SNAME("ToolSelect"))); - tool_button[TOOL_MODE_MOVE]->set_icon(get_editor_theme_icon(SNAME("ToolMove"))); - tool_button[TOOL_MODE_ROTATE]->set_icon(get_editor_theme_icon(SNAME("ToolRotate"))); - tool_button[TOOL_MODE_SCALE]->set_icon(get_editor_theme_icon(SNAME("ToolScale"))); - tool_button[TOOL_MODE_LIST_SELECT]->set_icon(get_editor_theme_icon(SNAME("ListSelect"))); - tool_button[TOOL_LOCK_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Lock"))); - tool_button[TOOL_UNLOCK_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Unlock"))); - tool_button[TOOL_GROUP_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Group"))); - tool_button[TOOL_UNGROUP_SELECTED]->set_icon(get_editor_theme_icon(SNAME("Ungroup"))); + select_tool_button->set_icon(get_editor_theme_icon(SNAME("ToolSelect"))); + move_tool_button->set_icon(get_editor_theme_icon(SNAME("ToolMove"))); + rotate_tool_button->set_icon(get_editor_theme_icon(SNAME("ToolRotate"))); + scale_tool_button->set_icon(get_editor_theme_icon(SNAME("ToolScale"))); + list_select_tool_button->set_icon(get_editor_theme_icon(SNAME("ListSelect"))); + lock_selected_button->set_icon(get_editor_theme_icon(SNAME("Lock"))); + unlock_selected_button->set_icon(get_editor_theme_icon(SNAME("Unlock"))); + group_selected_button->set_icon(get_editor_theme_icon(SNAME("Group"))); + ungroup_selected_button->set_icon(get_editor_theme_icon(SNAME("Ungroup"))); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_icon(get_editor_theme_icon(SNAME("Object"))); tool_option_button[TOOL_OPT_USE_SNAP]->set_icon(get_editor_theme_icon(SNAME("Snap"))); @@ -8682,7 +8671,6 @@ Node3DEditor::Node3DEditor() { snap_enabled = false; snap_key_enabled = false; - tool_mode = TOOL_MODE_SELECT; camera_override_viewport_id = 0; @@ -8704,85 +8692,84 @@ Node3DEditor::Node3DEditor() { String sct; - tool_button[TOOL_MODE_SELECT] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_MODE_SELECT]); - tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true); - tool_button[TOOL_MODE_SELECT]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_SELECT]->set_pressed(true); - tool_button[TOOL_MODE_SELECT]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT)); - tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q)); - tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this); - tool_button[TOOL_MODE_SELECT]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); - main_menu_hbox->add_child(memnew(VSeparator)); + tool_button_group.instantiate(); + tool_button_group->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_tool_button_group_pressed)); - tool_button[TOOL_MODE_MOVE] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_MODE_MOVE]); - tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true); - tool_button[TOOL_MODE_MOVE]->set_theme_type_variation("FlatButton"); - - tool_button[TOOL_MODE_MOVE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_MOVE)); - tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), Key::W)); - tool_button[TOOL_MODE_MOVE]->set_shortcut_context(this); - tool_button[TOOL_MODE_MOVE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); - - tool_button[TOOL_MODE_ROTATE] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_MODE_ROTATE]); - tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true); - tool_button[TOOL_MODE_ROTATE]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_ROTATE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_ROTATE)); - tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), Key::E)); - tool_button[TOOL_MODE_ROTATE]->set_shortcut_context(this); - tool_button[TOOL_MODE_ROTATE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); - - tool_button[TOOL_MODE_SCALE] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_MODE_SCALE]); - tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true); - tool_button[TOOL_MODE_SCALE]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_SCALE]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SCALE)); - tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), Key::R)); - tool_button[TOOL_MODE_SCALE]->set_shortcut_context(this); - tool_button[TOOL_MODE_SCALE]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + select_tool_button = memnew(Button); + main_menu_hbox->add_child(select_tool_button); + select_tool_button->set_toggle_mode(true); + select_tool_button->set_theme_type_variation("FlatButton"); + select_tool_button->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q)); + select_tool_button->set_shortcut_context(this); + select_tool_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + select_tool_button->set_pressed(true); + add_tool(select_tool_button); main_menu_hbox->add_child(memnew(VSeparator)); - tool_button[TOOL_MODE_LIST_SELECT] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_MODE_LIST_SELECT]); - tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); - tool_button[TOOL_MODE_LIST_SELECT]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_MODE_LIST_SELECT]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT)); - tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked.")); + move_tool_button = memnew(Button); + main_menu_hbox->add_child(move_tool_button); + move_tool_button->set_theme_type_variation("FlatButton"); + move_tool_button->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), Key::W)); + move_tool_button->set_shortcut_context(this); + move_tool_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + add_tool(move_tool_button); - tool_button[TOOL_LOCK_SELECTED] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]); - tool_button[TOOL_LOCK_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_LOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED)); - tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(TTR("Lock selected node, preventing selection and movement.")); - // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/lock_selected_nodes")); + rotate_tool_button = memnew(Button); + main_menu_hbox->add_child(rotate_tool_button); + rotate_tool_button->set_theme_type_variation("FlatButton"); + rotate_tool_button->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), Key::E)); + rotate_tool_button->set_shortcut_context(this); + rotate_tool_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + add_tool(rotate_tool_button); - tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]); - tool_button[TOOL_UNLOCK_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_UNLOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED)); - tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement.")); - // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/unlock_selected_nodes")); + scale_tool_button = memnew(Button); + main_menu_hbox->add_child(scale_tool_button); + scale_tool_button->set_theme_type_variation("FlatButton"); + scale_tool_button->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), Key::R)); + scale_tool_button->set_shortcut_context(this); + scale_tool_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Drag: Use snap.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.")); + add_tool(scale_tool_button); - tool_button[TOOL_GROUP_SELECTED] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]); - tool_button[TOOL_GROUP_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_GROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); - tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Groups the selected node with its children. This selects the parent when any child node is clicked in 2D and 3D view.")); - // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/group_selected_nodes")); + main_menu_hbox->add_child(memnew(VSeparator)); - tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button); - main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]); - tool_button[TOOL_UNGROUP_SELECTED]->set_theme_type_variation("FlatButton"); - tool_button[TOOL_UNGROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); - tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view.")); + list_select_tool_button = memnew(Button); + main_menu_hbox->add_child(list_select_tool_button); + list_select_tool_button->set_theme_type_variation("FlatButton"); + list_select_tool_button->set_tooltip_text(TTR("Show list of selectable nodes at position clicked.")); + add_tool(list_select_tool_button); + + lock_selected_button = memnew(Button); + main_menu_hbox->add_child(lock_selected_button); + lock_selected_button->set_theme_type_variation("FlatButton"); + lock_selected_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED)); + lock_selected_button->set_tooltip_text(TTR("Lock selected node, preventing selection and movement.")); // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. - tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes")); + lock_selected_button->set_shortcut(ED_GET_SHORTCUT("editor/lock_selected_nodes")); + + unlock_selected_button = memnew(Button); + main_menu_hbox->add_child(unlock_selected_button); + unlock_selected_button->set_theme_type_variation("FlatButton"); + unlock_selected_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED)); + unlock_selected_button->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + unlock_selected_button->set_shortcut(ED_GET_SHORTCUT("editor/unlock_selected_nodes")); + + group_selected_button = memnew(Button); + main_menu_hbox->add_child(group_selected_button); + group_selected_button->set_theme_type_variation("FlatButton"); + group_selected_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED)); + group_selected_button->set_tooltip_text(TTR("Groups the selected node with its children. This selects the parent when any child node is clicked in 2D and 3D view.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + group_selected_button->set_shortcut(ED_GET_SHORTCUT("editor/group_selected_nodes")); + + ungroup_selected_button = memnew(Button); + main_menu_hbox->add_child(ungroup_selected_button); + ungroup_selected_button->set_theme_type_variation("FlatButton"); + ungroup_selected_button->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED)); + ungroup_selected_button->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + ungroup_selected_button->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes")); main_menu_hbox->add_child(memnew(VSeparator)); @@ -9330,6 +9317,49 @@ void Node3DEditorPlugin::make_visible(bool p_visible) { } } +void Node3DEditor::_tool_button_group_pressed(Button *p_button) { + update_transform_gizmo(); +} + +void Node3DEditor::add_tool(Button *p_button) const { + p_button->set_button_group(tool_button_group); + p_button->set_toggle_mode(true); +} + +bool Node3DEditor::is_list_select_tool_selected() { + return is_tool_selected(list_select_tool_button); +} + +bool Node3DEditor::is_move_tool_selected() { + return is_tool_selected(move_tool_button); +} + +bool Node3DEditor::is_rotate_tool_selected() { + return is_tool_selected(rotate_tool_button); +} + +bool Node3DEditor::is_scale_tool_selected() { + return is_tool_selected(scale_tool_button); +} + +bool Node3DEditor::is_select_tool_selected() { + return is_tool_selected(select_tool_button); +} + +bool Node3DEditor::is_tool_selected(Button *p_button) { + BaseButton *pressed_button = tool_button_group->get_pressed_button(); + + return pressed_button == p_button; +} + +void Node3DEditor::remove_tool(Button *p_button) { + if (is_tool_selected(p_button)) { + select_tool_button->set_pressed(true); + } + + p_button->set_button_group(NULL); +} + void Node3DEditorPlugin::edit(Object *p_object) { spatial_editor->edit(Object::cast_to(p_object)); } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 1b03362606a..087ab139df9 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -606,25 +606,11 @@ class Node3DEditor : public VBoxContainer { public: static const unsigned int VIEWPORTS_COUNT = 4; - enum ToolMode { - TOOL_MODE_SELECT, - TOOL_MODE_MOVE, - TOOL_MODE_ROTATE, - TOOL_MODE_SCALE, - TOOL_MODE_LIST_SELECT, - TOOL_LOCK_SELECTED, - TOOL_UNLOCK_SELECTED, - TOOL_GROUP_SELECTED, - TOOL_UNGROUP_SELECTED, - TOOL_MAX - }; - enum ToolOptions { TOOL_OPT_LOCAL_COORDS, TOOL_OPT_USE_SNAP, TOOL_OPT_OVERRIDE_CAMERA, TOOL_OPT_MAX - }; private: @@ -638,8 +624,6 @@ private: ///// - ToolMode tool_mode; - RID origin_mesh; RID origin_multimesh; RID origin_instance; @@ -697,11 +681,6 @@ private: } gizmo; enum MenuOption { - MENU_TOOL_SELECT, - MENU_TOOL_MOVE, - MENU_TOOL_ROTATE, - MENU_TOOL_SCALE, - MENU_TOOL_LIST_SELECT, MENU_TOOL_LOCAL_COORDS, MENU_TOOL_USE_SNAP, MENU_TOOL_OVERRIDE_CAMERA, @@ -724,7 +703,20 @@ private: MENU_SNAP_TO_FLOOR }; - Button *tool_button[TOOL_MAX]; + void _tool_button_group_pressed(Button *p_button); + + Ref tool_button_group; + Button *select_tool_button; + Button *move_tool_button; + Button *rotate_tool_button; + Button *scale_tool_button; + Button *list_select_tool_button; + + Button *lock_selected_button; + Button *unlock_selected_button; + Button *group_selected_button; + Button *ungroup_selected_button; + Button *tool_option_button[TOOL_OPT_MAX]; MenuButton *transform_menu = nullptr; @@ -892,7 +884,6 @@ public: Transform3D get_gizmo_transform() const { return gizmo.transform; } bool is_gizmo_visible() const; - ToolMode get_tool_mode() const { return tool_mode; } bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } void set_local_coords_enabled(bool on) const { tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_pressed(on); } bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; } @@ -914,6 +905,15 @@ public: void select_gizmo_highlight_axis(int p_axis); void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } + void add_tool(Button *p_button) const; + bool is_tool_selected(Button *p_button); + void remove_tool(Button *p_button); + bool is_list_select_tool_selected(); + bool is_move_tool_selected(); + bool is_rotate_tool_selected(); + bool is_scale_tool_selected(); + bool is_select_tool_selected(); + Dictionary get_state() const; void set_state(const Dictionary &p_state); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 81beaf6f911..e4a7eebc471 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -1412,7 +1412,7 @@ EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_3d_gui_input(Camera3 if (se && se->is_edit_mode()) { const Ref mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { - if (ne->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) { + if (!ne->is_select_tool_selected()) { if (!ne->is_gizmo_visible()) { return EditorPlugin::AFTER_GUI_INPUT_STOP; } @@ -1522,7 +1522,7 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi return -1; } - if (Node3DEditor::get_singleton()->get_tool_mode() != Node3DEditor::TOOL_MODE_SELECT) { + if (!Node3DEditor::get_singleton()->is_select_tool_selected()) { return -1; } @@ -1598,19 +1598,19 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); ur->create_action(TTR("Set Bone Transform")); - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { + if (ne->is_select_tool_selected() || ne->is_move_tool_selected()) { for (int i = 0; i < p_ids.size(); i++) { ur->add_do_method(skeleton, "set_bone_pose_position", p_ids[i], skeleton->get_bone_pose_position(p_ids[i])); ur->add_undo_method(skeleton, "set_bone_pose_position", p_ids[i], se->get_bone_original_position()); } } - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { + if (ne->is_select_tool_selected() || ne->is_rotate_tool_selected()) { for (int i = 0; i < p_ids.size(); i++) { ur->add_do_method(skeleton, "set_bone_pose_rotation", p_ids[i], skeleton->get_bone_pose_rotation(p_ids[i])); ur->add_undo_method(skeleton, "set_bone_pose_rotation", p_ids[i], se->get_bone_original_rotation()); } } - if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { + if (ne->is_scale_tool_selected()) { for (int i = 0; i < p_ids.size(); i++) { // If the axis is swapped by scaling, the rotation can be changed. ur->add_do_method(skeleton, "set_bone_pose_rotation", p_ids[i], skeleton->get_bone_pose_rotation(p_ids[i])); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 4c11565c512..6ce86e51efc 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -101,6 +101,9 @@ void GridMapEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CURSOR_ROTATE_Y: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -116,6 +119,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_X: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -131,6 +137,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_ROTATE_Z: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -146,6 +155,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Y: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -161,6 +173,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_X: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -176,6 +191,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_BACK_ROTATE_Z: { + if (!_is_paint_tool_selected()) + break; + Basis r; if (input_action == INPUT_PASTE) { r = node->get_basis_with_orthogonal_index(paste_indicator.orientation); @@ -191,6 +209,9 @@ void GridMapEditor::_menu_option(int p_option) { _update_cursor_transform(); } break; case MENU_OPTION_CURSOR_CLEAR_ROTATION: { + if (!_is_paint_tool_selected()) + break; + if (input_action == INPUT_PASTE) { paste_indicator.orientation = 0; _update_paste_indicator(); @@ -343,6 +364,56 @@ void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const options->get_popup()->set_item_disabled(options->get_popup()->get_item_index(MENU_OPTION_SELECTION_FILL), !selection.active); } +void GridMapEditor::_add_paint_tool() { + Node3DEditor::get_singleton()->add_tool(paint_tool_button); + + paint_tool_button->connect("toggled", callable_mp(this, &GridMapEditor::_paint_tool_button_toggled)); + + if (selected_palette >= 0) { + _select_paint_tool(); + } +} + +void GridMapEditor::_remove_paint_tool() { + Node3DEditor::get_singleton()->remove_tool(paint_tool_button); + + paint_tool_button->disconnect("toggled", callable_mp(this, &GridMapEditor::_paint_tool_button_toggled)); +} + +bool GridMapEditor::_cancel_actions() { + if (input_action == INPUT_PASTE) { + _clear_clipboard_data(); + input_action = INPUT_NONE; + _update_paste_indicator(); + return true; + } else if (selection.active) { + _set_selection(false); + return true; + } else if (selected_palette >= 0 || mesh_library_palette->is_anything_selected()) { + selected_palette = -1; + mesh_library_palette->deselect_all(); + update_palette(); + _update_cursor_instance(); + return true; + } + + return false; +} + +void GridMapEditor::_paint_tool_button_toggled(bool p_toggled_on) { + if (!_is_paint_tool_selected()) { + _cancel_actions(); + } +} + +void GridMapEditor::_select_paint_tool() { + paint_tool_button->set_pressed(true); +} + +bool GridMapEditor::_is_paint_tool_selected() const { + return Node3DEditor::get_singleton()->is_tool_selected(paint_tool_button); +} + bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click) { if (!spatial_editor) { return false; @@ -351,6 +422,9 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b if (selected_palette < 0 && input_action != INPUT_PICK && input_action != INPUT_SELECT && input_action != INPUT_PASTE) { return false; } + if (!_is_paint_tool_selected()) { + return false; + } if (mesh_library.is_null()) { return false; } @@ -653,6 +727,12 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D } else { input_action = INPUT_PAINT; set_items.clear(); + if (selection.active) { + _set_selection(false); + if (selected_palette < 0) { + return EditorPlugin::AFTER_GUI_INPUT_STOP; + } + } } } else if (mb->get_button_index() == MouseButton::RIGHT) { if (input_action == INPUT_PASTE) { @@ -735,22 +815,8 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D if (k.is_valid()) { if (k->is_pressed()) { - if (k->get_keycode() == Key::ESCAPE) { - if (input_action == INPUT_PASTE) { - _clear_clipboard_data(); - input_action = INPUT_NONE; - _update_paste_indicator(); - return EditorPlugin::AFTER_GUI_INPUT_STOP; - } else if (selection.active) { - _set_selection(false); - return EditorPlugin::AFTER_GUI_INPUT_STOP; - } else { - selected_palette = -1; - mesh_library_palette->deselect_all(); - update_palette(); - _update_cursor_instance(); - return EditorPlugin::AFTER_GUI_INPUT_STOP; - } + if (k->get_keycode() == Key::ESCAPE && _cancel_actions()) { + return EditorPlugin::AFTER_GUI_INPUT_STOP; } // Consume input to avoid conflicts with other plugins. @@ -1058,6 +1124,7 @@ void GridMapEditor::_draw_grids(const Vector3 &cell_size) { } void GridMapEditor::_update_theme() { + paint_tool_button->set_icon(get_editor_theme_icon(SNAME("Paint"))); options->set_icon(get_theme_icon(SNAME("GridMap"), EditorStringName(EditorIcons))); search_box->set_right_icon(get_theme_icon(SNAME("Search"), EditorStringName(EditorIcons))); mode_thumbnail->set_icon(get_theme_icon(SNAME("FileThumbnail"), EditorStringName(EditorIcons))); @@ -1158,6 +1225,8 @@ void GridMapEditor::_update_cursor_instance() { void GridMapEditor::_item_selected_cbk(int idx) { selected_palette = mesh_library_palette->get_item_metadata(idx); + _select_paint_tool(); + _update_cursor_instance(); } @@ -1210,6 +1279,13 @@ GridMapEditor::GridMapEditor() { spatial_editor_hb->set_alignment(BoxContainer::ALIGNMENT_END); Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb); + paint_tool_button = memnew(Button); + paint_tool_button->set_theme_type_variation("FlatButton"); + paint_tool_button->set_tooltip_text(TTR("LMB: Place selected mesh on the grid.") + "\n" + TTR("RMB: Remove the mesh at position clicked.") + "\n" + TTR("Shift+Drag: Creates a selection box.")); + spatial_editor_hb->add_child(paint_tool_button); + + spatial_editor_hb->add_child(memnew(VSeparator)); + spin_box_label = memnew(Label); spin_box_label->set_text(TTR("Floor:")); spatial_editor_hb->add_child(spin_box_label); @@ -1521,10 +1597,17 @@ bool GridMapEditorPlugin::handles(Object *p_object) const { void GridMapEditorPlugin::make_visible(bool p_visible) { if (p_visible) { + grid_map_editor->_add_paint_tool(); + + if (grid_map_editor->selected_palette >= 0) { + grid_map_editor->_select_paint_tool(); + } + grid_map_editor->show(); grid_map_editor->spatial_editor_hb->show(); grid_map_editor->set_process(true); } else { + grid_map_editor->_remove_paint_tool(); grid_map_editor->spatial_editor_hb->hide(); grid_map_editor->hide(); grid_map_editor->set_process(false); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 4294c93c936..1c72cb30655 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -80,6 +80,7 @@ class GridMapEditor : public VBoxContainer { VBoxContainer *settings_vbc = nullptr; SpinBox *settings_pick_distance = nullptr; Label *spin_box_label = nullptr; + Button *paint_tool_button = nullptr; struct SetItem { Vector3i position; @@ -195,6 +196,7 @@ class GridMapEditor : public VBoxContainer { void _set_display_mode(int p_mode); void _item_selected_cbk(int idx); void _update_cursor_transform(); + void _hide_cursor_instance(); void _update_cursor_instance(); void _update_theme(); @@ -218,6 +220,13 @@ class GridMapEditor : public VBoxContainer { void _delete_selection(); void _fill_selection(); + void _select_paint_tool(); + bool _is_paint_tool_selected() const; + void _add_paint_tool(); + void _remove_paint_tool(); + void _paint_tool_button_toggled(bool p_toggled_on); + bool _cancel_actions(); + bool do_input_action(Camera3D *p_camera, const Point2 &p_point, bool p_click); friend class GridMapEditorPlugin;