/
ObjectSwitcherEditor.cs
183 lines (162 loc) · 6.17 KB
/
ObjectSwitcherEditor.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEngine.Utilities;
namespace FlaxEditor.CustomEditors.Editors
{
/// <summary>
/// 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.
/// </summary>
public abstract class ObjectSwitcherEditor : CustomEditor
{
/// <summary>
/// Defines type that can be assigned to the modified property.
/// </summary>
public struct OptionType
{
/// <summary>
/// The type name used to show in the type selector dropdown menu (for user interface).
/// </summary>
public string Name;
/// <summary>
/// The type.
/// </summary>
public Type Type;
/// <summary>
/// The creator function that spawns the object of the given type.
/// </summary>
public Func<Type, object> Creator;
/// <summary>
/// Initializes a new instance of the <see cref="OptionType"/> struct.
/// </summary>
/// <param name="type">The type.</param>
public OptionType(Type type)
{
Name = type.Name;
Type = type;
Creator = Activator.CreateInstance;
}
/// <summary>
/// Initializes a new instance of the <see cref="OptionType"/> struct.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="type">The type.</param>
public OptionType(string name, Type type)
{
Name = name;
Type = type;
Creator = Activator.CreateInstance;
}
/// <summary>
/// Initializes a new instance of the <see cref="OptionType"/> struct.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="type">The type.</param>
/// <param name="creator">The instance creation function.</param>
public OptionType(string name, Type type, Func<Type, object> creator)
{
Name = name;
Type = type;
Creator = creator;
}
}
/// <summary>
/// Gets the options collection for the property value assignment.
/// </summary>
protected abstract OptionType[] Options { get; }
/// <summary>
/// Gets the name of the type ComboBox property name for the object type picking.
/// </summary>
protected virtual string TypeComboBoxName => "Type";
private OptionType[] _options;
private ScriptType _type;
private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
/// <inheritdoc />
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("<null>");
return;
}
// Value
var values = new CustomValueContainer(type, (instance, index) => instance);
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();
}
/// <inheritdoc />
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();
}
}
}
}