SplineCtrl.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "EditorDefs.h"
  9. #include "SplineCtrl.h"
  10. // Qt
  11. #include <QPainter>
  12. #include <QPainterPath>
  13. #include <QToolTip>
  14. // Editor
  15. #include "TimelineCtrl.h"
  16. #define MIN_TIME_EPSILON 0.01f
  17. //////////////////////////////////////////////////////////////////////////
  18. CSplineCtrl::CSplineCtrl(QWidget* parent)
  19. : QWidget(parent)
  20. {
  21. m_nActiveKey = -1;
  22. m_nHitKeyIndex = -1;
  23. m_nKeyDrawRadius = 3;
  24. m_bTracking = false;
  25. m_pSpline = nullptr;
  26. m_gridX = 10;
  27. m_gridY = 10;
  28. m_fMinTime = -1;
  29. m_fMaxTime = 1;
  30. m_fMinValue = -1;
  31. m_fMaxValue = 1;
  32. m_fTooltipScaleX = 1;
  33. m_fTooltipScaleY = 1;
  34. m_bLockFirstLastKey = false;
  35. m_pTimelineCtrl = nullptr;
  36. m_bSelectedKeys.reserve(0);
  37. m_fTimeMarker = -10;
  38. setMouseTracking(true);
  39. }
  40. CSplineCtrl::~CSplineCtrl()
  41. {
  42. }
  43. /////////////////////////////////////////////////////////////////////////////
  44. // CSplineCtrl message handlers
  45. //////////////////////////////////////////////////////////////////////////
  46. void CSplineCtrl::resizeEvent([[maybe_unused]] QResizeEvent* event)
  47. {
  48. m_rcSpline = rect();
  49. if (m_pTimelineCtrl)
  50. {
  51. QRect rct = m_rcSpline;
  52. rct.setHeight(20);
  53. m_rcSpline.setTop(rct.bottom() + 1);
  54. m_pTimelineCtrl->setGeometry(rct);
  55. }
  56. m_rcSpline.adjust(2, 2, -2, -2);
  57. }
  58. //////////////////////////////////////////////////////////////////////////
  59. QPoint CSplineCtrl::KeyToPoint(int nKey)
  60. {
  61. if (nKey >= 0)
  62. {
  63. return TimeToPoint(m_pSpline->GetKeyTime(nKey));
  64. }
  65. return QPoint(0, 0);
  66. }
  67. //////////////////////////////////////////////////////////////////////////
  68. QPoint CSplineCtrl::TimeToPoint(float time)
  69. {
  70. QPoint point;
  71. point.setX(static_cast<int>((time - m_fMinTime) * (m_rcSpline.width() / (m_fMaxTime - m_fMinTime)) + m_rcSpline.left()));
  72. float val = 0;
  73. if (m_pSpline)
  74. {
  75. m_pSpline->InterpolateFloat(time, val);
  76. }
  77. point.setY(static_cast<int>((floor((m_fMaxValue - val) * (m_rcSpline.height() / (m_fMaxValue - m_fMinValue)) + 0.5f) + m_rcSpline.top())));
  78. return point;
  79. }
  80. //////////////////////////////////////////////////////////////////////////
  81. void CSplineCtrl::PointToTimeValue(const QPoint& point, float& time, float& value)
  82. {
  83. time = XOfsToTime(point.x());
  84. float t = float(m_rcSpline.bottom() - point.y()) / m_rcSpline.height();
  85. value = AZ::Lerp(m_fMinValue, m_fMaxValue, t);
  86. }
  87. //////////////////////////////////////////////////////////////////////////
  88. float CSplineCtrl::XOfsToTime(int x)
  89. {
  90. // m_fMinTime to m_fMaxTime time range.
  91. float t = float(x - m_rcSpline.left()) / m_rcSpline.width();
  92. return AZ::Lerp(m_fMinTime, m_fMaxTime, t);
  93. }
  94. //////////////////////////////////////////////////////////////////////////
  95. QPoint CSplineCtrl::XOfsToPoint(int x)
  96. {
  97. return TimeToPoint(XOfsToTime(x));
  98. }
  99. //////////////////////////////////////////////////////////////////////////
  100. void CSplineCtrl::paintEvent(QPaintEvent* event)
  101. {
  102. QPainter painter(this);
  103. if (m_pSpline)
  104. {
  105. m_bSelectedKeys.resize(m_pSpline->GetKeyCount());
  106. }
  107. {
  108. if (m_TimeUpdateRect != event->rect())
  109. {
  110. painter.fillRect(event->rect(), QColor(140, 140, 140));
  111. //Draw Grid
  112. DrawGrid(&painter);
  113. //Draw Keys and Curve
  114. if (m_pSpline)
  115. {
  116. DrawSpline(&painter);
  117. DrawKeys(&painter);
  118. }
  119. }
  120. m_TimeUpdateRect = QRect();
  121. }
  122. DrawTimeMarker(&painter);
  123. }
  124. //////////////////////////////////////////////////////////////////////////
  125. void CSplineCtrl::DrawGrid(QPainter* painter)
  126. {
  127. QPen pOldPen = painter->pen();
  128. int cx = m_rcSpline.width();
  129. int cy = m_rcSpline.height();
  130. QPen pen(QColor(90, 90, 90), 1, Qt::DotLine);
  131. pen.setCosmetic(true);
  132. painter->setPen(pen);
  133. //Draw Vertical Grid Lines
  134. for (int y = 1; y < m_gridX; y++)
  135. {
  136. painter->drawLine(m_rcSpline.left() + y * cx / m_gridX, m_rcSpline.top() + cy, m_rcSpline.left() + y * cx / m_gridX, m_rcSpline.top());
  137. }
  138. //Draw Horizontal Grid Lines
  139. for (int x = 1; x < m_gridY; x++)
  140. {
  141. painter->drawLine(m_rcSpline.left(), m_rcSpline.top() + x * cy / m_gridY, m_rcSpline.left() + cx, m_rcSpline.top() + x * cy / m_gridY);
  142. }
  143. painter->setPen(QColor(75, 75, 75));
  144. painter->drawLine(m_rcSpline.left() + (m_gridX / 2) * cx / m_gridX, m_rcSpline.top() + cy, m_rcSpline.left() + (m_gridX / 2) * cx / m_gridX, m_rcSpline.top() + 0);
  145. painter->drawLine(m_rcSpline.left() + 0, m_rcSpline.left() + (m_gridY / 2) * cy / m_gridY, m_rcSpline.left() + cx, m_rcSpline.left() + (m_gridY / 2) * cy / m_gridY);
  146. painter->drawRect(m_rcSpline);
  147. painter->setPen(pOldPen);
  148. }
  149. //////////////////////////////////////////////////////////////////////////
  150. void CSplineCtrl::DrawSpline(QPainter* painter)
  151. {
  152. //Draw Curve
  153. // create and select a thick, white pen
  154. const QPen pOldPen = painter->pen();
  155. painter->setPen(QColor(128, 255, 128));
  156. const QRect rcClip = painter->hasClipping() ? painter->clipBoundingRect().intersected(m_rcSpline).toRect() : m_rcSpline;
  157. bool bFirst = true;
  158. QPainterPath path;
  159. for (int x = rcClip.left(); x < rcClip.right(); x++)
  160. {
  161. QPoint pt = XOfsToPoint(x);
  162. if (!bFirst)
  163. {
  164. path.lineTo(pt);
  165. }
  166. else
  167. {
  168. path.moveTo(pt);
  169. bFirst = false;
  170. }
  171. }
  172. painter->drawPath(path);
  173. // Put back the old objects
  174. painter->setPen(pOldPen);
  175. }
  176. //////////////////////////////////////////////////////////////////////////
  177. void CSplineCtrl::DrawKeys(QPainter* painter)
  178. {
  179. if (!m_pSpline)
  180. {
  181. return;
  182. }
  183. // create and select a white pen
  184. const QPen pOldPen = painter->pen();
  185. painter->setPen(Qt::black);
  186. m_bSelectedKeys.resize(m_pSpline->GetKeyCount());
  187. for (int i = 0; i < m_pSpline->GetKeyCount(); i++)
  188. {
  189. float time = m_pSpline->GetKeyTime(i);
  190. const QPoint pt = TimeToPoint(time);
  191. QColor clr(220, 220, 0);
  192. if (m_bSelectedKeys[i])
  193. {
  194. clr = QColor(255, 0, 0);
  195. }
  196. const QBrush pOldBrush = painter->brush();
  197. painter->setBrush(clr);
  198. // Draw this key.
  199. painter->drawRect(QRect(QPoint(pt.x() - m_nKeyDrawRadius, pt.y() - m_nKeyDrawRadius), QPoint(pt.x() + m_nKeyDrawRadius - 1, pt.y() + m_nKeyDrawRadius - 1)));
  200. painter->setBrush(pOldBrush);
  201. }
  202. painter->setPen(pOldPen);
  203. }
  204. //////////////////////////////////////////////////////////////////////////
  205. void CSplineCtrl::DrawTimeMarker(QPainter* painter)
  206. {
  207. painter->setPen(QColor(255, 0, 255));
  208. const QPoint pt = TimeToPoint(m_fTimeMarker);
  209. painter->drawLine(pt.x(), m_rcSpline.top() + 1, pt.x(), m_rcSpline.bottom() - 1);
  210. }
  211. void CSplineCtrl::UpdateToolTip()
  212. {
  213. if (m_nHitKeyIndex >= 0 && m_pSpline)
  214. {
  215. float time = m_pSpline->GetKeyTime(m_nHitKeyIndex);
  216. float val;
  217. m_pSpline->GetKeyValueFloat(m_nHitKeyIndex, val);
  218. int cont_s = (m_pSpline->GetKeyFlags(m_nHitKeyIndex) >> SPLINE_KEY_TANGENT_IN_SHIFT) & SPLINE_KEY_TANGENT_LINEAR ? 1 : 2;
  219. int cont_d = (m_pSpline->GetKeyFlags(m_nHitKeyIndex) >> SPLINE_KEY_TANGENT_OUT_SHIFT) & SPLINE_KEY_TANGENT_LINEAR ? 1 : 2;
  220. const QString tipText = tr("%1, %2, [%3|%4").arg(time * m_fTooltipScaleX, 3, 'f').arg(val * m_fTooltipScaleY, 3, 'f').arg(cont_s).arg(cont_d);
  221. QToolTip::showText(QCursor::pos(), tipText, this);
  222. }
  223. }
  224. /////////////////////////////////////////////////////////////////////////////
  225. //Mouse Message Handlers
  226. //////////////////////////////////////////////////////////////////////////
  227. void CSplineCtrl::mousePressEvent(QMouseEvent* event)
  228. {
  229. switch (event->button())
  230. {
  231. case Qt::LeftButton:
  232. OnLButtonDown(event->pos(), event->modifiers());
  233. break;
  234. case Qt::RightButton:
  235. OnRButtonDown(event->pos(), event->modifiers());
  236. break;
  237. }
  238. }
  239. void CSplineCtrl::mouseReleaseEvent(QMouseEvent* event)
  240. {
  241. switch (event->button())
  242. {
  243. case Qt::LeftButton:
  244. OnLButtonUp(event->pos(), event->modifiers());
  245. break;
  246. }
  247. }
  248. void CSplineCtrl::OnLButtonDown([[maybe_unused]] const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  249. {
  250. if (m_bTracking)
  251. {
  252. return;
  253. }
  254. if (!m_pSpline)
  255. {
  256. return;
  257. }
  258. setFocus();
  259. switch (m_hitCode)
  260. {
  261. case HIT_KEY:
  262. StartTracking();
  263. SetActiveKey(m_nHitKeyIndex);
  264. break;
  265. case HIT_SPLINE:
  266. // Cycle the spline slope of the nearest key.
  267. ToggleKeySlope(m_nHitKeyIndex, m_nHitKeyDist);
  268. SetActiveKey(-1);
  269. break;
  270. case HIT_NOTHING:
  271. SetActiveKey(-1);
  272. break;
  273. }
  274. update();
  275. }
  276. //////////////////////////////////////////////////////////////////////////
  277. void CSplineCtrl::OnRButtonDown([[maybe_unused]] const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  278. {
  279. setFocus();
  280. if (!m_pSpline)
  281. {
  282. return;
  283. }
  284. }
  285. //////////////////////////////////////////////////////////////////////////
  286. void CSplineCtrl::mouseDoubleClickEvent(QMouseEvent* event)
  287. {
  288. if (!m_pSpline || event->button() != Qt::LeftButton)
  289. {
  290. return;
  291. }
  292. switch (m_hitCode)
  293. {
  294. case HIT_NOTHING:
  295. {
  296. int iIndex = InsertKey(event->pos());
  297. SetActiveKey(iIndex);
  298. update();
  299. }
  300. break;
  301. case HIT_KEY:
  302. {
  303. RemoveKey(m_nHitKeyIndex);
  304. }
  305. break;
  306. }
  307. }
  308. //////////////////////////////////////////////////////////////////////////
  309. void CSplineCtrl::mouseMoveEvent(QMouseEvent* event)
  310. {
  311. OnSetCursor();
  312. if (!m_pSpline)
  313. {
  314. return;
  315. }
  316. if (m_bTracking)
  317. {
  318. TrackKey(event->pos());
  319. UpdateToolTip();
  320. }
  321. }
  322. //////////////////////////////////////////////////////////////////////////
  323. void CSplineCtrl::OnLButtonUp([[maybe_unused]] const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  324. {
  325. if (!m_pSpline)
  326. {
  327. return;
  328. }
  329. if (m_bTracking)
  330. {
  331. StopTracking();
  332. }
  333. }
  334. /////////////////////////////////////////////////////////////////////////////
  335. void CSplineCtrl::SetActiveKey(int nIndex)
  336. {
  337. ClearSelection();
  338. // Activate New Key
  339. if (nIndex >= 0)
  340. {
  341. m_bSelectedKeys[nIndex] = true;
  342. }
  343. m_nActiveKey = nIndex;
  344. update();
  345. }
  346. /////////////////////////////////////////////////////////////////////////////
  347. void CSplineCtrl::SetSpline(ISplineInterpolator* pSpline, bool bRedraw)
  348. {
  349. if (pSpline != m_pSpline)
  350. {
  351. m_pSpline = pSpline;
  352. }
  353. ValidateSpline();
  354. ClearSelection();
  355. if (bRedraw)
  356. {
  357. update();
  358. }
  359. }
  360. void CSplineCtrl::ValidateSpline()
  361. {
  362. // Add initial control points (will be serialised only if edited).
  363. if (m_pSpline->GetKeyCount() == 0)
  364. {
  365. m_pSpline->InsertKeyFloat(0.f, 1.f);
  366. m_pSpline->InsertKeyFloat(1.f, 1.f);
  367. m_pSpline->Update();
  368. }
  369. }
  370. //////////////////////////////////////////////////////////////////////////
  371. ISplineInterpolator* CSplineCtrl::GetSpline()
  372. {
  373. return m_pSpline;
  374. }
  375. /////////////////////////////////////////////////////////////////////////////
  376. void CSplineCtrl::OnSetCursor()
  377. {
  378. const QPoint point = mapFromGlobal(QCursor::pos());
  379. const int hitKey = m_nHitKeyIndex;
  380. switch (HitTest(point))
  381. {
  382. case HIT_SPLINE:
  383. {
  384. setCursor(CMFCUtils::LoadCursor(IDC_ARRWHITE));
  385. } break;
  386. case HIT_KEY:
  387. {
  388. setCursor(CMFCUtils::LoadCursor(IDC_ARRBLCK));
  389. } break;
  390. default:
  391. unsetCursor();
  392. break;
  393. }
  394. if (m_bTracking)
  395. {
  396. m_nHitKeyIndex = hitKey;
  397. }
  398. if (m_pSpline)
  399. {
  400. if (m_nHitKeyIndex >= 0)
  401. {
  402. UpdateToolTip();
  403. }
  404. else if (!m_bTracking)
  405. {
  406. QToolTip::hideText();
  407. }
  408. }
  409. }
  410. /////////////////////////////////////////////////////////////////////////////
  411. void CSplineCtrl::keyPressEvent(QKeyEvent* event)
  412. {
  413. bool bProcessed = false;
  414. if (m_nActiveKey != -1 && m_pSpline)
  415. {
  416. switch (event->key())
  417. {
  418. case Qt::Key_Space:
  419. {
  420. ToggleKeySlope(m_nActiveKey, 0);
  421. bProcessed = true;
  422. } break;
  423. case Qt::Key_Delete:
  424. {
  425. RemoveKey(m_nActiveKey);
  426. bProcessed = true;
  427. } break;
  428. case Qt::Key_Up:
  429. {
  430. CUndo undo("Move Spline Key");
  431. QPoint point = KeyToPoint(m_nActiveKey);
  432. point.ry() -= 1;
  433. emit beforeChange();
  434. TrackKey(point);
  435. bProcessed = true;
  436. } break;
  437. case Qt::Key_Down:
  438. {
  439. CUndo undo("Move Spline Key");
  440. QPoint point = KeyToPoint(m_nActiveKey);
  441. point.ry() += 1;
  442. emit beforeChange();
  443. TrackKey(point);
  444. bProcessed = true;
  445. } break;
  446. case Qt::Key_Left:
  447. {
  448. CUndo undo("Move Spline Key");
  449. QPoint point = KeyToPoint(m_nActiveKey);
  450. point.rx() -= 1;
  451. emit beforeChange();
  452. TrackKey(point);
  453. bProcessed = true;
  454. } break;
  455. case Qt::Key_Right:
  456. {
  457. CUndo undo("Move Spline Key");
  458. QPoint point = KeyToPoint(m_nActiveKey);
  459. point.ry() += 1;
  460. emit beforeChange();
  461. TrackKey(point);
  462. bProcessed = true;
  463. } break;
  464. default:
  465. break; //do nothing
  466. }
  467. update();
  468. }
  469. event->setAccepted(bProcessed);
  470. }
  471. //////////////////////////////////////////////////////////////////////////////
  472. CSplineCtrl::EHitCode CSplineCtrl::HitTest(const QPoint& point)
  473. {
  474. if (!m_pSpline)
  475. {
  476. return HIT_NOTHING;
  477. }
  478. float time, val;
  479. PointToTimeValue(point, time, val);
  480. m_nHitKeyIndex = -1;
  481. m_nHitKeyDist = 0xFFFF;
  482. m_hitCode = HIT_NOTHING;
  483. QPoint splinePt = TimeToPoint(time);
  484. if (abs(splinePt.y() - point.y()) < 4)
  485. {
  486. m_hitCode = HIT_SPLINE;
  487. for (int i = 0; i < m_pSpline->GetKeyCount(); i++)
  488. {
  489. const QPoint splinePt2 = TimeToPoint(m_pSpline->GetKeyTime(i));
  490. if (abs(point.x() - splinePt2.x()) < abs(m_nHitKeyDist))
  491. {
  492. m_nHitKeyIndex = i;
  493. m_nHitKeyDist = point.x() - splinePt2.x();
  494. }
  495. }
  496. if (abs(m_nHitKeyDist) < 4)
  497. {
  498. m_hitCode = HIT_KEY;
  499. }
  500. }
  501. return m_hitCode;
  502. }
  503. ///////////////////////////////////////////////////////////////////////////////
  504. void CSplineCtrl::StartTracking()
  505. {
  506. m_bTracking = true;
  507. GetIEditor()->BeginUndo();
  508. emit beforeChange();
  509. setCursor(CMFCUtils::LoadCursor(IDC_ARRBLCKCROSS));
  510. }
  511. //////////////////////////////////////////////////////////////////////////
  512. void CSplineCtrl::TrackKey(const QPoint& p)
  513. {
  514. int nKey = m_nHitKeyIndex;
  515. QPoint point = p;
  516. if (nKey >= 0)
  517. {
  518. float time, val;
  519. // Editing time & value.
  520. Limit(point.rx(), m_rcSpline.left(), m_rcSpline.right());
  521. Limit(point.ry(), m_rcSpline.top(), m_rcSpline.bottom());
  522. PointToTimeValue(point, time, val);
  523. int i;
  524. for (i = 0; i < m_pSpline->GetKeyCount(); i++)
  525. {
  526. // Switch to next key.
  527. if (fabs(m_pSpline->GetKeyTime(i) - time) < MIN_TIME_EPSILON)
  528. {
  529. if (i != nKey)
  530. {
  531. return;
  532. }
  533. }
  534. }
  535. m_pSpline->SetKeyValueFloat(nKey, val);
  536. if ((nKey != 0 && nKey != m_pSpline->GetKeyCount() - 1) || !m_bLockFirstLastKey)
  537. {
  538. m_pSpline->SetKeyTime(nKey, time);
  539. }
  540. else if (m_bLockFirstLastKey)
  541. {
  542. int first = 0;
  543. int last = m_pSpline->GetKeyCount() - 1;
  544. if (nKey == first)
  545. {
  546. m_pSpline->SetKeyValueFloat(last, val);
  547. }
  548. else if (nKey == last)
  549. {
  550. m_pSpline->SetKeyValueFloat(first, val);
  551. }
  552. }
  553. m_pSpline->Update();
  554. emit change();
  555. if (m_updateCallback)
  556. {
  557. m_updateCallback(this);
  558. }
  559. update();
  560. }
  561. }
  562. //////////////////////////////////////////////////////////////////////////
  563. void CSplineCtrl::StopTracking()
  564. {
  565. if (!m_bTracking)
  566. {
  567. return;
  568. }
  569. GetIEditor()->AcceptUndo("Spline Move");
  570. m_bTracking = false;
  571. }
  572. //////////////////////////////////////////////////////////////////////////
  573. void CSplineCtrl::RemoveKey(int nKey)
  574. {
  575. if (!m_pSpline)
  576. {
  577. return;
  578. }
  579. if (nKey)
  580. {
  581. if (m_bLockFirstLastKey)
  582. {
  583. if (nKey == 0 || nKey == m_pSpline->GetKeyCount() - 1)
  584. {
  585. return;
  586. }
  587. }
  588. }
  589. CUndo undo("Remove Spline Key");
  590. emit beforeChange();
  591. m_nActiveKey = -1;
  592. m_nHitKeyIndex = -1;
  593. if (m_pSpline)
  594. {
  595. m_pSpline->RemoveKey(nKey);
  596. m_pSpline->Update();
  597. ValidateSpline();
  598. }
  599. emit change();
  600. if (m_updateCallback)
  601. {
  602. m_updateCallback(this);
  603. }
  604. update();
  605. }
  606. //////////////////////////////////////////////////////////////////////////
  607. int CSplineCtrl::InsertKey(const QPoint& point)
  608. {
  609. CUndo undo("Spline Insert Key");
  610. float time, val;
  611. PointToTimeValue(point, time, val);
  612. int i;
  613. for (i = 0; i < m_pSpline->GetKeyCount(); i++)
  614. {
  615. // Skip if any key already have time that is very close.
  616. if (fabs(m_pSpline->GetKeyTime(i) - time) < MIN_TIME_EPSILON)
  617. {
  618. return i;
  619. }
  620. }
  621. emit beforeChange();
  622. m_pSpline->InsertKeyFloat(time, val);
  623. m_pSpline->Update();
  624. ClearSelection();
  625. update();
  626. emit change();
  627. if (m_updateCallback)
  628. {
  629. m_updateCallback(this);
  630. }
  631. for (i = 0; i < m_pSpline->GetKeyCount(); i++)
  632. {
  633. // Find key with added time.
  634. if (m_pSpline->GetKeyTime(i) == time)
  635. {
  636. return i;
  637. }
  638. }
  639. return -1;
  640. }
  641. void CSplineCtrl::ToggleKeySlope(int nIndex, int nDir)
  642. {
  643. if (nIndex >= 0)
  644. {
  645. int flags = m_pSpline->GetKeyFlags(nIndex);
  646. if (nDir <= 0)
  647. {
  648. // Toggle left side.
  649. flags ^= SPLINE_KEY_TANGENT_LINEAR << SPLINE_KEY_TANGENT_IN_SHIFT;
  650. }
  651. if (nDir >= 0)
  652. {
  653. // Toggle right side.
  654. flags ^= SPLINE_KEY_TANGENT_LINEAR << SPLINE_KEY_TANGENT_OUT_SHIFT;
  655. }
  656. m_pSpline->SetKeyFlags(nIndex, flags);
  657. m_pSpline->Update();
  658. emit change();
  659. if (m_updateCallback)
  660. {
  661. m_updateCallback(this);
  662. }
  663. }
  664. }
  665. //////////////////////////////////////////////////////////////////////////
  666. void CSplineCtrl::ClearSelection()
  667. {
  668. m_nActiveKey = -1;
  669. if (m_pSpline)
  670. {
  671. m_bSelectedKeys.resize(m_pSpline->GetKeyCount());
  672. }
  673. for (int i = 0; i < (int)m_bSelectedKeys.size(); i++)
  674. {
  675. m_bSelectedKeys[i] = false;
  676. }
  677. }
  678. //////////////////////////////////////////////////////////////////////////
  679. void CSplineCtrl::SetTimeMarker(float fTime)
  680. {
  681. if (!m_pSpline)
  682. {
  683. return;
  684. }
  685. if (fTime == m_fTimeMarker)
  686. {
  687. return;
  688. }
  689. // Erase old first.
  690. QPoint pt0 = TimeToPoint(m_fTimeMarker);
  691. QPoint pt1 = TimeToPoint(fTime);
  692. QRect rc(QPoint(pt0.x(), m_rcSpline.top()), QPoint(pt1.x(), m_rcSpline.bottom()));
  693. rc = rc.normalized();
  694. rc.adjust(-5, 0, 5, 0);
  695. rc = rc.intersected(m_rcSpline);
  696. m_TimeUpdateRect = rc;
  697. update(rc);
  698. m_fTimeMarker = fTime;
  699. }
  700. //////////////////////////////////////////////////////////////////////////
  701. void CSplineCtrl::SetTimelineCtrl(TimelineWidget* pTimelineCtrl)
  702. {
  703. m_pTimelineCtrl = pTimelineCtrl;
  704. if (m_pTimelineCtrl)
  705. {
  706. m_pTimelineCtrl->setParent(this);
  707. }
  708. }
  709. #include <Controls/moc_SplineCtrl.cpp>