AnimationWindow.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Collections.Generic;
  5. using BansheeEngine;
  6. namespace BansheeEditor
  7. {
  8. /** @addtogroup Windows
  9. * @{
  10. */
  11. /// <summary>
  12. /// Displays animation curve editor window.
  13. /// </summary>
  14. [DefaultSize(900, 500)]
  15. internal class AnimationWindow : EditorWindow
  16. {
  17. /// <summary>
  18. /// A set of animation curves for a field of a certain type.
  19. /// </summary>
  20. private struct FieldCurves
  21. {
  22. public SerializableProperty.FieldType type;
  23. public EdAnimationCurve[] curves;
  24. }
  25. private const int FIELD_DISPLAY_WIDTH = 200;
  26. private bool isInitialized;
  27. private GUIButton playButton;
  28. private GUIButton recordButton;
  29. private GUIButton prevFrameButton;
  30. private GUIIntField frameInputField;
  31. private GUIButton nextFrameButton;
  32. private GUIButton addKeyframeButton;
  33. private GUIButton addEventButton;
  34. private GUIButton optionsButton;
  35. private GUIButton addPropertyBtn;
  36. private GUIButton delPropertyBtn;
  37. private GUILayout buttonLayout;
  38. private int buttonLayoutHeight;
  39. private int scrollBarWidth;
  40. private int scrollBarHeight;
  41. private GUIResizeableScrollBarH horzScrollBar;
  42. private GUIResizeableScrollBarV vertScrollBar;
  43. private GUIPanel editorPanel;
  44. private GUIAnimFieldDisplay guiFieldDisplay;
  45. private GUICurveEditor guiCurveEditor;
  46. private SceneObject selectedSO;
  47. private int currentFrameIdx;
  48. private int fps = 1;
  49. private Dictionary<string, FieldCurves> curves = new Dictionary<string, FieldCurves>();
  50. private List<string> selectedFields = new List<string>();
  51. internal int FPS
  52. {
  53. get { return fps; }
  54. set { guiCurveEditor.SetFPS(value); fps = MathEx.Max(value, 1); }
  55. }
  56. /// <summary>
  57. /// Opens the animation window.
  58. /// </summary>
  59. [MenuItem("Windows/Animation", ButtonModifier.CtrlAlt, ButtonCode.A, 6000)]
  60. private static void OpenGameWindow()
  61. {
  62. OpenWindow<AnimationWindow>();
  63. }
  64. /// <inheritdoc/>
  65. protected override LocString GetDisplayName()
  66. {
  67. return new LocEdString("Animation");
  68. }
  69. private void OnInitialize()
  70. {
  71. Selection.OnSelectionChanged += OnSelectionChanged;
  72. EditorInput.OnPointerPressed += OnPointerPressed;
  73. EditorInput.OnPointerMoved += OnPointerMoved;
  74. EditorInput.OnPointerReleased += OnPointerReleased;
  75. EditorInput.OnButtonUp += OnButtonUp;
  76. Rebuild();
  77. }
  78. private void OnEditorUpdate()
  79. {
  80. }
  81. private void OnDestroy()
  82. {
  83. Selection.OnSelectionChanged -= OnSelectionChanged;
  84. EditorInput.OnPointerPressed -= OnPointerPressed;
  85. EditorInput.OnPointerMoved -= OnPointerMoved;
  86. EditorInput.OnPointerReleased -= OnPointerReleased;
  87. EditorInput.OnButtonUp -= OnButtonUp;
  88. }
  89. protected override void WindowResized(int width, int height)
  90. {
  91. if (!isInitialized)
  92. return;
  93. guiFieldDisplay.SetSize(FIELD_DISPLAY_WIDTH, height - buttonLayoutHeight*2);
  94. Vector2I curveEditorSize = GetCurveEditorSize();
  95. guiCurveEditor.SetSize(curveEditorSize.x, curveEditorSize.y);
  96. guiCurveEditor.Redraw();
  97. horzScrollBar.SetWidth(curveEditorSize.x);
  98. vertScrollBar.SetHeight(curveEditorSize.y);
  99. }
  100. private void Rebuild()
  101. {
  102. GUI.Clear();
  103. selectedFields.Clear();
  104. curves.Clear();
  105. isInitialized = false;
  106. selectedSO = Selection.SceneObject;
  107. if (selectedSO == null)
  108. {
  109. GUILabel warningLbl = new GUILabel(new LocEdString("Select an object to animate in the Hierarchy or Scene windows."));
  110. GUILayoutY vertLayout = GUI.AddLayoutY();
  111. vertLayout.AddFlexibleSpace();
  112. GUILayoutX horzLayout = vertLayout.AddLayoutX();
  113. vertLayout.AddFlexibleSpace();
  114. horzLayout.AddFlexibleSpace();
  115. horzLayout.AddElement(warningLbl);
  116. horzLayout.AddFlexibleSpace();
  117. return;
  118. }
  119. // TODO - Retrieve Animation & AnimationClip from the selected object, fill curves dictionary
  120. // - If not available, show a button to create new animation clip
  121. // Top button row
  122. GUIContent playIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Play),
  123. new LocEdString("Play"));
  124. GUIContent recordIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.Record),
  125. new LocEdString("Record"));
  126. GUIContent prevFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameBack),
  127. new LocEdString("Previous frame"));
  128. GUIContent nextFrameIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.FrameForward),
  129. new LocEdString("Next frame"));
  130. GUIContent addKeyframeIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddKeyframe),
  131. new LocEdString("Add keyframe"));
  132. GUIContent addEventIcon = new GUIContent(EditorBuiltin.GetAnimationWindowIcon(AnimationWindowIcon.AddEvent),
  133. new LocEdString("Add event"));
  134. GUIContent optionsIcon = new GUIContent(EditorBuiltin.GetLibraryWindowIcon(LibraryWindowIcon.Options),
  135. new LocEdString("Options"));
  136. playButton = new GUIButton(playIcon);
  137. recordButton = new GUIButton(recordIcon);
  138. prevFrameButton = new GUIButton(prevFrameIcon);
  139. frameInputField = new GUIIntField();
  140. nextFrameButton = new GUIButton(nextFrameIcon);
  141. addKeyframeButton = new GUIButton(addKeyframeIcon);
  142. addEventButton = new GUIButton(addEventIcon);
  143. optionsButton = new GUIButton(optionsIcon);
  144. playButton.OnClick += () =>
  145. {
  146. // TODO
  147. // - Record current state of the scene object hierarchy
  148. // - Evaluate all curves manually and update them
  149. // - On end, restore original values of the scene object hierarchy
  150. };
  151. recordButton.OnClick += () =>
  152. {
  153. // TODO
  154. // - Every frame read back current values of all the current curve's properties and assign it to the current frame
  155. };
  156. prevFrameButton.OnClick += () =>
  157. {
  158. SetCurrentFrame(currentFrameIdx - 1);
  159. };
  160. frameInputField.OnChanged += SetCurrentFrame;
  161. nextFrameButton.OnClick += () =>
  162. {
  163. SetCurrentFrame(currentFrameIdx + 1);
  164. };
  165. addKeyframeButton.OnClick += () =>
  166. {
  167. guiCurveEditor.AddKeyFrameAtMarker();
  168. // TODO - Update local curves?
  169. };
  170. addEventButton.OnClick += () =>
  171. {
  172. // TODO - Add event
  173. };
  174. optionsButton.OnClick += () =>
  175. {
  176. Vector2I openPosition = ScreenToWindowPos(Input.PointerPosition);
  177. AnimationOptions dropDown = DropDownWindow.Open<AnimationOptions>(this, openPosition);
  178. dropDown.Initialize(this);
  179. };
  180. // Property buttons
  181. addPropertyBtn = new GUIButton(new LocEdString("Add property"));
  182. delPropertyBtn = new GUIButton(new LocEdString("Delete selected"));
  183. addPropertyBtn.OnClick += () =>
  184. {
  185. Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition);
  186. FieldSelectionWindow fieldSelection = DropDownWindow.Open<FieldSelectionWindow>(this, windowPos);
  187. fieldSelection.OnFieldSelected += OnFieldAdded;
  188. };
  189. delPropertyBtn.OnClick += () =>
  190. {
  191. LocEdString title = new LocEdString("Warning");
  192. LocEdString message = new LocEdString("Are you sure you want to remove all selected fields?");
  193. DialogBox.Open(title, message, DialogBox.Type.YesNo, x =>
  194. {
  195. if (x == DialogBox.ResultType.Yes)
  196. {
  197. RemoveSelectedFields();
  198. }
  199. });
  200. };
  201. GUILayout mainLayout = GUI.AddLayoutY();
  202. buttonLayout = mainLayout.AddLayoutX();
  203. buttonLayout.AddSpace(5);
  204. buttonLayout.AddElement(playButton);
  205. buttonLayout.AddElement(recordButton);
  206. buttonLayout.AddSpace(5);
  207. buttonLayout.AddElement(prevFrameButton);
  208. buttonLayout.AddElement(frameInputField);
  209. buttonLayout.AddElement(nextFrameButton);
  210. buttonLayout.AddSpace(5);
  211. buttonLayout.AddElement(addKeyframeButton);
  212. buttonLayout.AddElement(addEventButton);
  213. buttonLayout.AddSpace(5);
  214. buttonLayout.AddElement(optionsButton);
  215. buttonLayout.AddFlexibleSpace();
  216. buttonLayoutHeight = playButton.Bounds.height;
  217. GUILayout contentLayout = mainLayout.AddLayoutX();
  218. GUILayout fieldDisplayLayout = contentLayout.AddLayoutY(GUIOption.FixedWidth(FIELD_DISPLAY_WIDTH));
  219. guiFieldDisplay = new GUIAnimFieldDisplay(fieldDisplayLayout, FIELD_DISPLAY_WIDTH,
  220. Height - buttonLayoutHeight * 2, selectedSO);
  221. guiFieldDisplay.OnEntrySelected += OnFieldSelected;
  222. GUILayout bottomButtonLayout = fieldDisplayLayout.AddLayoutX();
  223. bottomButtonLayout.AddElement(addPropertyBtn);
  224. bottomButtonLayout.AddElement(delPropertyBtn);
  225. horzScrollBar = new GUIResizeableScrollBarH();
  226. horzScrollBar.OnScrollOrResize += OnHorzScrollOrResize;
  227. vertScrollBar = new GUIResizeableScrollBarV();
  228. vertScrollBar.OnScrollOrResize += OnVertScrollOrResize;
  229. GUILayout curveLayout = contentLayout.AddLayoutY();
  230. GUILayout curveLayoutHorz = curveLayout.AddLayoutX();
  231. GUILayout horzScrollBarLayout = curveLayout.AddLayoutX();
  232. horzScrollBarLayout.AddElement(horzScrollBar);
  233. horzScrollBarLayout.AddFlexibleSpace();
  234. editorPanel = curveLayoutHorz.AddPanel();
  235. curveLayoutHorz.AddElement(vertScrollBar);
  236. curveLayoutHorz.AddFlexibleSpace();
  237. scrollBarHeight = horzScrollBar.Bounds.height;
  238. scrollBarWidth = vertScrollBar.Bounds.width;
  239. Vector2I curveEditorSize = GetCurveEditorSize();
  240. guiCurveEditor = new GUICurveEditor(this, editorPanel, curveEditorSize.x, curveEditorSize.y);
  241. guiCurveEditor.OnFrameSelected += OnFrameSelected;
  242. guiCurveEditor.Redraw();
  243. horzScrollBar.SetWidth(curveEditorSize.x);
  244. vertScrollBar.SetHeight(curveEditorSize.y);
  245. SetCurrentFrame(currentFrameIdx);
  246. isInitialized = true;
  247. }
  248. private void SetCurrentFrame(int frameIdx)
  249. {
  250. currentFrameIdx = Math.Max(0, frameIdx);
  251. frameInputField.Value = currentFrameIdx;
  252. guiCurveEditor.SetMarkedFrame(currentFrameIdx);
  253. float time = guiCurveEditor.GetTimeForFrame(currentFrameIdx);
  254. List<GUIAnimFieldPathValue> values = new List<GUIAnimFieldPathValue>();
  255. foreach (var kvp in curves)
  256. {
  257. SerializableProperty property = GUIAnimFieldDisplay.FindProperty(selectedSO, kvp.Key);
  258. if (property != null)
  259. {
  260. GUIAnimFieldPathValue fieldValue = new GUIAnimFieldPathValue();
  261. fieldValue.path = kvp.Key;
  262. switch (kvp.Value.type)
  263. {
  264. case SerializableProperty.FieldType.Vector2:
  265. {
  266. Vector2 value = new Vector2();
  267. for(int i = 0; i < 2; i++)
  268. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  269. fieldValue.value = value;
  270. }
  271. break;
  272. case SerializableProperty.FieldType.Vector3:
  273. {
  274. Vector3 value = new Vector3();
  275. for (int i = 0; i < 3; i++)
  276. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  277. fieldValue.value = value;
  278. }
  279. break;
  280. case SerializableProperty.FieldType.Vector4:
  281. {
  282. Vector4 value = new Vector4();
  283. for (int i = 0; i < 4; i++)
  284. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  285. fieldValue.value = value;
  286. }
  287. break;
  288. case SerializableProperty.FieldType.Color:
  289. {
  290. Color value = new Color();
  291. for (int i = 0; i < 4; i++)
  292. value[i] = kvp.Value.curves[i].Evaluate(time, false);
  293. fieldValue.value = value;
  294. }
  295. break;
  296. case SerializableProperty.FieldType.Bool:
  297. case SerializableProperty.FieldType.Int:
  298. case SerializableProperty.FieldType.Float:
  299. fieldValue.value = kvp.Value.curves[0].Evaluate(time, false); ;
  300. break;
  301. }
  302. values.Add(fieldValue);
  303. }
  304. }
  305. guiFieldDisplay.SetDisplayValues(values.ToArray());
  306. }
  307. private void OnPointerPressed(PointerEvent ev)
  308. {
  309. if (!isInitialized)
  310. return;
  311. guiCurveEditor.OnPointerPressed(ev);
  312. }
  313. private void OnPointerMoved(PointerEvent ev)
  314. {
  315. if (!isInitialized)
  316. return;
  317. guiCurveEditor.OnPointerMoved(ev);
  318. }
  319. private void OnPointerReleased(PointerEvent ev)
  320. {
  321. if (!isInitialized)
  322. return;
  323. guiCurveEditor.OnPointerReleased(ev);
  324. }
  325. private void OnButtonUp(ButtonEvent ev)
  326. {
  327. if (!isInitialized)
  328. return;
  329. guiCurveEditor.OnButtonUp(ev);
  330. }
  331. private void UpdateDisplayedCurves()
  332. {
  333. List<EdAnimationCurve> curvesToDisplay = new List<EdAnimationCurve>();
  334. for (int i = 0; i < selectedFields.Count; i++)
  335. {
  336. EdAnimationCurve curve;
  337. if(TryGetCurve(selectedFields[i], out curve))
  338. curvesToDisplay.Add(curve);
  339. }
  340. guiCurveEditor.SetCurves(curvesToDisplay.ToArray());
  341. float xRange;
  342. float yRange;
  343. CalculateRange(curvesToDisplay, out xRange, out yRange);
  344. // Don't allow zero range
  345. if (xRange == 0.0f)
  346. xRange = 60.0f;
  347. if (yRange == 0.0f)
  348. yRange = 10.0f;
  349. // Add padding to y range
  350. yRange *= 1.05f;
  351. // Don't reduce visible range
  352. xRange = Math.Max(xRange, guiCurveEditor.XRange);
  353. yRange = Math.Max(yRange, guiCurveEditor.YRange);
  354. guiCurveEditor.SetRange(xRange, yRange);
  355. guiCurveEditor.Redraw();
  356. }
  357. private Vector2I GetCurveEditorSize()
  358. {
  359. Vector2I output = new Vector2I();
  360. output.x = Math.Max(0, Width - FIELD_DISPLAY_WIDTH - scrollBarWidth);
  361. output.y = Math.Max(0, Height - buttonLayoutHeight - scrollBarHeight);
  362. return output;
  363. }
  364. private static void CalculateRange(List<EdAnimationCurve> curves, out float xRange, out float yRange)
  365. {
  366. xRange = 0.0f;
  367. yRange = 0.0f;
  368. foreach (var curve in curves)
  369. {
  370. KeyFrame[] keyframes = curve.KeyFrames;
  371. foreach (var key in keyframes)
  372. {
  373. xRange = Math.Max(xRange, key.time);
  374. yRange = Math.Max(yRange, Math.Abs(key.value));
  375. }
  376. }
  377. }
  378. private bool TryGetCurve(string path, out EdAnimationCurve curve)
  379. {
  380. int index = path.LastIndexOf(".");
  381. string parentPath;
  382. string subPathSuffix = null;
  383. if (index == -1)
  384. {
  385. parentPath = path;
  386. }
  387. else
  388. {
  389. parentPath = path.Substring(0, index);
  390. subPathSuffix = path.Substring(index, path.Length - index);
  391. }
  392. FieldCurves fieldCurves;
  393. if (curves.TryGetValue(parentPath, out fieldCurves))
  394. {
  395. if (!string.IsNullOrEmpty(subPathSuffix))
  396. {
  397. if (subPathSuffix == ".x" || subPathSuffix == ".r")
  398. {
  399. curve = fieldCurves.curves[0];
  400. return true;
  401. }
  402. else if (subPathSuffix == ".y" || subPathSuffix == ".g")
  403. {
  404. curve = fieldCurves.curves[1];
  405. return true;
  406. }
  407. else if (subPathSuffix == ".z" || subPathSuffix == ".b")
  408. {
  409. curve = fieldCurves.curves[2];
  410. return true;
  411. }
  412. else if (subPathSuffix == ".w" || subPathSuffix == ".a")
  413. {
  414. curve = fieldCurves.curves[3];
  415. return true;
  416. }
  417. }
  418. else
  419. {
  420. curve = fieldCurves.curves[0];
  421. return true;
  422. }
  423. }
  424. curve = null;
  425. return false;
  426. }
  427. private void OnFieldAdded(string path, SerializableProperty.FieldType type)
  428. {
  429. guiFieldDisplay.AddField(path);
  430. switch (type)
  431. {
  432. case SerializableProperty.FieldType.Vector4:
  433. {
  434. FieldCurves fieldCurves = new FieldCurves();
  435. fieldCurves.type = type;
  436. fieldCurves.curves = new EdAnimationCurve[4];
  437. string[] subPaths = { ".x", ".y", ".z", ".w" };
  438. for (int i = 0; i < subPaths.Length; i++)
  439. {
  440. string subFieldPath = path + subPaths[i];
  441. fieldCurves.curves[i] = new EdAnimationCurve();
  442. selectedFields.Add(subFieldPath);
  443. }
  444. curves[path] = fieldCurves;
  445. }
  446. break;
  447. case SerializableProperty.FieldType.Vector3:
  448. {
  449. FieldCurves fieldCurves = new FieldCurves();
  450. fieldCurves.type = type;
  451. fieldCurves.curves = new EdAnimationCurve[3];
  452. string[] subPaths = { ".x", ".y", ".z" };
  453. for (int i = 0; i < subPaths.Length; i++)
  454. {
  455. string subFieldPath = path + subPaths[i];
  456. fieldCurves.curves[i] = new EdAnimationCurve();
  457. selectedFields.Add(subFieldPath);
  458. }
  459. curves[path] = fieldCurves;
  460. }
  461. break;
  462. case SerializableProperty.FieldType.Vector2:
  463. {
  464. FieldCurves fieldCurves = new FieldCurves();
  465. fieldCurves.type = type;
  466. fieldCurves.curves = new EdAnimationCurve[2];
  467. string[] subPaths = { ".x", ".y" };
  468. for (int i = 0; i < subPaths.Length; i++)
  469. {
  470. string subFieldPath = path + subPaths[i];
  471. fieldCurves.curves[i] = new EdAnimationCurve();
  472. selectedFields.Add(subFieldPath);
  473. }
  474. curves[path] = fieldCurves;
  475. }
  476. break;
  477. case SerializableProperty.FieldType.Color:
  478. {
  479. FieldCurves fieldCurves = new FieldCurves();
  480. fieldCurves.type = type;
  481. fieldCurves.curves = new EdAnimationCurve[4];
  482. string[] subPaths = { ".r", ".g", ".b", ".a" };
  483. for (int i = 0; i < subPaths.Length; i++)
  484. {
  485. string subFieldPath = path + subPaths[i];
  486. fieldCurves.curves[i] = new EdAnimationCurve();
  487. selectedFields.Add(subFieldPath);
  488. }
  489. curves[path] = fieldCurves;
  490. }
  491. break;
  492. default: // Primitive type
  493. {
  494. FieldCurves fieldCurves = new FieldCurves();
  495. fieldCurves.type = type;
  496. fieldCurves.curves = new EdAnimationCurve[1];
  497. fieldCurves.curves[0] = new EdAnimationCurve();
  498. selectedFields.Add(path);
  499. curves[path] = fieldCurves;
  500. }
  501. break;
  502. }
  503. UpdateDisplayedCurves();
  504. }
  505. private bool IsPathParent(string child, string parent)
  506. {
  507. string[] childEntries = child.Split('/', '.');
  508. string[] parentEntries = parent.Split('/', '.');
  509. if (parentEntries.Length >= child.Length)
  510. return false;
  511. int compareLength = Math.Min(childEntries.Length, parentEntries.Length);
  512. for (int i = 0; i < compareLength; i++)
  513. {
  514. if (childEntries[i] != parentEntries[i])
  515. return false;
  516. }
  517. return true;
  518. }
  519. private string GetSubPathParent(string path)
  520. {
  521. int index = path.LastIndexOf(".");
  522. if (index == -1)
  523. return path;
  524. return path.Substring(0, index);
  525. }
  526. private void OnVertScrollOrResize(float arg1, float arg2)
  527. {
  528. throw new NotImplementedException();
  529. }
  530. private void OnHorzScrollOrResize(float arg1, float arg2)
  531. {
  532. throw new NotImplementedException();
  533. }
  534. private void OnFieldSelected(string path)
  535. {
  536. if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift))
  537. selectedFields.Clear();
  538. if (!string.IsNullOrEmpty(path))
  539. {
  540. selectedFields.RemoveAll(x => { return x == path || IsPathParent(x, path); });
  541. selectedFields.Add(path);
  542. }
  543. guiFieldDisplay.SetSelection(selectedFields.ToArray());
  544. UpdateDisplayedCurves();
  545. }
  546. private void RemoveSelectedFields()
  547. {
  548. for (int i = 0; i < selectedFields.Count; i++)
  549. {
  550. selectedFields.Remove(selectedFields[i]);
  551. curves.Remove(GetSubPathParent(selectedFields[i]));
  552. }
  553. List<string> existingFields = new List<string>();
  554. foreach(var KVP in curves)
  555. existingFields.Add(KVP.Key);
  556. guiFieldDisplay.SetFields(existingFields.ToArray());
  557. selectedFields.Clear();
  558. UpdateDisplayedCurves();
  559. }
  560. private void OnSelectionChanged(SceneObject[] sceneObjects, string[] resourcePaths)
  561. {
  562. Rebuild();
  563. }
  564. private void OnFrameSelected(int frameIdx)
  565. {
  566. SetCurrentFrame(frameIdx);
  567. }
  568. }
  569. /// <summary>
  570. /// Drop down window that displays options used by the animation window.
  571. /// </summary>
  572. [DefaultSize(100, 50)]
  573. internal class AnimationOptions : DropDownWindow
  574. {
  575. /// <summary>
  576. /// Initializes the drop down window by creating the necessary GUI. Must be called after construction and before
  577. /// use.
  578. /// </summary>
  579. /// <param name="parent">Animation window that this drop down window is a part of.</param>
  580. internal void Initialize(AnimationWindow parent)
  581. {
  582. GUIIntField fpsField = new GUIIntField(new LocEdString("FPS"), 40);
  583. fpsField.Value = parent.FPS;
  584. fpsField.OnChanged += x => { parent.FPS = x; };
  585. GUILayoutY vertLayout = GUI.AddLayoutY();
  586. vertLayout.AddFlexibleSpace();
  587. GUILayoutX contentLayout = vertLayout.AddLayoutX();
  588. contentLayout.AddFlexibleSpace();
  589. contentLayout.AddElement(fpsField);
  590. contentLayout.AddFlexibleSpace();
  591. vertLayout.AddFlexibleSpace();
  592. }
  593. }
  594. /** @} */
  595. }