From 41b9e25ea899ba8e904c7f67392b6e0817eb43ce Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 27 May 2023 00:22:34 -0500 Subject: [PATCH] Timeline play --- .../scwx/qt/manager/timeline_manager.cpp | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/scwx-qt/source/scwx/qt/manager/timeline_manager.cpp b/scwx-qt/source/scwx/qt/manager/timeline_manager.cpp index 2ebd038e..534daed7 100644 --- a/scwx-qt/source/scwx/qt/manager/timeline_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/timeline_manager.cpp @@ -7,6 +7,7 @@ #include +#include #include namespace scwx @@ -33,11 +34,15 @@ public: ~Impl() { // Lock mutexes before destroying + std::unique_lock animationTimerLock {animationTimerMutex_}; + animationTimer_.cancel(); + std::unique_lock selectTimeLock {selectTimeMutex_}; } TimelineManager* self_; + void Play(); void SelectTime(std::chrono::system_clock::time_point selectedTime = {}); void Step(Direction direction); @@ -50,6 +55,9 @@ public: std::chrono::minutes loopTime_ {30}; double loopSpeed_ {1.0}; + boost::asio::steady_timer animationTimer_ {scwx::util::io_context()}; + std::mutex animationTimerMutex_ {}; + std::mutex selectTimeMutex_ {}; }; @@ -125,6 +133,11 @@ void TimelineManager::SetLoopSpeed(double loopSpeed) { logger_->debug("SetLoopSpeed: {}", loopSpeed); + if (loopSpeed < 1.0) + { + loopSpeed = 1.0; + } + p->loopSpeed_ = loopSpeed; } @@ -155,6 +168,8 @@ void TimelineManager::AnimationStepBack() void TimelineManager::AnimationPlay() { logger_->debug("AnimationPlay"); + + p->Play(); } void TimelineManager::AnimationPause() @@ -185,6 +200,80 @@ void TimelineManager::AnimationStepEnd() } } +void TimelineManager::Impl::Play() +{ + using namespace std::chrono_literals; + + { + std::unique_lock animationTimerLock {animationTimerMutex_}; + animationTimer_.cancel(); + } + + scwx::util::async( + [this]() + { + // Take a lock for time selection + std::unique_lock lock {selectTimeMutex_}; + + // Determine loop end time + std::chrono::system_clock::time_point endTime; + + if (viewType_ == types::MapTime::Live || + pinnedTime_ == std::chrono::system_clock::time_point {}) + { + endTime = std::chrono::floor( + std::chrono::system_clock::now()); + } + else + { + endTime = pinnedTime_; + } + + // Determine loop start time and current position in the loop + std::chrono::system_clock::time_point startTime = endTime - loopTime_; + std::chrono::system_clock::time_point currentTime = selectedTime_; + + // Unlock prior to selecting time + lock.unlock(); + + if (currentTime < startTime || currentTime >= endTime) + { + // If the currently selected time is out of the loop, select the + // start time + SelectTime(startTime); + } + else + { + // If the currently selected time is in the loop, increment + SelectTime(currentTime + 1min); + } + + // Determine repeat interval (loop speed of 1.0 is 1 minute per second) + std::chrono::milliseconds interval = + std::chrono::milliseconds(std::lroundl(1000.0 / loopSpeed_)); + + std::unique_lock animationTimerLock {animationTimerMutex_}; + + animationTimer_.expires_after(interval); + animationTimer_.async_wait( + [this](const boost::system::error_code& e) + { + if (e == boost::system::errc::success) + { + Play(); + } + else if (e == boost::asio::error::operation_aborted) + { + logger_->debug("Play timer cancelled"); + } + else + { + logger_->warn("Play timer error: {}", e.message()); + } + }); + }); +} + void TimelineManager::Impl::SelectTime( std::chrono::system_clock::time_point selectedTime) {