From 7800bc4712b951f625754de63484cbf53001f091 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 10 Oct 2018 01:07:49 +1100 Subject: [PATCH] started ridiculously more efficient timeline rendering --- dialogs/speeddialog.cpp | 2 +- mainwindow.cpp | 12 +- panels/effectcontrols.cpp | 4 +- panels/project.cpp | 8 +- panels/timeline.cpp | 107 +++++----- panels/timeline.h | 8 +- panels/timeline.ui | 265 +++++++++++++---------- ui/timelineheader.cpp | 78 ++++--- ui/timelineheader.h | 11 +- ui/timelinewidget.cpp | 439 ++++++++++++++++++-------------------- ui/timelinewidget.h | 9 +- 11 files changed, 489 insertions(+), 454 deletions(-) diff --git a/dialogs/speeddialog.cpp b/dialogs/speeddialog.cpp index 713d2019b..088a1a585 100644 --- a/dialogs/speeddialog.cpp +++ b/dialogs/speeddialog.cpp @@ -392,6 +392,6 @@ void SpeedDialog::accept() { undo_stack.push(ca); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); QDialog::accept(); } diff --git a/mainwindow.cpp b/mainwindow.cpp index 66bfcf790..15f580289 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -283,12 +283,12 @@ void MainWindow::editMenu_About_To_Be_Shown() { void MainWindow::undo() { undo_stack.undo(); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } void MainWindow::redo() { undo_stack.redo(); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } void MainWindow::openSpeedDialog() { @@ -428,7 +428,7 @@ void MainWindow::on_actionProject_triggered() project_url.clear(); panel_project->new_project(); updateTitle(""); - panel_timeline->redraw_all_clips(false); + panel_timeline->repaint_timeline(false); } } @@ -709,7 +709,7 @@ void MainWindow::on_actionSet_Out_Point_triggered() void MainWindow::on_actionClear_In_Out_triggered() { if (panel_timeline->focused() && sequence->using_workarea) { undo_stack.push(new SetTimelineInOutCommand(sequence, false, 0, 0)); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } @@ -730,13 +730,13 @@ void MainWindow::on_actionRipple_Delete_In_Out_triggered() void MainWindow::on_actionTimeline_Track_Lines_triggered() { config.show_track_lines = !config.show_track_lines; - panel_timeline->redraw_all_clips(false); + panel_timeline->repaint_timeline(false); } void MainWindow::on_actionRectified_Waveforms_triggered() { config.rectified_waveforms = !config.rectified_waveforms; - panel_timeline->redraw_all_clips(false); + panel_timeline->repaint_timeline(false); } void MainWindow::on_actionDefault_triggered() { diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 7940a4540..9813bd84d 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -81,7 +81,7 @@ void EffectControls::menu_select(QAction* q) { } undo_stack.push(ca); if (transition_menu) { - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } else { reload_clips(); panel_viewer->viewer_widget->update(); @@ -89,7 +89,7 @@ void EffectControls::menu_select(QAction* q) { } void EffectControls::update_keyframes() { - if (ui->headers->isVisible()) ui->headers->update_header(zoom); + if (ui->headers->isVisible()) ui->headers->update_zoom(zoom); ui->keyframeView->update(); } diff --git a/panels/project.cpp b/panels/project.cpp index 364c8a6ca..8e56d4125 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -317,7 +317,7 @@ void Project::delete_selected_media() { // redraw clips if (redraw) { - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } } else { delete ca; @@ -564,7 +564,7 @@ void Project::delete_clips_using_selected_media() { } if (deleted) { undo_stack.push(ca); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } else { delete ca; } @@ -980,7 +980,7 @@ void Project::load_project() { if (cont) { if (open_seq != NULL) set_sequence(open_seq); - panel_timeline->redraw_all_clips(false); + panel_timeline->repaint_timeline(false); mainWindow->setWindowModified(false); } else { new_project(); @@ -1286,7 +1286,7 @@ void MediaThrobber::stop(int icon_type, bool replace) { } // redraw clips - panel_timeline->redraw_all_clips(replace); + panel_timeline->repaint_timeline(replace); panel_project->source_table->viewport()->update(); deleteLater(); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index a2318f599..d278930a2 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -59,7 +59,8 @@ Timeline::Timeline(QWidget *parent) : ui(new Ui::Timeline), last_frame(0), creating(false), - queue_audio_reset(false) + queue_audio_reset(false), + scroll(0) { default_track_height = (QGuiApplication::primaryScreen()->logicalDotsPerInch() / 96) * TRACK_DEFAULT_HEIGHT; @@ -80,16 +81,16 @@ Timeline::Timeline(QWidget *parent) : ui->toolArrowButton->click(); - int timeline_area_height = (ui->timeline_area->height()>>1); + /*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))); + ui->audioScrollArea->resize(ui->audioScrollArea->width(), timeline_area_height);*/ + ui->headerScrollArea->setMaximumHeight(ui->headers->minimumHeight()); + connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(setScroll(int))); + connect(ui->horizontalScrollBar, SIGNAL(valueChanged(int)), ui->headers, SLOT(set_scroll(int))); update_sequence(); - connect(&playback_updater, SIGNAL(timeout()), this, SLOT(repaint_timeline())); + connect(&playback_updater, SIGNAL(timeout()), this, SLOT(repaint_timeline())); } Timeline::~Timeline() @@ -165,7 +166,7 @@ void Timeline::seek(long p) { pause(); sequence->playhead = p; queue_audio_reset = true; - repaint_timeline(); + repaint_timeline(false); } void Timeline::toggle_play() { @@ -231,7 +232,7 @@ void Timeline::add_transition() { delete ca; } - redraw_all_clips(true); + repaint_timeline(true); } int Timeline::calculate_track_height(int track, int value) { @@ -271,57 +272,51 @@ void Timeline::update_sequence() { } else { setWindowTitle("Timeline: " + sequence->name); reset_all_audio(); - redraw_all_clips(false); + repaint_timeline(false); playback_updater.setInterval(qFloor(1000 / sequence->frame_rate)); } } int Timeline::get_snap_range() { - return getTimelineFrameFromScreenPoint(10); + return getFrameFromScreenPoint(zoom, 10); } bool Timeline::focused() { return (sequence != NULL && (ui->headers->hasFocus() || ui->video_area->hasFocus() || ui->audio_area->hasFocus())); } -void Timeline::repaint_timeline() { +void Timeline::repaint_timeline(bool changed) { if (playing) { sequence->playhead = round(playhead_start + ((QDateTime::currentMSecsSinceEpoch()-start_msecs) * 0.001 * sequence->frame_rate)); + } else if (changed) { + reset_all_audio(); } - ui->headers->update_header(zoom); + ui->headers->update(); ui->video_area->update(); ui->audio_area->update(); panel_effect_controls->update_keyframes(); - if (last_frame != sequence->playhead) { - panel_viewer->viewer_widget->update(); - ui->audio_monitor->update(); - last_frame = sequence->playhead; - } - panel_viewer->update_playhead_timecode(sequence->playhead); -} - -void Timeline::redraw_all_clips(bool changed) { - if (changed) { - if (!playing) reset_all_audio(); - panel_viewer->viewer_widget->update(); - } - - ui->headers->update_header(zoom); - ui->video_area->redraw_clips(); - ui->audio_area->redraw_clips(); - panel_effect_controls->update_keyframes(); - - if (zoomChanged) { - ui->audioScrollArea->update(); - ui->audioScrollArea->horizontalScrollBar()->setValue(getTimelineScreenPointFromFrame(sequence->playhead)-(ui->audioScrollArea->width()/2)); - zoomChanged = false; - } - - panel_viewer->update_end_timecode(); - update_effect_controls(); + + if (sequence != NULL) { + panel_timeline->ui->horizontalScrollBar->setMaximum(qMax(0, getScreenPointFromFrame(panel_timeline->zoom, sequence->getEndFrame()) + 100 - ui->editAreas->width())); + + if (last_frame != sequence->playhead) { + panel_viewer->viewer_widget->update(); + ui->audio_monitor->update(); + last_frame = sequence->playhead; + } + + if (zoomChanged) { + zoomChanged = false; + int target_scroll = getScreenPointFromFrame(zoom, sequence->playhead)-(ui->editAreas->width()>>1); + // TODO find a way to gradually move towards target_scroll instead of just setting it? + ui->horizontalScrollBar->setValue(target_scroll); + } + + panel_viewer->update_playhead_timecode(sequence->playhead); + } } void Timeline::select_all() { @@ -337,7 +332,7 @@ void Timeline::select_all() { sequence->selections.append(s); } } - repaint_timeline(); + repaint_timeline(false); } } @@ -407,7 +402,7 @@ void Timeline::delete_in_out(bool ripple) { if (ripple) ca->append(new RippleCommand(sequence, sequence->workarea_in, sequence->workarea_in - sequence->workarea_out)); ca->append(new SetTimelineInOutCommand(sequence, false, 0, 0)); undo_stack.push(ca); - redraw_all_clips(true); + repaint_timeline(true); } } @@ -467,7 +462,7 @@ void Timeline::delete_selection(bool ripple_delete) { undo_stack.push(ca); - redraw_all_clips(true); + repaint_timeline(true); } } @@ -481,8 +476,9 @@ void Timeline::set_zoom(bool in) { } else { zoom /= 2; } + ui->headers->update_zoom(zoom); zoomChanged = true; - redraw_all_clips(false); + repaint_timeline(false); } void Timeline::decheck_tool_buttons(QObject* sender) { @@ -826,7 +822,7 @@ void Timeline::paste() { undo_stack.push(ca); - redraw_all_clips(true); + repaint_timeline(true); if (config.paste_seeks) { seek(paste_end); @@ -885,7 +881,7 @@ void Timeline::ripple_to_in_point(bool in) { ca->append(new RippleCommand(sequence, in_point, (in) ? (in_point - sequence->playhead) : (sequence->playhead - in_point))); undo_stack.push(ca); - redraw_all_clips(true); + repaint_timeline(true); if (in) seek(in_point); } @@ -1018,7 +1014,7 @@ void Timeline::split_at_playhead() { if (split_selected) { undo_stack.push(ca); - redraw_all_clips(true); + repaint_timeline(true); } else { delete ca; } @@ -1142,7 +1138,7 @@ void Timeline::toggle_links() { } if (command->clips.size() > 0) { undo_stack.push(command); - redraw_all_clips(true); + repaint_timeline(true); } else { delete command; } @@ -1155,7 +1151,7 @@ void Timeline::increase_track_height() { for (int i=0;iselections.clear(); - repaint_timeline(); + repaint_timeline(false); } long getFrameFromScreenPoint(double zoom, int x) { @@ -1188,11 +1184,11 @@ int getScreenPointFromFrame(double zoom, long frame) { } long Timeline::getTimelineFrameFromScreenPoint(int x) { - return getFrameFromScreenPoint(zoom, x); + return getFrameFromScreenPoint(zoom, x + scroll); } int Timeline::getTimelineScreenPointFromFrame(long frame) { - return getScreenPointFromFrame(zoom, frame); + return getScreenPointFromFrame(zoom, frame) - scroll; } void Timeline::on_toolArrowButton_clicked() { @@ -1286,3 +1282,8 @@ void Timeline::addMenuItem(QAction* action) { creating = true; creatingObject = action->data().toInt(); } + +void Timeline::setScroll(int s) { + scroll = s; + repaint_timeline(false); +} diff --git a/panels/timeline.h b/panels/timeline.h index 197093fd0..08637df38 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -99,6 +99,8 @@ public: int getTimelineScreenPointFromFrame(long frame); long getTimelineFrameFromScreenPoint(int x); + int getDisplayScreenPointFromFrame(long frame); + long getDisplayFrameFromScreenPoint(int x); int get_snap_range(); bool snap_to_point(long point, long* l); @@ -128,7 +130,6 @@ public: double zoom; long drag_frame_start; int drag_track_start; - void redraw_all_clips(bool changed); void update_effect_controls(); QVector video_track_heights; @@ -185,7 +186,7 @@ public: Ui::Timeline *ui; public slots: - void repaint_timeline(); + void repaint_timeline(bool changed = false); private slots: @@ -213,6 +214,8 @@ private slots: void addMenuItem(QAction*); + void setScroll(int); + private: QVector tool_buttons; void decheck_tool_buttons(QObject* sender); @@ -220,6 +223,7 @@ private: long last_frame; QVector clip_clipboard; bool queue_audio_reset; + int scroll; int default_track_height; }; diff --git a/panels/timeline.ui b/panels/timeline.ui index 23da16569..bc7311dab 100644 --- a/panels/timeline.ui +++ b/panels/timeline.ui @@ -285,7 +285,7 @@ 0 - + 0 @@ -328,6 +328,14 @@ true + + + 0 + 0 + 821 + 16 + + 0 @@ -368,124 +376,149 @@ - - - - 0 - 1 - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 0 + 0 + 807 + 217 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::ClickFocus + + + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 807 + 270 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::ClickFocus + + + + + + + + + + + + + + + 2 + + + 20 + + + 1826 - Qt::Vertical + Qt::Horizontal - - false - - - false - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - true - - - Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft - - - - - 0 - 0 - 817 - 174 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::ClickFocus - - - - - - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOn - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 817 - 339 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::ClickFocus - - - - - - diff --git a/ui/timelineheader.cpp b/ui/timelineheader.cpp index b3434426c..25f64bdf5 100644 --- a/ui/timelineheader.cpp +++ b/ui/timelineheader.cpp @@ -16,6 +16,7 @@ #define CLICK_RANGE 5 #define PLAYHEAD_SIZE 6 #define LINE_MIN_PADDING 50 +#define SUBLINE_MIN_PADDING 50 // TODO play with this #define MARKER_SIZE 4 TimelineHeader::TimelineHeader(QWidget *parent) : @@ -26,19 +27,25 @@ TimelineHeader::TimelineHeader(QWidget *parent) : in_visible(0), snapping(true), fm(font()), - dragging_markers(false) + dragging_markers(false), + scroll(0) { setCursor(Qt::ArrowCursor); setMouseTracking(true); - setMinimumHeight(fm.height()*2); + setMinimumHeight(fm.height()*2); +} + +void TimelineHeader::set_scroll(int s) { + scroll = s; + update(); } long TimelineHeader::getHeaderFrameFromScreenPoint(int x) { - return getFrameFromScreenPoint(zoom, x) + in_visible; + return getFrameFromScreenPoint(zoom, x + scroll) + in_visible; } int TimelineHeader::getHeaderScreenPointFromFrame(long frame) { - return getScreenPointFromFrame(zoom, frame - in_visible); + return getScreenPointFromFrame(zoom, frame - in_visible) - scroll; } void TimelineHeader::set_playhead(int mouse_x) { @@ -61,7 +68,7 @@ void TimelineHeader::set_in_point(long new_in) { } undo_stack.push(new SetTimelineInOutCommand(sequence, true, new_in, new_out)); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } void TimelineHeader::set_out_point(long new_out) { @@ -72,7 +79,7 @@ void TimelineHeader::set_out_point(long new_out) { new_in = 0; } undo_stack.push(new SetTimelineInOutCommand(sequence, true, new_in, new_out)); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } void TimelineHeader::mousePressEvent(QMouseEvent* event) { @@ -135,7 +142,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { temp_workarea_out = qMin(qMax(temp_workarea_in+1, frame), sequence_end); } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else if (dragging_markers) { long frame_movement = getHeaderFrameFromScreenPoint(event->pos().x()) - getHeaderFrameFromScreenPoint(drag_start); @@ -162,7 +169,7 @@ void TimelineHeader::mouseMoveEvent(QMouseEvent* event) { sequence->markers[selected_markers.at(i)].frame = selected_marker_original_times.at(i) + frame_movement; } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else { set_playhead(event->pos().x()); } @@ -212,7 +219,7 @@ void TimelineHeader::mouseReleaseEvent(QMouseEvent*) { dragging = false; dragging_markers = false; panel_timeline->snapped = false; - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } void TimelineHeader::focusOutEvent(QFocusEvent*) { @@ -220,7 +227,7 @@ void TimelineHeader::focusOutEvent(QFocusEvent*) { update(); } -void TimelineHeader::update_header(double z) { +void TimelineHeader::update_zoom(double z) { zoom = z; update(); } @@ -232,7 +239,7 @@ void TimelineHeader::delete_markers() { dma->markers.append(selected_markers.at(i)); } undo_stack.push(dma); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } @@ -243,15 +250,15 @@ void TimelineHeader::paintEvent(QPaintEvent*) { double interval = sequence->frame_rate; int textWidth = 0; - int lastTextBoundary = 0; + int lastTextBoundary = INT_MIN; int i = 0; - int lastLineX = -LINE_MIN_PADDING-1; + int lastLineX = INT_MIN; int sublineCount = 1; int sublineTest = qRound(interval*zoom); int sublineInterval = 1; - while (sublineTest > LINE_MIN_PADDING + while (sublineTest > SUBLINE_MIN_PADDING && sublineInterval >= 1) { sublineCount *= 2; sublineInterval = (interval/sublineCount); @@ -261,30 +268,35 @@ void TimelineHeader::paintEvent(QPaintEvent*) { while (true) { long frame = qRound(interval*i); - int lineX = qRound(frame*zoom); + int lineX = qRound(frame*zoom) - scroll; + int next_lineX = qRound(qRound(interval*(i+1))*zoom) - scroll; + if (lineX > width()) break; - if (lineX > lastLineX+LINE_MIN_PADDING) { - // draw text - if (lineX-textWidth > lastTextBoundary) { - p.setPen(Qt::white); + if (next_lineX > 0 && lineX > lastLineX+LINE_MIN_PADDING) { + // draw text + if (lineX-textWidth > lastTextBoundary) { + p.setPen(Qt::white); QString timecode = frame_to_timecode(frame + in_visible, config.timecode_view, sequence->frame_rate); - textWidth = fm.width(timecode)>>1; - lastTextBoundary = lineX+textWidth; - p.drawText(QRect(lineX-textWidth, 0, lastTextBoundary, yoff), timecode); - } + textWidth = fm.width(timecode)>>1; + if (lineX + textWidth > 0) { + int text_x = qMax(lineX-textWidth, 0); + lastTextBoundary = text_x+textWidth+textWidth; + p.drawText(QRect(text_x, 0, lastTextBoundary, yoff), timecode); + } + } - // draw line markers - p.setPen(Qt::gray); - p.drawLine(lineX, yoff, lineX, height()); + // draw line markers + p.setPen(Qt::gray); + p.drawLine(lineX, yoff, lineX, height()); - lastLineX = lineX; + lastLineX = lineX; - // draw sub-line markers - for (int j=1;j>1)); - } - } + // draw sub-line markers + for (int j=1;j>1)); + } + } i++; } diff --git a/ui/timelineheader.h b/ui/timelineheader.h index 2f4d8cdb6..978630d3c 100644 --- a/ui/timelineheader.h +++ b/ui/timelineheader.h @@ -15,10 +15,14 @@ public: bool snapping; - void update_header(double z); + void update_zoom(double z); void delete_markers(); +public slots: + void set_scroll(int); + void set_visible_in(long i); + protected: void paintEvent(QPaintEvent*); void mousePressEvent(QMouseEvent*); @@ -51,10 +55,9 @@ private: long getHeaderFrameFromScreenPoint(int x); int getHeaderScreenPointFromFrame(long frame); -signals: + int scroll; -public slots: - void set_visible_in(long i); +signals: }; #endif // TIMELINEHEADER_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 6913f7f42..b00353f7e 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -71,7 +71,7 @@ void TimelineWidget::right_click_ripple() { if (can_ripple) { undo_stack.push(new RippleCommand(sequence, rc_ripple_min, rc_ripple_min - rc_ripple_max)); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } } @@ -166,10 +166,6 @@ bool same_sign(int a, int b) { return (a < 0) == (b < 0); } -void TimelineWidget::resizeEvent(QResizeEvent*) { - if (sequence != NULL) redraw_clips(); -} - void TimelineWidget::dragEnterEvent(QDragEnterEvent *event) { if (event->source() == panel_project->source_table) { event->accept(); @@ -337,7 +333,7 @@ void TimelineWidget::dragMoveEvent(QDragMoveEvent *event) { if (sequence != NULL && panel_timeline->importing) { QPoint pos = event->pos(); update_ghosts(pos); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } @@ -345,7 +341,7 @@ void TimelineWidget::dragLeaveEvent(QDragLeaveEvent*) { if (sequence != NULL && panel_timeline->importing) { panel_timeline->ghosts.clear(); panel_timeline->importing = false; - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } @@ -452,7 +448,6 @@ void TimelineWidget::dropEvent(QDropEvent* event) { } } - panel_timeline->ghosts.clear(); panel_timeline->importing = false; panel_timeline->snapped = false; @@ -461,7 +456,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { setFocus(); - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } } @@ -476,7 +471,7 @@ void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *event) { s.out = clip->timeline_out; s.track = clip->track; sequence->selections.append(s); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } } @@ -639,7 +634,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { panel_timeline->rect_select_init = true; } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } break; @@ -651,7 +646,7 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { { panel_timeline->splitting = true; panel_timeline->split_tracks.append(panel_timeline->drag_track_start); - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } break; } @@ -958,10 +953,10 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { post_clips.clear(); if (redraw) { - panel_timeline->redraw_all_clips(true); + panel_timeline->repaint_timeline(true); } else { if (repaint) { - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } panel_timeline->update_effect_controls(); } @@ -1284,7 +1279,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { if (config.edit_tool_also_seeks) { panel_timeline->seek(qMin(panel_timeline->drag_frame_start, panel_timeline->cursor_frame)); } else { - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } } else if (panel_timeline->moving_init) { if (track_resizing) { @@ -1297,7 +1292,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } if (new_height < TRACK_MIN_HEIGHT) new_height = TRACK_MIN_HEIGHT; panel_timeline->calculate_track_height(track_target, new_height); - redraw_clips(); + update(); } else if (panel_timeline->moving_proc) { QPoint pos = event->pos(); update_ghosts(pos); @@ -1481,7 +1476,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { panel_timeline->moving_proc = true; } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else if (panel_timeline->splitting) { int track_start = qMin(panel_timeline->cursor_track, panel_timeline->drag_track_start); int track_end = qMax(panel_timeline->cursor_track, panel_timeline->drag_track_start); @@ -1505,7 +1500,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } } } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else if (panel_timeline->rect_select_init) { if (panel_timeline->rect_select_proc) { panel_timeline->rect_select_w = event->pos().x() - panel_timeline->rect_select_x; @@ -1567,7 +1562,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { s.old_track = s.track = clip->track; } - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else { panel_timeline->rect_select_x = event->pos().x(); panel_timeline->rect_select_y = event->pos().y(); @@ -1578,7 +1573,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { } } else if (isLiveEditing()) { // redraw because we have a cursor - panel_timeline->repaint_timeline(); + panel_timeline->repaint_timeline(false); } else if (panel_timeline->tool == TIMELINE_TOOL_POINTER || panel_timeline->tool == TIMELINE_TOOL_RIPPLE || panel_timeline->tool == TIMELINE_TOOL_ROLLING) { @@ -1704,22 +1699,22 @@ int color_brightness(int r, int g, int b) { return (0.2126*r + 0.7152*g + 0.0722*b); } -void TimelineWidget::redraw_clips() { - // Draw clips - if (sequence != NULL) { +void TimelineWidget::paintEvent(QPaintEvent*) { + // Draw clips + if (sequence != NULL) { + QPainter p(this); + // get widget width and height int video_track_limit = 0; int audio_track_limit = 0; - long end_frame = 0; - for (int i=0;iclips.size();i++) { - Clip* clip = sequence->clips.at(i); + for (int i=0;iclips.size();i++) { + Clip* clip = sequence->clips.at(i); if (clip != NULL) { - end_frame = qMax(end_frame, clip->timeline_out); video_track_limit = qMin(video_track_limit, clip->track); audio_track_limit = qMax(audio_track_limit, clip->track); } } - int panel_width = panel_timeline->getTimelineScreenPointFromFrame(end_frame) + 100; + int panel_height = 100; if (bottom_align) { for (int i=-1;i>=video_track_limit;i--) { @@ -1731,227 +1726,219 @@ void TimelineWidget::redraw_clips() { } } - if (minimumWidth() != panel_width || clip_pixmap.height() != height() || panel_height != minimumHeight()) { - panel_timeline->ui->headers->setMinimumWidth(panel_width + 100); - setMinimumWidth(panel_width); - int scrollOffset = (panel_height-minimumHeight()); - setMinimumHeight(panel_height); - if (bottom_align) { - updateGeometry(); - container->verticalScrollBar()->setValue(container->verticalScrollBar()->value()+scrollOffset); - } - clip_pixmap = QPixmap(qMax(width(), panel_width), qMax(height(), panel_height)); - } - - clip_pixmap.fill(Qt::transparent); - QPainter clip_painter(&clip_pixmap); - - QColor transition_color(255, 0, 0, 16); - for (int i=0;iclips.size();i++) { - Clip* clip = sequence->clips.at(i); + QColor transition_color(255, 0, 0, 16); + for (int i=0;iclips.size();i++) { + Clip* clip = sequence->clips.at(i); if (clip != NULL && is_track_visible(clip->track)) { QRect clip_rect(panel_timeline->getTimelineScreenPointFromFrame(clip->timeline_in), getScreenPointFromTrack(clip->track), clip->getLength() * panel_timeline->zoom, panel_timeline->calculate_track_height(clip->track, -1)); - clip_painter.fillRect(clip_rect, QColor(clip->color_r, clip->color_g, clip->color_b)); + QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - 1, clip_rect.height() - CLIP_TEXT_PADDING - 1); + if (clip_rect.left() < width() && clip_rect.right() >= 0) { + QRect actual_clip_rect = clip_rect; + if (actual_clip_rect.x() < 0) actual_clip_rect.setX(0); + if (actual_clip_rect.right() >= width()) actual_clip_rect.setRight(width()); + p.fillRect(actual_clip_rect, QColor(clip->color_r, clip->color_g, clip->color_b)); - int thumb_x = clip_rect.x() + 1; + int thumb_x = clip_rect.x() + 1; - QRect text_rect(clip_rect.left() + CLIP_TEXT_PADDING, clip_rect.top() + CLIP_TEXT_PADDING, clip_rect.width() - CLIP_TEXT_PADDING - 1, clip_rect.height() - CLIP_TEXT_PADDING - 1); + if (clip->media_type == MEDIA_TYPE_FOOTAGE) { + bool draw_checkerboard = false; + QRect checkerboard_rect(clip_rect); + Media* m = static_cast(clip->media); + MediaStream* ms = m->get_stream_from_file_index(clip->track < 0, clip->media_stream); + if (ms == NULL) { + draw_checkerboard = true; + } else if (ms->preview_done) { + // draw thumbnail/waveform + long media_length = clip->getMaximumLength(); - if (clip->media_type == MEDIA_TYPE_FOOTAGE) { - bool draw_checkerboard = false; - QRect checkerboard_rect(clip_rect); - Media* m = static_cast(clip->media); - MediaStream* ms = m->get_stream_from_file_index(clip->track < 0, clip->media_stream); - if (ms == NULL) { - draw_checkerboard = true; - } else if (ms->preview_done) { - // draw thumbnail/waveform - long media_length = clip->getMaximumLength(); - - if (clip->track < 0) { - // draw thumbnail - int space_for_thumb = clip_rect.width(); - if (clip->opening_transition != NULL) { - int ot_width = panel_timeline->getTimelineScreenPointFromFrame(clip->opening_transition->length); - thumb_x += ot_width; - space_for_thumb -= ot_width; - } - if (clip->closing_transition != NULL) { - space_for_thumb -= panel_timeline->getTimelineScreenPointFromFrame(clip->closing_transition->length); - } - int thumb_y = clip_painter.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; - int thumb_height = clip_rect.height()-thumb_y; - int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height())); - if (thumb_height > thumb_y && text_rect.width() + CLIP_TEXT_PADDING > thumb_width && space_for_thumb >= thumb_width) { // at small clip heights, don't even draw it - QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height); - clip_painter.drawImage(thumb_rect, ms->video_preview); - } - } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { - int waveform_limit = qMin(clip_rect.width(), panel_timeline->getTimelineScreenPointFromFrame(media_length - clip->clip_in)); - - if (waveform_limit < clip_rect.width()) { - draw_checkerboard = true; - if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); - } - - // draw waveform - clip_painter.setPen(QColor(80, 80, 80)); - - int divider = ms->audio_channels*2; - int channel_height = clip_rect.height()/ms->audio_channels; - - for (int i=0;iclip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider; - - if (clip->reverse) { - waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2); - } - - int rectified_height = 0; - - for (int j=0;jaudio_channels;j++) { - int mid = clip_rect.top()+channel_height*j+(channel_height/2); - int offset = waveform_index+(j*2); - - if ((offset + 1) < ms->audio_preview.size()) { - qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2); - qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2); - - if (config.rectified_waveforms) { - rectified_height += (max - min); - } else { - clip_painter.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); - } - } else { - qDebug() << "[WARNING] Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size(); + if (clip->track < 0) { + // draw thumbnail + if (thumb_x < width()) { + int space_for_thumb = clip_rect.width(); + if (clip->opening_transition != NULL) { + int ot_width = getScreenPointFromFrame(panel_timeline->zoom, clip->opening_transition->length); + thumb_x += ot_width; + space_for_thumb -= ot_width; + } + if (clip->closing_transition != NULL) { + space_for_thumb -= getScreenPointFromFrame(panel_timeline->zoom, clip->closing_transition->length); + } + int thumb_y = p.fontMetrics().height()+CLIP_TEXT_PADDING+CLIP_TEXT_PADDING; + int thumb_height = clip_rect.height()-thumb_y; + int thumb_width = (thumb_height*((double)ms->video_preview.width()/(double)ms->video_preview.height())); + if (thumb_x + thumb_width >= 0 + && thumb_height > thumb_y + && text_rect.width() + CLIP_TEXT_PADDING > thumb_width + && space_for_thumb >= thumb_width) { // at small clip heights, don't even draw it + QRect thumb_rect(thumb_x, clip_rect.y()+thumb_y, thumb_width, thumb_height); + p.drawImage(thumb_rect, ms->video_preview); } } + } else if (clip_rect.height() > TRACK_MIN_HEIGHT) { + int waveform_start = -qMin(clip_rect.x(), 0); + int waveform_limit = qMin(clip_rect.width(), getScreenPointFromFrame(panel_timeline->zoom, media_length - clip->clip_in)); - if (config.rectified_waveforms) { - clip_painter.drawLine(clip_rect.left()+i, clip_rect.height(), clip_rect.left()+i, clip_rect.height() - rectified_height); + if ((clip_rect.x() + waveform_limit) > width()) { + waveform_limit -= (clip_rect.x() + waveform_limit - width()); + } else if (waveform_limit < clip_rect.width()) { + draw_checkerboard = true; + if (waveform_limit > 0) checkerboard_rect.setLeft(checkerboard_rect.left() + waveform_limit); + } + + // draw waveform + p.setPen(QColor(80, 80, 80)); + + int divider = ms->audio_channels*2; + int channel_height = clip_rect.height()/ms->audio_channels; + + for (int i=waveform_start;iclip_in + ((double) i/panel_timeline->zoom))/media_length) * ms->audio_preview.size())/divider)*divider; + + if (clip->reverse) { + waveform_index = ms->audio_preview.size() - waveform_index - (ms->audio_channels * 2); + } + + int rectified_height = 0; + + for (int j=0;jaudio_channels;j++) { + int mid = clip_rect.top()+channel_height*j+(channel_height/2); + int offset = waveform_index+(j*2); + + if ((offset + 1) < ms->audio_preview.size()) { + qint8 min = (double)ms->audio_preview.at(offset) / 128.0 * (channel_height/2); + qint8 max = (double)ms->audio_preview.at(offset+1) / 128.0 * (channel_height/2); + + if (config.rectified_waveforms) { + rectified_height += (max - min); + } else { + p.drawLine(clip_rect.left()+i, mid+min, clip_rect.left()+i, mid+max); + } + } else { + qDebug() << "[WARNING] Tried to reach" << offset + 1 << ", limit:" << ms->audio_preview.size(); + } + } + + if (config.rectified_waveforms) { + p.drawLine(clip_rect.left()+i, clip_rect.height(), clip_rect.left()+i, clip_rect.height() - rectified_height); + } } } - } - } - if (draw_checkerboard) { - // draw "error lines" if media stream is missing - clip_painter.setPen(QPen(QColor(64, 64, 64), 2)); - int limit = checkerboard_rect.width(); - int clip_height = checkerboard_rect.height(); - for (int j=-clip_height;j= 0) { + // draw "error lines" if media stream is missing + p.setPen(QPen(QColor(64, 64, 64), 2)); + int limit = checkerboard_rect.width(); + int clip_height = checkerboard_rect.height(); + for (int j=-clip_height;j checkerboard_rect.right()) { + lines_end_y -= (checkerboard_rect.right() - lines_end_x); + lines_end_x = checkerboard_rect.right(); + } + p.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); + } } - if (lines_end_x > checkerboard_rect.right()) { - lines_end_y -= (checkerboard_rect.right() - lines_end_x); - lines_end_x = checkerboard_rect.right(); - } - clip_painter.drawLine(lines_start_x, lines_start_y, lines_end_x, lines_end_y); } } - } - // draw clip transitions - for (int i=0;i<2;i++) { - Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition; - if (t != NULL) { - int transition_width = panel_timeline->getTimelineScreenPointFromFrame(t->length); - int transition_height = clip_rect.height(); - int tr_y = clip_rect.y(); - int tr_x = 0; - if (i == 0) { - tr_x = clip_rect.x(); - text_rect.setX(text_rect.x()+transition_width); - } else { - tr_x = clip_rect.right()-transition_width; - text_rect.setWidth(text_rect.width()-transition_width); - } - QRect transition_rect = QRect(tr_x, tr_y, transition_width, transition_height); - clip_painter.fillRect(transition_rect, transition_color); - QRect transition_text_rect(transition_rect.x() + CLIP_TEXT_PADDING, transition_rect.y() + CLIP_TEXT_PADDING, transition_rect.width() - CLIP_TEXT_PADDING, transition_rect.height() - CLIP_TEXT_PADDING); - if (transition_text_rect.width() > MAX_TEXT_WIDTH) { - clip_painter.setPen(QColor(0, 0, 0, 96)); + // draw clip transitions + for (int i=0;i<2;i++) { + Transition* t = (i == 0) ? clip->opening_transition : clip->closing_transition; + if (t != NULL) { + int transition_width = panel_timeline->getTimelineScreenPointFromFrame(t->length); + int transition_height = clip_rect.height(); + int tr_y = clip_rect.y(); + int tr_x = 0; if (i == 0) { - clip_painter.drawLine(transition_rect.bottomLeft(), transition_rect.topRight()); + tr_x = clip_rect.x(); + text_rect.setX(text_rect.x()+transition_width); } else { - clip_painter.drawLine(transition_rect.topLeft(), transition_rect.bottomRight()); + tr_x = clip_rect.right()-transition_width; + text_rect.setWidth(text_rect.width()-transition_width); } + QRect transition_rect = QRect(tr_x, tr_y, transition_width, transition_height); + p.fillRect(transition_rect, transition_color); + QRect transition_text_rect(transition_rect.x() + CLIP_TEXT_PADDING, transition_rect.y() + CLIP_TEXT_PADDING, transition_rect.width() - CLIP_TEXT_PADDING, transition_rect.height() - CLIP_TEXT_PADDING); + if (transition_text_rect.width() > MAX_TEXT_WIDTH) { + p.setPen(QColor(0, 0, 0, 96)); + if (i == 0) { + p.drawLine(transition_rect.bottomLeft(), transition_rect.topRight()); + } else { + p.drawLine(transition_rect.topLeft(), transition_rect.bottomRight()); + } - clip_painter.setPen(Qt::white); - clip_painter.drawText(transition_text_rect, 0, t->name, &transition_text_rect); + p.setPen(Qt::white); + p.drawText(transition_text_rect, 0, t->name, &transition_text_rect); + } + p.setPen(Qt::black); + p.drawRect(transition_rect); } - clip_painter.setPen(Qt::black); - clip_painter.drawRect(transition_rect); } + + // top left bevel + p.setPen(Qt::white); + if (clip_rect.x() >= 0) p.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft()); + p.drawLine(QPoint(qMax(0, clip_rect.left()), qMax(0, clip_rect.top())), QPoint(qMin(width(), clip_rect.right()), qMax(0, clip_rect.top()))); + + // draw text + if (text_rect.width() > MAX_TEXT_WIDTH && text_rect.right() > 0 && text_rect.left() < width()) { + if (color_brightness(clip->color_r, clip->color_g, clip->color_b) > 160) { + // set to black if color is bright + p.setPen(Qt::black); + } + if (clip->linked.size() > 0) { + int underline_y = CLIP_TEXT_PADDING + p.fontMetrics().height() + clip_rect.top(); + int underline_width = qMin(text_rect.width() - 1, p.fontMetrics().width(clip->name)); + p.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); + } + QString name = clip->name; + if (clip->speed != 1.0 || clip->reverse) { + name += " ("; + if (clip->reverse) name += "-"; + name += QString::number(clip->speed*100) + "%)"; + } + p.drawText(text_rect, 0, name, &text_rect); + } + + // bottom right gray + p.setPen(QColor(0, 0, 0, 128)); + if (clip_rect.right() < width()) p.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); + p.drawLine(QPoint(qMax(0, clip_rect.left()), qMin(height(), clip_rect.bottom())), QPoint(qMin(width(), clip_rect.right()), qMin(height(), clip_rect.bottom()))); } + } + } - // top left bevel - clip_painter.setPen(Qt::white); - clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.topLeft()); - clip_painter.drawLine(clip_rect.topLeft(), clip_rect.topRight()); + // Draw track lines + if (config.show_track_lines) { + p.setPen(QColor(0, 0, 0, 96)); + audio_track_limit++; + if (video_track_limit == 0) video_track_limit--; - // draw text - if (text_rect.width() > MAX_TEXT_WIDTH) { - if (color_brightness(clip->color_r, clip->color_g, clip->color_b) > 160) { - // set to black if color is bright - clip_painter.setPen(Qt::black); - } - if (clip->linked.size() > 0) { - int underline_y = CLIP_TEXT_PADDING + clip_painter.fontMetrics().height() + clip_rect.top(); - int underline_width = qMin(text_rect.width() - 1, clip_painter.fontMetrics().width(clip->name)); - clip_painter.drawLine(text_rect.x(), underline_y, text_rect.x() + underline_width, underline_y); - } - QString name = clip->name; - if (clip->speed != 1.0 || clip->reverse) { - name += " ("; - if (clip->reverse) name += "-"; - name += QString::number(clip->speed*100) + "%)"; - } - clip_painter.drawText(text_rect, 0, name, &text_rect); - } - - // bottom right gray - clip_painter.setPen(QColor(0, 0, 0, 128)); - clip_painter.drawLine(clip_rect.bottomLeft(), clip_rect.bottomRight()); - clip_painter.drawLine(clip_rect.bottomRight(), clip_rect.topRight()); - } - } - - // Draw track lines - if (config.show_track_lines) { - clip_painter.setPen(QColor(0, 0, 0, 96)); - audio_track_limit++; - if (video_track_limit == 0) video_track_limit--; - - if (bottom_align) { - // only draw lines for video tracks - for (int i=video_track_limit;i<0;i++) { - int line_y = getScreenPointFromTrack(i) - 1; - clip_painter.drawLine(0, line_y, rect().width(), line_y); - } - } else { - // only draw lines for audio tracks + if (bottom_align) { + // only draw lines for video tracks + for (int i=video_track_limit;i<0;i++) { + int line_y = getScreenPointFromTrack(i) - 1; + p.drawLine(0, line_y, rect().width(), line_y); + } + } else { + // only draw lines for audio tracks for (int i=0;icalculate_track_height(i, -1); - clip_painter.drawLine(0, line_y, rect().width(), line_y); - } - } - } - } - - update(); -} - -void TimelineWidget::paintEvent(QPaintEvent*) { - if (sequence != NULL) { - QPainter p(this); - - p.drawPixmap(0, 0, clip_pixmap.width(), height(), clip_pixmap); + p.drawLine(0, line_y, rect().width(), line_y); + } + } + } // Draw selections for (int i=0;iselections.size();i++) { @@ -1980,7 +1967,7 @@ void TimelineWidget::paintEvent(QPaintEvent*) { if (is_track_visible(g.track)) { int ghost_x = panel_timeline->getTimelineScreenPointFromFrame(g.in); int ghost_y = getScreenPointFromTrack(g.track); - int ghost_width = panel_timeline->getTimelineScreenPointFromFrame(g.out - g.in) - 1; + int ghost_width = panel_timeline->getTimelineScreenPointFromFrame(g.out) - ghost_x - 1; int ghost_height = panel_timeline->calculate_track_height(g.track, -1) - 1; p.setPen(QColor(255, 255, 0)); for (int j=0;jcalculate_track_height(panel_timeline->cursor_track, -1)); } - } + } } } diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index b047ce20f..108978ca3 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -25,12 +25,9 @@ public: bool bottom_align; - void redraw_clips(); - QScrollArea* container; protected: - void paintEvent(QPaintEvent*); - void resizeEvent(QResizeEvent*); + void paintEvent(QPaintEvent*); void mouseDoubleClickEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); @@ -55,9 +52,7 @@ private: int track_target; QVector pre_clips; - QVector post_clips; - - QPixmap clip_pixmap; + QVector post_clips; int predicted_video_width; int predicted_video_height;