diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 0fb7a6ef9..42563c44c 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -192,8 +192,8 @@ void ExportDialog::accept() QMatrix4x4 transform; - int dest_width = video_tab_->width_slider()->GetValue(); - int dest_height = video_tab_->height_slider()->GetValue(); + int dest_width = static_cast(video_tab_->width_slider()->GetValue()); + int dest_height = static_cast(video_tab_->height_slider()->GetValue()); if (video_tab_->scaling_method_combobox()->isEnabled()) { int source_width = viewer_node_->video_params().width(); @@ -444,13 +444,14 @@ QMatrix4x4 ExportDialog::GenerateMatrix(ExportVideoTab::ScalingMethod method, in void ExportDialog::UpdateViewerDimensions() { - preview_viewer_->SetOverrideSize(video_tab_->width_slider()->GetValue(), video_tab_->height_slider()->GetValue()); + preview_viewer_->SetOverrideSize(static_cast(video_tab_->width_slider()->GetValue()), + static_cast(video_tab_->height_slider()->GetValue())); preview_viewer_->SetMatrix(GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()), viewer_node_->video_params().width(), viewer_node_->video_params().height(), - video_tab_->width_slider()->GetValue(), - video_tab_->height_slider()->GetValue())); + static_cast(video_tab_->width_slider()->GetValue()), + static_cast(video_tab_->height_slider()->GetValue()))); } void ExportDialog::ExporterIsDone() diff --git a/app/panel/CMakeLists.txt b/app/panel/CMakeLists.txt index 9358ead66..7ad3390c3 100644 --- a/app/panel/CMakeLists.txt +++ b/app/panel/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(node) add_subdirectory(param) add_subdirectory(project) add_subdirectory(taskmanager) +add_subdirectory(timebased) add_subdirectory(timeline) add_subdirectory(tool) add_subdirectory(viewer) diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index 6e586462a..0c89c00d5 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -1,16 +1,13 @@ #include "curve.h" CurvePanel::CurvePanel(QWidget *parent) : - PanelWidget(parent) + TimeBasedPanel(parent) { // FIXME: This won't work if there's ever more than one of this panel setObjectName("CurvePanel"); // Create main widget and set it - widget_ = new CurveWidget(); - setWidget(widget_); - - connect(widget_, &CurveWidget::TimeChanged, this, &CurvePanel::TimeChanged); + SetTimeBasedWidget(new CurveWidget()); // Set strings Retranslate(); @@ -18,48 +15,24 @@ CurvePanel::CurvePanel(QWidget *parent) : void CurvePanel::SetInput(NodeInput *input) { - widget_->SetInput(input); -} - -void CurvePanel::SetTimebase(const rational &timebase) -{ - widget_->SetTimebase(timebase); -} - -void CurvePanel::SetTime(const int64_t ×tamp) -{ - widget_->SetTime(timestamp); -} - -void CurvePanel::ZoomIn() -{ - widget_->SetScale(widget_->GetScale() * 2); -} - -void CurvePanel::ZoomOut() -{ - widget_->SetScale(widget_->GetScale() * 0.5); + static_cast(GetTimeBasedWidget())->SetInput(input); } void CurvePanel::IncreaseTrackHeight() { - widget_->SetVerticalScale(widget_->GetVerticalScale() * 2); + CurveWidget* c = static_cast(GetTimeBasedWidget()); + c->SetVerticalScale(c->GetVerticalScale() * 2); } void CurvePanel::DecreaseTrackHeight() { - widget_->SetVerticalScale(widget_->GetVerticalScale() * 0.5); -} - -void CurvePanel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - PanelWidget::changeEvent(e); + CurveWidget* c = static_cast(GetTimeBasedWidget()); + c->SetVerticalScale(c->GetVerticalScale() * 0.5); } void CurvePanel::Retranslate() { + TimeBasedPanel::Retranslate(); + SetTitle(tr("Curve Editor")); } diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index 6a0134b14..4c425c0a9 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -1,10 +1,10 @@ #ifndef CURVEPANEL_H #define CURVEPANEL_H +#include "panel/timebased/timebased.h" #include "widget/curvewidget/curvewidget.h" -#include "widget/panel/panel.h" -class CurvePanel : public PanelWidget +class CurvePanel : public TimeBasedPanel { Q_OBJECT public: @@ -13,28 +13,12 @@ public: public slots: void SetInput(NodeInput* input); - void SetTimebase(const rational& timebase); - - void SetTime(const int64_t& timestamp); - - virtual void ZoomIn() override; - - virtual void ZoomOut() override; - virtual void IncreaseTrackHeight() override; virtual void DecreaseTrackHeight() override; -signals: - void TimeChanged(const int64_t& timestamp); - protected: - virtual void changeEvent(QEvent* e) override; - -private: - void Retranslate(); - - CurveWidget* widget_; + virtual void Retranslate() override; }; diff --git a/app/panel/footageviewer/footageviewer.cpp b/app/panel/footageviewer/footageviewer.cpp index a6c165b7e..0e5c443c0 100644 --- a/app/panel/footageviewer/footageviewer.cpp +++ b/app/panel/footageviewer/footageviewer.cpp @@ -28,11 +28,8 @@ FootageViewerPanel::FootageViewerPanel(QWidget *parent) : // FIXME: This won't work if there's ever more than one of this panel setObjectName("FootageViewerPanel"); - // QObject system handles deleting this - viewer_ = new FootageViewerWidget(this); - // Set ViewerWidget as the central widget - setWidget(viewer_); + SetTimeBasedWidget(new FootageViewerWidget()); // Set strings Retranslate(); @@ -40,7 +37,7 @@ FootageViewerPanel::FootageViewerPanel(QWidget *parent) : void FootageViewerPanel::SetFootage(Footage *f) { - static_cast(viewer_)->SetFootage(f); + static_cast(GetTimeBasedWidget())->SetFootage(f); if (f) { SetSubtitle(f->name()); @@ -49,19 +46,9 @@ void FootageViewerPanel::SetFootage(Footage *f) } } -void FootageViewerPanel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - PanelWidget::changeEvent(e); -} - void FootageViewerPanel::Retranslate() { - SetTitle(tr("Footage Viewer")); + ViewerPanelBase::Retranslate(); - if (!static_cast(viewer_)->GetFootage()) { - SetSubtitle(tr("(none)")); - } + SetTitle(tr("Footage Viewer")); } diff --git a/app/panel/footageviewer/footageviewer.h b/app/panel/footageviewer/footageviewer.h index 582c56a41..817837d04 100644 --- a/app/panel/footageviewer/footageviewer.h +++ b/app/panel/footageviewer/footageviewer.h @@ -36,10 +36,7 @@ public: void SetFootage(Footage* f); protected: - virtual void changeEvent(QEvent* e) override; - -private: - void Retranslate(); + virtual void Retranslate() override; }; diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 6bedce0ea..e16dc0c6c 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -21,59 +21,35 @@ #include "param.h" ParamPanel::ParamPanel(QWidget* parent) : - PanelWidget(parent) + TimeBasedPanel(parent) { // FIXME: This won't work if there's ever more than one of this panel setObjectName("ParamPanel"); - view_ = new NodeParamView(this); - connect(view_, &NodeParamView::TimeChanged, this, &ParamPanel::TimeChanged); - connect(view_, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged); - connect(view_, &NodeParamView::TimebaseChanged, this, &ParamPanel::TimebaseChanged); - - setWidget(view_); + NodeParamView* view = new NodeParamView(); + connect(view, &NodeParamView::SelectedInputChanged, this, &ParamPanel::SelectedInputChanged); + SetTimeBasedWidget(view); Retranslate(); } -void ParamPanel::ZoomIn() -{ - view_->SetScale(view_->GetScale() * 2); -} - -void ParamPanel::ZoomOut() -{ - view_->SetScale(view_->GetScale() * 0.5); -} - void ParamPanel::SetNodes(QList nodes) { - view_->SetNodes(nodes); + static_cast(GetTimeBasedWidget())->SetNodes(nodes); Retranslate(); } -void ParamPanel::SetTime(const int64_t ×tamp) -{ - view_->SetTime(timestamp); -} - -void ParamPanel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - PanelWidget::changeEvent(e); -} - void ParamPanel::Retranslate() { SetTitle(tr("Parameter Editor")); - if (view_->nodes().isEmpty()) { + NodeParamView* view = static_cast(GetTimeBasedWidget()); + + if (view->nodes().isEmpty()) { SetSubtitle(tr("(none)")); - } else if (view_->nodes().size() == 1) { - SetSubtitle(view_->nodes().first()->Name()); + } else if (view->nodes().size() == 1) { + SetSubtitle(view->nodes().first()->Name()); } else { SetSubtitle(tr("(multiple)")); } diff --git a/app/panel/param/param.h b/app/panel/param/param.h index c45b5b2f5..0e0e0e3cb 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -21,38 +21,24 @@ #ifndef PARAM_H #define PARAM_H +#include "panel/timebased/timebased.h" #include "widget/nodeparamview/nodeparamview.h" -#include "widget/panel/panel.h" -class ParamPanel : public PanelWidget +class ParamPanel : public TimeBasedPanel { Q_OBJECT public: ParamPanel(QWidget* parent); - virtual void ZoomIn() override; - - virtual void ZoomOut() override; - public slots: void SetNodes(QList nodes); - void SetTime(const int64_t& timestamp); - signals: - void TimeChanged(const int64_t& timestamp); - void SelectedInputChanged(NodeInput* input); - void TimebaseChanged(const rational& timebase); - protected: - virtual void changeEvent(QEvent* e) override; + virtual void Retranslate() override; -private: - void Retranslate(); - - NodeParamView* view_; }; #endif // PARAM_H diff --git a/app/panel/timebased/CMakeLists.txt b/app/panel/timebased/CMakeLists.txt new file mode 100644 index 000000000..957f3ae6a --- /dev/null +++ b/app/panel/timebased/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + panel/timebased/timebased.h + panel/timebased/timebased.cpp + PARENT_SCOPE +) diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp new file mode 100644 index 000000000..54cf74881 --- /dev/null +++ b/app/panel/timebased/timebased.cpp @@ -0,0 +1,131 @@ +#include "timebased.h" + +TimeBasedPanel::TimeBasedPanel(QWidget *parent) : + PanelWidget(parent), + widget_(nullptr) +{ +} + +rational TimeBasedPanel::GetTime() +{ + return widget_->GetTime(); +} + +void TimeBasedPanel::GoToStart() +{ + widget_->GoToStart(); +} + +void TimeBasedPanel::PrevFrame() +{ + widget_->PrevFrame(); +} + +void TimeBasedPanel::NextFrame() +{ + widget_->NextFrame(); +} + +void TimeBasedPanel::GoToEnd() +{ + widget_->GoToEnd(); +} + +void TimeBasedPanel::ZoomIn() +{ + widget_->ZoomIn(); +} + +void TimeBasedPanel::ZoomOut() +{ + widget_->ZoomOut(); +} + +void TimeBasedPanel::SetTimebase(const rational &timebase) +{ + widget_->SetTimebase(timebase); +} + +void TimeBasedPanel::SetTime(const int64_t ×tamp) +{ + widget_->SetTime(timestamp); +} + +void TimeBasedPanel::GoToPrevCut() +{ + widget_->GoToPrevCut(); +} + +void TimeBasedPanel::GoToNextCut() +{ + widget_->GoToNextCut(); +} + +void TimeBasedPanel::PlayPause() +{ + emit PlayPauseRequested(); +} + +void TimeBasedPanel::ShuttleLeft() +{ + emit ShuttleLeftRequested(); +} + +void TimeBasedPanel::ShuttleStop() +{ + emit ShuttleStopRequested(); +} + +void TimeBasedPanel::ShuttleRight() +{ + emit ShuttleRightRequested(); +} + +TimeBasedWidget *TimeBasedPanel::GetTimeBasedWidget() const +{ + return widget_; +} + +ViewerOutput *TimeBasedPanel::GetConnectedViewer() const +{ + return widget_->GetConnectedNode(); +} + +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()); + } +} + +void TimeBasedPanel::SetTimeBasedWidget(TimeBasedWidget *widget) +{ + if (widget_) { + disconnect(widget_, &TimeBasedWidget::TimeChanged, this, &TimeBasedPanel::TimeChanged); + disconnect(widget_, &TimeBasedWidget::TimebaseChanged, this, &TimeBasedPanel::TimebaseChanged); + } + + widget_ = widget; + + if (widget_) { + connect(widget_, &TimeBasedWidget::TimeChanged, this, &TimeBasedPanel::TimeChanged); + connect(widget_, &TimeBasedWidget::TimebaseChanged, this, &TimeBasedPanel::TimebaseChanged); + } + + setWidget(widget_); +} + +void TimeBasedPanel::Retranslate() +{ + if (!GetTimeBasedWidget()->GetConnectedNode()) { + SetSubtitle(tr("(none)")); + } +} diff --git a/app/panel/timebased/timebased.h b/app/panel/timebased/timebased.h new file mode 100644 index 000000000..2b7a8f053 --- /dev/null +++ b/app/panel/timebased/timebased.h @@ -0,0 +1,75 @@ +#ifndef TIMEBASEDPANEL_H +#define TIMEBASEDPANEL_H + +#include "widget/panel/panel.h" +#include "widget/timebased/timebased.h" + +class TimeBasedPanel : public PanelWidget +{ + Q_OBJECT +public: + TimeBasedPanel(QWidget *parent = nullptr); + + void ConnectViewerNode(ViewerOutput* node); + + void DisconnectViewerNode(); + + rational GetTime(); + + ViewerOutput* GetConnectedViewer() const; + + virtual void ZoomIn() override; + + virtual void ZoomOut() override; + + virtual void GoToStart() override; + + virtual void PrevFrame() override; + + virtual void NextFrame() override; + + virtual void GoToEnd() override; + + virtual void GoToPrevCut() override; + + virtual void GoToNextCut() override; + + virtual void PlayPause() override; + + virtual void ShuttleLeft() override; + + virtual void ShuttleStop() override; + + virtual void ShuttleRight() override; + +public slots: + void SetTimebase(const rational& timebase); + + void SetTime(const int64_t& timestamp); + +signals: + void TimeChanged(const int64_t& time); + + void TimebaseChanged(const rational& timebase); + + void PlayPauseRequested(); + + void ShuttleLeftRequested(); + + void ShuttleStopRequested(); + + void ShuttleRightRequested(); + +protected: + TimeBasedWidget* GetTimeBasedWidget() const; + + void SetTimeBasedWidget(TimeBasedWidget* widget); + + virtual void Retranslate() override; + +private: + TimeBasedWidget* widget_; + +}; + +#endif // TIMEBASEDPANEL_H diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index efb973bf2..348ed27f8 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -21,137 +21,74 @@ #include "timeline.h" TimelinePanel::TimelinePanel(QWidget *parent) : - PanelWidget(parent) + TimeBasedPanel(parent) { // FIXME: This won't work if there's ever more than one of this panel setObjectName("TimelinePanel"); - timeline_widget_ = new TimelineWidget(); - setWidget(timeline_widget_); - - connect(timeline_widget_, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&))); + SetTimeBasedWidget(new TimelineWidget()); Retranslate(); } void TimelinePanel::Clear() { - timeline_widget_->Clear(); -} - -void TimelinePanel::SetTimebase(const rational &timebase) -{ - timeline_widget_->SetTimebase(timebase); -} - -void TimelinePanel::SetTime(const int64_t ×tamp) -{ - timeline_widget_->SetTime(timestamp); -} - -void TimelinePanel::ConnectTimelineNode(ViewerOutput *node) -{ - if (timeline_widget_->GetConnectedNode()) { - disconnect(timeline_widget_->GetConnectedNode(), &ViewerOutput::MediaNameChanged, this, &TimelinePanel::SetSubtitle); - Retranslate(); - } - - timeline_widget_->ConnectTimelineNode(node); - - if (node) { - connect(node, &ViewerOutput::MediaNameChanged, this, &TimelinePanel::SetSubtitle); - SetSubtitle(node->media_name()); - } -} - -void TimelinePanel::DisconnectTimelineNode() -{ - timeline_widget_->DisconnectTimelineNode(); + static_cast(GetTimeBasedWidget())->Clear(); } void TimelinePanel::SplitAtPlayhead() { - timeline_widget_->SplitAtPlayhead(); -} - -void TimelinePanel::ZoomIn() -{ - timeline_widget_->ZoomIn(); -} - -void TimelinePanel::ZoomOut() -{ - timeline_widget_->ZoomOut(); + static_cast(GetTimeBasedWidget())->SplitAtPlayhead(); } void TimelinePanel::SelectAll() { - timeline_widget_->SelectAll(); + static_cast(GetTimeBasedWidget())->SelectAll(); } void TimelinePanel::DeselectAll() { - timeline_widget_->DeselectAll(); + static_cast(GetTimeBasedWidget())->DeselectAll(); } void TimelinePanel::RippleToIn() { - timeline_widget_->RippleToIn(); + static_cast(GetTimeBasedWidget())->RippleToIn(); } void TimelinePanel::RippleToOut() { - timeline_widget_->RippleToOut(); + static_cast(GetTimeBasedWidget())->RippleToOut(); } void TimelinePanel::EditToIn() { - timeline_widget_->EditToIn(); + static_cast(GetTimeBasedWidget())->EditToIn(); } void TimelinePanel::EditToOut() { - timeline_widget_->EditToOut(); -} - -void TimelinePanel::GoToPrevCut() -{ - timeline_widget_->GoToPrevCut(); -} - -void TimelinePanel::GoToNextCut() -{ - timeline_widget_->GoToNextCut(); + static_cast(GetTimeBasedWidget())->EditToOut(); } void TimelinePanel::DeleteSelected() { - timeline_widget_->DeleteSelected(); + static_cast(GetTimeBasedWidget())->DeleteSelected(); } void TimelinePanel::IncreaseTrackHeight() { - timeline_widget_->IncreaseTrackHeight(); + static_cast(GetTimeBasedWidget())->IncreaseTrackHeight(); } void TimelinePanel::DecreaseTrackHeight() { - timeline_widget_->DecreaseTrackHeight(); -} - -void TimelinePanel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - PanelWidget::changeEvent(e); + static_cast(GetTimeBasedWidget())->DecreaseTrackHeight(); } void TimelinePanel::Retranslate() { - SetTitle(tr("Timeline")); + TimeBasedPanel::Retranslate(); - if (!timeline_widget_->GetConnectedNode()) { - SetSubtitle(tr("(none)")); - } + SetTitle(tr("Timeline")); } diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index 9abc56f9c..df3a74bca 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -21,14 +21,13 @@ #ifndef TIMELINE_PANEL_H #define TIMELINE_PANEL_H -#include "widget/panel/panel.h" - +#include "panel/timebased/timebased.h" #include "widget/timelinewidget/timelinewidget.h" /** * @brief Panel container for a TimelineWidget */ -class TimelinePanel : public PanelWidget +class TimelinePanel : public TimeBasedPanel { Q_OBJECT public: @@ -36,16 +35,8 @@ public: void Clear(); - void ConnectTimelineNode(ViewerOutput* node); - - void DisconnectTimelineNode(); - void SplitAtPlayhead(); - virtual void ZoomIn() override; - - virtual void ZoomOut() override; - virtual void SelectAll() override; virtual void DeselectAll() override; @@ -58,31 +49,14 @@ public: virtual void EditToOut() override; - virtual void GoToPrevCut() override; - - virtual void GoToNextCut() override; - virtual void DeleteSelected() override; virtual void IncreaseTrackHeight() override; virtual void DecreaseTrackHeight() override; -public slots: - void SetTimebase(const rational& timebase); - - void SetTime(const int64_t& timestamp); - protected: - virtual void changeEvent(QEvent* e) override; - -signals: - void TimeChanged(const int64_t& time); - -private: - void Retranslate(); - - TimelineWidget* timeline_widget_; + virtual void Retranslate() override; }; diff --git a/app/panel/tool/tool.h b/app/panel/tool/tool.h index 1ecd6dcc0..7df05b3f4 100644 --- a/app/panel/tool/tool.h +++ b/app/panel/tool/tool.h @@ -37,6 +37,7 @@ protected: private: void Retranslate(); + }; #endif // TOOL_PANEL_H diff --git a/app/panel/viewer/viewer.cpp b/app/panel/viewer/viewer.cpp index c2fa38ed4..6c5b6267a 100644 --- a/app/panel/viewer/viewer.cpp +++ b/app/panel/viewer/viewer.cpp @@ -26,60 +26,16 @@ ViewerPanel::ViewerPanel(QWidget *parent) : // FIXME: This won't work if there's ever more than one of this panel setObjectName("ViewerPanel"); - // QObject system handles deleting this - viewer_ = new ViewerWidget(this); - connect(viewer_, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&))); - // Set ViewerWidget as the central widget - setWidget(viewer_); + SetTimeBasedWidget(new ViewerWidget()); // Set strings Retranslate(); } -void ViewerPanel::ConnectViewerNode(ViewerOutput *node) -{ - if (viewer_->GetConnectedViewer()) { - disconnect(viewer_->GetConnectedViewer(), &ViewerOutput::MediaNameChanged, this, &ViewerPanel::SetSubtitle); - Retranslate(); - } - - viewer_->ConnectViewerNode(node); - - if (node) { - connect(node, &ViewerOutput::MediaNameChanged, this, &ViewerPanel::SetSubtitle); - SetSubtitle(node->media_name()); - } -} - -rational ViewerPanel::GetTime() -{ - return viewer_->GetTime(); -} - -ViewerOutput *ViewerPanel::GetConnectedViewer() const -{ - return viewer_->GetConnectedViewer(); -} - -void ViewerPanel::SetTime(const int64_t ×tamp) -{ - viewer_->SetTime(timestamp); -} - -void ViewerPanel::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - Retranslate(); - } - PanelWidget::changeEvent(e); -} - void ViewerPanel::Retranslate() { - SetTitle(tr("Viewer")); + ViewerPanelBase::Retranslate(); - if (!viewer_->GetConnectedViewer()) { - SetSubtitle(tr("(none)")); - } + SetTitle(tr("Viewer")); } diff --git a/app/panel/viewer/viewer.h b/app/panel/viewer/viewer.h index 4ecccffde..fdec43265 100644 --- a/app/panel/viewer/viewer.h +++ b/app/panel/viewer/viewer.h @@ -33,23 +33,8 @@ class ViewerPanel : public ViewerPanelBase { public: ViewerPanel(QWidget* parent); - void ConnectViewerNode(ViewerOutput* node); - - rational GetTime(); - - ViewerOutput* GetConnectedViewer() const; - -public slots: - void SetTime(const int64_t& timestamp); - protected: - virtual void changeEvent(QEvent* e) override; - -signals: - void TimeChanged(const int64_t&); - -private: - void Retranslate(); + virtual void Retranslate() override; }; diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index e5d5af669..f97f5505b 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -1,56 +1,34 @@ #include "viewerbase.h" ViewerPanelBase::ViewerPanelBase(QWidget *parent) : - PanelWidget(parent) + TimeBasedPanel(parent) { } -void ViewerPanelBase::ZoomIn() -{ - viewer_->SetScale(viewer_->scale() * 2); -} - -void ViewerPanelBase::ZoomOut() -{ - viewer_->SetScale(viewer_->scale() * 0.5); -} - -void ViewerPanelBase::GoToStart() -{ - viewer_->GoToStart(); -} - -void ViewerPanelBase::PrevFrame() -{ - viewer_->PrevFrame(); -} - void ViewerPanelBase::PlayPause() { - viewer_->TogglePlayPause(); -} - -void ViewerPanelBase::NextFrame() -{ - viewer_->NextFrame(); -} - -void ViewerPanelBase::GoToEnd() -{ - viewer_->GoToEnd(); + static_cast(GetTimeBasedWidget())->TogglePlayPause(); } void ViewerPanelBase::ShuttleLeft() { - viewer_->ShuttleLeft(); + static_cast(GetTimeBasedWidget())->ShuttleLeft(); } void ViewerPanelBase::ShuttleStop() { - viewer_->ShuttleStop(); + static_cast(GetTimeBasedWidget())->ShuttleStop(); } void ViewerPanelBase::ShuttleRight() { - viewer_->ShuttleRight(); + static_cast(GetTimeBasedWidget())->ShuttleRight(); +} + +void ViewerPanelBase::ConnectTimeBasedPanel(TimeBasedPanel *panel) +{ + connect(panel, &TimeBasedPanel::PlayPauseRequested, this, &ViewerPanelBase::PlayPause); + connect(panel, &TimeBasedPanel::ShuttleLeftRequested, this, &ViewerPanelBase::ShuttleLeft); + connect(panel, &TimeBasedPanel::ShuttleStopRequested, this, &ViewerPanelBase::ShuttleStop); + connect(panel, &TimeBasedPanel::ShuttleRightRequested, this, &ViewerPanelBase::ShuttleRight); } diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index 475eeaf16..d764c057e 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -1,39 +1,24 @@ #ifndef VIEWERPANELBASE_H #define VIEWERPANELBASE_H -#include "widget/panel/panel.h" +#include "panel/timebased/timebased.h" #include "widget/viewer/viewer.h" -class ViewerPanelBase : public PanelWidget +class ViewerPanelBase : public TimeBasedPanel { Q_OBJECT public: ViewerPanelBase(QWidget* parent = nullptr); - virtual void ZoomIn() override; - - virtual void ZoomOut() override; - - virtual void GoToStart() override; - - virtual void PrevFrame() override; - virtual void PlayPause() override; - virtual void NextFrame() override; - - virtual void GoToEnd() override; - virtual void ShuttleLeft() override; virtual void ShuttleStop() override; virtual void ShuttleRight() override; -protected: - ViewerWidget* viewer_; - -private: + void ConnectTimeBasedPanel(TimeBasedPanel* panel); }; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 994918abd..b6d5dcbe8 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -187,7 +187,7 @@ void Sequence::Open(Sequence* sequence) NodePanel* node_panel = PanelManager::instance()->MostRecentlyFocused(); viewer_panel->ConnectViewerNode(sequence->viewer_output_); - timeline_panel->ConnectTimelineNode(sequence->viewer_output_); + timeline_panel->ConnectViewerNode(sequence->viewer_output_); node_panel->SetGraph(sequence); } diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index a27ab55e2..10bf36817 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -56,7 +56,7 @@ DiskManager::~DiskManager() ds << h.file_size; } } else { - qWarning() << "Failed to write cache index"; + qWarning() << "Failed to write cache index:" << GetCacheIndexFilename(); } } } @@ -196,5 +196,7 @@ qint64 DiskManager::DiskLimit() QString DiskManager::GetCacheIndexFilename() { - return QDir(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("diskindex"); + QDir d(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); + d.mkpath("."); + return d.filePath("diskindex"); } diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 4ae18ef53..dc16dd0ec 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(projectexplorer) add_subdirectory(projecttoolbar) add_subdirectory(slider) add_subdirectory(taskview) +add_subdirectory(timebased) add_subdirectory(timelinewidget) add_subdirectory(timeruler) add_subdirectory(toolbar) diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index 34ad3cc46..b77d9855a 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -53,7 +53,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect) painter->setPen(QPen(palette().window().color(), 1)); do { - x_grid_interval = qRound(x_interval * scale_ * timebase_dbl()); + x_grid_interval = qRound(x_interval * GetScale() * timebase_dbl()); x_interval *= 2.0; } while (x_grid_interval < minimum_grid_space_); @@ -70,7 +70,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect) // Add vertical lines for (int i=x_start;i(i) / scale_ / timebase_dbl()); + int value = qRound(static_cast(i) / GetScale() / timebase_dbl()); painter->drawText(i + text_padding_, qRound(scene_bottom_left.y()) - text_padding_, QString::number(value)); lines.append(QLine(i, qRound(rect.top()), i, qRound(rect.bottom()))); } @@ -183,7 +183,7 @@ void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key) disconnect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged); } -void CurveView::ScaleChangedEvent(double scale) +void CurveView::ScaleChangedEvent(const double& scale) { KeyframeViewBase::ScaleChangedEvent(scale); @@ -208,10 +208,10 @@ void CurveView::wheelEvent(QWheelEvent *event) if (WheelEventIsAZoomEvent(event)) { if (event->delta() != 0) { if (event->delta() > 0) { - emit ScaleChanged(scale_ * 1.1); + emit ScaleChanged(GetScale() * 1.1); SetYScale(y_scale_ * 1.1); } else { - emit ScaleChanged(scale_ * 0.9); + emit ScaleChanged(GetScale() * 0.9); SetYScale(y_scale_ * 0.9); } } @@ -259,18 +259,18 @@ void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *i QPointF CurveView::ScalePoint(const QPointF &point) { // Flips Y coordinate because curves are drawn bottom to top - return QPointF(point.x() * scale_, - point.y() * y_scale_); + return QPointF(point.x() * GetScale(), - point.y() * y_scale_); } void CurveView::CreateBezierControlPoints(KeyframeViewItem* item) { BezierControlPointItem* bezier_in_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kInHandle, item); - bezier_in_pt->SetXScale(scale_); + bezier_in_pt->SetXScale(GetScale()); bezier_control_points_.append(bezier_in_pt); connect(bezier_in_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection); BezierControlPointItem* bezier_out_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kOutHandle, item); - bezier_out_pt->SetXScale(scale_); + bezier_out_pt->SetXScale(GetScale()); bezier_control_points_.append(bezier_out_pt); connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection); } diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index b240c3d40..0b7976c4d 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -23,7 +23,7 @@ protected: virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override; - virtual void ScaleChangedEvent(double scale) override; + virtual void ScaleChangedEvent(const double &scale) override; virtual void VerticalScaleChangedEvent(double scale) override; diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index b4cb73a87..48175e0d7 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -12,7 +12,7 @@ #include "widget/keyframeview/keyframeviewundo.h" CurveWidget::CurveWidget(QWidget *parent) : - QWidget(parent), + TimeBasedWidget(parent), input_(nullptr), bridge_(nullptr) { @@ -51,8 +51,7 @@ CurveWidget::CurveWidget(QWidget *parent) : ruler_view_layout->setMargin(0); ruler_view_layout->setSpacing(0); - ruler_ = new TimeRuler(); - ruler_view_layout->addWidget(ruler_); + ruler_view_layout->addWidget(ruler()); view_ = new CurveView(); ruler_view_layout->addWidget(view_); @@ -60,15 +59,10 @@ CurveWidget::CurveWidget(QWidget *parent) : layout->addLayout(ruler_view_layout); // Connect ruler and view together - connect(ruler_, &TimeRuler::TimeChanged, view_, &CurveView::SetTime); - connect(view_, &CurveView::TimeChanged, ruler_, &TimeRuler::SetTime); - connect(ruler_, &TimeRuler::TimeChanged, this, &CurveWidget::TimeChanged); - connect(view_, &CurveView::TimeChanged, this, &CurveWidget::TimeChanged); - connect(ruler_, &TimeRuler::TimeChanged, this, &CurveWidget::UpdateBridgeTime); - connect(view_, &CurveView::TimeChanged, this, &CurveWidget::UpdateBridgeTime); + connect(view_, &CurveView::TimeChanged, this, &CurveWidget::SetTimeAndSignal); connect(view_->scene(), &QGraphicsScene::selectionChanged, this, &CurveWidget::SelectionChanged); connect(view_, &CurveView::ScaleChanged, this, &CurveWidget::SetScale); - connect(view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler_, &TimeRuler::SetScroll); + connect(view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); widget_bridge_layout_ = new QHBoxLayout(); widget_bridge_layout_->addStretch(); @@ -127,32 +121,6 @@ void CurveWidget::SetInput(NodeInput *input) UpdateInputLabel(); } -void CurveWidget::SetTimebase(const rational &timebase) -{ - ruler_->SetTimebase(timebase); - view_->SetTimebase(timebase); -} - -void CurveWidget::SetTime(const int64_t ×tamp) -{ - ruler_->SetTime(timestamp); - view_->SetTime(timestamp); - UpdateBridgeTime(timestamp); -} - -const double &CurveWidget::GetScale() -{ - return ruler_->scale(); -} - -void CurveWidget::SetScale(double scale) -{ - scale = qMin(scale, TimelineViewBase::kMaximumScale); - - ruler_->SetScale(scale); - view_->SetScale(scale, true); -} - const double &CurveWidget::GetVerticalScale() { return view_->GetYScale(); @@ -171,6 +139,28 @@ void CurveWidget::changeEvent(QEvent *e) QWidget::changeEvent(e); } +void CurveWidget::TimeChangedEvent(const int64_t ×tamp) +{ + TimeBasedWidget::TimeChangedEvent(timestamp); + + view_->SetTime(timestamp); + UpdateBridgeTime(timestamp); +} + +void CurveWidget::TimebaseChangedEvent(const rational &timebase) +{ + TimeBasedWidget::TimebaseChangedEvent(timebase); + + view_->SetTimebase(timebase); +} + +void CurveWidget::ScaleChangedEvent(const double &scale) +{ + TimeBasedWidget::ScaleChangedEvent(scale); + + view_->SetScaleAndCenterOnPlayhead(scale); +} + void CurveWidget::UpdateInputLabel() { if (input_) { @@ -283,9 +273,5 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked) void CurveWidget::KeyControlRequestedTimeChanged(const rational &time) { - int64_t timestamp = Timecode::time_to_timestamp(time, view_->timebase()); - - SetTime(timestamp); - - emit TimeChanged(timestamp); + SetTimeAndSignal(Timecode::time_to_timestamp(time, view_->timebase())); } diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h index 74e711582..9c3fd17e9 100644 --- a/app/widget/curvewidget/curvewidget.h +++ b/app/widget/curvewidget/curvewidget.h @@ -9,9 +9,9 @@ #include "node/input.h" #include "widget/nodeparamview/nodeparamviewkeyframecontrol.h" #include "widget/nodeparamview/nodeparamviewwidgetbridge.h" -#include "widget/timeruler/timeruler.h" +#include "widget/timebased/timebased.h" -class CurveWidget : public QWidget +class CurveWidget : public TimeBasedWidget { Q_OBJECT public: @@ -21,24 +21,16 @@ public: void SetInput(NodeInput* input); - void SetTimebase(const rational& timebase); - - void SetTime(const int64_t& timestamp); - - const double& GetScale(); - const double& GetVerticalScale(); void SetVerticalScale(const double& vscale); -public slots: - void SetScale(double scale); - -signals: - void TimeChanged(const int64_t& timestamp); - protected: virtual void changeEvent(QEvent *) override; + virtual void TimeChangedEvent(const int64_t &) override; + virtual void TimebaseChangedEvent(const rational &) override; + virtual void ScaleChangedEvent(const double &) override; + private: void UpdateInputLabel(); @@ -48,14 +40,14 @@ private: void SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type); + void UpdateBridgeTime(const int64_t& timestamp); + QPushButton* linear_button_; QPushButton* bezier_button_; QPushButton* hold_button_; - TimeRuler* ruler_; - CurveView* view_; NodeInput* input_; @@ -69,8 +61,6 @@ private: NodeParamViewKeyframeControl* key_control_; private slots: - void UpdateBridgeTime(const int64_t& timestamp); - void SelectionChanged(); void KeyframeTypeButtonTriggered(bool checked); diff --git a/app/widget/keyframeview/keyframeviewbase.cpp b/app/widget/keyframeview/keyframeviewbase.cpp index 5251ac70e..58abb28ec 100644 --- a/app/widget/keyframeview/keyframeviewbase.cpp +++ b/app/widget/keyframeview/keyframeviewbase.cpp @@ -59,7 +59,7 @@ void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key) KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key) { KeyframeViewItem* item = new KeyframeViewItem(key); - item->SetScale(scale_); + item->SetScale(GetScale()); item_map_.insert(key.get(), item); scene()->addItem(item); return item; @@ -210,8 +210,10 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) } } -void KeyframeViewBase::ScaleChangedEvent(double scale) +void KeyframeViewBase::ScaleChangedEvent(const double &scale) { + TimelineViewBase::ScaleChangedEvent(scale); + QMap::const_iterator iterator; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { @@ -333,7 +335,7 @@ void KeyframeViewBase::ProcessBezierDrag(QPointF mouse_diff_scaled, bool include QPointF KeyframeViewBase::GetScaledCursorPos(const QPoint &cursor_pos) { - return QPointF(static_cast(cursor_pos.x()) / scale_, + return QPointF(static_cast(cursor_pos.x()) / GetScale(), static_cast(cursor_pos.y()) / y_scale_); } diff --git a/app/widget/keyframeview/keyframeviewbase.h b/app/widget/keyframeview/keyframeviewbase.h index 1889a68a0..6881c4b5f 100644 --- a/app/widget/keyframeview/keyframeviewbase.h +++ b/app/widget/keyframeview/keyframeviewbase.h @@ -27,7 +27,7 @@ protected: virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent *event) override; - virtual void ScaleChangedEvent(double scale) override; + virtual void ScaleChangedEvent(const double& scale) override; virtual void VerticalScaleChangedEvent(double scale); diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index 50b2502c3..2357ae456 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -28,7 +28,7 @@ #include "node/output/viewer/viewer.h" NodeParamView::NodeParamView(QWidget *parent) : - QWidget(parent), + TimeBasedWidget(true, false, parent), last_scroll_val_(0) { // Create horizontal layout to place scroll area in (and keyframe editing eventually) @@ -64,8 +64,7 @@ NodeParamView::NodeParamView(QWidget *parent) : keyframe_area_layout->setMargin(0); // Create ruler object - ruler_ = new TimeRuler(true); - keyframe_area_layout->addWidget(ruler_); + keyframe_area_layout->addWidget(ruler()); // Create keyframe view keyframe_view_ = new KeyframeView(); @@ -74,10 +73,9 @@ NodeParamView::NodeParamView(QWidget *parent) : keyframe_area_layout->addWidget(keyframe_view_); // Connect ruler and keyframe view together - connect(ruler_, &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime); - connect(keyframe_view_, &KeyframeView::TimeChanged, ruler_, &TimeRuler::SetTime); - connect(ruler_, &TimeRuler::TimeChanged, this, &NodeParamView::RulerTimeChanged); - connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::RulerTimeChanged); + connect(ruler(), &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime); + connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime); + connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime); // Connect keyframe view scaling to this connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale); @@ -106,10 +104,12 @@ NodeParamView::NodeParamView(QWidget *parent) : connect(vertical_scrollbar_, &QScrollBar::valueChanged, scroll_area->verticalScrollBar(), &QScrollBar::setValue); connect(vertical_scrollbar_, &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue); - connect(keyframe_view_->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int))); + connect(keyframe_view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); // Set a default scale - FIXME: Hardcoded SetScale(120); + + SetMaximumScale(TimelineViewBase::kMaximumScale); } void NodeParamView::SetNodes(QList nodes) @@ -169,38 +169,32 @@ void NodeParamView::resizeEvent(QResizeEvent *event) vertical_scrollbar_->setPageStep(vertical_scrollbar_->height()); } -const QList &NodeParamView::nodes() +void NodeParamView::ScaleChangedEvent(const double &scale) { - return nodes_; + TimeBasedWidget::ScaleChangedEvent(scale); + + keyframe_view_->SetScaleAndCenterOnPlayhead(scale); } -const double &NodeParamView::GetScale() const +void NodeParamView::TimebaseChangedEvent(const rational &timebase) { - return ruler_->scale(); + TimeBasedWidget::TimebaseChangedEvent(timebase); + + keyframe_view_->SetTimebase(timebase); } -void NodeParamView::SetScale(double scale) +void NodeParamView::TimeChangedEvent(const int64_t ×tamp) { - scale = qMin(scale, TimelineViewBase::kMaximumScale); + TimeBasedWidget::TimeChangedEvent(timestamp); - ruler_->SetScale(scale); - keyframe_view_->SetScale(scale, true); -} - -void NodeParamView::SetTime(const int64_t ×tamp) -{ - ruler_->SetTime(timestamp); keyframe_view_->SetTime(timestamp); UpdateItemTime(timestamp); } -void NodeParamView::SetTimebase(const rational &timebase) +const QList &NodeParamView::nodes() { - ruler_->SetTimebase(timebase); - keyframe_view_->SetTimebase(timebase); - - emit TimebaseChanged(timebase); + return nodes_; } void NodeParamView::UpdateItemTime(const int64_t ×tamp) @@ -212,18 +206,9 @@ void NodeParamView::UpdateItemTime(const int64_t ×tamp) } } -void NodeParamView::RulerTimeChanged(const int64_t ×tamp) -{ - UpdateItemTime(timestamp); - - emit TimeChanged(timestamp); -} - void NodeParamView::ItemRequestedTimeChanged(const rational &time) { - int64_t timestamp = Timecode::time_to_timestamp(time, keyframe_view_->timebase()); - SetTime(timestamp); - emit TimeChanged(timestamp); + SetTimeAndSignal(Timecode::time_to_timestamp(time, keyframe_view_->timebase())); } void NodeParamView::ForceKeyframeViewToScroll(int min, int max) diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 97ff5ff5c..17316869d 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -27,45 +27,34 @@ #include "node/node.h" #include "nodeparamviewitem.h" #include "widget/keyframeview/keyframeview.h" -#include "widget/timeruler/timeruler.h" +#include "widget/timebased/timebased.h" -class NodeParamView : public QWidget +class NodeParamView : public TimeBasedWidget { Q_OBJECT public: - NodeParamView(QWidget* parent); + NodeParamView(QWidget* parent = nullptr); void SetNodes(QList nodes); const QList& nodes(); - const double& GetScale() const; - -public slots: - void SetScale(double scale); - - void SetTime(const int64_t& timestamp); - signals: - void TimeChanged(const int64_t& timestamp); - void SelectedInputChanged(NodeInput* input); - void TimebaseChanged(const rational& timebase); - protected: virtual void resizeEvent(QResizeEvent *event) override; -private: - void SetTimebase(const rational& timebase); + virtual void ScaleChangedEvent(const double &) override; + virtual void TimebaseChangedEvent(const rational&) override; + virtual void TimeChangedEvent(const int64_t &) override; +private: void UpdateItemTime(const int64_t ×tamp); QVBoxLayout* param_layout_; KeyframeView* keyframe_view_; - TimeRuler* ruler_; - QList nodes_; QList items_; @@ -77,8 +66,6 @@ private: int last_scroll_val_; private slots: - void RulerTimeChanged(const int64_t& timestamp); - void ItemRequestedTimeChanged(const rational& time); void ForceKeyframeViewToScroll(int min, int max); diff --git a/app/widget/panel/panel.cpp b/app/widget/panel/panel.cpp index 1ede85d1e..9f4f75936 100644 --- a/app/widget/panel/panel.cpp +++ b/app/widget/panel/panel.cpp @@ -101,3 +101,15 @@ void PanelWidget::UpdateTitle() setWindowTitle(tr("%1: %2").arg(title_, subtitle_)); } } + +void PanelWidget::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + Retranslate(); + } + QDockWidget::changeEvent(e); +} + +void PanelWidget::Retranslate() +{ +} diff --git a/app/widget/panel/panel.h b/app/widget/panel/panel.h index ce2d6cc60..aca9a1f39 100644 --- a/app/widget/panel/panel.h +++ b/app/widget/panel/panel.h @@ -119,6 +119,9 @@ protected: */ void paintEvent(QPaintEvent *event) override; + virtual void changeEvent(QEvent* e) override; + + virtual void Retranslate(); protected slots: /** diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index 54b1e50be..523a7a9e5 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -49,7 +49,8 @@ PlaybackControls::PlaybackControls(QWidget *parent) : lower_left_layout->setSpacing(0); lower_left_layout->setMargin(0); - cur_tc_lbl_ = new QLabel(); + cur_tc_lbl_ = new TimeSlider(); + connect(cur_tc_lbl_, &TimeSlider::ValueChanged, this, &PlaybackControls::TimeChanged); lower_left_layout->addWidget(cur_tc_lbl_); lower_left_layout->addStretch(); @@ -67,12 +68,12 @@ PlaybackControls::PlaybackControls(QWidget *parent) : // Go To Start Button go_to_start_btn_ = new QPushButton(); lower_middle_layout->addWidget(go_to_start_btn_); - connect(go_to_start_btn_, SIGNAL(clicked(bool)), this, SIGNAL(BeginClicked())); + connect(go_to_start_btn_, &QPushButton::clicked, this, &PlaybackControls::BeginClicked); // Prev Frame Button prev_frame_btn_ = new QPushButton(); lower_middle_layout->addWidget(prev_frame_btn_); - connect(prev_frame_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PrevFrameClicked())); + connect(prev_frame_btn_, &QPushButton::clicked, this, &PlaybackControls::PrevFrameClicked); // Play/Pause Button playpause_stack_ = new QStackedWidget(); @@ -80,11 +81,11 @@ PlaybackControls::PlaybackControls(QWidget *parent) : play_btn_ = new QPushButton(); playpause_stack_->addWidget(play_btn_); - connect(play_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PlayClicked())); + connect(play_btn_, &QPushButton::clicked, this, &PlaybackControls::PlayClicked); pause_btn_ = new QPushButton(); playpause_stack_->addWidget(pause_btn_); - connect(pause_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PauseClicked())); + connect(pause_btn_, &QPushButton::clicked, this, &PlaybackControls::PauseClicked); // Default to showing play button playpause_stack_->setCurrentWidget(play_btn_); @@ -93,12 +94,12 @@ PlaybackControls::PlaybackControls(QWidget *parent) : // Next Frame Button next_frame_btn_ = new QPushButton(); lower_middle_layout->addWidget(next_frame_btn_); - connect(next_frame_btn_, SIGNAL(clicked(bool)), this, SIGNAL(NextFrameClicked())); + connect(next_frame_btn_, &QPushButton::clicked, this, &PlaybackControls::NextFrameClicked); // Go To End Button go_to_end_btn_ = new QPushButton(); lower_middle_layout->addWidget(go_to_end_btn_); - connect(go_to_end_btn_, SIGNAL(clicked(bool)), this, SIGNAL(EndClicked())); + connect(go_to_end_btn_, &QPushButton::clicked, this, &PlaybackControls::EndClicked); lower_middle_layout->addStretch(); @@ -117,6 +118,8 @@ PlaybackControls::PlaybackControls(QWidget *parent) : lower_right_layout->addWidget(end_tc_lbl_); UpdateIcons(); + + SetTimebase(0); } void PlaybackControls::SetTimecodeEnabled(bool enabled) @@ -128,16 +131,25 @@ void PlaybackControls::SetTimecodeEnabled(bool enabled) void PlaybackControls::SetTimebase(const rational &r) { time_base_ = r; + cur_tc_lbl_->SetTimebase(r); + + cur_tc_lbl_->setEnabled(!r.isNull()); } void PlaybackControls::SetTime(const int64_t &r) { - SetTimeLabelInternal(cur_tc_lbl_, r); + cur_tc_lbl_->SetValue(r); } void PlaybackControls::SetEndTime(const int64_t &r) { - SetTimeLabelInternal(end_tc_lbl_, r); + if (time_base_.isNull()) { + return; + } + + end_tc_lbl_->setText(Timecode::timestamp_to_timecode(r, + time_base_, + Timecode::CurrentDisplay())); } void PlaybackControls::ShowPauseButton() @@ -169,14 +181,3 @@ void PlaybackControls::UpdateIcons() next_frame_btn_->setIcon(icon::NextFrame); go_to_end_btn_->setIcon(icon::GoToEnd); } - -void PlaybackControls::SetTimeLabelInternal(QLabel* label, const int64_t& time) -{ - if (time_base_.isNull()) { - return; - } - - label->setText(Timecode::timestamp_to_timecode(time, - time_base_, - Timecode::CurrentDisplay())); -} diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 5464b4847..2c9701d91 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -27,6 +27,7 @@ #include #include "common/rational.h" +#include "widget/slider/timeslider.h" /** * @brief A playback controls widget providing buttons for navigating media @@ -86,18 +87,18 @@ signals: */ void EndClicked(); + void TimeChanged(const int64_t& t); + protected: virtual void changeEvent(QEvent *) override; private: void UpdateIcons(); - void SetTimeLabelInternal(QLabel *label, const int64_t &time); - QWidget* lower_left_container_; QWidget* lower_right_container_; - QLabel* cur_tc_lbl_; + TimeSlider* cur_tc_lbl_; QLabel* end_tc_lbl_; rational time_base_; diff --git a/app/widget/slider/floatslider.cpp b/app/widget/slider/floatslider.cpp index 36b33c3d7..c71f1cd3d 100644 --- a/app/widget/slider/floatslider.cpp +++ b/app/widget/slider/floatslider.cpp @@ -149,10 +149,10 @@ double FloatSlider::AdjustDragDistanceInternal(const double &start, const double current_db += drag; qreal adjusted_linear = QAudio::convertVolume(current_db, QAudio::DecibelVolumeScale, QAudio::LinearVolumeScale); - return adjusted_linear - start; + return adjusted_linear; } case kPercentage: - return drag * 0.01; + return SliderBase::AdjustDragDistanceInternal(start, drag * 0.01); } return SliderBase::AdjustDragDistanceInternal(start, drag); diff --git a/app/widget/slider/integerslider.cpp b/app/widget/slider/integerslider.cpp index 25135873f..c7d52b846 100644 --- a/app/widget/slider/integerslider.cpp +++ b/app/widget/slider/integerslider.cpp @@ -26,9 +26,9 @@ IntegerSlider::IntegerSlider(QWidget* parent) : connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant))); } -int IntegerSlider::GetValue() +int64_t IntegerSlider::GetValue() { - return Value().toInt(); + return Value().toLongLong(); } void IntegerSlider::SetValue(const int64_t &v) diff --git a/app/widget/slider/integerslider.h b/app/widget/slider/integerslider.h index f57fd7883..86a7a33ba 100644 --- a/app/widget/slider/integerslider.h +++ b/app/widget/slider/integerslider.h @@ -29,7 +29,7 @@ class IntegerSlider : public SliderBase public: IntegerSlider(QWidget* parent = nullptr); - int GetValue(); + int64_t GetValue(); void SetValue(const int64_t& v); diff --git a/app/widget/slider/sliderbase.cpp b/app/widget/slider/sliderbase.cpp index 5ed495980..74cb69d8f 100644 --- a/app/widget/slider/sliderbase.cpp +++ b/app/widget/slider/sliderbase.cpp @@ -119,6 +119,10 @@ const QVariant &SliderBase::Value() void SliderBase::SetValue(const QVariant &v) { + if (IsDragging()) { + return; + } + value_ = ClampValue(v); // Disable tristate @@ -185,8 +189,7 @@ void SliderBase::UpdateLabel(const QVariant &v) double SliderBase::AdjustDragDistanceInternal(const double &start, const double &drag) { - Q_UNUSED(start) - return drag; + return start + drag; } QString SliderBase::ValueToString(const QVariant &v) @@ -203,16 +206,13 @@ QVariant SliderBase::StringToValue(const QString &s, bool *ok) void SliderBase::LabelPressed() { dragged_ = false; - - if (mode_ != kString) { - dragged_diff_ = 0; - } + dragged_diff_ = 0; } void SliderBase::LabelClicked() { if (dragged_) { - double drag_val = value_.toDouble() + AdjustDragDistanceInternal(value_.toDouble(), dragged_diff_); + dragged_ = false; // This was a drag switch (mode_) { @@ -220,14 +220,13 @@ void SliderBase::LabelClicked() // No-op break; case kInteger: - SetValue(qRound(drag_val)); + SetValue(temp_dragged_value_.toInt()); break; case kFloat: - SetValue(drag_val); + SetValue(temp_dragged_value_.toDouble()); break; } - dragged_ = false; emit ValueChanged(value_); } else { // This was a simple click @@ -255,11 +254,9 @@ void SliderBase::LabelDragged(int i) case kInteger: case kFloat: { - double real_drag = static_cast(i) * drag_multiplier_; + dragged_diff_ += static_cast(i) * drag_multiplier_; - dragged_diff_ += real_drag; - - double drag_val = value_.toDouble() + AdjustDragDistanceInternal(value_.toDouble(), dragged_diff_); + double drag_val = AdjustDragDistanceInternal(value_.toDouble(), dragged_diff_); // Update temporary value if (mode_ == kInteger) { diff --git a/app/widget/timebased/CMakeLists.txt b/app/widget/timebased/CMakeLists.txt new file mode 100644 index 000000000..9711117d9 --- /dev/null +++ b/app/widget/timebased/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/timebased/timebased.h + widget/timebased/timebased.cpp + PARENT_SCOPE +) diff --git a/app/widget/timebased/timebased.cpp b/app/widget/timebased/timebased.cpp new file mode 100644 index 000000000..df76eeb44 --- /dev/null +++ b/app/widget/timebased/timebased.cpp @@ -0,0 +1,201 @@ +#include "timebased.h" + +#include "common/timecodefunctions.h" + +TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_status_visible, QWidget *parent) : + QWidget(parent), + viewer_node_(nullptr) +{ + ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this); + connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal); + + scrollbar_ = new QScrollBar(Qt::Horizontal, this); +} + +rational TimeBasedWidget::GetTime() const +{ + return Timecode::timestamp_to_time(ruler()->GetTime(), timebase()); +} + +const int64_t &TimeBasedWidget::GetTimestamp() const +{ + return ruler_->GetTime(); +} + +ViewerOutput *TimeBasedWidget::GetConnectedNode() const +{ + return viewer_node_; +} + +void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) +{ + if (viewer_node_) { + DisconnectNodeInternal(viewer_node_); + } + + viewer_node_ = node; + + ConnectedNodeChanged(viewer_node_); + + if (viewer_node_) { + ConnectNodeInternal(viewer_node_); + } +} + +TimeRuler *TimeBasedWidget::ruler() const +{ + return ruler_; +} + +QScrollBar *TimeBasedWidget::scrollbar() const +{ + return scrollbar_; +} + +void TimeBasedWidget::TimebaseChangedEvent(const rational &timebase) +{ + TimelineScaledObject::TimebaseChangedEvent(timebase); + + ruler_->SetTimebase(timebase); + + emit TimebaseChanged(timebase); +} + +void TimeBasedWidget::ScaleChangedEvent(const double &scale) +{ + TimelineScaledObject::ScaleChangedEvent(scale); + + ruler_->SetScale(scale); +} + +void TimeBasedWidget::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + + // Update horizontal scrollbar's page step to the width of the panel + scrollbar()->setPageStep(scrollbar()->width()); +} + +void TimeBasedWidget::SetTime(int64_t timestamp) +{ + ruler_->SetTime(timestamp); + + TimeChangedEvent(timestamp); +} + +void TimeBasedWidget::SetTimebase(const rational &timebase) +{ + TimelineScaledObject::SetTimebase(timebase); +} + +void TimeBasedWidget::SetScale(const double &scale) +{ + TimelineScaledObject::SetScale(scale); +} + +void TimeBasedWidget::ZoomIn() +{ + SetScale(GetScale() * 2); +} + +void TimeBasedWidget::ZoomOut() +{ + SetScale(GetScale() * 0.5); +} + +void TimeBasedWidget::GoToPrevCut() +{ + if (!GetConnectedNode()) { + return; + } + + if (GetTimestamp() == 0) { + return; + } + + int64_t closest_cut = 0; + + foreach (TrackOutput* track, viewer_node_->Tracks()) { + int64_t this_track_closest_cut = 0; + + foreach (Block* block, track->Blocks()) { + int64_t block_out_ts = Timecode::time_to_timestamp(block->out(), timebase()); + + if (block_out_ts < GetTimestamp()) { + this_track_closest_cut = block_out_ts; + } else { + break; + } + } + + closest_cut = qMax(closest_cut, this_track_closest_cut); + } + + SetTimeAndSignal(closest_cut); +} + +void TimeBasedWidget::GoToNextCut() +{ + if (!GetConnectedNode()) { + return; + } + + int64_t closest_cut = INT64_MAX; + + foreach (TrackOutput* track, GetConnectedNode()->Tracks()) { + int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase()); + + if (this_track_closest_cut <= GetTimestamp()) { + this_track_closest_cut = INT64_MAX; + } + + foreach (Block* block, track->Blocks()) { + int64_t block_in_ts = Timecode::time_to_timestamp(block->in(), timebase()); + + if (block_in_ts > GetTimestamp()) { + this_track_closest_cut = block_in_ts; + break; + } + } + + closest_cut = qMin(closest_cut, this_track_closest_cut); + } + + if (closest_cut < INT64_MAX) { + SetTimeAndSignal(closest_cut); + } +} + +void TimeBasedWidget::GoToStart() +{ + if (viewer_node_) { + SetTimeAndSignal(0); + } +} + +void TimeBasedWidget::PrevFrame() +{ + if (viewer_node_) { + SetTimeAndSignal(qMax(static_cast(0), ruler()->GetTime() - 1)); + } +} + +void TimeBasedWidget::NextFrame() +{ + if (viewer_node_) { + SetTimeAndSignal(ruler()->GetTime() + 1); + } +} + +void TimeBasedWidget::GoToEnd() +{ + if (viewer_node_) { + SetTimeAndSignal(Timecode::time_to_timestamp(viewer_node_->Length(), timebase())); + } +} + +void TimeBasedWidget::SetTimeAndSignal(const int64_t &t) +{ + SetTime(t); + emit TimeChanged(t); +} diff --git a/app/widget/timebased/timebased.h b/app/widget/timebased/timebased.h new file mode 100644 index 000000000..518c5fdf1 --- /dev/null +++ b/app/widget/timebased/timebased.h @@ -0,0 +1,85 @@ +#ifndef TIMEBASEDWIDGET_H +#define TIMEBASEDWIDGET_H + +#include +#include + +#include "node/output/viewer/viewer.h" +#include "widget/timelinewidget/timelinescaledobject.h" +#include "widget/timeruler/timeruler.h" + +class TimeBasedWidget : public QWidget, public TimelineScaledObject +{ + Q_OBJECT +public: + TimeBasedWidget(bool ruler_text_visible = true, bool ruler_cache_status_visible = false, QWidget* parent = nullptr); + + rational GetTime() const; + + const int64_t& GetTimestamp() const; + + void ZoomIn(); + + void ZoomOut(); + + ViewerOutput* GetConnectedNode() const; + + void ConnectViewerNode(ViewerOutput *node); + +public slots: + // FIXME: Rename this to SetTimestamp to reduce confusion + void SetTime(int64_t timestamp); + + void SetTimebase(const rational& timebase); + + void SetScale(const double& scale); + + void GoToStart(); + + void PrevFrame(); + + void NextFrame(); + + void GoToEnd(); + + void GoToPrevCut(); + + void GoToNextCut(); + +protected slots: + void SetTimeAndSignal(const int64_t& t); + +protected: + TimeRuler* ruler() const; + + QScrollBar* scrollbar() const; + + virtual void TimebaseChangedEvent(const rational&) override; + + virtual void TimeChangedEvent(const int64_t&){} + + virtual void ScaleChangedEvent(const double &) override; + + virtual void ConnectedNodeChanged(ViewerOutput*){} + + virtual void ConnectNodeInternal(ViewerOutput*){} + + virtual void DisconnectNodeInternal(ViewerOutput*){} + + virtual void resizeEvent(QResizeEvent *event) override; + +signals: + void TimeChanged(const int64_t&); + + void TimebaseChanged(const rational&); + +private: + ViewerOutput* viewer_node_; + + TimeRuler* ruler_; + + QScrollBar* scrollbar_; + +}; + +#endif // TIMEBASEDWIDGET_H diff --git a/app/widget/timelinewidget/timelinescaledobject.cpp b/app/widget/timelinewidget/timelinescaledobject.cpp index 36b91e4eb..324e63438 100644 --- a/app/widget/timelinewidget/timelinescaledobject.cpp +++ b/app/widget/timelinewidget/timelinescaledobject.cpp @@ -3,11 +3,20 @@ #include TimelineScaledObject::TimelineScaledObject() : - scale_(1.0) + scale_(1.0), + max_scale_(DBL_MAX) { } +void TimelineScaledObject::SetTimebase(const rational &timebase) +{ + timebase_ = timebase; + timebase_dbl_ = timebase_.toDouble(); + + TimebaseChangedEvent(timebase); +} + const rational &TimelineScaledObject::timebase() const { return timebase_; @@ -45,8 +54,23 @@ rational TimelineScaledObject::SceneToTime(const double &x, bool round) return SceneToTime(x, scale_, timebase_, round); } -void TimelineScaledObject::SetTimebaseInternal(const rational &timebase) +void TimelineScaledObject::SetMaximumScale(const double &max) { - timebase_ = timebase; - timebase_dbl_ = timebase_.toDouble(); + max_scale_ = max; + + if (GetScale() > max_scale_) { + SetScale(max_scale_); + } +} + +const double& TimelineScaledObject::GetScale() const +{ + return scale_; +} + +void TimelineScaledObject::SetScale(const double& scale) +{ + scale_ = scale; + + ScaleChangedEvent(scale_); } diff --git a/app/widget/timelinewidget/timelinescaledobject.h b/app/widget/timelinewidget/timelinescaledobject.h index 7a925467e..ed6a6bcb7 100644 --- a/app/widget/timelinewidget/timelinescaledobject.h +++ b/app/widget/timelinewidget/timelinescaledobject.h @@ -7,25 +7,38 @@ class TimelineScaledObject { public: TimelineScaledObject(); + virtual ~TimelineScaledObject() = default; + + void SetTimebase(const rational &timebase); const rational& timebase() const; const double& timebase_dbl() const; static rational SceneToTime(const double &x, const double& x_scale, const rational& timebase, bool round = false); + const double& GetScale() const; + + void SetScale(const double& scale); + protected: double TimeToScene(const rational& time); rational SceneToTime(const double &x, bool round = false); - void SetTimebaseInternal(const rational& timebase); + virtual void TimebaseChangedEvent(const rational&){} - double scale_; + virtual void ScaleChangedEvent(const double&){} + + void SetMaximumScale(const double& max); private: rational timebase_; double timebase_dbl_; + double scale_; + + double max_scale_; + }; #endif // TIMELINESCALEDOBJECT_H diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 528f9feeb..16c66501a 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -14,11 +14,9 @@ #include "widget/nodeview/nodeviewundo.h" TimelineWidget::TimelineWidget(QWidget *parent) : - QWidget(parent), + TimeBasedWidget(true, true, parent), rubberband_(QRubberBand::Rectangle, this), - active_tool_(nullptr), - timeline_node_(nullptr), - playhead_(0) + active_tool_(nullptr) { QVBoxLayout* vert_layout = new QVBoxLayout(this); vert_layout->setSpacing(0); @@ -30,14 +28,10 @@ TimelineWidget::TimelineWidget(QWidget *parent) : timecode_label_ = new TimeSlider(); timecode_label_->SetAlignment(Qt::AlignCenter); timecode_label_->setVisible(false); - connect(timecode_label_, SIGNAL(ValueChanged(int64_t)), this, SIGNAL(TimeChanged(const int64_t&))); - connect(timecode_label_, SIGNAL(ValueChanged(int64_t)), this, SLOT(UpdateInternalTime(const int64_t&))); + connect(timecode_label_, &TimeSlider::ValueChanged, this, &TimelineWidget::SetTimeAndSignal); ruler_and_time_layout->addWidget(timecode_label_); - ruler_ = new TimeRuler(true, true); - connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&))); - connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), this, SLOT(UpdateInternalTime(const int64_t&))); - ruler_and_time_layout->addWidget(ruler_); + ruler_and_time_layout->addWidget(ruler()); // Create list of TimelineViews - these MUST correspond to the ViewType enum @@ -74,10 +68,9 @@ TimelineWidget::TimelineWidget(QWidget *parent) : tools_.append(import_tool_); // Global scrollbar - horizontal_scroll_ = new QScrollBar(Qt::Horizontal); - connect(horizontal_scroll_, SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int))); - connect(views_.first()->view()->horizontalScrollBar(), SIGNAL(rangeChanged(int, int)), horizontal_scroll_, SLOT(setRange(int, int))); - vert_layout->addWidget(horizontal_scroll_); + connect(scrollbar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); + connect(views_.first()->view()->horizontalScrollBar(), &QScrollBar::rangeChanged, scrollbar(), &QScrollBar::setRange); + vert_layout->addWidget(scrollbar()); foreach (TimelineAndTrackView* tview, views_) { TimelineView* view = tview->view(); @@ -87,32 +80,32 @@ TimelineWidget::TimelineWidget(QWidget *parent) : view_splitter->addWidget(tview); - connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int))); - connect(view, SIGNAL(ScaleChanged(double)), this, SLOT(SetScale(double))); - connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), view, SLOT(SetTime(const int64_t&))); - connect(view, SIGNAL(TimeChanged(const int64_t&)), ruler_, SLOT(SetTime(const int64_t&))); - connect(view, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&))); - connect(view, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(ShowContextMenu())); - connect(horizontal_scroll_, SIGNAL(valueChanged(int)), view->horizontalScrollBar(), SLOT(setValue(int))); - connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), horizontal_scroll_, SLOT(setValue(int))); + connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); + connect(view, &TimelineView::ScaleChanged, this, &TimelineWidget::SetScale); + connect(ruler(), &TimeRuler::TimeChanged, view, &TimelineView::SetTime); + connect(view, &TimelineView::TimeChanged, ruler(), &TimeRuler::SetTime); + connect(view, &TimelineView::TimeChanged, this, &TimelineWidget::TimeChanged); + connect(view, &TimelineView::customContextMenuRequested, this, &TimelineWidget::ShowContextMenu); + connect(scrollbar(), &QScrollBar::valueChanged, view->horizontalScrollBar(), &QScrollBar::setValue); + connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, scrollbar(), &QScrollBar::setValue); - connect(view, SIGNAL(MousePressed(TimelineViewMouseEvent*)), this, SLOT(ViewMousePressed(TimelineViewMouseEvent*))); - connect(view, SIGNAL(MouseMoved(TimelineViewMouseEvent*)), this, SLOT(ViewMouseMoved(TimelineViewMouseEvent*))); - connect(view, SIGNAL(MouseReleased(TimelineViewMouseEvent*)), this, SLOT(ViewMouseReleased(TimelineViewMouseEvent*))); - connect(view, SIGNAL(MouseDoubleClicked(TimelineViewMouseEvent*)), this, SLOT(ViewMouseDoubleClicked(TimelineViewMouseEvent*))); - connect(view, SIGNAL(DragEntered(TimelineViewMouseEvent*)), this, SLOT(ViewDragEntered(TimelineViewMouseEvent*))); - connect(view, SIGNAL(DragMoved(TimelineViewMouseEvent*)), this, SLOT(ViewDragMoved(TimelineViewMouseEvent*))); - connect(view, SIGNAL(DragLeft(QDragLeaveEvent*)), this, SLOT(ViewDragLeft(QDragLeaveEvent*))); - connect(view, SIGNAL(DragDropped(TimelineViewMouseEvent*)), this, SLOT(ViewDragDropped(TimelineViewMouseEvent*))); + connect(view, &TimelineView::MousePressed, this, &TimelineWidget::ViewMousePressed); + connect(view, &TimelineView::MouseMoved, this, &TimelineWidget::ViewMouseMoved); + connect(view, &TimelineView::MouseReleased, this, &TimelineWidget::ViewMouseReleased); + connect(view, &TimelineView::MouseDoubleClicked, this, &TimelineWidget::ViewMouseDoubleClicked); + connect(view, &TimelineView::DragEntered, this, &TimelineWidget::ViewDragEntered); + connect(view, &TimelineView::DragMoved, this, &TimelineWidget::ViewDragMoved); + connect(view, &TimelineView::DragLeft, this, &TimelineWidget::ViewDragLeft); + connect(view, &TimelineView::DragDropped, this, &TimelineWidget::ViewDragDropped); - connect(tview->splitter(), SIGNAL(splitterMoved(int, int)), this, SLOT(UpdateHorizontalSplitters())); + connect(tview->splitter(), &QSplitter::splitterMoved, this, &TimelineWidget::UpdateHorizontalSplitters); // Connect each view's scroll to each other foreach (TimelineAndTrackView* other_tview, views_) { TimelineView* other_view = other_tview->view(); if (view != other_view) { - connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), other_view->horizontalScrollBar(), SLOT(setValue(int))); + connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, other_view->horizontalScrollBar(), &QScrollBar::setValue); } } } @@ -121,6 +114,7 @@ TimelineWidget::TimelineWidget(QWidget *parent) : view_splitter->setSizes({INT_MAX, INT_MAX}); // FIXME: Magic number + SetMaximumScale(TimelineViewBase::kMaximumScale); SetScale(90.0); } @@ -146,11 +140,10 @@ void TimelineWidget::Clear() block_items_.clear(); } -void TimelineWidget::SetTimebase(const rational &timebase) +void TimelineWidget::TimebaseChangedEvent(const rational &timebase) { - SetTimebaseInternal(timebase); + TimeBasedWidget::TimebaseChangedEvent(timebase); - ruler_->SetTimebase(timebase); timecode_label_->SetTimebase(timebase); timecode_label_->setVisible(!timebase.isNull()); @@ -162,91 +155,91 @@ void TimelineWidget::SetTimebase(const rational &timebase) void TimelineWidget::resizeEvent(QResizeEvent *event) { - QWidget::resizeEvent(event); - - // Update horizontal scrollbar's page step to the width of the panel - horizontal_scroll_->setPageStep(horizontal_scroll_->width()); + TimeBasedWidget::resizeEvent(event); // Update timecode label size UpdateTimecodeWidthFromSplitters(views_.first()->splitter()); } -void TimelineWidget::SetTime(int64_t timestamp) +void TimelineWidget::TimeChangedEvent(const int64_t& timestamp) { - ruler_->SetTime(timestamp); - foreach (TimelineAndTrackView* view, views_) { view->view()->SetTime(timestamp); } - UpdateInternalTime(timestamp); + timecode_label_->SetValue(timestamp); } -void TimelineWidget::ConnectTimelineNode(ViewerOutput *node) +void TimelineWidget::ScaleChangedEvent(const double &scale) { - if (timeline_node_ != nullptr) { - disconnect(timeline_node_, &ViewerOutput::LengthChanged, this, &TimelineWidget::UpdateTimelineLength); - disconnect(timeline_node_, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); - disconnect(timeline_node_, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); - disconnect(timeline_node_, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); - disconnect(timeline_node_, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); - disconnect(timeline_node_, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); - disconnect(timeline_node_, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); + TimeBasedWidget::ScaleChangedEvent(scale); - SetTimebase(0); + QMapIterator iterator(block_items_); - Clear(); + while (iterator.hasNext()) { + iterator.next(); - for (int i=0;itrack_view(); - track_view->DisconnectTrackList(); + if (iterator.value() != nullptr) { + iterator.value()->SetScale(scale); } } - timeline_node_ = node; + foreach (TimelineViewGhostItem* ghost, ghost_items_) { + ghost->SetScale(scale); + } - if (timeline_node_ != nullptr) { - connect(timeline_node_, &ViewerOutput::LengthChanged, this, &TimelineWidget::UpdateTimelineLength); - connect(timeline_node_, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); - connect(timeline_node_, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); - connect(timeline_node_, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); - connect(timeline_node_, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); - connect(timeline_node_, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); - connect(timeline_node_, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); + foreach (TimelineAndTrackView* view, views_) { + view->view()->SetScale(scale); + } +} - SetTimebase(timeline_node_->video_params().time_base()); +void TimelineWidget::ConnectNodeInternal(ViewerOutput *n) +{ + connect(n, &ViewerOutput::LengthChanged, this, &TimelineWidget::UpdateTimelineLength); + connect(n, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); + connect(n, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); + connect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); + connect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); + connect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); + connect(n, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); - for (int i=0;i(i); - TimelineView* view = views_.at(i)->view(); - TrackList* track_list = timeline_node_->track_list(track_type); - TrackView* track_view = views_.at(i)->track_view(); + SetTimebase(n->video_params().time_base()); - track_view->ConnectTrackList(track_list); - view->ConnectTrackList(track_list); - view->SetEndTime(timeline_node_->Length()); + for (int i=0;i(i); + TimelineView* view = views_.at(i)->view(); + TrackList* track_list = n->track_list(track_type); + TrackView* track_view = views_.at(i)->track_view(); - // Defer to the track to make all the block UI items necessary - foreach (TrackOutput* track, timeline_node_->track_list(track_type)->Tracks()) { - AddTrack(track, track_type); - } + track_view->ConnectTrackList(track_list); + view->ConnectTrackList(track_list); + view->SetEndTime(n->Length()); + + // Defer to the track to make all the block UI items necessary + foreach (TrackOutput* track, n->track_list(track_type)->Tracks()) { + AddTrack(track, track_type); } } } -void TimelineWidget::DisconnectTimelineNode() +void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) { - ConnectTimelineNode(nullptr); -} + disconnect(n, &ViewerOutput::LengthChanged, this, &TimelineWidget::UpdateTimelineLength); + disconnect(n, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); + disconnect(n, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); + disconnect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); + disconnect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); + disconnect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); + disconnect(n, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); -void TimelineWidget::ZoomIn() -{ - SetScale(scale_ * 2); -} + SetTimebase(0); -void TimelineWidget::ZoomOut() -{ - SetScale(scale_ * 0.5); + Clear(); + + for (int i=0;itrack_view(); + track_view->DisconnectTrackList(); + } } void TimelineWidget::SelectAll() @@ -283,72 +276,13 @@ void TimelineWidget::EditToOut() RippleEditTo(Timeline::kTrimOut, true); } -void TimelineWidget::GoToPrevCut() -{ - if (timeline_node_ == nullptr) { - return; - } - - if (playhead_ == 0) { - return; - } - - int64_t closest_cut = 0; - - foreach (TrackOutput* track, timeline_node_->Tracks()) { - int64_t this_track_closest_cut = 0; - - foreach (Block* block, track->Blocks()) { - int64_t block_out_ts = Timecode::time_to_timestamp(block->out(), timebase()); - - if (block_out_ts < playhead_) { - this_track_closest_cut = block_out_ts; - } else { - break; - } - } - - closest_cut = qMax(closest_cut, this_track_closest_cut); - } - - SetTimeAndSignal(closest_cut); -} - -void TimelineWidget::GoToNextCut() -{ - if (timeline_node_ == nullptr) { - return; - } - - int64_t closest_cut = INT64_MAX; - - foreach (TrackOutput* track, timeline_node_->Tracks()) { - int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase()); - - if (this_track_closest_cut <= playhead_) { - this_track_closest_cut = INT64_MAX; - } - - foreach (Block* block, track->Blocks()) { - int64_t block_in_ts = Timecode::time_to_timestamp(block->in(), timebase()); - - if (block_in_ts > playhead_) { - this_track_closest_cut = block_in_ts; - break; - } - } - - closest_cut = qMin(closest_cut, this_track_closest_cut); - } - - if (closest_cut < INT64_MAX) { - SetTimeAndSignal(closest_cut); - } -} - void TimelineWidget::SplitAtPlayhead() { - rational playhead_time = Timecode::timestamp_to_time(playhead_, timebase()); + if (!GetConnectedNode()) { + return; + } + + rational playhead_time = Timecode::timestamp_to_time(GetTimestamp(), timebase()); QList selected_blocks = GetSelectedBlocks(); @@ -359,7 +293,7 @@ void TimelineWidget::SplitAtPlayhead() bool some_blocks_are_selected = false; // Get all blocks at the playhead - foreach (TrackOutput* track, timeline_node_->Tracks()) { + foreach (TrackOutput* track, GetConnectedNode()->Tracks()) { Block* b = track->BlockContainingTime(playhead_time); if (b && b->type() == Block::kClip) { @@ -470,7 +404,7 @@ void TimelineWidget::DeleteSelected() // Clean each track foreach (const TrackReference& track, tracks_affected) { - new TrackCleanGapsCommand(timeline_node_->track_list(track.type()), + new TrackCleanGapsCommand(GetConnectedNode()->track_list(track.type()), track.index(), command); } @@ -480,11 +414,11 @@ void TimelineWidget::DeleteSelected() void TimelineWidget::IncreaseTrackHeight() { - if (!timeline_node_) { + if (!GetConnectedNode()) { return; } - QVector all_tracks = timeline_node_->Tracks(); + QVector all_tracks = GetConnectedNode()->Tracks(); // Increase the height of each track by one "unit" foreach (TrackOutput* t, all_tracks) { @@ -494,11 +428,11 @@ void TimelineWidget::IncreaseTrackHeight() void TimelineWidget::DecreaseTrackHeight() { - if (!timeline_node_) { + if (!GetConnectedNode()) { return; } - QVector all_tracks = timeline_node_->Tracks(); + QVector all_tracks = GetConnectedNode()->Tracks(); // Decrease the height of each track by one "unit" foreach (TrackOutput* t, all_tracks) { @@ -517,7 +451,7 @@ QList TimelineWidget::GetSelectedBlocks() TimelineViewBlockItem* item = iterator.value(); - if (item != nullptr && item->isSelected()) { + if (item && item->isSelected()) { list.append(item); } } @@ -525,14 +459,9 @@ QList TimelineWidget::GetSelectedBlocks() return list; } -ViewerOutput *TimelineWidget::GetConnectedNode() const -{ - return timeline_node_; -} - void TimelineWidget::RippleEditTo(Timeline::MovementMode mode, bool insert_gaps) { - rational playhead_time = Timecode::timestamp_to_time(playhead_, timebase()); + rational playhead_time = GetTime(); rational closest_point_to_playhead; if (mode == Timeline::kTrimIn) { @@ -541,7 +470,7 @@ void TimelineWidget::RippleEditTo(Timeline::MovementMode mode, bool insert_gaps) closest_point_to_playhead = RATIONAL_MAX; } - foreach (TrackOutput* track, timeline_node_->Tracks()) { + foreach (TrackOutput* track, GetConnectedNode()->Tracks()) { Block* b = track->NearestBlockBefore(playhead_time); if (b != nullptr) { @@ -568,7 +497,7 @@ void TimelineWidget::RippleEditTo(Timeline::MovementMode mode, bool insert_gaps) rational out_ripple = qMax(closest_point_to_playhead, playhead_time); rational ripple_length = out_ripple - in_ripple; - foreach (TrackOutput* track, timeline_node_->Tracks()) { + foreach (TrackOutput* track, GetConnectedNode()->Tracks()) { GapBlock* gap = nullptr; if (insert_gaps) { gap = new GapBlock(); @@ -595,15 +524,9 @@ void TimelineWidget::RippleEditTo(Timeline::MovementMode mode, bool insert_gaps) } } -void TimelineWidget::SetTimeAndSignal(const int64_t &t) -{ - SetTime(t); - emit TimeChanged(t); -} - TrackOutput *TimelineWidget::GetTrackFromReference(const TrackReference &ref) { - return timeline_node_->track_list(ref.type())->TrackAt(ref.index()); + return GetConnectedNode()->track_list(ref.type())->TrackAt(ref.index()); } int TimelineWidget::GetTrackY(const TrackReference &ref) @@ -618,32 +541,7 @@ int TimelineWidget::GetTrackHeight(const TrackReference &ref) void TimelineWidget::CenterOn(qreal scene_pos) { - horizontal_scroll_->setValue(qRound(scene_pos - horizontal_scroll_->width()/2)); -} - -void TimelineWidget::SetScale(double scale, bool center_on_playhead) -{ - scale_ = qMin(scale, TimelineViewBase::kMaximumScale); - - ruler_->SetScale(scale_); - - QMapIterator iterator(block_items_); - - while (iterator.hasNext()) { - iterator.next(); - - if (iterator.value() != nullptr) { - iterator.value()->SetScale(scale_); - } - } - - foreach (TimelineViewGhostItem* ghost, ghost_items_) { - ghost->SetScale(scale_); - } - - foreach (TimelineAndTrackView* view, views_) { - view->view()->SetScale(scale_, center_on_playhead); - } + scrollbar()->setValue(qRound(scene_pos - scrollbar()->width()/2)); } void TimelineWidget::ClearGhosts() @@ -662,12 +560,6 @@ bool TimelineWidget::HasGhosts() return !ghost_items_.isEmpty(); } -void TimelineWidget::UpdateInternalTime(const int64_t ×tamp) -{ - playhead_ = timestamp; - timecode_label_->SetValue(timestamp); -} - void TimelineWidget::UpdateTimelineLength(const rational &length) { foreach (TimelineAndTrackView* view, views_) { @@ -684,14 +576,14 @@ void TimelineWidget::ViewMousePressed(TimelineViewMouseEvent *event) { active_tool_ = GetActiveTool(); - if (timeline_node_ != nullptr && active_tool_ != nullptr) { + if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MousePress(event); } } void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event) { - if (timeline_node_) { + if (GetConnectedNode()) { if (active_tool_) { active_tool_->MouseMove(event); } else { @@ -707,7 +599,7 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event) void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event) { - if (timeline_node_ != nullptr && active_tool_ != nullptr) { + if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MouseRelease(event); active_tool_ = nullptr; } @@ -715,7 +607,7 @@ void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event) void TimelineWidget::ViewMouseDoubleClicked(TimelineViewMouseEvent *event) { - if (timeline_node_ != nullptr && active_tool_ != nullptr) { + if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MouseDoubleClick(event); active_tool_ = nullptr; } @@ -723,28 +615,28 @@ void TimelineWidget::ViewMouseDoubleClicked(TimelineViewMouseEvent *event) void TimelineWidget::ViewDragEntered(TimelineViewMouseEvent *event) { - if (timeline_node_ != nullptr) { + if (GetConnectedNode()) { import_tool_->DragEnter(event); } } void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event) { - if (timeline_node_ != nullptr) { + if (GetConnectedNode()) { import_tool_->DragMove(event); } } void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event) { - if (timeline_node_ != nullptr) { + if (GetConnectedNode()) { import_tool_->DragLeave(event); } } void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event) { - if (timeline_node_ != nullptr) { + if (GetConnectedNode()) { import_tool_->DragDrop(event); } } @@ -761,7 +653,7 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track) // Set up clip with view parameters (clip item will automatically size its rect accordingly) item->SetBlock(block); item->SetYCoords(GetTrackY(track), GetTrackHeight(track)); - item->SetScale(scale_); + item->SetScale(GetScale()); item->SetTrack(track); // Add to list of clip items that can be iterated through @@ -770,7 +662,7 @@ void TimelineWidget::AddBlock(Block *block, TrackReference track) // Add item to graphics scene views_.at(track.type())->view()->scene()->addItem(item); - connect(block, SIGNAL(Refreshed()), this, SLOT(BlockChanged())); + connect(block, &Block::Refreshed, this, &TimelineWidget::BlockChanged); break; } } @@ -854,7 +746,7 @@ void TimelineWidget::ShowContextMenu() if (!selected.isEmpty()) { QAction* speed_duration_action = menu.addAction(tr("Speed/Duration")); - connect(speed_duration_action, SIGNAL(triggered(bool)), this, SLOT(ShowSpeedDurationDialog())); + connect(speed_duration_action, &QAction::triggered, this, &TimelineWidget::ShowSpeedDurationDialog); } menu.exec(QCursor::pos()); @@ -882,12 +774,12 @@ void TimelineWidget::ShowSpeedDurationDialog() void TimelineWidget::DeferredScrollAction() { - horizontal_scroll_->setValue(deferred_scroll_value_); + scrollbar()->setValue(deferred_scroll_value_); } void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost) { - ghost->SetScale(scale_); + ghost->SetScale(GetScale()); ghost_items_.append(ghost); views_.at(ghost->Track().type())->view()->scene()->addItem(ghost); } diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 7f0a2b24b..dad85c8d3 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -9,15 +9,14 @@ #include "timelineandtrackview.h" #include "node/output/viewer/viewer.h" #include "widget/slider/timeslider.h" -#include "widget/timelinewidget/timelinescaledobject.h" -#include "widget/timeruler/timeruler.h" +#include "widget/timebased/timebased.h" /** * @brief Full widget for working with TimelineOutput nodes * * Encapsulates TimelineViews, TimeRulers, and scrollbars for a complete widget to manipulate Timelines */ -class TimelineWidget : public QWidget, public TimelineScaledObject +class TimelineWidget : public TimeBasedWidget { Q_OBJECT public: @@ -27,16 +26,6 @@ public: void Clear(); - void SetTime(int64_t timestamp); - - void ConnectTimelineNode(ViewerOutput *node); - - void DisconnectTimelineNode(); - - void ZoomIn(); - - void ZoomOut(); - void SelectAll(); void DeselectAll(); @@ -49,10 +38,6 @@ public: void EditToOut(); - void GoToPrevCut(); - - void GoToNextCut(); - void SplitAtPlayhead(); void DeleteSelected(); @@ -63,16 +48,15 @@ public: QList GetSelectedBlocks(); - ViewerOutput* GetConnectedNode() const; - -public slots: - void SetTimebase(const rational& timebase); - protected: virtual void resizeEvent(QResizeEvent *event) override; -signals: - void TimeChanged(const int64_t& time); + virtual void TimebaseChangedEvent(const rational &) override; + virtual void TimeChangedEvent(const int64_t &) override; + virtual void ScaleChangedEvent(const double &) override; + + virtual void ConnectNodeInternal(ViewerOutput* n) override; + virtual void DisconnectNodeInternal(ViewerOutput* n) override; private: class Tool @@ -364,20 +348,10 @@ private: void RippleEditTo(Timeline::MovementMode mode, bool insert_gaps); - void SetTimeAndSignal(const int64_t& t); - TrackOutput* GetTrackFromReference(const TrackReference& ref); QList views_; - TimeRuler* ruler_; - - ViewerOutput* timeline_node_; - - int64_t playhead_; - - QScrollBar* horizontal_scroll_; - TimeSlider* timecode_label_; int deferred_scroll_value_; @@ -390,10 +364,6 @@ private: void AddGhost(TimelineViewGhostItem* ghost); private slots: - void SetScale(double scale, bool center_on_playhead = true); - - void UpdateInternalTime(const int64_t& timestamp); - void UpdateTimelineLength(const rational& length); void ViewMousePressed(TimelineViewMouseEvent* event); diff --git a/app/widget/timelinewidget/tool/add.cpp b/app/widget/timelinewidget/tool/add.cpp index fe0050ed2..cde223fbf 100644 --- a/app/widget/timelinewidget/tool/add.cpp +++ b/app/widget/timelinewidget/tool/add.cpp @@ -51,11 +51,11 @@ void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event) ClipBlock* clip = new ClipBlock(); clip->set_length_and_media_out(ghost_->AdjustedLength()); - new NodeAddCommand(static_cast(parent()->timeline_node_->parent()), + new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), clip, command); - new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()), + new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()), track.index(), clip, ghost_->GetAdjustedIn(), diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index 67fb0df0c..762e724df 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -217,7 +217,7 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event) { if (parent()->HasGhosts()) { QUndoCommand* command = new QUndoCommand(); - NodeGraph* dst_graph = static_cast(parent()->timeline_node_->parent()); + NodeGraph* dst_graph = static_cast(parent()->GetConnectedNode()->parent()); QVector block_items(parent()->ghost_items_.size()); @@ -269,7 +269,7 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event) if (event->GetModifiers() & Qt::ControlModifier) { //emit parent()->RequestInsertBlockAtTime(clip, ghost->GetAdjustedIn()); } else { - new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(ghost->GetAdjustedTrack().type()), + new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(ghost->GetAdjustedTrack().type()), ghost->GetAdjustedTrack().index(), clip, ghost->GetAdjustedIn(), diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 1eb1511c3..0578c4c76 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -274,7 +274,7 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e command); } else { // Normal block placement - new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track_ref.type()), + new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track_ref.type()), track_ref.index(), b, ghost->GetAdjustedIn(), @@ -284,7 +284,7 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e if (command->childCount() > 0) { foreach (const TrackReference& t, tracks_affected) { - new TrackCleanGapsCommand(parent()->timeline_node_->track_list(t.type()), + new TrackCleanGapsCommand(parent()->GetConnectedNode()->track_list(t.type()), t.index(), command); } diff --git a/app/widget/timelinewidget/tool/ripple.cpp b/app/widget/timelinewidget/tool/ripple.cpp index 237486c97..7d8a20b2b 100644 --- a/app/widget/timelinewidget/tool/ripple.cpp +++ b/app/widget/timelinewidget/tool/ripple.cpp @@ -49,7 +49,7 @@ void TimelineWidget::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *ev if (ghost->AdjustedLength() > 0) { GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(ghost->AdjustedLength()); - new NodeAddCommand(static_cast(parent()->timeline_node_->parent()), gap, command); + new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), gap, command); Block* block_to_append_gap_to = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kReferenceBlock)); @@ -116,7 +116,7 @@ void TimelineWidget::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_i } // For each track that does NOT have a ghost, we need to make one for Gaps - foreach (TrackOutput* track, parent()->timeline_node_->Tracks()) { + foreach (TrackOutput* track, parent()->GetConnectedNode()->Tracks()) { // Determine if we've already created a ghost on this track bool ghost_on_this_track_exists = false; diff --git a/app/widget/timelinewidget/tool/rolling.cpp b/app/widget/timelinewidget/tool/rolling.cpp index bd92ca32b..1d0ca0839 100644 --- a/app/widget/timelinewidget/tool/rolling.cpp +++ b/app/widget/timelinewidget/tool/rolling.cpp @@ -56,7 +56,7 @@ void TimelineWidget::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *e if (b->previous() == nullptr) { const TrackReference& track_ref = ghost->Track(); - new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track_ref.type()), + new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track_ref.type()), track_ref.index(), b, ghost->GetAdjustedIn(), diff --git a/app/widget/timelinewidget/tool/tool.cpp b/app/widget/timelinewidget/tool/tool.cpp index ffd902aa6..28138c886 100644 --- a/app/widget/timelinewidget/tool/tool.cpp +++ b/app/widget/timelinewidget/tool/tool.cpp @@ -157,16 +157,16 @@ bool TimelineWidget::Tool::SnapPoint(QList start_times, rational* move QList proposed_pts; foreach (rational s, start_times) { - proposed_pts.append((s + *movement).toDouble() * parent()->scale_); + proposed_pts.append((s + *movement).toDouble() * parent()->GetScale()); } if (snap_points & kSnapToPlayhead) { - rational playhead_abs_time = rational(parent()->playhead_ * parent()->timebase().numerator(), + rational playhead_abs_time = rational(parent()->GetTimestamp() * parent()->timebase().numerator(), parent()->timebase().denominator()); - qreal playhead_pos = playhead_abs_time.toDouble() * parent()->scale_; + qreal playhead_pos = playhead_abs_time.toDouble() * parent()->GetScale(); AttemptSnap(proposed_pts, playhead_pos, start_times, playhead_abs_time, movement, &diff); } diff --git a/app/widget/timelinewidget/tool/transition.cpp b/app/widget/timelinewidget/tool/transition.cpp index 73bd7a64d..8e304c575 100644 --- a/app/widget/timelinewidget/tool/transition.cpp +++ b/app/widget/timelinewidget/tool/transition.cpp @@ -94,11 +94,11 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event) QUndoCommand* command = new QUndoCommand(); // Place transition in place - new NodeAddCommand(static_cast(parent()->timeline_node_->parent()), + new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), transition, command); - new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()), + new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()), track.index(), transition, ghost_->GetAdjustedIn(), diff --git a/app/widget/timelinewidget/tool/zoom.cpp b/app/widget/timelinewidget/tool/zoom.cpp index f2f40a891..55830dfb3 100644 --- a/app/widget/timelinewidget/tool/zoom.cpp +++ b/app/widget/timelinewidget/tool/zoom.cpp @@ -59,17 +59,17 @@ void TimelineWidget::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) double scene_right = scene_bottomright.x(); // Normalize scale to 1.0 scale - double scene_width = (scene_right - scene_left) / parent()->scale_; + double scene_width = (scene_right - scene_left) / parent()->GetScale(); double new_scale = qMin(TimelineViewBase::kMaximumScale, static_cast(reference_view->viewport()->width()) / scene_width); - parent()->deferred_scroll_value_ = qMax(0, qRound(scene_left / parent()->scale_ * new_scale)); + parent()->deferred_scroll_value_ = qMax(0, qRound(scene_left / parent()->GetScale() * new_scale)); - parent()->SetScale(new_scale, false); + parent()->SetScale(new_scale); dragging_ = false; } else { // Simple zoom in/out at the cursor position - double scale = parent()->scale_; + double scale = parent()->GetScale(); if (event->GetModifiers() & Qt::AltModifier) { // Zoom out if the user clicks while holding Alt @@ -79,7 +79,7 @@ void TimelineWidget::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) scale *= 2.0; } - parent()->SetScale(scale, false); + parent()->SetScale(scale); // Adjust scroll location for new scale double frame_x = event->GetFrame().toDouble() * scale; diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index af9020b75..0c2678714 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -267,7 +267,7 @@ TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::Key QPointF scene_pt = mapToScene(pos); TimelineViewMouseEvent timeline_event(scene_pt.x(), - scale_, + GetScale(), timebase(), TrackReference(ConnectedTrackType(), SceneToTrack(scene_pt.y())), modifiers); diff --git a/app/widget/timelinewidget/view/timelineviewbase.cpp b/app/widget/timelinewidget/view/timelineviewbase.cpp index 3fd901855..978dabdb5 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.cpp +++ b/app/widget/timelinewidget/view/timelineviewbase.cpp @@ -27,7 +27,7 @@ TimelineViewBase::TimelineViewBase(QWidget *parent) : scene_.addItem(end_item_); // Set default scale - SetScale(1.0, true); + SetScaleAndCenterOnPlayhead(1.0); SetDefaultDragMode(NoDrag); @@ -35,30 +35,12 @@ TimelineViewBase::TimelineViewBase(QWidget *parent) : connect(&scene_, SIGNAL(changed(const QList&)), this, SLOT(UpdateSceneRect())); connect(Core::instance(), &Core::ToolChanged, this, &TimelineViewBase::ApplicationToolChanged); + + SetMaximumScale(kMaximumScale); } -void TimelineViewBase::SetScale(const double &scale, bool center_on_playhead) +void TimelineViewBase::TimebaseChangedEvent(const rational &) { - scale_ = qMin(scale, kMaximumScale); - - end_item_->SetScale(scale_); - - ScaleChangedEvent(scale_); - - // Force redraw for playhead - viewport()->update(); - - if (center_on_playhead) { - // Zoom towards the playhead - // (using a hacky singleShot so the scroll occurs after the scene and its scrollbars have updated) - QTimer::singleShot(0, this, &TimelineViewBase::CenterScrollOnPlayhead); - } -} - -void TimelineViewBase::SetTimebase(const rational &timebase) -{ - SetTimebaseInternal(timebase); - // Timebase influences position/visibility of playhead viewport()->update(); } @@ -298,9 +280,23 @@ void TimelineViewBase::resizeEvent(QResizeEvent *event) UpdateSceneRect(); } -void TimelineViewBase::ScaleChangedEvent(double scale) +void TimelineViewBase::ScaleChangedEvent(const double &scale) { - Q_UNUSED(scale) + TimelineScaledObject::ScaleChangedEvent(scale); + + end_item_->SetScale(scale); + + // Force redraw for playhead + viewport()->update(); +} + +void TimelineViewBase::SetScaleAndCenterOnPlayhead(const double &scale) +{ + SetScale(scale); + + // Zoom towards the playhead + // (using a hacky singleShot so the scroll occurs after the scene and its scrollbars have updated) + QTimer::singleShot(0, this, &TimelineViewBase::CenterScrollOnPlayhead); } bool TimelineViewBase::HandleZoomFromScroll(QWheelEvent *event) @@ -309,9 +305,9 @@ bool TimelineViewBase::HandleZoomFromScroll(QWheelEvent *event) // If CTRL is held (or a preference is set to swap CTRL behavior), we zoom instead of scrolling if (event->delta() != 0) { if (event->delta() > 0) { - emit ScaleChanged(scale_ * 2.0); + emit ScaleChanged(GetScale() * 2.0); } else { - emit ScaleChanged(scale_ * 0.5); + emit ScaleChanged(GetScale() * 0.5); } } diff --git a/app/widget/timelinewidget/view/timelineviewbase.h b/app/widget/timelinewidget/view/timelineviewbase.h index ce4663614..8201e9773 100644 --- a/app/widget/timelinewidget/view/timelineviewbase.h +++ b/app/widget/timelinewidget/view/timelineviewbase.h @@ -14,15 +14,13 @@ class TimelineViewBase : public QGraphicsView, public TimelineScaledObject public: TimelineViewBase(QWidget* parent = nullptr); - void SetScale(const double& scale, bool center_on_playhead); - void SetEndTime(const rational& length); + void SetScaleAndCenterOnPlayhead(const double& scale); + static const double kMaximumScale; public slots: - void SetTimebase(const rational& timebase); - void SetTime(const int64_t time); signals: @@ -35,7 +33,7 @@ protected: virtual void resizeEvent(QResizeEvent *event) override; - virtual void ScaleChangedEvent(double scale); + virtual void ScaleChangedEvent(const double& scale) override; bool HandleZoomFromScroll(QWheelEvent* event); @@ -58,6 +56,8 @@ protected: virtual void ToolChangedEvent(Tool::Item tool); + virtual void TimebaseChangedEvent(const rational &) override; + private: qreal GetPlayheadX(); diff --git a/app/widget/timelinewidget/view/timelineviewrect.cpp b/app/widget/timelinewidget/view/timelineviewrect.cpp index 0aa1edc10..20adc35c3 100644 --- a/app/widget/timelinewidget/view/timelineviewrect.cpp +++ b/app/widget/timelinewidget/view/timelineviewrect.cpp @@ -46,9 +46,9 @@ void TimelineViewRect::SetTrack(const TrackReference &track) track_ = track; } -void TimelineViewRect::SetScale(const double &scale) +void TimelineViewRect::ScaleChangedEvent(const double &scale) { - scale_ = scale; + TimelineScaledObject::ScaleChangedEvent(scale); UpdateRect(); } diff --git a/app/widget/timelinewidget/view/timelineviewrect.h b/app/widget/timelinewidget/view/timelineviewrect.h index 3916676e0..b09953fc0 100644 --- a/app/widget/timelinewidget/view/timelineviewrect.h +++ b/app/widget/timelinewidget/view/timelineviewrect.h @@ -39,11 +39,11 @@ public: const TrackReference& Track(); void SetTrack(const TrackReference& track); - void SetScale(const double& scale); - virtual void UpdateRect() = 0; protected: + virtual void ScaleChangedEvent(const double &) override; + int y_; int height_; diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index a18d9d8c1..405b62120 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -58,7 +58,7 @@ TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* pare UpdateHeight(); } -const double &TimeRuler::scale() +const double &TimeRuler::GetScale() { return scale_; } @@ -174,7 +174,7 @@ void TimeRuler::paintEvent(QPaintEvent *) } if (short_interval < minimum_gap_between_lines_) { - if (long_interval == -1) { + if (long_interval <= 0) { do { short_interval *= 2; } while (short_interval < minimum_gap_between_lines_); diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 65c723576..a43b81edd 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -34,7 +34,7 @@ class TimeRuler : public QWidget public: TimeRuler(bool text_visible = true, bool cache_status_visible = false, QWidget* parent = nullptr); - const double& scale(); + const double& GetScale(); void SetScale(const double& d); void SetTimebase(const rational& r); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index bb7296353..e625757b5 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -35,11 +35,12 @@ #include "widget/menu/menu.h" ViewerWidget::ViewerWidget(QWidget *parent) : - QWidget(parent), - viewer_node_(nullptr), + TimeBasedWidget(false, true, parent), playback_speed_(0), color_menu_enabled_(true), - divider_(Config::Current()["DefaultViewerDivider"].toInt()) + divider_(Config::Current()["DefaultViewerDivider"].toInt()), + override_color_manager_(nullptr), + time_changed_from_timer_(false) { // Set up main layout QVBoxLayout* layout = new QVBoxLayout(this); @@ -54,15 +55,11 @@ ViewerWidget::ViewerWidget(QWidget *parent) : sizer_->SetWidget(gl_widget_); // Create time ruler - ruler_ = new TimeRuler(false, true); - layout->addWidget(ruler_); - connect(ruler_, &TimeRuler::TimeChanged, this, &ViewerWidget::RulerTimeChange); + layout->addWidget(ruler()); // Create scrollbar - scrollbar_ = new QScrollBar(Qt::Horizontal); - layout->addWidget(scrollbar_); - connect(scrollbar_, &QScrollBar::valueChanged, ruler_, &TimeRuler::SetScroll); - scrollbar_->setPageStep(ruler_->width()); + layout->addWidget(scrollbar()); + connect(scrollbar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); // Create lower controls controls_ = new PlaybackControls(); @@ -74,58 +71,87 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(controls_, &PlaybackControls::NextFrameClicked, this, &ViewerWidget::NextFrame); connect(controls_, &PlaybackControls::BeginClicked, this, &ViewerWidget::GoToStart); connect(controls_, &PlaybackControls::EndClicked, this, &ViewerWidget::GoToEnd); + connect(controls_, &PlaybackControls::TimeChanged, this, &ViewerWidget::SetTimeAndSignal); layout->addWidget(controls_); // Connect timer connect(&playback_timer_, &QTimer::timeout, this, &ViewerWidget::PlaybackTimerUpdate); // FIXME: Magic number - ruler_->SetScale(48.0); + ruler()->SetScale(48.0); // Start background renderers video_renderer_ = new OpenGLBackend(this); connect(video_renderer_, &VideoRenderBackend::CachedFrameReady, this, &ViewerWidget::RendererCachedFrame); connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, this, &ViewerWidget::RendererCachedTime); - connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler_, &TimeRuler::CacheTimeReady); - connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler_, &TimeRuler::CacheInvalidatedRange); + connect(video_renderer_, &VideoRenderBackend::CachedTimeReady, ruler(), &TimeRuler::CacheTimeReady); + connect(video_renderer_, &VideoRenderBackend::RangeInvalidated, ruler(), &TimeRuler::CacheInvalidatedRange); audio_renderer_ = new AudioBackend(this); connect(PixelService::instance(), &PixelService::FormatChanged, this, &ViewerWidget::UpdateRendererParameters); } -void ViewerWidget::SetTimebase(const rational &r) +void ViewerWidget::TimeChangedEvent(const int64_t &i) { - time_base_ = r; - time_base_dbl_ = r.toDouble(); + if (!time_changed_from_timer_) { + Pause(); + } - ruler_->SetTimebase(r); - controls_->SetTimebase(r); + controls_->SetTime(i); - controls_->SetTime(ruler_->GetTime()); - LengthChangedSlot(viewer_node_ ? viewer_node_->Length() : 0); + if (GetConnectedNode() && last_time_ != i) { + rational time_set = Timecode::timestamp_to_time(i, timebase()); - playback_timer_.setInterval(qFloor(r.toDouble())); + UpdateTextureFromNode(time_set); + + PushScrubbedAudio(); + } + + last_time_ = i; } -const double &ViewerWidget::scale() const +void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) { - return ruler_->scale(); + SetTimebase(n->video_params().time_base()); + + connect(n, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase); + connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); + connect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); + connect(n, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible); + + SizeChangedSlot(n->video_params().width(), n->video_params().height()); + LengthChangedSlot(n->Length()); + + if (override_color_manager_) { + gl_widget_->ConnectColorManager(override_color_manager_); + } else if (n->parent()) { + gl_widget_->ConnectColorManager(static_cast(n->parent())->project()->color_manager()); + } else { + qWarning() << "Failed to find a suitable color manager for the connected viewer node"; + } + + UpdateRendererParameters(); } -rational ViewerWidget::GetTime() const +void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) { - return Timecode::timestamp_to_time(ruler_->GetTime(), time_base_); + SetTimebase(0); + + disconnect(n, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase); + disconnect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); + disconnect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); + disconnect(n, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible); + + // Effectively disables the viewer and clears the state + SizeChangedSlot(0, 0); + + gl_widget_->DisconnectColorManager(); } -void ViewerWidget::SetScale(const double &scale_) +void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n) { - ruler_->SetScale(scale_); -} - -void ViewerWidget::SetTime(const int64_t &time) -{ - ruler_->SetTime(time); - UpdateTimeInternal(time); + video_renderer_->SetViewerNode(n); + audio_renderer_->SetViewerNode(n); } void ViewerWidget::TogglePlayPause() @@ -144,54 +170,12 @@ bool ViewerWidget::IsPlaying() const void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_manager) { - if (viewer_node_ != nullptr) { - SetTimebase(0); + override_color_manager_ = color_manager; - disconnect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase); - disconnect(viewer_node_, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); - disconnect(viewer_node_, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); - disconnect(viewer_node_, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible); - - // Effectively disables the viewer and clears the state - SizeChangedSlot(0, 0); - - gl_widget_->DisconnectColorManager(); - } - - viewer_node_ = node; - - video_renderer_->SetViewerNode(viewer_node_); - audio_renderer_->SetViewerNode(viewer_node_); + TimeBasedWidget::ConnectViewerNode(node); // Set texture to new texture (or null if no viewer node is available) UpdateTextureFromNode(GetTime()); - - if (viewer_node_ != nullptr) { - SetTimebase(viewer_node_->video_params().time_base()); - - connect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &ViewerWidget::SetTimebase); - connect(viewer_node_, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); - connect(viewer_node_, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); - connect(viewer_node_, &ViewerOutput::VisibleInvalidated, this, &ViewerWidget::InvalidateVisible); - - SizeChangedSlot(viewer_node_->video_params().width(), viewer_node_->video_params().height()); - LengthChangedSlot(viewer_node_->Length()); - - if (color_manager) { - gl_widget_->ConnectColorManager(color_manager); - } else if (viewer_node_->parent()) { - gl_widget_->ConnectColorManager(static_cast(viewer_node_->parent())->project()->color_manager()); - } else { - qWarning() << "Failed to find a suitable color manager for the connected viewer node"; - } - - UpdateRendererParameters(); - } -} - -ViewerOutput *ViewerWidget::GetConnectedViewer() const -{ - return viewer_node_; } void ViewerWidget::SetColorMenuEnabled(bool enabled) @@ -219,26 +203,9 @@ void ViewerWidget::SetTexture(OpenGLTexturePtr tex) gl_widget_->SetTexture(tex); } -void ViewerWidget::UpdateTimeInternal(int64_t i) -{ - rational time_set = rational(i) * time_base_; - - controls_->SetTime(i); - - if (viewer_node_ != nullptr && last_time_ != i) { - UpdateTextureFromNode(time_set); - - PushScrubbedAudio(); - } - - last_time_ = i; - - emit TimeChanged(i); -} - void ViewerWidget::UpdateTextureFromNode(const rational& time) { - if (viewer_node_ == nullptr) { + if (!GetConnectedNode()) { SetTexture(nullptr); } else { SetTexture(video_renderer_->GetCachedFrameAsTexture(time)); @@ -249,7 +216,7 @@ void ViewerWidget::PlayInternal(int speed) { Q_ASSERT(speed != 0); - if (time_base_.isNull()) { + if (timebase().isNull()) { qWarning() << "ViewerWidget can't play with an invalid timebase"; return; } @@ -264,7 +231,7 @@ void ViewerWidget::PlayInternal(int speed) } start_msec_ = QDateTime::currentMSecsSinceEpoch(); - start_timestamp_ = ruler_->GetTime(); + start_timestamp_ = ruler()->GetTime(); playback_timer_.start(); @@ -273,13 +240,13 @@ void ViewerWidget::PlayInternal(int speed) void ViewerWidget::PushScrubbedAudio() { - if (Config::Current()["AudioScrubbing"].toBool() && !IsPlaying()) { + if (!IsPlaying() && Config::Current()["AudioScrubbing"].toBool()) { // Get audio src device from renderer QIODevice* audio_src = audio_renderer_->GetAudioPullDevice(); - if (audio_src != nullptr && audio_src->open(QFile::ReadOnly)) { + if (audio_src && audio_src->open(QFile::ReadOnly)) { // Try to get one "frame" of audio - int size_of_sample = audio_renderer_->params().time_to_bytes(time_base_); + int size_of_sample = audio_renderer_->params().time_to_bytes(timebase()); // Push audio audio_src->seek(audio_renderer_->params().time_to_bytes(GetTime())); @@ -294,20 +261,20 @@ void ViewerWidget::PushScrubbedAudio() void ViewerWidget::UpdateRendererParameters() { - if (!viewer_node_) { + if (!GetConnectedNode()) { return; } RenderMode::Mode render_mode = RenderMode::kOffline; - video_renderer_->SetParameters(VideoRenderingParams(viewer_node_->video_params(), + video_renderer_->SetParameters(VideoRenderingParams(GetConnectedNode()->video_params(), PixelService::instance()->GetConfiguredFormatForMode(render_mode), render_mode, divider_)); - audio_renderer_->SetParameters(AudioRenderingParams(viewer_node_->audio_params(), + audio_renderer_->SetParameters(AudioRenderingParams(GetConnectedNode()->audio_params(), SampleFormat::GetConfiguredFormatForMode(render_mode))); - video_renderer_->InvalidateCache(0, viewer_node_->Length()); + video_renderer_->InvalidateCache(0, GetConnectedNode()->Length()); } void ViewerWidget::ShowContextMenu(const QPoint &pos) @@ -371,13 +338,6 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) menu.exec(mapToGlobal(pos)); } -void ViewerWidget::RulerTimeChange(int64_t i) -{ - Pause(); - - UpdateTimeInternal(i); -} - void ViewerWidget::Play() { PlayInternal(1); @@ -393,36 +353,6 @@ void ViewerWidget::Pause() } } -void ViewerWidget::GoToStart() -{ - Pause(); - - SetTime(0); -} - -void ViewerWidget::PrevFrame() -{ - Pause(); - - SetTime(qMax(static_cast(0), ruler_->GetTime() - 1)); -} - -void ViewerWidget::NextFrame() -{ - Pause(); - - SetTime(ruler_->GetTime() + 1); -} - -void ViewerWidget::GoToEnd() -{ - if (viewer_node_ != nullptr) { - Pause(); - - SetTime(Timecode::time_to_timestamp(viewer_node_->Length(), time_base_)); - } -} - void ViewerWidget::ShuttleLeft() { int current_speed = playback_speed_; @@ -478,20 +408,33 @@ void ViewerWidget::SetOCIOLook(const QString &look) gl_widget_->SetOCIOLook(look); } +void ViewerWidget::TimebaseChangedEvent(const rational &timebase) +{ + TimeBasedWidget::TimebaseChangedEvent(timebase); + + controls_->SetTimebase(timebase); + + controls_->SetTime(ruler()->GetTime()); + LengthChangedSlot(GetConnectedNode() ? GetConnectedNode()->Length() : 0); + + playback_timer_.setInterval(qFloor(timebase.toDouble())); +} + void ViewerWidget::PlaybackTimerUpdate() { int64_t real_time = QDateTime::currentMSecsSinceEpoch() - start_msec_; - int64_t frames_since_start = qRound(static_cast(real_time) / (time_base_dbl_ * 1000)); + int64_t frames_since_start = qRound(static_cast(real_time) / (timebase_dbl() * 1000)); int64_t current_time = start_timestamp_ + frames_since_start * playback_speed_; if (current_time < 0) { - current_time = 0; - Pause(); + SetTimeAndSignal(0); + } else { + time_changed_from_timer_ = true; + SetTimeAndSignal(current_time); + time_changed_from_timer_ = false; } - - SetTime(current_time); } void ViewerWidget::RendererCachedFrame(const rational &time, QVariant value, qint64 job_time) @@ -519,14 +462,8 @@ void ViewerWidget::SizeChangedSlot(int width, int height) void ViewerWidget::LengthChangedSlot(const rational &length) { - controls_->SetEndTime(Timecode::time_to_timestamp(length, time_base_)); - ruler_->SetCacheStatusLength(length); -} - -void ViewerWidget::resizeEvent(QResizeEvent *event) -{ - // Set scrollbar page step to the width - scrollbar_->setPageStep(event->size().width()); + controls_->SetEndTime(Timecode::time_to_timestamp(length, timebase())); + ruler()->SetCacheStatusLength(length); } void ViewerWidget::ColorDisplayChanged(QAction* action) diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 1f030f23b..02ab0f5df 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -36,12 +36,12 @@ #include "viewerglwidget.h" #include "viewersizer.h" #include "widget/playbackcontrols/playbackcontrols.h" -#include "widget/timeruler/timeruler.h" +#include "widget/timebased/timebased.h" /** * @brief An OpenGL-based viewer widget with playback controls (a PlaybackControls widget). */ -class ViewerWidget : public QWidget +class ViewerWidget : public TimeBasedWidget { Q_OBJECT public: @@ -51,22 +51,12 @@ public: void SetTimeRulerEnabled(bool enabled); - const double& scale() const; - - rational GetTime() const; - - void SetScale(const double& scale_); - - void SetTime(const int64_t& time); - void TogglePlayPause(); bool IsPlaying() const; void ConnectViewerNode(ViewerOutput* node, ColorManager *color_manager = nullptr); - ViewerOutput* GetConnectedViewer() const; - /** * @brief Enable or disable the color management menu * @@ -91,20 +81,10 @@ public slots: */ void SetTexture(OpenGLTexturePtr tex); - void SetTimebase(const rational& r); - - void GoToStart(); - - void PrevFrame(); - void Play(); void Pause(); - void NextFrame(); - - void GoToEnd(); - void ShuttleLeft(); void ShuttleStop(); @@ -134,11 +114,13 @@ public slots: */ void SetOCIOLook(const QString& look); -signals: - void TimeChanged(const int64_t&); - protected: - virtual void resizeEvent(QResizeEvent *event) override; + virtual void TimebaseChangedEvent(const rational &) override; + virtual void TimeChangedEvent(const int64_t &) override; + + virtual void ConnectNodeInternal(ViewerOutput *) override; + virtual void DisconnectNodeInternal(ViewerOutput *) override; + virtual void ConnectedNodeChanged(ViewerOutput*n) override; OpenGLBackend* video_renderer_; AudioBackend* audio_renderer_; @@ -158,21 +140,11 @@ private: PlaybackControls* controls_; - TimeRuler* ruler_; - - QScrollBar* scrollbar_; - - rational time_base_; - - double time_base_dbl_; - QTimer playback_timer_; qint64 start_msec_; int64_t start_timestamp_; - ViewerOutput* viewer_node_; - int playback_speed_; qint64 frame_cache_job_time_; @@ -183,9 +155,11 @@ private: int divider_; -private slots: - void RulerTimeChange(int64_t); + ColorManager* override_color_manager_; + bool time_changed_from_timer_; + +private slots: void PlaybackTimerUpdate(); void RendererCachedFrame(const rational& time, QVariant value, qint64 job_time); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 68c59c159..67b5cf771 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -90,6 +90,10 @@ MainWindow::MainWindow(QWidget *parent) : connect(curve_panel_, &CurvePanel::TimeChanged, viewer_panel_, &ViewerPanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, timeline_panel_, &TimelinePanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime); + + viewer_panel_->ConnectTimeBasedPanel(timeline_panel_); + viewer_panel_->ConnectTimeBasedPanel(param_panel_); + viewer_panel_->ConnectTimeBasedPanel(curve_panel_); } void MainWindow::SetFullscreen(bool fullscreen)