From 705ecc0910cb388c5c0536d6533c4c255dcbbe4e Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 24 Jul 2019 19:21:46 -0700 Subject: [PATCH] developed timeruler prototype --- app/common/timecodefunctions.cpp | 2 + app/common/timecodefunctions.h | 6 + app/panel/timeline/timeline.cpp | 2 + app/widget/timeruler/timeruler.cpp | 224 +++++++++++++++++++++++++---- app/widget/timeruler/timeruler.h | 23 ++- 5 files changed, 226 insertions(+), 31 deletions(-) create mode 100644 app/common/timecodefunctions.cpp create mode 100644 app/common/timecodefunctions.h diff --git a/app/common/timecodefunctions.cpp b/app/common/timecodefunctions.cpp new file mode 100644 index 000000000..b94b54fe9 --- /dev/null +++ b/app/common/timecodefunctions.cpp @@ -0,0 +1,2 @@ +#include "timecodefunctions.h" + diff --git a/app/common/timecodefunctions.h b/app/common/timecodefunctions.h new file mode 100644 index 000000000..264c18327 --- /dev/null +++ b/app/common/timecodefunctions.h @@ -0,0 +1,6 @@ +#ifndef TIMECODEFUNCTIONS_H +#define TIMECODEFUNCTIONS_H + + + +#endif // TIMECODEFUNCTIONS_H diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index d09c91ae8..68c400b5f 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -32,6 +32,8 @@ TimelinePanel::TimelinePanel(QWidget *parent) : setWidget(main); QVBoxLayout* layout = new QVBoxLayout(main); + layout->setSpacing(0); + layout->setMargin(0); TimeRuler* tr = new TimeRuler(true, this); layout->addWidget(tr); diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index c2e3a3d3d..1ee59563e 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -1,29 +1,43 @@ #include "timeruler.h" +#include #include +#include #include "common/qtversionabstraction.h" TimeRuler::TimeRuler(bool text_visible, QWidget* parent) : QWidget(parent), scroll_(0), - scale_(1.0) + centered_text_(true), + scale_(16.0) { - // Text height is used to calculate widget height - text_height_ = fontMetrics().height(); - - // FIXME: Fairly mediocre, but reliable way of scaling UI objects by font/DPI size QFontMetrics fm = fontMetrics(); - width_of_second_ = QFontMetricsWidth(&fm, "HHHHHHHHHHHHHHHH"); - minimum_gap_between_lines_ = QFontMetricsWidth(&fm, "HH"); + // Text height is used to calculate widget height + text_height_ = fm.height(); + + // Get the "minimum" space allowed between two line markers on the ruler (in screen pixels) + // Mediocre but reliable way of scaling UI objects by font/DPI size + minimum_gap_between_lines_ = QFontMetricsWidth(&fm, "H"); + + // Text visibility affects height, so we set that here SetTextVisible(text_visible); + + // FIXME: Test code + time_base_ = rational(1001, 30000); + connect(&test_timer_, SIGNAL(timeout()), this, SLOT(TimeOut())); + test_timer_.setInterval(20); + test_timer_.start(); + // End test code } void TimeRuler::SetTextVisible(bool e) { text_visible_ = e; + // Text visibility affects height, if text is visible the widget doubles in height with the top half for text and + // the bottom half for ruler markings if (text_visible_) { setMinimumHeight(text_height_ * 2); } else { @@ -47,38 +61,190 @@ void TimeRuler::SetTimebase(const rational &r) update(); } +void TimeRuler::SetScroll(int s) +{ + scroll_ = s; + + update(); +} + void TimeRuler::paintEvent(QPaintEvent *e) { Q_UNUSED(e) + // Nothing to paint if the timebase is invalid + if (time_base_.denominator() == 0) { + return; + } + QPainter p(this); - // FIXME: Make this CSS configurable - p.setPen(Qt::white); + int last_unit = -1; + int last_sec = -1; + /* + // Test code that draws a line every single time unit + for (int i=0;i last_unit) { - //int ruler_frame_line_top = (text_visible_) ? text_height_ : 0; - //int ruler_frame_line_bottom = height(); + if (sec > last_sec) { + p.setPen(Qt::red); + last_sec = sec; + } else { + p.setPen(Qt::white); + } - // Get scaled width of a second - double scaled_width = width_of_second_ * scale_; + p.drawLine(i, height()/2, i, height()); - // Draw a line for each second - int last_draw = -1; - for (double i=0;i minimum_gap_between_lines_) { - - p.drawLine(line_x, ruler_second_line_top, line_x, ruler_second_line_bottom); - - p.drawText(line_x, p.fontMetrics().ascent(), QString::number(line_x)); - - last_draw = line_x; + last_unit = unit; } } + */ + + // Depending on the scale, + // Determine an even number to divide the frame count by + int rough_frames_in_second = qRound(time_base_.flipped().ToDouble()); + int test_divider = 1; + while (!((rough_frames_in_second%test_divider == 0 || test_divider > rough_frames_in_second) + && scale_ * test_divider >= minimum_gap_between_lines_)) { + if (test_divider < rough_frames_in_second) { + test_divider++; + } else { + test_divider += rough_frames_in_second; + } + } + double reverse_divider = double(rough_frames_in_second) / double(test_divider); + qreal real_divider = qMax(1.0, time_base_.flipped().ToDouble() / reverse_divider); + + // Set where the loop ends (affected by text) + int loop_start = -1; + int loop_end = width(); + + // Determine where it can draw text + int text_skip = 1; + int half_average_text_width = 0; + int text_y = 0; + if (text_visible_) { + QFontMetrics fm = p.fontMetrics(); + double width_of_second = time_base_.flipped().ToDouble() * scale_; + int average_text_width = QFontMetricsWidth(&fm, "00:00:00;00"); // FIXME: Hardcoded string + half_average_text_width = average_text_width/2; + while (width_of_second * text_skip < average_text_width) { + text_skip++; + } + + if (centered_text_) { + loop_start = -half_average_text_width; + loop_end += half_average_text_width; + } else { + loop_start = -average_text_width; + } + + text_y = fm.ascent(); + } + + // Set line color to main text color + p.setPen(palette().text().color()); + + // Calculate where each line starts + int line_top = text_visible_ ? text_height_ : 0; + + // Calculate all three line lengths + int line_length = text_height_; + int line_sec_bottom = line_top + line_length; + int line_halfsec_bottom = line_top + line_length / 3 * 2; + int line_frame_bottom = line_top + line_length / 3; + + for (int i=loop_start;i qFloor(last_unit/real_divider)) { + + // Determine if this unit is a whole second or not + int sec = qFloor(unit * time_base_.ToDouble()); + + if (sec > last_sec) { + // This line marks a second so we make it long + p.drawLine(i, line_top, i, line_sec_bottom); + + last_sec = sec; + + // Try to draw text here + if (text_visible_ && sec%text_skip == 0) { + QString timecode_string = QString("00:00:%1;00").arg(sec, 2, 10, QChar('0')); + + int text_x = i; + + if (centered_text_) { + text_x -= half_average_text_width; + } else { + timecode_string.prepend(" "); + p.drawLine(i, 0, i, line_top); + } + + p.drawText(text_x, text_y, timecode_string); + } + } else if (unit%rough_frames_in_second == rough_frames_in_second/2) { + + // This line marks the half second point so we make it somewhere in between + p.drawLine(i, line_top, i, line_halfsec_bottom); + + } else { + + // This line just marks a frame so we make it short + p.drawLine(i, line_top, i, line_frame_bottom); + + } + + last_unit = unit; + } + } + + p.setPen(Qt::NoPen); + p.setBrush(Qt::red); + DrawPlayhead(&p, 100, height()); +} + +void TimeRuler::DrawPlayhead(QPainter *p, int x, int y) +{ + p->setRenderHint(QPainter::Antialiasing); + + int half_text_height = text_height_ / 3; + int half_gap = minimum_gap_between_lines_ / 2; + + QPoint points[] = { + QPoint(x, y), + QPoint(x - half_gap, y - half_text_height), + QPoint(x - half_gap, y - text_height_), + QPoint(x + half_gap, y - text_height_), + QPoint(x + half_gap, y - half_text_height) + }; + + p->drawPolygon(points, 5); +} + +double TimeRuler::UnitToScreen(const int &u) +{ + return u * scale_; +} + +int TimeRuler::ScreenToUnit(const int &p) +{ + double uf = p / scale_; + + int u = qRound(uf); + + if (qFuzzyCompare(UnitToScreen(u), uf)) { + return u; + } + + return -1; +} + +void TimeRuler::TimeOut() +{ + SetScroll(scroll_ + 2); } diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 06249589d..4dfaa3fbf 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -1,6 +1,7 @@ #ifndef TIMERULER_H #define TIMERULER_H +#include #include #include "common/rational.h" @@ -17,13 +18,22 @@ public: void SetTimebase(const rational& r); + void SetCenteredText(bool c); + +public slots: + void SetScroll(int s); + protected: virtual void paintEvent(QPaintEvent* e) override; private: - int text_height_; + void DrawPlayhead(QPainter* p, int x, int y); - int width_of_second_; + double UnitToScreen(const int& u); + + int ScreenToUnit(const int& p); + + int text_height_; int minimum_gap_between_lines_; @@ -31,9 +41,18 @@ private: bool text_visible_; + bool centered_text_; + double scale_; rational time_base_; + +// FIXME: Test code only + QTimer test_timer_; + +private slots: + void TimeOut(); +// End test code }; #endif // TIMERULER_H