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 object propertyValue; // TODO - This will unnecessarily hold references to the object private int numArrayElements; 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, depth, layout, property) { } /// public override GUILayoutX GetTitleLayout() { return listGUIField.GetTitleLayout(); } /// public override bool IsModified() { object newPropertyValue = property.GetValue(); if (propertyValue == null) return newPropertyValue != null; if (newPropertyValue == null) return propertyValue != null; SerializableList list = property.GetList(); if (list.GetLength() != numArrayElements) return true; return base.IsModified(); } /// public override void Refresh(int layoutIndex) { if (IsModified()) Update(layoutIndex); listGUIField.Refresh(); } /// public override bool ShouldRebuildOnModify() { return true; } /// protected internal override void BuildGUI(int layoutIndex) { GUILayout arrayLayout = layout.AddLayoutY(layoutIndex); listGUIField = InspectableListGUI.Create(title, property, arrayLayout, depth); } /// protected internal override void Update(int layoutIndex) { propertyValue = property.GetValue(); if (propertyValue != null) { SerializableList list = property.GetList(); numArrayElements = list.GetLength(); } else numArrayElements = 0; layout.DestroyElements(); BuildGUI(layoutIndex); } /// /// Handles creation of GUI elements for a GUI list field that displays a object. /// private class InspectableListGUI : GUIListFieldBase { 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; } /// /// 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; } /// protected override GUIListFieldRow CreateRow() { return new InspectableListGUIRow(); } /// protected override bool IsNull() { IList list = property.GetValue(); return list == null; } /// protected override int GetNumRows() { IList list = property.GetValue(); 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() { property.SetValue(property.CreateListInstance(0)); } /// protected override void ResizeList() { int size = guiSizeField.Value; IList newList = property.CreateListInstance(size); IList list = property.GetValue(); int maxSize = MathEx.Min(size, list.Count); for (int i = 0; i < maxSize; i++) newList[i] = list[i]; property.SetValue(newList); } /// protected override void ClearList() { property.SetValue(null); } /// protected internal override void DeleteElement(int index) { IList list = property.GetValue(); if (index >= 0 && index < list.Count) list.RemoveAt(index); } /// protected internal override void CloneElement(int index) { SerializableList serializableList = property.GetList(); IList list = property.GetValue(); if (index >= 0 && index < list.Count) list.Add(SerializableUtility.Clone(serializableList.GetProperty(index).GetValue())); } /// protected internal override void MoveUpElement(int index) { IList list = property.GetValue(); if ((index - 1) >= 0) { object previousEntry = list[index - 1]; list[index - 1] = list[index]; list[index] = previousEntry; } } /// protected internal override void MoveDownElement(int index) { IList list = property.GetValue(); 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) { if (field == null) { SerializableProperty property = GetValue(); field = CreateInspectable(seqIndex + ".", 0, depth + 1, new InspectableFieldLayout(layout), property); } return field.GetTitleLayout(); } /// protected internal override bool Refresh() { if (field.IsModified()) { field.Refresh(0); return field.ShouldRebuildOnModify(); } field.Refresh(0); return false; } } } }