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

Expose EditorInspector::get_edited_object to GDScript #81425

Merged

Conversation

Rubonnek
Copy link
Member

@Rubonnek Rubonnek commented Sep 7, 2023

I'm making an EditorPlugin for a Resource subclass and while it's possible to extract what property has been modified to using the property_edited signal, the plugin needs to know what the new value of the property is in order to set some internal flags. Exposing EditorInspector::get_edited_object allows the EditorPlugin to query the value of the property with Object.get(property) within a property_edited callback.

Production edit: Closes godotengine/godot-proposals#7789

@Rubonnek Rubonnek requested a review from a team as a code owner September 7, 2023 16:51
@AThousandShips AThousandShips added this to the 4.x milestone Sep 7, 2023
@akien-mga akien-mga requested a review from YuriSizov September 8, 2023 07:27
@akien-mga akien-mga changed the title Expose EditorInspector::get_edited_object to GDScript Expose EditorInspector::get_edited_object to GDScript Sep 8, 2023
@YuriSizov
Copy link
Contributor

Can you provide an example of how it would be used?

@Rubonnek
Copy link
Member Author

Rubonnek commented Sep 8, 2023

Can you provide an example of how it would be used?

My use case is detecting when the user changes an exported Resource to a custom type my plugin can handle. I need the object whose property_edited signal was called for in order to enable/disable the custom editor for that resource.

This is the snippet of code where I'm using EditorInspector::get_edited_object in a 3.x build:

func __on_godot_editor_inspector_property_edited(_p_property : String) -> void:
	var edited_object : Object = m_editor_inspector.get_edited_object()
	if editor_plugin_handles(edited_object):
		editor_plugin_edit(edited_object)
		editor_plugin_make_visible(true)
	else:
		# We cannot handle the current object. Disable the BehaviorTreeEditor.
		editor_plugin_make_visible(false)

In the snippet of code above the custom type my plugin can handle is a stateless BehaviorTree of base type Resource. Since any object can have multiple exported resources, I'm making it so that:

  1. When the user has multiple BehaviorTree resources under the same object, the BehaviorTreeEditor shows up and hints the user to select an object in the Inspector to edit it.
  2. If the new value for the property edited is BehaviorTree and is the only BehaviorTree associated with that object, show the BehaviorTreeEditor.
  3. If the new value for the property edited is null, and there's no other BehaviorTree associated with the object, disable the BehaviorTreeEditor.

I'm probably missing another practical few use cases for EditorInspector::get_edited_object, but that's the gist of it.

I suppose property_edited could instead provide the Object as well but since both 3.x and `master are considered stable, that would break backwards compatibility unless we add a new signal. I haven't found another way to get the object getting edited by the Inspector.

@YuriSizov
Copy link
Contributor

I haven't found another way to get the object getting edited by the Inspector.

You can get the same object reference from EditorProperty::get_edited_object, but I'm not sure from your example if it would be convenient.

@fire
Copy link
Member

fire commented Sep 21, 2023

What is pending on this?

@AnidemDex
Copy link

My use case is detecting when the user changes an exported Resource to a custom type my plugin can handle. I need the object whose property_edited signal was called for in order to enable/disable the custom editor for that resource.

@tool
extends EditorInspectorPlugin

var plugin:EditorPlugin # assigned by the plugin itself on creation

func _parse_property(object: Object, type: Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: PropertyUsageFlags, wide: bool) -> bool:
  if not(object is BehaviorTree): return false # Handle your object type, I guess plugin.editor_plugin_handles() works too
  
  plugin.editor_plugin_edit(edited_object)
  plugin.editor_plugin_make_visible(true) # hope none of these calls EditorInterface.edit
  
  return true # Is your object type, but you should return false if you don't want to override editor default node
  

What would be the difference between listening for property_edited signal and getting the edited object (which can be "cached" when _handles is called on plugin) and directly handling the property if has your custom type?

@Rubonnek
Copy link
Member Author

What would be the difference between listening for property_edited signal and getting the edited object (which can be "cached" when _handles is called on plugin) and directly handling the property if has your custom type?

The object passed through _handles is not the same as EditorInspector::get_edited_object() when called within a property_edited callback, and therefore it's not possible to store a reference to it through the _handles function. Unless the user clicks on the resource itself in Inspector, _handles will not be called with that resource as a parameter. Which brings me to the three usage examples I explained above.

I'm not sure how your script solves the issue I've explained. Any object could have an exported resource set to null by default, meaning that I won't be able to detect nor cache the instance of the custom resource I'm expecting. Also, _parse_property is not called again when the user updates the exported resource.

@RadiantUwU

This comment was marked as off-topic.

@AThousandShips
Copy link
Member

AThousandShips commented Sep 21, 2023

@RadiantUwU Please don't bump PRs without contributing significant new information. Use the 👍 reaction button on the first post instead.

@RadiantUwU
Copy link
Contributor

UPDATE: There is now a valid workaround for godot 4.1+

@tool
extends EditorPlugin

var currently_selected_objects:Array[Object]
var resource_sel:=false

func _edited_object_changed():
	if resource_sel:
		resource_sel = false
	else:
		currently_selected_objects.clear()
		currently_selected_objects.append_array(get_editor_interface().get_selection().get_selected_nodes())
	print(currently_selected_objects)
func _select_resource(resource: Resource):
	currently_selected_objects.clear()
	currently_selected_objects.append(resource)
	resource_sel = true
func _property_edited():
	print(currently_selected_objects,get_editor_interface().get_inspector().get_selected_path(),currently_selected_objects[0].get_indexed(get_editor_interface().get_inspector().get_selected_path()))

func _enter_tree():
	# Initialization of the plugin goes here.
	get_editor_interface().get_inspector().property_edited.connect(_property_edited)
	get_editor_interface().get_inspector().resource_selected.connect(_select_resource)
	get_editor_interface().get_inspector().edited_object_changed.connect(_edited_object_changed,CONNECT_DEFERRED)

func _exit_tree():
	# Clean-up of the plugin goes here.
	get_editor_interface().get_inspector().property_edited.disconnect(_property_edited)
	get_editor_interface().get_inspector().resource_selected.disconnect(_select_resource)
	get_editor_interface().get_inspector().edited_object_changed.disconnect(_edited_object_changed)

@RadiantUwU
Copy link
Contributor

Nevermind, works only on nodes

@YuriSizov YuriSizov modified the milestones: 4.x, 4.2 Sep 23, 2023
Copy link
Contributor

@YuriSizov YuriSizov left a comment

Choose a reason for hiding this comment

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

Aside from the doc correction, this should be okay as it only exposes a method.

@Rubonnek Rubonnek force-pushed the expose-inspector-methods-master branch from 8742b1e to c844988 Compare September 23, 2023 13:47
@akien-mga akien-mga merged commit 684effb into godotengine:master Sep 24, 2023
15 checks passed
@akien-mga
Copy link
Member

Thanks!

@Rubonnek Rubonnek deleted the expose-inspector-methods-master branch September 25, 2023 12:08
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.

Implementation of EditorInspector.get_edited_object
7 participants