SelectAndMoveItem.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using System;
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.Timeline;
  5. namespace UnityEditor.Timeline
  6. {
  7. class ClearSelection : Manipulator
  8. {
  9. protected override bool MouseDown(Event evt, WindowState state)
  10. {
  11. // If we hit this point this means no one used the mouse down events. We can safely clear the selection if needed
  12. if (evt.button != 0)
  13. return false;
  14. var window = state.GetWindow();
  15. if (!window.sequenceRect.Contains(evt.mousePosition))
  16. return false;
  17. if (ItemSelection.CanClearSelection(evt))
  18. {
  19. SelectionManager.Clear();
  20. return true;
  21. }
  22. return false;
  23. }
  24. }
  25. static class ItemSelection
  26. {
  27. public static bool CanClearSelection(Event evt)
  28. {
  29. return !evt.control && !evt.command && !evt.shift;
  30. }
  31. public static void RangeSelectItems(ITimelineItem lastItemToSelect)
  32. {
  33. var selectSorted = SelectionManager.SelectedItems().ToList();
  34. var firstSelect = selectSorted.FirstOrDefault();
  35. if (firstSelect == null)
  36. {
  37. SelectionManager.Add(lastItemToSelect);
  38. return;
  39. }
  40. var allTracks = TimelineEditor.inspectedAsset.flattenedTracks;
  41. var allItems = allTracks.SelectMany(ItemsUtils.GetItems).ToList();
  42. TimelineHelpers.RangeSelect(allItems, selectSorted, lastItemToSelect, SelectionManager.Add, SelectionManager.Remove);
  43. }
  44. public static ISelectable HandleSingleSelection(Event evt)
  45. {
  46. var item = PickerUtils.PickedLayerableOfType<ISelectable>();
  47. if (item != null)
  48. {
  49. var selected = item.IsSelected();
  50. if (!selected && CanClearSelection(evt))
  51. SelectionManager.Clear();
  52. if (evt.modifiers == EventModifiers.Shift)
  53. {
  54. if (!selected)
  55. RangeSelectItems((item as TimelineItemGUI).item);
  56. }
  57. else
  58. {
  59. HandleItemSelection(evt, item);
  60. }
  61. }
  62. return item;
  63. }
  64. public static void HandleItemSelection(Event evt, ISelectable item)
  65. {
  66. if (evt.modifiers == ManipulatorsUtils.actionModifier)
  67. {
  68. if (item.IsSelected())
  69. item.Deselect();
  70. else
  71. item.Select();
  72. }
  73. else
  74. {
  75. if (!item.IsSelected())
  76. item.Select();
  77. }
  78. }
  79. }
  80. class SelectAndMoveItem : Manipulator
  81. {
  82. bool m_Dragged;
  83. SnapEngine m_SnapEngine;
  84. TimeAreaAutoPanner m_TimeAreaAutoPanner;
  85. Vector2 m_MouseDownPosition;
  86. bool m_HorizontalMovementDone;
  87. bool m_VerticalMovementDone;
  88. MoveItemHandler m_MoveItemHandler;
  89. bool m_CycleMarkersPending;
  90. protected override bool MouseDown(Event evt, WindowState state)
  91. {
  92. if (evt.alt || evt.button != 0)
  93. return false;
  94. m_Dragged = false;
  95. // Cycling markers and selection are mutually exclusive operations
  96. if (!HandleMarkerCycle() && !HandleSingleSelection(evt))
  97. return false;
  98. m_MouseDownPosition = evt.mousePosition;
  99. m_VerticalMovementDone = false;
  100. m_HorizontalMovementDone = false;
  101. return true;
  102. }
  103. protected override bool MouseUp(Event evt, WindowState state)
  104. {
  105. if (!m_Dragged)
  106. {
  107. var item = PickerUtils.PickedLayerableOfType<ISelectable>();
  108. if (item == null)
  109. return false;
  110. if (!item.IsSelected())
  111. return false;
  112. // Re-selecting an item part of a multi-selection should only keep this item selected.
  113. if (SelectionManager.Count() > 1 && ItemSelection.CanClearSelection(evt))
  114. {
  115. SelectionManager.Clear();
  116. item.Select();
  117. return true;
  118. }
  119. if (m_CycleMarkersPending)
  120. {
  121. m_CycleMarkersPending = false;
  122. TimelineMarkerClusterGUI.CycleMarkers();
  123. return true;
  124. }
  125. return false;
  126. }
  127. m_TimeAreaAutoPanner = null;
  128. DropItems();
  129. m_SnapEngine = null;
  130. m_MoveItemHandler = null;
  131. state.Evaluate();
  132. state.RemoveCaptured(this);
  133. m_Dragged = false;
  134. TimelineCursors.ClearCursor();
  135. return true;
  136. }
  137. protected override bool DoubleClick(Event evt, WindowState state)
  138. {
  139. return MouseDown(evt, state) && MouseUp(evt, state);
  140. }
  141. protected override bool MouseDrag(Event evt, WindowState state)
  142. {
  143. if (state.editSequence.isReadOnly)
  144. return false;
  145. // case 1099285 - ctrl-click can cause no clips to be selected
  146. var selectedItemsGUI = SelectionManager.SelectedItems();
  147. if (!selectedItemsGUI.Any())
  148. {
  149. m_Dragged = false;
  150. return false;
  151. }
  152. const float hDeadZone = 5.0f;
  153. const float vDeadZone = 5.0f;
  154. bool vDone = m_VerticalMovementDone || Math.Abs(evt.mousePosition.y - m_MouseDownPosition.y) > vDeadZone;
  155. bool hDone = m_HorizontalMovementDone || Math.Abs(evt.mousePosition.x - m_MouseDownPosition.x) > hDeadZone;
  156. m_CycleMarkersPending = false;
  157. if (!m_Dragged)
  158. {
  159. var canStartMove = vDone || hDone;
  160. if (canStartMove)
  161. {
  162. state.AddCaptured(this);
  163. m_Dragged = true;
  164. var referenceTrack = GetTrackDropTargetAt(state, m_MouseDownPosition);
  165. foreach (var item in selectedItemsGUI)
  166. item.gui.StartDrag();
  167. m_MoveItemHandler = new MoveItemHandler(state);
  168. m_MoveItemHandler.Grab(selectedItemsGUI, referenceTrack, m_MouseDownPosition);
  169. m_SnapEngine = new SnapEngine(m_MoveItemHandler, m_MoveItemHandler, ManipulateEdges.Both,
  170. state, m_MouseDownPosition);
  171. m_TimeAreaAutoPanner = new TimeAreaAutoPanner(state);
  172. }
  173. }
  174. if (!m_VerticalMovementDone)
  175. {
  176. m_VerticalMovementDone = vDone;
  177. if (m_VerticalMovementDone)
  178. m_MoveItemHandler.OnTrackDetach();
  179. }
  180. if (!m_HorizontalMovementDone)
  181. {
  182. m_HorizontalMovementDone = hDone;
  183. }
  184. if (m_Dragged)
  185. {
  186. if (m_HorizontalMovementDone)
  187. m_SnapEngine.Snap(evt.mousePosition, evt.modifiers);
  188. if (m_VerticalMovementDone)
  189. {
  190. var track = GetTrackDropTargetAt(state, evt.mousePosition);
  191. m_MoveItemHandler.UpdateTrackTarget(track);
  192. }
  193. state.Evaluate();
  194. }
  195. return true;
  196. }
  197. public override void Overlay(Event evt, WindowState state)
  198. {
  199. if (!m_Dragged)
  200. return;
  201. if (m_TimeAreaAutoPanner != null)
  202. m_TimeAreaAutoPanner.OnGUI(evt);
  203. m_MoveItemHandler.OnGUI(evt);
  204. if (!m_MoveItemHandler.allowTrackSwitch || m_MoveItemHandler.targetTrack != null)
  205. {
  206. TimeIndicator.Draw(state, m_MoveItemHandler.start, m_MoveItemHandler.end);
  207. m_SnapEngine.OnGUI();
  208. }
  209. }
  210. bool HandleMarkerCycle()
  211. {
  212. m_CycleMarkersPending = TimelineMarkerClusterGUI.CanCycleMarkers();
  213. return m_CycleMarkersPending;
  214. }
  215. bool HandleSingleSelection(Event evt)
  216. {
  217. return ItemSelection.HandleSingleSelection(evt) != null;
  218. }
  219. void DropItems()
  220. {
  221. // Order matters here: m_MoveItemHandler.movingItems is destroyed during call to Drop()
  222. foreach (var movingItem in m_MoveItemHandler.movingItems)
  223. {
  224. foreach (var item in movingItem.items)
  225. item.gui.StopDrag();
  226. }
  227. m_MoveItemHandler.Drop();
  228. }
  229. static TrackAsset GetTrackDropTargetAt(WindowState state, Vector2 point)
  230. {
  231. var track = state.spacePartitioner.GetItemsAtPosition<IRowGUI>(point).FirstOrDefault();
  232. return track != null ? track.asset : null;
  233. }
  234. }
  235. }