Closed Calinou closed 1 month ago
How would this get communicated to the Inspector? Would you need to add a new METHOD_FLAG_*
value to indicate to the Inspector that it should do that? Or are we going to add a proper get_annotations()
or get_member_metadata()
API for the Script
interface so that the Editor can make use of that info?
I just wanted to open an issue about it, and I'd go for:
@export
func action():
pass
or in Godot 3 GDScript:
export func action():
pass
It should look like any other export, and it should throw an error if the exported function has arguments, because we do not want to/can't deal with that on a button.
If the editor can get the name and type of variables, get the name of the function then treating it as a "function type" should be doable (imo). Or if it needs to be a variable then this option can also work:
@export
var action = func():
action_backend()
func action_backend():
pass
In this case, if we can detect that this lambda has any number of arguments, then it might just inject as is into the existing export system.
I have a few ideas for the implementation of this proposal and I made a concept for it.
Inspector buttons should have 3 customizable options: color, icon, and text.
"Add"
is interpreted as get_theme_icon("Add", "EditorIcons")
; "checked,CheckBox"
is interpreted as get_theme_icon("checked", "CheckBox")
).capitalize()
function yields unwanted results in some scenarios (ex. "Node 2d" instead of "Node2D").@export_func(color: Color or EditorInspectorPlugin.BUTTON_COLOR_*, icon: String, custom_text: String")
@export_func button
@export_func(EditorInspectorPlugin.BUTTON_COLOR_ACCENT) accent_color_button
@export_func(Color("3cba53"), "ListSelect", "Click Me!") function_name
@export_func(Color("fc1532"), "Remove") remove_item
@export_func(Color("ab4fc2"), "AnimationPlayer", "Add AnimationPlayer") add_animation_player
@export_func(EditorInspectorPlugin.BUTTON_COLOR_DEFAULT, "res://icon.png") custom_icon
I think this feature set would make inspector buttons highly customizable without making them too complex, since all of these settings are optional. Let me know if you have any suggestions or opinions on this :)
@fire-forge I think that level is the realm of an addon. The export itself should be as small and simple as possible.
Replacing an exported field with an arbitrary scene is already a feature of addons, applying it to an exported function should not be that difficult. Then you don't even have those limits that you'd impose to make it work as an annotation.
edit to the downvotes: I also wrote this as "this is what you could do until we have nothing else"
@Frontrider thanks for the feedback! I wasn't really sure what the scope this feature was, so I was just giving some suggestions for what I would do if I was working on this.
To anyone still interested in this coming in the future, the hacky way where you would create a button in the inspector for Godot 4 now uses this syntax:
@export var working_button: bool = false : set = run_code
func run_code(fake_bool = null):
#Do stuff
Essentially this just creates a setter for working_button
that throws away the value and instead runs your code.
So do the same as before :)
My idea for the syntax, if this gets implemented (with my use case):
@export_button("Bake Textures", "Bakes the mask, fill, and outline textures into a new texture.")
# @icon("res://bake_textures.svg") # optional
func bake():
# irrelevant
return OK # can return an error, which will be shown to the user
For the workaround, I usually prefer this syntax
@export var perform_action := false:
set(_value):
pass # ...
TIL how to highlight gdscript in Github. That workaround is fine; however, it doesn't result in a button that looks like a button.
TIL how to highlight gdscript in Github. That workaround is fine; however, it doesn't result in a button that looks like a button.
Yeah. But that is the best we have for now.
This is the key problem for this, that needs to be kept in mind. https://github.com/godotengine/godot/pull/59289#issuecomment-1204320618
How would parameters work?
How would parameters work?
There's no proposed way to supply parameters in this proposal, so you'd have to spawn a dialog that asks for a parameter yourself if you need that.
If you are interessted in a lightweight Godot addon that turns your bool button-like checkboxes into real buttons. Just in place. Without changing the code logic or having dependencies. Then you could try out my addon.
Just download the addon and enable it in your project settings. Prefix your bool exports with btn_
and enjoy your buttons. Reload the scene (Scene > Reload Saved Scene) if you see no buttons.
@export var btn_update: bool:
set(v): update()
func update():
print("Button pressed")
How it works: In Godot you can export a bool variable, which will appear as a checkbox in the inspector. Then define a setter that ignores the value and only calls a function. Since a checkbox is confusing when expecting a button, I developed this addon to replace it with a real button. It detects buttons by the variable name prefix, which still allows regular checkboxes.
I still use the bool checkbox button solution, because this is currently the native way to implement button-like behavior in Godot inspector. If this addon is not present, you can still use it as a fallback like before. No changes needed. It simply replaces the checkbox with the button appearance.
This addon just replaces the bool fake button with a real button. No more, no less. There is currently no option for color or icon for compatibility reasons. But I already have some ideas for implementation. Also you have to reload the scene as you might already know when crafting tools in Godot. Just go to Scene > Reload Saved Scene. Maybe I can improve this for upcoming versions. Checkout my addon repository or download it from Godot Asset Library:
Update v1.1.0: Now in Color! You can now use colors.
Update v1.2.0: Advanced Button! You can now use icons and more.
Update v1.3.0: You can now use multiple buttons in row.
See Godot Assets Library or my repository for more info and upcoming updates.
Why not simply
@export_tool_button
func my_function():
pass
Why the complexity?
Also looking in 4.4dev3; the following pattern doesn't seem to be stable:
@export_tool_button
var my_function = func():
pass
After project reload it works as expected, but change the code / add new tool buttons / etc., and it breaks until the next project reload.
Why the complexity?
In order to show a new element in the Inspector, we need to add a property, either explicitly or implicitly. The Inspector simply doesn't care about methods and they don't have hints/flags for that purpose. The original suggestion was to use a fake property, but this has conceptual and technical problems:
_get_property_list()
, but you can't dynamically dispatch calls (like _call()
), so the old approach didn't allow creating dynamic tool buttons, since you couldn't create a new method or pass an argument to differentiate between buttons._validate_property()
. The problem with a fake property is that you would need to know its internal name, which is generated implicitly (like @tool_button_{method_name}
).After project reload it works as expected, but change the code / add new tool buttons / etc., and it breaks until the next project reload.
Thanks for the bug report, this was already reported in the contributor chat. I have some guesses about the cause and fix for this bug, so I'll try to take a look.
Sorry, I'm not very familiar with this platform but I am unsure why this issue has been close. Has it been implemented into the engine? Is it only going to make it in 4.4? Has it been closed to due to there being an addon that does exactly this (Simple Tool Button by domske)?
I am trying to use @tool_button
it in v4.3.stable
and the error message I am getting is as follows:
Annotation "@tool_button" is not allowed in this level.
I have tried putting this piece of code before/after class_name
, @icon
, and extends
, and it never
worked:
@tool_button("Something")
func something():
print("something")
Am I doing something wrong or is this simply not out yet?
Edit: apparently the error that I am getting, "Annotation "@[something]
" is not allowed in this level" is also thrown when I put random scribblish as an annotation name.
@nanto2016 This is implemented for the upcoming 4.4, it doesn't exist in 4.3. As for the confusing error Annotation "%s" is not allowed in this level.
, we should first check if the annotation exists.
See https://github.com/godotengine/godot/issues/9380 for previous discussion.
Describe the project you are working on
The Godot editor :slightly_smiling_face:
Describe the problem or limitation you are having in your project
There's no officially recognized/documented way to export a clickable action to the inspector. Such actions can be useful to expose "one-off" things you may need to do when using a node. This can be useful to expose additional functionality without having to create an editor plugin.
There's a hack you can use that works with boolean exported properties, but it's not particularly user-friendly.
Describe the feature / enhancement and how it helps to overcome the problem or limitation
Add a way to export proper clickable buttons in the Inspector, without exporting dummy properties.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Add an annotation that exports a method as a clickable action in the inspector. Like for property names, the action's name is named automatically based on the method name. For instance:
This would result in a clickable "Bake All" button in the inspector.
If this enhancement will not be used often, can it be worked around with a few lines of script?
Yes (see above), but it's not particularly clean or user-friendly. A checkbox isn't an one-state button :slightly_smiling_face:
Is there a reason why this should be core and not an add-on in the asset library?
This is core editor functionality.