InspectableField.cs 12 KB

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