private static void DrawUrdfJointData <T>(AGXUnity.IO.URDF.UJoint parent, MemberInfo member, T jointData) where T : struct { var fieldsAndProperties = InvokeWrapper.FindFieldsAndProperties(typeof(T)); var enabledFieldOrProperty = fieldsAndProperties.FirstOrDefault(wrapper => wrapper.Member.Name == "Enabled"); if (enabledFieldOrProperty == null) { return; } var enabled = enabledFieldOrProperty.Get <bool>(jointData); using (new GUI.EnabledBlock(enabled)) { if (!InspectorGUI.Foldout(GetEditorData(parent, member.Name), InspectorGUI.MakeLabel(member))) { return; } using (InspectorGUI.IndentScope.Single) { foreach (var wrapper in fieldsAndProperties) { if (wrapper == enabledFieldOrProperty) { continue; } var drawer = GetDrawerMethod(wrapper.GetContainingType()); drawer.Drawer?.Invoke(null, new object[] { new object[] { jointData }, wrapper }); } } } }
public static object UrdfJointCalibrationDrawer(object[] objects, InvokeWrapper wrapper) { DrawUrdfJointData(objects[0] as AGXUnity.IO.URDF.UJoint, wrapper.Member, wrapper.Get <AGXUnity.IO.URDF.UJoint.CalibrationData>(objects[0])); return(null); }
public static object UrdfJointSafetyControllerDrawer(object[] objects, InvokeWrapper wrapper) { DrawUrdfJointData(objects[0] as AGXUnity.IO.URDF.UJoint, wrapper.Member, wrapper.Get <AGXUnity.IO.URDF.UJoint.SafetyControllerData>(objects[0])); return(null); }
public static object ScriptDrawer(object[] objects, InvokeWrapper wrapper) { object result = null; var type = wrapper.GetContainingType(); bool allowSceneObject = type == typeof(GameObject) || typeof(ScriptComponent).IsAssignableFrom(type); Object valInField = wrapper.Get <Object>(objects[0]); bool recursiveEditing = wrapper.HasAttribute <AllowRecursiveEditing>(); if (recursiveEditing) { result = InspectorGUI.FoldoutObjectField(InspectorGUI.MakeLabel(wrapper.Member), valInField, type, EditorData.Instance.GetData(objects[0] as Object, wrapper.Member.Name), !wrapper.CanWrite()); } else { result = EditorGUILayout.ObjectField(InspectorGUI.MakeLabel(wrapper.Member), valInField, type, allowSceneObject); } return(result); }
/// <summary> /// Draw supported member GUI for given targets. This method supports /// non-UnityEngine.Object instances, such as pure Serializable classes, /// that are part of <paramref name="targets"/>. <paramref name="getChildCallback"/> /// is called to access these serializable objects. If <paramref name="getChildCallback"/> /// is null, targets will be rendered. /// </summary> /// <param name="targets">Target UnityEngine.Object instances (used for Undo and SetDirty).</param> /// <param name="getChildCallback">Null and targets will be rendered, otherwise the returned /// instance from this callback.</param> public static void DrawMembersGUI(Object[] targets, Func <Object, object> getChildCallback = null, SerializedObject fallback = null) { targets = targets.Where(obj => obj != null).ToArray(); if (targets.Length == 0) { return; } var objects = targets.Select(target => getChildCallback == null ? target : getChildCallback(target)) .Where(obj => obj != null).ToArray(); if (objects.Length == 0) { return; } Undo.RecordObjects(targets, "Inspector"); var hasChanges = false; InvokeWrapper[] fieldsAndProperties = InvokeWrapper.FindFieldsAndProperties(objects[0].GetType()); var group = InspectorGroupHandler.Create(); foreach (var wrapper in fieldsAndProperties) { if (!ShouldBeShownInInspector(wrapper.Member)) { continue; } group.Update(wrapper, objects[0]); if (group.IsHidden) { continue; } var runtimeDisabled = EditorApplication.isPlayingOrWillChangePlaymode && wrapper.Member.IsDefined(typeof(DisableInRuntimeInspectorAttribute), true); using (new GUI.EnabledBlock(UnityEngine.GUI.enabled && !runtimeDisabled)) hasChanges = HandleType(wrapper, objects, fallback) || hasChanges; } group.Dispose(); if (hasChanges) { foreach (var obj in targets) { EditorUtility.SetDirty(obj); } } }
public static object UrdfInertiaDrawer(object[] objects, InvokeWrapper wrapper) { var inertia = wrapper.Get <AGXUnity.IO.URDF.Inertia>(objects[0]); InspectorGUI.Vector3Field(InspectorGUI.MakeLabel(wrapper.Member), inertia.GetRow(0), "XX,XY,XZ"); InspectorGUI.Vector3Field(null, inertia.GetRow(1), "YX,YY,YZ"); InspectorGUI.Vector3Field(null, inertia.GetRow(2), "ZX,ZY,ZZ"); return(null); }
public static object EnumDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { if (!wrapper.GetContainingType().IsVisible) { return(null); } return(EditorGUILayout.EnumPopup(MakeLabel(wrapper.Member), wrapper.Get <Enum>(obj), skin.button)); }
public BeginConstraintRowGUI(ConstraintUtils.ConstraintRow row, InvokeWrapper wrapper) { m_guiWasEnabled = UnityEngine.GUI.enabled; if (row != null) { Undo.RecordObject(row.ElementaryConstraint, "RowUpdate"); } UnityEngine.GUI.enabled = m_guiWasEnabled && row != null && row.Valid; }
/// <summary> /// Draw supported member GUI for given targets. This method supports /// non-UnityEngine.Object instances, such as pure Serializable classes, /// that are part of <paramref name="targets"/>. <paramref name="getChildCallback"/> /// is called to access these serializable objects. If <paramref name="getChildCallback"/> /// is null, targets will be rendered. /// </summary> /// <param name="targets">Target UnityEngine.Object instances (used for Undo and SetDirty).</param> /// <param name="getChildCallback">Null and targets will be rendered, otherwise the returned /// instance from this callback.</param> public static void DrawMembersGUI(Object[] targets, Func <Object, object> getChildCallback = null, SerializedObject fallback = null) { targets = targets.Where(obj => obj != null).ToArray(); if (targets.Length == 0) { return; } var objects = targets.Select(target => getChildCallback == null ? target : getChildCallback(target)) .Where(obj => obj != null).ToArray(); if (objects.Length == 0) { return; } Undo.RecordObjects(targets, "Inspector"); var hasChanges = false; InvokeWrapper[] fieldsAndProperties = InvokeWrapper.FindFieldsAndProperties(objects[0].GetType()); var group = InspectorGroupHandler.Create(); foreach (var wrapper in fieldsAndProperties) { if (!ShouldBeShownInInspector(wrapper.Member)) { continue; } group.Update(wrapper, objects[0]); if (group.IsHidden) { continue; } hasChanges = HandleType(wrapper, objects, fallback) || hasChanges; } group.Dispose(); if (hasChanges) { foreach (var obj in targets) { EditorUtility.SetDirty(obj); } } }
public static object UrdfElementDrawer(object[] objects, InvokeWrapper wrapper) { if (objects.Length != 1) { InspectorGUI.WarningLabel("Multi-select of URDF Elements isn't supported."); return(null); } DrawUrdfElement(wrapper.Get <AGXUnity.IO.URDF.Element>(objects[0]), -1); return(null); }
public void ConstraintRowsGUI(GUISkin skin) { try { ConstraintUtils.ConstraintRowParser constraintRowParser = ConstraintUtils.ConstraintRowParser.Create(Constraint); InvokeWrapper[] memberWrappers = InvokeWrapper.FindFieldsAndProperties(null, typeof(ElementaryConstraintRowData)); if (constraintRowParser.HasTranslationalRows) { if (GUI.Foldout(Selected(SelectedFoldout.OrdinaryElementaryTranslational), GUI.MakeLabel("Translational properties </b>(along constraint axis)<b>", true), skin, OnFoldoutStateChange)) { using (new GUI.Indent(12)) HandleConstraintRowsGUI(constraintRowParser.TranslationalRows, memberWrappers, skin); } } if (constraintRowParser.HasRotationalRows) { GUI.Separator(); if (GUI.Foldout(Selected(SelectedFoldout.OrdinaryElementaryRotational), GUI.MakeLabel("Rotational properties </b>(about constraint axis)<b>", true), skin, OnFoldoutStateChange)) { using (new GUI.Indent(12)) HandleConstraintRowsGUI(constraintRowParser.RotationalRows, memberWrappers, skin); } } ElementaryConstraintController[] controllers = Constraint.GetElementaryConstraintControllers(); if (controllers.Length > 0) { if (!constraintRowParser.Empty) { GUI.Separator(); } if (GUI.Foldout(Selected(SelectedFoldout.Controllers), GUI.MakeLabel("Controllers", true), skin, OnFoldoutStateChange)) { using (new GUI.Indent(12)) { GUI.Separator(); foreach (var controller in controllers) { HandleConstraintControllerGUI(controller, skin); GUI.Separator(); } } } } } catch (AgXUnity.Exception e) { GUILayout.Label(GUI.MakeLabel("Unable to parse constraint rows", true), skin.label); GUILayout.Label(GUI.MakeLabel(" - " + e.Message, Color.red), skin.label); } }
public static object Vector3Drawer(object obj, InvokeWrapper wrapper, GUISkin skin) { var valInField = wrapper.Get <Vector3>(obj); GUILayout.BeginHorizontal(); { GUILayout.Label(GUI.MakeLabel(wrapper.Member.Name)); valInField = EditorGUILayout.Vector3Field("", valInField); } GUILayout.EndHorizontal(); return(valInField); }
private static bool CompareMulti <ValueT>(object[] objects, InvokeWrapper wrapper, Func <DefaultAndUserValue <ValueT>, bool> validator) where ValueT : struct { var identical = true; for (int i = 1; i < objects.Length; ++i) { identical = identical && validator(wrapper.Get <DefaultAndUserValue <ValueT> >(objects[i])); } return(identical); }
public static bool HandleType(InvokeWrapper wrapper, object[] objects) { if (!wrapper.CanRead()) { return(false); } var drawerInfo = InspectorGUI.GetDrawerMethod(wrapper.GetContainingType()); if (!drawerInfo.IsValid) { return(false); } EditorGUI.showMixedValue = !wrapper.AreValuesEqual(objects); var value = drawerInfo.Drawer.Invoke(null, new object[] { objects[0], wrapper, Skin }); var changed = UnityEngine.GUI.changed && (drawerInfo.IsNullable || value != null); // Reset changed state so that non-edited values // are propagated to other properties. UnityEngine.GUI.changed = false; EditorGUI.showMixedValue = false; if (!changed) { return(false); } foreach (var obj in objects) { object newValue = value; if (drawerInfo.CopyOp != null) { newValue = wrapper.GetValue(obj); // CopyOp returns the new value for value types. var ret = drawerInfo.CopyOp.Invoke(null, new object[] { value, newValue }); if (ret != null) { newValue = ret; } } wrapper.ConditionalSet(obj, newValue); } return(true); }
public static object DecimalDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { float value = wrapper.GetContainingType() == typeof(double) ? Convert.ToSingle(wrapper.Get <double>(obj)) : wrapper.Get <float>(obj); FloatSliderInInspector slider = wrapper.GetAttribute <FloatSliderInInspector>(); if (slider != null) { return(EditorGUILayout.Slider(MakeLabel(wrapper.Member), value, slider.Min, slider.Max)); } else { return(EditorGUILayout.FloatField(MakeLabel(wrapper.Member), value, skin.textField)); } }
public static object DefaultAndUserValueFloatDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { var dauvf = wrapper.Get <DefaultAndUserValueFloat>(obj); var value = GUI.HandleDefaultAndUserValue(wrapper.Member.Name, dauvf, skin); if (wrapper.IsValid(value)) { if (!dauvf.UseDefault) { dauvf.Value = value; } return(obj); } return(null); }
public static object EnumDrawer(object[] objects, InvokeWrapper wrapper) { if (!wrapper.GetContainingType().IsVisible) { return(null); } if (wrapper.GetContainingType().GetCustomAttribute <FlagsAttribute>() != null) { return(EditorGUILayout.EnumFlagsField(InspectorGUI.MakeLabel(wrapper.Member), wrapper.Get <Enum>(objects[0]), InspectorEditor.Skin.Popup)); } else { return(EditorGUILayout.EnumPopup(InspectorGUI.MakeLabel(wrapper.Member), wrapper.Get <Enum>(objects[0]), InspectorEditor.Skin.Popup)); } }
public void Update(InvokeWrapper wrapper, object targetInstance) { var foldoutBeginAttribute = wrapper.GetAttribute <InspectorGroupBeginAttribute>(); if (foldoutBeginAttribute != null || wrapper.HasAttribute <InspectorGroupEndAttribute>()) { End(); } if (foldoutBeginAttribute == null) { return; } var groupIdentifier = (targetInstance != null ? targetInstance.GetType().FullName : "null") + "_" + foldoutBeginAttribute.Name; Begin(!InspectorGUI.Foldout(EditorData.Instance.GetData(targetInstance as Object, groupIdentifier), GUI.MakeLabel(foldoutBeginAttribute.Name))); }
public static object RangeRealDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { var value = wrapper.Get <RangeReal>(obj); GUIStyle labelStyle = skin.label; if (value.Min > value.Max) { if (m_rangeRealInvalidStyle == null) { m_rangeRealInvalidStyle = new GUIStyle(skin.label); m_rangeRealInvalidStyle.normal.background = GUI.CreateColoredTexture(4, 4, Color.Lerp(UnityEngine.GUI.color, Color.red, 0.75f)); } labelStyle = m_rangeRealInvalidStyle; } RangeRealResult result = new RangeRealResult() { Min = value.Min, MinChanged = false, Max = value.Max, MaxChanged = false }; using (new GUILayout.HorizontalScope(labelStyle)) { GUILayout.Label(MakeLabel(wrapper.Member), skin.label); result.Min = EditorGUILayout.FloatField("", value.Min, skin.textField, GUILayout.MaxWidth(64)); result.MinChanged = UnityEngine.GUI.changed; UnityEngine.GUI.changed = false; result.Max = EditorGUILayout.FloatField("", value.Max, skin.textField, GUILayout.MaxWidth(64)); result.MaxChanged = UnityEngine.GUI.changed; UnityEngine.GUI.changed = result.MinChanged || result.MaxChanged; } if (labelStyle == m_rangeRealInvalidStyle) { GUI.WarningLabel("Invalid range, Min > Max: (" + value.Min + " > " + value.Max + ")", skin); } return(result); }
private static bool DrawMembersGUI(object obj, T target, GUISkin skin) { if (obj == null) { return(false); } if (obj == target) { Utils.GUI.PreTargetMembers(target, skin); } bool changed = false; InvokeWrapper[] fieldsAndProperties = InvokeWrapper.FindFieldsAndProperties(obj); foreach (InvokeWrapper wrapper in fieldsAndProperties) { if (ShouldBeShownInInspector(wrapper.Member)) { changed = HandleType(wrapper, target, skin) || changed; } } var methods = from methodInfo in obj.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) where ShouldBeShownInInspector(methodInfo) select methodInfo; methods.ToList().ForEach(methodInfo => changed = HandleMethod(methodInfo, target, skin) || changed); if (obj == target) { Utils.GUI.PostTargetMembers(target, skin); } return(changed); }
private void HandleConstraintRowType(ConstraintUtils.ConstraintRow row, int rowIndex, InvokeWrapper wrapper, GUISkin skin) { RowLabel(rowIndex, skin); var rowData = row != null ? row.RowData : null; object value = null; if (wrapper.IsType <float>()) { value = EditorGUILayout.FloatField(wrapper.Get <float>(rowData)); } else if (wrapper.IsType <RangeReal>()) { RangeReal currValue = wrapper.Get <RangeReal>(rowData); if (currValue == null) { currValue = new RangeReal(); } currValue.Min = EditorGUILayout.FloatField(currValue.Min, GUILayout.MaxWidth(128)); currValue.Max = EditorGUILayout.FloatField(currValue.Max, GUILayout.MaxWidth(128)); if (currValue.Min > currValue.Max) { currValue.Min = currValue.Max; } value = currValue; } else { } if (wrapper.ConditionalSet(rowData, value)) { EditorUtility.SetDirty(Constraint); } }
public static object Vector3Drawer(object[] objects, InvokeWrapper wrapper) { return(InspectorGUI.Vector3Field(InspectorGUI.MakeLabel(wrapper.Member), wrapper.Get <Vector3>(objects[0]))); }
public static object GenericListDrawer(object[] objects, InvokeWrapper wrapper) { var list = wrapper.Get <System.Collections.IList>(objects[0]); var target = objects[0] as Object; if (InspectorGUI.Foldout(EditorData.Instance.GetData(target, wrapper.Member.Name), InspectorGUI.MakeLabel(wrapper.Member))) { object insertElementBefore = null; object insertElementAfter = null; object eraseElement = null; var skin = InspectorEditor.Skin; var buttonLayout = new GUILayoutOption[] { GUILayout.Width(1.0f * EditorGUIUtility.singleLineHeight), GUILayout.Height(1.0f * EditorGUIUtility.singleLineHeight) }; foreach (var listObject in list) { using (InspectorGUI.IndentScope.Single) { GUILayout.BeginHorizontal(); { InspectorGUI.Separator(1.0f, EditorGUIUtility.singleLineHeight); if (InspectorGUI.Button(MiscIcon.EntryInsertBefore, true, "Insert new element before this.", buttonLayout)) { insertElementBefore = listObject; } if (InspectorGUI.Button(MiscIcon.EntryInsertAfter, true, "Insert new element after this.", buttonLayout)) { insertElementAfter = listObject; } if (InspectorGUI.Button(MiscIcon.EntryRemove, true, "Remove this element.", buttonLayout)) { eraseElement = listObject; } } GUILayout.EndHorizontal(); InspectorEditor.DrawMembersGUI(new Object[] { target }, ignored => listObject); } } InspectorGUI.Separator(1.0f, 0.5f * EditorGUIUtility.singleLineHeight); if (list.Count == 0) { GUILayout.Label(GUI.MakeLabel("Empty", true), skin.Label); } bool addElementToList = false; GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); addElementToList = InspectorGUI.Button(MiscIcon.EntryInsertAfter, true, "Add new element.", buttonLayout); } GUILayout.EndHorizontal(); object newObject = null; if (addElementToList || insertElementBefore != null || insertElementAfter != null) { newObject = Activator.CreateInstance(list.GetType().GetGenericArguments()[0], new object[] { }); } if (eraseElement != null) { list.Remove(eraseElement); } else if (newObject != null) { if (addElementToList || (list.Count > 0 && insertElementAfter != null && insertElementAfter == list[list.Count - 1])) { list.Add(newObject); } else if (insertElementAfter != null) { list.Insert(list.IndexOf(insertElementAfter) + 1, newObject); } else if (insertElementBefore != null) { list.Insert(list.IndexOf(insertElementBefore), newObject); } } if (eraseElement != null || newObject != null) { EditorUtility.SetDirty(target); } } // A bit of a hack until I figure out how to handle multi-selection // of lists, if that should be possible at all. We're handling the // list from inside this drawer and by returning null the return // value isn't propagated to any targets. return(null); }
public static object BoolDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { return(GUI.Toggle(MakeLabel(wrapper.Member), wrapper.Get <bool>(obj), skin.button, skin.label)); }
public static object ColorDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { return(EditorGUILayout.ColorField(MakeLabel(wrapper.Member), wrapper.Get <Color>(obj))); }
public static object IntDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { return(EditorGUILayout.IntField(MakeLabel(wrapper.Member).text, wrapper.Get <int>(obj), skin.textField)); }
public static object Vector2Drawer(object obj, InvokeWrapper wrapper, GUISkin skin) { return(EditorGUILayout.Vector2Field(MakeLabel(wrapper.Member).text, wrapper.Get <Vector2>(obj))); }
public static object StringDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { return(EditorGUILayout.TextField(MakeLabel(wrapper.Member), wrapper.Get <string>(obj), skin.textField)); }
public static object ScriptDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { object result = null; var type = wrapper.GetContainingType(); bool allowSceneObject = type == typeof(GameObject) || type.BaseType == typeof(ScriptComponent); Object valInField = wrapper.Get <Object>(obj); bool recursiveEditing = wrapper.HasAttribute <AllowRecursiveEditing>(); bool createNewAssetButton = false; if (recursiveEditing) { var foldoutData = EditorData.Instance.GetData(obj as Object, wrapper.Member.Name); GUILayout.BeginHorizontal(); { var objFieldLabel = MakeLabel(wrapper.Member); var buttonSize = skin.label.CalcHeight(objFieldLabel, Screen.width); UnityEngine.GUI.enabled = valInField != null; foldoutData.Bool = GUILayout.Button(GUI.MakeLabel(foldoutData.Bool ? "-" : "+"), skin.button, new GUILayoutOption[] { GUILayout.Width(20.0f), GUILayout.Height(buttonSize) }) ? // Button clicked - toggle current value. !foldoutData.Bool : // If foldout were enabled but valInField has changed to null - foldout will become disabled. valInField != null && foldoutData.Bool; UnityEngine.GUI.enabled = true; result = EditorGUILayout.ObjectField(objFieldLabel, valInField, type, allowSceneObject, new GUILayoutOption[] { }); if (typeof(ScriptAsset).IsAssignableFrom(type)) { GUILayout.Space(4); using (new GUI.ColorBlock(Color.Lerp(UnityEngine.GUI.color, Color.green, 0.1f))) createNewAssetButton = GUILayout.Button(GUI.MakeLabel("New", false, "Create new asset"), GUILayout.Width(42), GUILayout.Height(buttonSize)); } } GUILayout.EndHorizontal(); if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0) { Event.current.Use(); foldoutData.Bool = !foldoutData.Bool; GUIUtility.ExitGUI(); } if (foldoutData.Bool) { using (new GUI.Indent(12)) { GUI.Separator(); GUILayout.Space(6); AGXUnity.Utils.GUI.WarningLabel("Changes made to this object will affect all objects referencing this asset.", skin); GUILayout.Space(6); Editor editor = Editor.CreateEditor(result as Object); if (editor != null) { editor.OnInspectorGUI(); } GUI.Separator(); } } } else { result = EditorGUILayout.ObjectField(MakeLabel(wrapper.Member), valInField, type, allowSceneObject, new GUILayoutOption[] { }); } if (createNewAssetButton) { var assetName = type.Name.SplitCamelCase().ToLower(); var path = EditorUtility.SaveFilePanel("Create new " + assetName, "Assets", "new " + assetName + ".asset", "asset"); if (path != string.Empty) { var info = new System.IO.FileInfo(path); var relativePath = IO.Utils.MakeRelative(path, Application.dataPath); var newInstance = ScriptAsset.Create(type); newInstance.name = info.Name; AssetDatabase.CreateAsset(newInstance, relativePath + (info.Extension == ".asset" ? "" : ".asset")); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); result = newInstance; } } return(result); }
public static object GenericListDrawer(object obj, InvokeWrapper wrapper, GUISkin skin) { System.Collections.IList list = wrapper.Get <System.Collections.IList>(obj); var target = obj as Object; if (GUI.Foldout(EditorData.Instance.GetData(target, wrapper.Member.Name), MakeLabel(wrapper.Member), skin)) { object insertElementBefore = null; object insertElementAfter = null; object eraseElement = null; var buttonLayout = new GUILayoutOption[] { GUILayout.Width(26), GUILayout.Height(18) }; using (new GUI.Indent(12)) { foreach (var listObject in list) { GUI.Separator(); using (new GUI.Indent(12)) { GUILayout.BeginHorizontal(); { GUILayout.BeginVertical(); { // Using target to render listObject since it normally (CollisionGroupEntry) isn't an Object. InspectorEditor.DrawMembersGUI(new Object[] { target }, ignored => listObject); } GUILayout.EndVertical(); using (GUI.NodeListButtonColor) { if (GUILayout.Button(GUI.MakeLabel(GUI.Symbols.ListInsertElementBefore.ToString(), false, "Insert new element before this"), skin.button, buttonLayout)) { insertElementBefore = listObject; } if (GUILayout.Button(GUI.MakeLabel(GUI.Symbols.ListInsertElementAfter.ToString(), false, "Insert new element after this"), skin.button, buttonLayout)) { insertElementAfter = listObject; } if (GUILayout.Button(GUI.MakeLabel(GUI.Symbols.ListEraseElement.ToString(), false, "Erase this element"), skin.button, buttonLayout)) { eraseElement = listObject; } } } GUILayout.EndHorizontal(); } } if (list.Count == 0) { GUILayout.Label(GUI.MakeLabel("Empty", true), skin.label); } else { GUI.Separator(); } } bool addElementToList = false; GUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); using (GUI.NodeListButtonColor) addElementToList = GUILayout.Button(GUI.MakeLabel(GUI.Symbols.ListInsertElementAfter.ToString(), false, "Add new element to list"), skin.button, buttonLayout); } GUILayout.EndHorizontal(); object newObject = null; if (addElementToList || insertElementBefore != null || insertElementAfter != null) { newObject = Activator.CreateInstance(list.GetType().GetGenericArguments()[0], new object[] { }); } if (eraseElement != null) { list.Remove(eraseElement); } else if (newObject != null) { if (addElementToList || (list.Count > 0 && insertElementAfter != null && insertElementAfter == list[list.Count - 1])) { list.Add(newObject); } else if (insertElementAfter != null) { list.Insert(list.IndexOf(insertElementAfter) + 1, newObject); } else if (insertElementBefore != null) { list.Insert(list.IndexOf(insertElementBefore), newObject); } } if (eraseElement != null || newObject != null) { EditorUtility.SetDirty(target); } } // A bit of a hack until I figure out how to handle multi-selection // of lists, if that should be possible at all. We're handling the // list from inside this drawer and by returning null the return // value isn't propagated to any targets. return(null); }