| using System; |
| using System.Linq; |
| using UnityEditor.ShortcutManagement; |
| using UnityEditor.Timeline.Actions; |
| using UnityEngine; |
|
|
| namespace UnityEditor.Timeline |
| { |
| class TimelinePanManipulator : Manipulator |
| { |
| const float k_MaxPanSpeed = 50.0f; |
| bool m_Active; |
|
|
| protected override bool MouseDown(Event evt, WindowState state) |
| { |
| if ((evt.button == 2 && evt.modifiers == EventModifiers.None) || |
| (evt.button == 0 && evt.modifiers == EventModifiers.Alt)) |
| { |
| TimelineCursors.SetCursor(TimelineCursors.CursorType.Pan); |
|
|
| m_Active = true; |
| return true; |
| } |
|
|
| return false; |
| } |
|
|
| protected override bool MouseUp(Event evt, WindowState state) |
| { |
| if (m_Active) |
| { |
| TimelineCursors.ClearCursor(); |
| state.editorWindow.Repaint(); |
| } |
|
|
| return false; |
| } |
|
|
| protected override bool MouseDrag(Event evt, WindowState state) |
| { |
| |
| |
|
|
| if (!m_Active) |
| return false; |
|
|
| return Pan(evt, state); |
| } |
|
|
| protected override bool MouseWheel(Event evt, WindowState state) |
| { |
| if (Math.Abs(evt.delta.x) < 1e-5 || Math.Abs(evt.delta.x) <= Math.Abs(evt.delta.y)) |
| return false; |
|
|
| TimelineZoomManipulator.InvalidateWheelZoom(); |
|
|
| var panEvent = new Event(evt); |
| panEvent.delta = new Vector2(panEvent.delta.x * k_MaxPanSpeed * -1.0f, 0.0f); |
|
|
| return Pan(panEvent, state); |
| } |
|
|
| static bool Pan(Event evt, WindowState state) |
| { |
| var cursorRect = TimelineWindow.instance.sequenceContentRect; |
| cursorRect.xMax = TimelineWindow.instance.position.xMax; |
| cursorRect.yMax = TimelineWindow.instance.position.yMax; |
|
|
| if (state.GetWindow() != null && state.GetWindow().treeView != null) |
| { |
| var scroll = state.GetWindow().treeView.scrollPosition; |
| scroll.y -= evt.delta.y; |
| state.GetWindow().treeView.scrollPosition = scroll; |
| state.OffsetTimeArea((int)evt.delta.x); |
| return true; |
| } |
|
|
| return false; |
| } |
| } |
|
|
|
|
| class TimelineZoomManipulator : Manipulator |
| { |
| Vector2 m_MouseDownPos = Vector2.zero; |
| float m_FocalTime; |
| float m_LastMouseMoveX = -1; |
| bool m_WheelUsedLast; |
|
|
| TimelineZoomManipulator() { } |
|
|
| public static readonly TimelineZoomManipulator Instance = new TimelineZoomManipulator(); |
|
|
| internal void DoZoom(float zoomFactor) |
| { |
| var refRange = TimelineEditor.visibleTimeRange; |
| DoZoom(zoomFactor, refRange, (refRange.x + refRange.y) / 2); |
| |
| InvalidateWheelZoom(); |
| } |
|
|
| static void DoZoom(float zoomFactor, Vector2 refRange, float focalTime) |
| { |
| const float kMinRange = 0.05f; |
|
|
| if (zoomFactor <= 0) |
| return; |
|
|
| var t = Mathf.Max(focalTime, refRange.x); |
| var x = (refRange.x + t * (zoomFactor - 1)) / zoomFactor; |
| var y = (refRange.y + t * (zoomFactor - 1)) / zoomFactor; |
|
|
| var newRange = Mathf.Abs(x - y) < kMinRange ? refRange : new Vector2( |
| Mathf.Max(x, -WindowConstants.timeAreaShownRangePadding), |
| Mathf.Min(y, WindowState.kMaxShownTime)); |
|
|
| if (newRange != refRange) |
| |
| TimelineEditor.visibleTimeRange = newRange; |
| } |
|
|
| internal static void InvalidateWheelZoom() |
| { |
| Instance.m_WheelUsedLast = false; |
| } |
|
|
| protected override bool MouseDown(Event evt, WindowState state) |
| { |
| m_MouseDownPos = evt.mousePosition; |
| m_FocalTime = state.PixelToTime(m_MouseDownPos.x); |
| return false; |
| } |
|
|
| protected override bool MouseWheel(Event evt, WindowState state) |
| { |
| if (Math.Abs(evt.delta.y) < 1e-5) |
| return false; |
|
|
| var zoomRect = TimelineWindow.instance.sequenceContentRect; |
| zoomRect.yMax += TimelineWindow.instance.horizontalScrollbarHeight; |
|
|
| if (!zoomRect.Contains(evt.mousePosition)) |
| return false; |
|
|
| if (!m_WheelUsedLast || Mathf.Abs(m_LastMouseMoveX - evt.mousePosition.x) > 1.0f) |
| { |
| m_LastMouseMoveX = evt.mousePosition.x; |
| m_FocalTime = state.PixelToTime(m_LastMouseMoveX); |
| } |
|
|
| var zoomFactor = -evt.delta.y * 0.02f + 1; |
| DoZoom(zoomFactor, state.timeAreaShownRange, m_FocalTime); |
|
|
| m_WheelUsedLast = true; |
| return true; |
| } |
|
|
| protected override bool MouseDrag(Event evt, WindowState state) |
| { |
| |
| if (evt.modifiers != EventModifiers.Alt || evt.button != 1) return false; |
|
|
| var mouseMoveLength = Event.current.mousePosition - m_MouseDownPos; |
| var delta = Math.Abs(mouseMoveLength.x) > Math.Abs(mouseMoveLength.y) |
| ? mouseMoveLength.x |
| : -mouseMoveLength.y; |
| var zoomFactor = PixelToZoom(delta); |
| DoZoom(zoomFactor, state.timeAreaShownRange, m_FocalTime); |
|
|
| m_WheelUsedLast = false; |
| return true; |
| } |
|
|
| static float PixelToZoom(float x) |
| { |
| const float pixel2Zoom = 1 / 300.0f; |
| x *= pixel2Zoom; |
| if (x < -0.75) |
| { |
| |
| |
| |
| |
| |
| return 1 / (98.6667f + 268.444f * x + 189.63f * x * x); |
| } |
| return 1 + x; |
| } |
| } |
|
|
| class TimelineShortcutManipulator : Manipulator |
| { |
| protected override bool ValidateCommand(Event evt, WindowState state) |
| { |
| return evt.commandName == EventCommandNames.Copy || |
| evt.commandName == EventCommandNames.Paste || |
| evt.commandName == EventCommandNames.Duplicate || |
| evt.commandName == EventCommandNames.SelectAll || |
| evt.commandName == EventCommandNames.Delete || |
| evt.commandName == EventCommandNames.SoftDelete || |
| evt.commandName == EventCommandNames.FrameSelected; |
| } |
|
|
| protected override bool ExecuteCommand(Event evt, WindowState state) |
| { |
| if (state.IsCurrentEditingASequencerTextField()) |
| return false; |
|
|
| if (evt.commandName == EventCommandNames.SelectAll) |
| { |
| Invoker.InvokeWithSelected<SelectAllAction>(); |
| return true; |
| } |
|
|
| if (evt.commandName == EventCommandNames.SoftDelete) |
| { |
| Invoker.InvokeWithSelected<DeleteAction>(); |
| return true; |
| } |
|
|
| if (evt.commandName == EventCommandNames.FrameSelected) |
| { |
| Invoker.InvokeWithSelected<FrameSelectedAction>(); |
| return true; |
| } |
|
|
| return ActionManager.HandleShortcut(evt); |
| } |
| } |
|
|
| class InlineCurvesShortcutManipulator : Manipulator |
| { |
| protected override bool ExecuteCommand(Event evt, WindowState state) |
| { |
| if (state.IsCurrentEditingASequencerTextField()) |
| return false; |
|
|
| var inlineCurveEditor = SelectionManager.GetCurrentInlineEditorCurve(); |
| if (inlineCurveEditor == null || !inlineCurveEditor.inlineCurvesSelected) |
| return false; |
|
|
| if (evt.commandName != EventCommandNames.FrameSelected) |
| return false; |
|
|
| Invoker.InvokeWithSelected<FrameSelectedAction>(); |
| return true; |
| } |
|
|
| |
| |
| protected override bool KeyDown(Event evt, WindowState state) |
| { |
| var inlineCurveEditor = SelectionManager.GetCurrentInlineEditorCurve(); |
| if (inlineCurveEditor == null || !inlineCurveEditor.inlineCurvesSelected) |
| return false; |
|
|
| |
| if (evt.keyCode != KeyCode.A) |
| return false; |
|
|
| var combination = ShortcutManager.instance.GetShortcutBinding(Shortcuts.Timeline.frameAll) |
| .keyCombinationSequence.ToList(); |
|
|
| var shortcutCombination = combination.First(); |
| var currentCombination = KeyCombination.FromKeyboardInput(evt); |
|
|
| |
| if (combination.Count == 1 && shortcutCombination.Equals(currentCombination)) |
| Invoker.InvokeWithSelected<FrameAllAction>(); |
|
|
| return true; |
| } |
| } |
| } |
|
|