Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @tool_button annotation for easily creating inspector buttons. #59289

Closed

Conversation

jordi-star
Copy link
Contributor

@jordi-star jordi-star commented Mar 18, 2022

Closes godotengine/godot-proposals#2149

Adds an function annotation that allows you to add clickable actions to the inspector view of a script.
The script must be a tool script and the function must accept the EditorUndoRedoManager as a parameter.

Usage:

@tool
extends Sprite2D

@export var randomize_alpha = false;
# Args are name and icon name, icon is optional.
# Tool button methods must allow for an EditorUndoRedoManager to be passed to it, 
# but static typing is optional.
@tool_button("Randomize Color", "ColorRect")
func rand_col(history):
	var random_color = Color(randf_range(0, 1.0), randf_range(0, 1.0), randf_range(0, 1.0));
	if randomize_alpha:
		random_color.a = randf_range(0, 1.0);
	history.create_action("Randomize Color");
	history.add_do_property(self, "modulate", random_color);
	history.add_undo_property(self, "modulate", modulate);
	history.commit_action();

image

Another example, where you press a button to add a new enemy to your scene at a random position:

@tool
extends Node2D

@export var max_distance = 500.0;

@tool_button("Add enemy at random spot", "Skeleton2D")
func add_enemy(history:EditorUndoRedoManager):
	var enemy = load('res://Enemy.tscn').instantiate();
	var random_pos = Vector2(randf_range(-max_distance, max_distance), randf_range(-max_distance, max_distance));
	history.create_action("Add Enemy");
	history.add_do_method(self, "add_child", enemy);
	history.add_do_property(enemy, "owner", self);
	history.add_do_property(enemy, "name", "Scary Enemy");
	history.add_do_property(enemy, "position", random_pos);
	history.add_do_reference(enemy);
	history.add_undo_method(enemy, "queue_free");
	history.commit_action();
Screen.Recording.2023-04-27.at.6.05.01.AM.mov

@Calinou
Copy link
Member

Calinou commented Mar 18, 2022

This looks great, amazing work!

What do you think about adding an optional parameter to @export_action() to allow specifying an editor icon name (or a custom res:// path)? This would allow for easier visual grepping for nodes that have many exported actions: godotengine/godot-proposals#2149 (comment)

The editor icon names would refer to one of the icons located in https://github.com/godotengine/godot/tree/master/editor/icons, and they wouldn't have any res:// prefix or file extension.

@jordi-star
Copy link
Contributor Author

This looks great, amazing work!

What do you think about adding an optional parameter to @export_action() to allow specifying an editor icon name (or a custom res:// path)? This would allow for easier visual grepping for nodes that have many exported actions: godotengine/godot-proposals#2149 (comment)

The editor icon names would refer to one of the icons located in https://github.com/godotengine/godot/tree/master/editor/icons, and they wouldn't have any res:// prefix or file extension.

Sure, I can work on that.

@jordi-star jordi-star force-pushed the export_action_callable branch 2 times, most recently from 5caa0a3 to e2fc2e1 Compare March 18, 2022 19:56
@jordi-star
Copy link
Contributor Author

jordi-star commented Mar 18, 2022

This looks great, amazing work!

What do you think about adding an optional parameter to @export_action() to allow specifying an editor icon name (or a custom res:// path)? This would allow for easier visual grepping for nodes that have many exported actions: godotengine/godot-proposals#2149 (comment)

The editor icon names would refer to one of the icons located in https://github.com/godotengine/godot/tree/master/editor/icons, and they wouldn't have any res:// prefix or file extension.

Added! 👍

@export_action('Add') var add:Callable = add_nums;
@export_action('Camera2D') var recenter_camera = func():
	pass
@export_action var no_icon = func():
	pass

image

@jordi-star jordi-star force-pushed the export_action_callable branch 4 times, most recently from 3561d88 to 89cb9d3 Compare March 19, 2022 02:21
@jordi-star
Copy link
Contributor Author

All checks should be passing now.

editor/plugins/inspector_callable_editor_plugin.cpp Outdated Show resolved Hide resolved
editor/editor_node.cpp Outdated Show resolved Hide resolved
editor/plugins/inspector_callable_editor_plugin.cpp Outdated Show resolved Hide resolved
modules/gdscript/gdscript_parser.cpp Outdated Show resolved Hide resolved
@KoBeWi
Copy link
Member

KoBeWi commented Apr 27, 2023

Tested the new implementation and it works correctly.
One note though - using EditorUndoRedoManager as argument type will break the script when the project is exported, because the class is editor-only. We should warn about it in the documentation and maybe discourage using type hint in this case.

EDIT:
btw you need to run doctool and fill the description of the new annotation.

@KoBeWi

This comment was marked as resolved.

@@ -106,6 +106,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>);
register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray(""));
register_annotation(MethodInfo("@export_subgroup", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_SUBGROUP>, varray(""));
register_annotation(MethodInfo("@tool_button", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "icon")), AnnotationInfo::FUNCTION, &GDScriptParser::tool_button_annotation, varray("", ""), true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still specifying default arguments.
If you don't want any, use varray().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the default arguments, I've noticed that it's erroring that I only have 1 argument instead of the 2 required. Is there any way to fix that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, it should be varray(""), to make the icon optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, I'll get on that and finishing up the rest of the problems listed in a bit. I do want to note that to fix the EditorUndoRedoManager issue, I've changed the tool buttons to instead pass the relevant UndoRedo for that object. If there's a better solution, I'd gladly implement it.

@akien-mga akien-mga changed the title Add @export_action annotation for clickable actions in inspector. Add @tool_button annotation for easily creating inspector buttons. Apr 27, 2023
@KoBeWi
Copy link
Member

KoBeWi commented Apr 27, 2023

I see you replaced UndoRedo with EditorUndoRedoManager in response to my comment. Unfortunately it won't work, because all actions should go through EditorUndoRedoManager.

@jordi-star
Copy link
Contributor Author

I see you replaced UndoRedo with EditorUndoRedoManager in response to my comment. Unfortunately it won't work, because all actions should go through EditorUndoRedoManager.

Gotcha, I'll see what I can do.

@YuriSizov YuriSizov modified the milestones: 4.1, 4.2 Jun 12, 2023
@fire
Copy link
Member

fire commented Jun 17, 2023

I would like this, will see how I can get this ready for 4.2

@akien-mga
Copy link
Member

Superseded by #78355. Thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a way to export clickable actions to the inspector