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;
}
}
}
}