AnimatorParameterDrawer.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Chronos.Controls.Editor;
  4. using Chronos.Reflection.Internal;
  5. using UnityEditor;
  6. using UnityEditor.Animations;
  7. using UnityEngine;
  8. namespace Chronos.Reflection.Editor
  9. {
  10. [CustomPropertyDrawer(typeof(AnimatorParameter))]
  11. public class AnimatorParameterDrawer : TargetedDrawer
  12. {
  13. #region Fields
  14. /// <summary>
  15. /// The inspected property, of type AnimatorParameter.
  16. /// </summary>
  17. protected SerializedProperty property;
  18. /// <summary>
  19. /// The UnityMember.name of the inspected property, of type string.
  20. /// </summary>
  21. protected SerializedProperty nameProperty;
  22. /// <summary>
  23. /// The targeted animators.
  24. /// </summary>
  25. protected Animator[] targets;
  26. #endregion
  27. /// <inheritdoc />
  28. protected override void Update(SerializedProperty property)
  29. {
  30. // Update the targeted drawer
  31. base.Update(property);
  32. // Assign the property and sub-properties
  33. this.property = property;
  34. nameProperty = property.FindPropertyRelative("_name");
  35. // Find the targets
  36. targets = FindTargets();
  37. }
  38. /// <inheritdoc />
  39. protected override void RenderMemberControl(Rect position)
  40. {
  41. var options = GetNameOptions();
  42. DropdownOption<AnimatorParameter> selectedOption = null;
  43. DropdownOption<AnimatorParameter> noneOption = new DropdownOption<AnimatorParameter>(null, "No Parameter");
  44. AnimatorParameter value = GetValue();
  45. if (value != null)
  46. {
  47. string label = value.name;
  48. AnimatorParameter valueInOptions = options.Select(option => option.value).FirstOrDefault(ap => ap.Corresponds(value));
  49. if (valueInOptions != null)
  50. {
  51. selectedOption = new DropdownOption<AnimatorParameter>(valueInOptions, label);
  52. }
  53. else
  54. {
  55. selectedOption = new DropdownOption<AnimatorParameter>(value, label);
  56. }
  57. }
  58. // Make sure the callback uses the property of this drawer, not at its later value.
  59. var propertyNow = property;
  60. bool enabled = targets.Any(target => target != null);
  61. if (!enabled) EditorGUI.BeginDisabledGroup(true);
  62. DropdownGUI<AnimatorParameter>.PopupSingle
  63. (
  64. position,
  65. newValue =>
  66. {
  67. Update(propertyNow);
  68. SetValue(newValue);
  69. propertyNow.serializedObject.ApplyModifiedProperties();
  70. },
  71. options,
  72. selectedOption,
  73. noneOption,
  74. nameProperty.hasMultipleDifferentValues
  75. );
  76. if (!enabled) EditorGUI.EndDisabledGroup();
  77. }
  78. #region Value
  79. /// <summary>
  80. /// Returns an animator parameter constructed from the current property values.
  81. /// </summary>
  82. protected AnimatorParameter GetValue()
  83. {
  84. if (nameProperty.hasMultipleDifferentValues || string.IsNullOrEmpty(nameProperty.stringValue))
  85. {
  86. return null;
  87. }
  88. string name = nameProperty.stringValue;
  89. if (name == string.Empty) name = null;
  90. return new AnimatorParameter(name);
  91. }
  92. /// <summary>
  93. /// Assigns the property values from a specified animator parameter.
  94. /// </summary>
  95. protected void SetValue(AnimatorParameter value)
  96. {
  97. if (value != null)
  98. {
  99. nameProperty.stringValue = value.name;
  100. }
  101. else
  102. {
  103. nameProperty.stringValue = null;
  104. }
  105. }
  106. #endregion
  107. #region Targetting
  108. /// <inheritdoc />
  109. protected override Object GetSelfTarget(Object obj)
  110. {
  111. if (obj is GameObject)
  112. {
  113. return ((GameObject)obj).GetComponent<Animator>();
  114. }
  115. else if (obj is Component)
  116. {
  117. return ((Component)obj).GetComponent<Animator>();
  118. }
  119. else
  120. {
  121. return null;
  122. }
  123. }
  124. /// <summary>
  125. /// Gets the list of targets on the inspected objects.
  126. /// </summary>
  127. protected Animator[] FindTargets()
  128. {
  129. IEnumerable<Object> objects = targetProperty.Multiple().Select(p => p.objectReferenceValue);
  130. var childrenAnimators = objects.OfType<GameObject>().SelectMany(gameObject => gameObject.GetComponents<Animator>());
  131. var siblingAnimators = objects.OfType<Component>().SelectMany(component => component.GetComponents<Animator>());
  132. return childrenAnimators.Concat(siblingAnimators).ToArray();
  133. }
  134. #endregion
  135. #region Reflection
  136. /// <summary>
  137. /// Gets the list of shared parameter names as popup options.
  138. /// </summary>
  139. protected List<DropdownOption<AnimatorParameter>> GetNameOptions()
  140. {
  141. var options = new List<DropdownOption<AnimatorParameter>>();
  142. List<string> names = targets
  143. .Select(animator => ((AnimatorController)animator.runtimeAnimatorController))
  144. .Where(animatorController => animatorController != null)
  145. .Select(animatorController => animatorController.parameters)
  146. .Select(parameters => parameters.Select(parameter => parameter.name))
  147. .IntersectAll()
  148. .Distinct()
  149. .ToList();
  150. foreach (string name in names)
  151. {
  152. options.Add(new DropdownOption<AnimatorParameter>(new AnimatorParameter(name), name));
  153. }
  154. return options;
  155. }
  156. #endregion
  157. }
  158. }