Last active
December 8, 2025 09:25
-
-
Save lfod1997/6e4ad613637d7e8411c1a603999b41d8 to your computer and use it in GitHub Desktop.
Godot: Create & Use `PopupMenu`s
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # In your class that manages popup menus: | |
| # These hold references to built menus | |
| var _menus: Dictionary[StringName, PopupMenu] | |
| var _menu_item_locator: Dictionary[StringName, Dictionary] | |
| func _enter_tree() -> void: | |
| # Build the main context menu | |
| add_child(build_menu( | |
| &"main_menu", # You later access the built `PopupMenu` through: `_menus[&"main_menu"]` | |
| [ | |
| [1, "Edit", false], # To add a normal menu item, use format: [ID, Label, Enabled by default] | |
| [2, "Copy Name", false], | |
| [], # To add a separator without text, use empty array: [] | |
| [101, "Group Selected", false], | |
| # To add a submenu, use format: [ID, Label, Enabled by default, Submenu Name, [Submenu Items]] | |
| [100, "Create", true, | |
| &"main_menu_add", # You later access the built sub-`PopupMenu` through: `_menus[&"main_menu_add"]` | |
| [ | |
| [111, "New Dependency Group...", false], | |
| [112, "New Path Pattern...", false], | |
| [113, "New Proxy...", false], | |
| ] | |
| ], | |
| ], | |
| _execute_routine, # "Primary handler" of all menu items, see below | |
| _menus, # All built `PopupMenu` are inserted into this | |
| _menu_item_locator # Converts an item's ID (that you define in the above array) to its index in the built `PopupMenu` that contains it | |
| )) | |
| # Build the menu to show on file drop | |
| add_child(build_menu( | |
| &"drag_menu", | |
| [ | |
| ["Import"], # To add a separator with text, use format: [Label] | |
| [1001, "As File Group", false], | |
| [1002, "As Path Pattern", false], | |
| [1003, "Dependency Group from this", false], | |
| ], | |
| _execute_routine, _menus, _menu_item_locator # Same as in the previous call | |
| )) | |
| # This function handles signal `PopupMenu.id_pressed`, which emits when an item in the popup menu is selected (and the menu hides) | |
| func _execute_routine(id: int) -> void: | |
| print("MENU SELECT: %d" % id) | |
| match id: # `id` equals what you've defined in the menu items array: [ This number!! -> ID, Label, Enabled by default ] | |
| 1: # [1, "Edit", false] | |
| print("The user wants to edit the selected file") | |
| 2: # [2, "Copy Name", false] | |
| print("The user wants to copy name of the selected file") | |
| 101: # [101, "Group Selected", false] | |
| print("The user wants to group selected files") | |
| #TODO: ^^^ Make cases & call your code above ^^^ | |
| _: | |
| print("Routine %d is invalid or not yet implemented" % id) | |
| # This function (that YOU should somehow call!) shows the main context menu | |
| func _show_main_menu(pos: Vector2) -> void: | |
| # Before showing, update related items' availability | |
| # Let's say the menu item "Edit" should be DISABLED if more than one file is selected | |
| _menus[&"main_menu"].set_item_disabled( # Godot API that sets: if item at the given index (not ID!) is disabled (true) or not (false) | |
| _menu_item_locator[&"main_menu"][1], # ID 1 is "Edit", this expr means: find index of item "Edit" in the `&"main_menu"` menu! | |
| _selected_files.size() != 1 # ykwim | |
| ) | |
| # ...and "Group Selected" should only be ENABLED when more than one file is selected | |
| _menus[&"main_menu"].set_item_disabled( | |
| _menu_item_locator[&"main_menu"][101], # ID 101 is "Group Selected" | |
| _selected_files.size() == 1 | |
| ) | |
| _menus[&"main_menu"].position = pos + Vector2(get_window().position) # Should popup at a screen space position (in pixels) | |
| _menus[&"main_menu"].popup() # Shows the popup |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment