using System;
using System.Collections;
using System.Collections.Generic;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Displays GUI for a serializable property containing a dictionary. Dictionary contents are displayed as rows of
/// entries that can be shown, hidden or manipulated.
///
public class InspectableDictionary : InspectableField
{
private object propertyValue; // TODO - This will unnecessarily hold references to the object
private int numElements;
private InspectableDictionaryGUI dictionaryGUIField;
///
/// Creates a new inspectable dictionary 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 dictionary whose contents to display.
public InspectableDictionary(string title, int depth, InspectableFieldLayout layout, SerializableProperty property)
: base(title, depth, layout, property)
{
}
///
public override GUILayoutX GetTitleLayout()
{
return dictionaryGUIField.GetTitleLayout();
}
///
public override bool IsModified()
{
object newPropertyValue = property.GetValue();
if (propertyValue == null)
return newPropertyValue != null;
if (newPropertyValue == null)
return propertyValue != null;
SerializableDictionary dictionary = property.GetDictionary();
if (dictionary.GetLength() != numElements)
return true;
return base.IsModified();
}
///
public override void Refresh(int layoutIndex)
{
if (IsModified())
Update(layoutIndex);
dictionaryGUIField.Refresh();
}
///
public override bool ShouldRebuildOnModify()
{
return true;
}
///
protected internal override void BuildGUI(int layoutIndex)
{
GUILayout dictionaryLayout = layout.AddLayoutY(layoutIndex);
dictionaryGUIField = InspectableDictionaryGUI.Create(title, property, dictionaryLayout, depth);
}
///
protected internal override void Update(int layoutIndex)
{
propertyValue = property.GetValue();
if (propertyValue != null)
{
SerializableDictionary dictionary = property.GetDictionary();
numElements = dictionary.GetLength();
}
else
numElements = 0;
layout.DestroyElements();
BuildGUI(layoutIndex);
}
///
/// Creates GUI elements that allow viewing and manipulation of a referenced
/// by a serializable property.
///
public class InspectableDictionaryGUI : GUIDictionaryFieldBase
{
private SerializableProperty property;
private List orderedKeys = new List();
///
/// Constructs a new dictionary GUI.
///
/// Label to display on the list GUI title.
/// Serializable property referencing a dictionary
/// 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.
protected InspectableDictionaryGUI(LocString title, SerializableProperty property, GUILayout layout, int depth = 0)
: base(title, layout, depth)
{
this.property = property;
UpdateKeys();
}
///
/// Builds the inspectable dictionary GUI elements. Must be called at least once in order for the contents to
/// be populated.
///
/// Label to display on the list GUI title.
/// Serializable property referencing a dictionary
/// 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 InspectableDictionaryGUI Create(LocString title, SerializableProperty property, GUILayout layout,
int depth = 0)
{
InspectableDictionaryGUI guiDictionary = new InspectableDictionaryGUI(title, property, layout, depth);
guiDictionary.BuildGUI();
return guiDictionary;
}
///
/// Updates the ordered set of keys used for mapping sequential indexes to keys. Should be called whenever a
/// dictionary key changes.
///
private void UpdateKeys()
{
orderedKeys.Clear();
IDictionary dictionary = property.GetValue();
if (dictionary != null)
{
foreach (var key in dictionary)
orderedKeys.Add(key);
}
}
///
protected override GUIDictionaryFieldRow CreateRow()
{
return new InspectableDictionaryGUIRow();
}
///
protected override int GetNumRows()
{
IDictionary dictionary = property.GetValue();
if (dictionary != null)
return dictionary.Count;
return 0;
}
///
protected override bool IsNull()
{
IDictionary dictionary = property.GetValue();
return dictionary == null;
}
///
protected internal override object GetKey(int rowIdx)
{
return orderedKeys[rowIdx];
}
///
protected internal override object GetValue(object key)
{
SerializableDictionary dictionary = property.GetDictionary();
return dictionary.GetProperty(key);
}
///
protected internal override void SetValue(object key, object value)
{
// Setting the value should be done through the property
throw new InvalidOperationException();
}
///
protected internal override bool Contains(object key)
{
IDictionary dictionary = property.GetValue();
return dictionary.Contains(key); ;
}
///
protected internal override void EditEntry(object oldKey, object newKey, object value)
{
IDictionary dictionary = property.GetValue();
dictionary.Remove(oldKey);
dictionary.Add(newKey, value);
UpdateKeys();
}
///
protected internal override void AddEntry(object key, object value)
{
IDictionary dictionary = property.GetValue();
dictionary.Add(key, value);
UpdateKeys();
}
///
protected internal override void RemoveEntry(object key)
{
IDictionary dictionary = property.GetValue();
dictionary.Remove(key);
UpdateKeys();
}
///
protected internal override object CreateKey()
{
SerializableDictionary dictionary = property.GetDictionary();
return SerializableUtility.Create(dictionary.KeyType);
}
///
protected internal override object CreateValue()
{
SerializableDictionary dictionary = property.GetDictionary();
return SerializableUtility.Create(dictionary.ValueType);
}
///
protected override void CreateDictionary()
{
property.SetValue(property.CreateDictionaryInstance());
UpdateKeys();
}
///
protected override void DeleteDictionary()
{
property.SetValue(null);
UpdateKeys();
}
}
///
/// Contains GUI elements for a single key/value pair in the dictionary.
///
private class InspectableDictionaryGUIRow : GUIDictionaryFieldRow
{
private InspectableField fieldKey;
private InspectableField fieldValue;
///
protected override GUILayoutX CreateKeyGUI(GUILayoutY layout)
{
if (fieldKey == null)
{
SerializableProperty property = GetKey();
fieldKey = CreateInspectable("Key", 0, depth + 1,
new InspectableFieldLayout(layout), property);
}
return fieldKey.GetTitleLayout();
}
///
protected override void CreateValueGUI(GUILayoutY layout)
{
if (fieldValue == null)
{
SerializableProperty property = GetValue();
fieldValue = CreateInspectable("Value", 0, depth + 1,
new InspectableFieldLayout(layout), property);
}
}
///
protected internal override bool Refresh()
{
bool rebuild = false;
if (fieldKey.IsModified())
rebuild = fieldKey.ShouldRebuildOnModify();
fieldKey.Refresh(0);
fieldValue.Refresh(0);
return rebuild;
}
}
}
}