FieldFactory.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UIElements;
  5. using UnityEditor.UIElements;
  6. using System;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Globalization;
  10. namespace GraphProcessor
  11. {
  12. [Obsolete("Field Factory is not necessary anymore. You can use a SerializedProperty directly instead.")]
  13. public static class FieldFactory
  14. {
  15. static readonly Dictionary< Type, Type > fieldDrawers = new Dictionary< Type, Type >();
  16. static readonly MethodInfo createFieldMethod = typeof(FieldFactory).GetMethod("CreateFieldSpecific", BindingFlags.Static | BindingFlags.Public);
  17. static FieldFactory()
  18. {
  19. foreach (var type in AppDomain.CurrentDomain.GetAllTypes())
  20. {
  21. var drawerAttribute = type.GetCustomAttributes(typeof(FieldDrawerAttribute), false).FirstOrDefault() as FieldDrawerAttribute;
  22. if (drawerAttribute == null)
  23. continue ;
  24. AddDrawer(drawerAttribute.fieldType, type);
  25. }
  26. // щ(ºДºщ) ...
  27. AddDrawer(typeof(bool), typeof(Toggle));
  28. AddDrawer(typeof(int), typeof(IntegerField));
  29. AddDrawer(typeof(long), typeof(LongField));
  30. AddDrawer(typeof(float), typeof(FloatField));
  31. AddDrawer(typeof(double), typeof(DoubleField));
  32. AddDrawer(typeof(string), typeof(TextField));
  33. AddDrawer(typeof(Bounds), typeof(BoundsField));
  34. AddDrawer(typeof(Color), typeof(ColorField));
  35. AddDrawer(typeof(Vector2), typeof(Vector2Field));
  36. AddDrawer(typeof(Vector2Int), typeof(Vector2IntField));
  37. AddDrawer(typeof(Vector3), typeof(Vector3Field));
  38. AddDrawer(typeof(Vector3Int), typeof(Vector3IntField));
  39. AddDrawer(typeof(Vector4), typeof(Vector4Field));
  40. AddDrawer(typeof(AnimationCurve), typeof(CurveField));
  41. AddDrawer(typeof(Enum), typeof(EnumField));
  42. AddDrawer(typeof(Gradient), typeof(GradientField));
  43. AddDrawer(typeof(UnityEngine.Object), typeof(ObjectField));
  44. AddDrawer(typeof(Rect), typeof(RectField));
  45. }
  46. static void AddDrawer(Type fieldType, Type drawerType)
  47. {
  48. var iNotifyType = typeof(INotifyValueChanged<>).MakeGenericType(fieldType);
  49. if (!iNotifyType.IsAssignableFrom(drawerType))
  50. {
  51. Debug.LogWarning("The custom field drawer " + drawerType + " does not implements INotifyValueChanged< " + fieldType + " >");
  52. return ;
  53. }
  54. fieldDrawers[fieldType] = drawerType;
  55. }
  56. public static INotifyValueChanged< T > CreateField< T >(T value, string label = null)
  57. {
  58. return CreateField(value != null ? value.GetType() : typeof(T), label) as INotifyValueChanged< T >;
  59. }
  60. public static VisualElement CreateField(Type t, string label)
  61. {
  62. Type drawerType;
  63. fieldDrawers.TryGetValue(t, out drawerType);
  64. if (drawerType == null)
  65. drawerType = fieldDrawers.FirstOrDefault(kp => kp.Key.IsReallyAssignableFrom(t)).Value;
  66. if (drawerType == null)
  67. {
  68. Debug.LogWarning("Can't find field drawer for type: " + t);
  69. return null;
  70. }
  71. // Call the constructor that have a label
  72. object field;
  73. if (drawerType == typeof(EnumField))
  74. {
  75. field = new EnumField(label, Activator.CreateInstance(t) as Enum);
  76. }
  77. else
  78. {
  79. try {
  80. field = Activator.CreateInstance(drawerType,
  81. BindingFlags.CreateInstance |
  82. BindingFlags.Public |
  83. BindingFlags.NonPublic |
  84. BindingFlags.Instance |
  85. BindingFlags.OptionalParamBinding, null,
  86. new object[]{ label, Type.Missing }, CultureInfo.CurrentCulture);
  87. } catch {
  88. field = Activator.CreateInstance(drawerType,
  89. BindingFlags.CreateInstance |
  90. BindingFlags.Public |
  91. BindingFlags.NonPublic |
  92. BindingFlags.Instance |
  93. BindingFlags.OptionalParamBinding, null,
  94. new object[]{ label }, CultureInfo.CurrentCulture);
  95. }
  96. }
  97. // For mutiline
  98. switch (field)
  99. {
  100. case TextField textField:
  101. textField.multiline = true;
  102. break;
  103. case ObjectField objField:
  104. objField.allowSceneObjects = true;
  105. objField.objectType = typeof(UnityEngine.Object);
  106. break;
  107. }
  108. return field as VisualElement;
  109. }
  110. public static INotifyValueChanged< T > CreateFieldSpecific< T >(T value, Action< object > onValueChanged, string label)
  111. {
  112. var fieldDrawer = CreateField< T >(value, label);
  113. if (fieldDrawer == null)
  114. return null;
  115. fieldDrawer.value = value;
  116. fieldDrawer.RegisterValueChangedCallback((e) => {
  117. onValueChanged(e.newValue);
  118. });
  119. return fieldDrawer as INotifyValueChanged< T >;
  120. }
  121. public static VisualElement CreateField(Type fieldType, object value, Action< object > onValueChanged, string label)
  122. {
  123. if (typeof(Enum).IsAssignableFrom(fieldType))
  124. fieldType = typeof(Enum);
  125. VisualElement field = null;
  126. // Handle special cases here
  127. if (fieldType == typeof(LayerMask))
  128. {
  129. // LayerMasks inherit from INotifyValueChanged<int> instead of INotifyValueChanged<LayerMask>
  130. // so we can't register it inside our factory system :(
  131. var layerField = new LayerMaskField(label, ((LayerMask)value).value);
  132. layerField.RegisterValueChangedCallback(e => {
  133. onValueChanged(new LayerMask{ value = e.newValue});
  134. });
  135. field = layerField;
  136. }
  137. else
  138. {
  139. try
  140. {
  141. var createFieldSpecificMethod = createFieldMethod.MakeGenericMethod(fieldType);
  142. try
  143. {
  144. field = createFieldSpecificMethod.Invoke(null, new object[]{value, onValueChanged, label}) as VisualElement;
  145. } catch {}
  146. // handle the Object field case
  147. if (field == null && (value == null || value is UnityEngine.Object))
  148. {
  149. createFieldSpecificMethod = createFieldMethod.MakeGenericMethod(typeof(UnityEngine.Object));
  150. field = createFieldSpecificMethod.Invoke(null, new object[]{value, onValueChanged, label}) as VisualElement;
  151. if (field is ObjectField objField)
  152. {
  153. objField.objectType = fieldType;
  154. objField.value = value as UnityEngine.Object;
  155. }
  156. }
  157. }
  158. catch (Exception e)
  159. {
  160. Debug.LogError(e);
  161. }
  162. }
  163. return field;
  164. }
  165. }
  166. }