using System; using System.Collections; using System.Collections.Generic; using BansheeEngine; namespace BansheeEditor { /// /// Displays GUI for a serializable property containing a list. List contents are displayed as rows of entries /// that can be shown, hidden or manipulated. /// public class InspectableList : InspectableField { private InspectableListGUI listGUIField; /// /// Creates a new inspectable list 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 list whose contents to display. public InspectableList(string title, int depth, InspectableFieldLayout layout, SerializableProperty property) : base(title, SerializableProperty.FieldType.List, depth, layout, property) { } /// public override GUILayoutX GetTitleLayout() { return listGUIField.GetTitleLayout(); } /// public override InspectableState Refresh(int layoutIndex) { return listGUIField.Refresh(); } /// protected internal override void Initialize(int layoutIndex) { GUILayout arrayLayout = layout.AddLayoutY(layoutIndex); listGUIField = InspectableListGUI.Create(title, property, arrayLayout, depth); } /// /// Handles creation of GUI elements for a GUI list field that displays a object. /// private class InspectableListGUI : GUIListFieldBase { private IList list; private int numElements; private SerializableProperty property; /// /// Constructs a new empty inspectable list GUI. /// /// Label to display on the list GUI title. /// Serializable property referencing a list. /// 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 InspectableListGUI(LocString title, SerializableProperty property, GUILayout layout, int depth) : base(title, layout, depth) { this.property = property; list = property.GetValue(); if (list != null) numElements = list.Count; } /// /// Creates a new inspectable list GUI object that displays the contents of the provided serializable property. /// /// Label to display on the list GUI title. /// Serializable property referencing a list. /// 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 InspectableListGUI Create(LocString title, SerializableProperty property, GUILayout layout, int depth) { InspectableListGUI listGUI = new InspectableListGUI(title, property, layout, depth); listGUI.BuildGUI(); return listGUI; } /// public override InspectableState Refresh() { // Check if any modifications to the array were made outside the inspector IList newList = property.GetValue(); if (list == null && newList != null) { list = newList; numElements = list.Count; BuildGUI(); } else if (newList == null && list != null) { list = null; numElements = 0; BuildGUI(); } else { if (list != null) { if (numElements != list.Count) { numElements = list.Count; BuildGUI(); } } } return base.Refresh(); } /// protected override GUIListFieldRow CreateRow() { return new InspectableListGUIRow(); } /// protected override bool IsNull() { return list == null; } /// protected override int GetNumRows() { if (list != null) return list.Count; return 0; } /// protected internal override object GetValue(int seqIndex) { SerializableList list = property.GetList(); return list.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() { list = property.CreateListInstance(0); property.SetValue(list); numElements = 0; } /// protected override void ResizeList() { int size = guiSizeField.Value; IList newList = property.CreateListInstance(size); int maxSize = MathEx.Min(size, list.Count); for (int i = 0; i < maxSize; i++) newList[i] = list[i]; property.SetValue(newList); list = newList; numElements = list.Count; } /// protected override void ClearList() { property.SetValue(null); list = null; numElements = 0; } /// protected internal override void DeleteElement(int index) { if (index >= 0 && index < list.Count) list.RemoveAt(index); numElements = list.Count; } /// protected internal override void CloneElement(int index) { SerializableList serializableList = property.GetList(); if (index >= 0 && index < list.Count) list.Add(SerializableUtility.Clone(serializableList.GetProperty(index).GetValue())); numElements = list.Count; } /// protected internal override void MoveUpElement(int index) { if ((index - 1) >= 0) { object previousEntry = list[index - 1]; list[index - 1] = list[index]; list[index] = previousEntry; } } /// protected internal override void MoveDownElement(int index) { if ((index + 1) < list.Count) { object nextEntry = list[index + 1]; list[index + 1] = list[index]; list[index] = nextEntry; } } } /// /// Contains GUI elements for a single entry in the list. /// private class InspectableListGUIRow : 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); } } } }