// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEngine.Utilities; namespace FlaxEditor.CustomEditors.Editors { /// /// Base implementation of the inspector used to edit properties of the given abstract or interface type that contain a setter to assign a derived implementation type. /// public abstract class ObjectSwitcherEditor : CustomEditor { /// /// Defines type that can be assigned to the modified property. /// public struct OptionType { /// /// The type name used to show in the type selector dropdown menu (for user interface). /// public string Name; /// /// The type. /// public Type Type; /// /// The creator function that spawns the object of the given type. /// public Func Creator; /// /// Initializes a new instance of the struct. /// /// The type. public OptionType(Type type) { Name = type.Name; Type = type; Creator = Activator.CreateInstance; } /// /// Initializes a new instance of the struct. /// /// The name. /// The type. public OptionType(string name, Type type) { Name = name; Type = type; Creator = Activator.CreateInstance; } /// /// Initializes a new instance of the struct. /// /// The name. /// The type. /// The instance creation function. public OptionType(string name, Type type, Func creator) { Name = name; Type = type; Creator = creator; } } /// /// Gets the options collection for the property value assignment. /// protected abstract OptionType[] Options { get; } /// /// Gets the name of the type ComboBox property name for the object type picking. /// protected virtual string TypeComboBoxName => "Type"; private OptionType[] _options; private ScriptType _type; private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]); /// public override void Initialize(LayoutElementsContainer layout) { // Get the target options _options = Options; if (_options == null) throw new ArgumentNullException(); int selectedIndex = -1; bool hasDifferentTypes = Values.HasDifferentTypes; var type = Type; _type = type; // Type var typeEditor = layout.ComboBox(TypeComboBoxName, "Type of the object value. Use it to change the object."); for (int i = 0; i < _options.Length; i++) { typeEditor.ComboBox.AddItem(_options[i].Name); selectedIndex = _options[i].Type == type.Type ? i : selectedIndex; } typeEditor.ComboBox.SupportMultiSelect = false; typeEditor.ComboBox.SelectedIndex = hasDifferentTypes ? -1 : selectedIndex; typeEditor.ComboBox.SelectedIndexChanged += OnSelectedIndexChanged; // Editing different types is not supported if (Values.HasDifferentTypes) { var property = layout.AddPropertyItem("Value"); property.Label("Different Values"); return; } // Nothing to edit if (Values.HasNull) { var property = layout.AddPropertyItem("Value"); property.Label(""); return; } // Value var values = new CustomValueContainer(type, (instance, index) => instance, (instance, index, value) => { }); values.AddRange(Values); var editor = CustomEditorsUtil.CreateEditor(type); var style = editor.Style; if (style == DisplayStyle.InlineIntoParent) { layout.Object(values, editor); } else if (style == DisplayStyle.Group) { var group = layout.Group("Value", true); group.Panel.Open(false); group.Object(values, editor); // Remove empty group if (group.ContainerControl.ChildrenCount == 0) { layout.Children.Remove(group); group.Panel.Dispose(); } } else { layout.AddPropertyItem("Value").Object(values, editor); } } private void OnSelectedIndexChanged(ComboBox comboBox) { object value = null; if (comboBox.SelectedIndex != -1) { var option = _options[comboBox.SelectedIndex]; if (option.Type != null) value = option.Creator(option.Type); } SetValue(value); RebuildLayoutOnRefresh(); } /// public override void Refresh() { base.Refresh(); // Check if type has been modified outside the editor (eg. from code) if (Type != _type) { if (ParentEditor != null) ParentEditor.RebuildLayout(); else RebuildLayout(); } } } }