using System; using BansheeEngine; namespace BansheeEditor { /// /// Displays GUI for a serializable property containing an array. Array contents are displayed as rows of entries /// that can be shown, hidden or manipulated. /// public class InspectableArray : InspectableField { private InspectableArrayGUI arrayGUIField; /// /// Creates a new inspectable array GUI for the specified property. /// /// Name of the property, or some other value to set as the title. /// Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one. /// Parent layout that all the field elements will be added to. /// Serializable property referencing the array whose contents to display. public InspectableArray(string title, int depth, InspectableFieldLayout layout, SerializableProperty property) : base(title, SerializableProperty.FieldType.Array, depth, layout, property) { } /// public override GUILayoutX GetTitleLayout() { return arrayGUIField.GetTitleLayout(); } /// public override InspectableState Refresh(int layoutIndex) { return arrayGUIField.Refresh(); } /// protected internal override void Initialize(int layoutIndex) { GUILayout arrayLayout = layout.AddLayoutY(layoutIndex); arrayGUIField = InspectableArrayGUI.Create(title, property, arrayLayout, depth); } /// /// Handles creation of GUI elements for a GUI list field that displays a object. /// private class InspectableArrayGUI : GUIListFieldBase { private Array array; private int numElements; private SerializableProperty property; /// /// Constructs a new inspectable array GUI. /// public InspectableArrayGUI(LocString title, SerializableProperty property, GUILayout layout, int depth) : base(title, layout, depth) { this.property = property; array = property.GetValue(); if (array != null) numElements = array.Length; } /// /// Creates a new inspectable array GUI object that displays the contents of the provided serializable property. /// /// Label to display on the list GUI title. /// Serializable property referencing a single-dimensional array. /// Layout to which to append the list GUI elements to. /// Determines at which depth to render the background. Useful when you have multiple /// nested containers whose backgrounds are overlaping. Also determines background style, /// depths divisible by two will use an alternate style. public static InspectableArrayGUI Create(LocString title, SerializableProperty property, GUILayout layout, int depth) { InspectableArrayGUI guiArray = new InspectableArrayGUI(title, property, layout, depth); guiArray.BuildGUI(); return guiArray; } /// public override InspectableState Refresh() { // Check if any modifications to the array were made outside the inspector Array newArray = property.GetValue(); if (array == null && newArray != null) { array = newArray; numElements = array.Length; BuildGUI(); } else if (newArray == null && array != null) { array = null; numElements = 0; BuildGUI(); } else { if (array != null) { if (numElements != array.Length) { numElements = array.Length; BuildGUI(); } } } return base.Refresh(); } /// protected override GUIListFieldRow CreateRow() { return new InspectableArrayGUIRow(); } /// protected override bool IsNull() { return array == null; } /// protected override int GetNumRows() { if (array != null) return array.Length; return 0; } /// protected internal override object GetValue(int seqIndex) { SerializableArray array = property.GetArray(); return array.GetProperty(seqIndex); } /// protected internal override void SetValue(int seqIndex, object value) { // Setting the value should be done through the property throw new InvalidOperationException(); } /// protected override void CreateList() { array = property.CreateArrayInstance(new int[1] { 0 }); property.SetValue(array); numElements = 0; } /// protected override void ResizeList() { int size = guiSizeField.Value; // TODO - Support multi-rank arrays Array newArray = property.CreateArrayInstance(new int[] { size }); int maxSize = MathEx.Min(size, array.Length); for (int i = 0; i < maxSize; i++) newArray.SetValue(array.GetValue(i), i); property.SetValue(newArray); array = newArray; numElements = size; } /// protected override void ClearList() { property.SetValue(null); array = null; numElements = 0; } /// protected internal override void DeleteElement(int index) { int size = MathEx.Max(0, array.Length - 1); Array newArray = property.CreateArrayInstance(new int[] { size }); int destIdx = 0; for (int i = 0; i < array.Length; i++) { if (i == index) continue; newArray.SetValue(array.GetValue(i), destIdx); destIdx++; } property.SetValue(newArray); array = newArray; numElements = array.Length; } /// protected internal override void CloneElement(int index) { SerializableArray array = property.GetArray(); int size = array.GetLength() + 1; Array newArray = property.CreateArrayInstance(new int[] { size }); object clonedEntry = null; for (int i = 0; i < array.GetLength(); i++) { object value = array.GetProperty(i).GetValue(); newArray.SetValue(value, i); if (i == index) { clonedEntry = SerializableUtility.Clone(array.GetProperty(i).GetValue()); } } newArray.SetValue(clonedEntry, size - 1); property.SetValue(newArray); this.array = newArray; numElements = newArray.Length; } /// protected internal override void MoveUpElement(int index) { if ((index - 1) >= 0) { object previousEntry = array.GetValue(index - 1); array.SetValue(array.GetValue(index), index - 1); array.SetValue(previousEntry, index); } } /// protected internal override void MoveDownElement(int index) { if ((index + 1) < array.Length) { object nextEntry = array.GetValue(index + 1); array.SetValue(array.GetValue(index), index + 1); array.SetValue(nextEntry, index); } } } /// /// Contains GUI elements for a single entry in the array. /// private class InspectableArrayGUIRow : GUIListFieldRow { private InspectableField field; /// protected override GUILayoutX CreateGUI(GUILayoutY layout) { SerializableProperty property = GetValue(); field = CreateInspectable(SeqIndex + ".", 0, Depth + 1, new InspectableFieldLayout(layout), property); return field.GetTitleLayout(); } /// protected internal override InspectableState Refresh() { field.Property = GetValue(); return field.Refresh(0); } } } }