123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditor.IMGUI.Controls;
- using UnityEditorInternal;
- using UnityEngine;
- using UnityEngine.Timeline;
-
- #if !UNITY_2020_2_OR_NEWER
- using L10n = UnityEditor.Timeline.L10n;
- #endif
-
- namespace UnityEditor.Timeline
- {
- class BindingTreeViewDataSource : TreeViewDataSource
- {
- struct BindingGroup : IEquatable<BindingGroup>, IComparable<BindingGroup>
- {
- public readonly string GroupName;
- public readonly string Path;
- public readonly Type Type;
-
- public BindingGroup(string path, string groupName, Type type)
- {
- Path = path;
- GroupName = groupName;
- Type = type;
- }
-
- public string groupDisplayName => string.IsNullOrEmpty(Path) ? GroupName : string.Format($"{Path} : {GroupName}");
- public bool Equals(BindingGroup other) => GroupName == other.GroupName && Type == other.Type && Path == other.Path;
- public int CompareTo(BindingGroup other) => GetHashCode() - other.GetHashCode();
- public override bool Equals(object obj) => obj is BindingGroup other && Equals(other);
- public override int GetHashCode()
- {
- return HashUtility.CombineHash(GroupName != null ? GroupName.GetHashCode() : 0, Type != null ? Type.GetHashCode() : 0, Path != null ? Path.GetHashCode() : 0);
- }
- }
-
- static readonly string s_DefaultValue = L10n.Tr("{0} (Default Value)");
-
- public const int RootID = int.MinValue;
- public const int GroupID = -1;
-
- private readonly AnimationClip m_Clip;
- private readonly CurveDataSource m_CurveDataSource;
-
- public BindingTreeViewDataSource(
- TreeViewController treeView, AnimationClip clip, CurveDataSource curveDataSource)
- : base(treeView)
- {
- m_Clip = clip;
- showRootItem = false;
- m_CurveDataSource = curveDataSource;
- }
-
- void SetupRootNodeSettings()
- {
- showRootItem = false;
- SetExpanded(RootID, true);
- SetExpanded(GroupID, true);
- }
-
- public override void FetchData()
- {
- if (m_Clip == null)
- return;
-
- var bindings = AnimationUtility.GetCurveBindings(m_Clip)
- .Union(AnimationUtility.GetObjectReferenceCurveBindings(m_Clip))
- .ToArray();
-
- // a sorted linear list of nodes
- var results = bindings.GroupBy(GetBindingGroup, p => p, CreateTuple)
- .OrderBy(t => t.Item1.Path)
- .ThenBy(NamePrioritySort)
- // this makes component ordering match the animation window
- .ThenBy(t => t.Item1.Type.ToString())
- .ThenBy(t => t.Item1.GroupName).ToArray();
-
- m_RootItem = new CurveTreeViewNode(RootID, null, "root", null)
- {
- children = new List<TreeViewItem>(1)
- };
-
- if (results.Any())
- {
- var groupingNode = new CurveTreeViewNode(GroupID, m_RootItem, m_CurveDataSource.groupingName, bindings)
- {
- children = new List<TreeViewItem>()
- };
-
- m_RootItem.children.Add(groupingNode);
-
- foreach (var r in results)
- {
- var key = r.Item1;
- var nodeBindings = r.Item2;
-
- FillMissingTransformCurves(nodeBindings);
- if (nodeBindings.Count == 1)
- groupingNode.children.Add(CreateLeafNode(nodeBindings[0], groupingNode, PropertyName(nodeBindings[0], true)));
- else if (nodeBindings.Count > 1)
- {
- var childBindings = nodeBindings.OrderBy(BindingSort).ToArray();
- var parent = new CurveTreeViewNode(key.GetHashCode(), groupingNode, key.groupDisplayName, childBindings) { children = new List<TreeViewItem>() };
- groupingNode.children.Add(parent);
- foreach (var b in childBindings)
- parent.children.Add(CreateLeafNode(b, parent, PropertyName(b, false)));
- }
- }
- SetupRootNodeSettings();
- }
-
- m_NeedRefreshRows = true;
- }
-
- public void UpdateData()
- {
- m_TreeView.ReloadData();
- }
-
- string GroupName(EditorCurveBinding binding)
- {
- var propertyName = m_CurveDataSource.ModifyPropertyDisplayName(binding.path, binding.propertyName);
- return CleanUpArrayBinding(AnimationWindowUtility.NicifyPropertyGroupName(binding.type, propertyName), true);
- }
-
- static string CleanUpArrayBinding(string propertyName, bool isGroup)
- {
- const string arrayIndicator = ".Array.data[";
- const string arrayDisplay = ".data[";
-
- var arrayIndex = propertyName.LastIndexOf(arrayIndicator, StringComparison.Ordinal);
- if (arrayIndex == -1)
- return propertyName;
- if (isGroup)
- propertyName = propertyName.Substring(0, arrayIndex);
- return propertyName.Replace(arrayIndicator, arrayDisplay);
- }
-
- string PropertyName(EditorCurveBinding binding, bool prependPathName)
- {
- var propertyName = m_CurveDataSource.ModifyPropertyDisplayName(binding.path, binding.propertyName);
- propertyName = CleanUpArrayBinding(AnimationWindowUtility.GetPropertyDisplayName(propertyName), false);
- if (binding.isPhantom)
- propertyName = string.Format(s_DefaultValue, propertyName);
- if (prependPathName && !string.IsNullOrEmpty(binding.path))
- propertyName = $"{binding.path} : {propertyName}";
- return propertyName;
- }
-
- BindingGroup GetBindingGroup(EditorCurveBinding binding)
- {
- return new BindingGroup(binding.path ?? string.Empty, GroupName(binding), binding.type);
- }
-
- static CurveTreeViewNode CreateLeafNode(EditorCurveBinding binding, TreeViewItem parent, string displayName)
- {
- return new CurveTreeViewNode(binding.GetHashCode(), parent, displayName, new[] { binding }, AnimationWindowUtility.ForceGrouping(binding));
- }
-
- static void FillMissingTransformCurves(List<EditorCurveBinding> bindings)
- {
- if (!AnimationWindowUtility.IsActualTransformCurve(bindings[0]) || bindings.Count >= 3)
- return;
-
- var binding = bindings[0];
- var prefixPropertyName = binding.propertyName.Split('.').First();
-
- binding.isPhantom = true;
- if (!bindings.Any(p => p.propertyName.EndsWith(".x")))
- {
- binding.propertyName = prefixPropertyName + ".x";
- bindings.Insert(0, binding);
- }
-
- if (!bindings.Any(p => p.propertyName.EndsWith(".y")))
- {
- binding.propertyName = prefixPropertyName + ".y";
- bindings.Insert(1, binding);
- }
-
- if (!bindings.Any(p => p.propertyName.EndsWith(".z")))
- {
- binding.propertyName = prefixPropertyName + ".z";
- bindings.Insert(2, binding);
- }
- }
-
- // make sure vectors and colors are sorted correctly in their subgroups
- static int BindingSort(EditorCurveBinding b)
- {
- return AnimationWindowUtility.GetComponentIndex(b.propertyName);
- }
-
- static int NamePrioritySort(ValueTuple<BindingGroup, List<EditorCurveBinding>> group)
- {
- if (group.Item1.Type != typeof(Transform))
- return 0;
-
- switch (group.Item1.GroupName)
- {
- case "Position": return Int32.MinValue;
- case "Rotation": return Int32.MinValue + 1;
- case "Scale": return Int32.MinValue + 2;
- default: return 0;
- }
- }
-
- static ValueTuple<BindingGroup, List<EditorCurveBinding>> CreateTuple(BindingGroup key, IEnumerable<EditorCurveBinding> items)
- {
- return new ValueTuple<BindingGroup, List<EditorCurveBinding>>()
- {
- Item1 = key,
- Item2 = items.ToList()
- };
- }
- }
- }
|