InspectableField.cs 10.0 KB

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