From 7e99b5fb00680c48a0dd44afc82619b9457a6069 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 12 Apr 2024 00:37:27 -0500 Subject: [PATCH] Handle held hotkeys on frame update (paintGL) rather than on key press --- .../source/scwx/qt/manager/hotkey_manager.cpp | 15 +- scwx-qt/source/scwx/qt/map/map_widget.cpp | 188 ++++++++++-------- 2 files changed, 124 insertions(+), 79 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp b/scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp index afcb9124..5ae17ed8 100644 --- a/scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp @@ -66,6 +66,10 @@ void HotkeyManager::Impl::UpdateHotkey(types::Hotkey hotkey, void HotkeyManager::HandleKeyPress(QKeyEvent* ev) { + logger_->trace("HandleKeyPress: {}, {}", + ev->keyCombination().toCombined(), + ev->isAutoRepeat()); + for (auto& hotkey : p->hotkeys_) { if (hotkey.second.count() == 1 && @@ -78,7 +82,16 @@ void HotkeyManager::HandleKeyPress(QKeyEvent* ev) void HotkeyManager::HandleKeyRelease(QKeyEvent* ev) { - Q_UNUSED(ev); + logger_->trace("HandleKeyRelease: {}", ev->keyCombination().toCombined()); + + for (auto& hotkey : p->hotkeys_) + { + if (hotkey.second.count() == 1 && + hotkey.second[0] == ev->keyCombination()) + { + Q_EMIT HotkeyReleased(hotkey.first); + } + } } std::shared_ptr HotkeyManager::Instance() diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 7ba843c1..5a3aa696 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -149,7 +149,9 @@ public: const std::string& before); void ConnectMapSignals(); void ConnectSignals(); - void HandleHotkey(types::Hotkey hotkey, bool isAutoRepeat); + void HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat); + void HandleHotkeyReleased(types::Hotkey hotkey); + void HandleHotkeyUpdates(); void ImGuiCheckFonts(); void InitializeNewRadarProductView(const std::string& colorPalette); void RadarProductManagerConnect(); @@ -232,8 +234,9 @@ public: double prevBearing_; double prevPitch_; - types::Hotkey prevHotkey_ = types::Hotkey::Unknown; + std::set activeHotkeys_ {}; std::chrono::system_clock::time_point prevHotkeyTime_ {}; + public slots: void Update(); }; @@ -342,23 +345,16 @@ void MapWidgetImpl::ConnectSignals() connect(hotkeyManager_.get(), &manager::HotkeyManager::HotkeyPressed, this, - &MapWidgetImpl::HandleHotkey); + &MapWidgetImpl::HandleHotkeyPressed); + connect(hotkeyManager_.get(), + &manager::HotkeyManager::HotkeyReleased, + this, + &MapWidgetImpl::HandleHotkeyReleased); } -void MapWidgetImpl::HandleHotkey(types::Hotkey hotkey, bool isAutoRepeat) +void MapWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat) { - static constexpr float kMapPanFactor = 0.2f; - static constexpr float kMapRotateFactor = 0.2f; - static constexpr double kMapScaleFactor = 1000.0; - - using namespace std::chrono_literals; - - std::chrono::system_clock::time_point hotkeyTime = - std::chrono::system_clock::now(); - std::chrono::milliseconds hotkeyElapsed = - isAutoRepeat ? std::chrono::duration_cast( - hotkeyTime - prevHotkeyTime_) : - 100ms; + Q_UNUSED(isAutoRepeat); switch (hotkey) { @@ -386,72 +382,105 @@ void MapWidgetImpl::HandleHotkey(types::Hotkey hotkey, bool isAutoRepeat) break; } - case types::Hotkey::MapPanUp: - { - QPointF delta {0.0f, kMapPanFactor * hotkeyElapsed.count()}; - map_->moveBy(delta); - break; - } - - case types::Hotkey::MapPanDown: - { - QPointF delta {0.0f, -kMapPanFactor * hotkeyElapsed.count()}; - map_->moveBy(delta); - break; - } - - case types::Hotkey::MapPanLeft: - { - QPointF delta {kMapPanFactor * hotkeyElapsed.count(), 0.0f}; - map_->moveBy(delta); - break; - } - - case types::Hotkey::MapPanRight: - { - QPointF delta {-kMapPanFactor * hotkeyElapsed.count(), 0.0f}; - map_->moveBy(delta); - break; - } - - case types::Hotkey::MapRotateClockwise: - { - QPointF delta {-kMapRotateFactor * hotkeyElapsed.count(), 0.0f}; - map_->rotateBy({}, delta); - break; - } - - case types::Hotkey::MapRotateCounterclockwise: - { - QPointF delta {kMapRotateFactor * hotkeyElapsed.count(), 0.0f}; - map_->rotateBy({}, delta); - break; - } - - case types::Hotkey::MapZoomIn: - { - auto widgetSize = widget_->size(); - QPointF center = {widgetSize.width() * 0.5f, widgetSize.height() * 0.5f}; - double scale = std::pow(2.0, hotkeyElapsed.count() / kMapScaleFactor); - map_->scaleBy(scale, center); - break; - } - - case types::Hotkey::MapZoomOut: - { - auto widgetSize = widget_->size(); - QPointF center = {widgetSize.width() * 0.5f, widgetSize.height() * 0.5f}; - double scale = - 1.0 / std::pow(2.0, hotkeyElapsed.count() / kMapScaleFactor); - map_->scaleBy(scale, center); - break; - } - default: break; } - prevHotkey_ = hotkey; + activeHotkeys_.insert(hotkey); +} + +void MapWidgetImpl::HandleHotkeyReleased(types::Hotkey hotkey) +{ + activeHotkeys_.erase(hotkey); +} + +void MapWidgetImpl::HandleHotkeyUpdates() +{ + using namespace std::chrono_literals; + + static constexpr float kMapPanFactor = 0.2f; + static constexpr float kMapRotateFactor = 0.2f; + static constexpr double kMapScaleFactor = 1000.0; + + std::chrono::system_clock::time_point hotkeyTime = + std::chrono::system_clock::now(); + std::chrono::milliseconds hotkeyElapsed = + std::min(std::chrono::duration_cast( + hotkeyTime - prevHotkeyTime_), + 100ms); + + for (auto& hotkey : activeHotkeys_) + { + switch (hotkey) + { + case types::Hotkey::MapPanUp: + { + QPointF delta {0.0f, kMapPanFactor * hotkeyElapsed.count()}; + map_->moveBy(delta); + break; + } + + case types::Hotkey::MapPanDown: + { + QPointF delta {0.0f, -kMapPanFactor * hotkeyElapsed.count()}; + map_->moveBy(delta); + break; + } + + case types::Hotkey::MapPanLeft: + { + QPointF delta {kMapPanFactor * hotkeyElapsed.count(), 0.0f}; + map_->moveBy(delta); + break; + } + + case types::Hotkey::MapPanRight: + { + QPointF delta {-kMapPanFactor * hotkeyElapsed.count(), 0.0f}; + map_->moveBy(delta); + break; + } + + case types::Hotkey::MapRotateClockwise: + { + QPointF delta {-kMapRotateFactor * hotkeyElapsed.count(), 0.0f}; + map_->rotateBy({}, delta); + break; + } + + case types::Hotkey::MapRotateCounterclockwise: + { + QPointF delta {kMapRotateFactor * hotkeyElapsed.count(), 0.0f}; + map_->rotateBy({}, delta); + break; + } + + case types::Hotkey::MapZoomIn: + { + auto widgetSize = widget_->size(); + QPointF center = {widgetSize.width() * 0.5f, + widgetSize.height() * 0.5f}; + double scale = std::pow(2.0, hotkeyElapsed.count() / kMapScaleFactor); + map_->scaleBy(scale, center); + break; + } + + case types::Hotkey::MapZoomOut: + { + auto widgetSize = widget_->size(); + QPointF center = {widgetSize.width() * 0.5f, + widgetSize.height() * 0.5f}; + double scale = + 1.0 / std::pow(2.0, hotkeyElapsed.count() / kMapScaleFactor); + map_->scaleBy(scale, center); + break; + } + + default: + break; + } + } + prevHotkeyTime_ = hotkeyTime; } @@ -1319,6 +1348,9 @@ void MapWidget::paintGL() p->frameDraws_++; + // Handle hotkey updates + p->HandleHotkeyUpdates(); + // Setup ImGui Frame ImGui::SetCurrentContext(p->imGuiContext_);