Describe the project you are working on:
a spaceship game
Describe the problem or limitation you are having in your project:
I want to create a editor however I find that menu buttons are not very well thought out.
first of all they require a editor to edit them
second they don't easily support nested menus
third they aren't easily bindable to click events because you have to match between the items since they are internal to the menu button
Describe the feature / enhancement and how it helps to overcome the problem or limitation:
I suggest making the menu button and other menu controls obsolete and introducing a menu item which can be nested infinitely and hooked up separately.
it also wouldn't need a editor because each menu item would be its own control with properties
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
so basically it would looks something like this for a titlebar
each one would have a click or pressed event
If this enhancement will not be used often, can it be worked around with a few lines of script?:
this would be used as often as the current system if not more and it can be worked around but its inconvenient and not standard to other ui frameworks
Is there a reason why this should be core and not an add-on in the asset library?:
its already in its just not done a ideal way
Individual control's are not used for each item because controls have a fair amount of memory overhead. This way, a PopupMenu is only a very small number of nodes in the tree and it does not change with the amount of items. You could imagine that if you had a menu with 20 items with labels, maybe checkboxes, icons, etc, that is starting to get to 100+ nodes just for one menu.
first of all they require a editor to edit them
second they don't easily support nested menus
What do you mean? You can edit them through code very easily, including sub-menus. This sets up the menu you describe, including a nested menu.
var mb = $MenuButton
var popup = mb.get_popup()
popup.add_item("New")
popup.add_separator()
popup.add_item("Open")
popup.add_item("Save")
var nested_menu = PopupMenu.new()
nested_menu.name = "nested_menu_name"
nested_menu.add_item("Nested Item 1")
nested_menu.add_item("Nested Item 2")
popup.add_child(nested_menu)
popup.add_submenu_item("Submenu", "nested_menu_name")
popup.add_separator()
popup.add_item("Exit")
third they aren't easily bindable to click events because you have to match between the items since they are internal to the menu button
You can easily bind to what item is selected by connecting to the "id_pressed" signal on the popup. In the example below I set up an enum to easily track what options I have. You can also set the id on each item when you create it so it's easy to read and change in the future.
# Create an enum to store the options
enum Options {
NEW,
OPEN
SAVE
NESTED_ITEM1
NESTED_ITEM2
EXIT
}
func _ready():
var mb = self
# Create the items and set the Id's to the enum values.
var popup = mb.get_popup()
popup.add_item("New", Options.NEW)
popup.add_separator()
popup.add_item("Open", Options.OPEN)
popup.add_item("Save", Options.SAVE)
var nested_menu = PopupMenu.new()
nested_menu.name = "nested_menu_name"
nested_menu.add_item("Nested Item 1", Options.NESTED_ITEM1)
nested_menu.add_item("Nested Item 2", Options.NESTED_ITEM2)
nested_menu.connect("id_pressed", self, "_item_selected")
popup.add_child(nested_menu)
popup.add_submenu_item("Submenu", "nested_menu_name")
popup.add_separator()
popup.add_item("Exit", Options.EXIT)
# Connect the id pressed signal to the function which will handle the option logic
popup.connect("id_pressed", self, "_item_selected")
func _item_selected(id: int):
match id:
Options.NEW:
print("New")
Options.OPEN:
print("Open")
Options.SAVE:
print("Save")
Options.NESTED_ITEM1:
print("Nested 1")
Options.NESTED_ITEM2:
print("Nested 2")
Options.EXIT:
print("Exit")

@EricEzaM you just proved my point
what I mean by it requires a editor to edit things is this...

which you can do it through code, but its not necessary and people don't want to manually add their items through code as you can't visualize it.
secondly no they don't easily support nested menus as the current editor doesn't allow such a thing. you have to do in in code
also when I say they aren't easily bindable and you have to match their strings or ids.
you again proved my point.
func _item_selected(id: int):
match id:
Options.NEW:
print("New")
Options.OPEN:
print("Open")
Options.SAVE:
print("Save")
Options.NESTED_ITEM1:
print("Nested 1")
Options.NESTED_ITEM2:
print("Nested 2")
Options.EXIT:
print("Exit")
other frameworks use the way I suggest just fine and they are easy to use because if you need to you can do this..
$menu_item_file_new.connect("pressed", self, "_filenew_pressed")
func _filenew_pressed():
# do something
also it supports modifying each one of them in the inspector
people don't want to manually add their items through code
Haven't heard this one before. We'll let the support of this proposal determine that.
you can't visualize it.
This I don't understand. How is this big list easier to visualise than the code? Your eyes have to do so much searching. You have to specifically look for whether the separator checkbox is checked, as well as the other options.
The code and the gif are exactly equivelant:
popup.add_item("New")
popup.add_separator()
popup.add_item("Open")
popup.add_item("Save")
popup.add_separator()
popup.add_item("Exit")

secondly no they don't easily support nested menus as the current editor doesn't allow such a thing.
Having the items editor support submenus could be looked at, but this would probably benefit from being in its own stand-alone proposal. Off the top of my head it shouldn't be too hard to do but there can always be hidden complications.
also when I say they aren't easily bendable and you have to match their strings of ids.
Under what circumstance would you have a MenuButton but then _not_ want to do anything when one of them is clicked? You would have to connect to every single item anyway... that's a whole lot of boilerplate just to get that going. Maybe it works in some of these other frameworks (would be nice if you dropped some names) but I don't see the problem with the current method.
Additionally, like I said, there is memory overhead with every control node added to the tree. Perhaps it could work if you kept the custom drawing of icons, checkboxes, shortcuts, etc all in a custom draw function in the item control. So then 1 item always equals 1 node. That could be possible and may have limited impact on memory/performance.
The thing with proposals is that someone from the community has to come along and decide they want to try implement it. So there are no guarantees of it getting done - especially on a proposal like this which deals with a small part of the editor. You are always welcome to have a go at implementing it yourself and submitting a PR - no obligations to do so of course.
people don't want to manually add their items through code
Haven't heard this one before. We'll let the support of this proposal determine that.
the point of the godot editor is so we don't have to code everything manually.
you can't visualize it.
This I don't understand. How is this big list easier to visualise than the code? Your eyes have to do so much searching. You have to specifically look for whether the separator checkbox is checked, as well as the other options.
The code and the gif are exactly equivelant:
popup.add_item("New") popup.add_separator() popup.add_item("Open") popup.add_item("Save") popup.add_separator() popup.add_item("Exit")
you can still do that with this suggestion.
file = menu_item.new("File")
editor.add_child(file)
file.add_child(menu_item.new("New"))
file.add_child(seperator.new())
file.add_child(menu_item.new("Open"))
file.add_child(menu_item.new("Save"))
file.add_child(seperator.new())
file.add_child(menu_item.new("Exit"))
secondly no they don't easily support nested menus as the current editor doesn't allow such a thing.
Having the items editor support submenus could be looked at, but this would probably benefit from being in its own stand-alone proposal. Off the top of my head it shouldn't be too hard to do but there can always be hidden complications.
one of those hidden complications being that we would have to match nested id's when clicked?
ya I would rather not.
also when I say they aren't easily bendable and you have to match their strings of ids.
Under what circumstance would you have a MenuButton but then _not_ want to do anything when one of them is clicked? You would have to connect to every single item anyway... that's a whole lot of boilerplate just to get that going. Maybe it works in some of these other frameworks (would be nice if you dropped some names) but I don't see the problem with the current method.
the current method is ugly because you can't really code fold what your not working on.
also again the current method is linear aka like a list. menus are more like trees.
Additionally, like I said, there is memory overhead with every control node added to the tree. Perhaps it could work if you kept the custom drawing of icons, checkboxes, shortcuts, etc all in a custom draw function in the item control. So then 1 item always equals 1 node. That could be possible and may have limited impact on memory/performance.
It would have to be looked into but again its not going to make the whole program crash or slow down as many other gui frameworks actully do this.
The thing with proposals is that someone from the community has to come along and decide they want to try implement it. So there are no guarantees of it getting done - especially on a proposal like this which deals with a small part of the editor. You are always welcome to have a go at implementing it yourself and submitting a PR - no obligations to do so of course.
I think godot has alot of minor issues in small parts of the editor or engine that could be improved and if I don't bring them up or if they are shutdown they will probably never be fixed
I actually agree with the idea behind this proposal, but for different reasons.
The PopupMenu class is currently a mess both for maintenance and for usage.
It's currently ~1500 lines of code, with a lot of repetition, and it's exposing a lot of methods that only serves purpose for one specific type of menu options. This both makes maintenance hard and risky for maintainers, and make it so users have to search through a very heavy documentation for something so simple.
Internally, all the "options" or "menu items" are currently of the "Item" struct containing all the ressources and parameter any kind of menu item could ever need.
This means we need to manually handle in a dozen of places situations like "Is someone trying to open a submenu on a separator item?". It also means that adding a new item to a popup menu requires adding checks and rewriting a whole lot of things in PopupMenu, possibly adding something to the item struct itself, which makes it both a pain, and a risk of breaking things.
People usually just end up coding their own menu, using nodes, to bypass this limitation.
If someone wants to add custom items to a popup menu, like a command bar at the top of the popup menu or a collapsible header section of items, the realistic solution is for them to either hack the PopupMenu, or use a PopupPanel or a Popup to recreate the whole PopupMenu logic, create a custom UI using nodes, and then adding their own custom UI elements.
It's a lot of work, that wouldn't be necessary if PopupMenu handled the same way other UI elements are handled. You could just drop a new custom node in the menu and everything else would be handled for you.
Separating the menu item from the PopupMenu would highly simplify making custom or new menu types, as the menu items would be easily adaptable.
For example, if someone wants to create a radial menu that can be customized and reused by the team, they wouldn't have to code EVERYTHING again from scratch just to do so. They could create a radial menu which would simply take some "MenuItem" as children, which already would have all of their type specific properties, methods, and signal coded. This way, they could add separators, multistates, shortcuts, accelerators, etc., as they want, without having to recode anything, but their layout logic.
I do agree that having the menu options as "controls" would potentially add a lot of nodes with a relatively big overhead "just for menus", but I don't think that's actually much of a problem.
Godot's mentality is about making things easy to use before making them performant, and in this case, I think this would make it much more friendly to both engine devs and user, for a relatively small overhead in normal scenarios. If it really becomes a problem in a game or app with a few hundred UI nodes constantly in the scene tree, perhaps it should be the user's job to optimize it, either by rethinking their UI, or by manually drawing things in a simpler menu the way it's done right now.
Beside, if the impact of using "Controls" is really too big to be worth it, we could always just make the menu items something else with a lower memory overhead and leave the layout logic as a responsibility of the PopupMenu, just like it is right now.
Most helpful comment
I actually agree with the idea behind this proposal, but for different reasons.
First: Maintainability
The PopupMenu class is currently a mess both for maintenance and for usage.
It's currently ~1500 lines of code, with a lot of repetition, and it's exposing a lot of methods that only serves purpose for one specific type of menu options. This both makes maintenance hard and risky for maintainers, and make it so users have to search through a very heavy documentation for something so simple.
Internally, all the "options" or "menu items" are currently of the "Item" struct containing all the ressources and parameter any kind of menu item could ever need.
This means we need to manually handle in a dozen of places situations like "Is someone trying to open a submenu on a separator item?". It also means that adding a new item to a popup menu requires adding checks and rewriting a whole lot of things in PopupMenu, possibly adding something to the item struct itself, which makes it both a pain, and a risk of breaking things.
People usually just end up coding their own menu, using nodes, to bypass this limitation.
Second: Customization
If someone wants to add custom items to a popup menu, like a command bar at the top of the popup menu or a collapsible header section of items, the realistic solution is for them to either hack the PopupMenu, or use a PopupPanel or a Popup to recreate the whole PopupMenu logic, create a custom UI using nodes, and then adding their own custom UI elements.
It's a lot of work, that wouldn't be necessary if PopupMenu handled the same way other UI elements are handled. You could just drop a new custom node in the menu and everything else would be handled for you.
Third: Adaptability / Reusability
Separating the menu item from the PopupMenu would highly simplify making custom or new menu types, as the menu items would be easily adaptable.
For example, if someone wants to create a radial menu that can be customized and reused by the team, they wouldn't have to code EVERYTHING again from scratch just to do so. They could create a radial menu which would simply take some "MenuItem" as children, which already would have all of their type specific properties, methods, and signal coded. This way, they could add separators, multistates, shortcuts, accelerators, etc., as they want, without having to recode anything, but their layout logic.
I do agree that having the menu options as "controls" would potentially add a lot of nodes with a relatively big overhead "just for menus", but I don't think that's actually much of a problem.
Godot's mentality is about making things easy to use before making them performant, and in this case, I think this would make it much more friendly to both engine devs and user, for a relatively small overhead in normal scenarios. If it really becomes a problem in a game or app with a few hundred UI nodes constantly in the scene tree, perhaps it should be the user's job to optimize it, either by rethinking their UI, or by manually drawing things in a simpler menu the way it's done right now.
Beside, if the impact of using "Controls" is really too big to be worth it, we could always just make the menu items something else with a lower memory overhead and leave the layout logic as a responsibility of the PopupMenu, just like it is right now.