InspectableList.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using BansheeEngine;
  7. namespace BansheeEditor
  8. {
  9. /** @addtogroup Inspector
  10. * @{
  11. */
  12. /// <summary>
  13. /// Displays GUI for a serializable property containing a list. List contents are displayed as rows of entries
  14. /// that can be shown, hidden or manipulated.
  15. /// </summary>
  16. public class InspectableList : InspectableField
  17. {
  18. private InspectableListGUI listGUIField;
  19. /// <summary>
  20. /// Creates a new inspectable list GUI for the specified property.
  21. /// </summary>
  22. /// <param name="parent">Parent Inspector this field belongs to.</param>
  23. /// <param name="title">Name of the property, or some other value to set as the title.</param>
  24. /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
  25. /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
  26. /// contain other fields, in which case you should increase this value by one.</param>
  27. /// <param name="layout">Parent layout that all the field elements will be added to.</param>
  28. /// <param name="property">Serializable property referencing the list whose contents to display.</param>
  29. public InspectableList(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
  30. SerializableProperty property)
  31. : base(parent, title, path, SerializableProperty.FieldType.List, depth, layout, property)
  32. {
  33. }
  34. /// <inheritdoc/>
  35. public override GUILayoutX GetTitleLayout()
  36. {
  37. return listGUIField.GetTitleLayout();
  38. }
  39. /// <inheritdoc/>
  40. public override InspectableState Refresh(int layoutIndex)
  41. {
  42. return listGUIField.Refresh();
  43. }
  44. /// <inheritdoc/>
  45. protected internal override void Initialize(int layoutIndex)
  46. {
  47. GUILayout arrayLayout = layout.AddLayoutY(layoutIndex);
  48. listGUIField = InspectableListGUI.Create(parent, title, path, property, arrayLayout, depth);
  49. listGUIField.IsExpanded = parent.Persistent.GetBool(path + "_Expanded");
  50. listGUIField.OnExpand += x => parent.Persistent.SetBool(path + "_Expanded", x);
  51. }
  52. /// <summary>
  53. /// Handles creation of GUI elements for a GUI list field that displays a <see cref="SerializableList"/> object.
  54. /// </summary>
  55. private class InspectableListGUI : GUIListFieldBase
  56. {
  57. private IList list;
  58. private int numElements;
  59. private Inspector parent;
  60. private SerializableProperty property;
  61. private string path;
  62. /// <summary>
  63. /// Returns the parent inspector the array GUI belongs to.
  64. /// </summary>
  65. public Inspector Inspector
  66. {
  67. get { return parent; }
  68. }
  69. /// <summary>
  70. /// Returns a property path to the array field (name of the array field and all parent object fields).
  71. /// </summary>
  72. public string Path
  73. {
  74. get { return path; }
  75. }
  76. /// <summary>
  77. /// Constructs a new empty inspectable list GUI.
  78. /// </summary>
  79. /// <param name="parent">Parent Inspector this field belongs to.</param>
  80. /// <param name="title">Label to display on the list GUI title.</param>
  81. /// <param name="path">Full path to this property (includes name of this property and all parent properties).
  82. /// </param>
  83. /// <param name="property">Serializable property referencing a list.</param>
  84. /// <param name="layout">Layout to which to append the list GUI elements to.</param>
  85. /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
  86. /// nested containers whose backgrounds are overlaping. Also determines background style,
  87. /// depths divisible by two will use an alternate style.</param>
  88. public InspectableListGUI(Inspector parent, LocString title, string path, SerializableProperty property,
  89. GUILayout layout, int depth)
  90. : base(title, layout, depth)
  91. {
  92. this.property = property;
  93. this.parent = parent;
  94. this.path = path;
  95. list = property.GetValue<IList>();
  96. if (list != null)
  97. numElements = list.Count;
  98. }
  99. /// <summary>
  100. /// Creates a new inspectable list GUI object that displays the contents of the provided serializable property.
  101. /// </summary>
  102. /// <param name="parent">Parent Inspector this field belongs to.</param>
  103. /// <param name="title">Label to display on the list GUI title.</param>
  104. /// <param name="path">Full path to this property (includes name of this property and all parent properties).
  105. /// </param>
  106. /// <param name="property">Serializable property referencing a list.</param>
  107. /// <param name="layout">Layout to which to append the list GUI elements to.</param>
  108. /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple
  109. /// nested containers whose backgrounds are overlaping. Also determines background style,
  110. /// depths divisible by two will use an alternate style.</param>
  111. public static InspectableListGUI Create(Inspector parent, LocString title, string path,
  112. SerializableProperty property, GUILayout layout, int depth)
  113. {
  114. InspectableListGUI listGUI = new InspectableListGUI(parent, title, path, property, layout, depth);
  115. listGUI.BuildGUI();
  116. return listGUI;
  117. }
  118. /// <inheritdoc/>
  119. public override InspectableState Refresh()
  120. {
  121. // Check if any modifications to the array were made outside the inspector
  122. IList newList = property.GetValue<IList>();
  123. if (list == null && newList != null)
  124. {
  125. list = newList;
  126. numElements = list.Count;
  127. BuildGUI();
  128. }
  129. else if (newList == null && list != null)
  130. {
  131. list = null;
  132. numElements = 0;
  133. BuildGUI();
  134. }
  135. else
  136. {
  137. if (list != null)
  138. {
  139. if (numElements != list.Count)
  140. {
  141. numElements = list.Count;
  142. BuildGUI();
  143. }
  144. }
  145. }
  146. return base.Refresh();
  147. }
  148. /// <inheritdoc/>
  149. protected override GUIListFieldRow CreateRow()
  150. {
  151. return new InspectableListGUIRow();
  152. }
  153. /// <inheritdoc/>
  154. protected override bool IsNull()
  155. {
  156. return list == null;
  157. }
  158. /// <inheritdoc/>
  159. protected override int GetNumRows()
  160. {
  161. if (list != null)
  162. return list.Count;
  163. return 0;
  164. }
  165. /// <inheritdoc/>
  166. protected internal override object GetValue(int seqIndex)
  167. {
  168. SerializableList list = property.GetList();
  169. return list.GetProperty(seqIndex);
  170. }
  171. /// <inheritdoc/>
  172. protected internal override void SetValue(int seqIndex, object value)
  173. {
  174. // Setting the value should be done through the property
  175. throw new InvalidOperationException();
  176. }
  177. /// <inheritdoc/>
  178. protected override void CreateList()
  179. {
  180. list = property.CreateListInstance(0);
  181. property.SetValue(list);
  182. numElements = 0;
  183. }
  184. /// <inheritdoc/>
  185. protected override void ResizeList()
  186. {
  187. int size = guiSizeField.Value;
  188. IList newList = property.CreateListInstance(size);
  189. int maxSize = MathEx.Min(size, list.Count);
  190. for (int i = 0; i < maxSize; i++)
  191. newList[i] = list[i];
  192. property.SetValue(newList);
  193. list = newList;
  194. numElements = list.Count;
  195. }
  196. /// <inheritdoc/>
  197. protected override void ClearList()
  198. {
  199. property.SetValue<object>(null);
  200. list = null;
  201. numElements = 0;
  202. }
  203. /// <inheritdoc/>
  204. protected internal override void DeleteElement(int index)
  205. {
  206. if (index >= 0 && index < list.Count)
  207. list.RemoveAt(index);
  208. numElements = list.Count;
  209. }
  210. /// <inheritdoc/>
  211. protected internal override void CloneElement(int index)
  212. {
  213. SerializableList serializableList = property.GetList();
  214. if (index >= 0 && index < list.Count)
  215. list.Add(SerializableUtility.Clone(serializableList.GetProperty(index).GetValue<object>()));
  216. numElements = list.Count;
  217. }
  218. /// <inheritdoc/>
  219. protected internal override void MoveUpElement(int index)
  220. {
  221. if ((index - 1) >= 0)
  222. {
  223. object previousEntry = list[index - 1];
  224. list[index - 1] = list[index];
  225. list[index] = previousEntry;
  226. }
  227. }
  228. /// <inheritdoc/>
  229. protected internal override void MoveDownElement(int index)
  230. {
  231. if ((index + 1) < list.Count)
  232. {
  233. object nextEntry = list[index + 1];
  234. list[index + 1] = list[index];
  235. list[index] = nextEntry;
  236. }
  237. }
  238. }
  239. /// <summary>
  240. /// Contains GUI elements for a single entry in the list.
  241. /// </summary>
  242. private class InspectableListGUIRow : GUIListFieldRow
  243. {
  244. private InspectableField field;
  245. /// <inheritdoc/>
  246. protected override GUILayoutX CreateGUI(GUILayoutY layout)
  247. {
  248. InspectableListGUI listParent = (InspectableListGUI)parent;
  249. SerializableProperty property = GetValue<SerializableProperty>();
  250. string entryPath = listParent.Path + "[" + SeqIndex + "]";
  251. field = CreateInspectable(listParent.Inspector, SeqIndex + ".", entryPath, 0, Depth + 1,
  252. new InspectableFieldLayout(layout), property, new InspectableFieldStyleInfo());
  253. return field.GetTitleLayout();
  254. }
  255. /// <inheritdoc/>
  256. protected internal override InspectableState Refresh()
  257. {
  258. field.Property = GetValue<SerializableProperty>();
  259. return field.Refresh(0);
  260. }
  261. }
  262. }
  263. /** @} */
  264. }