FTrackEditor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. using UnityEngine;
  2. using UnityEditor;
  3. using UnityEditor.AnimatedValues;
  4. using UnityEditorInternal;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Reflection;
  8. using Flux;
  9. namespace FluxEditor
  10. {
  11. public class FTrackEditor : FEditor
  12. {
  13. public const int DEFAULT_TRACK_HEIGHT = 20;
  14. public const int KEYFRAME_WIDTH = 4;
  15. public const int KEYFRAME_HALF_WIDTH = KEYFRAME_WIDTH / 2;
  16. public FTrack Track { get { return (FTrack)Obj; } }
  17. public List<FEventEditor> _eventEditors = new List<FEventEditor>();
  18. public FTimelineEditor TimelineEditor { get { return (FTimelineEditor)Owner; } }
  19. private GUIContent _enableContent;
  20. public float HeaderWidth { get; private set; }
  21. protected override void OnEnable()
  22. {
  23. base.OnEnable ();
  24. _enableContent = new GUIContent( (Texture2D)AssetDatabase.LoadAssetAtPath(FUtility.GetFluxSkinPath()+"View.png", typeof(Texture2D)), "Enable/Disable Track" );
  25. }
  26. public override void Init( FObject obj, FEditor owner )
  27. {
  28. base.Init( obj, owner );
  29. _eventEditors.Clear();
  30. List<FEvent> events = Track.Events;
  31. for( int i = 0; i < events.Count; ++i )
  32. {
  33. FEvent evt = events[i];
  34. FEventEditor evtEditor = SequenceEditor.GetEditor<FEventEditor>( evt );
  35. evtEditor.Init( evt, this );
  36. _eventEditors.Add( evtEditor );
  37. }
  38. }
  39. public virtual void OnStop()
  40. {
  41. }
  42. public override float Height {
  43. get {
  44. return _eventEditors != null && _eventEditors.Count > 0 ? _eventEditors[0].Height : DEFAULT_TRACK_HEIGHT;
  45. }
  46. }
  47. public override void ReserveGuiIds()
  48. {
  49. base.ReserveGuiIds();
  50. for( int i = 0; i != _eventEditors.Count; ++i )
  51. {
  52. _eventEditors[i].ReserveGuiIds();
  53. }
  54. }
  55. public void SelectEvents( FrameRange range )
  56. {
  57. for( int i = 0; i != _eventEditors.Count; ++i )
  58. {
  59. if( range.Overlaps( _eventEditors[i].Evt.FrameRange ) )
  60. SequenceEditor.Select( _eventEditors[i] );
  61. else if( _eventEditors[i].Evt.Start > range.End )
  62. break;
  63. }
  64. }
  65. public void DeselectEvents( FrameRange range )
  66. {
  67. for( int i = 0; i != _eventEditors.Count; ++i )
  68. {
  69. if( range.Overlaps( _eventEditors[i].Evt.FrameRange ) )
  70. SequenceEditor.Deselect( _eventEditors[i] );
  71. else if( _eventEditors[i].Evt.Start > range.End )
  72. break;
  73. }
  74. }
  75. protected virtual void RenderHeader( Rect labelRect, GUIContent label )
  76. {
  77. GUI.Label( labelRect, label, FGUI.GetTrackHeaderStyle() );
  78. }
  79. public override void Render( Rect rect, float headerWidth )
  80. {
  81. Rect = rect;
  82. HeaderWidth = headerWidth;
  83. Rect headerRect = rect;
  84. headerRect.width = headerWidth;
  85. Rect enableButtonRect = rect;
  86. enableButtonRect.xMax = rect.xMin+headerWidth;
  87. enableButtonRect.xMin = enableButtonRect.xMax-16;
  88. enableButtonRect.height = 16;
  89. Rect trackHeaderRect = rect;
  90. trackHeaderRect.width = headerWidth;
  91. Color guiColor = GUI.color;
  92. bool selected = _isSelected;
  93. if( selected )
  94. {
  95. Color c = FGUI.GetSelectionColor();
  96. c.a = GUI.color.a;
  97. GUI.color = c;
  98. GUI.DrawTexture( trackHeaderRect, EditorGUIUtility.whiteTexture );
  99. GUI.color = guiColor;
  100. }
  101. GUI.color = GetPreviewIconColor();
  102. if( !Track.enabled )
  103. {
  104. Color c = guiColor;
  105. c.a = 0.5f;
  106. GUI.color = c;
  107. }
  108. if( FGUI.Button(enableButtonRect, _enableContent) )
  109. {
  110. if( Event.current.shift ) // turn all?
  111. {
  112. SequenceEditor.EnableAllTracks( !Track.enabled );
  113. }
  114. else
  115. {
  116. OnToggle( !Track.enabled );
  117. }
  118. FUtility.RepaintGameView();
  119. Event.current.Use();
  120. }
  121. Rect trackLabelRect = trackHeaderRect;
  122. trackLabelRect.xMin += 8;
  123. RenderHeader( trackLabelRect, new GUIContent(Track.name) );
  124. rect.xMin = trackHeaderRect.xMax;
  125. if( rect.Contains( Event.current.mousePosition ) )
  126. SequenceEditor.SetMouseHover( Event.current.mousePosition.x - rect.xMin, this );
  127. FrameRange validKeyframeRange = new FrameRange(0, SequenceEditor.Sequence.Length);
  128. _contentOffset = rect.min;
  129. GUI.BeginGroup(rect);
  130. rect.x = 0;
  131. rect.y = 0;
  132. for( int i = 0; i != _eventEditors.Count; ++i )
  133. {
  134. if( i == 0 )
  135. validKeyframeRange.Start = 0;
  136. else
  137. validKeyframeRange.Start = _eventEditors[i-1].Evt.End;
  138. if( i == _eventEditors.Count-1 )
  139. validKeyframeRange.End = SequenceEditor.Sequence.Length;
  140. else
  141. validKeyframeRange.End = _eventEditors[i+1].Evt.Start;
  142. rect.xMin = SequenceEditor.GetXForFrame(_eventEditors[i].Evt.Start);
  143. rect.xMax = SequenceEditor.GetXForFrame(_eventEditors[i].Evt.End);
  144. _eventEditors[i].Render( rect, SequenceEditor.ViewRange, SequenceEditor.PixelsPerFrame, validKeyframeRange );
  145. }
  146. GUI.EndGroup();
  147. switch( Event.current.type )
  148. {
  149. case EventType.ContextClick:
  150. if( trackHeaderRect.Contains(Event.current.mousePosition) )
  151. {
  152. OnHeaderContextClick();
  153. }
  154. else if( Rect.Contains( Event.current.mousePosition ) )
  155. {
  156. OnBodyContextClick();
  157. }
  158. break;
  159. case EventType.MouseDown:
  160. if( EditorGUIUtility.hotControl == 0 && trackHeaderRect.Contains(Event.current.mousePosition) )
  161. {
  162. if( Event.current.button == 0 ) // selecting
  163. {
  164. if( Event.current.control )
  165. {
  166. if( IsSelected )
  167. SequenceEditor.Deselect( this );
  168. else
  169. SequenceEditor.Select( this );
  170. }
  171. else if( Event.current.shift )
  172. {
  173. SequenceEditor.Select( this );
  174. }
  175. else
  176. {
  177. SequenceEditor.SelectExclusive( this );
  178. }
  179. Event.current.Use();
  180. }
  181. }
  182. break;
  183. case EventType.MouseUp:
  184. break;
  185. case EventType.MouseDrag:
  186. break;
  187. }
  188. Handles.color = FGUI.GetLineColor();
  189. Handles.DrawLine( Rect.min, Rect.min + new Vector2(Rect.width, 0) );
  190. Handles.DrawLine( Rect.max, Rect.max - new Vector2(Rect.width, 0) );
  191. GUI.color = guiColor;
  192. }
  193. public virtual void OnToggle( bool on )
  194. {
  195. Undo.RecordObject( Track, on ? "enable" : "disable" );
  196. Track.enabled = on;
  197. EditorUtility.SetDirty(Track);
  198. if( Track.RequiresEditorCache )
  199. {
  200. if( on )
  201. {
  202. Track.CreateCache();
  203. }
  204. else
  205. {
  206. Track.ClearCache();
  207. }
  208. }
  209. if( !SequenceEditor.Sequence.IsStopped )
  210. {
  211. int currentFrame = SequenceEditor.Sequence.CurrentFrame;
  212. SequenceEditor.Stop();
  213. SequenceEditor.SetCurrentFrame(currentFrame);
  214. }
  215. SequenceEditor.SetDirty(this);
  216. SequenceEditor.NotifyDirtyTracks();
  217. }
  218. public override void OnDelete()
  219. {
  220. base.OnDelete();
  221. if( Track.HasCache )
  222. Track.ClearCache();
  223. }
  224. protected virtual Color GetPreviewIconColor()
  225. {
  226. return FGUI.GetIconColor();
  227. }
  228. public virtual void OnToolsGUI()
  229. {
  230. }
  231. public virtual bool HasTools() { return false; }
  232. protected virtual void OnHeaderContextClick()
  233. {
  234. GenericMenu menu = new GenericMenu();
  235. menu.AddItem( new GUIContent( "Copy" ), false, Copy );
  236. menu.AddItem( new GUIContent( "Cut" ), false, Cut );
  237. menu.AddItem( new GUIContent( "Duplicate" ), false, Duplicate );
  238. menu.AddItem( new GUIContent( "Delete" ), false, Delete );
  239. menu.ShowAsContext();
  240. Event.current.Use();
  241. }
  242. protected virtual void OnBodyContextClick()
  243. {
  244. int t = SequenceEditor.GetFrameForX( Event.current.mousePosition.x-HeaderWidth );
  245. GUIContent selectAllEvents = new GUIContent("Select All Events");
  246. GUIContent addEventAtFrame = new GUIContent("Add Event At Frame");
  247. GUIContent addEventFillGap = new GUIContent("Add Event Fill Gap");
  248. GUIContent pasteEvent = new GUIContent("Paste Event");
  249. GenericMenu menu = new GenericMenu();
  250. menu.AddItem( selectAllEvents, false, SelectAllEvents );
  251. if( Track.CanAddAt( t ) )
  252. {
  253. menu.AddItem( addEventAtFrame, false, AddEventAtPoint, t );
  254. menu.AddItem( addEventFillGap, false, AddEventFillGap, t );
  255. }
  256. else
  257. {
  258. menu.AddDisabledItem( addEventAtFrame );
  259. menu.AddDisabledItem( addEventFillGap );
  260. }
  261. if( FSequenceEditor.CopyObject != null )
  262. {
  263. FEvent copyEvt = FSequenceEditor.CopyObject as FEvent;
  264. if( copyEvt != null )
  265. {
  266. if( FSequenceEditor.CopyObject.GetType() != Track.GetEventType() )
  267. {
  268. menu.AddDisabledItem( pasteEvent );
  269. }
  270. else
  271. {
  272. FEvent eventBefore = Track.GetEventBefore(t);
  273. FEvent eventAfter = Track.GetEventAfter(t);
  274. FrameRange validRange = new FrameRange( eventBefore == null ? 0 : eventBefore.End, eventAfter == null ? SequenceEditor.Sequence.Length : eventAfter.Start );
  275. if( validRange.Length >= copyEvt.Length )
  276. menu.AddItem( pasteEvent, false, PasteEvent, t );
  277. else
  278. menu.AddDisabledItem( pasteEvent );
  279. }
  280. }
  281. }
  282. menu.ShowAsContext();
  283. Event.current.Use();
  284. }
  285. private void PasteEvent( object frameBoxed )
  286. {
  287. int frame = (int)frameBoxed;
  288. FEvent evt = Instantiate<FEvent>((FEvent)FSequenceEditor.CopyObject);
  289. evt.hideFlags = Track.hideFlags;
  290. Undo.RegisterCreatedObjectUndo( evt.gameObject, "Paste " + FSequenceEditor.CopyObject.name );
  291. Undo.RecordObject( Track, string.Empty );
  292. int evtLength = evt.Length;
  293. int maxEvtLength;
  294. if( Track.CanAddAt(frame, out maxEvtLength) && maxEvtLength >= evtLength )
  295. {
  296. int delta = frame - evt.Start;
  297. evt.Start += delta;
  298. evt.End += delta;
  299. }
  300. else
  301. {
  302. evt.End = frame + maxEvtLength;
  303. evt.Start = evt.End - evtLength;
  304. }
  305. Undo.SetTransformParent( evt.transform, Track.transform, string.Empty );
  306. Track.Add( evt );
  307. }
  308. private void Copy()
  309. {
  310. SequenceEditor.CopyEditor(this);
  311. }
  312. private void Cut()
  313. {
  314. SequenceEditor.CutEditor(this);
  315. }
  316. private void Duplicate()
  317. {
  318. Undo.RecordObjects( new UnityEngine.Object[]{ TimelineEditor, Track.Timeline }, string.Empty );
  319. GameObject duplicateTrack = (GameObject)Instantiate( Track.gameObject );
  320. duplicateTrack.name = Track.gameObject.name;
  321. Undo.SetTransformParent( duplicateTrack.transform, Track.Timeline.transform, string.Empty );
  322. Undo.RegisterCreatedObjectUndo( duplicateTrack, "duplicate Track" );
  323. if( !SequenceEditor.Sequence.IsStopped )
  324. duplicateTrack.GetComponent<FTrack>().Init();
  325. }
  326. private void Delete()
  327. {
  328. SequenceEditor.DestroyEditor( this );
  329. }
  330. private void SelectAllEvents()
  331. {
  332. SelectEvents( new FrameRange(0, Track.Sequence.Length) );
  333. }
  334. private void AddEventAtPoint( object userData )
  335. {
  336. int t = (int)userData;
  337. TryAddEvent( t );
  338. }
  339. private void AddEventFillGap( object userData )
  340. {
  341. int t = (int)userData;
  342. int newT = -1;
  343. List<FEvent> evts = Track.Events;
  344. for( int i = 0; i != evts.Count; ++i )
  345. {
  346. if( evts[i].FrameRange.ContainsExclusive( t ) )
  347. return; // can't add
  348. if( evts[i].FrameRange.Start >= t )
  349. {
  350. newT = i == 0 ? 0 : evts[i-1].End;
  351. break;
  352. }
  353. }
  354. if( newT == -1 )
  355. {
  356. newT = evts.Count == 0 ? 0 : evts[evts.Count-1].End;
  357. }
  358. TryAddEvent( newT );
  359. }
  360. public override FSequenceEditor SequenceEditor { get { return TimelineEditor != null ? TimelineEditor.SequenceEditor : null; } }
  361. private Type[] _fcEventTypes = null;
  362. public void ShowTrackMenu( FTrack track )
  363. {
  364. if( _fcEventTypes == null )
  365. {
  366. _fcEventTypes = new Type[0];
  367. Type[] allTypes = typeof(FEvent).Assembly.GetTypes();
  368. foreach( Type type in allTypes )
  369. {
  370. if( type.IsSubclassOf( typeof(FEvent) ) && !type.IsAbstract )
  371. {
  372. object[] attributes = type.GetCustomAttributes( typeof(FEventAttribute), false );
  373. if( attributes.Length == 1 )
  374. {
  375. ArrayUtility.Add<Type>( ref _fcEventTypes, type );
  376. }
  377. }
  378. }
  379. }
  380. GenericMenu menu = new GenericMenu();
  381. foreach( Type t in _fcEventTypes )
  382. {
  383. TimelineMenuData param = new TimelineMenuData();
  384. param.track = track; param.evtType = t;
  385. object[] attributes = t.GetCustomAttributes(typeof(FEventAttribute), false);
  386. menu.AddItem( new GUIContent( ((FEventAttribute)attributes[0]).menu ), false, AddEventToTrack, param );
  387. }
  388. menu.ShowAsContext();
  389. }
  390. private struct TimelineMenuData
  391. {
  392. public FTrack track;
  393. public Type evtType;
  394. }
  395. private void AddEventToTrack( object obj )
  396. {
  397. TimelineMenuData menuData = (TimelineMenuData)obj;
  398. GameObject go = new GameObject(menuData.evtType.ToString());
  399. FEvent evt = (FEvent)go.AddComponent(menuData.evtType);
  400. menuData.track.Add( evt );
  401. SequenceEditor.Refresh();
  402. }
  403. public FrameRange GetValidRange( FEventEditor evtEditor )
  404. {
  405. int index = 0;
  406. for( ; index < _eventEditors.Count; ++index )
  407. {
  408. if( _eventEditors[index] == evtEditor )
  409. {
  410. break;
  411. }
  412. }
  413. FrameRange range = new FrameRange( 0, SequenceEditor.Sequence.Length );
  414. if( index > 0 )
  415. {
  416. range.Start = _eventEditors[index-1].Evt.End+1;
  417. }
  418. if( index < _eventEditors.Count-1 )
  419. {
  420. range.End = _eventEditors[index+1].Evt.Start-1;
  421. }
  422. return range;
  423. }
  424. public FEvent TryAddEvent( int t )
  425. {
  426. FEvent newEvt = null;
  427. if( Track.CanAddAt( t ) )
  428. {
  429. FEvent evtAfterT = Track.GetEventAfter( t );
  430. int newEventEndT;
  431. if( evtAfterT == null )
  432. newEventEndT = SequenceEditor.Sequence.Length;
  433. else
  434. newEventEndT = evtAfterT.Start;
  435. newEvt = FEvent.Create( Track.GetEventType(), new FrameRange( t, newEventEndT ) );
  436. Undo.RecordObject( Track, string.Empty );
  437. Undo.RegisterCreatedObjectUndo( newEvt.gameObject, "create Event" );
  438. Track.Add( newEvt );
  439. newEvt.SetDefaultValues();
  440. }
  441. return newEvt;
  442. }
  443. public virtual void OnTrackChanged()
  444. {
  445. }
  446. public virtual void UpdateEventsEditor( int frame, float time )
  447. {
  448. // Track.UpdateEventsEditor( frame, time );
  449. }
  450. }
  451. }