diff --git a/app/widget/playbackcontrols/playbackcontrols.cpp b/app/widget/playbackcontrols/playbackcontrols.cpp index a7921c653..002128f35 100644 --- a/app/widget/playbackcontrols/playbackcontrols.cpp +++ b/app/widget/playbackcontrols/playbackcontrols.cpp @@ -21,7 +21,6 @@ #include "playbackcontrols.h" #include -#include #include "common/timecodefunctions.h" #include "config/config.h" @@ -76,10 +75,24 @@ PlaybackControls::PlaybackControls(QWidget *parent) : connect(prev_frame_btn, SIGNAL(clicked(bool)), this, SIGNAL(PrevFrameClicked())); // Play/Pause Button - QPushButton* play_btn = new QPushButton(); - play_btn->setIcon(olive::icon::Play); - lower_middle_layout->addWidget(play_btn); - connect(play_btn, SIGNAL(clicked(bool)), this, SIGNAL(PlayClicked())); + playpause_stack_ = new QStackedWidget(); + lower_middle_layout->addWidget(playpause_stack_); + + play_btn_ = new QPushButton(); + play_btn_->setIcon(olive::icon::Play); + playpause_stack_->addWidget(play_btn_); + connect(play_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PlayClicked())); + connect(play_btn_, SIGNAL(clicked(bool)), this, SLOT(PlayPauseClickedInternal())); + + pause_btn_ = new QPushButton(); + pause_btn_->setIcon(olive::icon::Pause); + playpause_stack_->addWidget(pause_btn_); + connect(pause_btn_, SIGNAL(clicked(bool)), this, SIGNAL(PauseClicked())); + connect(pause_btn_, SIGNAL(clicked(bool)), this, SLOT(PlayPauseClickedInternal())); + + // Default to showing play button + playpause_stack_->setCurrentWidget(play_btn_); + playpause_stack_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); // Next Frame Button QPushButton* next_frame_btn = new QPushButton(); @@ -127,3 +140,13 @@ void PlaybackControls::SetTime(const int64_t &r) cur_tc_lbl_->setText(olive::timestamp_to_timecode(r, time_base_, kTimecodeDisplay)); } + +void PlaybackControls::PlayPauseClickedInternal() +{ + if (sender() == play_btn_) { + // Play was clicked, toggle to pause + playpause_stack_->setCurrentWidget(pause_btn_); + } else { + playpause_stack_->setCurrentWidget(play_btn_); + } +} diff --git a/app/widget/playbackcontrols/playbackcontrols.h b/app/widget/playbackcontrols/playbackcontrols.h index 5a089d231..cb413d49b 100644 --- a/app/widget/playbackcontrols/playbackcontrols.h +++ b/app/widget/playbackcontrols/playbackcontrols.h @@ -23,6 +23,8 @@ #include #include +#include +#include #include "common/rational.h" @@ -59,10 +61,15 @@ signals: void PrevFrameClicked(); /** - * @brief Signal emitted when "Play/Pause" is clicked + * @brief Signal emitted when "Play" is clicked */ void PlayClicked(); + /** + * @brief Signal emitted when "Pause" is clicked + */ + void PauseClicked(); + /** * @brief Signal emitted when "Next Frame" is clicked */ @@ -81,6 +88,15 @@ private: QLabel* end_tc_lbl_; rational time_base_; + + QPushButton* play_btn_; + QPushButton* pause_btn_; + + QStackedWidget* playpause_stack_; + +private slots: + void PlayPauseClickedInternal(); + }; #endif // PLAYBACKCONTROLS_H diff --git a/app/widget/timeruler/timeruler.cpp b/app/widget/timeruler/timeruler.cpp index b2b5a359e..ddcd78910 100644 --- a/app/widget/timeruler/timeruler.cpp +++ b/app/widget/timeruler/timeruler.cpp @@ -92,6 +92,11 @@ void TimeRuler::SetTimebase(const rational &r) update(); } +const int64_t &TimeRuler::Time() +{ + return time_; +} + void TimeRuler::SetTime(const int64_t &r) { time_ = r; diff --git a/app/widget/timeruler/timeruler.h b/app/widget/timeruler/timeruler.h index 06bb51988..edbc3e333 100644 --- a/app/widget/timeruler/timeruler.h +++ b/app/widget/timeruler/timeruler.h @@ -42,6 +42,8 @@ public: void SetCenteredText(bool c); + const int64_t& Time(); + public slots: void SetTime(const int64_t &r); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 446c79dc8..7a1c6a9ca 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -20,8 +20,10 @@ #include "viewer.h" +#include #include #include +#include #include #include "viewersizer.h" @@ -58,8 +60,17 @@ ViewerWidget::ViewerWidget(QWidget *parent) : controls_ = new PlaybackControls(this); controls_->SetTimecodeEnabled(true); controls_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + connect(controls_, SIGNAL(PlayClicked()), this, SLOT(Play())); + connect(controls_, SIGNAL(PauseClicked()), this, SLOT(Pause())); + connect(controls_, SIGNAL(PrevFrameClicked()), this, SLOT(PrevFrame())); + connect(controls_, SIGNAL(NextFrameClicked()), this, SLOT(NextFrame())); + connect(controls_, SIGNAL(BeginClicked()), this, SLOT(GoToStart())); + connect(controls_, SIGNAL(EndClicked()), this, SLOT(GoToEnd())); layout->addWidget(controls_); + // Connect timer + connect(&playback_timer_, SIGNAL(timeout()), this, SLOT(PlaybackTimerUpdate())); + // FIXME: Magic number ruler_->SetScale(48.0); } @@ -67,9 +78,12 @@ ViewerWidget::ViewerWidget(QWidget *parent) : void ViewerWidget::SetTimebase(const rational &r) { time_base_ = r; + time_base_dbl_ = r.toDouble(); ruler_->SetTimebase(r); controls_->SetTimebase(r); + + playback_timer_.setInterval(qFloor(r.toDouble())); } const double &ViewerWidget::scale() @@ -82,6 +96,12 @@ void ViewerWidget::SetScale(const double &scale_) ruler_->SetScale(scale_); } +void ViewerWidget::SetTime(const int64_t &time) +{ + ruler_->SetTime(time); + RulerTimeChange(time); +} + void ViewerWidget::SetTexture(GLuint tex) { gl_widget_->SetTexture(tex); @@ -96,6 +116,61 @@ void ViewerWidget::RulerTimeChange(int64_t i) emit TimeChanged(time_set); } +void ViewerWidget::Play() +{ + if (time_base_.isNull()) { + qWarning() << "ViewerWidget can't play with an invalid timebase"; + return; + } + + start_msec_ = QDateTime::currentMSecsSinceEpoch(); + start_timestamp_ = ruler_->Time(); + + playback_timer_.start(); +} + +void ViewerWidget::Pause() +{ + playback_timer_.stop(); +} + +void ViewerWidget::GoToStart() +{ + Pause(); + + SetTime(0); +} + +void ViewerWidget::PrevFrame() +{ + Pause(); + + SetTime(ruler_->Time() - 1); +} + +void ViewerWidget::NextFrame() +{ + Pause(); + + SetTime(ruler_->Time() + 1); +} + +void ViewerWidget::GoToEnd() +{ + Pause(); + + qWarning() << "No end frame support yet"; +} + +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)); + + SetTime(start_timestamp_ + frames_since_start); +} + void ViewerWidget::resizeEvent(QResizeEvent *event) { // Set scrollbar page step to the width diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index bbb245640..dd6fe825f 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "common/rational.h" @@ -50,6 +51,8 @@ public: void SetScale(const double& scale_); + void SetTime(const int64_t& time); + public slots: /** * @brief Set the texture to draw and draw it @@ -77,8 +80,30 @@ private: rational time_base_; + double time_base_dbl_; + + QTimer playback_timer_; + + qint64 start_msec_; + int64_t start_timestamp_; + private slots: void RulerTimeChange(int64_t i); + + void Play(); + + void Pause(); + + void GoToStart(); + + void PrevFrame(); + + void NextFrame(); + + void GoToEnd(); + + void PlaybackTimerUpdate(); + }; #endif // VIEWER_WIDGET_H