//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
//**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************//
using System;
using System.Collections;
using System.Collections.Generic;
using bs;
namespace bs.Editor
{
/** @addtogroup GUI-Editor
* @{
*/
///
/// Base class for objects that display GUI for a modifyable list of elements. Elements can be added, removed and moved.
///
public abstract class GUIListFieldBase
{
private const int IndentAmount = 5;
protected List rows = new List();
protected GUILayoutY guiLayout;
protected GUIIntField guiSizeField;
protected GUILayoutX guiChildLayout;
protected GUILayoutX guiTitleLayout;
protected GUILayoutX guiInternalTitleLayout;
protected GUILayoutY guiContentLayout;
protected GUIToggle guiFoldout;
protected bool isExpanded;
protected int depth;
protected LocString title;
private State state;
private bool isModified;
///
/// Expands or collapses the entries of the dictionary.
///
public bool IsExpanded
{
get { return isExpanded; }
set
{
if (isExpanded != value)
ToggleFoldout(value, true);
}
}
///
/// Event that triggers when the list foldout is expanded or collapsed (rows are shown or hidden).
///
public Action OnExpand;
///
/// Constructs a new GUI list.
///
/// Label to display on the list GUI title.
/// Layout to which to append the array 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 GUIListFieldBase(LocString title, GUILayout layout, int depth)
{
this.title = title;
this.depth = depth;
guiLayout = layout.AddLayoutY();
guiTitleLayout = guiLayout.AddLayoutX();
}
///
/// (Re)builds the list GUI elements. Must be called at least once in order for the contents to be populated.
///
public void BuildGUI(bool force = false)
{
UpdateHeaderGUI();
if (!IsNull())
{
// Hidden dependency: Initialize must be called after all elements are
// in the dictionary so we do it in two steps
int numRows = GetNumRows();
int oldNumRows = rows.Count;
for (int i = oldNumRows; i < numRows; i++)
{
GUIListFieldRow newRow = CreateRow();
rows.Add(newRow);
}
for (int i = oldNumRows - 1; i >= numRows; i--)
{
rows[i].Destroy();
rows.RemoveAt(i);
}
for (int i = oldNumRows; i < numRows; i++)
rows[i].Initialize(this, guiContentLayout, i, depth + 1);
for (int i = 0; i < rows.Count; i++)
rows[i].SetIndex(i);
if(force)
guiSizeField.Value = numRows;
}
else
{
foreach (var row in rows)
row.Destroy();
rows.Clear();
}
}
///
/// Rebuilds the GUI list header if needed.
///
protected void UpdateHeaderGUI()
{
Action BuildEmptyGUI = () =>
{
guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
guiInternalTitleLayout.AddElement(new GUILabel(title));
guiInternalTitleLayout.AddElement(new GUILabel("Empty", GUIOption.FixedWidth(100)));
GUIContent createIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Create),
new LocEdString("Create"));
GUIButton createBtn = new GUIButton(createIcon, GUIOption.FixedWidth(30));
createBtn.OnClick += OnCreateButtonClicked;
guiInternalTitleLayout.AddElement(createBtn);
};
Action BuildFilledGUI = () =>
{
guiInternalTitleLayout = guiTitleLayout.InsertLayoutX(0);
guiFoldout = new GUIToggle(title, EditorStyles.Foldout);
guiFoldout.Value = isExpanded;
guiFoldout.AcceptsKeyFocus = false;
guiFoldout.OnToggled += x => ToggleFoldout(x, false);
guiSizeField = new GUIIntField("", GUIOption.FixedWidth(50));
guiSizeField.SetRange(0, int.MaxValue);
GUIContent resizeIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Resize),
new LocEdString("Resize"));
GUIButton guiResizeBtn = new GUIButton(resizeIcon, GUIOption.FixedWidth(30));
guiResizeBtn.OnClick += OnResizeButtonClicked;
GUIContent clearIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clear),
new LocEdString("Clear"));
GUIButton guiClearBtn = new GUIButton(clearIcon, GUIOption.FixedWidth(30));
guiClearBtn.OnClick += OnClearButtonClicked;
guiInternalTitleLayout.AddElement(guiFoldout);
guiInternalTitleLayout.AddElement(guiSizeField);
guiInternalTitleLayout.AddElement(guiResizeBtn);
guiInternalTitleLayout.AddElement(guiClearBtn);
guiSizeField.Value = GetNumRows();
guiChildLayout = guiLayout.AddLayoutX();
guiChildLayout.AddSpace(IndentAmount);
guiChildLayout.Active = isExpanded;
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
? EditorStylesInternal.InspectorContentBgAlternate
: EditorStylesInternal.InspectorContentBg;
GUIPanel backgroundPanel = guiContentPanel.AddPanel(backgroundDepth);
GUITexture inspectorContentBg = new GUITexture(null, bgPanelStyle);
backgroundPanel.AddElement(inspectorContentBg);
};
if (state == State.None)
{
if (!IsNull())
{
BuildFilledGUI();
state = State.Filled;
}
else
{
BuildEmptyGUI();
state = State.Empty;
}
}
else if (state == State.Empty)
{
if (!IsNull())
{
guiInternalTitleLayout.Destroy();
BuildFilledGUI();
state = State.Filled;
}
}
else if (state == State.Filled)
{
if (IsNull())
{
guiInternalTitleLayout.Destroy();
guiChildLayout.Destroy();
BuildEmptyGUI();
state = State.Empty;
}
}
}
///
/// 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 list rows and checks if anything was modified.
///
/// Forces the GUI fields to display the latest values assigned on the object.
/// State representing was anything modified between two last calls to .
public virtual InspectableState Refresh(bool force)
{
InspectableState state = InspectableState.NotModified;
for (int i = 0; i < rows.Count; i++)
state |= rows[i].Refresh(force);
if (isModified)
{
state |= InspectableState.Modified;
isModified = false;
}
return state;
}
///
/// 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();
rows.Clear();
}
///
/// Creates a new list row GUI.
///
/// Object containing the list row GUI.
protected abstract GUIListFieldRow CreateRow();
///
/// Checks is the list instance not assigned.
///
/// True if there is not a list instance.
protected abstract bool IsNull();
///
/// Returns the number of rows in the list.
///
/// Number of rows in the list.
protected abstract int GetNumRows();
///
/// Gets a value of an element at the specified index in the list.
///
/// Sequential index of the element whose value to retrieve.
/// Value of the list element at the specified index.
protected internal abstract object GetValue(int seqIndex);
///
/// Sets a value of an element at the specified index in the list.
///
/// Sequential index 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(int seqIndex, object value);
///
/// Triggered when the user clicks on the expand/collapse toggle in the title bar.
///
/// Determines whether the contents were expanded or collapsed.
/// True if the foldout was expanded/collapsed from outside code.
private void ToggleFoldout(bool expanded, bool external)
{
isExpanded = expanded;
if (guiChildLayout != null)
guiChildLayout.Active = isExpanded;
if (external)
{
if (guiFoldout != null)
guiFoldout.Value = isExpanded;
}
if (OnExpand != null)
OnExpand(expanded);
}
///
/// Triggered when the user clicks on the create button on the title bar. Creates a brand new list with zero
/// elements in the place of the current list.
///
protected void OnCreateButtonClicked()
{
CreateList();
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the resize button on the title bar. Changes the size of the list while
/// preserving existing contents.
///
protected void OnResizeButtonClicked()
{
ResizeList();
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the clear button on the title bar. Deletes the current list object.
///
protected void OnClearButtonClicked()
{
ClearList();
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the delete button next to a list entry. Deletes an element in the list.
///
/// Sequential index of the element in the list to remove.
protected internal void OnDeleteButtonClicked(int index)
{
DeleteElement(index);
guiSizeField.Value = GetNumRows();
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the clone button next to a list entry. Clones the element and adds the clone
/// to the back of the list.
///
/// Sequential index of the element in the list to clone.
protected internal void OnCloneButtonClicked(int index)
{
CloneElement(index);
guiSizeField.Value = GetNumRows();
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the move up button next to a list entry. Moves an element from the current
/// list index to the one right before it, if not at zero.
///
/// Sequential index of the element in the list to move.
protected internal void OnMoveUpButtonClicked(int index)
{
MoveUpElement(index);
BuildGUI();
isModified = true;
}
///
/// Triggered when the user clicks on the move down button next to a list entry. Moves an element from the current
/// list index to the one right after it, if the element isn't already the last element.
///
/// Sequential index of the element in the list to move.
protected internal void OnMoveDownButtonClicked(int index)
{
MoveDownElement(index);
BuildGUI();
isModified = true;
}
///
/// Creates a brand new list with zero elements in the place of the current list.
///
protected abstract void CreateList();
///
/// Changes the size of the list while preserving existing contents.
///
protected abstract void ResizeList();
///
/// Deletes the current list object.
///
protected abstract void ClearList();
///
/// Deletes an element in the list.
///
/// Sequential index of the element in the list to remove.
protected internal abstract void DeleteElement(int index);
///
/// Clones the element and adds the clone to the back of the list.
///
/// Sequential index of the element in the list to clone.
protected internal abstract void CloneElement(int index);
///
/// Moves an element from the current list index to the one right before it, if not at zero.
///
/// Sequential index of the element in the list to move.
protected internal abstract void MoveUpElement(int index);
///
/// Moves an element from the current list index to the one right after it, if the element isn't already the last
/// element.
///
/// Sequential index of the element in the list to move.
protected internal abstract void MoveDownElement(int index);
///
/// Possible states list GUI can be in.
///
private enum State
{
None,
Empty,
Filled
}
}
///
/// 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 array elements.
///
/// Type of elements stored in the array.
/// Type of rows that are used to handle GUI for individual array elements.
public class GUIArrayField : GUIListFieldBase where RowType : GUIListFieldRow, new()
{
///
/// 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 array has been changed.
///
public Action OnValueChanged;
///
/// Array object whose contents are displayed.
///
public ElementType[] Array { get { return array; } }
protected ElementType[] array;
///
/// Constructs a new GUI array field.
///
/// Label to display on the array GUI title.
/// Object containing the array data. Can be null.
/// Layout to which to append the array 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 GUIArrayField(LocString title, ElementType[] array, GUILayout layout, int depth = 0)
:base(title, layout, depth)
{
this.array = array;
}
///
/// Creates a array GUI field containing GUI elements for displaying an array.
///
/// Label to display on the array GUI title.
/// Object containing the array data. Can be null.
/// Layout to which to append the array 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.
/// New instance of an array GUI field.
public static GUIArrayField Create(LocString title, ElementType[] array, GUILayout layout,
int depth = 0)
{
GUIArrayField guiArray = new GUIArrayField(title, array, layout,
depth);
guiArray.BuildGUI();
return guiArray;
}
///
protected override GUIListFieldRow CreateRow()
{
return new RowType();
}
///
protected override bool IsNull()
{
return array == null;
}
///
protected override int GetNumRows()
{
if (array != null)
return array.GetLength(0);
return 0;
}
///
protected internal override object GetValue(int seqIndex)
{
return array.GetValue(seqIndex);
}
///
protected internal override void SetValue(int seqIndex, object value)
{
array.SetValue(value, seqIndex);
if (OnValueChanged != null)
OnValueChanged();
}
///
protected override void CreateList()
{
array = new ElementType[0];
if (OnChanged != null)
OnChanged(array);
}
///
protected override void ResizeList()
{
int size = guiSizeField.Value;
ElementType[] newArray = new ElementType[size];
int oldSize = array.GetLength(0);
int maxSize = MathEx.Min(size, oldSize);
for (int i = 0; i < maxSize; i++)
newArray.SetValue(array.GetValue(i), i);
array = newArray;
if (OnChanged != null)
OnChanged(array);
}
///
protected override void ClearList()
{
array = null;
if (OnChanged != null)
OnChanged(array);
}
///
protected internal override void DeleteElement(int index)
{
int size = MathEx.Max(0, array.GetLength(0) - 1);
ElementType[] newArray = new ElementType[size];
int destIdx = 0;
for (int i = 0; i < array.GetLength(0); i++)
{
if (i == index)
continue;
newArray.SetValue(array.GetValue(i), destIdx);
destIdx++;
}
array = newArray;
if (OnChanged != null)
OnChanged(array);
}
///
protected internal override void CloneElement(int index)
{
int size = array.GetLength(0) + 1;
ElementType[] newArray = new ElementType[size];
object clonedEntry = null;
for (int i = 0; i < array.GetLength(0); i++)
{
object value = array.GetValue(i);
newArray.SetValue(value, i);
if (i == index)
{
if (value == null)
clonedEntry = null;
else
clonedEntry = SerializableUtility.Clone(value);
}
}
newArray.SetValue(clonedEntry, size - 1);
array = newArray;
if (OnChanged != null)
OnChanged(array);
}
///
protected internal override void MoveUpElement(int index)
{
if ((index - 1) >= 0)
{
object previousEntry = array.GetValue(index - 1);
array.SetValue(array.GetValue(index), index - 1);
array.SetValue(previousEntry, index);
if (OnValueChanged != null)
OnValueChanged();
}
}
///
protected internal override void MoveDownElement(int index)
{
if ((index + 1) < array.GetLength(0))
{
object nextEntry = array.GetValue(index + 1);
array.SetValue(array.GetValue(index), index + 1);
array.SetValue(nextEntry, index);
if (OnValueChanged != null)
OnValueChanged();
}
}
}
///
/// 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 list elements.
///
/// Type of elements stored in the list.
/// Type of rows that are used to handle GUI for individual list elements.
public class GUIListField : GUIListFieldBase where RowType : GUIListFieldRow, new()
{
///
/// Triggered when the reference list 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;
///
/// List object whose contents are displayed.
///
public List List { get { return list; } }
protected List list;
///
/// Constructs a new GUI list field.
///
/// Label to display on the list GUI title.
/// Object containing the list 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.
protected GUIListField(LocString title, List list, GUILayout layout, int depth = 0)
: base(title, layout, depth)
{
this.list = list;
}
///
/// Creates a list GUI field containing GUI elements for displaying a list.
///
/// Label to display on the list GUI title.
/// Object containing the list 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.
/// New instance of a list GUI field.
public static GUIListField Create(LocString title, List list, GUILayout layout,
int depth = 0)
{
GUIListField guiList = new GUIListField(title, list, layout, depth);
guiList.BuildGUI();
return guiList;
}
///
protected override GUIListFieldRow CreateRow()
{
return new RowType();
}
///
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)
{
return list[seqIndex];
}
///
protected internal override void SetValue(int seqIndex, object value)
{
list[seqIndex] = (ElementType)value;
if (OnValueChanged != null)
OnValueChanged();
}
///
protected override void CreateList()
{
list = new List();
if (OnChanged != null)
OnChanged(list);
}
///
protected override void ResizeList()
{
int size = guiSizeField.Value;
if(size == list.Count)
return;
if (size < list.Count)
list.RemoveRange(size, list.Count - size);
else
{
ElementType[] extraElements = new ElementType[size - list.Count];
list.AddRange(extraElements);
}
if (OnValueChanged != null)
OnValueChanged();
}
///
protected override void ClearList()
{
list = null;
if (OnChanged != null)
OnChanged(list);
}
///
protected internal override void DeleteElement(int index)
{
list.RemoveAt(index);
if (OnValueChanged != null)
OnValueChanged();
}
///
protected internal override void CloneElement(int index)
{
object clonedEntry = null;
if (list[index] != null)
clonedEntry = SerializableUtility.Clone(list[index]);
list.Add((ElementType)clonedEntry);
if (OnValueChanged != null)
OnValueChanged();
}
///
protected internal override void MoveUpElement(int index)
{
if ((index - 1) >= 0)
{
ElementType previousEntry = list[index - 1];
list[index - 1] = list[index];
list[index] = previousEntry;
if (OnValueChanged != null)
OnValueChanged();
}
}
///
protected internal override void MoveDownElement(int index)
{
if ((index + 1) < list.Count)
{
ElementType nextEntry = list[index + 1];
list[index + 1] = list[index];
list[index] = nextEntry;
if (OnValueChanged != null)
OnValueChanged();
}
}
}
///
/// Contains GUI elements for a single entry in a list.
///
public abstract class GUIListFieldRow
{
private GUILayoutX rowLayout;
private GUILayoutY contentLayout;
private GUILayoutX titleLayout;
private bool localTitleLayout;
private int seqIndex;
private int depth;
private InspectableState modifiedState;
protected GUIListFieldBase parent;
///
/// Returns the sequential index of the list entry that this row displays.
///
protected int SeqIndex { get { return seqIndex; } }
///
/// Returns the depth at which the row is rendered.
///
protected int Depth { get { return depth; } }
///
/// Constructs a new list row object.
///
protected GUIListFieldRow()
{
}
///
/// Initializes the row and creates 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 list entry.
/// Determines the depth at which the element is rendered.
internal void Initialize(GUIListFieldBase parent, GUILayout parentLayout, int seqIndex, int depth)
{
this.parent = parent;
this.seqIndex = seqIndex;
this.depth = depth;
rowLayout = parentLayout.AddLayoutX();
contentLayout = rowLayout.AddLayoutY();
BuildGUI();
}
///
/// Changes the index of the list element this row represents.
///
/// Sequential index of the list entry.
internal void SetIndex(int seqIndex)
{
this.seqIndex = seqIndex;
}
///
/// (Re)creates all row GUI elements.
///
internal protected void BuildGUI()
{
contentLayout.Clear();
GUILayoutX externalTitleLayout = CreateGUI(contentLayout);
if (localTitleLayout || (titleLayout != null && titleLayout == externalTitleLayout))
return;
if (externalTitleLayout != null)
{
localTitleLayout = false;
titleLayout = externalTitleLayout;
}
else
{
GUILayoutY buttonCenter = rowLayout.AddLayoutY();
buttonCenter.AddFlexibleSpace();
titleLayout = buttonCenter.AddLayoutX();
buttonCenter.AddFlexibleSpace();
localTitleLayout = true;
}
GUIContent cloneIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Clone),
new LocEdString("Clone"));
GUIContent deleteIcon = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.Delete),
new LocEdString("Delete"));
GUIContent moveUp = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveUp),
new LocEdString("Move up"));
GUIContent moveDown = new GUIContent(EditorBuiltin.GetInspectorWindowIcon(InspectorWindowIcon.MoveDown),
new LocEdString("Move down"));
GUIButton cloneBtn = new GUIButton(cloneIcon, GUIOption.FixedWidth(30));
GUIButton deleteBtn = new GUIButton(deleteIcon, GUIOption.FixedWidth(30));
GUIButton moveUpBtn = new GUIButton(moveUp, GUIOption.FixedWidth(30));
GUIButton moveDownBtn = new GUIButton(moveDown, GUIOption.FixedWidth(30));
cloneBtn.OnClick += () => parent.OnCloneButtonClicked(seqIndex);
deleteBtn.OnClick += () => parent.OnDeleteButtonClicked(seqIndex);
moveUpBtn.OnClick += () => parent.OnMoveUpButtonClicked(seqIndex);
moveDownBtn.OnClick += () => parent.OnMoveDownButtonClicked(seqIndex);
titleLayout.AddElement(cloneBtn);
titleLayout.AddElement(deleteBtn);
titleLayout.AddElement(moveUpBtn);
titleLayout.AddElement(moveDownBtn);
}
///
/// Creates GUI elements specific to type in the array row.
///
/// Layout to insert the row GUI elements to.
/// An optional title bar layout that the standard array buttons will be appended to.
protected abstract GUILayoutX CreateGUI(GUILayoutY layout);
///
/// Refreshes the GUI for the list row and checks if anything was modified.
///
/// Forces the GUI fields to display the latest values assigned on the object.
/// State representing was anything modified between two last calls to .
protected internal virtual InspectableState Refresh(bool force)
{
InspectableState oldState = modifiedState;
if (modifiedState.HasFlag(InspectableState.Modified))
modifiedState = InspectableState.NotModified;
return oldState;
}
///
/// Marks the contents of the row as modified.
///
protected void MarkAsModified()
{
modifiedState |= InspectableState.ModifyInProgress;
}
///
/// Confirms any queued modifications, signaling parent elements.
///
protected void ConfirmModify()
{
if (modifiedState.HasFlag(InspectableState.ModifyInProgress))
modifiedState |= InspectableState.Modified;
}
///
/// Gets the value contained in this list row.
///
/// Type of the value. Must match the list's element type.
/// Value in this list row.
protected T GetValue()
{
return (T)parent.GetValue(seqIndex);
}
///
/// Sets the value contained in this list row.
///
/// Type of the value. Must match the list's element type.
/// Value to set.
protected void SetValue(T value)
{
parent.SetValue(seqIndex, value);
}
///
/// Destroys all row GUI elements.
///
public void Destroy()
{
if (rowLayout != null)
{
rowLayout.Destroy();
rowLayout = null;
}
contentLayout = null;
titleLayout = null;
localTitleLayout = false;
}
}
/** @} */
}