From ac9233fade8ca60057cfd3aaf9ffc100f842d608 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 12 Sep 2018 21:34:43 +1000 Subject: [PATCH] added proper timecodes in the timeline --- io/config.cpp | 13 +++++-- io/config.h | 5 +++ io/previewgenerator.cpp | 3 +- mainwindow.cpp | 16 ++++----- panels/timeline.cpp | 5 +-- panels/timeline.ui | 35 +++++-------------- panels/viewer.cpp | 12 +++---- panels/viewer.h | 5 --- ui/timelineheader.cpp | 77 +++++++++++++++++++++++++++++++---------- ui/timelineheader.h | 6 +++- 10 files changed, 107 insertions(+), 70 deletions(-) diff --git a/io/config.cpp b/io/config.cpp index d3033a1b3..504a0d913 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -17,7 +17,8 @@ Config::Config() select_also_seeks(false), paste_seeks(true), rectified_waveforms(false), - default_transition_length(30) + default_transition_length(30), + timecode_view(TIMECODE_DROP) { } @@ -55,10 +56,15 @@ void Config::load(QString path) { stream.readNext(); img_seq_formats = stream.text().toString(); } else if (stream.name() == "RectifiedWaveforms") { + stream.readNext(); rectified_waveforms = (stream.text() == "1"); } else if (stream.name() == "DefaultTransitionLength") { - rectified_waveforms = stream.text().toInt(); - } + stream.readNext(); + default_transition_length = stream.text().toInt(); + } else if (stream.name() == "TimecodeView") { + stream.readNext(); + timecode_view = stream.text().toInt(); + } } } if (stream.hasError()) { @@ -114,6 +120,7 @@ void Config::save(QString path) { stream.writeTextElement("ImageSequenceFormats", img_seq_formats); stream.writeTextElement("RectifiedWaveforms", QString::number(rectified_waveforms)); stream.writeTextElement("DefaultTransitionLength", QString::number(default_transition_length)); + stream.writeTextElement("TimecodeView", QString::number(timecode_view)); stream.writeEndElement(); stream.writeEndDocument(); // doc diff --git a/io/config.h b/io/config.h index d444d305e..d16542773 100644 --- a/io/config.h +++ b/io/config.h @@ -5,6 +5,10 @@ #define SAVE_VERSION "180820" // YYMMDD +#define TIMECODE_DROP 0 +#define TIMECODE_NONDROP 1 +#define TIMECODE_FRAMES 2 + struct Config { Config(); bool saved_layout; @@ -17,6 +21,7 @@ struct Config { QString img_seq_formats; bool rectified_waveforms; int default_transition_length; + int timecode_view; void load(QString path); void save(QString path); diff --git a/io/previewgenerator.cpp b/io/previewgenerator.cpp index bedcd7214..8ef3e4148 100644 --- a/io/previewgenerator.cpp +++ b/io/previewgenerator.cpp @@ -2,6 +2,7 @@ #include "media.h" #include "panels/viewer.h" +#include "io/config.h" #include #include @@ -90,7 +91,7 @@ void PreviewGenerator::finalize_media() { if (!contains_still_image || media->audio_tracks.size() > 0) { double frame_rate = 30; if (!contains_still_image && media->video_tracks.size() > 0) frame_rate = media->video_tracks.at(0)->video_frame_rate; - item->setText(1, frame_to_timecode(media->get_length_in_frames(frame_rate), TIMECODE_DROP, frame_rate)); + item->setText(1, frame_to_timecode(media->get_length_in_frames(frame_rate), config.timecode_view, frame_rate)); } } diff --git a/mainwindow.cpp b/mainwindow.cpp index 1fe305467..93e5a2ceb 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -39,7 +39,7 @@ QTimer autorecovery_timer; QString config_dir; -QString appName = "Olive (August 2018 | Alpha)"; +QString appName = "Olive (September 2018 | Alpha)"; bool demoNoticeShown = false; void MainWindow::setup_layout() { @@ -538,15 +538,15 @@ void MainWindow::windowMenu_About_To_Be_Shown() { void MainWindow::viewMenu_About_To_Be_Shown() { ui->actionTimeline_Track_Lines->setChecked(config.show_track_lines); - ui->actionFrames->setChecked(panel_viewer->timecode_view == TIMECODE_FRAMES); - ui->actionDrop_Frame->setChecked(panel_viewer->timecode_view == TIMECODE_DROP); - if (sequence != NULL) ui->actionDrop_Frame->setEnabled(frame_rate_is_droppable(sequence->frame_rate)); - ui->actionNon_Drop_Frame->setChecked(panel_viewer->timecode_view == TIMECODE_NONDROP); + ui->actionFrames->setChecked(config.timecode_view == TIMECODE_FRAMES); + ui->actionDrop_Frame->setChecked(config.timecode_view == TIMECODE_DROP); +// if (sequence != NULL) ui->actionDrop_Frame->setEnabled(frame_rate_is_droppable(sequence->frame_rate)); + ui->actionNon_Drop_Frame->setChecked(config.timecode_view == TIMECODE_NONDROP); } void MainWindow::on_actionFrames_triggered() { - panel_viewer->timecode_view = TIMECODE_FRAMES; + config.timecode_view = TIMECODE_FRAMES; if (sequence != NULL) { panel_viewer->update_playhead_timecode(panel_timeline->playhead); panel_viewer->update_end_timecode(); @@ -555,7 +555,7 @@ void MainWindow::on_actionFrames_triggered() void MainWindow::on_actionDrop_Frame_triggered() { - panel_viewer->timecode_view = TIMECODE_DROP; + config.timecode_view = TIMECODE_DROP; if (sequence != NULL) { panel_viewer->update_playhead_timecode(panel_timeline->playhead); panel_viewer->update_end_timecode(); @@ -564,7 +564,7 @@ void MainWindow::on_actionDrop_Frame_triggered() void MainWindow::on_actionNon_Drop_Frame_triggered() { - panel_viewer->timecode_view = TIMECODE_NONDROP; + config.timecode_view = TIMECODE_NONDROP; if (sequence != NULL) { panel_viewer->update_playhead_timecode(panel_timeline->playhead); panel_viewer->update_end_timecode(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 4637c8383..7b3841430 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -82,6 +82,7 @@ Timeline::Timeline(QWidget *parent) : int timeline_area_height = (ui->timeline_area->height()>>1); ui->videoScrollArea->resize(ui->videoScrollArea->width(), timeline_area_height); ui->audioScrollArea->resize(ui->audioScrollArea->width(), timeline_area_height); + ui->headerScrollArea->setMaximumHeight(ui->headers->minimumHeight()); connect(ui->audioScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)), ui->videoScrollArea->horizontalScrollBar(), SLOT(setValue(int))); connect(ui->audioScrollArea->horizontalScrollBar(), SIGNAL(valueChanged(int)), ui->headerScrollArea->horizontalScrollBar(), SLOT(setValue(int))); @@ -1095,7 +1096,7 @@ void Timeline::deselect() { } long getFrameFromScreenPoint(double zoom, int x) { - long f = round((float) x / zoom); + long f = qRound((float) x / zoom); if (f < 0) { return 0; } @@ -1103,7 +1104,7 @@ long getFrameFromScreenPoint(double zoom, int x) { } int getScreenPointFromFrame(double zoom, long frame) { - return (int) round(frame*zoom); + return (int) qRound(frame*zoom); } long Timeline::getTimelineFrameFromScreenPoint(int x) { diff --git a/panels/timeline.ui b/panels/timeline.ui index 534c009c3..23da16569 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -304,17 +304,11 @@ - + 0 0 - - - 16777215 - 15 - - QFrame::NoFrame @@ -327,18 +321,13 @@ Qt::ScrollBarAlwaysOff + + QAbstractScrollArea::AdjustToContents + true - - - 0 - 0 - 821 - 16 - - 0 @@ -369,12 +358,6 @@ 0 - - - 0 - 15 - - Qt::ClickFocus @@ -389,7 +372,7 @@ 0 - 0 + 1 @@ -422,8 +405,8 @@ 0 0 - 807 - 163 + 817 + 174 @@ -473,8 +456,8 @@ 0 0 - 807 - 377 + 817 + 339 diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 4c673d758..e0c2cd523 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -5,6 +5,7 @@ #include "timeline.h" #include "project/sequence.h" #include "panels/panels.h" +#include "io/config.h" #define FRAMES_IN_ONE_MINUTE 1798 // 1800 - 2 #define FRAMES_IN_TEN_MINUTES 17978 // (FRAMES_IN_ONE_MINUTE * 10) - 2 @@ -22,7 +23,6 @@ Viewer::Viewer(QWidget *parent) : ui->setupUi(this); ui->glViewerPane->child = ui->openGLWidget; viewer_widget = ui->openGLWidget; - timecode_view = TIMECODE_DROP; update_sequence(); update_playhead_timecode(0); @@ -99,14 +99,14 @@ bool frame_rate_is_droppable(float rate) { } void Viewer::update_playhead_timecode(long p) { - ui->currentTimecode->setText(frame_to_timecode(p, timecode_view, (sequence != NULL) ? sequence->frame_rate : 30)); + ui->currentTimecode->setText(frame_to_timecode(p, config.timecode_view, (sequence != NULL) ? sequence->frame_rate : 30)); } void Viewer::update_end_timecode() { if (sequence == NULL) { - ui->endTimecode->setText(frame_to_timecode(0, timecode_view, 30)); + ui->endTimecode->setText(frame_to_timecode(0, config.timecode_view, 30)); } else { - ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame(), timecode_view, sequence->frame_rate)); + ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame(), config.timecode_view, sequence->frame_rate)); } } @@ -125,9 +125,9 @@ void Viewer::update_sequence() { if (!null_sequence) { if (frame_rate_is_droppable(sequence->frame_rate)) { - timecode_view = TIMECODE_DROP; + config.timecode_view = TIMECODE_DROP; } else { - timecode_view = TIMECODE_NONDROP; + config.timecode_view = TIMECODE_NONDROP; } update_playhead_timecode(panel_timeline->playhead); diff --git a/panels/viewer.h b/panels/viewer.h index b623ecde9..085cb11fb 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -1,10 +1,6 @@ #ifndef VIEWER_H #define VIEWER_H -#define TIMECODE_DROP 0 -#define TIMECODE_NONDROP 1 -#define TIMECODE_FRAMES 2 - #include class Timeline; @@ -28,7 +24,6 @@ public: void update_sequence(); void compose(); void set_playpause_icon(bool play); - int timecode_view; void update_playhead_timecode(long p); void update_end_timecode(); diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index 55e20c93f..e58766981 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -4,17 +4,22 @@ #include "panels/timeline.h" #include "project/sequence.h" #include "project/undo.h" +#include "panels/viewer.h" +#include "io/config.h" #include #include #include +#include +#include #define CLICK_RANGE 5 #define PLAYHEAD_SIZE 6 -TimelineHeader::TimelineHeader(QWidget *parent) : QWidget(parent), dragging(false), resizing_workarea(false), zoom(1), in_visible(0), snapping(true) { +TimelineHeader::TimelineHeader(QWidget *parent) : QWidget(parent), dragging(false), resizing_workarea(false), zoom(1), in_visible(0), snapping(true), fm(font()) { setCursor(Qt::ArrowCursor); setMouseTracking(true); + setMinimumHeight(fm.height()*2); } void TimelineHeader::set_playhead(int mouse_x) { @@ -121,22 +126,58 @@ void TimelineHeader::update_header(double z) { update(); } +#define LINE_MIN_PADDING 50 + void TimelineHeader::paintEvent(QPaintEvent*) { if (sequence != NULL) { QPainter p(this); - p.setPen(Qt::gray); - int interval = 0; - int multiplier = 0; - do { - multiplier++; - interval = getScreenPointFromFrame(zoom, 1*multiplier); - } while (interval < 10); - for (int i=0;i 0) { - drawHeight = drawHeight>>1; - } - p.drawLine(i, 0, i, drawHeight); + int yoff = height()/2; + + double interval = sequence->frame_rate; + int textWidth = 0; + int lastTextBoundary = 0; + + int i = 0; + int lastLineX = -LINE_MIN_PADDING-1; + + int sublineCount = 1; + int sublineTest = qRound(interval*zoom); + int sublineInterval = 1; + while (sublineTest > LINE_MIN_PADDING + && sublineInterval >= 1) { + sublineCount *= 2; + sublineInterval = (interval/sublineCount); + sublineTest = qRound(sublineInterval*zoom); + } + sublineCount = qMin(sublineCount, qRound(interval)); + + while (true) { + long frame = qRound(interval*i); + int lineX = qRound(frame*zoom); + if (lineX > width()) break; + if (lineX > lastLineX+LINE_MIN_PADDING) { + // draw text + if (lineX-textWidth > lastTextBoundary) { + p.setPen(Qt::white); + QString timecode = frame_to_timecode(frame, config.timecode_view, sequence->frame_rate); + textWidth = fm.width(timecode)>>1; + lastTextBoundary = lineX+textWidth; + p.drawText(QRect(lineX-textWidth, 0, lastTextBoundary, yoff), timecode); + } + + // draw line markers + p.setPen(Qt::gray); + p.drawLine(lineX, yoff, lineX, height()); + + lastLineX = lineX; + + // draw sub-line markers + for (int j=1;j>1)); + } + } + i++; } // draw in/out selection @@ -151,12 +192,12 @@ void TimelineHeader::paintEvent(QPaintEvent*) { } // draw playhead triangle - in_x = getScreenPointFromFrame(zoom, panel_timeline->playhead - in_visible); - QPoint start(in_x, height()); + in_x = getScreenPointFromFrame(zoom, panel_timeline->playhead - in_visible); + QPoint start(in_x, height()+2); QPainterPath path; path.moveTo(start); - path.lineTo(in_x-PLAYHEAD_SIZE, 0); - path.lineTo(in_x+PLAYHEAD_SIZE, 0); + path.lineTo(in_x-PLAYHEAD_SIZE, yoff); + path.lineTo(in_x+PLAYHEAD_SIZE, yoff); path.lineTo(start); p.fillPath(path, Qt::red); } diff --git a/ui/timelineheader.h b/ui/timelineheader.h index 5ac8d8be8..305d71e93 100644 --- a/ui/timelineheader.h +++ b/ui/timelineheader.h @@ -2,6 +2,8 @@ #define TIMELINEHEADER_H #include +#include +class QScrollArea; class TimelineHeader : public QWidget { @@ -13,7 +15,7 @@ public: bool snapping; - void update_header(double z); + void update_header(double z); protected: void paintEvent(QPaintEvent*); @@ -36,6 +38,8 @@ private: void set_playhead(int mouse_x); + QFontMetrics fm; + signals: public slots: