1 #include "timelinewidget.h"
2 #include "profiledialog.h"
3 #include "trace_profiler.hpp"
10 #include <QMouseEvent>
11 #include <QWheelEvent>
12 #include <QApplication>
14 typedef trace::Profile::Call Call;
15 typedef trace::Profile::Frame Frame;
16 typedef trace::Profile::Program Program;
18 TimelineWidget::TimelineWidget(QWidget *parent)
24 m_axisLine(QColor(240, 240, 240)),
25 m_axisBorder(Qt::black),
26 m_axisForeground(Qt::black),
27 m_axisBackground(QColor(210, 210, 210)),
28 m_itemBorder(Qt::red),
29 m_itemGpuForeground(Qt::cyan),
30 m_itemGpuBackground(Qt::red),
31 m_itemCpuForeground(QColor(255, 255, 0)),
32 m_itemCpuBackground(QColor(0, 0, 255)),
33 m_itemDeselectedForeground(Qt::white),
34 m_itemDeselectedBackground(QColor(155, 155, 155)),
35 m_selectionBorder(Qt::green),
36 m_selectionBackground(QColor(100, 255, 100, 8)),
37 m_zoomBorder(QColor(255, 0, 255)),
38 m_zoomBackground(QColor(255, 0, 255, 30))
40 setBackgroundRole(QPalette::Base);
41 setAutoFillBackground(true);
42 setMouseTracking(true);
44 m_selection.type = SelectNone;
49 * Update horizontal view scroll based on scroll value
51 void TimelineWidget::setHorizontalScrollValue(int scrollValue)
57 /* Calculate time from scroll value */
58 double time = scrollValue;
60 time *= (m_timeMax - m_timeWidth) - m_timeMin;
63 setTimeScroll(time, false);
68 * Update vertical view scroll based on scroll value
70 void TimelineWidget::setVerticalScrollValue(int value)
76 setRowScroll(value, false);
81 * Set selection to nothing
83 void TimelineWidget::selectNone(bool notify)
85 m_selection.type = SelectNone;
96 * Set selection to a program
98 void TimelineWidget::selectProgram(unsigned program, bool notify)
100 m_selection.program = program;
101 m_selection.type = SelectProgram;
104 emit selectedProgram(program);
112 * Set selection to a period of time
114 void TimelineWidget::selectTime(int64_t start, int64_t end, bool notify)
116 m_selection.timeStart = start;
117 m_selection.timeEnd = end;
118 m_selection.type = SelectTime;
121 emit selectedTime(start, end);
129 * Convert time to view position
131 double TimelineWidget::timeToPosition(int64_t time)
142 * Convert view position to time
144 int64_t TimelineWidget::positionToTime(int pos)
150 return (int64_t)time;
155 * Binary Search for a time in start+durations
157 template<typename val_ty, int64_t val_ty::* mem_ptr_start, int64_t val_ty::* mem_ptr_dura>
158 typename std::vector<val_ty>::const_iterator binarySearchTimespan(
159 typename std::vector<val_ty>::const_iterator begin,
160 typename std::vector<val_ty>::const_iterator end,
164 int upper = end - begin;
165 int pos = (lower + upper) / 2;
166 typename std::vector<val_ty>::const_iterator itr = begin + pos;
168 while (!((*itr).*mem_ptr_start <= time && (*itr).*mem_ptr_start + (*itr).*mem_ptr_dura > time) && (lower <= upper)) {
169 if ((*itr).*mem_ptr_start > time) {
175 pos = (lower + upper) / 2;
179 if (lower <= upper) {
188 * Binary Search for a time in start+durations on an array of indices
190 std::vector<unsigned>::const_iterator binarySearchTimespanIndexed(
191 const std::vector<Call>& calls,
192 std::vector<unsigned>::const_iterator begin,
193 std::vector<unsigned>::const_iterator end,
197 int upper = end - begin - 1;
198 int pos = (lower + upper) / 2;
199 std::vector<unsigned>::const_iterator itr = begin + pos;
201 while (lower <= upper) {
202 const Call& call = calls[*itr];
204 if (call.gpuStart <= time && call.gpuStart + call.gpuDuration > time) {
208 if (call.gpuStart > time) {
214 pos = (lower + upper) / 2;
218 if (lower <= upper) {
227 * Find the frame at time
229 const Frame* TimelineWidget::frameAtTime(int64_t time)
235 std::vector<Frame>::const_iterator res
236 = binarySearchTimespan<Frame, &Frame::cpuStart, &Frame::cpuDuration>(
237 m_profile->frames.begin(),
238 m_profile->frames.end(),
241 if (res != m_profile->frames.end()) {
250 * Find the CPU call at time
252 const Call* TimelineWidget::cpuCallAtTime(int64_t time)
258 std::vector<Call>::const_iterator res
259 = binarySearchTimespan<Call, &Call::cpuStart, &Call::cpuDuration>(
260 m_profile->calls.begin(),
261 m_profile->calls.end(),
264 if (res != m_profile->calls.end()) {
273 * Find the draw call at time
275 const Call* TimelineWidget::drawCallAtTime(int64_t time)
281 for (int i = 0; i < m_rowPrograms.size(); ++i) {
282 const Call* call = drawCallAtTime(time, m_rowPrograms[i]);
294 * Find the draw call at time for a selected program
296 const Call* TimelineWidget::drawCallAtTime(int64_t time, int program)
302 std::vector<unsigned>::const_iterator res
303 = binarySearchTimespanIndexed(
305 m_profile->programs[program].calls.begin(),
306 m_profile->programs[program].calls.end(),
309 if (res != m_profile->programs[program].calls.end()) {
310 return &m_profile->calls[*res];
318 * Calculate the row order by total gpu time per shader
320 void TimelineWidget::calculateRows()
322 typedef QPair<uint64_t, unsigned> Pair;
323 std::vector<Pair> gpu;
325 /* Map shader to visible row */
326 for (std::vector<Program>::const_iterator itr = m_profile->programs.begin(); itr != m_profile->programs.end(); ++itr) {
327 const Program& program = *itr;
328 unsigned no = itr - m_profile->programs.begin();
330 if (program.gpuTotal > 0) {
331 gpu.push_back(Pair(program.gpuTotal, no));
335 /* Sort the shaders by most used gpu */
338 /* Create row order */
339 m_rowPrograms.clear();
341 for (std::vector<Pair>::const_reverse_iterator itr = gpu.rbegin(); itr != gpu.rend(); ++itr) {
342 m_rowPrograms.push_back(itr->second);
345 m_rowCount = m_rowPrograms.size();
350 * Set the trace profile to use for the timeline
352 void TimelineWidget::setProfile(trace::Profile* profile)
354 if (!profile->frames.size())
360 m_timeMin = m_profile->frames.front().cpuStart;
361 m_timeMax = m_profile->frames.back().cpuStart + m_profile->frames.back().cpuDuration;
364 m_timeWidth = m_timeMax - m_timeMin;
366 m_timeWidthMin = 1000;
367 m_timeWidthMax = m_timeWidth;
370 m_maxScrollY = qMax(0, (m_rowCount * m_rowHeight) - m_viewHeight);
372 setTimeScroll(m_time);
380 * Set the horizontal scroll position to time
382 void TimelineWidget::setTimeScroll(int64_t time, bool notify)
384 time = qBound(m_timeMin, time, m_timeMax - m_timeWidth);
388 if (m_timeWidth == m_timeWidthMax) {
391 m_maxScrollX = 10000;
395 double value = time - m_timeMin;
396 value /= m_timeMax - m_timeWidth - m_timeMin;
397 value *= m_maxScrollX;
400 emit horizontalScrollMaxChanged(m_maxScrollX);
401 emit horizontalScrollValueChanged(m_scrollX);
409 * Set the vertical scroll position to position
411 void TimelineWidget::setRowScroll(int position, bool notify)
413 position = qBound(0, position, m_maxScrollY);
415 m_scrollY = position;
416 m_row = m_scrollY / m_rowHeight;
419 emit verticalScrollMaxChanged(m_maxScrollY);
420 emit verticalScrollValueChanged(m_scrollY);
427 void TimelineWidget::resizeEvent(QResizeEvent *e)
429 /* Update viewport size */
430 m_viewWidth = qMax(0, width() - m_axisWidth);
431 m_viewHeight = qMax(0, height() - m_axisHeight - m_rowHeight * 2);
433 /* Update vertical scroll bar */
435 m_maxScrollY = qMax(0, (m_rowCount * m_rowHeight) - m_viewHeight);
436 emit verticalScrollMaxChanged(m_maxScrollY);
437 setRowScroll(m_scrollY);
442 void TimelineWidget::mouseMoveEvent(QMouseEvent *e)
444 bool tooltip = false;
445 m_mousePosition = e->pos();
451 /* Display tooltip if necessary */
452 if (e->buttons() == Qt::NoButton) {
453 if (m_mousePosition.x() > m_axisWidth && m_mousePosition.y() > m_axisHeight) {
454 int64_t time = positionToTime(m_mousePosition.x() - m_axisWidth);
455 int y = m_mousePosition.y() - m_axisHeight;
457 if (y < m_rowHeight) {
458 const Call* call = cpuCallAtTime(time);
462 text = QString::fromStdString(call->name);
463 text += QString("\nCall: %1").arg(call->no);
464 text += QString("\nCPU Start: %1").arg(getTimeString(call->cpuStart));
465 text += QString("\nCPU Duration: %1").arg(getTimeString(call->cpuDuration));
467 QToolTip::showText(e->globalPos(), text);
471 const Call* call = NULL;
473 if (y < m_rowHeight * 2) {
474 call = drawCallAtTime(time);
476 int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
478 if (row < m_rowPrograms.size()) {
479 call = drawCallAtTime(time, m_rowPrograms[row]);
485 text = QString::fromStdString(call->name);
486 text += QString("\nCall: %1").arg(call->no);
487 text += QString("\nCPU Start: %1").arg(getTimeString(call->cpuStart));
488 text += QString("\nGPU Start: %1").arg(getTimeString(call->gpuStart));
489 text += QString("\nCPU Duration: %1").arg(getTimeString(call->cpuDuration));
490 text += QString("\nGPU Duration: %1").arg(getTimeString(call->gpuDuration));
491 text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call->pixels));
493 QToolTip::showText(e->globalPos(), text);
497 } else if (m_mousePosition.x() < m_axisWidth && m_mousePosition.y() > m_axisHeight) {
498 int y = m_mousePosition.y() - m_axisHeight;
500 if (y < m_rowHeight) {
501 QToolTip::showText(e->globalPos(), "All CPU calls");
503 } else if (y < m_rowHeight * 2) {
504 QToolTip::showText(e->globalPos(), "All GPU calls");
507 int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
509 if (row < m_rowPrograms.size()) {
510 QToolTip::showText(e->globalPos(), QString("All calls in Shader Program %1").arg(m_rowPrograms[row]));
515 } else if (e->buttons().testFlag(Qt::LeftButton)) {
516 if (m_mousePressMode == DragView) {
517 /* Horizontal scroll */
518 double dt = m_timeWidth;
520 dt *= m_mousePressPosition.x() - e->pos().x();
521 setTimeScroll(m_mousePressTime + dt);
523 /* Vertical scroll */
524 int dy = m_mousePressPosition.y() - e->pos().y();
525 setRowScroll(m_mousePressRow + dy);
526 } else if (m_mousePressMode == RulerSelect) {
527 /* Horizontal selection */
528 int64_t down = positionToTime(m_mousePressPosition.x() - m_axisWidth);
529 int64_t up = positionToTime(qMax(e->pos().x() - m_axisWidth, 0));
531 selectTime(qMin(down, up), qMax(down, up), true);
538 QToolTip::hideText();
543 void TimelineWidget::mousePressEvent(QMouseEvent *e)
545 if (e->buttons() & Qt::LeftButton) {
546 if (e->pos().y() < m_axisHeight && e->pos().x() >= m_axisWidth) {
547 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
548 m_mousePressMode = RulerZoom;
550 m_mousePressMode = RulerSelect;
552 } else if (e->pos().x() >= m_axisWidth) {
553 m_mousePressMode = DragView;
555 m_mousePressMode = NoMousePress;
558 m_mousePressPosition = e->pos();
559 m_mousePressTime = m_time;
560 m_mousePressRow = m_scrollY;
567 void TimelineWidget::mouseReleaseEvent(QMouseEvent *e)
573 /* Calculate new time view based on selected area */
574 int dxy = qAbs(m_mousePressPosition.x() - e->pos().x()) + qAbs(m_mousePressPosition.y() - e->pos().y());
576 int64_t down = positionToTime(m_mousePressPosition.x() - m_axisWidth);
577 int64_t up = positionToTime(qMax(e->pos().x() - m_axisWidth, 0));
579 int64_t left = qMin(down, up);
580 int64_t right = qMax(down, up);
582 if (m_mousePressMode == RulerZoom) {
583 m_timeWidth = right - left;
584 m_timeWidth = qBound(m_timeWidthMin, m_timeWidth, m_timeWidthMax);
586 m_mousePressMode = NoMousePress;
590 if (m_selection.type == SelectTime) {
591 if (left < m_selection.timeStart || right > m_selection.timeEnd || e->pos().x() < m_axisWidth) {
594 } else if (m_selection.type == SelectProgram) {
595 int y = e->pos().y() - m_axisHeight;
596 int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
598 if (row < 0 || m_rowPrograms[row] != m_selection.program) {
602 } else if (m_mousePressMode == RulerSelect) {
603 selectTime(left, right, true);
609 void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *e)
611 int64_t time = positionToTime(e->pos().x() - m_axisWidth);
613 if (e->pos().x() > m_axisWidth) {
614 int row = (e->pos().y() - m_axisHeight) / m_rowHeight;
616 if (e->pos().y() < m_axisHeight) {
617 /* Horizontal axis */
618 const Frame* frame = frameAtTime(time);
621 selectTime(frame->cpuStart, frame->cpuStart + frame->cpuDuration, true);
624 } else if (row == 0) {
626 const Call* call = cpuCallAtTime(time);
629 emit jumpToCall(call->no);
632 } else if (row > 0) {
634 const Call* call = drawCallAtTime(time, 0);
637 emit jumpToCall(call->no);
642 int y = e->pos().y() - m_axisHeight;
643 int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
645 if (row >= 0 && row < m_rowPrograms.size()) {
646 selectProgram(m_rowPrograms[row], true);
652 void TimelineWidget::wheelEvent(QWheelEvent *e)
658 if (e->pos().x() < m_axisWidth) {
662 int zoomPercent = 10;
664 /* If holding Ctrl key then zoom 2x faster */
665 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
669 /* Zoom view by adjusting width */
670 double dt = m_timeWidth;
671 double size = m_timeWidth;
674 /* Zoom deltas normally come in increments of 120 */
675 size /= 120 * (100 / zoomPercent);
678 m_timeWidth = qBound(m_timeWidthMin, m_timeWidth, m_timeWidthMax);
680 /* Scroll view to zoom around mouse */
682 dt *= e->x() - m_axisWidth;
684 setTimeScroll(dt + m_time);
691 * Paints a single pixel column of the heat map
693 void TimelineWidget::drawHeat(QPainter& painter, int x, int64_t heat, bool gpu, bool selected)
699 if (m_selection.type == SelectTime) {
700 selected = x >= m_selectionLeft && x <= m_selectionRight;
703 double timePerPixel = m_timeWidth / (double)m_viewWidth;
704 double colour = heat / timePerPixel;
706 /* Gamma correction */
707 colour = qPow(colour, 1.0 / 2.0);
710 colour = qBound(0.0, colour * 100.0, 100.0);
711 painter.setPen(QColor(255 - colour, 255 - colour, 255 - colour));
713 colour = qBound(0.0, colour * 255.0, 255.0);
714 painter.setPen(QColor(255, 255 - colour, 255 - colour));
716 colour = qBound(0.0, colour * 255.0, 255.0);
717 painter.setPen(QColor(255 - colour, 255 - colour, 255));
720 painter.drawLine(x, 0, x, m_rowHeight - 1);
725 * Draws a call on the heatmap
727 bool TimelineWidget::drawCall(QPainter& painter, const trace::Profile::Call& call, int& lastX, int64_t& heat, bool gpu)
729 int64_t start, duration, end;
732 start = call.gpuStart;
733 duration = call.gpuDuration;
735 start = call.cpuStart;
736 duration = call.cpuDuration;
739 end = start + duration;
741 if (start > m_timeEnd) {
749 double left = timeToPosition(start);
750 double right = timeToPosition(end);
755 bool selected = true;
757 if (m_selection.type == SelectProgram) {
758 selected = call.program == m_selection.program;
761 /* Draw last heat if needed */
762 if (leftX != lastX) {
763 drawHeat(painter, lastX, heat, gpu, selected);
768 if (rightX <= leftX + 1) {
769 if (rightX == lastX) {
770 /* Fully contained in this X */
773 /* Split call time between the two pixels it occupies */
774 int64_t time = positionToTime(rightX);
775 heat += time - start;
777 drawHeat(painter, lastX, heat, gpu, selected);
784 rect.setLeft(left + 0.5);
785 rect.setWidth(right - left);
787 rect.setHeight(m_rowHeight);
789 if (m_selection.type == SelectTime) {
790 selected = (start >= m_selection.timeStart && start <= m_selection.timeEnd)
791 || (end >= m_selection.timeStart && end <= m_selection.timeEnd);
794 /* Draw background rect */
797 painter.fillRect(rect, m_itemGpuBackground);
799 painter.fillRect(rect, m_itemCpuBackground);
802 painter.fillRect(rect, m_itemDeselectedBackground);
805 /* If wide enough, draw text */
806 if (rect.width() > 6) {
807 rect.adjust(1, 0, -1, -2);
811 painter.setPen(m_itemGpuForeground);
813 painter.setPen(m_itemCpuForeground);
816 painter.setPen(m_itemDeselectedForeground);
819 painter.drawText(rect,
820 Qt::AlignLeft | Qt::AlignVCenter,
821 painter.fontMetrics().elidedText(QString::fromStdString(call.name), Qt::ElideRight, rect.width()));
830 * Render the whole widget
832 void TimelineWidget::paintEvent(QPaintEvent *e)
837 QPainter painter(this);
839 int rowEnd = qMin(m_row + qCeil(m_viewHeight / (double)m_rowHeight) + 1, m_rowCount);
840 int64_t heatGPU = 0, heatCPU = 0;
841 int lastCpuX = 0, lastGpuX = 0;
842 int widgetHeight = height();
843 int widgetWidth = width();
845 m_timeEnd = m_time + m_timeWidth;
846 m_selectionLeft = timeToPosition(m_selection.timeStart);
847 m_selectionRight = (timeToPosition(m_selection.timeEnd) + 0.5);
850 /* Draw program rows */
851 painter.translate(m_axisWidth, m_axisHeight + m_rowHeight * 2 - (m_scrollY % m_rowHeight));
853 for (int row = m_row; row < rowEnd; ++row) {
854 Program& program = m_profile->programs[m_rowPrograms[row]];
858 for (std::vector<unsigned>::const_iterator itr = program.calls.begin(); itr != program.calls.end(); ++itr) {
859 const Call& call = m_profile->calls[*itr];
861 if (!drawCall(painter, call, lastGpuX, heatGPU, true)) {
866 painter.translate(0, m_rowHeight);
870 /* Draw CPU/GPU rows */
871 painter.resetTransform();
872 painter.translate(m_axisWidth, m_axisHeight);
873 painter.fillRect(0, 0, m_viewWidth, m_rowHeight * 2, Qt::white);
875 lastCpuX = lastGpuX = 0;
876 heatCPU = heatGPU = 0;
878 for (std::vector<Call>::const_iterator itr = m_profile->calls.begin(); itr != m_profile->calls.end(); ++itr) {
879 const Call& call = *itr;
882 if (call.pixels >= 0) {
883 painter.translate(0, m_rowHeight);
884 drawCall(painter, call, lastGpuX, heatGPU, true);
885 painter.translate(0, -m_rowHeight);
889 if (!drawCall(painter, call, lastCpuX, heatCPU, false)) {
896 painter.resetTransform();
897 painter.setPen(m_axisBorder);
900 painter.fillRect(m_axisWidth - 1, 0, widgetWidth, m_axisHeight - 1, m_axisBackground);
901 painter.drawLine(0, m_axisHeight - 1, widgetWidth, m_axisHeight - 1);
904 painter.fillRect(0, m_axisHeight - 1, m_axisWidth - 1, widgetHeight, m_axisBackground);
905 painter.drawLine(m_axisWidth - 1, 0, m_axisWidth - 1, widgetHeight);
908 /* Draw the program numbers */
909 painter.translate(0, m_axisHeight + m_rowHeight * 2);
911 for (int row = m_row; row < rowEnd; ++row) {
912 int y = (row - m_row) * m_rowHeight - (m_scrollY % m_rowHeight);
914 painter.setPen(m_axisForeground);
915 painter.drawText(0, y, m_axisWidth, m_rowHeight, Qt::AlignHCenter | Qt::AlignVCenter, QString("%1").arg(m_rowPrograms[row]));
917 if (m_selection.type == SelectProgram && m_selection.program == m_rowPrograms[row]) {
918 painter.setPen(m_selectionBorder);
919 painter.drawLine(0, qMax(0, y - 1), widgetWidth, qMax(0, y - 1));
920 painter.drawLine(0, y + m_rowHeight - 1, widgetWidth, y + m_rowHeight - 1);
921 painter.drawLine(m_axisWidth - 1, y - 1, m_axisWidth - 1, y + m_rowHeight - 1);
923 painter.setPen(m_axisBorder);
924 painter.drawLine(0, y + m_rowHeight - 1, m_axisWidth - 1, y + m_rowHeight - 1);
926 painter.setPen(m_axisLine);
927 painter.drawLine(m_axisWidth, y + m_rowHeight - 1, widgetWidth, y + m_rowHeight - 1);
932 /* Draw the "CPU" axis label */
933 painter.resetTransform();
934 painter.translate(0, m_axisHeight);
936 painter.setPen(m_axisBorder);
937 painter.setBrush(m_axisBackground);
938 painter.drawRect(-1, -1, m_axisWidth, m_rowHeight);
940 painter.setPen(m_axisForeground);
941 painter.drawText(0, 0, m_axisWidth - 1, m_rowHeight - 1, Qt::AlignHCenter | Qt::AlignVCenter, "CPU");
943 painter.setPen(m_axisBorder);
944 painter.drawLine(m_axisWidth, m_rowHeight - 1, widgetWidth, m_rowHeight - 1);
947 /* Draw the "GPU" axis label */
948 painter.translate(0, m_rowHeight);
950 painter.setPen(m_axisBorder);
951 painter.setBrush(m_axisBackground);
952 painter.drawRect(-1, -1, m_axisWidth, m_rowHeight);
954 painter.setPen(m_axisForeground);
955 painter.drawText(0, 0, m_axisWidth - 1, m_rowHeight - 1, Qt::AlignHCenter | Qt::AlignVCenter, "GPU");
957 painter.setPen(m_axisBorder);
958 painter.drawLine(m_axisWidth, m_rowHeight - 1, widgetWidth, m_rowHeight - 1);
961 /* Draw the frame numbers */
962 painter.resetTransform();
964 painter.setPen(m_axisForeground);
965 painter.translate(m_axisWidth, 0);
967 int lastLabel = -999; /* Ensure first label gets drawn */
969 double scroll = m_time;
970 scroll /= m_timeWidth;
971 scroll *= m_viewWidth;
973 for (std::vector<Frame>::const_iterator itr = m_profile->frames.begin(); itr != m_profile->frames.end(); ++itr) {
974 static const int padding = 4;
975 const Frame& frame = *itr;
979 if (frame.cpuStart > m_timeEnd) {
983 if (frame.cpuStart + frame.cpuDuration < m_time) {
987 double left = frame.cpuStart;
991 double right = frame.cpuStart + frame.cpuDuration;
992 right /= m_timeWidth;
993 right *= m_viewWidth;
995 QString text = QString("%1").arg(frame.no);
997 width = painter.fontMetrics().width(text) + padding * 2;
999 if (left + width > scroll)
1002 /* Draw a frame number if we have space since the last one */
1003 if (left - lastLabel > width) {
1004 lastLabel = left + width;
1008 painter.setPen(m_axisForeground);
1010 if (left < scroll && right - left > width) {
1011 if (right - scroll > width) {
1014 textX = right - scroll - width;
1017 textX = left - scroll;
1020 /* Draw frame number and major ruler marking */
1021 painter.drawText(textX + padding, 0, width - padding, m_axisHeight - 5, Qt::AlignLeft | Qt::AlignVCenter, text);
1022 painter.drawLine(left - scroll, m_axisHeight / 2, left - scroll, m_axisHeight - 1);
1025 /* Draw a minor ruler marking */
1026 painter.drawLine(left - scroll, m_axisHeight - (m_axisHeight / 4), left - scroll, m_axisHeight - 1);
1031 /* Draw "Frame" axis label */
1032 painter.resetTransform();
1034 painter.setPen(m_axisBorder);
1035 painter.setBrush(m_axisBackground);
1036 painter.drawRect(-1, -1, m_axisWidth, m_axisHeight);
1038 painter.setPen(m_axisForeground);
1039 painter.drawText(0, 0, m_axisWidth - 1, m_axisHeight - 1, Qt::AlignHCenter | Qt::AlignVCenter, "Frame");
1042 /* Draw the active selection border */
1043 if (m_selection.type == SelectTime) {
1044 painter.setPen(m_selectionBorder);
1046 m_selectionLeft += m_axisWidth;
1047 m_selectionRight += m_axisWidth;
1049 if (m_selectionLeft >= m_axisWidth && m_selectionLeft < widgetWidth) {
1050 painter.drawLine(m_selectionLeft, 0, m_selectionLeft, widgetHeight);
1053 if (m_selectionRight >= m_axisWidth && m_selectionRight < widgetWidth) {
1054 painter.drawLine(m_selectionRight, 0, m_selectionRight, widgetHeight);
1057 m_selectionLeft = qBound(m_axisWidth, m_selectionLeft, widgetWidth);
1058 m_selectionRight = qBound(m_axisWidth, m_selectionRight, widgetWidth);
1060 painter.drawLine(m_selectionLeft, m_axisHeight - 1, m_selectionRight, m_axisHeight - 1);
1061 painter.fillRect(m_selectionLeft, 0, m_selectionRight - m_selectionLeft, widgetHeight, m_selectionBackground);
1065 /* Draw the ruler zoom */
1066 if (m_mousePressMode == RulerZoom) {
1067 int x1 = m_mousePressPosition.x();
1068 int x2 = qMax(m_mousePosition.x(), m_axisWidth);
1070 painter.setPen(m_zoomBorder);
1071 painter.drawLine(x1, 0, x1, widgetHeight);
1072 painter.drawLine(x2, 0, x2, widgetHeight);
1073 painter.drawLine(x1, m_axisHeight - 1, x2, m_axisHeight - 1);
1074 painter.fillRect(x1, m_axisHeight, x2 - x1, widgetHeight, m_zoomBackground);
1078 #include "timelinewidget.moc"