InspectableField.cs 9.0 KB

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