mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:20:06 +00:00 
			
		
		
		
	
						commit
						83e3291db2
					
				
					 27 changed files with 1466 additions and 68 deletions
				
			
		
							
								
								
									
										1
									
								
								scwx-qt/res/icons/font-awesome-6/keyboard-regular.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								scwx-qt/res/icons/font-awesome-6/keyboard-regular.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M64 112c-8.8 0-16 7.2-16 16V384c0 8.8 7.2 16 16 16H512c8.8 0 16-7.2 16-16V128c0-8.8-7.2-16-16-16H64zM0 128C0 92.7 28.7 64 64 64H512c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128zM176 320H400c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H176c-8.8 0-16-7.2-16-16V336c0-8.8 7.2-16 16-16zm-72-72c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H120c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H120c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H200c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H200c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H280c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H280c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H360c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H360c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16zm64 96c0-8.8 7.2-16 16-16h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H440c-8.8 0-16-7.2-16-16V248zm16-96h16c8.8 0 16 7.2 16 16v16c0 8.8-7.2 16-16 16H440c-8.8 0-16-7.2-16-16V168c0-8.8 7.2-16 16-16z"/></svg> | ||||
| After Width: | Height: | Size: 1.5 KiB | 
|  | @ -88,6 +88,7 @@ set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp | |||
| set(HDR_MANAGER source/scwx/qt/manager/alert_manager.hpp | ||||
|                 source/scwx/qt/manager/download_manager.hpp | ||||
|                 source/scwx/qt/manager/font_manager.hpp | ||||
|                 source/scwx/qt/manager/hotkey_manager.hpp | ||||
|                 source/scwx/qt/manager/media_manager.hpp | ||||
|                 source/scwx/qt/manager/placefile_manager.hpp | ||||
|                 source/scwx/qt/manager/position_manager.hpp | ||||
|  | @ -101,6 +102,7 @@ set(HDR_MANAGER source/scwx/qt/manager/alert_manager.hpp | |||
| set(SRC_MANAGER source/scwx/qt/manager/alert_manager.cpp | ||||
|                 source/scwx/qt/manager/download_manager.cpp | ||||
|                 source/scwx/qt/manager/font_manager.cpp | ||||
|                 source/scwx/qt/manager/hotkey_manager.cpp | ||||
|                 source/scwx/qt/manager/media_manager.cpp | ||||
|                 source/scwx/qt/manager/placefile_manager.cpp | ||||
|                 source/scwx/qt/manager/position_manager.cpp | ||||
|  | @ -162,6 +164,7 @@ set(SRC_REQUEST source/scwx/qt/request/download_request.cpp | |||
|                 source/scwx/qt/request/nexrad_file_request.cpp) | ||||
| set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp | ||||
|                  source/scwx/qt/settings/general_settings.hpp | ||||
|                  source/scwx/qt/settings/hotkey_settings.hpp | ||||
|                  source/scwx/qt/settings/map_settings.hpp | ||||
|                  source/scwx/qt/settings/palette_settings.hpp | ||||
|                  source/scwx/qt/settings/product_settings.hpp | ||||
|  | @ -176,6 +179,7 @@ set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp | |||
|                  source/scwx/qt/settings/ui_settings.hpp) | ||||
| set(SRC_SETTINGS source/scwx/qt/settings/audio_settings.cpp | ||||
|                  source/scwx/qt/settings/general_settings.cpp | ||||
|                  source/scwx/qt/settings/hotkey_settings.cpp | ||||
|                  source/scwx/qt/settings/map_settings.cpp | ||||
|                  source/scwx/qt/settings/palette_settings.cpp | ||||
|                  source/scwx/qt/settings/product_settings.cpp | ||||
|  | @ -191,6 +195,7 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp | |||
|               source/scwx/qt/types/event_types.hpp | ||||
|               source/scwx/qt/types/font_types.hpp | ||||
|               source/scwx/qt/types/github_types.hpp | ||||
|               source/scwx/qt/types/hotkey_types.hpp | ||||
|               source/scwx/qt/types/icon_types.hpp | ||||
|               source/scwx/qt/types/imgui_font.hpp | ||||
|               source/scwx/qt/types/layer_types.hpp | ||||
|  | @ -205,6 +210,7 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp | |||
|               source/scwx/qt/types/time_types.hpp) | ||||
| set(SRC_TYPES source/scwx/qt/types/alert_types.cpp | ||||
|               source/scwx/qt/types/github_types.cpp | ||||
|               source/scwx/qt/types/hotkey_types.cpp | ||||
|               source/scwx/qt/types/icon_types.cpp | ||||
|               source/scwx/qt/types/imgui_font.cpp | ||||
|               source/scwx/qt/types/layer_types.cpp | ||||
|  | @ -225,6 +231,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp | |||
|            source/scwx/qt/ui/county_dialog.hpp | ||||
|            source/scwx/qt/ui/download_dialog.hpp | ||||
|            source/scwx/qt/ui/flow_layout.hpp | ||||
|            source/scwx/qt/ui/hotkey_edit.hpp | ||||
|            source/scwx/qt/ui/imgui_debug_dialog.hpp | ||||
|            source/scwx/qt/ui/imgui_debug_widget.hpp | ||||
|            source/scwx/qt/ui/layer_dialog.hpp | ||||
|  | @ -247,6 +254,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp | |||
|            source/scwx/qt/ui/county_dialog.cpp | ||||
|            source/scwx/qt/ui/download_dialog.cpp | ||||
|            source/scwx/qt/ui/flow_layout.cpp | ||||
|            source/scwx/qt/ui/hotkey_edit.cpp | ||||
|            source/scwx/qt/ui/imgui_debug_dialog.cpp | ||||
|            source/scwx/qt/ui/imgui_debug_widget.cpp | ||||
|            source/scwx/qt/ui/layer_dialog.cpp | ||||
|  | @ -276,6 +284,10 @@ set(UI_UI  source/scwx/qt/ui/about_dialog.ui | |||
|            source/scwx/qt/ui/radar_site_dialog.ui | ||||
|            source/scwx/qt/ui/settings_dialog.ui | ||||
|            source/scwx/qt/ui/update_dialog.ui) | ||||
| set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp | ||||
|                     source/scwx/qt/ui/settings/settings_page_widget.hpp) | ||||
| set(SRC_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.cpp | ||||
|                     source/scwx/qt/ui/settings/settings_page_widget.cpp) | ||||
| set(HDR_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.hpp | ||||
|                  source/scwx/qt/ui/setup/finish_page.hpp | ||||
|                  source/scwx/qt/ui/setup/map_layout_page.hpp | ||||
|  | @ -387,6 +399,8 @@ set(PROJECT_SOURCES ${HDR_MAIN} | |||
|                     ${HDR_UI} | ||||
|                     ${SRC_UI} | ||||
|                     ${UI_UI} | ||||
|                     ${HDR_UI_SETTINGS} | ||||
|                     ${SRC_UI_SETTINGS} | ||||
|                     ${HDR_UI_SETUP} | ||||
|                     ${SRC_UI_SETUP} | ||||
|                     ${HDR_UTIL} | ||||
|  | @ -424,6 +438,8 @@ source_group("Header Files\\types"     FILES ${HDR_TYPES}) | |||
| source_group("Source Files\\types"        FILES ${SRC_TYPES}) | ||||
| source_group("Header Files\\ui"           FILES ${HDR_UI}) | ||||
| source_group("Source Files\\ui"           FILES ${SRC_UI}) | ||||
| source_group("Header Files\\ui\\settings" FILES ${HDR_UI_SETTINGS}) | ||||
| source_group("Source Files\\ui\\settings" FILES ${SRC_UI_SETTINGS}) | ||||
| source_group("Header Files\\ui\\setup"    FILES ${HDR_UI_SETUP}) | ||||
| source_group("Source Files\\ui\\setup"    FILES ${SRC_UI_SETUP}) | ||||
| source_group("UI Files\\ui"               FILES ${UI_UI}) | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ | |||
|         <file>res/icons/font-awesome-6/gears-solid.svg</file> | ||||
|         <file>res/icons/font-awesome-6/github.svg</file> | ||||
|         <file>res/icons/font-awesome-6/house-solid.svg</file> | ||||
|         <file>res/icons/font-awesome-6/keyboard-regular.svg</file> | ||||
|         <file>res/icons/font-awesome-6/layer-group-solid.svg</file> | ||||
|         <file>res/icons/font-awesome-6/palette-solid.svg</file> | ||||
|         <file>res/icons/font-awesome-6/pause-solid.svg</file> | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <scwx/qt/main/application.hpp> | ||||
| #include <scwx/qt/main/versions.hpp> | ||||
| #include <scwx/qt/manager/alert_manager.hpp> | ||||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/qt/manager/placefile_manager.hpp> | ||||
| #include <scwx/qt/manager/position_manager.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
|  | @ -42,6 +43,7 @@ | |||
| #include <boost/asio/post.hpp> | ||||
| #include <boost/asio/thread_pool.hpp> | ||||
| #include <QDesktopServices> | ||||
| #include <QKeyEvent> | ||||
| #include <QFileDialog> | ||||
| #include <QMessageBox> | ||||
| #include <QSplitter> | ||||
|  | @ -198,6 +200,8 @@ public: | |||
|    QTimer clockTimer_ {}; | ||||
| 
 | ||||
|    std::shared_ptr<manager::AlertManager>  alertManager_; | ||||
|    std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { | ||||
|       manager::HotkeyManager::Instance()}; | ||||
|    std::shared_ptr<manager::PlacefileManager> placefileManager_; | ||||
|    std::shared_ptr<manager::PositionManager>  positionManager_; | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
|  | @ -398,6 +402,24 @@ MainWindow::~MainWindow() | |||
|    delete ui; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::keyPressEvent(QKeyEvent* ev) | ||||
| { | ||||
|    if (p->hotkeyManager_->HandleKeyPress(ev)) | ||||
|    { | ||||
|       p->activeMap_->update(); | ||||
|       ev->accept(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::keyReleaseEvent(QKeyEvent* ev) | ||||
| { | ||||
|    if (p->hotkeyManager_->HandleKeyRelease(ev)) | ||||
|    { | ||||
|       p->activeMap_->update(); | ||||
|       ev->accept(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::showEvent(QShowEvent* event) | ||||
| { | ||||
|    QMainWindow::showEvent(event); | ||||
|  |  | |||
|  | @ -26,6 +26,8 @@ public: | |||
|    MainWindow(QWidget* parent = nullptr); | ||||
|    ~MainWindow(); | ||||
| 
 | ||||
|    void keyPressEvent(QKeyEvent* ev) override final; | ||||
|    void keyReleaseEvent(QKeyEvent* ev) override final; | ||||
|    void showEvent(QShowEvent* event) override; | ||||
| 
 | ||||
| signals: | ||||
|  |  | |||
							
								
								
									
										128
									
								
								scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								scwx-qt/source/scwx/qt/manager/hotkey_manager.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,128 @@ | |||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/qt/settings/hotkey_settings.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| #include <boost/container/flat_map.hpp> | ||||
| #include <QKeyEvent> | ||||
| #include <QKeySequence> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace manager | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::manager::hotkey_manager"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class HotkeyManager::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl() | ||||
|    { | ||||
|       auto& hotkeySettings = settings::HotkeySettings::Instance(); | ||||
| 
 | ||||
|       for (auto hotkey : types::HotkeyIterator()) | ||||
|       { | ||||
|          auto& hotkeyVariable = hotkeySettings.hotkey(hotkey); | ||||
| 
 | ||||
|          UpdateHotkey(hotkey, hotkeyVariable.GetValue()); | ||||
| 
 | ||||
|          callbacks_.emplace_back(hotkeyVariable, | ||||
|                                  hotkeyVariable.RegisterValueChangedCallback( | ||||
|                                     [this, hotkey](const std::string& value) | ||||
|                                     { UpdateHotkey(hotkey, value); })); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    ~Impl() | ||||
|    { | ||||
|       for (auto& callback : callbacks_) | ||||
|       { | ||||
|          callback.first.UnregisterValueChangedCallback(callback.second); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    void UpdateHotkey(types::Hotkey hotkey, const std::string& value); | ||||
| 
 | ||||
|    std::vector< | ||||
|       std::pair<settings::SettingsVariable<std::string>&, boost::uuids::uuid>> | ||||
|                                                            callbacks_ {}; | ||||
|    boost::container::flat_map<types::Hotkey, QKeySequence> hotkeys_ {}; | ||||
| }; | ||||
| 
 | ||||
| HotkeyManager::HotkeyManager() : p(std::make_unique<Impl>()) {} | ||||
| HotkeyManager::~HotkeyManager() = default; | ||||
| 
 | ||||
| void HotkeyManager::Impl::UpdateHotkey(types::Hotkey      hotkey, | ||||
|                                        const std::string& value) | ||||
| { | ||||
|    hotkeys_.insert_or_assign(hotkey, | ||||
|                              QKeySequence {QString::fromStdString(value)}); | ||||
| } | ||||
| 
 | ||||
| bool HotkeyManager::HandleKeyPress(QKeyEvent* ev) | ||||
| { | ||||
|    logger_->trace("HandleKeyPress: {}, {}", | ||||
|                   ev->keyCombination().toCombined(), | ||||
|                   ev->isAutoRepeat()); | ||||
| 
 | ||||
|    bool hotkeyPressed = false; | ||||
| 
 | ||||
|    for (auto& hotkey : p->hotkeys_) | ||||
|    { | ||||
|       if (hotkey.second.count() == 1 && | ||||
|           hotkey.second[0] == ev->keyCombination()) | ||||
|       { | ||||
|          hotkeyPressed = true; | ||||
|          Q_EMIT HotkeyPressed(hotkey.first, ev->isAutoRepeat()); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    return hotkeyPressed; | ||||
| } | ||||
| 
 | ||||
| bool HotkeyManager::HandleKeyRelease(QKeyEvent* ev) | ||||
| { | ||||
|    logger_->trace("HandleKeyRelease: {}", ev->keyCombination().toCombined()); | ||||
| 
 | ||||
|    bool hotkeyReleased = false; | ||||
| 
 | ||||
|    for (auto& hotkey : p->hotkeys_) | ||||
|    { | ||||
|       if (hotkey.second.count() == 1 && | ||||
|           hotkey.second[0] == ev->keyCombination()) | ||||
|       { | ||||
|          hotkeyReleased = true; | ||||
|          Q_EMIT HotkeyReleased(hotkey.first); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    return hotkeyReleased; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<HotkeyManager> HotkeyManager::Instance() | ||||
| { | ||||
|    static std::weak_ptr<HotkeyManager> hotkeyManagerReference_ {}; | ||||
|    static std::mutex                   instanceMutex_ {}; | ||||
| 
 | ||||
|    std::unique_lock lock(instanceMutex_); | ||||
| 
 | ||||
|    std::shared_ptr<HotkeyManager> hotkeyManager = | ||||
|       hotkeyManagerReference_.lock(); | ||||
| 
 | ||||
|    if (hotkeyManager == nullptr) | ||||
|    { | ||||
|       hotkeyManager           = std::make_shared<HotkeyManager>(); | ||||
|       hotkeyManagerReference_ = hotkeyManager; | ||||
|    } | ||||
| 
 | ||||
|    return hotkeyManager; | ||||
| } | ||||
| 
 | ||||
| } // namespace manager
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										43
									
								
								scwx-qt/source/scwx/qt/manager/hotkey_manager.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								scwx-qt/source/scwx/qt/manager/hotkey_manager.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/types/hotkey_types.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <QObject> | ||||
| 
 | ||||
| class QKeyEvent; | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace manager | ||||
| { | ||||
| 
 | ||||
| class HotkeyManager : public QObject | ||||
| { | ||||
|    Q_OBJECT | ||||
|    Q_DISABLE_COPY_MOVE(HotkeyManager) | ||||
| 
 | ||||
| public: | ||||
|    explicit HotkeyManager(); | ||||
|    ~HotkeyManager(); | ||||
| 
 | ||||
|    bool HandleKeyPress(QKeyEvent* event); | ||||
|    bool HandleKeyRelease(QKeyEvent* event); | ||||
| 
 | ||||
|    static std::shared_ptr<HotkeyManager> Instance(); | ||||
| 
 | ||||
| signals: | ||||
|    void HotkeyPressed(scwx::qt::types::Hotkey hotkey, bool isAutoRepeat); | ||||
|    void HotkeyReleased(scwx::qt::types::Hotkey hotkey); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace manager
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -2,6 +2,7 @@ | |||
| #include <scwx/qt/map/map_provider.hpp> | ||||
| #include <scwx/qt/settings/audio_settings.hpp> | ||||
| #include <scwx/qt/settings/general_settings.hpp> | ||||
| #include <scwx/qt/settings/hotkey_settings.hpp> | ||||
| #include <scwx/qt/settings/map_settings.hpp> | ||||
| #include <scwx/qt/settings/palette_settings.hpp> | ||||
| #include <scwx/qt/settings/product_settings.hpp> | ||||
|  | @ -132,6 +133,7 @@ boost::json::value SettingsManager::Impl::ConvertSettingsToJson() | |||
| 
 | ||||
|    settings::GeneralSettings::Instance().WriteJson(settingsJson); | ||||
|    settings::AudioSettings::Instance().WriteJson(settingsJson); | ||||
|    settings::HotkeySettings::Instance().WriteJson(settingsJson); | ||||
|    settings::MapSettings::Instance().WriteJson(settingsJson); | ||||
|    settings::PaletteSettings::Instance().WriteJson(settingsJson); | ||||
|    settings::ProductSettings::Instance().WriteJson(settingsJson); | ||||
|  | @ -147,6 +149,7 @@ void SettingsManager::Impl::GenerateDefaultSettings() | |||
| 
 | ||||
|    settings::GeneralSettings::Instance().SetDefaults(); | ||||
|    settings::AudioSettings::Instance().SetDefaults(); | ||||
|    settings::HotkeySettings::Instance().SetDefaults(); | ||||
|    settings::MapSettings::Instance().SetDefaults(); | ||||
|    settings::PaletteSettings::Instance().SetDefaults(); | ||||
|    settings::ProductSettings::Instance().SetDefaults(); | ||||
|  | @ -163,6 +166,7 @@ bool SettingsManager::Impl::LoadSettings( | |||
| 
 | ||||
|    jsonDirty |= !settings::GeneralSettings::Instance().ReadJson(settingsJson); | ||||
|    jsonDirty |= !settings::AudioSettings::Instance().ReadJson(settingsJson); | ||||
|    jsonDirty |= !settings::HotkeySettings::Instance().ReadJson(settingsJson); | ||||
|    jsonDirty |= !settings::MapSettings::Instance().ReadJson(settingsJson); | ||||
|    jsonDirty |= !settings::PaletteSettings::Instance().ReadJson(settingsJson); | ||||
|    jsonDirty |= !settings::ProductSettings::Instance().ReadJson(settingsJson); | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| #include <scwx/qt/map/map_widget.hpp> | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| #include <scwx/qt/manager/font_manager.hpp> | ||||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/qt/manager/placefile_manager.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
| #include <scwx/qt/map/alert_layer.hpp> | ||||
|  | @ -39,6 +40,7 @@ | |||
| #include <imgui.h> | ||||
| #include <re2/re2.h> | ||||
| #include <QApplication> | ||||
| #include <QClipboard> | ||||
| #include <QColor> | ||||
| #include <QDebug> | ||||
| #include <QFile> | ||||
|  | @ -147,6 +149,9 @@ public: | |||
|                           const std::string& before); | ||||
|    void ConnectMapSignals(); | ||||
|    void ConnectSignals(); | ||||
|    void HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat); | ||||
|    void HandleHotkeyReleased(types::Hotkey hotkey); | ||||
|    void HandleHotkeyUpdates(); | ||||
|    void ImGuiCheckFonts(); | ||||
|    void InitializeNewRadarProductView(const std::string& colorPalette); | ||||
|    void RadarProductManagerConnect(); | ||||
|  | @ -190,6 +195,8 @@ public: | |||
|    std::shared_ptr<model::LayerModel> layerModel_ { | ||||
|       model::LayerModel::Instance()}; | ||||
| 
 | ||||
|    std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { | ||||
|       manager::HotkeyManager::Instance()}; | ||||
|    std::shared_ptr<manager::PlacefileManager> placefileManager_ { | ||||
|       manager::PlacefileManager::Instance()}; | ||||
|    std::shared_ptr<manager::RadarProductManager> radarProductManager_; | ||||
|  | @ -227,6 +234,9 @@ public: | |||
|    double prevBearing_; | ||||
|    double prevPitch_; | ||||
| 
 | ||||
|    std::set<types::Hotkey>               activeHotkeys_ {}; | ||||
|    std::chrono::system_clock::time_point prevHotkeyTime_ {}; | ||||
| 
 | ||||
| public slots: | ||||
|    void Update(); | ||||
| }; | ||||
|  | @ -331,6 +341,160 @@ void MapWidgetImpl::ConnectSignals() | |||
|            [this](const QModelIndex& /* parent */, //
 | ||||
|                   int /* first */, | ||||
|                   int /* last */) { AddLayers(); }); | ||||
| 
 | ||||
|    connect(hotkeyManager_.get(), | ||||
|            &manager::HotkeyManager::HotkeyPressed, | ||||
|            this, | ||||
|            &MapWidgetImpl::HandleHotkeyPressed); | ||||
|    connect(hotkeyManager_.get(), | ||||
|            &manager::HotkeyManager::HotkeyReleased, | ||||
|            this, | ||||
|            &MapWidgetImpl::HandleHotkeyReleased); | ||||
| } | ||||
| 
 | ||||
| void MapWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat) | ||||
| { | ||||
|    Q_UNUSED(isAutoRepeat); | ||||
| 
 | ||||
|    switch (hotkey) | ||||
|    { | ||||
|    case types::Hotkey::ChangeMapStyle: | ||||
|       if (context_->settings().isActive_) | ||||
|       { | ||||
|          widget_->changeStyle(); | ||||
|       } | ||||
|       break; | ||||
| 
 | ||||
|    case types::Hotkey::CopyCursorCoordinates: | ||||
|       if (hasMouse_) | ||||
|       { | ||||
|          QClipboard* clipboard  = QGuiApplication::clipboard(); | ||||
|          auto        coordinate = map_->coordinateForPixel(lastPos_); | ||||
|          std::string text = | ||||
|             fmt::format("{}, {}", coordinate.first, coordinate.second); | ||||
|          clipboard->setText(QString::fromStdString(text)); | ||||
|       } | ||||
|       break; | ||||
| 
 | ||||
|    case types::Hotkey::CopyMapCoordinates: | ||||
|       if (context_->settings().isActive_) | ||||
|       { | ||||
|          QClipboard* clipboard  = QGuiApplication::clipboard(); | ||||
|          auto        coordinate = map_->coordinate(); | ||||
|          std::string text = | ||||
|             fmt::format("{}, {}", coordinate.first, coordinate.second); | ||||
|          clipboard->setText(QString::fromStdString(text)); | ||||
|       } | ||||
|       break; | ||||
| 
 | ||||
|    default: | ||||
|       break; | ||||
|    } | ||||
| 
 | ||||
|    activeHotkeys_.insert(hotkey); | ||||
| } | ||||
| 
 | ||||
| void MapWidgetImpl::HandleHotkeyReleased(types::Hotkey hotkey) | ||||
| { | ||||
|    // Erase the hotkey from the active set regardless of whether this is the
 | ||||
|    // active map
 | ||||
|    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<std::chrono::milliseconds>( | ||||
|                   hotkeyTime - prevHotkeyTime_), | ||||
|                100ms); | ||||
| 
 | ||||
|    prevHotkeyTime_ = hotkeyTime; | ||||
| 
 | ||||
|    if (!context_->settings().isActive_) | ||||
|    { | ||||
|       // Don't attempt to handle a hotkey if this is not the active map
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    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; | ||||
|       } | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| common::Level3ProductCategoryMap MapWidget::GetAvailableLevel3Categories() | ||||
|  | @ -1061,16 +1225,18 @@ void MapWidget::leaveEvent(QEvent* /* ev */) | |||
| 
 | ||||
| void MapWidget::keyPressEvent(QKeyEvent* ev) | ||||
| { | ||||
|    switch (ev->key()) | ||||
|    if (p->hotkeyManager_->HandleKeyPress(ev)) | ||||
|    { | ||||
|    case Qt::Key_S: | ||||
|       changeStyle(); | ||||
|       break; | ||||
|    default: | ||||
|       break; | ||||
|    } | ||||
| 
 | ||||
|       ev->accept(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void MapWidget::keyReleaseEvent(QKeyEvent* ev) | ||||
| { | ||||
|    if (p->hotkeyManager_->HandleKeyRelease(ev)) | ||||
|    { | ||||
|       ev->accept(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void MapWidget::mousePressEvent(QMouseEvent* ev) | ||||
|  | @ -1197,6 +1363,9 @@ void MapWidget::paintGL() | |||
| 
 | ||||
|    p->frameDraws_++; | ||||
| 
 | ||||
|    // Handle hotkey updates
 | ||||
|    p->HandleHotkeyUpdates(); | ||||
| 
 | ||||
|    // Setup ImGui Frame
 | ||||
|    ImGui::SetCurrentContext(p->imGuiContext_); | ||||
| 
 | ||||
|  |  | |||
|  | @ -125,6 +125,7 @@ private: | |||
|    bool event(QEvent* e) override; | ||||
|    void enterEvent(QEnterEvent* ev) override final; | ||||
|    void keyPressEvent(QKeyEvent* ev) override final; | ||||
|    void keyReleaseEvent(QKeyEvent* ev) override final; | ||||
|    void leaveEvent(QEvent* ev) override final; | ||||
|    void mousePressEvent(QMouseEvent* ev) override final; | ||||
|    void mouseMoveEvent(QMouseEvent* ev) override final; | ||||
|  |  | |||
							
								
								
									
										126
									
								
								scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,126 @@ | |||
| #include <scwx/qt/settings/hotkey_settings.hpp> | ||||
| 
 | ||||
| #include <QKeySequence> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace settings | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::settings::hotkey_settings"; | ||||
| 
 | ||||
| static const std::unordered_map<types::Hotkey, QKeySequence> kDefaultHotkeys_ { | ||||
|    {types::Hotkey::ChangeMapStyle, QKeySequence {Qt::Key::Key_Z}}, | ||||
|    {types::Hotkey::CopyCursorCoordinates, | ||||
|     QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier, | ||||
|                                    Qt::Key::Key_C}}}, | ||||
|    {types::Hotkey::CopyMapCoordinates, | ||||
|     QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier | | ||||
|                                       Qt::KeyboardModifier::ShiftModifier, | ||||
|                                    Qt::Key::Key_C}}}, | ||||
|    {types::Hotkey::MapPanUp, QKeySequence {Qt::Key::Key_W}}, | ||||
|    {types::Hotkey::MapPanDown, QKeySequence {Qt::Key::Key_S}}, | ||||
|    {types::Hotkey::MapPanLeft, QKeySequence {Qt::Key::Key_A}}, | ||||
|    {types::Hotkey::MapPanRight, QKeySequence {Qt::Key::Key_D}}, | ||||
|    {types::Hotkey::MapRotateClockwise, QKeySequence {Qt::Key::Key_E}}, | ||||
|    {types::Hotkey::MapRotateCounterclockwise, QKeySequence {Qt::Key::Key_Q}}, | ||||
|    {types::Hotkey::MapZoomIn, QKeySequence {Qt::Key::Key_Equal}}, | ||||
|    {types::Hotkey::MapZoomOut, QKeySequence {Qt::Key::Key_Minus}}, | ||||
|    {types::Hotkey::ProductTiltDecrease, | ||||
|     QKeySequence {Qt::Key::Key_BracketLeft}}, | ||||
|    {types::Hotkey::ProductTiltIncrease, | ||||
|     QKeySequence {Qt::Key::Key_BracketRight}}, | ||||
|    {types::Hotkey::TimelineStepBegin, | ||||
|     QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier, | ||||
|                                    Qt::Key::Key_Left}}}, | ||||
|    {types::Hotkey::TimelineStepBack, QKeySequence {Qt::Key::Key_Left}}, | ||||
|    {types::Hotkey::TimelinePlay, QKeySequence {Qt::Key::Key_Space}}, | ||||
|    {types::Hotkey::TimelineStepNext, QKeySequence {Qt::Key::Key_Right}}, | ||||
|    {types::Hotkey::TimelineStepEnd, | ||||
|     QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier, | ||||
|                                    Qt::Key::Key_Right}}}, | ||||
|    {types::Hotkey::Unknown, QKeySequence {}}}; | ||||
| 
 | ||||
| static bool IsHotkeyValid(const std::string& value); | ||||
| 
 | ||||
| class HotkeySettings::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl() | ||||
|    { | ||||
|       for (const auto& hotkey : types::HotkeyIterator()) | ||||
|       { | ||||
|          const std::string& name = types::GetHotkeyShortName(hotkey); | ||||
|          const std::string  defaultValue = | ||||
|             kDefaultHotkeys_.at(hotkey).toString().toStdString(); | ||||
| 
 | ||||
|          auto result = | ||||
|             hotkey_.emplace(hotkey, SettingsVariable<std::string> {name}); | ||||
| 
 | ||||
|          SettingsVariable<std::string>& settingsVariable = result.first->second; | ||||
| 
 | ||||
|          settingsVariable.SetDefault(defaultValue); | ||||
|          settingsVariable.SetValidator(&IsHotkeyValid); | ||||
| 
 | ||||
|          variables_.push_back(&settingsVariable); | ||||
|       } | ||||
| 
 | ||||
|       // Add an empty hotkey (not part of registered variables) for error
 | ||||
|       // handling
 | ||||
|       hotkey_.emplace(types::Hotkey::Unknown, | ||||
|                       SettingsVariable<std::string> {"?"}); | ||||
|    } | ||||
| 
 | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    std::unordered_map<types::Hotkey, SettingsVariable<std::string>> hotkey_ {}; | ||||
|    std::vector<SettingsVariableBase*> variables_ {}; | ||||
| }; | ||||
| 
 | ||||
| HotkeySettings::HotkeySettings() : | ||||
|     SettingsCategory("hotkeys"), p(std::make_unique<Impl>()) | ||||
| { | ||||
|    RegisterVariables(p->variables_); | ||||
|    SetDefaults(); | ||||
| 
 | ||||
|    p->variables_.clear(); | ||||
| } | ||||
| HotkeySettings::~HotkeySettings() = default; | ||||
| 
 | ||||
| HotkeySettings::HotkeySettings(HotkeySettings&&) noexcept            = default; | ||||
| HotkeySettings& HotkeySettings::operator=(HotkeySettings&&) noexcept = default; | ||||
| 
 | ||||
| SettingsVariable<std::string>& | ||||
| HotkeySettings::hotkey(scwx::qt::types::Hotkey hotkey) const | ||||
| { | ||||
|    auto hotkeyVariable = p->hotkey_.find(hotkey); | ||||
|    if (hotkeyVariable == p->hotkey_.cend()) | ||||
|    { | ||||
|       hotkeyVariable = p->hotkey_.find(types::Hotkey::Unknown); | ||||
|    } | ||||
|    return hotkeyVariable->second; | ||||
| } | ||||
| 
 | ||||
| HotkeySettings& HotkeySettings::Instance() | ||||
| { | ||||
|    static HotkeySettings hotkeySettings_; | ||||
|    return hotkeySettings_; | ||||
| } | ||||
| 
 | ||||
| bool operator==(const HotkeySettings& lhs, const HotkeySettings& rhs) | ||||
| { | ||||
|    return (lhs.p->hotkey_ == rhs.p->hotkey_); | ||||
| } | ||||
| 
 | ||||
| static bool IsHotkeyValid(const std::string& value) | ||||
| { | ||||
|    return QKeySequence::fromString(QString::fromStdString(value)) | ||||
|              .toString() | ||||
|              .toStdString() == value; | ||||
| } | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										42
									
								
								scwx-qt/source/scwx/qt/settings/hotkey_settings.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								scwx-qt/source/scwx/qt/settings/hotkey_settings.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/settings/settings_category.hpp> | ||||
| #include <scwx/qt/settings/settings_variable.hpp> | ||||
| #include <scwx/qt/types/hotkey_types.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace settings | ||||
| { | ||||
| 
 | ||||
| class HotkeySettings : public SettingsCategory | ||||
| { | ||||
| public: | ||||
|    explicit HotkeySettings(); | ||||
|    ~HotkeySettings(); | ||||
| 
 | ||||
|    HotkeySettings(const HotkeySettings&)            = delete; | ||||
|    HotkeySettings& operator=(const HotkeySettings&) = delete; | ||||
| 
 | ||||
|    HotkeySettings(HotkeySettings&&) noexcept; | ||||
|    HotkeySettings& operator=(HotkeySettings&&) noexcept; | ||||
| 
 | ||||
|    SettingsVariable<std::string>& hotkey(scwx::qt::types::Hotkey hotkey) const; | ||||
| 
 | ||||
|    static HotkeySettings& Instance(); | ||||
| 
 | ||||
|    friend bool operator==(const HotkeySettings& lhs, const HotkeySettings& rhs); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace settings
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include <scwx/qt/settings/settings_interface.hpp> | ||||
| #include <scwx/qt/settings/settings_variable.hpp> | ||||
| #include <scwx/qt/ui/hotkey_edit.hpp> | ||||
| 
 | ||||
| #include <boost/tokenizer.hpp> | ||||
| #include <fmt/ranges.h> | ||||
|  | @ -155,7 +156,27 @@ void SettingsInterface<T>::SetEditWidget(QWidget* widget) | |||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(widget)) | ||||
|    if (ui::HotkeyEdit* hotkeyEdit = dynamic_cast<ui::HotkeyEdit*>(widget)) | ||||
|    { | ||||
|       if constexpr (std::is_same_v<T, std::string>) | ||||
|       { | ||||
|          QObject::connect(hotkeyEdit, | ||||
|                           &ui::HotkeyEdit::KeySequenceChanged, | ||||
|                           p->context_.get(), | ||||
|                           [this](const QKeySequence& sequence) | ||||
|                           { | ||||
|                              std::string value { | ||||
|                                 sequence.toString().toStdString()}; | ||||
| 
 | ||||
|                              // Attempt to stage the value
 | ||||
|                              p->stagedValid_ = p->variable_->StageValue(value); | ||||
|                              p->UpdateResetButton(); | ||||
| 
 | ||||
|                              // TODO: Display invalid status
 | ||||
|                           }); | ||||
|       } | ||||
|    } | ||||
|    else if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(widget)) | ||||
|    { | ||||
|       if constexpr (std::is_same_v<T, std::string>) | ||||
|       { | ||||
|  | @ -487,7 +508,16 @@ void SettingsInterface<T>::Impl::UpdateEditWidget() | |||
|    const T                value        = variable_->GetValue(); | ||||
|    const T&               currentValue = staged.has_value() ? *staged : value; | ||||
| 
 | ||||
|    if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editWidget_)) | ||||
|    if (ui::HotkeyEdit* hotkeyEdit = dynamic_cast<ui::HotkeyEdit*>(editWidget_)) | ||||
|    { | ||||
|       if constexpr (std::is_same_v<T, std::string>) | ||||
|       { | ||||
|          QKeySequence keySequence = | ||||
|             QKeySequence::fromString(QString::fromStdString(currentValue)); | ||||
|          hotkeyEdit->set_key_sequence(keySequence); | ||||
|       } | ||||
|    } | ||||
|    else if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editWidget_)) | ||||
|    { | ||||
|       SetWidgetText(lineEdit, currentValue); | ||||
|    } | ||||
|  |  | |||
							
								
								
									
										72
									
								
								scwx-qt/source/scwx/qt/types/hotkey_types.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								scwx-qt/source/scwx/qt/types/hotkey_types.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| #include <scwx/qt/types/hotkey_types.hpp> | ||||
| #include <scwx/util/enum.hpp> | ||||
| 
 | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include <boost/algorithm/string.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace types | ||||
| { | ||||
| 
 | ||||
| static const std::unordered_map<Hotkey, std::string> hotkeyShortName_ { | ||||
|    {Hotkey::ChangeMapStyle, "change_map_style"}, | ||||
|    {Hotkey::CopyCursorCoordinates, "copy_cursor_coordinates"}, | ||||
|    {Hotkey::CopyMapCoordinates, "copy_map_coordinates"}, | ||||
|    {Hotkey::MapPanUp, "map_pan_up"}, | ||||
|    {Hotkey::MapPanDown, "map_pan_down"}, | ||||
|    {Hotkey::MapPanLeft, "map_pan_left"}, | ||||
|    {Hotkey::MapPanRight, "map_pan_right"}, | ||||
|    {Hotkey::MapRotateClockwise, "map_rotate_clockwise"}, | ||||
|    {Hotkey::MapRotateCounterclockwise, "map_rotate_counterclockwise"}, | ||||
|    {Hotkey::MapZoomIn, "map_zoom_in"}, | ||||
|    {Hotkey::MapZoomOut, "map_zoom_out"}, | ||||
|    {Hotkey::ProductTiltDecrease, "product_tilt_decrease"}, | ||||
|    {Hotkey::ProductTiltIncrease, "product_tilt_increase"}, | ||||
|    {Hotkey::TimelineStepBegin, "timeline_step_begin"}, | ||||
|    {Hotkey::TimelineStepBack, "timeline_step_back"}, | ||||
|    {Hotkey::TimelinePlay, "timeline_play"}, | ||||
|    {Hotkey::TimelineStepNext, "timeline_step_next"}, | ||||
|    {Hotkey::TimelineStepEnd, "timeline_step_end"}, | ||||
|    {Hotkey::Unknown, "?"}}; | ||||
| 
 | ||||
| static const std::unordered_map<Hotkey, std::string> hotkeyLongName_ { | ||||
|    {Hotkey::ChangeMapStyle, "Change Map Style"}, | ||||
|    {Hotkey::CopyCursorCoordinates, "Copy Cursor Coordinates"}, | ||||
|    {Hotkey::CopyMapCoordinates, "Copy Map Coordinates"}, | ||||
|    {Hotkey::MapPanUp, "Map Pan Up"}, | ||||
|    {Hotkey::MapPanDown, "Map Pan Down"}, | ||||
|    {Hotkey::MapPanLeft, "Map Pan Left"}, | ||||
|    {Hotkey::MapPanRight, "Map Pan Right"}, | ||||
|    {Hotkey::MapRotateClockwise, "Map Rotate Clockwise"}, | ||||
|    {Hotkey::MapRotateCounterclockwise, "Map Rotate Counterclockwise"}, | ||||
|    {Hotkey::MapZoomIn, "Map Zoom In"}, | ||||
|    {Hotkey::MapZoomOut, "Map Zoom Out"}, | ||||
|    {Hotkey::ProductTiltDecrease, "Product Tilt Decrease"}, | ||||
|    {Hotkey::ProductTiltIncrease, "Product Tilt Increase"}, | ||||
|    {Hotkey::TimelineStepBegin, "Timeline Step Begin"}, | ||||
|    {Hotkey::TimelineStepBack, "Timeline Step Back"}, | ||||
|    {Hotkey::TimelinePlay, "Timeline Play/Pause"}, | ||||
|    {Hotkey::TimelineStepNext, "Timeline Step Next"}, | ||||
|    {Hotkey::TimelineStepEnd, "Timeline Step End"}, | ||||
|    {Hotkey::Unknown, "?"}}; | ||||
| 
 | ||||
| SCWX_GET_ENUM(Hotkey, GetHotkeyFromShortName, hotkeyShortName_) | ||||
| SCWX_GET_ENUM(Hotkey, GetHotkeyFromLongName, hotkeyLongName_) | ||||
| 
 | ||||
| const std::string& GetHotkeyShortName(Hotkey hotkey) | ||||
| { | ||||
|    return hotkeyShortName_.at(hotkey); | ||||
| } | ||||
| 
 | ||||
| const std::string& GetHotkeyLongName(Hotkey hotkey) | ||||
| { | ||||
|    return hotkeyLongName_.at(hotkey); | ||||
| } | ||||
| 
 | ||||
| } // namespace types
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										47
									
								
								scwx-qt/source/scwx/qt/types/hotkey_types.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								scwx-qt/source/scwx/qt/types/hotkey_types.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/util/iterator.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace types | ||||
| { | ||||
| 
 | ||||
| enum class Hotkey | ||||
| { | ||||
|    ChangeMapStyle, | ||||
|    CopyCursorCoordinates, | ||||
|    CopyMapCoordinates, | ||||
|    MapPanUp, | ||||
|    MapPanDown, | ||||
|    MapPanLeft, | ||||
|    MapPanRight, | ||||
|    MapRotateClockwise, | ||||
|    MapRotateCounterclockwise, | ||||
|    MapZoomIn, | ||||
|    MapZoomOut, | ||||
|    ProductTiltDecrease, | ||||
|    ProductTiltIncrease, | ||||
|    TimelineStepBegin, | ||||
|    TimelineStepBack, | ||||
|    TimelinePlay, | ||||
|    TimelineStepNext, | ||||
|    TimelineStepEnd, | ||||
|    Unknown | ||||
| }; | ||||
| typedef scwx::util:: | ||||
|    Iterator<Hotkey, Hotkey::ChangeMapStyle, Hotkey::TimelineStepEnd> | ||||
|       HotkeyIterator; | ||||
| 
 | ||||
| Hotkey             GetHotkeyFromShortName(const std::string& name); | ||||
| Hotkey             GetHotkeyFromLongName(const std::string& name); | ||||
| const std::string& GetHotkeyShortName(Hotkey hotkey); | ||||
| const std::string& GetHotkeyLongName(Hotkey hotkey); | ||||
| 
 | ||||
| } // namespace types
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,6 +1,7 @@ | |||
| #include "animation_dock_widget.hpp" | ||||
| #include "ui_animation_dock_widget.h" | ||||
| 
 | ||||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/qt/settings/general_settings.hpp> | ||||
| #include <scwx/qt/util/time.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
|  | @ -39,6 +40,9 @@ public: | |||
| 
 | ||||
|    AnimationDockWidget* self_; | ||||
| 
 | ||||
|    std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { | ||||
|       manager::HotkeyManager::Instance()}; | ||||
| 
 | ||||
|    types::AnimationState animationState_ {types::AnimationState::Pause}; | ||||
|    types::MapTime        viewType_ {types::MapTime::Live}; | ||||
|    bool                  isLive_ {true}; | ||||
|  | @ -220,6 +224,39 @@ void AnimationDockWidgetImpl::ConnectSignals() | |||
|                     &QAbstractButton::clicked, | ||||
|                     self_, | ||||
|                     [this]() { Q_EMIT self_->AnimationStepEndSelected(); }); | ||||
| 
 | ||||
|    // Shortcuts
 | ||||
|    QObject::connect(hotkeyManager_.get(), | ||||
|                     &manager::HotkeyManager::HotkeyPressed, | ||||
|                     self_, | ||||
|                     [this](types::Hotkey hotkey, bool /* isAutoRepeat */) | ||||
|                     { | ||||
|                        switch (hotkey) | ||||
|                        { | ||||
|                        case types::Hotkey::TimelineStepBegin: | ||||
|                           Q_EMIT self_->AnimationStepBeginSelected(); | ||||
|                           break; | ||||
| 
 | ||||
|                        case types::Hotkey::TimelineStepBack: | ||||
|                           Q_EMIT self_->AnimationStepBackSelected(); | ||||
|                           break; | ||||
| 
 | ||||
|                        case types::Hotkey::TimelinePlay: | ||||
|                           Q_EMIT self_->AnimationPlaySelected(); | ||||
|                           break; | ||||
| 
 | ||||
|                        case types::Hotkey::TimelineStepNext: | ||||
|                           Q_EMIT self_->AnimationStepNextSelected(); | ||||
|                           break; | ||||
| 
 | ||||
|                        case types::Hotkey::TimelineStepEnd: | ||||
|                           Q_EMIT self_->AnimationStepEndSelected(); | ||||
|                           break; | ||||
| 
 | ||||
|                        default: | ||||
|                           break; | ||||
|                        } | ||||
|                     }); | ||||
| } | ||||
| 
 | ||||
| void AnimationDockWidget::UpdateAnimationState(types::AnimationState state) | ||||
|  |  | |||
							
								
								
									
										137
									
								
								scwx-qt/source/scwx/qt/ui/hotkey_edit.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								scwx-qt/source/scwx/qt/ui/hotkey_edit.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,137 @@ | |||
| #include <scwx/qt/ui/hotkey_edit.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <qevent.h> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::ui::hotkey_edit"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class HotkeyEdit::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl() {}; | ||||
|    ~Impl() = default; | ||||
| 
 | ||||
|    QKeySequence sequence_ {}; | ||||
| }; | ||||
| 
 | ||||
| HotkeyEdit::HotkeyEdit(QWidget* parent) : | ||||
|     QLineEdit(parent), p {std::make_unique<Impl>()} | ||||
| { | ||||
|    setReadOnly(true); | ||||
|    setClearButtonEnabled(true); | ||||
| 
 | ||||
|    QAction* clearAction = findChild<QAction*>(); | ||||
|    if (clearAction != nullptr) | ||||
|    { | ||||
|       clearAction->setEnabled(true); | ||||
| 
 | ||||
|       connect(clearAction, | ||||
|               &QAction::triggered, | ||||
|               this, | ||||
|               [this](bool /* checked */) | ||||
|               { | ||||
|                  logger_->trace("clearAction"); | ||||
| 
 | ||||
|                  if (!p->sequence_.isEmpty()) | ||||
|                  { | ||||
|                     // Clear saved sequence
 | ||||
|                     p->sequence_ = QKeySequence {}; | ||||
|                     setText(p->sequence_.toString()); | ||||
|                     Q_EMIT KeySequenceChanged({}); | ||||
|                  } | ||||
|               }); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| HotkeyEdit::~HotkeyEdit() {} | ||||
| 
 | ||||
| QKeySequence HotkeyEdit::key_sequence() const | ||||
| { | ||||
|    return p->sequence_; | ||||
| } | ||||
| 
 | ||||
| void HotkeyEdit::set_key_sequence(const QKeySequence& sequence) | ||||
| { | ||||
|    if (sequence != p->sequence_) | ||||
|    { | ||||
|       p->sequence_ = sequence; | ||||
|       setText(sequence.toString()); | ||||
|       Q_EMIT KeySequenceChanged(sequence); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void HotkeyEdit::focusInEvent(QFocusEvent* e) | ||||
| { | ||||
|    logger_->trace("focusInEvent"); | ||||
| 
 | ||||
|    // Replace text with placeholder prompting for input
 | ||||
|    setPlaceholderText("Press any key"); | ||||
|    setText({}); | ||||
| 
 | ||||
|    QLineEdit::focusInEvent(e); | ||||
| } | ||||
| 
 | ||||
| void HotkeyEdit::focusOutEvent(QFocusEvent* e) | ||||
| { | ||||
|    logger_->trace("focusOutEvent"); | ||||
| 
 | ||||
|    // Replace text with saved sequence
 | ||||
|    setPlaceholderText({}); | ||||
|    setText(p->sequence_.toString()); | ||||
| 
 | ||||
|    QLineEdit::focusOutEvent(e); | ||||
| } | ||||
| 
 | ||||
| void HotkeyEdit::keyPressEvent(QKeyEvent* e) | ||||
| { | ||||
|    logger_->trace("keyPressEvent"); | ||||
| 
 | ||||
|    QKeySequence sequence {}; | ||||
| 
 | ||||
|    switch (e->key()) | ||||
|    { | ||||
|    case Qt::Key::Key_Shift: | ||||
|    case Qt::Key::Key_Control: | ||||
|    case Qt::Key::Key_Alt: | ||||
|    case Qt::Key::Key_Meta: | ||||
|    case Qt::Key::Key_Mode_switch: | ||||
|       // Record modifiers only in sequence
 | ||||
|       sequence = e->modifiers().toInt(); | ||||
|       break; | ||||
| 
 | ||||
|    default: | ||||
|       // Record modifiers and keys in sequence, and save sequence
 | ||||
|       sequence = e->modifiers().toInt() | e->key(); | ||||
| 
 | ||||
|       if (sequence != p->sequence_) | ||||
|       { | ||||
|          p->sequence_ = sequence; | ||||
|          Q_EMIT KeySequenceChanged(sequence); | ||||
|       } | ||||
| 
 | ||||
|       clearFocus(); | ||||
|       break; | ||||
|    } | ||||
| 
 | ||||
|    setText(sequence.toString()); | ||||
| } | ||||
| 
 | ||||
| void HotkeyEdit::keyReleaseEvent(QKeyEvent*) | ||||
| { | ||||
|    logger_->trace("keyReleaseEvent"); | ||||
| 
 | ||||
|    // Modifiers were released prior to pressing a non-modifier key
 | ||||
|    setText({}); | ||||
| } | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										41
									
								
								scwx-qt/source/scwx/qt/ui/hotkey_edit.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								scwx-qt/source/scwx/qt/ui/hotkey_edit.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <QLineEdit> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| class HotkeyEdit : public QLineEdit | ||||
| { | ||||
|    Q_OBJECT | ||||
|    Q_DISABLE_COPY_MOVE(HotkeyEdit) | ||||
| 
 | ||||
| public: | ||||
|    explicit HotkeyEdit(QWidget* parent = nullptr); | ||||
|    ~HotkeyEdit(); | ||||
| 
 | ||||
|    QKeySequence key_sequence() const; | ||||
| 
 | ||||
|    void set_key_sequence(const QKeySequence& sequence); | ||||
| 
 | ||||
| protected: | ||||
|    void focusInEvent(QFocusEvent* e) override; | ||||
|    void focusOutEvent(QFocusEvent* e) override; | ||||
|    void keyPressEvent(QKeyEvent* e) override; | ||||
|    void keyReleaseEvent(QKeyEvent* e) override; | ||||
| 
 | ||||
| signals: | ||||
|    void KeySequenceChanged(const QKeySequence& sequence); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,6 +1,8 @@ | |||
| #include <scwx/qt/ui/level2_settings_widget.hpp> | ||||
| #include <scwx/qt/ui/flow_layout.hpp> | ||||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/common/characters.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <execution> | ||||
| 
 | ||||
|  | @ -16,6 +18,9 @@ namespace qt | |||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::ui::level2_settings_widget"; | ||||
| static const auto        logger_    = util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class Level2SettingsWidgetImpl : public QObject | ||||
| { | ||||
|    Q_OBJECT | ||||
|  | @ -46,9 +51,15 @@ public: | |||
|       settingsLayout->addWidget(declutterCheckBox_); | ||||
| 
 | ||||
|       settingsGroupBox_->setVisible(false); | ||||
| 
 | ||||
|       QObject::connect(hotkeyManager_.get(), | ||||
|                        &manager::HotkeyManager::HotkeyPressed, | ||||
|                        this, | ||||
|                        &Level2SettingsWidgetImpl::HandleHotkeyPressed); | ||||
|    } | ||||
|    ~Level2SettingsWidgetImpl() = default; | ||||
| 
 | ||||
|    void HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat); | ||||
|    void NormalizeElevationButtons(); | ||||
|    void SelectElevation(float elevation); | ||||
| 
 | ||||
|  | @ -63,6 +74,12 @@ public: | |||
| 
 | ||||
|    QGroupBox* settingsGroupBox_; | ||||
|    QCheckBox* declutterCheckBox_; | ||||
| 
 | ||||
|    float        currentElevation_ {}; | ||||
|    QToolButton* currentElevationButton_ {nullptr}; | ||||
| 
 | ||||
|    std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { | ||||
|       manager::HotkeyManager::Instance()}; | ||||
| }; | ||||
| 
 | ||||
| Level2SettingsWidget::Level2SettingsWidget(QWidget* parent) : | ||||
|  | @ -96,6 +113,71 @@ void Level2SettingsWidget::showEvent(QShowEvent* event) | |||
|    p->NormalizeElevationButtons(); | ||||
| } | ||||
| 
 | ||||
| void Level2SettingsWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, | ||||
|                                                    bool          isAutoRepeat) | ||||
| { | ||||
|    if (hotkey != types::Hotkey::ProductTiltDecrease && | ||||
|        hotkey != types::Hotkey::ProductTiltIncrease) | ||||
|    { | ||||
|       // Not handling this hotkey
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    logger_->trace("Handling hotkey: {}, repeat: {}", | ||||
|                   types::GetHotkeyShortName(hotkey), | ||||
|                   isAutoRepeat); | ||||
| 
 | ||||
|    if (!self_->isVisible() || currentElevationButton_ == nullptr) | ||||
|    { | ||||
|       // Level 2 product is not selected
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    // Find the current elevation tilt
 | ||||
|    auto tiltIt = std::find(elevationButtons_.cbegin(), | ||||
|                            elevationButtons_.cend(), | ||||
|                            currentElevationButton_); | ||||
| 
 | ||||
|    if (tiltIt == elevationButtons_.cend()) | ||||
|    { | ||||
|       logger_->error("Could not locate level 2 tilt: {}", currentElevation_); | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    if (hotkey == types::Hotkey::ProductTiltDecrease) | ||||
|    { | ||||
|       // Validate the current elevation tilt
 | ||||
|       if (tiltIt != elevationButtons_.cbegin()) | ||||
|       { | ||||
|          // Get the previous elevation tilt
 | ||||
|          --tiltIt; | ||||
| 
 | ||||
|          // Select the new elevation tilt
 | ||||
|          (*tiltIt)->click(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          logger_->info("Level 2 tilt at lower limit"); | ||||
|       } | ||||
|    } | ||||
|    else if (hotkey == types::Hotkey::ProductTiltIncrease) | ||||
|    { | ||||
|       // Get the next elevation tilt
 | ||||
|       ++tiltIt; | ||||
| 
 | ||||
|       // Validate the next elevation tilt
 | ||||
|       if (tiltIt != elevationButtons_.cend()) | ||||
|       { | ||||
|          // Select the new elevation tilt
 | ||||
|          (*tiltIt)->click(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          logger_->info("Level 2 tilt at upper limit"); | ||||
|       } | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void Level2SettingsWidgetImpl::NormalizeElevationButtons() | ||||
| { | ||||
|    // Set each elevation cut's tool button to the same size
 | ||||
|  | @ -135,12 +217,15 @@ void Level2SettingsWidget::UpdateElevationSelection(float elevation) | |||
|    QString buttonText {QString::number(elevation, 'f', 1) + | ||||
|                        common::Characters::DEGREE}; | ||||
| 
 | ||||
|    QToolButton* newElevationButton = nullptr; | ||||
| 
 | ||||
|    std::for_each(p->elevationButtons_.cbegin(), | ||||
|                  p->elevationButtons_.cend(), | ||||
|                  [&](auto& toolButton) | ||||
|                  { | ||||
|                     if (toolButton->text() == buttonText) | ||||
|                     { | ||||
|                        newElevationButton = toolButton; | ||||
|                        toolButton->setCheckable(true); | ||||
|                        toolButton->setChecked(true); | ||||
|                     } | ||||
|  | @ -150,6 +235,9 @@ void Level2SettingsWidget::UpdateElevationSelection(float elevation) | |||
|                        toolButton->setCheckable(false); | ||||
|                     } | ||||
|                  }); | ||||
| 
 | ||||
|    p->currentElevation_       = elevation; | ||||
|    p->currentElevationButton_ = newElevationButton; | ||||
| } | ||||
| 
 | ||||
| void Level2SettingsWidget::UpdateSettings(map::MapWidget* activeMap) | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #include <scwx/qt/ui/level3_products_widget.hpp> | ||||
| #include <scwx/qt/ui/flow_layout.hpp> | ||||
| #include <scwx/qt/manager/hotkey_manager.hpp> | ||||
| #include <scwx/qt/settings/product_settings.hpp> | ||||
| #include <scwx/qt/settings/settings_interface.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
|  | @ -127,9 +128,15 @@ public: | |||
| 
 | ||||
|       stiPastEnabled_.SetEditWidget(stiPastEnableCheckBox); | ||||
|       stiForecastEnabled_.SetEditWidget(stiForecastEnableCheckBox); | ||||
| 
 | ||||
|       QObject::connect(hotkeyManager_.get(), | ||||
|                        &manager::HotkeyManager::HotkeyPressed, | ||||
|                        this, | ||||
|                        &Level3ProductsWidgetImpl::HandleHotkeyPressed); | ||||
|    } | ||||
|    ~Level3ProductsWidgetImpl() = default; | ||||
| 
 | ||||
|    void HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat); | ||||
|    void NormalizeProductButtons(); | ||||
|    void SelectProductCategory(common::Level3ProductCategory category); | ||||
|    void UpdateCategorySelection(common::Level3ProductCategory category); | ||||
|  | @ -144,11 +151,17 @@ public: | |||
|                       std::unordered_map<std::string, QMenu*>> | ||||
|       categoryMenuMap_; | ||||
| 
 | ||||
|    std::shared_ptr<manager::HotkeyManager> hotkeyManager_ { | ||||
|       manager::HotkeyManager::Instance()}; | ||||
| 
 | ||||
|    std::unordered_map<std::string, std::vector<QAction*>> productTiltMap_; | ||||
| 
 | ||||
|    std::unordered_map<QAction*, std::string> awipsProductMap_; | ||||
|    std::shared_mutex                         awipsProductMutex_; | ||||
| 
 | ||||
|    std::string currentAwipsId_ {}; | ||||
|    QAction*    currentProductTiltAction_ {nullptr}; | ||||
| 
 | ||||
|    settings::SettingsInterface<bool> stiPastEnabled_ {}; | ||||
|    settings::SettingsInterface<bool> stiForecastEnabled_ {}; | ||||
| }; | ||||
|  | @ -167,6 +180,84 @@ void Level3ProductsWidget::showEvent(QShowEvent* event) | |||
|    p->NormalizeProductButtons(); | ||||
| } | ||||
| 
 | ||||
| void Level3ProductsWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, | ||||
|                                                    bool          isAutoRepeat) | ||||
| { | ||||
|    if (hotkey != types::Hotkey::ProductTiltDecrease && | ||||
|        hotkey != types::Hotkey::ProductTiltIncrease) | ||||
|    { | ||||
|       // Not handling this hotkey
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    logger_->trace("Handling hotkey: {}, repeat: {}", | ||||
|                   types::GetHotkeyShortName(hotkey), | ||||
|                   isAutoRepeat); | ||||
| 
 | ||||
|    std::string currentAwipsId           = currentAwipsId_; | ||||
|    QAction*    currentProductTiltAction = currentProductTiltAction_; | ||||
| 
 | ||||
|    if (currentProductTiltAction == nullptr || currentAwipsId.empty() || | ||||
|        currentAwipsId == "?") | ||||
|    { | ||||
|       // Level 3 product is not selected
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    // Get product
 | ||||
|    std::string product = common::GetLevel3ProductByAwipsId(currentAwipsId); | ||||
|    if (product == "?") | ||||
|    { | ||||
|       logger_->error("Invalid AWIPS ID: {}", currentAwipsId); | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    std::shared_lock lock {awipsProductMutex_}; | ||||
| 
 | ||||
|    // Find the current product tilt
 | ||||
|    auto productTiltsIt = productTiltMap_.find(product); | ||||
|    if (productTiltsIt == productTiltMap_.cend()) | ||||
|    { | ||||
|       logger_->error("Could not find product tilt map: {}", | ||||
|                      common::GetLevel3ProductDescription(product)); | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    auto& productTilts  = productTiltsIt->second; | ||||
|    auto  productTiltIt = std::find( | ||||
|       productTilts.cbegin(), productTilts.cend(), currentProductTiltAction); | ||||
|    if (productTiltIt == productTilts.cend()) | ||||
|    { | ||||
|       logger_->error("Could not locate product tilt: {}", currentAwipsId); | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    std::ptrdiff_t productTiltIndex = | ||||
|       std::distance(productTilts.cbegin(), productTiltIt); | ||||
| 
 | ||||
|    // Determine the new product tilt index
 | ||||
|    std::ptrdiff_t newProductTiltIndex = | ||||
|       (hotkey == types::Hotkey::ProductTiltDecrease) ? productTiltIndex - 1 : | ||||
|                                                        productTiltIndex + 1; | ||||
| 
 | ||||
|    // Validate the new product tilt index
 | ||||
|    if (newProductTiltIndex < 0 || | ||||
|        newProductTiltIndex >= | ||||
|           static_cast<std::ptrdiff_t>(productTilts.size()) || | ||||
|        !productTilts.at(newProductTiltIndex)->isVisible()) | ||||
|    { | ||||
|       const std::string direction = | ||||
|          (hotkey == types::Hotkey::ProductTiltDecrease) ? "lower" : "upper"; | ||||
| 
 | ||||
|       logger_->info("Product tilt at {} limit", direction); | ||||
| 
 | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    // Select the new tilt
 | ||||
|    productTilts.at(newProductTiltIndex)->trigger(); | ||||
| } | ||||
| 
 | ||||
| void Level3ProductsWidgetImpl::NormalizeProductButtons() | ||||
| { | ||||
|    int level3MaxWidth = 0; | ||||
|  | @ -283,6 +374,8 @@ void Level3ProductsWidget::UpdateProductSelection( | |||
|    else | ||||
|    { | ||||
|       p->UpdateCategorySelection(common::Level3ProductCategory::Unknown); | ||||
|       p->currentAwipsId_.erase(); | ||||
|       p->currentProductTiltAction_ = nullptr; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
|  | @ -293,7 +386,7 @@ void Level3ProductsWidgetImpl::UpdateCategorySelection( | |||
| 
 | ||||
|    std::for_each(categoryButtons_.cbegin(), | ||||
|                  categoryButtons_.cend(), | ||||
|                  [&](auto& toolButton) | ||||
|                  [&, this](auto& toolButton) | ||||
|                  { | ||||
|                     if (toolButton->text().toStdString() == categoryName) | ||||
|                     { | ||||
|  | @ -313,10 +406,25 @@ void Level3ProductsWidgetImpl::UpdateProductSelection( | |||
| { | ||||
|    std::shared_lock lock {awipsProductMutex_}; | ||||
| 
 | ||||
|    QAction* newProductTilt = nullptr; | ||||
| 
 | ||||
|    std::for_each(awipsProductMap_.cbegin(), | ||||
|                  awipsProductMap_.cend(), | ||||
|                  [=](const auto& pair) | ||||
|                  { pair.first->setChecked(pair.second == awipsId); }); | ||||
|                  [&, this](const auto& pair) | ||||
|                  { | ||||
|                     if (pair.second == awipsId) | ||||
|                     { | ||||
|                        newProductTilt = pair.first; | ||||
|                        pair.first->setChecked(true); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                        pair.first->setChecked(false); | ||||
|                     } | ||||
|                  }); | ||||
| 
 | ||||
|    currentAwipsId_           = awipsId; | ||||
|    currentProductTiltAction_ = newProductTilt; | ||||
| } | ||||
| 
 | ||||
| } // namespace ui
 | ||||
|  |  | |||
							
								
								
									
										107
									
								
								scwx-qt/source/scwx/qt/ui/settings/hotkey_settings_widget.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								scwx-qt/source/scwx/qt/ui/settings/hotkey_settings_widget.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| #include <scwx/qt/ui/settings/hotkey_settings_widget.hpp> | ||||
| #include <scwx/qt/ui/hotkey_edit.hpp> | ||||
| #include <scwx/qt/settings/hotkey_settings.hpp> | ||||
| #include <scwx/qt/settings/settings_interface.hpp> | ||||
| #include <scwx/qt/types/hotkey_types.hpp> | ||||
| 
 | ||||
| #include <boost/unordered/unordered_flat_map.hpp> | ||||
| #include <QGridLayout> | ||||
| #include <QLabel> | ||||
| #include <QScrollArea> | ||||
| #include <QToolButton> | ||||
| #include <QVBoxLayout> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = | ||||
|    "scwx::qt::ui::settings::hotkey_settings_widget"; | ||||
| 
 | ||||
| class HotkeySettingsWidget::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(HotkeySettingsWidget* self) | ||||
|    { | ||||
|       auto& hotkeySettings = settings::HotkeySettings::Instance(); | ||||
| 
 | ||||
|       gridLayout_ = new QGridLayout(self); | ||||
|       contents_   = new QWidget(self); | ||||
|       contents_->setLayout(gridLayout_); | ||||
| 
 | ||||
|       scrollArea_ = new QScrollArea(self); | ||||
|       scrollArea_->setHorizontalScrollBarPolicy( | ||||
|          Qt::ScrollBarPolicy::ScrollBarAlwaysOff); | ||||
|       scrollArea_->setWidgetResizable(true); | ||||
|       scrollArea_->setWidget(contents_); | ||||
| 
 | ||||
|       layout_ = new QVBoxLayout(self); | ||||
|       layout_->setContentsMargins(0, 0, 0, 0); | ||||
|       layout_->addWidget(scrollArea_); | ||||
| 
 | ||||
|       self->setLayout(layout_); | ||||
| 
 | ||||
|       int row = 0; | ||||
| 
 | ||||
|       for (types::Hotkey hotkey : types::HotkeyIterator()) | ||||
|       { | ||||
|          const std::string& labelText = types::GetHotkeyLongName(hotkey); | ||||
| 
 | ||||
|          QLabel*      label = new QLabel(QObject::tr(labelText.c_str()), self); | ||||
|          HotkeyEdit*  hotkeyEdit  = new HotkeyEdit(self); | ||||
|          QToolButton* resetButton = new QToolButton(self); | ||||
| 
 | ||||
|          resetButton->setIcon( | ||||
|             QIcon {":/res/icons/font-awesome-6/rotate-left-solid.svg"}); | ||||
|          resetButton->setVisible(false); | ||||
| 
 | ||||
|          gridLayout_->addWidget(label, row, 0); | ||||
|          gridLayout_->addWidget(hotkeyEdit, row, 1); | ||||
|          gridLayout_->addWidget(resetButton, row, 2); | ||||
| 
 | ||||
|          // Create settings interface
 | ||||
|          auto result = hotkeys_.emplace( | ||||
|             hotkey, settings::SettingsInterface<std::string> {}); | ||||
|          auto& pair      = *result.first; | ||||
|          auto& interface = pair.second; | ||||
| 
 | ||||
|          // Add to settings list
 | ||||
|          self->AddSettingsInterface(&interface); | ||||
| 
 | ||||
|          auto& hotkeyVariable = hotkeySettings.hotkey(hotkey); | ||||
|          interface.SetSettingsVariable(hotkeyVariable); | ||||
|          interface.SetEditWidget(hotkeyEdit); | ||||
|          interface.SetResetButton(resetButton); | ||||
| 
 | ||||
|          ++row; | ||||
|       } | ||||
| 
 | ||||
|       QSpacerItem* spacer = | ||||
|          new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); | ||||
|       gridLayout_->addItem(spacer, row, 0); | ||||
|    } | ||||
|    ~Impl() = default; | ||||
| 
 | ||||
|    QWidget*     contents_; | ||||
|    QLayout*     layout_; | ||||
|    QScrollArea* scrollArea_ {}; | ||||
|    QGridLayout* gridLayout_ {}; | ||||
| 
 | ||||
|    boost::unordered_flat_map<types::Hotkey, | ||||
|                              settings::SettingsInterface<std::string>> | ||||
|       hotkeys_ {}; | ||||
| }; | ||||
| 
 | ||||
| HotkeySettingsWidget::HotkeySettingsWidget(QWidget* parent) : | ||||
|     SettingsPageWidget(parent), p {std::make_shared<Impl>(this)} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| HotkeySettingsWidget::~HotkeySettingsWidget() = default; | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -0,0 +1,29 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/ui/settings/settings_page_widget.hpp> | ||||
| 
 | ||||
| #include <QWidget> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| class HotkeySettingsWidget : public SettingsPageWidget | ||||
| { | ||||
|    Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|    explicit HotkeySettingsWidget(QWidget* parent = nullptr); | ||||
|    ~HotkeySettingsWidget(); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::shared_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										68
									
								
								scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| #include <scwx/qt/ui/settings/settings_page_widget.hpp> | ||||
| #include <scwx/qt/settings/settings_interface_base.hpp> | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = | ||||
|    "scwx::qt::ui::settings::settings_page_widget"; | ||||
| 
 | ||||
| class SettingsPageWidget::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl() {} | ||||
|    ~Impl() = default; | ||||
| 
 | ||||
|    std::vector<settings::SettingsInterfaceBase*> settings_; | ||||
| }; | ||||
| 
 | ||||
| SettingsPageWidget::SettingsPageWidget(QWidget* parent) : | ||||
|     QWidget(parent), p {std::make_shared<Impl>()} | ||||
| { | ||||
| } | ||||
| 
 | ||||
| SettingsPageWidget::~SettingsPageWidget() = default; | ||||
| 
 | ||||
| void SettingsPageWidget::AddSettingsInterface( | ||||
|    settings::SettingsInterfaceBase* setting) | ||||
| { | ||||
|    p->settings_.push_back(setting); | ||||
| } | ||||
| 
 | ||||
| bool SettingsPageWidget::CommitChanges() | ||||
| { | ||||
|    bool committed = false; | ||||
| 
 | ||||
|    for (auto& setting : p->settings_) | ||||
|    { | ||||
|       committed |= setting->Commit(); | ||||
|    } | ||||
| 
 | ||||
|    return committed; | ||||
| } | ||||
| 
 | ||||
| void SettingsPageWidget::DiscardChanges() | ||||
| { | ||||
|    for (auto& setting : p->settings_) | ||||
|    { | ||||
|       setting->Reset(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void SettingsPageWidget::ResetToDefault() | ||||
| { | ||||
|    for (auto& setting : p->settings_) | ||||
|    { | ||||
|       setting->StageDefault(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										36
									
								
								scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/settings/settings_interface_base.hpp> | ||||
| 
 | ||||
| #include <QWidget> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace ui | ||||
| { | ||||
| 
 | ||||
| class SettingsPageWidget : public QWidget | ||||
| { | ||||
|    Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|    explicit SettingsPageWidget(QWidget* parent = nullptr); | ||||
|    ~SettingsPageWidget(); | ||||
| 
 | ||||
|    bool CommitChanges(); | ||||
|    void DiscardChanges(); | ||||
|    void ResetToDefault(); | ||||
| 
 | ||||
| protected: | ||||
|    void AddSettingsInterface(settings::SettingsInterfaceBase* setting); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
|    std::shared_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace ui
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -22,6 +22,7 @@ | |||
| #include <scwx/qt/types/time_types.hpp> | ||||
| #include <scwx/qt/ui/county_dialog.hpp> | ||||
| #include <scwx/qt/ui/radar_site_dialog.hpp> | ||||
| #include <scwx/qt/ui/settings/hotkey_settings_widget.hpp> | ||||
| #include <scwx/qt/util/color.hpp> | ||||
| #include <scwx/qt/util/file.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
|  | @ -177,6 +178,7 @@ public: | |||
|    void SetupPalettesAlertsTab(); | ||||
|    void SetupAudioTab(); | ||||
|    void SetupTextTab(); | ||||
|    void SetupHotkeysTab(); | ||||
| 
 | ||||
|    void ShowColorDialog(QLineEdit* lineEdit, QFrame* frame = nullptr); | ||||
|    void UpdateRadarDialogLocation(const std::string& id); | ||||
|  | @ -216,6 +218,9 @@ public: | |||
|    std::shared_ptr<manager::PositionManager> positionManager_ { | ||||
|       manager::PositionManager::Instance()}; | ||||
| 
 | ||||
|    std::vector<SettingsPageWidget*> settingsPages_ {}; | ||||
|    HotkeySettingsWidget*            hotkeySettingsWidget_ {}; | ||||
| 
 | ||||
|    settings::SettingsInterface<std::string>  defaultRadarSite_ {}; | ||||
|    settings::SettingsInterface<std::int64_t> gridWidth_ {}; | ||||
|    settings::SettingsInterface<std::int64_t> gridHeight_ {}; | ||||
|  | @ -289,6 +294,9 @@ SettingsDialog::SettingsDialog(QWidget* parent) : | |||
|    // Text
 | ||||
|    p->SetupTextTab(); | ||||
| 
 | ||||
|    // Hotkeys
 | ||||
|    p->SetupHotkeysTab(); | ||||
| 
 | ||||
|    p->ConnectSignals(); | ||||
| } | ||||
| 
 | ||||
|  | @ -1171,6 +1179,16 @@ void SettingsDialogImpl::SetupTextTab() | |||
|       self_->ui->radarSiteHoverTextCheckBox); | ||||
| } | ||||
| 
 | ||||
| void SettingsDialogImpl::SetupHotkeysTab() | ||||
| { | ||||
|    QVBoxLayout* layout = new QVBoxLayout(self_->ui->hotkeys); | ||||
| 
 | ||||
|    hotkeySettingsWidget_ = new HotkeySettingsWidget(self_->ui->hotkeys); | ||||
|    layout->addWidget(hotkeySettingsWidget_); | ||||
| 
 | ||||
|    settingsPages_.push_back(hotkeySettingsWidget_); | ||||
| } | ||||
| 
 | ||||
| QImage SettingsDialogImpl::GenerateColorTableImage( | ||||
|    std::shared_ptr<common::ColorTable> colorTable, | ||||
|    std::uint16_t                       min, | ||||
|  | @ -1343,6 +1361,11 @@ void SettingsDialogImpl::ApplyChanges() | |||
|       committed |= setting->Commit(); | ||||
|    } | ||||
| 
 | ||||
|    for (auto& page : settingsPages_) | ||||
|    { | ||||
|       committed |= page->CommitChanges(); | ||||
|    } | ||||
| 
 | ||||
|    if (committed) | ||||
|    { | ||||
|       manager::SettingsManager::Instance().SaveSettings(); | ||||
|  | @ -1357,6 +1380,11 @@ void SettingsDialogImpl::DiscardChanges() | |||
|    { | ||||
|       setting->Reset(); | ||||
|    } | ||||
| 
 | ||||
|    for (auto& page : settingsPages_) | ||||
|    { | ||||
|       page->DiscardChanges(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void SettingsDialogImpl::ResetToDefault() | ||||
|  | @ -1367,6 +1395,11 @@ void SettingsDialogImpl::ResetToDefault() | |||
|    { | ||||
|       setting->StageDefault(); | ||||
|    } | ||||
| 
 | ||||
|    for (auto& page : settingsPages_) | ||||
|    { | ||||
|       page->ResetToDefault(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| std::string SettingsDialogImpl::RadarSiteLabel( | ||||
|  |  | |||
|  | @ -13,8 +13,8 @@ | |||
|   <property name="windowTitle"> | ||||
|    <string>Settings</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|    <item> | ||||
|   <layout class="QGridLayout" name="gridLayout_11"> | ||||
|    <item row="0" column="0"> | ||||
|     <widget class="QFrame" name="frame"> | ||||
|      <property name="frameShape"> | ||||
|       <enum>QFrame::StyledPanel</enum> | ||||
|  | @ -95,6 +95,15 @@ | |||
|             <normaloff>:/res/icons/font-awesome-6/font-solid.svg</normaloff>:/res/icons/font-awesome-6/font-solid.svg</iconset> | ||||
|           </property> | ||||
|          </item> | ||||
|          <item> | ||||
|           <property name="text"> | ||||
|            <string>Hotkeys</string> | ||||
|           </property> | ||||
|           <property name="icon"> | ||||
|            <iconset resource="../../../../scwx-qt.qrc"> | ||||
|             <normaloff>:/res/icons/font-awesome-6/keyboard-regular.svg</normaloff>:/res/icons/font-awesome-6/keyboard-regular.svg</iconset> | ||||
|           </property> | ||||
|          </item> | ||||
|         </widget> | ||||
|         <widget class="QStackedWidget" name="stackedWidget"> | ||||
|          <property name="sizePolicy"> | ||||
|  | @ -209,6 +218,9 @@ | |||
|               <item row="5" column="2"> | ||||
|                <widget class="QComboBox" name="mapProviderComboBox"/> | ||||
|               </item> | ||||
|               <item row="10" column="2"> | ||||
|                <widget class="QComboBox" name="defaultTimeZoneComboBox"/> | ||||
|               </item> | ||||
|               <item row="7" column="4"> | ||||
|                <widget class="QToolButton" name="resetMapTilerApiKeyButton"> | ||||
|                 <property name="text"> | ||||
|  | @ -249,6 +261,17 @@ | |||
|                 </property> | ||||
|                </widget> | ||||
|               </item> | ||||
|               <item row="9" column="4"> | ||||
|                <widget class="QToolButton" name="resetClockFormatButton"> | ||||
|                 <property name="text"> | ||||
|                  <string>...</string> | ||||
|                 </property> | ||||
|                 <property name="icon"> | ||||
|                  <iconset resource="../../../../scwx-qt.qrc"> | ||||
|                   <normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset> | ||||
|                 </property> | ||||
|                </widget> | ||||
|               </item> | ||||
|               <item row="2" column="2"> | ||||
|                <widget class="QSpinBox" name="gridWidthSpinBox"/> | ||||
|               </item> | ||||
|  | @ -329,20 +352,6 @@ | |||
|               <item row="3" column="2"> | ||||
|                <widget class="QSpinBox" name="gridHeightSpinBox"/> | ||||
|               </item> | ||||
|               <item row="10" column="2"> | ||||
|                <widget class="QComboBox" name="defaultTimeZoneComboBox"/> | ||||
|               </item> | ||||
|               <item row="9" column="4"> | ||||
|                <widget class="QToolButton" name="resetClockFormatButton"> | ||||
|                 <property name="text"> | ||||
|                  <string>...</string> | ||||
|                 </property> | ||||
|                 <property name="icon"> | ||||
|                  <iconset resource="../../../../scwx-qt.qrc"> | ||||
|                   <normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset> | ||||
|                 </property> | ||||
|                </widget> | ||||
|               </item> | ||||
|               <item row="10" column="4"> | ||||
|                <widget class="QToolButton" name="resetDefaultTimeZoneButton"> | ||||
|                 <property name="text"> | ||||
|  | @ -429,8 +438,8 @@ | |||
|                    <rect> | ||||
|                     <x>0</x> | ||||
|                     <y>0</y> | ||||
|                     <width>63</width> | ||||
|                     <height>18</height> | ||||
|                     <width>498</width> | ||||
|                     <height>383</height> | ||||
|                    </rect> | ||||
|                   </property> | ||||
|                   <layout class="QGridLayout" name="gridLayout_3"> | ||||
|  | @ -1007,13 +1016,14 @@ | |||
|            </item> | ||||
|           </layout> | ||||
|          </widget> | ||||
|          <widget class="QWidget" name="hotkeys"/> | ||||
|         </widget> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|    <item row="1" column="0"> | ||||
|     <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|      <property name="orientation"> | ||||
|       <enum>Qt::Horizontal</enum> | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| Subproject commit 2ba8740516bbdc58c848bf71755b2f285aa47938 | ||||
| Subproject commit 260b340030487b01ce9aa37135d949008c972f27 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat