How can I use Godot's built-in property editors?

Godot Version

4.2.1.stable.mono

Question

Hi, I’m making an inspector plugin which implies replacing property editors of some Godot collections. I also want the elements (such as Vectors, Ints, Strings etc) in the collection custom editor to be editable from the inspector like on this screenshot:

I want to somehow instantiate or create those editors.
How can I do that (may be via GDExtension or a module)?

I’ll be greatfull for any help.

1 Like

Hey @inaunius!

Just started fiddling with this in Godot, so I’m very much a noob, but it is entirely possible!

(Before I start, disclaimer: I’m actually using Godot 4.3.stable. I cannot vouch for the differences as of 4.2… sorry.)

You have to use EditorInspectorPlugin:

  • Write a script extending EditorPlugin
  • Write a script extending EditorInspectorPlugin
  • Instantiate the EditorInspectorPlugin
  • Add the instance to the EditorPlugin via add_inspector_plugin() (and remove it via remove_inspector_plugin() on _exit_tree)

e.g., In your EditorPlugin gd script:

@tool
extends EditorPlugin

# ...
var inspector_plugin: EditorInspectorPlugin = null
# ...

func _enter_tree() -> void:
    # self passed here explained later:
    inspector_plugin = CustomInspectorPlugin.new(self)
    add_inspector_plugin(inspector_plugin)
    # ... other setup

func _exit_tree() -> void:
    remove_inspector_plugin(inspector_plugin)
    # ... other cleanup

Then, in CustomInspectorPlugin, you can:

  • Capture the EditorPlugin via _init()
  • Target certain (or all) node types to override properties for via _can_handle
  • Target specific properties to provide custom editor interface controls for via _parse_property
  • (Also check out _parse_begin / _parse_end / _parse_category / _parse_group to target specific groups / sections of the inspector)

This can look like,

@tool
extends EditorInspectorPlugin

var plugin:EditorPlugin = null

func _init(plugin) -> void:
    # constructor
    self.plugin = plugin

func _can_handle(object:Object) -> bool:
    # target a certain node type to modify properties for
    # e.g., to modify properties of Node3D...
    # return object is Node3D
    # since it's a function, you can get as complex as needed
    
    return object is MyCustomNodeType

func _parse_property(
    object:Object,  # the node being targeted
    type:Variant.Type,  # the type of the property
    name:String,  # the name of this property
    hint:PropertyHint,  # the property export hint
    hint_text:String,  # text passed to the export hint
    usage:int,  # usage flags; e.g., if the property is hidden
    wide:bool  # no idea.. very new - may not be in v4.2
) -> bool:
    # called for each property of the targeted nodes

    # overrides the 'special_property' inspector control with a textbox and a button
    if name != "special_property": return false
    
    var hbox = HBoxContainer.new()
    var label = Label.new()
    var text = LineEdit.new()
    var button = Button.new()
    
    hbox.add_child(label)
    hbox.add_child(text)
    hbox.add_child(button)
    
    label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
    label.text = "Special Property"
    
    text.size_flags_horizontal = Control.SIZE_EXPAND_FILL
    
    button.text = "Button"
    button.pressed.connect(_on_save.bind(object))
    
    add_property_editor(name, hbox)
    
    return true

It can get pretty complex, but hopefully this is enough to get you started! … Also, it’s basically all I know at this point :slight_smile: … If you have a more specific question, maybe someone else could chime in. Or you could just check out the docs related to these classes / functions.

Good luck! :wink: