reckfellENGINE

Inspector: custom property and Undo/Redo

Replace one resource field while preserving correct data flow.

On this page

An Inspector plugin replaces the UI for a selected property, not the entire resource. This example handles only numeric DocsInspectorSettings.Amount; unrelated objects keep their standard Inspector.

Prepare the example

Create asset://addons/docs_inspector/. Save these four C# files and plugin.cfg there, build, and enable the addon. Create a DocsInspectorSettings resource and open it in Inspector. [GlobalClass] declares the resource type for the editor; all example classes run as tool code.

C#
using Reckfell;

[Tool, GlobalClass]
public partial class DocsInspectorSettings : Resource
{
    [Export(PropertyHint.Range, "0,100,0.5")]
    public double Amount { get; set; } = 2;
}
C#
using Reckfell;

[Tool]
public partial class AmountEditor : EditorProperty
{
    private readonly SpinBox _spin = new() { Name = "Value", MinValue = 0, MaxValue = 100, Step = 0.5 };
    private bool _readOnly;
    public AmountEditor()
    {
        Name = "DocsAmountEditor";
        AddChild(_spin); AddFocusable(_spin.GetLineEdit());
        _spin.ValueChanged += OnValueChanged;
    }
    private void OnValueChanged(double value)
    {
        if (!_readOnly) EmitChanged(GetEditedProperty(), value);
    }
    public override void _UpdateProperty()
    {
        var edited = GetEditedObject();
        if (edited is not null) _spin.SetValueNoSignal(edited.Get(GetEditedProperty()).AsDouble());
    }
    public override void _SetReadOnly(bool readOnly)
    {
        _readOnly = readOnly; _spin.Editable = !readOnly;
    }
}
C#
using Reckfell;

[Tool]
public partial class AmountInspector : EditorInspectorPlugin
{
    public override bool _CanHandle(ReckfellObject @object) => @object is DocsInspectorSettings;
    public override bool _ParseProperty(ReckfellObject @object, Variant.Type type, string name,
        PropertyHint hintType, string hintString, PropertyUsageFlags usageFlags, bool wide)
    {
        if (type != Variant.Type.Float || name != "Amount") return false;
        AddPropertyEditor(name, new AmountEditor(), false, "Amount");
        return true;
    }
}
C#
using Reckfell;

[Tool]
public partial class DocsInspectorPlugin : EditorPlugin
{
    private AmountInspector? _inspector;
    public override void _EnterTree()
    {
        _inspector = new AmountInspector(); AddInspectorPlugin(_inspector);
    }
    public override void _ExitTree()
    {
        if (_inspector is null) return;
        RemoveInspectorPlugin(_inspector);
        var mainInspector = EditorInterface.Singleton.GetInspector();
        var edited = mainInspector.GetEditedObject();
        if (edited is DocsInspectorSettings)
        {
            mainInspector.Edit(null!); mainInspector.Edit(edited);
        }
        _inspector.Dispose(); _inspector = null;
    }
}
Configuration
[plugin]
name="Docs amount inspector"
description="Custom numeric editor for DocsInspectorSettings"
author="Reckfell documentation"
version="1.0.0"
script="DocsInspectorPlugin.cs"

AmountInspector restricts _CanHandle() to one class and _ParseProperty() to one name/type. Returning true means the property was handled and does not need its standard editor. False preserves ordinary processing. Do not return true for every property merely because a widget was created.

Two directions of data flow

On input, AmountEditor calls EmitChanged(GetEditedProperty(), value). Inspector receives the edit and routes it through editor mechanisms, including Undo/Redo. Directly assigning settings.Amount inside the handler does not replace that path.

On refresh, _UpdateProperty() reads the resource's current value and updates the widget through SetValueNoSignal(). This is not user input: emitting another change would create update loops and unwanted undo actions. _SetReadOnly() separately disables input and guards the handler.

The check changed initial 2 to 5.5; Undo restored 2 and Redo restored 5.5. An external assignment of 7.5 followed by refresh emitted no change. This verifies the refresh contract, not instant UI updates without waiting for editor processing.

PropertyHint.Range and SpinBox configure the editing range. The resource's automatic property does not validate arbitrary external assignments. Add model validation if the game needs a strict invariant.

Cleanup and reenablement

EditorInspectorPlugin is ref-counted: unregister with RemoveInspectorPlugin(), then release your reference with Dispose(). Do not use the Entity operation QueueFree() on it.

On disable, the example rebuilds the main Inspector if it displays this resource, removing the old custom EditorProperty. Reenablement should not leave two fields. If an object was already selected when registering the addon, reselect it to reparse properties.

A custom widget handed to Inspector belongs to its UI. Do not free an active property editor from a SpinBox handler. Separate floating Inspectors are outside this example and require additional checks.

Checks covered property binding, a single change, Undo/Redo, signal-free refresh, read-only handling, disable/reenable, and unrelated-Resource refusal. Physical input, appearance, resource save/reload, floating Inspectors, and exports were not tested.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.