/************************************************************************************************************************/ #region Context Menu /************************************************************************************************************************/ /// <summary>Adds functions relevant to the <see cref="AnimancerNodeDrawer{T}.Target"/>.</summary> protected override void PopulateContextMenu(GenericMenu menu) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "CurrentState: " + Target.CurrentState)); menu.AddDisabledItem(new GUIContent(DetailsPrefix + "CommandCount: " + Target.CommandCount)); AnimancerEditorUtilities.AddMenuItem(menu, "Stop", HasAnyStates((state) => state.IsPlaying || state.Weight != 0), () => Target.Stop()); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade In", Target.Index > 0 && Target.Weight != 1, Target, (duration) => Target.StartFade(1, duration)); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade Out", Target.Index > 0 && Target.Weight != 0, Target, (duration) => Target.StartFade(0, duration)); AnimancerEditorUtilities.AddContextMenuIK(menu, Target); menu.AddSeparator(""); AnimancerEditorUtilities.AddMenuItem(menu, "Destroy States", ActiveStates.Count > 0 || InactiveStates.Count > 0, () => Target.DestroyStates()); AnimancerPlayableDrawer.AddRootFunctions(menu, Target.Root); menu.AddSeparator(""); AnimancerPlayableDrawer.AddDisplayOptions(menu); AnimancerEditorUtilities.AddDocumentationLink(menu, "Layer Documentation", "/docs/manual/blending/layers"); menu.ShowAsContext(); }
/************************************************************************************************************************/ #region Context Menu /************************************************************************************************************************/ /// <summary>Adds functions relevant to the <see cref="AnimancerNodeDrawer{T}.Target"/>.</summary> protected override void PopulateContextMenu(GenericMenu menu) { AddContextMenuFunctions(menu); AnimancerEditorUtilities.AddMenuItem(menu, "Play", !Target.IsPlaying || Target.Weight != 1, () => { Target.Root.UnpauseGraph(); Target.Root.Play(Target); }); AnimancerEditorUtilities.AddFadeFunction(menu, "Cross Fade (Ctrl + Click)", Target.Weight != 1, Target, (duration) => { Target.Root.UnpauseGraph(); Target.Root.Play(Target, duration); }); AnimancerEditorUtilities.AddFadeFunction(menu, "Cross Fade Queued (Ctrl + Shift + Click)", Target.Weight != 1, Target, (duration) => { AnimationQueue.CrossFadeQueued(Target); }); menu.AddSeparator(""); menu.AddItem(new GUIContent("Destroy State"), false, () => Target.Destroy()); menu.AddSeparator(""); AnimancerEditorUtilities.AddDocumentationLink(menu, "State Documentation", "/docs/manual/states"); }
/************************************************************************************************************************/ /// <summary>Adds the details of this state to the menu.</summary> protected virtual void AddContextMenuFunctions(GenericMenu menu) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Key: " + Target.Key)); var length = Target.Length; if (!float.IsNaN(length)) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Length: " + length)); } menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Playable Path: " + Target.GetPath())); var mainAsset = Target.MainObject; if (mainAsset != null) { var assetPath = AssetDatabase.GetAssetPath(mainAsset); if (assetPath != null) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Asset Path: " + assetPath.Replace("/", "->"))); } } const string OnEndPrefix = "End Event/"; { var endEvent = Target.Events.endEvent; menu.AddDisabledItem(new GUIContent(OnEndPrefix + "NormalizedTime: " + endEvent.normalizedTime)); if (endEvent.callback == null) { menu.AddDisabledItem(new GUIContent(OnEndPrefix + "Callback: null")); } else { var label = OnEndPrefix + (endEvent.callback.Target != null ? ("Target: " + endEvent.callback.Target) : "Target: null"); var targetObject = endEvent.callback.Target as Object; AnimancerEditorUtilities.AddMenuItem(menu, label, targetObject != null, () => Selection.activeObject = targetObject); menu.AddDisabledItem(new GUIContent( OnEndPrefix + "Declaring Type: " + endEvent.callback.Method.DeclaringType.FullName)); menu.AddDisabledItem(new GUIContent( OnEndPrefix + "Method: " + endEvent.callback.Method)); } AnimancerEditorUtilities.AddMenuItem(menu, OnEndPrefix + "Clear", !float.IsNaN(endEvent.normalizedTime) || endEvent.callback != null, () => Target.Events.endEvent = new AnimancerEvent(float.NaN, null)); AnimancerEditorUtilities.AddMenuItem(menu, OnEndPrefix + "Invoke", endEvent.callback != null, () => Target.Events.endEvent.Invoke(Target)); } }
/************************************************************************************************************************/ #region Context Menu /************************************************************************************************************************/ /// <summary>Adds functions relevant to the <see cref="AnimancerNodeDrawer{T}.Target"/>.</summary> protected override void PopulateContextMenu(GenericMenu menu) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "CurrentState: " + Target.CurrentState)); menu.AddDisabledItem(new GUIContent(DetailsPrefix + "CommandCount: " + Target.CommandCount)); AnimancerEditorUtilities.AddMenuItem(menu, "Stop", HasAnyStates((state) => state.IsPlaying || state.Weight != 0), () => Target.Stop()); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade In", Target.Index > 0 && Target.Weight != 1, Target, (duration) => Target.StartFade(1, duration)); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade Out", Target.Index > 0 && Target.Weight != 0, Target, (duration) => Target.StartFade(0, duration)); menu.AddItem(new GUIContent("Inverse Kinematics/Apply Animator IK"), Target.ApplyAnimatorIK, () => Target.ApplyAnimatorIK = !Target.ApplyAnimatorIK); menu.AddItem(new GUIContent("Inverse Kinematics/Default Apply Animator IK"), Target.DefaultApplyAnimatorIK, () => Target.DefaultApplyAnimatorIK = !Target.DefaultApplyAnimatorIK); menu.AddItem(new GUIContent("Inverse Kinematics/Apply Foot IK"), Target.ApplyFootIK, () => Target.ApplyFootIK = !Target.ApplyFootIK); menu.AddItem(new GUIContent("Inverse Kinematics/Default Apply Foot IK"), Target.DefaultApplyFootIK, () => Target.DefaultApplyFootIK = !Target.DefaultApplyFootIK); menu.AddSeparator(""); AnimancerEditorUtilities.AddMenuItem(menu, "Destroy States", ActiveStates.Count > 0 || InactiveStates.Count > 0, () => Target.DestroyStates()); AnimancerEditorUtilities.AddMenuItem(menu, "Add Layer", Target.Root.Layers.Count < AnimancerPlayable.LayerList.defaultCapacity, () => Target.Root.Layers.Count++); AnimancerEditorUtilities.AddMenuItem(menu, "Remove Layer", Target.Root.Layers.Count > 0, () => Target.Root.Layers.Count--); menu.AddSeparator(""); menu.AddItem(new GUIContent("Keep Weightless Playables Connected"), Target.Root.KeepChildrenConnected, () => Target.Root.KeepChildrenConnected = !Target.Root.KeepChildrenConnected); AddPrefFunctions(menu); menu.AddSeparator(""); AnimancerEditorUtilities.AddDocumentationLink(menu, "Layer Documentation", "/docs/manual/blending/layers"); menu.ShowAsContext(); }
/************************************************************************************************************************/ /// <summary>Adds functions for controlling the `playable`.</summary> public static void AddRootFunctions(GenericMenu menu, AnimancerPlayable playable) { AnimancerEditorUtilities.AddMenuItem(menu, "Add Layer", playable.Layers.Count < AnimancerPlayable.LayerList.DefaultCapacity, () => playable.Layers.Count++); AnimancerEditorUtilities.AddMenuItem(menu, "Remove Layer", playable.Layers.Count > 0, () => playable.Layers.Count--); menu.AddItem(new GUIContent("Keep Children Connected ?"), playable.KeepChildrenConnected, () => playable.KeepChildrenConnected = !playable.KeepChildrenConnected); }
/************************************************************************************************************************/ /// <summary>Adds a menu function to open the Playable Graph Visualiser if it exists in the project.</summary> public static void AddPlayableGraphVisualizerFunction(GenericMenu menu, string prefix, PlayableGraph graph) { var type = Type.GetType("GraphVisualizer.PlayableGraphVisualizerWindow, Unity.PlayableGraphVisualizer.Editor"); AnimancerEditorUtilities.AddMenuItem(menu, prefix + "Playable Graph Visualizer", type != null, () => { var window = EditorWindow.GetWindow(type); var field = type.GetField("m_CurrentGraph", AnimancerEditorUtilities.AnyAccessBindings); if (field != null) { field.SetValue(window, graph); } }); }
/************************************************************************************************************************/ private void AddPlayableGraphVisualizerFunction(GenericMenu menu) { var type = Type.GetType("GraphVisualizer.PlayableGraphVisualizerWindow," + " Unity.PlayableGraphVisualizer.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); AnimancerEditorUtilities.AddMenuItem(menu, DetailsPrefix + "Playable Graph Visualizer", type != null, () => { var window = EditorWindow.GetWindow(type); var field = type.GetField("m_CurrentGraph", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); if (field != null) { field.SetValue(window, Target.Root._Graph); } }); }
/************************************************************************************************************************/ /// <summary>[Editor-Only] /// Adds the details of this state to the menu. /// By default, that means a single item showing the path of the <see cref="AnimancerState.MainObject"/>. /// </summary> protected virtual void AddContextMenuFunctions(GenericMenu menu) { if (State.HasLength) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Length: " + State.Length)); } menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Playable Path: " + State.GetPath())); var mainAsset = State.MainObject; if (mainAsset != null) { var assetPath = AssetDatabase.GetAssetPath(mainAsset); if (assetPath != null) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Asset Path: " + assetPath.Replace("/", "->"))); } } if (State.OnEnd != null) { const string OnEndPrefix = "On End/"; var label = OnEndPrefix + (State.OnEnd.Target != null ? ("Target: " + State.OnEnd.Target) : "Target: null"); var targetObject = State.OnEnd.Target as Object; AnimancerEditorUtilities.AddMenuItem(menu, label, targetObject != null, () => Selection.activeObject = targetObject); menu.AddDisabledItem(new GUIContent(OnEndPrefix + "Declaring Type: " + State.OnEnd.Method.DeclaringType.FullName)); menu.AddDisabledItem(new GUIContent(OnEndPrefix + "Method: " + State.OnEnd.Method)); menu.AddItem(new GUIContent(OnEndPrefix + "Clear"), false, () => State.OnEnd = null); menu.AddItem(new GUIContent(OnEndPrefix + "Invoke"), false, () => State.OnEnd()); } }
/// <summary> /// Checks if the current event is a context menu click within the 'clickArea' and opens a context menu with various /// functions for the <see cref="State"/>. /// </summary> protected void CheckContextMenu(Rect clickArea) { if (!AnimancerEditorUtilities.TryUseContextClick(clickArea)) { return; } var menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent(DetailsPrefix + "State: " + State.ToString())); var key = State.Key; if (key != null) { menu.AddDisabledItem(new GUIContent(DetailsPrefix + "Key: " + key)); } AnimancerEditorUtilities.AddMenuItem(menu, "Play", !State.IsPlaying || State.Weight != 1, () => State.Root.Play(State)); AnimancerEditorUtilities.AddFadeFunction(menu, "Cross Fade (Ctrl + Click)", State.Weight != 1, State, (duration) => State.Root.CrossFade(State, duration)); AddContextMenuFunctions(menu); menu.AddItem(new GUIContent(DetailsPrefix + "Log Details"), false, () => Debug.Log("AnimancerState: " + State.GetDescription(true))); menu.AddSeparator(""); menu.AddItem(new GUIContent("Destroy State"), false, () => State.Dispose()); menu.AddSeparator(""); AnimancerEditorUtilities.AddDocumentationLink(menu, "State Documentation", "/docs/manual/animancer-states"); menu.ShowAsContext(); }
/************************************************************************************************************************/ #region Context Menu /************************************************************************************************************************/ /// <summary> /// Checks if the current event is a context menu click within the 'clickArea' and opens a context menu with various /// functions for the <see cref="Layer"/>. /// </summary> private void CheckContextMenu(Rect clickArea) { if (!AnimancerEditorUtilities.TryUseContextClick(clickArea)) { return; } var menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent(Layer.ToString())); AnimancerEditorUtilities.AddMenuItem(menu, "Stop", HasAnyStates((state) => state.IsPlaying || state.Weight != 0), () => Layer.Stop()); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade In", Layer.PortIndex > 0 && Layer.Weight != 1, Layer, (duration) => Layer.StartFade(1, duration)); AnimancerEditorUtilities.AddFadeFunction(menu, "Fade Out", Layer.PortIndex > 0 && Layer.Weight != 0, Layer, (duration) => Layer.StartFade(0, duration)); menu.AddItem(new GUIContent("Inverse Kinematics/Apply Animator IK"), Layer.ApplyAnimatorIK, () => Layer.ApplyAnimatorIK = !Layer.ApplyAnimatorIK); menu.AddItem(new GUIContent("Inverse Kinematics/Default Apply Animator IK"), Layer.DefaultApplyAnimatorIK, () => Layer.DefaultApplyAnimatorIK = !Layer.DefaultApplyAnimatorIK); menu.AddItem(new GUIContent("Inverse Kinematics/Apply Foot IK"), Layer.ApplyFootIK, () => Layer.ApplyFootIK = !Layer.ApplyFootIK); menu.AddItem(new GUIContent("Inverse Kinematics/Default Apply Foot IK"), Layer.DefaultApplyFootIK, () => Layer.DefaultApplyFootIK = !Layer.DefaultApplyFootIK); menu.AddSeparator(""); AnimancerEditorUtilities.AddMenuItem(menu, "Destroy States", ActiveStates.Count > 0 || InactiveStates.Count > 0, () => Layer.DestroyStates()); AnimancerEditorUtilities.AddMenuItem(menu, "Add Layer", Layer.Root.LayerCount < AnimancerPlayable.maxLayerCount, () => Layer.Root.LayerCount++); AnimancerEditorUtilities.AddMenuItem(menu, "Remove Layer", Layer.Root.LayerCount > 0, () => Layer.Root.LayerCount--); menu.AddSeparator(""); menu.AddItem(new GUIContent("Keep Weightless Playables Connected"), Layer.Root.KeepPlayablesConnected, () => Layer.Root.KeepPlayablesConnected = !Layer.Root.KeepPlayablesConnected); AddPrefFunctions(menu); menu.AddSeparator(""); AnimancerEditorUtilities.AddDocumentationLink(menu, "Layer Documentation", "/docs/manual/animation-layers"); AddPlayableGraphVisualizerFunction(menu); menu.ShowAsContext(); }