TimelineCtrl.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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 "TimelineCtrl.h"
  10. // Qt
  11. #include <QPainter>
  12. // Editor
  13. #include "ScopedVariableSetter.h"
  14. #include "GridUtils.h"
  15. QColor InterpolateColor(const QColor& c1, const QColor& c2, float fraction)
  16. {
  17. const int r = static_cast<int>(static_cast<float>(c2.red() - c1.red()) * fraction + c1.red());
  18. const int g = static_cast<int>(static_cast<float>(c2.green() - c1.green()) * fraction + c1.green());
  19. const int b = static_cast<int>(static_cast<float>(c2.blue() - c1.blue()) * fraction + c1.blue());
  20. return QColor(r, g, b);
  21. }
  22. //////////////////////////////////////////////////////////////////////////
  23. TimelineWidget::TimelineWidget(QWidget* parent /* = nullptr */)
  24. : QWidget(parent)
  25. {
  26. setMouseTracking(true);
  27. m_timeRange.start = 0;
  28. m_timeRange.end = 1;
  29. m_timeScale = 1;
  30. m_fTicksTextScale = 1.0f;
  31. m_fTimeMarker = -10;
  32. m_nTicksStep = 100;
  33. m_trackingMode = TRACKING_MODE_NONE;
  34. m_leftOffset = 0;
  35. m_scrollOffset = 0;
  36. m_ticksStep = 10.0f;
  37. m_grid.zoom.SetX(100);
  38. m_bIgnoreSetTime = false;
  39. m_pKeyTimeSet = nullptr;
  40. m_markerStyle = MARKER_STYLE_SECONDS;
  41. m_fps = 30.0f;
  42. m_copyKeyTimes = false;
  43. m_bTrackingSnapToFrames = false;
  44. }
  45. TimelineWidget::~TimelineWidget()
  46. {
  47. }
  48. /////////////////////////////////////////////////////////////////////////////
  49. // CTimelineCtrl message handlers
  50. //////////////////////////////////////////////////////////////////////////
  51. void TimelineWidget::resizeEvent(QResizeEvent* event)
  52. {
  53. Q_UNUSED(event);
  54. m_rcTimeline = rect();
  55. m_grid.rect = m_rcTimeline;
  56. }
  57. //////////////////////////////////////////////////////////////////////////
  58. int TimelineWidget::TimeToClient(float time)
  59. {
  60. return m_grid.WorldToClient(Vec2(time, 0)).x();
  61. }
  62. //////////////////////////////////////////////////////////////////////////
  63. float TimelineWidget::ClientToTime(int x)
  64. {
  65. return m_grid.ClientToWorld(QPoint(x, 0)).x;
  66. }
  67. //////////////////////////////////////////////////////////////////////////
  68. void TimelineWidget::paintEvent(QPaintEvent* event)
  69. {
  70. QPainter painter(this);
  71. QRect rcClient = rect();
  72. {
  73. //////////////////////////////////////////////////////////////////////////
  74. // Fill keys background.
  75. //////////////////////////////////////////////////////////////////////////
  76. const QRect rc = rcClient.intersected(event->rect());
  77. painter.fillRect(rc, palette().color(QPalette::Button));
  78. painter.drawRect(rc);
  79. //////////////////////////////////////////////////////////////////////////
  80. m_grid.CalculateGridLines();
  81. DrawTicks(&painter);
  82. }
  83. }
  84. //////////////////////////////////////////////////////////////////////////
  85. float TimelineWidget::SnapTime(float time)
  86. {
  87. double t = floor((double)time * m_ticksStep + 0.5);
  88. t = t / m_ticksStep;
  89. return static_cast<float>(t);
  90. }
  91. //////////////////////////////////////////////////////////////////////////
  92. void TimelineWidget::DrawTicks(QPainter* painter)
  93. {
  94. const QRectF rc = rect();
  95. const QPen pOldPen = painter->pen();
  96. const QPen ltgray(QColor(110, 110, 110));
  97. const QPen redpen(QColor(255, 0, 255));
  98. // Draw time ticks every tick step seconds.
  99. painter->setPen(ltgray);
  100. switch (m_markerStyle)
  101. {
  102. case MARKER_STYLE_SECONDS:
  103. DrawSecondTicks(painter);
  104. break;
  105. case MARKER_STYLE_FRAMES:
  106. DrawFrameTicks(painter);
  107. break;
  108. }
  109. painter->setPen(redpen);
  110. int x = TimeToClient(m_fTimeMarker);
  111. painter->setBrush(Qt::NoBrush);
  112. painter->drawRect(QRect(QPoint(x - 3, static_cast<int>(rc.top())), QPoint(x + 2, static_cast<int>(rc.bottom()))));
  113. painter->setPen(redpen);
  114. painter->drawLine(x, static_cast<int>(rc.top()), x, static_cast<int>(rc.bottom()));
  115. painter->setBrush(Qt::NoBrush);
  116. // Draw vertical line showing current time.
  117. {
  118. int x2 = TimeToClient(m_fTimeMarker);
  119. if (x2 > m_rcTimeline.left() && x2 < m_rcTimeline.right())
  120. {
  121. painter->setPen(QColor(255, 0, 255));
  122. painter->drawLine(x2, 0, x2, m_rcTimeline.bottom());
  123. }
  124. }
  125. // Draw the key times.
  126. painter->setPen(redpen);
  127. painter->setBrush(Qt::NoBrush);
  128. const QPen keySelectedPen(QColor(100, 255, 255));
  129. const QBrush keySelectedBrush(QColor(100, 255, 255));
  130. for (int keyTimeIndex = 0; m_pKeyTimeSet && keyTimeIndex < m_pKeyTimeSet->GetKeyTimeCount(); ++keyTimeIndex)
  131. {
  132. int keyCountBound = __max(m_pKeyTimeSet->GetKeyCountBound(), 1);
  133. int keyCount = __min(m_pKeyTimeSet->GetKeyCount(keyTimeIndex), keyCountBound);
  134. float colorCodeFraction = float(keyCount) / keyCountBound;
  135. const QColor keyMarkerCol = InterpolateColor(Qt::green, Qt::red, colorCodeFraction);
  136. const QPen keyPen(keyMarkerCol);
  137. const QBrush keyBrush(keyMarkerCol);
  138. bool keyTimeSelected = m_pKeyTimeSet && m_pKeyTimeSet->GetKeyTimeSelected(keyTimeIndex);
  139. painter->setBrush(keyTimeSelected ? keySelectedBrush : keyBrush);
  140. painter->setPen(keyTimeSelected ? keySelectedPen : keyPen);
  141. float keyTime = (m_pKeyTimeSet ? m_pKeyTimeSet->GetKeyTime(keyTimeIndex) : 0.0f);
  142. int x2 = TimeToClient(keyTime);
  143. painter->drawRect(QRect(QPoint(x2 - 1, static_cast<int>(rc.top())), QPoint(x2 + 2, static_cast<int>(rc.bottom()))));
  144. }
  145. painter->setPen(pOldPen);
  146. }
  147. //////////////////////////////////////////////////////////////////////////
  148. Range TimelineWidget::GetVisibleRange() const
  149. {
  150. Range r;
  151. r.start = (m_scrollOffset - m_leftOffset) / m_timeScale;
  152. r.end = r.start + (m_rcTimeline.width()) / m_timeScale;
  153. // Intersect range with global time range.
  154. r = m_timeRange & r;
  155. return r;
  156. }
  157. /////////////////////////////////////////////////////////////////////////////
  158. //Mouse Message Handlers
  159. //////////////////////////////////////////////////////////////////////////
  160. void TimelineWidget::mousePressEvent(QMouseEvent* event)
  161. {
  162. switch (event->button())
  163. {
  164. case Qt::LeftButton:
  165. OnLButtonDown(event->pos(), event->modifiers());
  166. break;
  167. case Qt::RightButton:
  168. OnRButtonDown(event->pos(), event->modifiers());
  169. break;
  170. }
  171. }
  172. void TimelineWidget::mouseReleaseEvent(QMouseEvent* event)
  173. {
  174. switch (event->button())
  175. {
  176. case Qt::LeftButton:
  177. OnLButtonUp(event->pos(), event->modifiers());
  178. break;
  179. case Qt::RightButton:
  180. OnRButtonUp(event->pos(), event->modifiers());
  181. break;
  182. }
  183. }
  184. namespace
  185. {
  186. const float EDITOR_FPS = 30.0f;
  187. float SnapTimeToFrame(float time) {return int((time * EDITOR_FPS) + 0.5f) * (1.0f / EDITOR_FPS); }
  188. }
  189. void TimelineWidget::OnLButtonDown(const QPoint& point, Qt::KeyboardModifiers modifiers)
  190. {
  191. if (m_trackingMode != TRACKING_MODE_NONE)
  192. {
  193. return;
  194. }
  195. Q_EMIT clicked();
  196. int hitKeyTimeIndex = HitKeyTimes(point);
  197. bool autoDeselect = !(modifiers& Qt::ControlModifier) && (m_pKeyTimeSet && ((hitKeyTimeIndex >= 0) ? !m_pKeyTimeSet->GetKeyTimeSelected(hitKeyTimeIndex) : true));
  198. for (int keyTimeIndex = 0; m_pKeyTimeSet && keyTimeIndex < m_pKeyTimeSet->GetKeyTimeCount(); ++keyTimeIndex)
  199. {
  200. bool shouldBeSelected;
  201. if (keyTimeIndex == hitKeyTimeIndex)
  202. {
  203. shouldBeSelected = (modifiers& Qt::ControlModifier) || !((modifiers& Qt::ShiftModifier) && m_pKeyTimeSet->GetKeyTimeSelected(keyTimeIndex));
  204. }
  205. else
  206. {
  207. shouldBeSelected = (!autoDeselect || (modifiers & Qt::ShiftModifier)) && m_pKeyTimeSet->GetKeyTimeSelected(keyTimeIndex);
  208. }
  209. m_pKeyTimeSet->SetKeyTimeSelected(keyTimeIndex, shouldBeSelected);
  210. }
  211. TrackingMode trackingMode = (hitKeyTimeIndex >= 0 ? TRACKING_MODE_MOVE_KEYS : TRACKING_MODE_NONE);
  212. if (trackingMode == TRACKING_MODE_NONE)
  213. {
  214. trackingMode = ((modifiers& Qt::ControlModifier) ? TRACKING_MODE_SELECTION_RANGE : TRACKING_MODE_SET_TIME);
  215. }
  216. StartTracking(trackingMode);
  217. switch (m_trackingMode)
  218. {
  219. case TRACKING_MODE_SET_TIME:
  220. {
  221. if (m_bTrackingSnapToFrames)
  222. {
  223. SetTimeMarker(SnapTimeToFrame(ClientToTime(point.x())));
  224. }
  225. else
  226. {
  227. SetTimeMarker(ClientToTime(point.x()));
  228. }
  229. CScopedVariableSetter<bool> ignoreSetTime(m_bIgnoreSetTime, true);
  230. Q_EMIT startChange();
  231. Q_EMIT change();
  232. }
  233. break;
  234. case TRACKING_MODE_MOVE_KEYS:
  235. m_bChangedKeyTimeSet = false;
  236. m_copyKeyTimes = (modifiers & Qt::ControlModifier ? true : false);
  237. break;
  238. case TRACKING_MODE_NONE:
  239. break;
  240. }
  241. m_lastPoint = point;
  242. update();
  243. }
  244. //////////////////////////////////////////////////////////////////////////
  245. void TimelineWidget::OnRButtonDown(const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  246. {
  247. Q_EMIT clicked();
  248. if (m_trackingMode != TRACKING_MODE_NONE)
  249. {
  250. return;
  251. }
  252. StartTracking(TRACKING_MODE_SET_TIME);
  253. if (m_bTrackingSnapToFrames)
  254. {
  255. SetTimeMarker(SnapTimeToFrame(ClientToTime(point.x())));
  256. }
  257. else
  258. {
  259. SetTimeMarker(ClientToTime(point.x()));
  260. }
  261. CScopedVariableSetter<bool> ignoreSetTime(m_bIgnoreSetTime, true);
  262. Q_EMIT startChange();
  263. Q_EMIT change();
  264. update();
  265. }
  266. //////////////////////////////////////////////////////////////////////////
  267. void TimelineWidget::OnRButtonUp([[maybe_unused]] const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  268. {
  269. switch (m_trackingMode)
  270. {
  271. case TRACKING_MODE_SET_TIME:
  272. {
  273. Q_EMIT endChange();
  274. }
  275. break;
  276. }
  277. if (m_trackingMode != TRACKING_MODE_NONE)
  278. {
  279. StopTracking();
  280. }
  281. }
  282. //////////////////////////////////////////////////////////////////////////
  283. void TimelineWidget::keyPressEvent(QKeyEvent* event)
  284. {
  285. if (event->matches(QKeySequence::Delete))
  286. {
  287. Q_EMIT deleteRequested();
  288. }
  289. if (event->key() == Qt::Key_Space && m_playCallback)
  290. {
  291. m_playCallback();
  292. }
  293. }
  294. //////////////////////////////////////////////////////////////////////////
  295. void TimelineWidget::mouseMoveEvent(QMouseEvent* event)
  296. {
  297. switch (m_trackingMode)
  298. {
  299. case TRACKING_MODE_SET_TIME:
  300. {
  301. if (m_bTrackingSnapToFrames)
  302. {
  303. SetTimeMarker(SnapTimeToFrame(ClientToTime(event->x())));
  304. }
  305. else
  306. {
  307. SetTimeMarker(ClientToTime(event->x()));
  308. }
  309. CScopedVariableSetter<bool> ignoreSetTime(m_bIgnoreSetTime, true);
  310. Q_EMIT change();
  311. }
  312. break;
  313. case TRACKING_MODE_MOVE_KEYS:
  314. {
  315. if (m_pKeyTimeSet && !m_bChangedKeyTimeSet)
  316. {
  317. m_bChangedKeyTimeSet = true;
  318. m_pKeyTimeSet->BeginEdittingKeyTimes();
  319. }
  320. const bool altClicked = (Qt::AltModifier & QApplication::queryKeyboardModifiers());
  321. float scale, offset;
  322. float startTime = ClientToTime(m_lastPoint.x());
  323. float endTime = ClientToTime(event->x());
  324. if (altClicked)
  325. {
  326. // Alt was pressed, so we should scale the key times rather than translate.
  327. // Calculate the scaling parameters (ie t1 = t0 * M + C).
  328. scale = 1.0f;
  329. if (fabsf(startTime - m_fTimeMarker) > 0.1)
  330. {
  331. scale = (endTime - m_fTimeMarker) / (startTime - m_fTimeMarker);
  332. }
  333. offset = endTime - startTime * scale;
  334. }
  335. else
  336. {
  337. // Simply move the keys.
  338. offset = endTime - startTime;
  339. scale = 1.0f;
  340. }
  341. MoveSelectedKeyTimes(scale, offset);
  342. }
  343. break;
  344. case TRACKING_MODE_SELECTION_RANGE:
  345. {
  346. float start = min(ClientToTime(m_lastPoint.x()), ClientToTime(event->x()));
  347. float end = max(ClientToTime(m_lastPoint.x()), ClientToTime(event->x()));
  348. SelectKeysInRange(start, end, !(event->modifiers() & Qt::ShiftModifier));
  349. m_lastPoint = event->pos();
  350. update();
  351. }
  352. break;
  353. case TRACKING_MODE_NONE:
  354. break;
  355. }
  356. //m_lastPoint = point;
  357. }
  358. //////////////////////////////////////////////////////////////////////////
  359. QString TimelineWidget::TimeToString(float time)
  360. {
  361. return QString::number(time, 'f', 3);
  362. }
  363. //////////////////////////////////////////////////////////////////////////
  364. void TimelineWidget::OnLButtonUp([[maybe_unused]] const QPoint& point, [[maybe_unused]] Qt::KeyboardModifiers modifiers)
  365. {
  366. switch (m_trackingMode)
  367. {
  368. case TRACKING_MODE_MOVE_KEYS:
  369. {
  370. if (m_pKeyTimeSet && m_bChangedKeyTimeSet)
  371. {
  372. m_pKeyTimeSet->EndEdittingKeyTimes();
  373. }
  374. }
  375. break;
  376. case TRACKING_MODE_SET_TIME:
  377. {
  378. Q_EMIT endChange();
  379. }
  380. break;
  381. case TRACKING_MODE_NONE:
  382. break;
  383. }
  384. if (m_trackingMode != TRACKING_MODE_NONE)
  385. {
  386. StopTracking();
  387. }
  388. }
  389. ///////////////////////////////////////////////////////////////////////////////
  390. void TimelineWidget::StartTracking(TrackingMode trackingMode)
  391. {
  392. m_trackingMode = trackingMode;
  393. }
  394. //////////////////////////////////////////////////////////////////////////
  395. void TimelineWidget::StopTracking()
  396. {
  397. if (!m_trackingMode)
  398. {
  399. return;
  400. }
  401. m_trackingMode = TRACKING_MODE_NONE;
  402. }
  403. //////////////////////////////////////////////////////////////////////////
  404. void TimelineWidget::SetTimeMarker(float fTime)
  405. {
  406. if (fTime < m_timeRange.start)
  407. {
  408. fTime = m_timeRange.start;
  409. }
  410. else if (fTime > m_timeRange.end)
  411. {
  412. fTime = m_timeRange.end;
  413. }
  414. if (fTime == m_fTimeMarker || m_bIgnoreSetTime)
  415. {
  416. return;
  417. }
  418. int x0 = TimeToClient(m_fTimeMarker);
  419. int x1 = TimeToClient(fTime);
  420. QRect rc(QPoint(x0, m_rcClient.top()), QPoint(x1, m_rcClient.bottom()));
  421. rc = rc.normalized();
  422. rc.adjust(-5, 0, 5, 0);
  423. update(rc);
  424. m_fTimeMarker = fTime;
  425. }
  426. //////////////////////////////////////////////////////////////////////////
  427. void TimelineWidget::SetZoom(float fZoom)
  428. {
  429. m_grid.zoom.SetX(fZoom);
  430. }
  431. //////////////////////////////////////////////////////////////////////////
  432. void TimelineWidget::SetOrigin(float fOffset)
  433. {
  434. m_grid.origin.SetX(fOffset);
  435. }
  436. //////////////////////////////////////////////////////////////////////////
  437. void TimelineWidget::SetKeyTimeSet(IKeyTimeSet* pKeyTimeSet)
  438. {
  439. m_pKeyTimeSet = pKeyTimeSet;
  440. }
  441. //////////////////////////////////////////////////////////////////////////
  442. int TimelineWidget::HitKeyTimes(const QPoint& point)
  443. {
  444. const int threshold = 3;
  445. int hitKeyTimeIndex = -1;
  446. for (int keyTimeIndex = 0; m_pKeyTimeSet && keyTimeIndex < m_pKeyTimeSet->GetKeyTimeCount(); ++keyTimeIndex)
  447. {
  448. float keyTime = (m_pKeyTimeSet ? m_pKeyTimeSet->GetKeyTime(keyTimeIndex) : 0.0f);
  449. int x = TimeToClient(keyTime);
  450. if (abs(point.x() - x) <= threshold)
  451. {
  452. hitKeyTimeIndex = keyTimeIndex;
  453. }
  454. }
  455. return hitKeyTimeIndex;
  456. }
  457. //////////////////////////////////////////////////////////////////////////
  458. void TimelineWidget::MoveSelectedKeyTimes(float scale, float offset)
  459. {
  460. std::vector<int> indices;
  461. for (int keyTimeIndex = 0; m_pKeyTimeSet && keyTimeIndex < m_pKeyTimeSet->GetKeyTimeCount(); ++keyTimeIndex)
  462. {
  463. if (m_pKeyTimeSet && m_pKeyTimeSet->GetKeyTimeSelected(keyTimeIndex))
  464. {
  465. indices.push_back(keyTimeIndex);
  466. }
  467. }
  468. if (m_pKeyTimeSet)
  469. {
  470. m_pKeyTimeSet->MoveKeyTimes(int(indices.size()), &indices[0], scale, offset, m_copyKeyTimes);
  471. }
  472. }
  473. //////////////////////////////////////////////////////////////////////////
  474. void TimelineWidget::SelectKeysInRange(float start, float end, bool select)
  475. {
  476. for (int keyTimeIndex = 0; m_pKeyTimeSet && keyTimeIndex < m_pKeyTimeSet->GetKeyTimeCount(); ++keyTimeIndex)
  477. {
  478. float time = (m_pKeyTimeSet ? m_pKeyTimeSet->GetKeyTime(keyTimeIndex) : 0.0f);
  479. if (m_pKeyTimeSet && time >= start && time <= end)
  480. {
  481. m_pKeyTimeSet->SetKeyTimeSelected(keyTimeIndex, select);
  482. }
  483. }
  484. }
  485. //////////////////////////////////////////////////////////////////////////
  486. void TimelineWidget::SetMarkerStyle(MarkerStyle markerStyle)
  487. {
  488. m_markerStyle = markerStyle;
  489. }
  490. //////////////////////////////////////////////////////////////////////////
  491. void TimelineWidget::SetFPS(float fps)
  492. {
  493. m_fps = fps;
  494. }
  495. //////////////////////////////////////////////////////////////////////////
  496. void TimelineWidget::DrawSecondTicks(QPainter* painter)
  497. {
  498. const QPen ltgray(QColor(110, 110, 110));
  499. const QPen black(palette().color(QPalette::Normal, QPalette::Text));
  500. for (int gx = m_grid.firstGridLine.x(); gx < m_grid.firstGridLine.x() + m_grid.numGridLines.x() + 1; gx++)
  501. {
  502. painter->setPen(ltgray);
  503. int x = m_grid.GetGridLineX(gx);
  504. if (x < 0)
  505. {
  506. continue;
  507. }
  508. painter->drawLine(m_rcTimeline.left() + x, m_rcTimeline.bottom() - 2, m_rcTimeline.left() + x, m_rcTimeline.bottom() - 4);
  509. //if (gx % 10 == 0)
  510. {
  511. float t = m_grid.GetGridLineXValue(gx);
  512. t = floor(t * 1000.0f + 0.5f) / 1000.0f;
  513. const QString str = QString::number(t * m_fTicksTextScale, 'g');
  514. //t = t / pow(10,precision);
  515. painter->setPen(black);
  516. painter->drawLine(m_rcTimeline.left() + x, m_rcTimeline.bottom() - 2, m_rcTimeline.left() + x, m_rcTimeline.bottom() - 14);
  517. painter->drawText(m_rcTimeline.left() + x + 2, m_rcTimeline.top(), str);
  518. }
  519. }
  520. }
  521. //////////////////////////////////////////////////////////////////////////
  522. class TickDrawer
  523. {
  524. public:
  525. TickDrawer(QPainter* painter, const QRect& rect)
  526. : rect(rect)
  527. , painter(painter)
  528. {
  529. }
  530. void operator()(int frameIndex, int x)
  531. {
  532. if (painter)
  533. {
  534. painter->setPen(QColor(110, 110, 110));
  535. painter->drawLine(rect.left() + x, rect.bottom() - 2, rect.left() + x, rect.bottom() - 4);
  536. {
  537. const QString str = QString::number(frameIndex);
  538. painter->setPen(Qt::black);
  539. painter->drawLine(rect.left() + x, rect.bottom() - 2, rect.left() + x, rect.bottom() - 14);
  540. painter->drawText(rect.left() + x + 2, rect.top(), str);
  541. }
  542. }
  543. }
  544. QRect rect;
  545. QPainter* painter;
  546. };
  547. void TimelineWidget::DrawFrameTicks(QPainter* painter)
  548. {
  549. TickDrawer tickDrawer(painter, m_rcTimeline);
  550. GridUtils::IterateGrid(tickDrawer, 50.0f, m_grid.zoom.GetX(), m_grid.origin.GetX(), m_fps, m_grid.rect.left(), m_grid.rect.right() + 1);
  551. }
  552. void TimelineWidget::SetPlayCallback(const std::function<void()>& callback)
  553. {
  554. m_playCallback = callback;
  555. }
  556. #include <Controls/moc_TimelineCtrl.cpp>