diff --git a/app/config/config.cpp b/app/config/config.cpp index 27080faa3..7b9eaae02 100644 --- a/app/config/config.cpp +++ b/app/config/config.cpp @@ -81,6 +81,7 @@ void Config::SetDefaults() config_map_["SetNameWithMarker"] = false; config_map_["RectifiedWaveforms"] = false; config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; + config_map_["Loop"] = false; config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); config_map_["DiskCacheSize"] = 20.0; diff --git a/app/panel/timebased/timebased.cpp b/app/panel/timebased/timebased.cpp index e35628800..2b3363654 100644 --- a/app/panel/timebased/timebased.cpp +++ b/app/panel/timebased/timebased.cpp @@ -88,6 +88,11 @@ void TimeBasedPanel::PlayPause() emit PlayPauseRequested(); } +void TimeBasedPanel::PlayInToOut() +{ + emit PlayInToOutRequested(); +} + void TimeBasedPanel::ShuttleLeft() { emit ShuttleLeftRequested(); diff --git a/app/panel/timebased/timebased.h b/app/panel/timebased/timebased.h index a47a4ea18..9c68567b3 100644 --- a/app/panel/timebased/timebased.h +++ b/app/panel/timebased/timebased.h @@ -60,6 +60,8 @@ public: virtual void PlayPause() override; + virtual void PlayInToOut() override; + virtual void ShuttleLeft() override; virtual void ShuttleStop() override; @@ -96,6 +98,8 @@ signals: void PlayPauseRequested(); + void PlayInToOutRequested(); + void ShuttleLeftRequested(); void ShuttleStopRequested(); diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index 85597a659..1cd35960f 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -32,6 +32,11 @@ void ViewerPanelBase::PlayPause() static_cast(GetTimeBasedWidget())->TogglePlayPause(); } +void ViewerPanelBase::PlayInToOut() +{ + static_cast(GetTimeBasedWidget())->Play(true); +} + void ViewerPanelBase::ShuttleLeft() { static_cast(GetTimeBasedWidget())->ShuttleLeft(); @@ -50,6 +55,7 @@ void ViewerPanelBase::ShuttleRight() void ViewerPanelBase::ConnectTimeBasedPanel(TimeBasedPanel *panel) { connect(panel, &TimeBasedPanel::PlayPauseRequested, this, &ViewerPanelBase::PlayPause); + connect(panel, &TimeBasedPanel::PlayInToOutRequested, this, &ViewerPanelBase::PlayInToOut); connect(panel, &TimeBasedPanel::ShuttleLeftRequested, this, &ViewerPanelBase::ShuttleLeft); connect(panel, &TimeBasedPanel::ShuttleStopRequested, this, &ViewerPanelBase::ShuttleStop); connect(panel, &TimeBasedPanel::ShuttleRightRequested, this, &ViewerPanelBase::ShuttleRight); @@ -58,6 +64,7 @@ void ViewerPanelBase::ConnectTimeBasedPanel(TimeBasedPanel *panel) void ViewerPanelBase::DisconnectTimeBasedPanel(TimeBasedPanel *panel) { disconnect(panel, &TimeBasedPanel::PlayPauseRequested, this, &ViewerPanelBase::PlayPause); + disconnect(panel, &TimeBasedPanel::PlayInToOutRequested, this, &ViewerPanelBase::PlayInToOut); disconnect(panel, &TimeBasedPanel::ShuttleLeftRequested, this, &ViewerPanelBase::ShuttleLeft); disconnect(panel, &TimeBasedPanel::ShuttleStopRequested, this, &ViewerPanelBase::ShuttleStop); disconnect(panel, &TimeBasedPanel::ShuttleRightRequested, this, &ViewerPanelBase::ShuttleRight); diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index d9906a9f8..dd593b066 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -35,6 +35,8 @@ public: virtual void PlayPause() override; + virtual void PlayInToOut() override; + virtual void ShuttleLeft() override; virtual void ShuttleStop() override; diff --git a/app/widget/panel/panel.h b/app/widget/panel/panel.h index 1eaa76367..2b666dfa7 100644 --- a/app/widget/panel/panel.h +++ b/app/widget/panel/panel.h @@ -91,6 +91,8 @@ public: */ virtual void PlayPause(){} + virtual void PlayInToOut(){} + virtual void NextFrame(){} virtual void GoToEnd(){} diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 00b4b9486..1db2435cc 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -84,7 +84,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : controls_ = new PlaybackControls(); controls_->SetTimecodeEnabled(true); controls_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - connect(controls_, &PlaybackControls::PlayClicked, this, &ViewerWidget::Play); + connect(controls_, &PlaybackControls::PlayClicked, this, static_cast(&ViewerWidget::Play)); connect(controls_, &PlaybackControls::PauseClicked, this, &ViewerWidget::Pause); connect(controls_, &PlaybackControls::PrevFrameClicked, this, &ViewerWidget::PrevFrame); connect(controls_, &PlaybackControls::NextFrameClicked, this, &ViewerWidget::NextFrame); @@ -332,7 +332,7 @@ void ViewerWidget::UpdateTextureFromNode(const rational& time) } } -void ViewerWidget::PlayInternal(int speed) +void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) { Q_ASSERT(speed != 0); @@ -342,6 +342,7 @@ void ViewerWidget::PlayInternal(int speed) } playback_speed_ = speed; + play_in_to_out_only_ = in_to_out_only; QIODevice* audio_src = audio_renderer_->GetAudioPullDevice(); if (audio_src != nullptr && audio_src->open(QIODevice::ReadOnly)) { @@ -649,9 +650,21 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) menu.exec(static_cast(sender())->mapToGlobal(pos)); } +void ViewerWidget::Play(bool in_to_out_only) +{ + if (in_to_out_only + && GetConnectedTimelinePoints() + && GetConnectedTimelinePoints()->workarea()->enabled()) { + // Jump to in point + SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->in(), timebase())); + } + + PlayInternal(1, in_to_out_only); +} + void ViewerWidget::Play() { - PlayInternal(1); + Play(false); } void ViewerWidget::Pause() @@ -683,7 +696,7 @@ void ViewerWidget::ShuttleLeft() current_speed--; } - PlayInternal(current_speed); + PlayInternal(current_speed, false); } void ViewerWidget::ShuttleStop() @@ -705,7 +718,7 @@ void ViewerWidget::ShuttleRight() current_speed++; } - PlayInternal(current_speed); + PlayInternal(current_speed, false); } void ViewerWidget::SetOCIOParameters(const QString &display, const QString &view, const QString &look) @@ -773,12 +786,64 @@ void ViewerWidget::PlaybackTimerUpdate() int64_t current_time = start_timestamp_ + frames_since_start * playback_speed_; - if (current_time < 0) { - SetTimeAndSignal(0); + int64_t min_time, max_time; + + { + if ((play_in_to_out_only_ || Config::Current()["Loop"].toBool()) + && GetConnectedTimelinePoints() + && GetConnectedTimelinePoints()->workarea()->enabled()) { + + // If "play in to out" is enabled or we're looping AND we have a workarea, only play the workarea + min_time = Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->in(), timebase()); + max_time = Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->out(), timebase()); + + } else { + + // Otherwise set the bounds to the range of the sequence + min_time = 0; + max_time = Timecode::time_to_timestamp(GetConnectedNode()->Length(), timebase()); + + } + } + + if ((playback_speed_ < 0 && current_time <= min_time) + || (playback_speed_ > 0 && current_time >= max_time)) { + + // Determine which timestamp we tripped + int64_t tripped_time; + + if (current_time <= min_time) { + tripped_time = min_time; + } else { + tripped_time = max_time; + } + + if (Config::Current()["Loop"].toBool()) { + + // If we're looping, jump to the other side of the workarea and continue + int64_t opposing_time = (tripped_time == min_time) ? max_time : min_time; + + // Cache the current speed + int current_speed = playback_speed_; + + // Jump to the other side and keep playing at the same speed + SetTimeAndSignal(opposing_time); + PlayInternal(current_speed, play_in_to_out_only_); + + } else { + + // Pause at the boundary + SetTimeAndSignal(tripped_time); + + } + } else { + + // Sets time, wrapping in this bool ensures we don't pause from setting the time time_changed_from_timer_ = true; SetTimeAndSignal(current_time); time_changed_from_timer_ = false; + } } diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 892c5b5f0..1396f9a9c 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -83,6 +83,8 @@ public: VideoRenderBackend* video_renderer() const; public slots: + void Play(bool in_to_out_only); + void Play(); void Pause(); @@ -152,7 +154,7 @@ private: void UpdateTextureFromNode(const rational &time); - void PlayInternal(int speed); + void PlayInternal(int speed, bool in_to_out_only); void PushScrubbedAudio(); @@ -186,6 +188,8 @@ private: bool time_changed_from_timer_; + bool play_in_to_out_only_; + AudioWaveformView* waveform_view_; QList windows_; diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index 133c8ea09..e75c8ce76 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -24,6 +24,7 @@ #include #include "common/timecodefunctions.h" +#include "config/config.h" #include "core.h" #include "dialog/actionsearch/actionsearch.h" #include "panel/panelmanager.h" @@ -152,7 +153,7 @@ MainMenu::MainMenu(MainWindow *parent) : // // PLAYBACK MENU // - playback_menu_ = new Menu(this); + playback_menu_ = new Menu(this, this, &MainMenu::PlaybackMenuAboutToShow); playback_gotostart_item_ = playback_menu_->AddItem("gotostart", this, &MainMenu::GoToStartTriggered, "Home"); playback_prevframe_item_ = playback_menu_->AddItem("prevframe", this, &MainMenu::PrevFrameTriggered, "Left"); playback_playpause_item_ = playback_menu_->AddItem("playpause", this, &MainMenu::PlayPauseTriggered, "Space"); @@ -179,7 +180,7 @@ MainMenu::MainMenu(MainWindow *parent) : playback_menu_->addSeparator(); playback_loop_item_ = playback_menu_->AddItem("loop", this, &MainMenu::LoopTriggered); - //Menu::SetBooleanAction(playback_loop_item_, &olive::config.loop); + playback_loop_item_->setCheckable(true); // // WINDOW MENU @@ -359,6 +360,11 @@ void MainMenu::ToolsMenuAboutToShow() tools_snapping_item_->setChecked(Core::instance()->snapping()); } +void MainMenu::PlaybackMenuAboutToShow() +{ + playback_loop_item_->setChecked(Config::Current()["Loop"].toBool()); +} + void MainMenu::WindowMenuAboutToShow() { // QMainWindow generates a perfectly usable menu for this purpose, we just need to copy it to the window menu @@ -450,12 +456,12 @@ void MainMenu::PlayPauseTriggered() void MainMenu::PlayInToOutTriggered() { - qDebug() << "FIXME: Stub"; + PanelManager::instance()->CurrentlyFocused()->PlayInToOut(); } -void MainMenu::LoopTriggered() +void MainMenu::LoopTriggered(bool enabled) { - qDebug() << "FIXME: Stub"; + Config::Current()["Loop"] = enabled; } void MainMenu::NextFrameTriggered() diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index e866db597..142320986 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -84,6 +84,11 @@ private slots: */ void ToolsMenuAboutToShow(); + /** + * @brief PlaybackMenuAboutToShow + */ + void PlaybackMenuAboutToShow(); + /** * @brief Slot triggered just before the Window menu shows */ @@ -133,7 +138,7 @@ private slots: void PlayInToOutTriggered(); - void LoopTriggered(); + void LoopTriggered(bool enabled); void NextFrameTriggered(); void GoToEndTriggered();