설명 없음
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PrimitiveVectorDrawer.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System;
  2. using UnityEditor;
  3. using UnityEngine;
  4. namespace Unity.Mathematics.Editor
  5. {
  6. [CustomPropertyDrawer(typeof(bool2)), CustomPropertyDrawer(typeof(bool3)), CustomPropertyDrawer(typeof(bool4))]
  7. [CustomPropertyDrawer(typeof(double2)), CustomPropertyDrawer(typeof(double3)), CustomPropertyDrawer(typeof(double4))]
  8. [CustomPropertyDrawer(typeof(float2)), CustomPropertyDrawer(typeof(float3)), CustomPropertyDrawer(typeof(float4))]
  9. [CustomPropertyDrawer(typeof(int2)), CustomPropertyDrawer(typeof(int3)), CustomPropertyDrawer(typeof(int4))]
  10. [CustomPropertyDrawer(typeof(uint2)), CustomPropertyDrawer(typeof(uint3)), CustomPropertyDrawer(typeof(uint4))]
  11. [CustomPropertyDrawer(typeof(DoNotNormalizeAttribute))]
  12. class PrimitiveVectorDrawer : PropertyDrawer
  13. {
  14. private string _PropertyType;
  15. string GetPropertyType(SerializedProperty property)
  16. {
  17. if (_PropertyType == null)
  18. {
  19. _PropertyType = property.type;
  20. var isManagedRef = property.type.StartsWith("managedReference", StringComparison.Ordinal);
  21. if (isManagedRef)
  22. {
  23. var startIndex = "managedReference<".Length;
  24. var length = _PropertyType.Length - startIndex - 1;
  25. _PropertyType = _PropertyType.Substring("managedReference<".Length, length);
  26. }
  27. }
  28. return _PropertyType;
  29. }
  30. static class Content
  31. {
  32. public static readonly string doNotNormalizeCompatibility = L10n.Tr(
  33. $"{typeof(DoNotNormalizeAttribute).Name} only works with {typeof(quaternion)} and primitive vector types."
  34. );
  35. public static readonly string doNotNormalizeTooltip =
  36. L10n.Tr("This value is not normalized, which may produce unexpected results.");
  37. public static readonly GUIContent[] labels2 = { new GUIContent("X"), new GUIContent("Y") };
  38. public static readonly GUIContent[] labels3 = { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z") };
  39. public static readonly GUIContent[] labels4 = { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z"), new GUIContent("W") };
  40. }
  41. public override bool CanCacheInspectorGUI(SerializedProperty property)
  42. {
  43. return false;
  44. }
  45. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  46. {
  47. var height = EditorGUIUtility.singleLineHeight;
  48. if (!EditorGUIUtility.wideMode)
  49. height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
  50. return height;
  51. }
  52. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  53. {
  54. var subLabels = Content.labels4;
  55. var startIter = "x";
  56. var propertyType = GetPropertyType(property);
  57. switch (propertyType[propertyType.Length - 1])
  58. {
  59. case '2':
  60. subLabels = Content.labels2;
  61. break;
  62. case '3':
  63. subLabels = Content.labels3;
  64. break;
  65. case '4':
  66. subLabels = Content.labels4;
  67. break;
  68. default:
  69. {
  70. if (property.type == nameof(quaternion))
  71. startIter = "value.x";
  72. else if (attribute is DoNotNormalizeAttribute)
  73. {
  74. EditorGUI.HelpBox(EditorGUI.PrefixLabel(position, label), Content.doNotNormalizeCompatibility, MessageType.None);
  75. return;
  76. }
  77. break;
  78. }
  79. }
  80. if (attribute is DoNotNormalizeAttribute && string.IsNullOrEmpty(label.tooltip))
  81. label.tooltip = Content.doNotNormalizeTooltip;
  82. label = EditorGUI.BeginProperty(position, label, property);
  83. var valuesIterator = property.FindPropertyRelative(startIter);
  84. MultiPropertyField(position, subLabels, valuesIterator, label);
  85. EditorGUI.EndProperty();
  86. }
  87. void MultiPropertyField(Rect position, GUIContent[] subLabels, SerializedProperty valuesIterator, GUIContent label)
  88. {
  89. #if UNITY_2022_1_OR_NEWER
  90. EditorGUI.MultiPropertyField(position, subLabels, valuesIterator, label, EditorGUI.PropertyVisibility.All);
  91. #else
  92. EditorGUICopy.MultiPropertyField(position, subLabels, valuesIterator, label);
  93. #endif
  94. }
  95. }
  96. #if !UNITY_2022_1_OR_NEWER
  97. internal class EditorGUICopy
  98. {
  99. internal const float kSpacingSubLabel = 4;
  100. private const float kIndentPerLevel = 15;
  101. internal const float kPrefixPaddingRight = 2;
  102. internal static int indentLevel = 0;
  103. private static readonly int s_FoldoutHash = "Foldout".GetHashCode();
  104. // internal static readonly SVC<float> kVerticalSpacingMultiField = new SVC<float>("--theme-multifield-vertical-spacing", 0.0f);
  105. // kVerticalSpacingMultiField should actually look like the above line ^^^ but we don't have access to SVC<T>,
  106. // so instead we just set this value to what is observed in the debugger with the Unity dark theme.
  107. internal const float kVerticalSpacingMultiField = 2;
  108. internal enum PropertyVisibility
  109. {
  110. All,
  111. OnlyVisible
  112. }
  113. // This code is basically EditorGUI.MultiPropertyField(Rect, GUIContent[], SerializedProperty, GUIContent),
  114. // but with the property visibility assumed to be "All" instead of "OnlyVisible". We really want to have "All"
  115. // because it's possible for someone to hide something in the inspector with [HideInInspector] but then manually
  116. // draw it themselves later. In this case, if you called EditorGUI.MultiPropertyField() directly, you'd
  117. // end up with some fields that point to some unrelated visible property.
  118. public static void MultiPropertyField(Rect position, GUIContent[] subLabels, SerializedProperty valuesIterator, GUIContent label)
  119. {
  120. int id = GUIUtility.GetControlID(s_FoldoutHash, FocusType.Keyboard, position);
  121. position = MultiFieldPrefixLabel(position, id, label, subLabels.Length);
  122. position.height = EditorGUIUtility.singleLineHeight;
  123. MultiPropertyFieldInternal(position, subLabels, valuesIterator, PropertyVisibility.All);
  124. }
  125. internal static void BeginDisabled(bool disabled)
  126. {
  127. // Unused, but left here to minimize changes in EditorGUICopy.MultiPropertyFieldInternal().
  128. }
  129. internal static void EndDisabled()
  130. {
  131. // Unused, but left here to minimize changes in EditorGUICopy.MultiPropertyFieldInternal().
  132. }
  133. internal static float CalcPrefixLabelWidth(GUIContent label, GUIStyle style = null)
  134. {
  135. if (style == null)
  136. style = EditorStyles.label;
  137. return style.CalcSize(label).x;
  138. }
  139. internal static void MultiPropertyFieldInternal(Rect position, GUIContent[] subLabels, SerializedProperty valuesIterator, PropertyVisibility visibility, bool[] disabledMask = null, float prefixLabelWidth = -1)
  140. {
  141. int eCount = subLabels.Length;
  142. float w = (position.width - (eCount - 1) * kSpacingSubLabel) / eCount;
  143. Rect nr = new Rect(position) {width = w};
  144. float t = EditorGUIUtility.labelWidth;
  145. int l = indentLevel;
  146. indentLevel = 0;
  147. for (int i = 0; i < subLabels.Length; i++)
  148. {
  149. EditorGUIUtility.labelWidth = prefixLabelWidth > 0 ? prefixLabelWidth : CalcPrefixLabelWidth(subLabels[i]);
  150. if (disabledMask != null)
  151. BeginDisabled(disabledMask[i]);
  152. EditorGUI.PropertyField(nr, valuesIterator, subLabels[i]);
  153. if (disabledMask != null)
  154. EndDisabled();
  155. nr.x += w + kSpacingSubLabel;
  156. switch (visibility)
  157. {
  158. case PropertyVisibility.All:
  159. valuesIterator.Next(false);
  160. break;
  161. case PropertyVisibility.OnlyVisible:
  162. valuesIterator.NextVisible(false);
  163. break;
  164. }
  165. }
  166. EditorGUIUtility.labelWidth = t;
  167. indentLevel = l;
  168. }
  169. internal static bool LabelHasContent(GUIContent label)
  170. {
  171. if (label == null)
  172. {
  173. return true;
  174. }
  175. // @TODO: find out why checking for GUIContent.none doesn't work
  176. return label.text != string.Empty || label.image != null;
  177. }
  178. internal static float indent => indentLevel * kIndentPerLevel;
  179. internal static Rect MultiFieldPrefixLabel(Rect totalPosition, int id, GUIContent label, int columns)
  180. {
  181. if (!LabelHasContent(label))
  182. {
  183. return EditorGUI.IndentedRect(totalPosition);
  184. }
  185. if (EditorGUIUtility.wideMode)
  186. {
  187. Rect labelPosition = new Rect(totalPosition.x + indent, totalPosition.y, EditorGUIUtility.labelWidth - indent, EditorGUIUtility.singleLineHeight);
  188. Rect fieldPosition = totalPosition;
  189. fieldPosition.xMin += EditorGUIUtility.labelWidth + kPrefixPaddingRight;
  190. // If there are 2 columns we use the same column widths as if there had been 3 columns
  191. // in order to make columns line up neatly.
  192. if (columns == 2)
  193. {
  194. float columnWidth = (fieldPosition.width - (3 - 1) * kSpacingSubLabel) / 3f;
  195. fieldPosition.xMax -= (columnWidth + kSpacingSubLabel);
  196. }
  197. EditorGUI.HandlePrefixLabel(totalPosition, labelPosition, label, id);
  198. return fieldPosition;
  199. }
  200. else
  201. {
  202. Rect labelPosition = new Rect(totalPosition.x + indent, totalPosition.y, totalPosition.width - indent, EditorGUIUtility.singleLineHeight);
  203. Rect fieldPosition = totalPosition;
  204. fieldPosition.xMin += indent + kIndentPerLevel;
  205. fieldPosition.yMin += EditorGUIUtility.singleLineHeight + kVerticalSpacingMultiField;
  206. EditorGUI.HandlePrefixLabel(totalPosition, labelPosition, label, id);
  207. return fieldPosition;
  208. }
  209. }
  210. }
  211. #endif
  212. }