Property Editors

The editor uses Inspector widget to show the contents of your scripts and when you're using custom structures inside your scripts the editor needs to know how to show them in the UI. Inspector widget has a special mechanism for this called property editors. Basically, it defines a pair TypeId -> Widget - a type has an associated widget that is responsible for showing the content of the type and (optionally) edit it. If there's no widget associated with a type, the editor will print an error message near this field, basically telling you that you need to fix this.

Adding Property Editors

The engine has property editors for pretty much every case, all you need to do is to associate your type with one of them. The following sections covers the most common use cases, each of them should be added to editor/src/main.rs file, after editor's initialization.

Structures

This is the most common case when you need to associate your type with a property editor, and in this case the property editor will be InspectablePropertyEditorDefinition:

#![allow(unused)]
fn main() {
#[derive(Reflect, Debug)]
struct MyStruct {
    foo: u32,
    bar: String,
}

fn add_property_editor(editor: &Editor) {
    editor
        .inspector
        .property_editors
        .insert(InspectablePropertyEditorDefinition::<MyStruct>::new());
}
}

Keep in mind, that your structure must implement Reflect trait, otherwise you'll get a compilation error.

Enumerations

Enumerations are a bit trickier to support, than simple structures, because they require a bit more traits to be implemented for your enumeration. At first, make sure that your editor project has the following dependencies:

#[dependencies]
strum = "0.26.0"
strum_macros = "0.26.0"

These two crates responsible for enum to string (and vice versa) conversions which will be very useful for us. The following example shows a typical usage:

#![allow(unused)]
fn main() {
#[derive(Reflect, Default, Debug, AsRefStr, EnumString, VariantNames, TypeUuidProvider, Clone)]
#[type_uuid(id = "31311d8b-f956-4ae9-a633-1e45b755f322")]
enum MyEnum {
    #[default]
    Baz,
    Foo(u32),
    Bar {
        baz: String,
        foobar: u32,
    },
}

fn add_enum_property_editor(editor: &Editor) {
    editor
        .inspector
        .property_editors
        .insert(EnumPropertyEditorDefinition::<MyEnum>::new());
}
}

As you can see, your enumeration needs a decent number of trait implementations, hopefully all of them can be derived.

Inheritable Properties

If your structure or enumeration needs to be inheritable (see more info about property inheritance), then you need one more step. In case of inheritable variables, your fields will be wrapped in InheritableVariable<> and this fact requires you to register an appropriate property editor for this:

#![allow(unused)]
fn main() {
#[derive(Reflect, Debug, TypeUuidProvider, Default, Clone)]
#[type_uuid(id = "31311d8b-f956-4ae9-a633-1e45b755f323")]
struct MyOtherStruct {
    foo: u32,
    bar: String,
}

// An example script with inheritable field of custom structure.
struct MyScript {
    inheritable: InheritableVariable<MyOtherStruct>,
}

fn add_inheritable_property_editor(editor: &Editor) {
    editor
        .inspector
        .property_editors
        .insert(InspectablePropertyEditorDefinition::<MyOtherStruct>::new());

    // This is responsible for supporting inheritable properties in scripts.
    editor
        .inspector
        .property_editors
        .insert(InheritablePropertyEditorDefinition::<MyOtherStruct>::new());

    // Alternatively, the two previous insertions could be replaced by a single call of helper
    // method:
    editor
        .inspector
        .property_editors
        .register_inheritable_inspectable::<MyStruct>();
}
}

Collections

If you have a vector of some custom structure (Vec<MyStruct>), then you also need to register a property editor for it:

#![allow(unused)]

fn main() {
// An example script with Vec field of custom structure.
struct MyOtherScript {
    inheritable: Vec<MyOtherStruct>,
}

fn add_collection_property_editor(editor: &Editor) {
    editor
        .inspector
        .property_editors
        .insert(InspectablePropertyEditorDefinition::<MyOtherStruct>::new());

    // VecCollectionPropertyEditorDefinition is used to create a property editor for Vec<MyStruct>,
    // internally it uses a registered property editor for its generic argument (MyStruct).
    editor
        .inspector
        .property_editors
        .insert(VecCollectionPropertyEditorDefinition::<MyOtherStruct>::new());

    // Alternatively, you can use a special helper method to replace the two blocks above by a
    // single one.
    editor
        .inspector
        .property_editors
        .register_inheritable_vec_collection::<MyOtherStruct>();
}
}

Custom Property Editors

See Inspector widget chapter to learn how to create custom property editors.