summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp')
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp196
1 files changed, 115 insertions, 81 deletions
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
index 9b883552..a72509df 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
@@ -33,6 +33,8 @@
#include <QtGui/qpainter.h>
#include <QtWidgets/qwidget.h>
+using namespace TimelineConstants;
+
Ruler::Ruler(TimelineItem *parent) : TimelineItem(parent)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
@@ -42,95 +44,141 @@ void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
{
Q_UNUSED(option)
- double xStep = TimelineConstants::RULER_SEC_W / TimelineConstants::RULER_SEC_DIV * m_timeScale;
- double activeSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_duration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
- double totalSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_maxDuration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
-
- // Ruler painted width to be at least widget width
- double minRulerWidth = widget->width();
- double rowXMax = std::max(minRulerWidth, totalSegmentsWidth);
+ painter->translate(RULER_EDGE_OFFSET, RULER_BASE_Y);
- painter->save();
+ // draw inactive base line
+ int startX = qMax(m_viewportX - int(RULER_EDGE_OFFSET), 0);
+ int endX = m_viewportX + widget->width();
painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
- painter->drawLine(TimelineConstants::RULER_EDGE_OFFSET,
- TimelineConstants::RULER_BASE_Y,
- rowXMax + TimelineConstants::RULER_EDGE_OFFSET,
- TimelineConstants::RULER_BASE_Y);
- painter->setPen(CStudioPreferences::timelineRulerColor());
- painter->drawLine(TimelineConstants::RULER_EDGE_OFFSET,
- TimelineConstants::RULER_BASE_Y,
- activeSegmentsWidth,
- TimelineConstants::RULER_BASE_Y);
+ painter->drawLine(startX, 0, endX, 0);
+
+ // draw active base line
+ int durEndX = qMin(endX, int(timeToDistance(m_duration)));
+ if (durEndX > startX) {
+ painter->setPen(CStudioPreferences::timelineRulerColor());
+ painter->drawLine(startX, 0, durEndX, 0);
+ }
+ // draw ruler steps and text
QFont font = painter->font();
font.setPointSize(8);
painter->setFont(font);
- const int margin = 50;
- const int secDiv = TimelineConstants::RULER_SEC_DIV;
- double rowX = 0;
bool useDisabledColor = false;
- for (int i = 0; rowX < rowXMax; i++) {
- rowX = TimelineConstants::RULER_EDGE_OFFSET + xStep * i;
-
- // Optimization to skip painting outside the visible area
- if (rowX < (m_viewportX - margin) || rowX > (m_viewportX + minRulerWidth + margin))
+ int startSecond = int(distanceToTime(startX) / 1000);
+ int endSecond = int(distanceToTime(endX) / 1000) + 1;
+
+ static const int LABEL_W = 40;
+ static const int LABEL_H = 10;
+ static const int MIN_SEC_STEP_DIVISION = 20;
+ static const int MIN_SEC_STEP_LABEL = 60;
+ static const int MIN_HALF_SEC_STEP_DIVISION = 10;
+ static const int MIN_HALF_SEC_STEP_LABEL = 70;
+ static const int MIN_ONE_TENTH_STEP_DIVISION = 4;
+ static const int MIN_ONE_TENTH_STEP_LABEL = 30;
+
+ QRectF labelRect(0, 0, LABEL_W, LABEL_H);
+ double secStep = timeToDistance(1000);
+ double halfSecStep = timeToDistance(500);
+ double oneTenthStep = timeToDistance(100);
+
+ int skipperSecLabel = qMax(int(MIN_SEC_STEP_LABEL / secStep), 1);
+ if (skipperSecLabel > 5)
+ skipperSecLabel = lroundf(skipperSecLabel / 5.f) * 5;
+
+ int skipperSecDivision = qMax(int(MIN_SEC_STEP_DIVISION / secStep), 1);
+
+ // keep skipperSecLabel and skipperSecDivision in sync
+ if (skipperSecLabel > 5 && skipperSecDivision % 5)
+ skipperSecDivision = lroundf(skipperSecLabel / 10.f) * 5;
+
+ bool drawHalfSecDiv = halfSecStep > MIN_HALF_SEC_STEP_DIVISION;
+ bool drawHalfSecLabel = halfSecStep > MIN_HALF_SEC_STEP_LABEL;
+ bool drawOneTenthDiv = oneTenthStep > MIN_ONE_TENTH_STEP_DIVISION;
+ bool drawOneTenthLabel = oneTenthStep > MIN_ONE_TENTH_STEP_LABEL;
+
+ for (int i = startSecond; i <= endSecond; ++i) { // draw seconds
+ if (i % skipperSecDivision)
continue;
- const int h = i % secDiv == 0 ? TimelineConstants::RULER_DIV_H1
- : i % secDiv == secDiv * 0.5 ? TimelineConstants::RULER_DIV_H2
- : TimelineConstants::RULER_DIV_H3;
-
- if (!useDisabledColor && rowX > activeSegmentsWidth) {
+ int x = int(timeToDistance(i * 1000));
+ if (!useDisabledColor && x > durEndX) {
painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
useDisabledColor = true;
}
- painter->drawLine(QPointF(rowX, TimelineConstants::RULER_BASE_Y - h),
- QPointF(rowX, TimelineConstants::RULER_BASE_Y - 1));
-
- // See if label should be shown at this tick at this zoom level
- bool drawTimestamp = false;
- if ((i % (secDiv * 4) == 0)
- || (i % (secDiv * 2) == 0 && m_timeScale >= TimelineConstants::RULER_TICK_SCALE1)
- || (i % secDiv == 0 && m_timeScale >= TimelineConstants::RULER_TICK_SCALE2)
- || (i % secDiv == secDiv * 0.5
- && m_timeScale >= TimelineConstants::RULER_TICK_SCALE3)
- || (m_timeScale >= TimelineConstants::RULER_TICK_SCALE4)) {
- drawTimestamp = true;
+
+ // draw second division
+ painter->drawLine(x, -RULER_DIV_H1, x, 0);
+
+ if (i % skipperSecLabel == 0) { // draw label if not skipped
+ labelRect.moveTo(x - LABEL_W / 2, -LABEL_H - 7);
+ painter->drawText(labelRect, Qt::AlignCenter, formatTime(i));
}
- if (drawTimestamp) {
- QRectF timestampPos = QRectF(TimelineConstants::RULER_EDGE_OFFSET
- + xStep * i - TimelineConstants::RULER_LABEL_W / 2,
- 1, TimelineConstants::RULER_LABEL_W,
- TimelineConstants::RULER_LABEL_H);
- painter->drawText(timestampPos, Qt::AlignCenter,
- timestampString(i * 1000 / TimelineConstants::RULER_SEC_DIV));
+ // draw half seconds
+ if (!drawHalfSecDiv || i == endSecond)
+ continue;
+
+ x = int(timeToDistance(i * 1000 + 500));
+ if (!useDisabledColor && x > durEndX) {
+ painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
+ useDisabledColor = true;
}
+ painter->drawLine(x, -RULER_DIV_H2, x, 0);
- }
+ if (drawHalfSecLabel) {
+ labelRect.moveTo(x - LABEL_W / 2, -LABEL_H - 7);
+ painter->drawText(labelRect, Qt::AlignCenter, formatTime(i + .5));
+ }
+
+ // draw one tenth
+ if (!drawOneTenthDiv)
+ continue;
- painter->restore();
+ for (int j = 1; j <= 9; ++j) {
+ if (j != 5) {
+ x = int(timeToDistance(i * 1000 + j * 100));
+ if (!useDisabledColor && x > durEndX) {
+ painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
+ useDisabledColor = true;
+ }
+ painter->drawLine(x, -RULER_DIV_H3, x, 0);
+
+ if (drawOneTenthLabel) {
+ labelRect.moveTo(x - LABEL_W / 2, -LABEL_H - 7);
+ painter->drawText(labelRect, Qt::AlignCenter, formatTime(i + .1 * j));
+ }
+ }
+ }
+ }
}
-void Ruler::setTimelineScale(double scl)
+void Ruler::setTimelineScale(int scl)
{
- m_timeScale = scl;
+ // scl is in the range 0..100, project it to an exponential value
+ bool isScaleDown = scl < 50;
+ const double normVal = abs(scl - 50) / 10.; // normalize to range 5..0..5 from scale down to up
+ double scaleVal = pow(normVal, 1.3);
+
+ // For scaling down normalize to range -1..0. 5^1.3 is max scaleVal but 5.1 is used to make
+ // sure scaleVal doesn't reach -1 in which case m_timeScale would become 0.
+ if (isScaleDown)
+ scaleVal /= -pow(5.1, 1.3);
+
+ m_timeScale = 1 + scaleVal;
update();
}
// convert distance values to time (milliseconds)
long Ruler::distanceToTime(double distance) const
{
- return distance / (TimelineConstants::RULER_MILLI_W * m_timeScale);
+ return long(distance / (RULER_MILLI_W * m_timeScale));
}
// convert time (milliseconds) values to distance
double Ruler::timeToDistance(long time) const
{
- return time * TimelineConstants::RULER_MILLI_W * m_timeScale;
+ return time * RULER_MILLI_W * m_timeScale;
}
double Ruler::timelineScale() const
@@ -159,7 +207,6 @@ void Ruler::setDuration(long duration)
if (m_duration != duration) {
m_duration = duration;
update();
- emit durationChanged(m_duration);
}
}
@@ -187,30 +234,17 @@ int Ruler::viewportX() const
return m_viewportX;
}
-// Returns timestamp in mm:ss.ttt or ss.ttt format
-const QString Ruler::timestampString(int timeMs)
+// Returns ruler time in m:s.t or s.t format
+const QString Ruler::formatTime(double seconds)
{
- static const QString zeroString = tr("0");
- static const QChar fillChar = tr("0").at(0);
- static const QString noMinutesTemplate = tr("%1.%2");
- static const QString minutesTemplate = tr("%1:%2.%3");
-
- int ms = timeMs % 1000;
- int s = timeMs % 60000 / 1000;
- int m = timeMs % 3600000 / 60000;
- const QString msString = QString::number(ms).rightJustified(3, fillChar);
- const QString sString = QString::number(s);
-
- if (timeMs == 0) {
- return zeroString;
- } else if (m == 0) {
- if (s < 10)
- return noMinutesTemplate.arg(sString).arg(msString);
- else
- return noMinutesTemplate.arg(sString.rightJustified(2, fillChar)).arg(msString);
- } else {
- return minutesTemplate.arg(m).arg(sString.rightJustified(2, fillChar)).arg(msString);
- }
+ if (seconds < 60)
+ return QString::number(seconds);
+
+ int mins = int(seconds) / 60;
+ double secs = seconds - mins * 60;
+
+ const QChar fillChar = tr("0").at(0);
+ return QStringLiteral("%1:%2").arg(mins).arg(QString::number(secs).rightJustified(2, fillChar));
}
int Ruler::type() const