InspectableField.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Linq;
  5. using BansheeEngine;
  6. namespace BansheeEditor
  7. {
  8. /** @addtogroup Inspector
  9. * @{
  10. */
  11. /// <summary>
  12. /// Inspectable field displays GUI elements for a single <see cref="SerializableProperty"/>. This is a base class that
  13. /// should be specialized for all supported types contained by <see cref="SerializableProperty"/>. Inspectable fields
  14. /// can and should be created recursively - normally complex types like objects and arrays will contain fields of their
  15. /// own, while primitive types like integer or boolean will consist of only a GUI element.
  16. /// </summary>
  17. public abstract class InspectableField
  18. {
  19. protected Inspector parent;
  20. protected InspectableFieldLayout layout;
  21. protected SerializableProperty property;
  22. protected string title;
  23. protected string path;
  24. protected int depth;
  25. protected SerializableProperty.FieldType type;
  26. /// <summary>
  27. /// Property this field is displaying contents of.
  28. /// </summary>
  29. public SerializableProperty Property
  30. {
  31. get { return property; }
  32. set
  33. {
  34. if (value == null)
  35. throw new ArgumentException("Cannot assign a null property to an inspectable field.");
  36. if (value.Type != type)
  37. {
  38. throw new ArgumentException(
  39. "Attempting to initialize an inspectable field with a property of invalid type.");
  40. }
  41. property = value;
  42. }
  43. }
  44. /// <summary>
  45. /// Creates a new inspectable field GUI for the specified property.
  46. /// </summary>
  47. /// <param name="parent">Parent Inspector this field belongs to.</param>
  48. /// <param name="title">Name of the property, or some other value to set as the title.</param>
  49. /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
  50. /// <param name="type">Type of property this field will be used for displaying.</param>
  51. /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
  52. /// contain other fields, in which case you should increase this value by one.</param>
  53. /// <param name="layout">Parent layout that all the field elements will be added to.</param>
  54. /// <param name="property">Serializable property referencing the array whose contents to display.</param>
  55. public InspectableField(Inspector parent, string title, string path, SerializableProperty.FieldType type,
  56. int depth, InspectableFieldLayout layout, SerializableProperty property)
  57. {
  58. this.parent = parent;
  59. this.layout = layout;
  60. this.title = title;
  61. this.path = path;
  62. this.type = type;
  63. this.depth = depth;
  64. Property = property;
  65. }
  66. /// <summary>
  67. /// Checks if contents of the field have been modified, and updates them if needed.
  68. /// </summary>
  69. /// <param name="layoutIndex">Index in the parent's layout at which to insert the GUI elements for this field.
  70. /// </param>
  71. /// <returns>State representing was anything modified between two last calls to <see cref="Refresh"/>.</returns>
  72. public virtual InspectableState Refresh(int layoutIndex)
  73. {
  74. return InspectableState.NotModified;
  75. }
  76. /// <summary>
  77. /// Returns the total number of GUI elements in the field's layout.
  78. /// </summary>
  79. /// <returns>Number of GUI elements in the field's layout.</returns>
  80. public int GetNumLayoutElements()
  81. {
  82. return layout.NumElements;
  83. }
  84. /// <summary>
  85. /// Returns an optional title layout. Certain fields may contain separate title and content layouts. Parent fields
  86. /// may use the separate title layout instead of the content layout to append elements. Having a separate title
  87. /// layout is purely cosmetical.
  88. /// </summary>
  89. /// <returns>Title layout if the field has one, null otherwise.</returns>
  90. public virtual GUILayoutX GetTitleLayout()
  91. {
  92. return null;
  93. }
  94. /// <summary>
  95. /// Initializes the GUI elements for the field.
  96. /// </summary>
  97. /// <param name="layoutIndex">Index at which to insert the GUI elements.</param>
  98. protected internal abstract void Initialize(int layoutIndex);
  99. /// <summary>
  100. /// Destroys all GUI elements in the inspectable field.
  101. /// </summary>
  102. public virtual void Destroy()
  103. {
  104. layout.DestroyElements();
  105. }
  106. /// <summary>
  107. /// Creates a new inspectable field, automatically detecting the most appropriate implementation for the type
  108. /// contained in the provided serializable property. This may be one of the built-in inspectable field implemetations
  109. /// (like ones for primitives like int or bool), or a user defined implementation defined with a
  110. /// <see cref="CustomInspector"/> attribute.
  111. /// </summary>
  112. /// <param name="parent">Parent Inspector this field belongs to.</param>
  113. /// <param name="title">Name of the property, or some other value to set as the title.</param>
  114. /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
  115. /// <param name="layoutIndex">Index into the parent layout at which to insert the GUI elements for the field .</param>
  116. /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
  117. /// contain other fields, in which case you should increase this value by one.</param>
  118. /// <param name="layout">Parent layout that all the field elements will be added to.</param>
  119. /// <param name="property">Serializable property referencing the array whose contents to display.</param>
  120. /// <param name="style">Information related the field style</param>
  121. /// <returns>Inspectable field implementation that can be used for displaying the GUI for a serializable property
  122. /// of the provided type.</returns>
  123. public static InspectableField CreateInspectable(Inspector parent, string title, string path, int layoutIndex,
  124. int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyle[] style = null)
  125. {
  126. InspectableField field = null;
  127. Type customInspectable = InspectorUtility.GetCustomInspectable(property.InternalType);
  128. if (customInspectable != null)
  129. {
  130. field = (InspectableField) Activator.CreateInstance(customInspectable, depth, title, property);
  131. }
  132. else
  133. {
  134. InspectableFieldRangeStyle rangeInfo = null;
  135. if (style != null)
  136. rangeInfo = InspectableFieldStyle.FindStyle<InspectableFieldRangeStyle>(style);
  137. switch (property.Type)
  138. {
  139. case SerializableProperty.FieldType.Int:
  140. if (rangeInfo == null)
  141. {
  142. field = new InspectableInt(parent, title, path, depth, layout, property);
  143. }
  144. else
  145. {
  146. field = new InspectableRangedInt(parent, title, path, depth, layout, property, rangeInfo);
  147. }
  148. break;
  149. case SerializableProperty.FieldType.Float:
  150. if (rangeInfo == null)
  151. {
  152. field = new InspectableFloat(parent, title, path, depth, layout, property);
  153. }
  154. else
  155. {
  156. field = new InspectableRangedFloat(parent, title, path, depth, layout, property, rangeInfo);
  157. }
  158. break;
  159. case SerializableProperty.FieldType.Bool:
  160. field = new InspectableBool(parent, title, path, depth, layout, property);
  161. break;
  162. case SerializableProperty.FieldType.Color:
  163. field = new InspectableColor(parent, title, path, depth, layout, property);
  164. break;
  165. case SerializableProperty.FieldType.String:
  166. field = new InspectableString(parent, title, path, depth, layout, property);
  167. break;
  168. case SerializableProperty.FieldType.Vector2:
  169. field = new InspectableVector2(parent, title, path, depth, layout, property);
  170. break;
  171. case SerializableProperty.FieldType.Vector3:
  172. field = new InspectableVector3(parent, title, path, depth, layout, property);
  173. break;
  174. case SerializableProperty.FieldType.Vector4:
  175. field = new InspectableVector4(parent, title, path, depth, layout, property);
  176. break;
  177. case SerializableProperty.FieldType.ResourceRef:
  178. field = new InspectableResourceRef(parent, title, path, depth, layout, property);
  179. break;
  180. case SerializableProperty.FieldType.GameObjectRef:
  181. field = new InspectableGameObjectRef(parent, title, path, depth, layout, property);
  182. break;
  183. case SerializableProperty.FieldType.Object:
  184. field = new InspectableObject(parent, title, path, depth, layout, property);
  185. break;
  186. case SerializableProperty.FieldType.Array:
  187. field = new InspectableArray(parent, title, path, depth, layout, property);
  188. break;
  189. case SerializableProperty.FieldType.List:
  190. field = new InspectableList(parent, title, path, depth, layout, property);
  191. break;
  192. case SerializableProperty.FieldType.Dictionary:
  193. field = new InspectableDictionary(parent, title, path, depth, layout, property);
  194. break;
  195. }
  196. }
  197. if (field == null)
  198. throw new Exception("No inspector exists for the provided field type.");
  199. field.Initialize(layoutIndex);
  200. field.Refresh(layoutIndex);
  201. return field;
  202. }
  203. }
  204. /** @} */
  205. }