Merge pull request #85477 from KoBeWi/submenus_that_shall_not_be_named

Add methods to add submenus without using names
This commit is contained in:
Rémi Verschelde 2024-02-23 11:29:28 +01:00
commit 42a15bcc49
No known key found for this signature in database
GPG Key ID: C3336907360768E1
21 changed files with 166 additions and 223 deletions

View File

@ -197,7 +197,7 @@
If [param allow_echo] is [code]true[/code], the shortcut can be activated with echo events.
</description>
</method>
<method name="add_submenu_item">
<method name="add_submenu_item" deprecated="Prefer using [method add_submenu_node_item] instead.">
<return type="void" />
<param index="0" name="label" type="String" />
<param index="1" name="submenu" type="String" />
@ -207,6 +207,17 @@
An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
<method name="add_submenu_node_item">
<return type="void" />
<param index="0" name="label" type="String" />
<param index="1" name="submenu" type="PopupMenu" />
<param index="2" name="id" type="int" default="-1" />
<description>
Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. This submenu will be shown when the item is clicked, hovered for long enough, or activated using the [code]ui_select[/code] or [code]ui_right[/code] input actions.
[param submenu] must be either child of this [PopupMenu] or has no parent node (in which case it will be automatically added as a child). If the [param submenu] popup has another parent, this method will fail.
An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
<method name="clear">
<return type="void" />
<param index="0" name="free_submenus" type="bool" default="false" />
@ -304,13 +315,20 @@
Returns the [Shortcut] associated with the item at the given [param index].
</description>
</method>
<method name="get_item_submenu" qualifiers="const">
<method name="get_item_submenu" qualifiers="const" deprecated="Prefer using [method get_item_submenu_node] instead.">
<return type="String" />
<param index="0" name="index" type="int" />
<description>
Returns the submenu name of the item at the given [param index]. See [method add_submenu_item] for more info on how to add a submenu.
</description>
</method>
<method name="get_item_submenu_node" qualifiers="const">
<return type="PopupMenu" />
<param index="0" name="index" type="int" />
<description>
Returns the submenu of the item at the given [param index], or [code]null[/code] if no submenu was added. See [method add_submenu_node_item] for more info on how to add a submenu.
</description>
</method>
<method name="get_item_text" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
@ -545,7 +563,7 @@
Disables the [Shortcut] of the item at the given [param index].
</description>
</method>
<method name="set_item_submenu">
<method name="set_item_submenu" deprecated="Prefer using [method set_item_submenu_node] instead.">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="submenu" type="String" />
@ -553,6 +571,14 @@
Sets the submenu of the item at the given [param index]. The submenu is the name of a child [PopupMenu] node that would be shown when the item is clicked.
</description>
</method>
<method name="set_item_submenu_node">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="submenu" type="PopupMenu" />
<description>
Sets the submenu of the item at the given [param index]. The submenu is a [PopupMenu] node that would be shown when the item is clicked. It must either be a child of this [PopupMenu] or has no parent (in which case it will be automatically added as a child). If the [param submenu] popup has another parent, this method will fail.
</description>
</method>
<method name="set_item_text">
<return type="void" />
<param index="0" name="index" type="int" />

View File

@ -5535,9 +5535,7 @@ void EditorNode::add_tool_menu_item(const String &p_name, const Callable &p_call
void EditorNode::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
ERR_FAIL_NULL(p_submenu);
ERR_FAIL_COND(p_submenu->get_parent() != nullptr);
tool_menu->add_child(p_submenu);
tool_menu->add_submenu_item(p_name, p_submenu->get_name(), TOOLS_CUSTOM);
tool_menu->add_submenu_node_item(p_name, p_submenu, TOOLS_CUSTOM);
}
void EditorNode::remove_tool_menu_item(const String &p_name) {
@ -6841,7 +6839,10 @@ EditorNode::EditorNode() {
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE);
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD_OR_CTRL + Key::O), FILE_OPEN_SCENE);
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV);
file_menu->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
recent_scenes = memnew(PopupMenu);
file_menu->add_submenu_node_item(TTR("Open Recent"), recent_scenes, FILE_OPEN_RECENT);
recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene));
file_menu->add_separator();
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD_OR_CTRL + Key::S), FILE_SAVE_SCENE);
@ -6857,9 +6858,7 @@ EditorNode::EditorNode() {
file_menu->add_separator();
export_as_menu = memnew(PopupMenu);
export_as_menu->set_name("Export");
file_menu->add_child(export_as_menu);
file_menu->add_submenu_item(TTR("Export As..."), "Export");
file_menu->add_submenu_node_item(TTR("Export As..."), export_as_menu);
export_as_menu->add_shortcut(ED_SHORTCUT("editor/export_as_mesh_library", TTR("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY);
export_as_menu->connect("index_pressed", callable_mp(this, &EditorNode::_export_as_menu_option));
@ -6871,11 +6870,6 @@ EditorNode::EditorNode() {
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE);
recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes");
file_menu->add_child(recent_scenes);
recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene));
if (!global_menu || !OS::get_singleton()->has_feature("macos")) {
// On macOS "Quit" and "About" options are in the "app" menu.
file_menu->add_separator();
@ -6918,10 +6912,8 @@ EditorNode::EditorNode() {
project_menu->add_separator();
tool_menu = memnew(PopupMenu);
tool_menu->set_name("Tools");
tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option));
project_menu->add_child(tool_menu);
project_menu->add_submenu_item(TTR("Tools"), "Tools");
project_menu->add_submenu_node_item(TTR("Tools"), tool_menu);
tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES);
tool_menu->add_item(TTR("Upgrade Mesh Surfaces..."), TOOLS_SURFACE_UPGRADE);
@ -6972,11 +6964,9 @@ EditorNode::EditorNode() {
settings_menu->add_separator();
editor_layouts = memnew(PopupMenu);
editor_layouts->set_name("Layouts");
editor_layouts->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
settings_menu->add_child(editor_layouts);
settings_menu->add_submenu_node_item(TTR("Editor Layout"), editor_layouts);
editor_layouts->connect("id_pressed", callable_mp(this, &EditorNode::_layout_menu_option));
settings_menu->add_submenu_item(TTR("Editor Layout"), "Layouts");
settings_menu->add_separator();
ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KeyModifierMask::CTRL | Key::F12);
@ -7404,12 +7394,10 @@ EditorNode::EditorNode() {
add_editor_plugin(VersionControlEditorPlugin::get_singleton());
vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel();
vcs_actions_menu->set_name("Version Control");
vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option));
vcs_actions_menu->add_item(TTR("Create/Override Version Control Metadata..."), RUN_VCS_METADATA);
vcs_actions_menu->add_item(TTR("Version Control Settings..."), RUN_VCS_SETTINGS);
project_menu->add_child(vcs_actions_menu);
project_menu->set_item_submenu(project_menu->get_item_index(VCS_MENU), "Version Control");
project_menu->set_item_submenu_node(project_menu->get_item_index(VCS_MENU), vcs_actions_menu);
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));

View File

@ -3052,11 +3052,9 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (p_paths.size() == 1 && p_display_path_dependent_options) {
PopupMenu *new_menu = memnew(PopupMenu);
new_menu->set_name("New");
new_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option));
p_popup->add_child(new_menu);
p_popup->add_submenu_item(TTR("Create New"), "New", FILE_NEW);
p_popup->add_submenu_node_item(TTR("Create New"), new_menu, FILE_NEW);
p_popup->set_item_icon(p_popup->get_item_index(FILE_NEW), get_editor_theme_icon(SNAME("Add")));
new_menu->add_icon_item(get_editor_theme_icon(SNAME("Folder")), TTR("Folder..."), FILE_NEW_FOLDER);
@ -3079,11 +3077,9 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (p_paths[0] != "res://") {
PopupMenu *folder_colors_menu = memnew(PopupMenu);
folder_colors_menu->set_name("FolderColor");
folder_colors_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_folder_color_index_pressed).bind(folder_colors_menu));
p_popup->add_child(folder_colors_menu);
p_popup->add_submenu_item(TTR("Set Folder Color..."), "FolderColor");
p_popup->add_submenu_node_item(TTR("Set Folder Color..."), folder_colors_menu);
p_popup->set_item_icon(-1, get_editor_theme_icon(SNAME("Paint")));
folder_colors_menu->add_icon_item(get_editor_theme_icon(SNAME("Folder")), TTR("Default (Reset)"));

View File

@ -80,7 +80,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
classes.sort_custom<StringName::AlphCompare>();
menu->add_submenu_item(TTR("Add Animation"), "AddAnimations");
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
List<StringName> names;
tree->get_animation_list(&names);
@ -802,9 +802,8 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type));
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("AddAnimations");
animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
menu->add_child(animations_menu);
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_animation_type));
open_file = memnew(EditorFileDialog);

View File

@ -125,7 +125,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
classes.sort_custom<StringName::AlphCompare>();
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "AddAnimations");
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
List<StringName> names;
tree->get_animation_list(&names);
@ -1081,9 +1081,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_menu_type));
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("AddAnimations");
animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
menu->add_child(animations_menu);
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_animation_type));
open_file = memnew(EditorFileDialog);

View File

@ -568,7 +568,7 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
List<StringName> animation_names;
tree->get_animation_list(&animation_names);
menu->add_submenu_item(TTR("Add Animation"), "AddAnimations");
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
if (animation_names.is_empty()) {
menu->set_item_disabled(menu->get_item_idx_from_text(TTR("Add Animation")), true);
} else {
@ -1777,9 +1777,8 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
menu->connect("popup_hide", callable_mp(this, &AnimationNodeStateMachineEditor::_stop_connecting));
animations_menu = memnew(PopupMenu);
menu->add_child(animations_menu);
animations_menu->set_name("AddAnimations");
animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
menu->add_child(animations_menu);
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_animation_type));
connect_menu = memnew(PopupMenu);

View File

@ -5319,14 +5319,8 @@ CanvasItemEditor::CanvasItemEditor() {
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL);
p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping");
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE);
smartsnap_config_popup = memnew(PopupMenu);
p->add_child(smartsnap_config_popup);
smartsnap_config_popup->set_name("SmartSnapping");
smartsnap_config_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
smartsnap_config_popup->set_hide_on_checkable_item_selection(false);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT);
@ -5335,6 +5329,10 @@ CanvasItemEditor::CanvasItemEditor() {
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_center", TTR("Snap to Node Center")), SNAP_USE_NODE_CENTER);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES);
p->add_submenu_node_item(TTR("Smart Snapping"), smartsnap_config_popup);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE);
main_menu_hbox->add_child(memnew(VSeparator));
@ -5416,14 +5414,12 @@ CanvasItemEditor::CanvasItemEditor() {
grid_menu = memnew(PopupMenu);
grid_menu->connect("about_to_popup", callable_mp(this, &CanvasItemEditor::_prepare_grid_menu));
grid_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_on_grid_menu_id_pressed));
grid_menu->set_name("GridMenu");
grid_menu->add_radio_check_item(TTR("Show"), GRID_VISIBILITY_SHOW);
grid_menu->add_radio_check_item(TTR("Show When Snapping"), GRID_VISIBILITY_SHOW_WHEN_SNAPPING);
grid_menu->add_radio_check_item(TTR("Hide"), GRID_VISIBILITY_HIDE);
grid_menu->add_separator();
grid_menu->add_shortcut(ED_SHORTCUT("canvas_item_editor/toggle_grid", TTR("Toggle Grid"), KeyModifierMask::CMD_OR_CTRL | Key::APOSTROPHE));
p->add_child(grid_menu);
p->add_submenu_item(TTR("Grid"), "GridMenu");
p->add_submenu_node_item(TTR("Grid"), grid_menu);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), Key::H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers")), SHOW_RULERS);
@ -5452,12 +5448,10 @@ CanvasItemEditor::CanvasItemEditor() {
theme_menu = memnew(PopupMenu);
theme_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_switch_theme_preview));
theme_menu->set_name("ThemeMenu");
theme_menu->add_radio_check_item(TTR("Project theme"), THEME_PREVIEW_PROJECT);
theme_menu->add_radio_check_item(TTR("Editor theme"), THEME_PREVIEW_EDITOR);
theme_menu->add_radio_check_item(TTR("Default theme"), THEME_PREVIEW_DEFAULT);
p->add_child(theme_menu);
p->add_submenu_item(TTR("Preview Theme"), "ThemeMenu");
p->add_submenu_node_item(TTR("Preview Theme"), theme_menu);
theme_preview = (ThemePreviewMode)(int)EditorSettings::get_singleton()->get_project_metadata("2d_editor", "theme_preview", THEME_PREVIEW_PROJECT);
for (int i = 0; i < THEME_PREVIEW_MAX; i++) {

View File

@ -723,7 +723,7 @@ void EditorPropertyOTFeatures::update_property() {
}
for (int i = 0; i < FGRP_MAX; i++) {
if (have_sub[i]) {
menu->add_submenu_item(RTR(group_names[i]), "FTRMenu_" + itos(i));
menu->add_submenu_node_item(RTR(group_names[i]), menu_sub[i]);
}
}
@ -851,7 +851,6 @@ EditorPropertyOTFeatures::EditorPropertyOTFeatures() {
for (int i = 0; i < FGRP_MAX; i++) {
menu_sub[i] = memnew(PopupMenu);
menu_sub[i]->set_name("FTRMenu_" + itos(i));
menu->add_child(menu_sub[i]);
menu_sub[i]->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature));
}

View File

@ -5077,9 +5077,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->set_shortcut_context(this);
vbox->add_child(view_menu);
display_submenu = memnew(PopupMenu);
view_menu->get_popup()->set_hide_on_checkable_item_selection(false);
view_menu->get_popup()->add_child(display_submenu);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
@ -5104,6 +5102,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_lighting", TTR("Display Lighting")), VIEW_DISPLAY_LIGHTING);
view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_UNSHADED);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
display_submenu = memnew(PopupMenu);
display_submenu->set_hide_on_checkable_item_selection(false);
display_submenu->add_radio_check_item(TTR("Directional Shadow Splits"), VIEW_DISPLAY_DEBUG_PSSM_SPLITS);
display_submenu->add_separator();
@ -5137,9 +5137,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
display_submenu->add_radio_check_item(TTR("Occlusion Culling Buffer"), VIEW_DISPLAY_DEBUG_OCCLUDERS);
display_submenu->add_radio_check_item(TTR("Motion Vectors"), VIEW_DISPLAY_MOTION_VECTORS);
display_submenu->add_radio_check_item(TTR("Internal Buffer"), VIEW_DISPLAY_INTERNAL_BUFFER);
view_menu->get_popup()->add_submenu_node_item(TTR("Display Advanced..."), display_submenu, VIEW_DISPLAY_ADVANCED);
display_submenu->set_name("DisplayAdvanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "DisplayAdvanced", VIEW_DISPLAY_ADVANCED);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
@ -8518,7 +8517,10 @@ Node3DEditor::Node3DEditor() {
p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KeyModifierMask::CMD_OR_CTRL + Key::KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
gizmos_menu = memnew(PopupMenu);
gizmos_menu->set_hide_on_checkable_item_selection(false);
p->add_submenu_node_item(TTR("Gizmos"), gizmos_menu);
gizmos_menu->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_gizmo_toggled));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
@ -8532,12 +8534,6 @@ Node3DEditor::Node3DEditor() {
p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed));
gizmos_menu = memnew(PopupMenu);
p->add_child(gizmos_menu);
gizmos_menu->set_name("GizmosMenu");
gizmos_menu->set_hide_on_checkable_item_selection(false);
gizmos_menu->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_gizmo_toggled));
/* REST OF MENU */
left_panel_split = memnew(HSplitContainer);

View File

@ -4004,12 +4004,11 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::N), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::T), FILE_REOPEN_CLOSED);
file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT);
recent_scripts = memnew(PopupMenu);
recent_scripts->set_name("RecentScripts");
file_menu->get_popup()->add_child(recent_scripts);
file_menu->get_popup()->add_submenu_node_item(TTR("Open Recent"), recent_scripts, FILE_OPEN_RECENT);
recent_scripts->connect("id_pressed", callable_mp(this, &ScriptEditor::_open_recent_script));
_update_recent_scripts();
file_menu->get_popup()->add_separator();
@ -4027,14 +4026,11 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KeyModifierMask::ALT | Key::RIGHT), WINDOW_NEXT);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_submenu_item(TTR("Theme"), "Theme", FILE_THEME);
theme_submenu = memnew(PopupMenu);
theme_submenu->set_name("Theme");
file_menu->get_popup()->add_child(theme_submenu);
theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option));
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme...")), THEME_IMPORT);
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD);
file_menu->get_popup()->add_submenu_node_item(TTR("Theme"), theme_submenu, FILE_THEME);
theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option));
theme_submenu->add_separator();
theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), THEME_SAVE);

View File

@ -2255,7 +2255,6 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_separator();
{
PopupMenu *sub_menu = memnew(PopupMenu);
sub_menu->set_name("LineMenu");
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
@ -2263,47 +2262,39 @@ void ScriptTextEditor::_enable_code_editor() {
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(sub_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Line"), "LineMenu");
edit_menu->get_popup()->add_submenu_node_item(TTR("Line"), sub_menu);
}
{
PopupMenu *sub_menu = memnew(PopupMenu);
sub_menu->set_name("FoldingMenu");
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/create_code_region"), EDIT_CREATE_CODE_REGION);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(sub_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Folding"), "FoldingMenu");
edit_menu->get_popup()->add_submenu_node_item(TTR("Folding"), sub_menu);
}
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
{
PopupMenu *sub_menu = memnew(PopupMenu);
sub_menu->set_name("IndentMenu");
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(sub_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Indentation"), "IndentMenu");
edit_menu->get_popup()->add_submenu_node_item(TTR("Indentation"), sub_menu);
}
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_separator();
{
PopupMenu *sub_menu = memnew(PopupMenu);
sub_menu->set_name("ConvertCase");
sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(sub_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "ConvertCase");
edit_menu->get_popup()->add_submenu_node_item(TTR("Convert Case"), sub_menu);
}
edit_menu->get_popup()->add_child(highlighter_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "HighlighterMenu");
edit_menu->get_popup()->add_submenu_node_item(TTR("Syntax Highlighter"), highlighter_menu);
highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter));
edit_hb->add_child(search_menu);
@ -2325,14 +2316,12 @@ void ScriptTextEditor::_enable_code_editor() {
goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE);
goto_menu->get_popup()->add_separator();
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "BookmarksMenu");
goto_menu->get_popup()->add_submenu_node_item(TTR("Bookmarks"), bookmarks_menu);
_update_bookmark_list();
bookmarks_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed));
goto_menu->get_popup()->add_child(breakpoints_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "BreakpointsMenu");
goto_menu->get_popup()->add_submenu_node_item(TTR("Breakpoints"), breakpoints_menu);
_update_breakpoint_list();
breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list));
breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed));
@ -2393,7 +2382,6 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->set_shortcut_context(this);
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("HighlighterMenu");
Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter;
plain_highlighter.instantiate();
@ -2415,10 +2403,7 @@ ScriptTextEditor::ScriptTextEditor() {
goto_menu->set_shortcut_context(this);
bookmarks_menu = memnew(PopupMenu);
bookmarks_menu->set_name("BookmarksMenu");
breakpoints_menu = memnew(PopupMenu);
breakpoints_menu->set_name("BreakpointsMenu");
connection_info_dialog = memnew(ConnectionInfoDialog);

View File

@ -654,18 +654,14 @@ TextEditor::TextEditor() {
edit_menu->get_popup()->add_separator();
PopupMenu *convert_case = memnew(PopupMenu);
convert_case->set_name("ConvertCase");
edit_menu->get_popup()->add_child(convert_case);
edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "ConvertCase");
edit_menu->get_popup()->add_submenu_node_item(TTR("Convert Case"), convert_case);
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE);
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE);
convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("HighlighterMenu");
edit_menu->get_popup()->add_child(highlighter_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "HighlighterMenu");
edit_menu->get_popup()->add_submenu_node_item(TTR("Syntax Highlighter"), highlighter_menu);
highlighter_menu->connect("id_pressed", callable_mp(this, &TextEditor::_change_syntax_highlighter));
Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter;
@ -703,9 +699,7 @@ TextEditor::TextEditor() {
goto_menu->get_popup()->add_separator();
bookmarks_menu = memnew(PopupMenu);
bookmarks_menu->set_name("BookmarksMenu");
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "BookmarksMenu");
goto_menu->get_popup()->add_submenu_node_item(TTR("Bookmarks"), bookmarks_menu);
_update_bookmark_list();
bookmarks_menu->connect("about_to_popup", callable_mp(this, &TextEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &TextEditor::_bookmark_item_pressed));

View File

@ -1161,9 +1161,7 @@ TextShaderEditor::TextShaderEditor() {
goto_menu->get_popup()->add_separator();
bookmarks_menu = memnew(PopupMenu);
bookmarks_menu->set_name("BookmarksMenu");
goto_menu->get_popup()->add_child(bookmarks_menu);
goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "BookmarksMenu");
goto_menu->get_popup()->add_submenu_node_item(TTR("Bookmarks"), bookmarks_menu);
_update_bookmark_list();
bookmarks_menu->connect("about_to_popup", callable_mp(this, &TextShaderEditor::_update_bookmark_list));
bookmarks_menu->connect("index_pressed", callable_mp(this, &TextShaderEditor::_bookmark_item_pressed));

View File

@ -353,9 +353,7 @@ DefaultThemeEditorPreview::DefaultThemeEditorPreview() {
test_menu_button->get_popup()->add_separator(TTR("Named Separator"));
PopupMenu *test_submenu = memnew(PopupMenu);
test_menu_button->get_popup()->add_child(test_submenu);
test_submenu->set_name("SubMenu");
test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "SubMenu");
test_menu_button->get_popup()->add_submenu_node_item(TTR("Submenu"), test_submenu);
test_submenu->add_item(TTR("Subitem 1"));
test_submenu->add_item(TTR("Subitem 2"));
first_vb->add_child(test_menu_button);

View File

@ -1444,18 +1444,14 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
extra_options_remove_branch_list = memnew(PopupMenu);
extra_options_remove_branch_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_branch_remove_confirm));
extra_options_remove_branch_list->set_name("RemoveBranch");
extra_options->get_popup()->add_child(extra_options_remove_branch_list);
extra_options->get_popup()->add_submenu_item(TTR("Remove Branch"), "RemoveBranch");
extra_options->get_popup()->add_submenu_node_item(TTR("Remove Branch"), extra_options_remove_branch_list);
extra_options->get_popup()->add_separator();
extra_options->get_popup()->add_item(TTR("Create New Remote"), EXTRA_OPTION_CREATE_REMOTE);
extra_options_remove_remote_list = memnew(PopupMenu);
extra_options_remove_remote_list->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_popup_remote_remove_confirm));
extra_options_remove_remote_list->set_name("RemoveRemote");
extra_options->get_popup()->add_child(extra_options_remove_remote_list);
extra_options->get_popup()->add_submenu_item(TTR("Remove Remote"), "RemoveRemote");
extra_options->get_popup()->add_submenu_node_item(TTR("Remove Remote"), extra_options_remove_remote_list);
change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_NEW] = TTR("New");
change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = TTR("Modified");

View File

@ -4209,18 +4209,15 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
if (selected_float_constant != -1) {
popup_menu->add_submenu_item(TTR("Float Constants"), "FloatConstants", int(NodeMenuOptions::FLOAT_CONSTANTS));
if (!constants_submenu) {
constants_submenu = memnew(PopupMenu);
constants_submenu->set_name("FloatConstants");
for (int i = 0; i < MAX_FLOAT_CONST_DEFS; i++) {
constants_submenu->add_item(float_constant_defs[i].name, i);
}
popup_menu->add_child(constants_submenu);
constants_submenu->connect("index_pressed", callable_mp(this, &VisualShaderEditor::_float_constant_selected));
}
popup_menu->add_submenu_node_item(TTR("Float Constants"), constants_submenu, int(NodeMenuOptions::FLOAT_CONSTANTS));
}
if (selected_constants.size() > 0) {

View File

@ -3263,7 +3263,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
if (menu->get_item_count() == 0) {
menu->add_submenu_item(TTR("Sub-Resources"), "SubResources");
menu->add_submenu_node_item(TTR("Sub-Resources"), menu_subresources);
}
menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
menu_subresources->set_item_indent(-1, p_depth);
@ -3504,11 +3504,9 @@ void SceneTreeDock::_update_tree_menu() {
tree_menu->set_item_tooltip(tree_menu->get_item_index(TOOL_CENTER_PARENT), TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible."));
PopupMenu *resource_list = memnew(PopupMenu);
resource_list->set_name("AllResources");
resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list));
resource_list->connect("index_pressed", callable_mp(this, &SceneTreeDock::_edit_subresource).bind(resource_list));
tree_menu->add_child(resource_list);
tree_menu->add_submenu_item(TTR("All Scene Sub-Resources"), "AllResources");
tree_menu->add_submenu_node_item(TTR("All Scene Sub-Resources"), resource_list);
}
void SceneTreeDock::_filter_changed(const String &p_filter) {
@ -4365,7 +4363,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
menu_subresources = memnew(PopupMenu);
menu_subresources->set_name("SubResources");
menu_subresources->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
menu->add_child(menu_subresources);

View File

@ -2406,15 +2406,12 @@ void LineEdit::_generate_context_menu() {
add_child(menu, false, INTERNAL_MODE_FRONT);
menu_dir = memnew(PopupMenu);
menu_dir->set_name("DirMenu");
menu_dir->add_radio_check_item(RTR("Same as Layout Direction"), MENU_DIR_INHERITED);
menu_dir->add_radio_check_item(RTR("Auto-Detect Direction"), MENU_DIR_AUTO);
menu_dir->add_radio_check_item(RTR("Left-to-Right"), MENU_DIR_LTR);
menu_dir->add_radio_check_item(RTR("Right-to-Left"), MENU_DIR_RTL);
menu->add_child(menu_dir, false, INTERNAL_MODE_FRONT);
menu_ctl = memnew(PopupMenu);
menu_ctl->set_name("CTLMenu");
menu_ctl->add_item(RTR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM);
menu_ctl->add_item(RTR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM);
menu_ctl->add_item(RTR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE);
@ -2433,7 +2430,6 @@ void LineEdit::_generate_context_menu() {
menu_ctl->add_item(RTR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ);
menu_ctl->add_item(RTR("Word Joiner (WJ)"), MENU_INSERT_WJ);
menu_ctl->add_item(RTR("Soft Hyphen (SHY)"), MENU_INSERT_SHY);
menu->add_child(menu_ctl, false, INTERNAL_MODE_FRONT);
menu->add_item(RTR("Cut"), MENU_CUT);
menu->add_item(RTR("Copy"), MENU_COPY);
@ -2445,10 +2441,10 @@ void LineEdit::_generate_context_menu() {
menu->add_item(RTR("Undo"), MENU_UNDO);
menu->add_item(RTR("Redo"), MENU_REDO);
menu->add_separator();
menu->add_submenu_item(RTR("Text Writing Direction"), "DirMenu", MENU_SUBMENU_TEXT_DIR);
menu->add_submenu_node_item(RTR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR);
menu->add_separator();
menu->add_check_item(RTR("Display Control Characters"), MENU_DISPLAY_UCC);
menu->add_submenu_item(RTR("Insert Control Character"), "CTLMenu", MENU_SUBMENU_INSERT_UCC);
menu->add_submenu_node_item(RTR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC);
menu->connect("id_pressed", callable_mp(this, &LineEdit::menu_option));
menu_dir->connect("id_pressed", callable_mp(this, &LineEdit::menu_option));

View File

@ -111,13 +111,10 @@ String PopupMenu::bind_global_menu() {
ds->global_menu_add_separator(global_menu_name);
} else {
int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), item.shortcut_is_global ? callable_mp(this, &PopupMenu::activate_item) : Callable(), i);
if (!item.submenu.is_empty()) {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(item.submenu));
if (pm) {
String submenu_name = pm->bind_global_menu();
ds->global_menu_set_item_submenu(global_menu_name, index, submenu_name);
item.submenu_bound = true;
}
if (item.submenu) {
String submenu_name = item.submenu->bind_global_menu();
ds->global_menu_set_item_submenu(global_menu_name, index, submenu_name);
item.submenu_bound = true;
}
if (item.checkable_type == Item::CHECKABLE_TYPE_CHECK_BOX) {
ds->global_menu_set_item_checkable(global_menu_name, index, true);
@ -158,11 +155,8 @@ void PopupMenu::unbind_global_menu() {
for (int i = 0; i < items.size(); i++) {
Item &item = items.write[i];
if (!item.submenu.is_empty()) {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(item.submenu));
if (pm) {
pm->unbind_global_menu();
}
if (item.submenu) {
item.submenu->unbind_global_menu();
item.submenu_bound = false;
}
}
@ -251,7 +245,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
accel_max_w = MAX(accel_w, accel_max_w);
}
if (!items[i].submenu.is_empty()) {
if (items[i].submenu) {
item_size.width += theme_cache.submenu->get_width();
}
@ -335,10 +329,7 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
}
void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
Node *n = get_node_or_null(items[p_over].submenu);
ERR_FAIL_NULL_MSG(n, "Item subnode does not exist: '" + items[p_over].submenu + "'.");
Popup *submenu_popup = Object::cast_to<Popup>(n);
ERR_FAIL_NULL_MSG(submenu_popup, "Item subnode is not a Popup: '" + items[p_over].submenu + "'.");
Popup *submenu_popup = items[p_over].submenu;
if (submenu_popup->is_visible()) {
return; // Already visible.
}
@ -551,7 +542,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
}
}
} else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
set_input_as_handled();
} else {
@ -564,7 +555,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
}
} else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
if (items[mouse_over].submenu && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
} else {
activate_item(mouse_over);
@ -620,7 +611,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
return;
}
if (!items[over].submenu.is_empty()) {
if (items[over].submenu) {
_activate_submenu(over);
return;
}
@ -657,7 +648,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
return;
}
if (!items[over].submenu.is_empty() && submenu_over != over) {
if (items[over].submenu && submenu_over != over) {
submenu_over = over;
submenu_timer->start();
}
@ -858,7 +849,7 @@ void PopupMenu::_draw_items() {
}
// Submenu arrow on right hand side.
if (!items[i].submenu.is_empty()) {
if (items[i].submenu) {
if (rtl) {
submenu->draw(ci, Point2(scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
} else {
@ -974,11 +965,13 @@ void PopupMenu::_menu_changed() {
void PopupMenu::add_child_notify(Node *p_child) {
Window::add_child_notify(p_child);
if (Object::cast_to<PopupMenu>(p_child) && !global_menu_name.is_empty()) {
String node_name = p_child->get_name();
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(node_name));
PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
if (!pm) {
return;
}
if (!global_menu_name.is_empty()) {
for (int i = 0; i < items.size(); i++) {
if (items[i].submenu == node_name) {
if (items[i].submenu == p_child) {
String submenu_name = pm->bind_global_menu();
DisplayServer::get_singleton()->global_menu_set_item_submenu(global_menu_name, i, submenu_name);
items.write[i].submenu_bound = true;
@ -996,9 +989,8 @@ void PopupMenu::remove_child_notify(Node *p_child) {
return;
}
if (Object::cast_to<PopupMenu>(p_child) && !global_menu_name.is_empty()) {
String node_name = p_child->get_name();
for (int i = 0; i < items.size(); i++) {
if (items[i].submenu == node_name) {
if (items[i].submenu == p_child) {
DisplayServer::get_singleton()->global_menu_set_item_submenu(global_menu_name, i, String());
items.write[i].submenu_bound = false;
}
@ -1056,7 +1048,7 @@ void PopupMenu::_notification(int p_what) {
} break;
case NOTIFICATION_WM_MOUSE_EXIT: {
if (mouse_over >= 0 && (items[mouse_over].submenu.is_empty() || submenu_over != -1)) {
if (mouse_over >= 0 && (!items[mouse_over].submenu || submenu_over != -1)) {
mouse_over = -1;
control->queue_redraw();
}
@ -1166,21 +1158,10 @@ void PopupMenu::_notification(int p_what) {
}
for (int i = 0; i < items.size(); i++) {
if (items[i].submenu.is_empty()) {
if (!items[i].submenu) {
continue;
}
Node *n = get_node(items[i].submenu);
if (!n) {
continue;
}
PopupMenu *pm = Object::cast_to<PopupMenu>(n);
if (!pm || !pm->is_visible()) {
continue;
}
pm->hide();
items[i].submenu->hide();
}
set_process_internal(false);
@ -1563,9 +1544,18 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
String submenu_name_safe = p_submenu.replace("@", "_"); // Allow special characters for auto-generated names.
if (submenu_name_safe.validate_node_name() != submenu_name_safe) {
ERR_FAIL_MSG(vformat("Invalid node name '%s' for a submenu, the following characters are not allowed:\n%s", p_submenu, String::get_invalid_node_name_characters(true)));
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(p_submenu));
ERR_FAIL_NULL_MSG(pm, vformat("Child PopupMenu \"%s\" does not exist.", p_submenu));
add_submenu_node_item(p_label, pm, p_id);
}
void PopupMenu::add_submenu_node_item(const String &p_label, PopupMenu *p_submenu, int p_id) {
ERR_FAIL_NULL(p_submenu);
if (p_submenu->get_parent() != this) {
ERR_FAIL_COND_MSG(p_submenu->get_parent() != nullptr, vformat("The submenu \"%s\" already has a different parent.", p_submenu->get_name()));
add_child(p_submenu);
}
Item item;
@ -1573,17 +1563,15 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.xl_text = atr(p_label);
item.id = p_id == -1 ? items.size() : p_id;
item.submenu = p_submenu;
item.submenu_name = p_submenu->get_name();
items.push_back(item);
if (!global_menu_name.is_empty()) {
DisplayServer *ds = DisplayServer::get_singleton();
int index = ds->global_menu_add_item(global_menu_name, item.xl_text, callable_mp(this, &PopupMenu::activate_item), Callable(), items.size() - 1);
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(item.submenu)); // Find first menu with this name.
if (pm) {
String submenu_name = pm->bind_global_menu();
ds->global_menu_set_item_submenu(global_menu_name, index, submenu_name);
items.write[index].submenu_bound = true;
}
String submenu_name = p_submenu->bind_global_menu();
ds->global_menu_set_item_submenu(global_menu_name, index, submenu_name);
items.write[index].submenu_bound = true;
}
_shape_item(items.size() - 1);
@ -1804,18 +1792,31 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
}
ERR_FAIL_INDEX(p_idx, items.size());
if (items[p_idx].submenu == p_submenu) {
if (items[p_idx].submenu_name == p_submenu) {
return;
}
String submenu_name_safe = p_submenu.replace("@", "_"); // Allow special characters for auto-generated names.
if (submenu_name_safe.validate_node_name() != submenu_name_safe) {
ERR_FAIL_MSG(vformat("Invalid node name '%s' for a submenu, the following characters are not allowed:\n%s", p_submenu, String::get_invalid_node_name_characters(true)));
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(p_submenu));
ERR_FAIL_NULL_MSG(pm, vformat("Child PopupMenu \"%s\" does not exist.", p_submenu));
set_item_submenu_node(p_idx, pm);
}
void PopupMenu::set_item_submenu_node(int p_idx, PopupMenu *p_submenu) {
ERR_FAIL_NULL(p_submenu);
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
if (p_submenu->get_parent() != this) {
ERR_FAIL_COND_MSG(p_submenu->get_parent() != nullptr, vformat("The submenu \"%s\" already has a different parent.", p_submenu->get_name()));
add_child(p_submenu);
}
if (!global_menu_name.is_empty()) {
if (items[p_idx].submenu_bound) {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(items[p_idx].submenu));
PopupMenu *pm = items[p_idx].submenu;
if (pm) {
DisplayServer::get_singleton()->global_menu_set_item_submenu(global_menu_name, p_idx, String());
pm->unbind_global_menu();
@ -1827,13 +1828,10 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
items.write[p_idx].submenu = p_submenu;
if (!global_menu_name.is_empty()) {
if (!items[p_idx].submenu.is_empty()) {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(items[p_idx].submenu));
if (pm) {
String submenu_name = pm->bind_global_menu();
DisplayServer::get_singleton()->global_menu_set_item_submenu(global_menu_name, p_idx, submenu_name);
items.write[p_idx].submenu_bound = true;
}
if (items[p_idx].submenu) {
String submenu_name = p_submenu->bind_global_menu();
DisplayServer::get_singleton()->global_menu_set_item_submenu(global_menu_name, p_idx, submenu_name);
items.write[p_idx].submenu_bound = true;
}
}
@ -1937,6 +1935,11 @@ int PopupMenu::get_item_index(int p_id) const {
String PopupMenu::get_item_submenu(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), "");
return items[p_idx].submenu_name;
}
PopupMenu *PopupMenu::get_item_submenu_node(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), nullptr);
return items[p_idx].submenu;
}
@ -2333,18 +2336,8 @@ bool PopupMenu::activate_item_by_event(const Ref<InputEvent> &p_event, bool p_fo
return true;
}
if (!items[i].submenu.is_empty()) {
Node *n = get_node(items[i].submenu);
if (!n) {
continue;
}
PopupMenu *pm = Object::cast_to<PopupMenu>(n);
if (!pm) {
continue;
}
if (pm->activate_item_by_event(p_event, p_for_global_only)) {
if (items[i].submenu) {
if (items[i].submenu->activate_item_by_event(p_event, p_for_global_only)) {
return true;
}
}
@ -2458,12 +2451,9 @@ void PopupMenu::clear(bool p_free_submenus) {
_unref_shortcut(I.shortcut);
}
if (p_free_submenus && !I.submenu.is_empty()) {
Node *submenu = get_node_or_null(I.submenu);
if (submenu) {
remove_child(submenu);
submenu->queue_free();
}
if (p_free_submenus && I.submenu) {
remove_child(I.submenu);
I.submenu->queue_free();
}
}
@ -2471,11 +2461,8 @@ void PopupMenu::clear(bool p_free_submenus) {
DisplayServer *ds = DisplayServer::get_singleton();
for (int i = items.size() - 1; i >= 0; i--) {
Item &item = items.write[i];
if (!item.submenu.is_empty()) {
PopupMenu *pm = Object::cast_to<PopupMenu>(get_node_or_null(item.submenu));
if (pm) {
pm->unbind_global_menu();
}
if (item.submenu) {
item.submenu->unbind_global_menu();
item.submenu_bound = false;
}
ds->global_menu_remove_item(global_menu_name, i);
@ -2654,6 +2641,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_icon_radio_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_radio_check_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_submenu_node_item", "label", "submenu", "id"), &PopupMenu::add_submenu_node_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_item_text", "index", "text"), &PopupMenu::set_item_text);
ClassDB::bind_method(D_METHOD("set_item_text_direction", "index", "direction"), &PopupMenu::set_item_text_direction);
@ -2667,6 +2655,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_metadata", "index", "metadata"), &PopupMenu::set_item_metadata);
ClassDB::bind_method(D_METHOD("set_item_disabled", "index", "disabled"), &PopupMenu::set_item_disabled);
ClassDB::bind_method(D_METHOD("set_item_submenu", "index", "submenu"), &PopupMenu::set_item_submenu);
ClassDB::bind_method(D_METHOD("set_item_submenu_node", "index", "submenu"), &PopupMenu::set_item_submenu_node);
ClassDB::bind_method(D_METHOD("set_item_as_separator", "index", "enable"), &PopupMenu::set_item_as_separator);
ClassDB::bind_method(D_METHOD("set_item_as_checkable", "index", "enable"), &PopupMenu::set_item_as_checkable);
ClassDB::bind_method(D_METHOD("set_item_as_radio_checkable", "index", "enable"), &PopupMenu::set_item_as_radio_checkable);
@ -2693,6 +2682,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_metadata", "index"), &PopupMenu::get_item_metadata);
ClassDB::bind_method(D_METHOD("is_item_disabled", "index"), &PopupMenu::is_item_disabled);
ClassDB::bind_method(D_METHOD("get_item_submenu", "index"), &PopupMenu::get_item_submenu);
ClassDB::bind_method(D_METHOD("get_item_submenu_node", "index"), &PopupMenu::get_item_submenu_node);
ClassDB::bind_method(D_METHOD("is_item_separator", "index"), &PopupMenu::is_item_separator);
ClassDB::bind_method(D_METHOD("is_item_checkable", "index"), &PopupMenu::is_item_checkable);
ClassDB::bind_method(D_METHOD("is_item_radio_checkable", "index"), &PopupMenu::is_item_radio_checkable);

View File

@ -68,7 +68,8 @@ class PopupMenu : public Popup {
bool dirty = true;
int id = 0;
Variant metadata;
String submenu;
String submenu_name; // Compatibility.
PopupMenu *submenu = nullptr;
String tooltip;
Key accel = Key::NONE;
int _ofs_cache = 0;
@ -254,6 +255,7 @@ public:
void add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id = -1, bool p_global = false);
void add_submenu_item(const String &p_label, const String &p_submenu, int p_id = -1);
void add_submenu_node_item(const String &p_label, PopupMenu *p_submenu, int p_id = -1);
void set_item_text(int p_idx, const String &p_text);
@ -268,6 +270,7 @@ public:
void set_item_metadata(int p_idx, const Variant &p_meta);
void set_item_disabled(int p_idx, bool p_disabled);
void set_item_submenu(int p_idx, const String &p_submenu);
void set_item_submenu_node(int p_idx, PopupMenu *p_submenu);
void set_item_as_separator(int p_idx, bool p_separator);
void set_item_as_checkable(int p_idx, bool p_checkable);
void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable);
@ -296,6 +299,7 @@ public:
Variant get_item_metadata(int p_idx) const;
bool is_item_disabled(int p_idx) const;
String get_item_submenu(int p_idx) const;
PopupMenu *get_item_submenu_node(int p_idx) const;
bool is_item_separator(int p_idx) const;
bool is_item_checkable(int p_idx) const;
bool is_item_radio_checkable(int p_idx) const;

View File

@ -6873,15 +6873,12 @@ void TextEdit::_generate_context_menu() {
add_child(menu, false, INTERNAL_MODE_FRONT);
menu_dir = memnew(PopupMenu);
menu_dir->set_name("DirMenu");
menu_dir->add_radio_check_item(RTR("Same as Layout Direction"), MENU_DIR_INHERITED);
menu_dir->add_radio_check_item(RTR("Auto-Detect Direction"), MENU_DIR_AUTO);
menu_dir->add_radio_check_item(RTR("Left-to-Right"), MENU_DIR_LTR);
menu_dir->add_radio_check_item(RTR("Right-to-Left"), MENU_DIR_RTL);
menu->add_child(menu_dir, false, INTERNAL_MODE_FRONT);
menu_ctl = memnew(PopupMenu);
menu_ctl->set_name("CTLMenu");
menu_ctl->add_item(RTR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM);
menu_ctl->add_item(RTR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM);
menu_ctl->add_item(RTR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE);
@ -6900,7 +6897,6 @@ void TextEdit::_generate_context_menu() {
menu_ctl->add_item(RTR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ);
menu_ctl->add_item(RTR("Word Joiner (WJ)"), MENU_INSERT_WJ);
menu_ctl->add_item(RTR("Soft Hyphen (SHY)"), MENU_INSERT_SHY);
menu->add_child(menu_ctl, false, INTERNAL_MODE_FRONT);
menu->add_item(RTR("Cut"), MENU_CUT);
menu->add_item(RTR("Copy"), MENU_COPY);
@ -6912,10 +6908,10 @@ void TextEdit::_generate_context_menu() {
menu->add_item(RTR("Undo"), MENU_UNDO);
menu->add_item(RTR("Redo"), MENU_REDO);
menu->add_separator();
menu->add_submenu_item(RTR("Text Writing Direction"), "DirMenu", MENU_SUBMENU_TEXT_DIR);
menu->add_submenu_node_item(RTR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR);
menu->add_separator();
menu->add_check_item(RTR("Display Control Characters"), MENU_DISPLAY_UCC);
menu->add_submenu_item(RTR("Insert Control Character"), "CTLMenu", MENU_SUBMENU_INSERT_UCC);
menu->add_submenu_node_item(RTR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC);
menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));
menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option));