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.