Plugins del inspector

El panel del inspector te permite crear widgets personalizados para editar propiedades a través de plugins. Esto puede ser beneficioso cuando se trabaja con tipos de datos y recursos personalizados, aunque también puedes utilizar esta función para cambiar los widgets del inspector para tipos integrados. Puedes diseñar controles personalizados para propiedades específicas, objetos completos e incluso controles separados asociados con tipos de datos particulares.

Esta guía explica cómo utilizar las clases EditorInspectorPlugin y EditorProperty para crear una interfaz personalizada para enteros (integers), reemplazando el comportamiento predeterminado con un botón que genera valores aleatorios entre 0 y 99.

../../../_images/inspector_plugin_example.png

El comportamiento predeterminado a la izquierda y el resultado final a la derecha.

Configurando su plugin

Crea un nuevo plugin vacío para comenzar.

Ver también

Consulta la guía Creando plugins para configurar tu nuevo plugin.

Supongamos que has llamado a tu carpeta de plugin my_inspector_plugin. Si es así, deberías obtener una nueva carpeta addons/my_inspector_plugin que contiene dos archivos: plugin.cfg y plugin.gd.

Como antes, plugin.gd es un script que extiende EditorPlugin y necesitas agregar nuevo código para sus métodos _enter_tree y _exit_tree. Para configurar tu plugin de inspector, debes cargar su script, luego crear y agregar la instancia llamando a add_inspector_plugin(). Si el plugin está deshabilitado, debes eliminar la instancia que agregaste llamando a remove_inspector_plugin().

Nota

Aquí estás cargando un script y no una escena empaquetada. Por lo tanto, deberías usar new() en lugar de instance().

# plugin.gd
tool
extends EditorPlugin

var plugin


func _enter_tree():
    plugin = preload("res://addons/my_inspector_plugin/MyInspectorPlugin.gd").new()
    add_inspector_plugin(plugin)


func _exit_tree():
    remove_inspector_plugin(plugin)

Interactuar con el inspector

Para interactuar con el panel del inspector, tu script MyInspectorPlugin.gd debe extender la clase EditorInspectorPlugin. Esta clase proporciona varios métodos virtuales que afectan cómo el inspector maneja las propiedades.

Para que tenga algún efecto, el script debe implementar el método can_handle(). Esta función es llamada para cada Object editado y debe devolver true si este plugin debe manejar el objeto o sus propiedades.

Nota

Esto incluye cualquier Resource adjunto al objeto.

Puedes implementar otros cuatro métodos para agregar controles al inspector en posiciones específicas. Los métodos parse_begin() y parse_end() se llaman solo una vez al inicio y al final del análisis para cada objeto, respectivamente. Pueden agregar controles en la parte superior o inferior del diseño del inspector llamando a add_custom_control().

Mientras el editor analiza el objeto, llama a los métodos parse_category() y parse_property(). En esos métodos, además de add_custom_control(), puedes llamar a add_property_editor() y add_property_editor_for_multiple_properties(). Utiliza estos dos últimos métodos para agregar específicamente controles basados en EditorProperty.

# MyInspectorPlugin.gd
extends EditorInspectorPlugin

var RandomIntEditor = preload("res://addons/my_inspector_plugin/RandomIntEditor.gd")


func can_handle(object):
    # We support all objects in this example.
    return true


func 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

Agregando una interfaz para editar propiedades

La clase EditorProperty es un tipo especial de Control que puede interactuar con los objetos editados del panel del inspector. No muestra nada en sí mismo, pero puede contener cualquier otro nodo de control, incluidas escenas complejas.

Hay tres partes esenciales en el script que extiende EditorProperty:

  1. Debes definir el método _init() para configurar la estructura de los nodos de control.

  2. Debes implementar el método update_property() para manejar los cambios en los datos desde el exterior.

  3. Se debe emitir una señal en algún momento para informar al inspector que el control ha cambiado la propiedad utilizando emit_changed.

Puedes mostrar tu widget personalizado de dos formas. Usa simplemente el método predeterminado add_child() para mostrarlo a la derecha del nombre de la propiedad, y utiliza add_child() seguido de set_bottom_editor() para posicionarlo debajo del nombre.

# RandomIntEditor.gd
extends 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 = false


func _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 = false

func refresh_control_text():
    property_control.text = "Value: " + str(current_value)

Usando el código de ejemplo anterior, deberías poder crear un widget personalizado que reemplace el control SpinBox predeterminado para enteros con un Button que genere valores aleatorios.