SerializableField.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Runtime.CompilerServices;
  5. namespace BansheeEngine
  6. {
  7. /** @addtogroup Serialization
  8. * @{
  9. */
  10. /// <summary>
  11. /// Flags that are used to define properties of a single field in a managed object.
  12. /// </summary>
  13. public enum SerializableFieldAttributes // Note: Must match C++ enum ScriptFieldFlags
  14. {
  15. /// <summary>
  16. /// Field will be automatically serialized.
  17. /// </summary>
  18. Serializable = 1 << 0,
  19. /// <summary>
  20. /// Field will be visible in the default inspector.
  21. /// </summary>
  22. Inspectable = 1 << 1,
  23. /// <summary>
  24. /// Integer or floating point field with min/max range.
  25. /// </summary>
  26. Ranged = 1 << 2,
  27. /// <summary>
  28. /// Integer or floating point field with a minimum increment/decrement step.
  29. /// </summary>
  30. Stepped = 1 << 3,
  31. /// <summary>
  32. /// Field can be animated through the animation window.
  33. /// </summary>
  34. Animable = 1 << 4,
  35. /// <summary>
  36. /// Integer field rendered as a layer selection dropdown.
  37. /// </summary>
  38. LayerMask = 1 << 5,
  39. /// <summary>
  40. /// Field containing a reference type being passed by copy instead of by reference.
  41. /// </summary>
  42. PassByCopy = 1 << 6,
  43. /// <summary>
  44. /// Field containing a reference type that should never be null.
  45. /// </summary>
  46. NotNull = 1 << 7,
  47. /// <summary>
  48. /// Field represents a property that wraps a native object. Getters and setters of such a property issue calls into
  49. /// native code to update the native object.
  50. /// </summary>
  51. NativeWrapper = 1 << 8,
  52. /// <summary>
  53. /// When a field changes those changes need to be applied to the parent object by calling the field setter. Only
  54. /// applicable to properties containing reference types.
  55. /// </summary>
  56. ApplyOnDirty = 1 << 9,
  57. /// <summary>
  58. /// When a quaternion is displayed in the inspector, by default it will be displayed as converted into euler angles.
  59. /// Use this flag to force it to be displayed as a quaternion (4D value) with no conversion instead.
  60. /// </summary>
  61. DisplayAsQuaternion = 1 << 10
  62. }
  63. /// <summary>
  64. /// Allows you to access meta-data about field in an object. Similar to Reflection but simpler and faster.
  65. /// </summary>
  66. public class SerializableField : ScriptObject
  67. {
  68. private SerializableObject parent;
  69. private SerializableProperty.FieldType type;
  70. private int flags;
  71. private Type internalType;
  72. private string name;
  73. /// <summary>
  74. /// Constructor for internal use by the runtime.
  75. /// </summary>
  76. /// <param name="parent">Object that conains the field.</param>
  77. /// <param name="name">Name of the field.</param>
  78. /// <param name="flags">Flags that control whether the field is inspectable or serializable.</param>
  79. /// <param name="internalType">Internal C# type of the field.</param>
  80. private SerializableField(SerializableObject parent, string name, int flags, Type internalType)
  81. {
  82. this.parent = parent;
  83. this.name = name;
  84. this.flags = flags;
  85. this.type = SerializableProperty.DetermineFieldType(internalType);
  86. this.internalType = internalType;
  87. }
  88. public SerializableFieldAttributes Flags
  89. {
  90. get { return (SerializableFieldAttributes) flags; }
  91. }
  92. /// <summary>
  93. /// Returns the type of data contained in the field.
  94. /// </summary>
  95. public SerializableProperty.FieldType Type
  96. {
  97. get { return type; }
  98. }
  99. /// <summary>
  100. /// Returns the actual type of the object contained in the field.
  101. /// </summary>
  102. public Type InternalType
  103. {
  104. get { return internalType; }
  105. }
  106. /// <summary>
  107. /// Returns the name of the field.
  108. /// </summary>
  109. public string Name
  110. {
  111. get { return name; }
  112. }
  113. /// <summary>
  114. /// Returns the requested style of the field, that may be used for controlling how the field is displayed and how
  115. /// is its input filtered.
  116. /// </summary>
  117. public SerializableFieldStyle Style
  118. {
  119. get
  120. {
  121. SerializableFieldStyle style;
  122. Internal_GetStyle(mCachedPtr, out style);
  123. return style;
  124. }
  125. }
  126. /// <summary>
  127. /// Returns a serializable property for the field.
  128. /// </summary>
  129. /// <returns>Serializable property that allows you to manipulate contents of the field.</returns>
  130. public SerializableProperty GetProperty()
  131. {
  132. SerializableProperty.Getter getter = () =>
  133. {
  134. object parentObject = parent.GetReferencedObject();
  135. if (parentObject != null)
  136. return Internal_GetValue(mCachedPtr, parentObject);
  137. else
  138. return null;
  139. };
  140. bool applyOnChange = Flags.HasFlag(SerializableFieldAttributes.ApplyOnDirty) ||
  141. Flags.HasFlag(SerializableFieldAttributes.PassByCopy);
  142. SerializableProperty.Setter setter = (object value) =>
  143. {
  144. object parentObject = parent.GetReferencedObject();
  145. if (parentObject != null)
  146. {
  147. Internal_SetValue(mCachedPtr, parentObject, value);
  148. // If value type we cannot just modify the parent object because it's just a copy
  149. if ((applyOnChange || parentObject.GetType().IsValueType) && parent.parentProperty != null)
  150. parent.parentProperty.SetValue(parentObject);
  151. }
  152. };
  153. SerializableProperty newProperty = Internal_CreateProperty(mCachedPtr);
  154. newProperty.Construct(type, internalType, getter, setter);
  155. return newProperty;
  156. }
  157. [MethodImpl(MethodImplOptions.InternalCall)]
  158. private static extern SerializableProperty Internal_CreateProperty(IntPtr nativeInstance);
  159. [MethodImpl(MethodImplOptions.InternalCall)]
  160. private static extern object Internal_GetValue(IntPtr nativeInstance, object instance);
  161. [MethodImpl(MethodImplOptions.InternalCall)]
  162. private static extern void Internal_SetValue(IntPtr nativeInstance, object instance, object value);
  163. [MethodImpl(MethodImplOptions.InternalCall)]
  164. private static extern void Internal_GetStyle(IntPtr nativeInstance, out SerializableFieldStyle style);
  165. }
  166. /// <summary>
  167. /// Contains information about a style of a serializable field.
  168. /// </summary>
  169. public struct SerializableFieldStyle // Note: Must match C++ struct SerializableMemberStyle
  170. {
  171. /// <summary>
  172. /// True if the range of the field is limited, false if unlimited.
  173. /// </summary>
  174. public bool HasRange;
  175. /// <summary>
  176. /// Returns the lower bound of the range. Only relevant if <see cref="HasRange"/> is true.
  177. /// </summary>
  178. public float RangeMin;
  179. /// <summary>
  180. /// Returns the upper bound of the range. Only relevant if <see cref="HasRange"/> is true.
  181. /// </summary>
  182. public float RangeMax;
  183. /// <summary>
  184. /// True if the field value can only be incremented in specific increments.
  185. /// </summary>
  186. public bool HasStep;
  187. /// <summary>
  188. /// Minimum increment the field value can be increment/decremented by. Only relevant if <see cref="HasStep"/> is true.
  189. /// </summary>
  190. public float StepIncrement;
  191. /// <summary>
  192. /// If true, number fields will be displayed as sliders instead of regular input boxes.
  193. /// </summary>
  194. public bool DisplayAsSlider;
  195. /// <summary>
  196. /// If true, 64-bit fields will be displayed as a layer mask drop down menu.
  197. /// </summary>
  198. public bool DisplayAsLayerMask;
  199. }
  200. /** @} */
  201. }