Inspector plugins

The inspector dock allows you to create custom widgets to edit properties through plugins. This can be beneficial when working with custom datatypes and resources, although you can use the feature to change the inspector widgets for built-in types. You can design custom controls for specific properties, entire objects, and even separate controls associated with particular datatypes. EditorInspectorPlugin and EditorProperty classes to create a custom interface for integers, replacing the default behavior with a button that generates random values between 0 and 99. The default behavior on the left and the end result on the right.

Setting up your plugin

Create a new empty plugin to get started. See also Making plugins guide to set up your new plugin. my_inspector_plugin. If so, you should end up with a new addons/my_inspector_plugin folder that contains two files: plugin.cfg and plugin.gd. plugin.gd is a script extending EditorPlugin and you need to introduce new code for its _enter_tree and _exit_tree methods. To set up your inspector plugin, you must load its script, then create and add the instance by calling add_inspector_plugin(). If the plugin is disabled, you should remove the instance you have added by calling remove_inspector_plugin(). Note new() instead of instance(). GDScript C#

  1. # plugin.gdtoolextends EditorPluginvar pluginfunc _enter_tree(): plugin = preload("res://addons/my_inspector_plugin/MyInspectorPlugin.gd").new() add_inspector_plugin(plugin)func _exit_tree(): remove_inspector_plugin(plugin)
  1. // Plugin.cs#if TOOLSusing Godot;[Tool]public class Plugin : EditorPlugin{ private MyInspectorPlugin _plugin; public override void _EnterTree() { _plugin = new MyInspectorPlugin(); AddInspectorPlugin(_plugin); } public override void _ExitTree() { RemoveInspectorPlugin(_plugin); }}#endif

Interacting with the inspector

MyInspectorPlugin.gd script must extend the EditorInspectorPlugin class. This class provides several virtual methods that affect how the inspector handles properties. can_handle() method. This function is called for each edited Object and must return true if this plugin should handle the object or its properties. Note Resource attached to the object. parse_begin() and parse_end() methods are called only once at the beginning and the end of parsing for each object, respectively. They can add controls at the top or bottom of the inspector layout by calling add_custom_control(). parse_category() and parse_property() methods. There, in addition to add_custom_control(), you can call both add_property_editor() and add_property_editor_for_multiple_properties(). Use these last two methods to specifically add EditorProperty-based controls. GDScript C#

  1. # MyInspectorPlugin.gdextends EditorInspectorPluginvar RandomIntEditor = preload("res://addons/my_inspector_plugin/RandomIntEditor.gd")func can_handle(object): # We support all objects in this example. return truefunc parse_property(object, type, path, hint, hint_text, usage): # We handle properties of type integer. if type == TYPE_INT: # Create an instance of the custom property editor and register # it to a specific property path. add_property_editor(path, RandomIntEditor.new()) # Inform the editor to remove the default property editor for # this property type. return true else: return false
  1. // MyInspectorPlugin.cs#if TOOLSusing Godot;public class MyInspectorPlugin : EditorInspectorPlugin{ public override bool CanHandle(Object @object) { // We support all objects in this example. return true; } public override bool ParseProperty(Object @object, int type, string path, int hint, string hintText, int usage) { // We handle properties of type integer. if (type == (int)Variant.Type.Int) { // Create an instance of the custom property editor and register // it to a specific property path. AddPropertyEditor(path, new RandomIntEditor()); // Inform the editor to remove the default property editor for // this property type. return true; } return false; }}#endif

Adding an interface to edit properties

EditorProperty class is a special type of Control that can interact with the inspector dock’s edited objects. It doesn’t display anything but can house any other control nodes, including complex scenes. EditorProperty:

  1. _init() method to set up the control nodes’ structure.
  2. update_property() to handle changes to the data from the outside.
  3. emit_changed. add_child() method to display it to the right of the property name, and use add_child() followed by set_bottom_editor() to position it below the name. GDScript C#
    1. # RandomIntEditor.gdextends EditorProperty# The main control for editing the property.var property_control = Button.new()# An internal value of the property.var current_value = 0# A guard against internal changes when the property is updated.var updating = falsefunc _init(): # Add the control as a direct child of EditorProperty node. add_child(property_control) # Make sure the control is able to retain the focus. add_focusable(property_control) # Setup the initial state and connect to the signal to track changes. refresh_control_text() property_control.connect("pressed", self, "_on_button_pressed")func _on_button_pressed(): # Ignore the signal if the property is currently being updated. if (updating): return # Generate a new random integer between 0 and 99. current_value = randi() % 100 refresh_control_text() emit_changed(get_edited_property(), current_value)func update_property(): # Read the current value from the property. var new_value = get_edited_object()[get_edited_property()] if (new_value == current_value): return # Update the control with the new value. updating = true current_value = new_value refresh_control_text() updating = falsefunc refresh_control_text(): property_control.text = "Value: " + str(current_value)
    1. // RandomIntEditor.cs#if TOOLSusing Godot;public class RandomIntEditor : EditorProperty{ // The main control for editing the property. private Button _propertyControl = new Button(); // An internal value of the property. private int _currentValue = 0; // A guard against internal changes when the property is updated. private bool _updating = false; public RandomIntEditor() { // Add the control as a direct child of EditorProperty node. AddChild(_propertyControl); // Make sure the control is able to retain the focus. AddFocusable(_propertyControl); // Setup the initial state and connect to the signal to track changes. RefreshControlText(); _propertyControl.Connect("pressed", this, nameof(OnButtonPressed)); } private void OnButtonPressed() { // Ignore the signal if the property is currently being updated. if (_updating) { return; } // Generate a new random integer between 0 and 99. _currentValue = (int)GD.Randi() % 100; RefreshControlText(); EmitChanged(GetEditedProperty(), _currentValue); } public override void UpdateProperty() { // Read the current value from the property. var newValue = (int)GetEditedObject().Get(GetEditedProperty()); if (newValue == _currentValue) { return; } // Update the control with the new value. _updating = true; _currentValue = newValue; RefreshControlText(); _updating = false; } private void RefreshControlText() { _propertyControl.Text = $"Value: {_currentValue}"; }}#endif
    SpinBox control for integers with a Button that generates random values.