EditCurve.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. //-----------------------------------------------------------------------------
  2. // EditCurve.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. using System.Windows.Forms;
  11. using System.IO;
  12. using System.Xml;
  13. using System.Drawing;
  14. using Microsoft.Xna.Framework;
  15. using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
  16. namespace Xna.Tools
  17. {
  18. /// <summary>
  19. /// This class contains curve editting related information.
  20. /// </summary>
  21. public class EditCurve
  22. {
  23. #region Properties
  24. /// <summary>
  25. /// Sets/Gets Control that owns this EditCurve.
  26. /// </summary>
  27. public Control Owner { get { return owner; } set { owner = value; } }
  28. /// <summary>
  29. /// Sets/Gets Id of this EditCurve.
  30. /// </summary>
  31. public long Id { get { return id; } set { id = value; } }
  32. /// <summary>
  33. /// Sets/Gets Name of this EditCurve.
  34. /// </summary>
  35. public string Name
  36. {
  37. get { return state.Name; }
  38. set { state.Name = value; FireStateChangeEvent(); }
  39. }
  40. /// <summary>
  41. /// Sets/Gets Color of this EditCurve.
  42. /// </summary>
  43. public System.Drawing.Color Color
  44. {
  45. get { return color; }
  46. set { color = value; FireStateChangeEvent(); }
  47. }
  48. /// <summary>
  49. /// Gets EditCurveKeyCollection.
  50. /// </summary>
  51. public EditCurveKeyCollection Keys { get { return keys; } }
  52. /// <summary>
  53. /// Sets/Gets PreLoop
  54. /// </summary>
  55. public CurveLoopType PreLoop
  56. {
  57. get { return OriginalCurve.PreLoop; }
  58. set
  59. {
  60. state.PreLoop = OriginalCurve.PreLoop = value;
  61. FireStateChangeEvent();
  62. }
  63. }
  64. /// <summary>
  65. /// Sets/Gets PostLoop
  66. /// </summary>
  67. public CurveLoopType PostLoop
  68. {
  69. get { return OriginalCurve.PostLoop; }
  70. set {
  71. state.PostLoop = OriginalCurve.PostLoop = value;
  72. FireStateChangeEvent();
  73. }
  74. }
  75. /// <summary>
  76. /// Gets original curve object.
  77. /// </summary>
  78. public Curve OriginalCurve { get { return originalCurve; } }
  79. /// <summary>
  80. /// Sets/Gets Visible that represents this EditCurve rendered or not
  81. /// in CurveControl.
  82. /// </summary>
  83. public bool Visible { get { return visible; } set { visible = value; } }
  84. /// <summary>
  85. /// Sets/Gets Editable that represents this EditCurve could update states.
  86. /// </summary>
  87. public bool Editable { get { return editable; } set { editable = value; } }
  88. /// <summary>
  89. /// Sets/Gets Dirty flag for file saving.
  90. /// </summary>
  91. public bool Dirty { get { return dirty; } set { dirty = value; } }
  92. /// <summary>
  93. /// Get selections.
  94. /// </summary>
  95. public EditCurveKeySelection Selection { get { return selection; } }
  96. /// <summary>
  97. /// Occures after EditCurve state (Name, Visible, Editable, PreLoop,
  98. /// and PostLoop) changed.
  99. /// </summary>
  100. public event EventHandler StateChanged;
  101. #endregion
  102. #region Constructors
  103. public EditCurve(string name, System.Drawing.Color curveColor, CommandHistory commandHistory)
  104. {
  105. originalCurve = new Curve();
  106. this.color = curveColor;
  107. keys = new EditCurveKeyCollection(this);
  108. state.Name = name;
  109. state.PreLoop = OriginalCurve.PreLoop;
  110. state.PostLoop = OriginalCurve.PostLoop;
  111. this.commandHistory = commandHistory;
  112. }
  113. public EditCurve(string name, System.Drawing.Color curveColor, Curve curve,
  114. CommandHistory commandHistory)
  115. {
  116. originalCurve = curve;
  117. this.color = curveColor;
  118. keys = new EditCurveKeyCollection(this);
  119. state.Name = name;
  120. state.PreLoop = OriginalCurve.PreLoop;
  121. state.PostLoop = OriginalCurve.PostLoop;
  122. this.commandHistory = commandHistory;
  123. }
  124. #endregion
  125. public override string ToString()
  126. {
  127. return state.Name;
  128. }
  129. #region Public Methods
  130. /// <summary>
  131. /// Evaluate this curve at given position.
  132. /// </summary>
  133. /// <param name="position"></param>
  134. /// <returns></returns>
  135. public float Evaluate(float position)
  136. {
  137. return OriginalCurve.Evaluate(position);
  138. }
  139. /// <summary>
  140. /// Begin update curve parameters.
  141. /// </summary>
  142. /// <remarks>It records curve satte and key values modification between
  143. /// BeginUpdate and EndUpdate method.</remarks>
  144. public void BeginUpdate()
  145. {
  146. if (inUpdating)
  147. throw new InvalidOperationException("BeginUpdate called twice.");
  148. modifiedKeys = new Dictionary<long, EditCurveKey>();
  149. savedState = (EditCurveState)state.Clone();
  150. inUpdating = true;
  151. }
  152. /// <summary>
  153. /// EndUpdate and generate Undo/Redo command buffer if there is any
  154. /// modification happend since BeginUpdate called.
  155. /// </summary>
  156. public void EndUpdate()
  157. {
  158. if (!inUpdating)
  159. throw new InvalidOperationException(
  160. "You must call BeginUpdate before call EndUpdate.");
  161. // Compare modified key values.
  162. if (modifiedKeys != null && modifiedKeys.Count > 0)
  163. {
  164. List<EditCurveKey> oldKeyValues =
  165. new List<EditCurveKey>(modifiedKeys.Count);
  166. List<EditCurveKey> newKeyValues =
  167. new List<EditCurveKey>(modifiedKeys.Count);
  168. foreach (EditCurveKey savedKey in modifiedKeys.Values)
  169. {
  170. EditCurveKey curKey;
  171. if (keys.TryGetValue(savedKey.Id, out curKey))
  172. {
  173. if (!curKey.Equals(savedKey))
  174. {
  175. // Saved value is already cloned.
  176. oldKeyValues.Add(savedKey);
  177. newKeyValues.Add(curKey.Clone());
  178. }
  179. }
  180. }
  181. if (newKeyValues.Count != 0)
  182. {
  183. dirty = true;
  184. if (commandHistory != null)
  185. commandHistory.Add(new EditCurveKeyUpdateCommand(
  186. this, oldKeyValues, newKeyValues));
  187. }
  188. }
  189. modifiedKeys = null;
  190. // Compare states
  191. bool stateChanged = state != savedState;
  192. if (commandHistory != null && stateChanged)
  193. commandHistory.Add(new EditCurveStateChangeCommand(
  194. this, savedState, state));
  195. savedState = null;
  196. inUpdating = false;
  197. if (stateChanged) FireStateChangeEvent();
  198. }
  199. /// <summary>
  200. /// Select keys and key tangents.
  201. /// </summary>
  202. /// <param name="selectRegion">Selection region in unit coordinate.</param>
  203. /// <param name="tangentScale">Tangent scale in unit coordinate.</param>
  204. /// <param name="keyView"></param>
  205. /// <param name="tangentView"></param>
  206. /// <param name="toggleSelection"></param>
  207. /// <param name="singleSelection"></param>
  208. public void Select(BoundingBox selectRegion, Vector2 tangentScale,
  209. EditCurveView keyView, EditCurveView tangentView,
  210. bool toggleSelection, bool singleSelect)
  211. {
  212. if (!Editable) return;
  213. EditCurveKeySelection newSelection = new EditCurveKeySelection();
  214. // Check Intersection of Keys and Tangents.
  215. if (keyView != EditCurveView.Never)
  216. {
  217. ICollection<EditCurveKey> targetKeys =
  218. (keyView == EditCurveView.Always) ?
  219. (ICollection<EditCurveKey>)keys :
  220. (ICollection<EditCurveKey>)selectedKeys.Values;
  221. newSelection.SelectKeys(targetKeys, selectRegion, singleSelect);
  222. }
  223. // Check Tangents if any keys are not selected.
  224. if (newSelection.Count == 0 && tangentView != EditCurveView.Never)
  225. {
  226. ICollection<EditCurveKey> targetKeys
  227. = (tangentView == EditCurveView.Always) ?
  228. (ICollection<EditCurveKey>)keys :
  229. (ICollection<EditCurveKey>)selectedKeys.Values;
  230. newSelection.SelectTangents(targetKeys, selectRegion, tangentScale,
  231. singleSelect);
  232. }
  233. if (toggleSelection)
  234. newSelection = EditCurveKeySelection.ToggleSelection(
  235. selection, newSelection);
  236. ApplySelection(newSelection, true);
  237. }
  238. /// <summary>
  239. /// Clear selection.
  240. /// </summary>
  241. public void ClearSelection()
  242. {
  243. ApplySelection(new EditCurveKeySelection(), true);
  244. }
  245. /// <summary>
  246. /// Apply key selection.
  247. /// </summary>
  248. /// <param name="newSelection"></param>
  249. /// <param name="generateCommand"></param>
  250. public void ApplySelection(EditCurveKeySelection newSelection,
  251. bool generateCommand)
  252. {
  253. // Re-create selected keys and store selection information from
  254. // new selection.
  255. selectedKeys.Clear();;
  256. foreach (long id in newSelection.Keys)
  257. {
  258. EditCurveKey key = keys.GetValue(id);
  259. key.Selection = newSelection[id];
  260. selectedKeys.Add(key.Id, key);
  261. }
  262. // Clear de-selected keys selection information.
  263. foreach (long id in selection.Keys)
  264. {
  265. if (!newSelection.ContainsKey(id))
  266. {
  267. EditCurveKey key;
  268. if ( keys.TryGetValue(id, out key))
  269. key.Selection = EditCurveSelections.None;
  270. }
  271. }
  272. // Invoke selection change event.
  273. if ( generateCommand == true && !newSelection.Equals(selection) &&
  274. commandHistory != null)
  275. commandHistory.Add(new SelectCommand(this, newSelection, selection));
  276. // Update selection.
  277. selection = newSelection;
  278. }
  279. /// <summary>
  280. /// Move selected keys or tangents.
  281. /// </summary>
  282. /// <param name="newPos"></param>
  283. /// <param name="prevPos"></param>
  284. public void Move(Vector2 newPos, Vector2 prevPos)
  285. {
  286. if (!Editable || !Visible) return;
  287. Vector2 delta = newPos - prevPos;
  288. foreach (EditCurveKey key in selectedKeys.Values)
  289. {
  290. MarkModify(key);
  291. int oldIdx = keys.IndexOf(key);
  292. // Move tangents.
  293. if ((key.Selection & (EditCurveSelections.TangentIn |
  294. EditCurveSelections.TangentOut)) != 0)
  295. {
  296. // Compute delta angle.
  297. Vector2 pos = new Vector2(key.Position, key.Value);
  298. float minAngle = MathHelper.ToRadians(MinTangentAngle);
  299. float maxAngle = MathHelper.ToRadians(MaxTangentAngle);
  300. const float epsilon = 1e-5f;
  301. if ((key.Selection & EditCurveSelections.TangentIn) != 0)
  302. {
  303. // Compute delta angle.
  304. double prevAngle =
  305. Math.Atan2(prevPos.Y - pos.Y, pos.X - prevPos.X);
  306. double newAngle =
  307. Math.Atan2(newPos.Y - pos.Y, pos.X - newPos.X);
  308. double da = prevAngle - newAngle;
  309. float d = GetDistanceOfKeys(oldIdx, 0);
  310. if (Math.Abs(d) > epsilon)
  311. {
  312. float tn = key.TangentIn / d;
  313. key.TangentIn = (float)Math.Tan(MathHelper.Clamp(
  314. (float)(Math.Atan(tn) + da), minAngle, maxAngle)) * d;
  315. if (Single.IsNaN(key.TangentIn))
  316. key.TangentIn = key.TangentIn;
  317. key.TangentInType = EditCurveTangent.Fixed;
  318. }
  319. }
  320. if ((key.Selection & EditCurveSelections.TangentOut) != 0)
  321. {
  322. // Compute delta angle.
  323. double prevAngle =
  324. Math.Atan2(prevPos.Y - pos.Y, prevPos.X - pos.X);
  325. double newAngle =
  326. Math.Atan2(newPos.Y - pos.Y, newPos.X - pos.X);
  327. double da = newAngle - prevAngle;
  328. float d = GetDistanceOfKeys(oldIdx, 1);
  329. if (Math.Abs(d) > epsilon)
  330. {
  331. float tn = key.TangentOut / d;
  332. key.TangentOut = (float)Math.Tan(MathHelper.Clamp(
  333. (float)(Math.Atan(tn) + da), minAngle, maxAngle)) * d;
  334. key.TangentOutType = EditCurveTangent.Fixed;
  335. }
  336. }
  337. }
  338. // Move key position.
  339. keys.RemoveAt(oldIdx); // remove key from curve once.
  340. if ((key.Selection & EditCurveSelections.Key) != 0)
  341. {
  342. key.OriginalKey = new CurveKey(
  343. key.Position + delta.X, key.Value + delta.Y,
  344. key.TangentIn, key.TangentOut, key.Continuity);
  345. }
  346. // Then store updated node back to the curve.
  347. keys.Add(key);
  348. // Compute auto-generated tangents.
  349. int newIdx = keys.IndexOf(key);
  350. ComputeTangents(newIdx);
  351. if (newIdx != oldIdx)
  352. ComputeTangents(oldIdx);
  353. }
  354. }
  355. /// <summary>
  356. /// Updated specified key values.
  357. /// </summary>
  358. public void UpdateKey( long keyId, float newPosition, float newValue)
  359. {
  360. if (!Editable || !Visible) return;
  361. EditCurveKey key;
  362. keys.TryGetValue(keyId, out key);
  363. MarkModify(key);
  364. int oldIdx = keys.IndexOf(key);
  365. // Move key position.
  366. keys.RemoveAt(oldIdx); // remove key from curve once.
  367. key.OriginalKey = new CurveKey( newPosition, newValue,
  368. key.TangentIn, key.TangentOut, key.Continuity);
  369. // Then store updated node back to the curve.
  370. keys.Add(key);
  371. // Compute auto-generated tangents.
  372. int newIdx = keys.IndexOf(key);
  373. ComputeTangents(newIdx);
  374. if (newIdx != oldIdx)
  375. ComputeTangents(oldIdx);
  376. dirty = true;
  377. }
  378. /// <summary>
  379. /// Add new key at given position.
  380. /// </summary>
  381. /// <param name="pos"></param>
  382. public void AddKey(Vector2 pos)
  383. {
  384. EnsureUpdating("AddKey");
  385. // Create new key.
  386. EditCurveKey key = new EditCurveKey(EditCurveKey.GenerateUniqueId(),
  387. new CurveKey(pos.X, pos.Y));
  388. key.Selection = EditCurveSelections.Key;
  389. // Generate add key command and execute it.
  390. EditCurveKeyAddRemoveCommand command =
  391. new EditCurveKeyAddRemoveCommand(this, key, selection);
  392. command.Execute();
  393. if (commandHistory != null) commandHistory.Add(command);
  394. }
  395. /// <summary>
  396. /// Remove selected keys.
  397. /// </summary>
  398. public void RemoveKeys()
  399. {
  400. if (!Editable) return;
  401. if (selectedKeys.Count != 0)
  402. {
  403. // Generate Remove keys command and execute it.
  404. EditCurveKeyAddRemoveCommand command =
  405. new EditCurveKeyAddRemoveCommand(this, selectedKeys.Values);
  406. command.Execute();
  407. if (commandHistory != null) commandHistory.Add(command);
  408. // Clear selection
  409. selection.Clear();
  410. selectedKeys.Clear();
  411. dirty = true;
  412. }
  413. }
  414. /// <summary>
  415. /// Apply new EditCurveState.
  416. /// </summary>
  417. /// <param name="newState"></param>
  418. public void ApplyState(EditCurveState newState)
  419. {
  420. if (newState == null) throw new ArgumentNullException("newState");
  421. inUpdating = true;
  422. Name = newState.Name;
  423. PreLoop = newState.PreLoop;
  424. PostLoop = newState.PostLoop;
  425. inUpdating = false;
  426. FireStateChangeEvent();
  427. }
  428. /// <summary>
  429. /// Apply given key values.
  430. /// </summary>
  431. /// <param name="newKeyValues"></param>
  432. public void ApplyKeyValues(ICollection<EditCurveKey> newKeyValues)
  433. {
  434. foreach (EditCurveKey newKeyValue in newKeyValues)
  435. {
  436. EditCurveKey key = newKeyValue.Clone();
  437. // Update key value.
  438. keys.Remove(keys.GetValue(key.Id));
  439. keys.Add(key);
  440. // Also, update key values if that key is selected.
  441. if (selectedKeys.ContainsKey(key.Id))
  442. {
  443. selectedKeys.Remove(key.Id);
  444. selectedKeys.Add(key.Id, key);
  445. }
  446. dirty = true;
  447. }
  448. }
  449. /// <summary>
  450. /// Set specfied tangent type to selected tangents.
  451. /// </summary>
  452. /// <param name="targetTangent">target tangent (In/Out)</param>
  453. /// <param name="tangentType"></param>
  454. public void SetTangents(EditCurveSelections targetTangent,
  455. EditCurveTangent tangentType)
  456. {
  457. if (!Editable) return;
  458. EnsureUpdating("SetTangents");
  459. // Change tangent type of selcted nodes.
  460. foreach (EditCurveKey key in selectedKeys.Values)
  461. {
  462. MarkModify(key);
  463. if (tangentType == EditCurveTangent.Stepped)
  464. {
  465. SetKeyContinuity(key, CurveContinuity.Step);
  466. }
  467. else
  468. {
  469. SetKeyContinuity(key, CurveContinuity.Smooth);
  470. if ((targetTangent & EditCurveSelections.TangentIn) != 0)
  471. key.TangentInType = tangentType;
  472. if ((targetTangent & EditCurveSelections.TangentOut) != 0)
  473. key.TangentOutType = tangentType;
  474. }
  475. }
  476. // Then, compute tangents.
  477. foreach (EditCurveKey key in selectedKeys.Values)
  478. ComputeTangents(keys.IndexOf(key));
  479. }
  480. /// <summary>
  481. /// Compute specfied index key tangents.
  482. /// </summary>
  483. /// <param name="idx"></param>
  484. public void ComputeTangents(int keyIndex)
  485. {
  486. if (keyIndex < 0 || keyIndex >keys.Count ||keyIndex > Int32.MaxValue - 2)
  487. throw new ArgumentOutOfRangeException("keyIndex");
  488. // Compute neighbors tangents too.
  489. for (int i = keyIndex - 1; i < keyIndex + 2; ++i)
  490. {
  491. if (i >= 0 && i < keys.Count)
  492. {
  493. EditCurveKey key = keys[i];
  494. MarkModify(key);
  495. float tangentInValue = key.TangentIn;
  496. float tangentOutValue = key.TangentOut;
  497. CurveTangent tangentIn = Convert(key.TangentInType);
  498. CurveTangent tangentOut = Convert(key.TangentOutType);
  499. OriginalCurve.ComputeTangent(i, tangentIn, tangentOut);
  500. if (Single.IsNaN(key.TangentIn)) key.TangentIn = 0.0f;
  501. if (Single.IsNaN(key.TangentOut)) key.TangentOut = 0.0f;
  502. // Restore original value if EditCurveTanget is fixed.
  503. if (key.TangentInType == EditCurveTangent.Fixed)
  504. key.TangentIn = tangentInValue;
  505. if (key.TangentOutType == EditCurveTangent.Fixed)
  506. key.TangentOut = tangentOutValue;
  507. }
  508. }
  509. }
  510. /// <summary>
  511. /// Get distance between given index key position and previous/next key.
  512. /// </summary>
  513. /// <param name="index"></param>
  514. /// <param name="direction">0:previeous key, 1:next key</param>
  515. /// <returns></returns>
  516. public float GetDistanceOfKeys(int index, int direction)
  517. {
  518. float result = 1.0f;
  519. if (direction == 0)
  520. {
  521. // From previous key.
  522. if (index > 0)
  523. {
  524. result = keys[index].Position - keys[index - 1].Position;
  525. }
  526. else if (OriginalCurve.PreLoop == CurveLoopType.Oscillate &&
  527. keys.Count > 1)
  528. {
  529. result = keys[1].Position - keys[0].Position;
  530. }
  531. }
  532. else
  533. {
  534. // From next key.
  535. if (index < keys.Count - 1)
  536. {
  537. result = keys[index + 1].Position - keys[index].Position;
  538. }
  539. else if (OriginalCurve.PostLoop == CurveLoopType.Oscillate &&
  540. keys.Count > 1)
  541. {
  542. result = keys[index].Position - keys[index - 1].Position;
  543. }
  544. }
  545. return result;
  546. }
  547. /// <summary>
  548. /// Returns selected key list.
  549. /// </summary>
  550. /// <returns></returns>
  551. public EditCurveKey[] GetSelectedKeys()
  552. {
  553. EditCurveKey[] keys = new EditCurveKey[selectedKeys.Count];
  554. int idx = 0;
  555. foreach (EditCurveKey key in selectedKeys.Values)
  556. keys[idx++] = key;
  557. return keys;
  558. }
  559. /// <summary>
  560. /// Load a Curve from given filename.
  561. /// </summary>
  562. /// <param name="filename"></param>
  563. /// <param name="name"></param>
  564. /// <param name="color"></param>
  565. /// <param name="commandHistory"></param>
  566. /// <returns></returns>
  567. public static EditCurve LoadFromFile(string filename, string name,
  568. System.Drawing.Color color, CommandHistory commandHistory)
  569. {
  570. EditCurve editCurve = null;
  571. using (XmlReader xr = XmlReader.Create(filename))
  572. {
  573. Curve curve = IntermediateSerializer.Deserialize<Curve>(xr,
  574. Path.GetDirectoryName(filename));
  575. editCurve = new EditCurve(name, color, curve, commandHistory);
  576. }
  577. return editCurve;
  578. }
  579. /// <summary>
  580. /// Save this curve to given filename.
  581. /// </summary>
  582. /// <param name="filename"></param>
  583. public void Save(string filename)
  584. {
  585. using (XmlWriter xw = XmlWriter.Create(filename))
  586. {
  587. IntermediateSerializer.Serialize(xw, originalCurve,
  588. Path.GetDirectoryName(filename));
  589. dirty = false;
  590. }
  591. }
  592. #endregion
  593. #region Private methods
  594. /// <summary>
  595. /// Mark modified key.
  596. /// </summary>
  597. private void MarkModify(EditCurveKey key)
  598. {
  599. // Clone and save current EditCurveKey to modified keys.
  600. if (modifiedKeys != null && !modifiedKeys.ContainsKey(key.Id))
  601. {
  602. modifiedKeys.Add(key.Id, key.Clone());
  603. dirty = true;
  604. }
  605. }
  606. /// <summary>
  607. ///
  608. /// </summary>
  609. /// <param name="key"></param>
  610. /// <param name="continuity"></param>
  611. private void SetKeyContinuity(EditCurveKey key, CurveContinuity continuity)
  612. {
  613. if (key.Continuity != continuity)
  614. {
  615. MarkModify(key);
  616. key.Continuity = continuity;
  617. if (continuity == CurveContinuity.Step)
  618. {
  619. key.TangentIn = key.TangentOut = 0;
  620. key.TangentInType = key.TangentInType = EditCurveTangent.Flat;
  621. }
  622. }
  623. }
  624. /// <summary>
  625. /// Convert EditCurveTanget to CurveTangent.
  626. /// </summary>
  627. /// <param name="tangent"></param>
  628. /// <returns></returns>
  629. private static CurveTangent Convert(EditCurveTangent tangent)
  630. {
  631. return (tangent == EditCurveTangent.Fixed) ?
  632. CurveTangent.Flat : (CurveTangent)tangent;
  633. }
  634. private void FireStateChangeEvent()
  635. {
  636. dirty = true;
  637. if (inUpdating) return;
  638. if (StateChanged != null) StateChanged(this, EventArgs.Empty);
  639. if (Owner != null)
  640. Owner.Invalidate();
  641. }
  642. private void EnsureUpdating(string operationName)
  643. {
  644. if (!inUpdating)
  645. throw new InvalidOperationException(String.Format(
  646. "You have to call BeginUpdate before call {0}", operationName));
  647. }
  648. #endregion
  649. #region Private Constants
  650. const float MinTangentAngle = -89.99999f;
  651. const float MaxTangentAngle = +89.99999f;
  652. #endregion
  653. #region Properties wrap members
  654. private Control owner;
  655. private long id;
  656. private System.Drawing.Color color = System.Drawing.Color.Red;
  657. private Curve originalCurve;
  658. private EditCurveKeyCollection keys;
  659. private bool editable = true;
  660. private bool visible = true;
  661. private bool dirty = false;
  662. #endregion
  663. #region Private members
  664. private CommandHistory commandHistory;
  665. private Dictionary<long, EditCurveKey> selectedKeys =
  666. new Dictionary<long, EditCurveKey>();
  667. private EditCurveKeySelection selection = new EditCurveKeySelection();
  668. private Dictionary<long, EditCurveKey> modifiedKeys;
  669. private EditCurveState state = new EditCurveState();
  670. private EditCurveState savedState;
  671. private bool inUpdating;
  672. #endregion
  673. }
  674. }