From 9f89f57090200e09f7f42462915b46596771b754 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 7 Apr 2020 02:34:59 +1000 Subject: [PATCH 1/4] track: when length changes, force the new area to invalidate The track limits cache invalidation signals to the length of the track. On some platforms, if a block length was changed to the point that it changed the track length, the track length would change AFTER the cache invalidation and therefore never end up getting rendered. This commit ensures that when a track's length changes, the new section is invalidated regardless of ordering. --- app/node/output/track/track.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 7b432013c..32fc313c0 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -450,8 +450,13 @@ void TrackOutput::UpdateInOutFrom(int index) // Update track length if (new_track_length != track_length_) { + rational old_track_length = track_length_; + track_length_ = new_track_length; emit TrackLengthChanged(); + + InvalidateCache(qMin(old_track_length, new_track_length), + qMax(old_track_length, new_track_length)); } } From cf04cad23810cabba46d38fcde004a7df4f5e181 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 7 Apr 2020 03:07:43 +1000 Subject: [PATCH 2/4] mainwindow/timelinepanel: closing a timeline will close a sequence entirely UI detail. --- app/panel/panelmanager.cpp | 11 ++++++ app/panel/panelmanager.h | 9 +++++ app/panel/timebased/timebased.cpp | 9 +++-- app/panel/timeline/timeline.cpp | 18 +++++++++- app/panel/timeline/timeline.h | 9 +++++ app/window/mainwindow/mainwindow.cpp | 51 +++++++++++++++++++--------- app/window/mainwindow/mainwindow.h | 6 +++- 7 files changed, 92 insertions(+), 21 deletions(-) diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index 224f629ba..a76d65093 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -150,4 +150,15 @@ void PanelManager::SetPanelsLocked(bool locked) locked_ = locked; } +void PanelManager::PanelDestroyed() +{ + PanelWidget* panel = static_cast(sender()); + + focus_history_.removeOne(panel); + + if (last_focused_panel_ == panel) { + last_focused_panel_ = focus_history_.isEmpty() ? nullptr : focus_history_.first(); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/panel/panelmanager.h b/app/panel/panelmanager.h index 8264cb48b..7acba73e3 100644 --- a/app/panel/panelmanager.h +++ b/app/panel/panelmanager.h @@ -162,6 +162,12 @@ private: */ PanelWidget* last_focused_panel_; +private slots: + /** + * @brief Processing if a panel gets deleted + */ + void PanelDestroyed(); + }; template @@ -171,6 +177,9 @@ T *PanelManager::CreatePanel(QWidget *parent) panel->SetMovementLocked(locked_); + // Connect destroy signal so we can remove it from focus history + connect(panel, &PanelWidget::destroyed, this, &PanelManager::PanelDestroyed); + // Add panel to the bottom of the focus history focus_history_.append(panel); diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp index a2e0c7bd8..363e1b924 100644 --- a/app/panel/timebased/timebased.cpp +++ b/app/panel/timebased/timebased.cpp @@ -122,15 +122,16 @@ void TimeBasedPanel::ConnectViewerNode(ViewerOutput *node) { if (widget_->GetConnectedNode()) { disconnect(widget_->GetConnectedNode(), &ViewerOutput::MediaNameChanged, this, &TimeBasedPanel::SetSubtitle); - Retranslate(); } widget_->ConnectViewerNode(node); if (node) { connect(node, &ViewerOutput::MediaNameChanged, this, &TimeBasedPanel::SetSubtitle); - SetSubtitle(node->media_name()); } + + // Update strings + Retranslate(); } void TimeBasedPanel::SetTimeBasedWidget(TimeBasedWidget *widget) @@ -152,7 +153,9 @@ void TimeBasedPanel::SetTimeBasedWidget(TimeBasedWidget *widget) void TimeBasedPanel::Retranslate() { - if (!GetTimeBasedWidget()->GetConnectedNode()) { + if (GetTimeBasedWidget()->GetConnectedNode()) { + SetSubtitle(GetTimeBasedWidget()->GetConnectedNode()->media_name()); + } else { SetSubtitle(tr("(none)")); } } diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index 52b859434..8e4c00159 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -26,7 +26,8 @@ OLIVE_NAMESPACE_ENTER TimelinePanel::TimelinePanel(QWidget *parent) : - TimeBasedPanel(parent) + TimeBasedPanel(parent), + signal_instead_of_close_(false) { // FIXME: This won't work if there's ever more than one of this panel setObjectName("TimelinePanel"); @@ -152,6 +153,11 @@ void TimelinePanel::OverwriteFootageAtPlayhead(const QList &footage) static_cast(GetTimeBasedWidget())->OverwriteFootageAtPlayhead(footage); } +void TimelinePanel::SetSignalInsteadOfClose(bool e) +{ + signal_instead_of_close_ = e; +} + void TimelinePanel::Retranslate() { TimeBasedPanel::Retranslate(); @@ -159,4 +165,14 @@ void TimelinePanel::Retranslate() SetTitle(tr("Timeline")); } +void TimelinePanel::closeEvent(QCloseEvent *event) +{ + if (signal_instead_of_close_) { + event->ignore(); + emit CloseRequested(); + } else { + PanelWidget::closeEvent(event); + } +} + OLIVE_NAMESPACE_EXIT diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index 70641c2c2..391a1279d 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -77,12 +77,21 @@ public: void OverwriteFootageAtPlayhead(const QList &footage); + void SetSignalInsteadOfClose(bool e); + protected: virtual void Retranslate() override; + virtual void closeEvent(QCloseEvent* event) override; + signals: void SelectionChanged(const QList& selected_blocks); + void CloseRequested(); + +private: + bool signal_instead_of_close_; + }; OLIVE_NAMESPACE_EXIT diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 4d118687b..489ef9a67 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -144,22 +144,18 @@ void MainWindow::OpenSequence(Sequence *sequence) panel->ConnectViewerNode(sequence->viewer_output()); - TimelineFocused(panel); + TimelineFocused(sequence->viewer_output()); } void MainWindow::CloseSequence(Sequence *sequence) { - for (int i=0;i copy = timeline_panels_; - if (tl->GetConnectedViewer() == sequence->viewer_output()) { - tl->ConnectViewerNode(nullptr); - - if (timeline_panels_.size() > 1) { - delete tl; - timeline_panels_.removeAt(i); - i--; - } + foreach (TimelinePanel* tp, copy) { + if (tp->GetConnectedViewer() == sequence->viewer_output()) { + RemoveTimelinePanel(tp); } } } @@ -305,6 +301,11 @@ void MainWindow::UpdateTitle() } } +void MainWindow::TimelineCloseRequested() +{ + RemoveTimelinePanel(static_cast(sender())); +} + TimelinePanel* MainWindow::AppendTimelinePanel() { TimelinePanel* panel = PanelManager::instance()->CreatePanel(this);; @@ -321,6 +322,10 @@ TimelinePanel* MainWindow::AppendTimelinePanel() timeline_panels_.append(panel); + // Let us handle the panel closing rather than the panel itself + panel->SetSignalInsteadOfClose(true); + connect(panel, &TimelinePanel::CloseRequested, this, &MainWindow::TimelineCloseRequested); + connect(panel, &TimelinePanel::TimeChanged, param_panel_, &ParamPanel::SetTime); connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); @@ -336,14 +341,28 @@ TimelinePanel* MainWindow::AppendTimelinePanel() return panel; } -void MainWindow::TimelineFocused(TimelinePanel* panel) +void MainWindow::RemoveTimelinePanel(TimelinePanel *panel) { - sequence_viewer_panel_->ConnectViewerNode(panel->GetConnectedViewer()); + // Stop showing this timeline in the viewer + TimelineFocused(nullptr); + + if (timeline_panels_.size() == 1) { + // Leave our single remaining timeline panel open + panel->ConnectViewerNode(nullptr); + } else { + timeline_panels_.removeOne(panel); + panel->deleteLater(); + } +} + +void MainWindow::TimelineFocused(ViewerOutput* viewer) +{ + sequence_viewer_panel_->ConnectViewerNode(viewer); Sequence* seq = nullptr; - if (panel->GetConnectedViewer()) { - seq = static_cast(panel->GetConnectedViewer()->parent()); + if (viewer) { + seq = static_cast(viewer->parent()); } node_panel_->SetGraph(seq); @@ -354,7 +373,7 @@ void MainWindow::FocusedPanelChanged(PanelWidget *panel) TimelinePanel* timeline = dynamic_cast(panel); if (timeline) { - TimelineFocused(timeline); + TimelineFocused(timeline->GetConnectedViewer()); } } diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index c3b2e69c9..e2d8ee10e 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -80,7 +80,9 @@ protected: private: TimelinePanel* AppendTimelinePanel(); - void TimelineFocused(TimelinePanel *panel); + void RemoveTimelinePanel(TimelinePanel *panel); + + void TimelineFocused(ViewerOutput *viewer); QByteArray premaximized_state_; @@ -108,6 +110,8 @@ private slots: void UpdateTitle(); + void TimelineCloseRequested(); + }; OLIVE_NAMESPACE_EXIT From 6d6b2b237e57e5ef95ab96523b48ed7e43746ccf Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Tue, 7 Apr 2020 03:11:50 +1000 Subject: [PATCH 3/4] projectexplorer/mainwindow: close sequence if it's open before deleting it --- app/widget/projectexplorer/projectexplorer.cpp | 10 ++++++++++ app/window/mainwindow/mainwindow.cpp | 11 +++++++++++ app/window/mainwindow/mainwindow.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index 5b519396d..286925665 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -32,6 +32,7 @@ #include "dialog/footageproperties/footageproperties.h" #include "dialog/sequence/sequence.h" #include "widget/menu/menu.h" +#include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER @@ -422,6 +423,15 @@ void ProjectExplorer::DeleteSelected() foreach (Item* item, selected) { ItemPtr item_ptr = item->get_shared_ptr(); + // If this is a sequence, close it + if (item_ptr->type() == Item::kSequence) { + Sequence* s = static_cast(item_ptr.get()); + + if (Core::instance()->main_window()->IsSequenceOpen(s)) { + Core::instance()->main_window()->CloseSequence(s); + } + } + new ProjectViewModel::RemoveItemCommand(&model_, item_ptr, command); } diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 489ef9a67..96500c42d 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -160,6 +160,17 @@ void MainWindow::CloseSequence(Sequence *sequence) } } +bool MainWindow::IsSequenceOpen(Sequence *sequence) const +{ + foreach (TimelinePanel* tp, timeline_panels_) { + if (tp->GetConnectedViewer() == sequence->viewer_output()) { + return true; + } + } + + return false; +} + #ifdef Q_OS_WINDOWS void MainWindow::SetTaskbarButtonState(TBPFLAG flags) { diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index e2d8ee10e..716f17a56 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -57,6 +57,8 @@ public: void CloseSequence(Sequence* sequence); + bool IsSequenceOpen(Sequence* sequence) const; + #ifdef Q_OS_WINDOWS void SetTaskbarButtonState(TBPFLAG flags); From 4cb02b676930eca9419b302c370eed9623144723 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 8 Apr 2020 02:03:46 +1000 Subject: [PATCH 4/4] core: set config defaults a second time before loading Works around an issue where media cache directories would be set before the app name is set (which Qt uses to return the local appdata dirs used to set the cache directories). --- app/core.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/core.cpp b/app/core.cpp index c22a6c9c6..37471e1f8 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -116,6 +116,10 @@ void Core::Start() // Set up the index manager for renderers IndexManager::CreateInstance(); + // Reset config (Config sets to default on construction already, but we do it again here as a workaround that fixes + // the fact that some of the config paths set by default rely on the app name having been set (in main()) + Config::Current().SetDefaults(); + // Load application config Config::Load();