using System;
using System.Collections;
using System.Collections.Generic;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Base class for objects that display GUI for a modifyable dictionary of elements. Elements can be added, modified or
/// removed.
///
public abstract class GUIDictionaryFieldBase
{
private const int IndentAmount = 5;
protected Dictionary rows = new Dictionary();
protected GUIDictionaryFieldRow editRow;
protected GUILayoutX guiChildLayout;
protected GUILayoutX guiTitleLayout;
protected GUILayoutY guiContentLayout;
protected bool isExpanded;
protected int depth;
private int editRowIdx = -1;
private object editKey;
private object editValue;
private object editOriginalKey;
///
/// Constructs a new GUI dictionary.
///
protected GUIDictionaryFieldBase()
{ }
///
/// Builds the dictionary GUI elements. Must be called at least once in order for the contents to be populated.
///
/// Type of rows that are used to handle GUI for individual dictionary elements.
/// Label to display on the dictionary GUI title.
/// Should the created field represent a null object.
/// Number of rows to create GUI for. Only matters for a non-null 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 void BuildGUI(LocString title, bool empty, int numRows, GUILayout layout,
int depth = 0) where T : GUIDictionaryFieldRow, new()
{
Destroy();
this.depth = depth;
this.editKey = CreateKey();
this.editValue = CreateValue();
if (empty)
{
rows.Clear();
guiChildLayout = null;
guiContentLayout = null;
guiTitleLayout = layout.AddLayoutX();
guiTitleLayout.AddElement(new GUILabel(title));
guiTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create));
GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
createBtn.OnClick += OnCreateButtonClicked;
guiTitleLayout.AddElement(createBtn);
}
else
{
GUIToggle guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
guiFoldout.Value = isExpanded;
guiFoldout.OnToggled += ToggleFoldout;
GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear));
GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
guiClearBtn.OnClick += OnClearButtonClicked;
GUIContent addIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Add));
GUIButton guiAddBtn = new GUIButton(addIcon, GUIOption.FixedWidth(30));
guiAddBtn.OnClick += OnAddButtonClicked;
guiTitleLayout = layout.AddLayoutX();
guiTitleLayout.AddElement(guiFoldout);
guiTitleLayout.AddElement(guiAddBtn);
guiTitleLayout.AddElement(guiClearBtn);
guiChildLayout = layout.AddLayoutX();
guiChildLayout.AddSpace(IndentAmount);
GUIPanel guiContentPanel = guiChildLayout.AddPanel();
GUILayoutX guiIndentLayoutX = guiContentPanel.AddLayoutX();
guiIndentLayoutX.AddSpace(IndentAmount);
GUILayoutY guiIndentLayoutY = guiIndentLayoutX.AddLayoutY();
guiIndentLayoutY.AddSpace(IndentAmount);
guiContentLayout = guiIndentLayoutY.AddLayoutY();
guiIndentLayoutY.AddSpace(IndentAmount);
guiIndentLayoutX.AddSpace(IndentAmount);
guiChildLayout.AddSpace(IndentAmount);
short backgroundDepth = (short)(Inspector.START_BACKGROUND_DEPTH - depth - 1);
string bgPanelStyle = depth % 2 == 0
? EditorStyles.InspectorContentBgAlternate
: EditorStyles.InspectorContentBg;
GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
backgroundPanel.AddElement(inspectorContentBg);
// Hidden dependency: BuildGUI must be called after all elements are
// in the dictionary so we do it in two steps
for (int i = rows.Count; i < numRows; i++)
{
GUIDictionaryFieldRow newRow = new T();
rows.Add(i, newRow);
}
for (int i = numRows; i < rows.Count; i++)
rows.Remove(i);
if(editRow == null)
editRow = new T();
editRow.BuildGUI(this, guiContentLayout, numRows, depth + 1);
editRow.Enabled = false;
for (int i = 0; i < numRows; i++)
rows[i].BuildGUI(this, guiContentLayout, i, depth + 1);
ToggleFoldout(isExpanded);
}
}
///
/// Returns the layout that is used for positioning the elements in the title bar.
///
/// Horizontal layout for positioning the title bar elements.
public GUILayoutX GetTitleLayout()
{
return guiTitleLayout;
}
///
/// Refreshes contents of all dictionary rows and checks if anything was modified.
///
/// True if any entry in the list was modified, false otherwise.
public bool Refresh()
{
bool anythingModified = false;
for (int i = 0; i < rows.Count; i++)
{
if (rows[i].Refresh())
rows[i].BuildGUI(this, guiContentLayout, i, depth + 1);
}
if (editRow != null && editRow.Enabled)
{
if (editRow.Refresh())
editRow.BuildGUI(this, guiContentLayout, rows.Count, depth + 1);
}
return anythingModified;
}
///
/// Destroys the GUI elements.
///
public void Destroy()
{
if (guiTitleLayout != null)
{
guiTitleLayout.Destroy();
guiTitleLayout = null;
}
if (guiChildLayout != null)
{
guiChildLayout.Destroy();
guiChildLayout = null;
}
for (int i = 0; i < rows.Count; i++)
rows[i].Destroy();
if (editRow != null)
editRow.Destroy();
}
///
/// Checks is the specified row index the temporary edit row.
///
/// Sequential index of the row to check.
/// True if the index is of an edit row.
private bool IsTemporaryRow(int rowIdx)
{
return rowIdx == rows.Count;
}
///
/// Checks is any row being currently edited.
///
/// True if a row is being edited, false otherwise.
private bool IsEditInProgress()
{
return editRowIdx != -1;
}
///
/// Gets a value of an element at the specified index in the list. Also handles temporary edit fields.
///
/// Sequential index of the row to set the value for.
/// Value of the list element at the specified key.
protected internal virtual object GetValueInternal(int rowIdx)
{
if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
return editValue;
else
return GetValue(GetKey(rowIdx));
}
///
/// Sets a value of an element at the specified index in the list. Also handles temporary edit fields.
///
/// Sequential index of the row to set the value for.
/// Value to assign to the element. Caller must ensure it is of valid type.
protected internal virtual void SetValueInternal(int rowIdx, object value)
{
if (rowIdx == editRowIdx || IsTemporaryRow(rowIdx))
editValue = value;
else
SetValue(GetKey(rowIdx), value);
}
///
/// Changes the value of the key of the specified row.
///
/// Sequential index of the row to set the key for.
/// Key to assign to the specified row.
protected internal void SetKey(int rowIdx, object key)
{
if (editRowIdx != rowIdx)
{
Debug.LogError("Cannot change a dictionary row that is not in edit state.");
return;
}
editKey = key;
}
///
/// Gets a key for a row at the specified index. Handles the special case for the currently edited row.
///
/// Sequential index of the row for which to retrieve the key.
/// Key for a row at the specified index.
protected internal object GetKeyInternal(int rowIdx)
{
if (editRowIdx == rowIdx || IsTemporaryRow(rowIdx))
return editKey;
return GetKey(rowIdx);
}
///
/// Gets a key for a row at the specified index.
///
/// Sequential index of the row for which to retrieve the key.
/// Key for a row at the specified index.
protected internal abstract object GetKey(int rowIdx);
///
/// Gets a value of an element at the specified index in the list.
///
/// Key of the element whose value to retrieve.
/// Value of the dictionary entry for the specified key.
protected internal abstract object GetValue(object key);
///
/// Sets a value of an element at the specified index in the list.
///
/// Key of the element whose value to set.
/// Value to assign to the element. Caller must ensure it is of valid type.
protected internal abstract void SetValue(object key, object value);
///
/// Updates both key and value of an existing entry.
///
/// Original key of the entry.
/// New key of the entry.
/// New value of the entry.
protected internal abstract void EditEntry(object oldKey, object newKey, object value);
///
/// Adds a new entry to the dictionary.
///
/// Key of the entry to add.
/// Value of the entry to add.
protected internal abstract void AddEntry(object key, object value);
///
/// Removes the specified entry from the dictionary.
///
/// Key of the entry to remove.
protected internal abstract void RemoveEntry(object key);
///
/// Creates a new empty key object of a valid type that can be used in the dictionary.
///
/// New empty key object.
protected internal abstract object CreateKey();
///
/// Creates a new empty value object of a valid type that can be used in the dictionary.
///
/// New empty value object.
protected internal abstract object CreateValue();
///
/// Checks does the element with the specified key exist in the dictionary.
///
/// Key of the element to check for existence.
/// True if the key exists in the dictionary, false otherwise.
protected internal abstract bool Contains(object key);
///
/// Hides or shows the dictionary rows.
///
/// True if the rows should be displayed, false otherwise.
private void ToggleFoldout(bool expanded)
{
isExpanded = expanded;
if (guiChildLayout != null)
guiChildLayout.Active = isExpanded && (rows.Count > 0 || IsEditInProgress());
}
///
/// Triggered when the user clicks on the create button on the title bar. Creates a brand new dictionary with zero
/// elements in the place of the current dictionary.
///
protected abstract void OnCreateButtonClicked();
///
/// Triggered when the user clicks on the add button on the title bar. Adds a new empty element to the dictionary.
///
protected virtual void OnAddButtonClicked()
{
if (IsEditInProgress())
{
DialogBox.Open(
new LocEdString("Edit in progress."),
new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot add a row " +
"before applying or discarding those changes. Do you wish to apply those changes first?"),
DialogBox.Type.YesNoCancel,
x =>
{
switch (x)
{
case DialogBox.ResultType.Yes:
if (ApplyChanges())
StartAdd();
break;
case DialogBox.ResultType.No:
DiscardChanges();
StartAdd();
break;
}
});
}
else
{
if (!isExpanded)
ToggleFoldout(true);
StartAdd();
}
}
///
/// Triggered when the user clicks on the clear button on the title bar. Deletes the current dictionary object.
///
protected abstract void OnClearButtonClicked();
///
/// Triggered when the user clicks on the delete button next to a dictionary entry. Deletes an element in the
/// dictionary.
///
/// Sequential row index of the entry that was clicked.
protected internal virtual void OnDeleteButtonClicked(int rowIdx)
{
if (IsEditInProgress())
DiscardChanges();
else
RemoveEntry(GetKey(rowIdx));
}
///
/// Triggered when the user clicks on the clone button next to a dictionary entry. Clones an element and
/// adds the clone to the dictionary.
///
/// Sequential row index of the entry that was clicked.
protected internal virtual void OnCloneButtonClicked(int rowIdx)
{
if (IsEditInProgress())
{
DialogBox.Open(
new LocEdString("Edit in progress."),
new LocEdString("You are editing the entry with key \"" + editKey + "\". You cannot clone a row " +
"before applying or discarding those changes. Do you wish to apply those changes first?"),
DialogBox.Type.YesNoCancel,
x =>
{
switch (x)
{
case DialogBox.ResultType.Yes:
if (ApplyChanges())
StartClone(rowIdx);
break;
case DialogBox.ResultType.No:
DiscardChanges();
StartClone(rowIdx);
break;
}
});
}
else
StartClone(rowIdx);
}
///
/// Triggered when user clicks the edit or apply (depending on state) button next to the dictionary entry. Starts
/// edit mode for the element, if not already in edit mode. Applies edit mode changes if already in edit mode.
///
/// Sequential row index of the entry that was clicked.
protected internal virtual void OnEditButtonClicked(int rowIdx)
{
if (editRowIdx == rowIdx)
ApplyChanges();
else
{
if (IsEditInProgress())
{
DialogBox.Open(
new LocEdString("Edit in progress."),
new LocEdString("You are already editing the entry with key \"" + editKey + "\". You cannot edit " +
"another row before applying or discarding those changes. Do you wish to apply those changes first?"),
DialogBox.Type.YesNoCancel,
x =>
{
switch (x)
{
case DialogBox.ResultType.Yes:
if (ApplyChanges())
StartEdit(rowIdx);
break;
case DialogBox.ResultType.No:
DiscardChanges();
StartEdit(rowIdx);
break;
}
});
}
else
StartEdit(rowIdx);
}
}
///
/// Starts an edit operation on a row with the specified key. Allows the user to change the key of the specified row.
/// Caller must ensure no edit operation is already in progress.
///
/// Sequential row index of the entry to edit.
private void StartEdit(int rowIdx)
{
object key = GetKey(rowIdx);
editKey = SerializableUtility.Clone(key);
editValue = SerializableUtility.Clone(GetValue(key));
editOriginalKey = key;
editRowIdx = rowIdx;
rows[rowIdx].EditMode = true;
guiChildLayout.Active = rows.Count > 0 && isExpanded;
}
///
/// Starts an add operation. Adds a new key/value pair and allows the user to set them up in a temporary row
/// before inserting them into the dictionary. Caller must ensure no edit operation is already in progress.
///
private void StartAdd()
{
editKey = CreateKey();
editValue = CreateValue();
editOriginalKey = null;
editRowIdx = rows.Count;
editRow.Enabled = true;
editRow.EditMode = true;
ToggleFoldout(isExpanded);
}
///
/// Starts a clone operation. Adds a new key/value pair by cloning an existing one. Allows the user to modify the
/// new pair in a temporary row before inserting them into the dictionary. Caller must ensure no edit operation is
/// already in progress.
///
/// Sequential row index of the entry to clone.
private void StartClone(int rowIdx)
{
object key = GetKey(rowIdx);
editKey = SerializableUtility.Clone(key);
editValue = SerializableUtility.Clone(GetValue(key));
editOriginalKey = null;
editRowIdx = rows.Count;
editRow.Enabled = true;
editRow.EditMode = true;
ToggleFoldout(isExpanded);
}
///
/// Attempts to apply any changes made to the currently edited row.
///
/// True if the changes were successfully applied, false if the new key already exists in the dictionary.
///
private bool ApplyChanges()
{
if (!IsEditInProgress())
return true;
if (Contains(editKey) && (editOriginalKey == null || !editOriginalKey.Equals(editKey)))
{
DialogBox.Open(
new LocEdString("Key already exists."),
new LocEdString("Cannot add a key \"" + editKey + "\" to dictionary. Key already exists"),
DialogBox.Type.OK);
return false;
}
else
{
if (IsTemporaryRow(editRowIdx))
{
editRow.EditMode = false;
editRow.Enabled = false;
}
else
{
rows[editRowIdx].EditMode = false;
}
if (editOriginalKey != null) // Editing
EditEntry(editOriginalKey, editKey, editValue);
else // Adding/Cloning
AddEntry(editKey, editValue);
editKey = CreateKey();
editValue = CreateValue();
editOriginalKey = null;
editRowIdx = -1;
ToggleFoldout(isExpanded);
return true;
}
}
///
/// Cancels any changes made on the currently edited row.
///
private void DiscardChanges()
{
if (IsEditInProgress())
{
editKey = CreateKey();
editValue = CreateValue();
editOriginalKey = null;
editRow.Enabled = false;
editRowIdx = -1;
ToggleFoldout(isExpanded);
}
}
}
///
/// Creates GUI elements that allow viewing and manipulation of a . When constructing the
/// object user can provide a custom type that manages GUI for individual dictionary elements.
///
/// Type of key used by the dictionary.
/// Type of value stored in the dictionary.
public class GUIDictionaryField : GUIDictionaryFieldBase
{
public delegate int SortDictionaryDelegate(Key a, Key b);
///
/// Triggered when the reference array has been changed. This does not include changes that only happen to its
/// internal elements.
///
public Action> OnChanged;
///
/// Triggered when an element in the list has been changed.
///
public Action OnValueChanged;
///
/// Optional method that will be used for sorting the elements in the dictionary.
///
public SortDictionaryDelegate SortMethod;
///
/// Array object whose contents are displayed.
///
public Dictionary Dictionary { get { return dictionary; } }
protected Dictionary dictionary;
private List orderedKeys = new List();
///
/// Constructs a new empty dictionary GUI.
///
public GUIDictionaryField()
{ }
///
/// Builds the dictionary GUI elements. Must be called at least once in order for the contents to be populated.
///
/// Type of rows that are used to handle GUI for individual dictionary elements.
/// Label to display on the list GUI title.
/// Object containing the data. Can be null.
/// 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 void BuildGUI(LocString title, Dictionary dictionary,
GUILayout layout, int depth = 0)
where RowType : GUIDictionaryFieldRow, new()
{
this.dictionary = dictionary;
UpdateKeys();
if (dictionary != null)
base.BuildGUI(title, false, dictionary.Count, layout, depth);
else
base.BuildGUI(title, true, 0, layout, depth);
}
///
/// 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();
if (dictionary != null)
{
foreach (var KVP in dictionary)
orderedKeys.Add(KVP.Key);
if (SortMethod != null)
orderedKeys.Sort((x,y) => SortMethod(x, y));
else
orderedKeys.Sort();
}
}
///
protected internal override object GetKey(int rowIdx)
{
return orderedKeys[rowIdx];
}
///
protected internal override object GetValue(object key)
{
return dictionary[(Key)key];
}
///
protected internal override void SetValue(object key, object value)
{
dictionary[(Key)key] = (Value)value;
if (OnValueChanged != null)
OnValueChanged((Key)key);
}
///
protected internal override bool Contains(object key)
{
return dictionary.ContainsKey((Key)key); ;
}
///
protected internal override void EditEntry(object oldKey, object newKey, object value)
{
dictionary.Remove((Key)oldKey);
dictionary[(Key)newKey] = (Value)value;
if (OnChanged != null)
OnChanged(dictionary);
UpdateKeys();
}
///
protected internal override void AddEntry(object key, object value)
{
dictionary[(Key)key] = (Value)value;
if (OnChanged != null)
OnChanged(dictionary);
UpdateKeys();
}
///
protected internal override void RemoveEntry(object key)
{
dictionary.Remove((Key) key);
if (OnChanged != null)
OnChanged(dictionary);
UpdateKeys();
}
///
protected internal override object CreateKey()
{
return SerializableUtility.Create();
}
///
protected internal override object CreateValue()
{
return SerializableUtility.Create();
}
///
protected override void OnCreateButtonClicked()
{
dictionary = new Dictionary();
if (OnChanged != null)
OnChanged(dictionary);
UpdateKeys();
}
///
protected override void OnClearButtonClicked()
{
dictionary = null;
if (OnChanged != null)
OnChanged(dictionary);
UpdateKeys();
}
}
///
/// Contains GUI elements for a single entry in a dictionary.
///
public abstract class GUIDictionaryFieldRow
{
private GUILayoutY rowLayout;
private GUILayoutX keyRowLayout;
private GUILayoutY keyLayout;
private GUILayoutY valueLayout;
private GUILayoutX titleLayout;
private GUIButton deleteBtn;
private GUIButton editBtn;
private bool localTitleLayout;
private bool enabled = true;
private GUIDictionaryFieldBase parent;
protected int rowIdx;
protected int depth;
///
/// Determines is the row currently being displayed.
///
internal bool Enabled
{
get { return enabled; }
set { enabled = value; rowLayout.Active = value; }
}
///
/// Enables or disables the row's edit mode. This determines what type of buttons are shown on the row title bar.
///
internal bool EditMode
{
set
{
if (value)
{
GUIContent cancelIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Cancel));
GUIContent applyIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Apply));
deleteBtn.SetContent(cancelIcon);
editBtn.SetContent(applyIcon);
}
else
{
GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete));
GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit));
deleteBtn.SetContent(deleteIcon);
editBtn.SetContent(editIcon);
}
}
}
///
/// Constructs a new dictionary row object.
///
protected GUIDictionaryFieldRow()
{
}
///
/// (Re)creates all row GUI elements.
///
/// Parent array GUI object that the entry is contained in.
/// Parent layout that row GUI elements will be added to.
/// Sequential index of the row.
/// Determines the depth at which the element is rendered.
internal void BuildGUI(GUIDictionaryFieldBase parent, GUILayout parentLayout, int rowIdx, int depth)
{
this.parent = parent;
this.rowIdx = rowIdx;
this.depth = depth;
if (rowLayout == null)
rowLayout = parentLayout.AddLayoutY();
if (keyRowLayout == null)
keyRowLayout = rowLayout.AddLayoutX();
if (keyLayout == null)
keyLayout = keyRowLayout.AddLayoutY();
if (valueLayout == null)
valueLayout = rowLayout.AddLayoutY();
GUILayoutX externalTitleLayout = CreateKeyGUI(keyLayout);
CreateValueGUI(valueLayout);
if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
return;
if (externalTitleLayout != null)
{
localTitleLayout = false;
titleLayout = externalTitleLayout;
}
else
{
GUILayoutY buttonCenter = keyRowLayout.AddLayoutY();
buttonCenter.AddFlexibleSpace();
titleLayout = buttonCenter.AddLayoutX();
buttonCenter.AddFlexibleSpace();
localTitleLayout = true;
}
GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone));
GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete));
GUIContent editIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Edit));
GUIButton cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
editBtn = new GUIButton(editIcon, GUIOption.FixedWidth(30));
cloneBtn.OnClick += () => parent.OnCloneButtonClicked(rowIdx);
deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(rowIdx);
editBtn.OnClick += () => parent.OnEditButtonClicked(rowIdx);
titleLayout.AddElement(cloneBtn);
titleLayout.AddElement(deleteBtn);
titleLayout.AddSpace(10);
titleLayout.AddElement(editBtn);
}
///
/// Creates GUI elements specific to type in the key portion of a dictionary entry.
///
/// Layout to insert the row GUI elements to.
/// An optional title bar layout that the standard dictionary buttons will be appended to.
protected abstract GUILayoutX CreateKeyGUI(GUILayoutY layout);
///
/// Creates GUI elements specific to type in the key portion of a dictionary entry.
///
/// Layout to insert the row GUI elements to.
protected abstract void CreateValueGUI(GUILayoutY layout);
///
/// Refreshes the GUI for the dictionary row and checks if anything was modified.
///
/// Determines should the field's GUI elements be updated due to modifications.
internal protected virtual bool Refresh()
{
return false;
}
///
/// Gets the key contained in this dictionary's row.
///
/// Type of the key. Must match the dictionary's element type.
/// Key in this dictionary's row.
protected T GetKey()
{
return (T)parent.GetKeyInternal(rowIdx);
}
///
/// Sets the key for in this dictionary's row.
///
/// Type of the key. Must match the dictionary's element type.
/// Key to assign to this row.
protected void SetKey(T key)
{
parent.SetKey(rowIdx, key);
}
///
/// Gets the value contained in this dictionary's row.
///
/// Type of the value. Must match the dictionary's element type.
/// Value in this dictionary's row.
protected T GetValue()
{
return (T)parent.GetValueInternal(rowIdx);
}
///
/// Sets the value contained in this dictionary's row.
///
/// Type of the value. Must match the dictionary's element type.
/// Value to set.
protected void SetValue(T value)
{
parent.SetValueInternal(rowIdx, value);
}
///
/// Destroys all row GUI elements.
///
public void Destroy()
{
if (rowLayout != null)
{
rowLayout.Destroy();
rowLayout = null;
}
keyRowLayout = null;
keyLayout = null;
valueLayout = null;
titleLayout = null;
deleteBtn = null;
editBtn = null;
localTitleLayout = false;
}
}
}