TrimClip.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using UnityEngine;
  6. using UnityEngine.Timeline;
  7. namespace UnityEditor.Timeline
  8. {
  9. class TrimClip : Manipulator
  10. {
  11. class TrimClipAttractionHandler : IAttractionHandler
  12. {
  13. public void OnAttractedEdge(IAttractable attractable, ManipulateEdges manipulateEdges, AttractedEdge edge, double time)
  14. {
  15. var clipGUI = attractable as TimelineClipGUI;
  16. if (clipGUI == null)
  17. return;
  18. var clipItem = ItemsUtils.ToItem(clipGUI.clip);
  19. if (manipulateEdges == ManipulateEdges.Right)
  20. {
  21. bool affectTimeScale = Event.current.modifiers == EventModifiers.Shift; // TODO Do not use Event.current from here.
  22. EditMode.TrimEnd(clipItem, time, affectTimeScale);
  23. }
  24. else if (manipulateEdges == ManipulateEdges.Left)
  25. {
  26. EditMode.TrimStart(clipItem, time);
  27. }
  28. }
  29. }
  30. bool m_IsCaptured;
  31. TimelineClipHandle m_TrimClipHandler;
  32. double m_OriginalDuration;
  33. double m_OriginalTimeScale;
  34. bool m_UndoSaved;
  35. SnapEngine m_SnapEngine;
  36. readonly StringBuilder m_OverlayText = new StringBuilder();
  37. readonly List<string> m_OverlayStrings = new List<string>();
  38. static readonly double kEpsilon = 0.0000001;
  39. protected override bool MouseDown(Event evt, WindowState state)
  40. {
  41. var handle = PickerUtils.PickedLayerableOfType<TimelineClipHandle>();
  42. if (handle == null)
  43. return false;
  44. if (handle.clipGUI.clip.parentTrack != null && handle.clipGUI.clip.parentTrack.lockedInHierarchy)
  45. return false;
  46. if (ItemSelection.CanClearSelection(evt))
  47. SelectionManager.Clear();
  48. if (!SelectionManager.Contains(handle.clipGUI.clip))
  49. SelectionManager.Add(handle.clipGUI.clip);
  50. m_TrimClipHandler = handle;
  51. m_IsCaptured = true;
  52. state.AddCaptured(this);
  53. m_UndoSaved = false;
  54. var clip = m_TrimClipHandler.clipGUI.clip;
  55. m_OriginalDuration = clip.duration;
  56. m_OriginalTimeScale = clip.timeScale;
  57. RefreshOverlayStrings(m_TrimClipHandler, state);
  58. // in ripple trim, the right edge moves and needs to snap
  59. var edges = ManipulateEdges.Right;
  60. if (EditMode.editType != EditMode.EditType.Ripple && m_TrimClipHandler.trimDirection == TrimEdge.Start)
  61. edges = ManipulateEdges.Left;
  62. m_SnapEngine = new SnapEngine(m_TrimClipHandler.clipGUI, new TrimClipAttractionHandler(), edges, state,
  63. evt.mousePosition);
  64. EditMode.BeginTrim(ItemsUtils.ToItem(clip), m_TrimClipHandler.trimDirection);
  65. return true;
  66. }
  67. protected override bool MouseUp(Event evt, WindowState state)
  68. {
  69. if (!m_IsCaptured)
  70. return false;
  71. m_IsCaptured = false;
  72. m_TrimClipHandler = null;
  73. m_UndoSaved = false;
  74. m_SnapEngine = null;
  75. EditMode.FinishTrim();
  76. state.captured.Clear();
  77. return true;
  78. }
  79. protected override bool MouseDrag(Event evt, WindowState state)
  80. {
  81. if (state.editSequence.isReadOnly)
  82. return false;
  83. if (!m_IsCaptured)
  84. return false;
  85. if (!m_UndoSaved)
  86. {
  87. var uiClip = m_TrimClipHandler.clipGUI;
  88. TimelineUndo.PushUndo(uiClip.clip.parentTrack, "Trim Clip");
  89. if (TimelineUtility.IsRecordableAnimationClip(uiClip.clip))
  90. {
  91. TimelineUndo.PushUndo(uiClip.clip.animationClip, "Trim Clip");
  92. }
  93. m_UndoSaved = true;
  94. }
  95. if (m_SnapEngine != null)
  96. m_SnapEngine.Snap(evt.mousePosition, evt.modifiers);
  97. RefreshOverlayStrings(m_TrimClipHandler, state);
  98. if (Selection.activeObject != null)
  99. EditorUtility.SetDirty(Selection.activeObject);
  100. // updates the duration of the graph without rebuilding
  101. state.UpdateRootPlayableDuration(state.editSequence.duration);
  102. return true;
  103. }
  104. public override void Overlay(Event evt, WindowState state)
  105. {
  106. if (!m_IsCaptured)
  107. return;
  108. EditMode.DrawTrimGUI(state, m_TrimClipHandler.clipGUI, m_TrimClipHandler.trimDirection);
  109. bool trimStart = m_TrimClipHandler.trimDirection == TrimEdge.Start;
  110. TimeIndicator.Draw(state, trimStart ? m_TrimClipHandler.clipGUI.start : m_TrimClipHandler.clipGUI.end);
  111. if (m_SnapEngine != null)
  112. m_SnapEngine.OnGUI(trimStart, !trimStart);
  113. if (m_OverlayStrings.Count > 0)
  114. {
  115. const float padding = 4.0f;
  116. var labelStyle = TimelineWindow.styles.tinyFont;
  117. var longestLine = labelStyle.CalcSize(
  118. new GUIContent(m_OverlayStrings.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur)));
  119. var stringLength = longestLine.x + padding;
  120. var lineHeight = longestLine.y + padding;
  121. var r = new Rect(evt.mousePosition.x - (stringLength / 2.0f),
  122. m_TrimClipHandler.clipGUI.rect.yMax,
  123. stringLength, lineHeight);
  124. foreach (var s in m_OverlayStrings)
  125. {
  126. GUI.Label(r, s, labelStyle);
  127. r.y += lineHeight;
  128. }
  129. }
  130. }
  131. void RefreshOverlayStrings(TimelineClipHandle handle, WindowState state)
  132. {
  133. m_OverlayStrings.Clear();
  134. m_OverlayText.Length = 0;
  135. var differenceDuration = handle.clipGUI.clip.duration - m_OriginalDuration;
  136. bool hasDurationDelta = Math.Abs(differenceDuration) > kEpsilon;
  137. if (state.timeInFrames)
  138. {
  139. var durationInFrame = handle.clipGUI.clip.duration * state.referenceSequence.frameRate;
  140. m_OverlayText.Append("duration: ").Append(durationInFrame.ToString("f2")).Append(" frames");
  141. if (hasDurationDelta)
  142. {
  143. m_OverlayText.Append(" (");
  144. if (differenceDuration > 0.0)
  145. m_OverlayText.Append("+");
  146. var valueInFrame = differenceDuration * state.referenceSequence.frameRate;
  147. m_OverlayText.Append(valueInFrame.ToString("f2")).Append(" frames)");
  148. }
  149. }
  150. else
  151. {
  152. m_OverlayText.Append("duration: ").Append(handle.clipGUI.clip.duration.ToString("f2")).Append("s");
  153. if (hasDurationDelta)
  154. {
  155. m_OverlayText.Append(" (");
  156. if (differenceDuration > 0.0)
  157. m_OverlayText.Append("+");
  158. m_OverlayText.Append(differenceDuration.ToString("f2")).Append("s)");
  159. }
  160. }
  161. m_OverlayStrings.Add(m_OverlayText.ToString());
  162. m_OverlayText.Length = 0;
  163. var differenceSpeed = m_OriginalTimeScale - handle.clipGUI.clip.timeScale;
  164. if (Math.Abs(differenceSpeed) > kEpsilon)
  165. {
  166. m_OverlayText.Append("speed: ").Append(handle.clipGUI.clip.timeScale.ToString("p2"));
  167. m_OverlayText.Append(" (");
  168. if (differenceSpeed > 0.0)
  169. m_OverlayText.Append("+");
  170. m_OverlayText.Append(differenceSpeed.ToString("p2")).Append(")");
  171. m_OverlayStrings.Add(m_OverlayText.ToString());
  172. }
  173. }
  174. }
  175. }