diff --git a/scwx-qt/res/icons/font-awesome-6/square-caret-down-regular.svg b/scwx-qt/res/icons/font-awesome-6/square-caret-down-regular.svg new file mode 100644 index 00000000..98e322ef --- /dev/null +++ b/scwx-qt/res/icons/font-awesome-6/square-caret-down-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scwx-qt/res/icons/font-awesome-6/square-caret-right-regular.svg b/scwx-qt/res/icons/font-awesome-6/square-caret-right-regular.svg new file mode 100644 index 00000000..06e4c955 --- /dev/null +++ b/scwx-qt/res/icons/font-awesome-6/square-caret-right-regular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 4b32eeb3..225d2b19 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -121,7 +121,8 @@ set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp source/scwx/qt/settings/settings_interface.hpp source/scwx/qt/settings/settings_interface_base.hpp source/scwx/qt/settings/settings_variable.hpp - source/scwx/qt/settings/settings_variable_base.hpp) + source/scwx/qt/settings/settings_variable_base.hpp + source/scwx/qt/settings/ui_settings.hpp) set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/map_settings.cpp source/scwx/qt/settings/palette_settings.cpp @@ -130,7 +131,8 @@ set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/settings_interface.cpp source/scwx/qt/settings/settings_interface_base.cpp source/scwx/qt/settings/settings_variable.cpp - source/scwx/qt/settings/settings_variable_base.cpp) + source/scwx/qt/settings/settings_variable_base.cpp + source/scwx/qt/settings/ui_settings.cpp) set(HDR_TYPES source/scwx/qt/types/alert_types.hpp source/scwx/qt/types/font_types.hpp source/scwx/qt/types/github_types.hpp @@ -147,6 +149,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp source/scwx/qt/ui/alert_dialog.hpp source/scwx/qt/ui/alert_dock_widget.hpp source/scwx/qt/ui/animation_dock_widget.hpp + source/scwx/qt/ui/collapsible_group.hpp source/scwx/qt/ui/flow_layout.hpp source/scwx/qt/ui/imgui_debug_dialog.hpp source/scwx/qt/ui/imgui_debug_widget.hpp @@ -160,6 +163,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp source/scwx/qt/ui/alert_dialog.cpp source/scwx/qt/ui/alert_dock_widget.cpp source/scwx/qt/ui/animation_dock_widget.cpp + source/scwx/qt/ui/collapsible_group.cpp source/scwx/qt/ui/flow_layout.cpp source/scwx/qt/ui/imgui_debug_dialog.cpp source/scwx/qt/ui/imgui_debug_widget.cpp @@ -173,6 +177,7 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/alert_dialog.ui source/scwx/qt/ui/alert_dock_widget.ui source/scwx/qt/ui/animation_dock_widget.ui + source/scwx/qt/ui/collapsible_group.ui source/scwx/qt/ui/imgui_debug_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui source/scwx/qt/ui/settings_dialog.ui diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc index 36618bee..3939ddf4 100644 --- a/scwx-qt/scwx-qt.qrc +++ b/scwx-qt/scwx-qt.qrc @@ -28,6 +28,8 @@ res/icons/font-awesome-6/play-solid.svg res/icons/font-awesome-6/rotate-left-solid.svg res/icons/font-awesome-6/sliders-solid.svg + res/icons/font-awesome-6/square-caret-down-regular.svg + res/icons/font-awesome-6/square-caret-right-regular.svg res/icons/font-awesome-6/square-minus-regular.svg res/icons/font-awesome-6/square-plus-regular.svg res/palettes/wct/CC.pal diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 23fd0785..225f439b 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -13,10 +13,12 @@ #include #include #include -#include -#include +#include #include +#include #include +#include +#include #include #include #include @@ -61,6 +63,11 @@ public: mainWindow_ {mainWindow}, settings_ {}, activeMap_ {nullptr}, + mapSettingsGroup_ {nullptr}, + level2ProductsGroup_ {nullptr}, + level2SettingsGroup_ {nullptr}, + level3ProductsGroup_ {nullptr}, + timelineGroup_ {nullptr}, level2ProductsWidget_ {nullptr}, level2SettingsWidget_ {nullptr}, level3ProductsWidget_ {nullptr}, @@ -115,6 +122,7 @@ public: void AsyncSetup(); void ConfigureMapLayout(); void ConfigureMapStyles(); + void ConfigureUiSettings(); void ConnectAnimationSignals(); void ConnectMapSignals(); void ConnectOtherSignals(); @@ -142,6 +150,11 @@ public: map::MapProvider mapProvider_; map::MapWidget* activeMap_; + ui::CollapsibleGroup* mapSettingsGroup_; + ui::CollapsibleGroup* level2ProductsGroup_; + ui::CollapsibleGroup* level2SettingsGroup_; + ui::CollapsibleGroup* level3ProductsGroup_; + ui::CollapsibleGroup* timelineGroup_; ui::Level2ProductsWidget* level2ProductsWidget_; ui::Level2SettingsWidget* level2SettingsWidget_; @@ -193,23 +206,12 @@ MainWindow::MainWindow(QWidget* parent) : p->alertDockWidget_->setVisible(false); addDockWidget(Qt::BottomDockWidgetArea, p->alertDockWidget_); - // Animation Dock Widget - p->animationDockWidget_ = new ui::AnimationDockWidget(this); - p->animationDockWidget_->setVisible(true); - addDockWidget(Qt::LeftDockWidgetArea, p->animationDockWidget_); - // Configure Menu ui->menuView->insertAction(ui->actionRadarToolbox, ui->radarToolboxDock->toggleViewAction()); ui->radarToolboxDock->toggleViewAction()->setText(tr("Radar &Toolbox")); ui->actionRadarToolbox->setVisible(false); - ui->menuView->insertAction(ui->actionAnimationToolbox, - p->animationDockWidget_->toggleViewAction()); - p->animationDockWidget_->toggleViewAction()->setText( - tr("A&nimation Toolbox")); - ui->actionAnimationToolbox->setVisible(false); - ui->menuView->insertAction(ui->actionResourceExplorer, ui->resourceExplorerDock->toggleViewAction()); ui->resourceExplorerDock->toggleViewAction()->setText( @@ -240,24 +242,55 @@ MainWindow::MainWindow(QWidget* parent) : // Settings Dialog p->settingsDialog_ = new ui::SettingsDialog(this); + // Map Settings + p->mapSettingsGroup_ = new ui::CollapsibleGroup(tr("Map Settings"), this); + p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleLabel); + p->mapSettingsGroup_->GetContentsLayout()->addWidget(ui->mapStyleComboBox); + ui->radarToolboxScrollAreaContents->layout()->replaceWidget( + ui->mapSettingsGroupBox, p->mapSettingsGroup_); + ui->mapSettingsGroupBox->setVisible(false); + // Add Level 2 Products + p->level2ProductsGroup_ = + new ui::CollapsibleGroup(tr("Level 2 Products"), this); p->level2ProductsWidget_ = new ui::Level2ProductsWidget(this); - ui->radarProductGroupBox->layout()->replaceWidget(ui->level2ProductFrame, - p->level2ProductsWidget_); - delete ui->level2ProductFrame; - ui->level2ProductFrame = p->level2ProductsWidget_; + p->level2ProductsGroup_->GetContentsLayout()->addWidget( + p->level2ProductsWidget_); + ui->radarToolboxScrollAreaContents->layout()->addWidget( + p->level2ProductsGroup_); // Add Level 3 Products + p->level3ProductsGroup_ = + new ui::CollapsibleGroup(tr("Level 3 Products"), this); p->level3ProductsWidget_ = new ui::Level3ProductsWidget(this); - ui->radarProductGroupBox->layout()->replaceWidget(ui->level3ProductFrame, - p->level3ProductsWidget_); - delete ui->level3ProductFrame; - ui->level3ProductFrame = p->level3ProductsWidget_; + p->level3ProductsGroup_->GetContentsLayout()->addWidget( + p->level3ProductsWidget_); + ui->radarToolboxScrollAreaContents->layout()->addWidget( + p->level3ProductsGroup_); // Add Level 2 Settings - p->level2SettingsWidget_ = new ui::Level2SettingsWidget(ui->settingsFrame); - ui->settingsFrame->layout()->addWidget(p->level2SettingsWidget_); - p->level2SettingsWidget_->setVisible(false); + p->level2SettingsGroup_ = + new ui::CollapsibleGroup(tr("Level 2 Settings"), this); + p->level2SettingsWidget_ = new ui::Level2SettingsWidget(this); + p->level2SettingsGroup_->GetContentsLayout()->addWidget( + p->level2SettingsWidget_); + ui->radarToolboxScrollAreaContents->layout()->addWidget( + p->level2SettingsGroup_); + p->level2SettingsGroup_->setVisible(false); + ui->radarToolboxScrollAreaContents->layout()->addWidget( + p->level2SettingsGroup_); + + // Timeline + p->timelineGroup_ = new ui::CollapsibleGroup(tr("Timeline"), this); + p->animationDockWidget_ = new ui::AnimationDockWidget(this); + p->timelineGroup_->GetContentsLayout()->addWidget(p->animationDockWidget_); + ui->radarToolboxScrollAreaContents->layout()->addWidget(p->timelineGroup_); + + // Reset toolbox spacer at the bottom + ui->radarToolboxScrollAreaContents->layout()->removeItem( + ui->radarToolboxSpacer); + ui->radarToolboxScrollAreaContents->layout()->addItem( + ui->radarToolboxSpacer); // ImGui Debug Dialog p->imGuiDebugDialog_ = new ui::ImGuiDebugDialog(this); @@ -280,6 +313,7 @@ MainWindow::MainWindow(QWidget* parent) : p->PopulateMapStyles(); p->ConfigureMapStyles(); + p->ConfigureUiSettings(); p->ConnectMapSignals(); p->ConnectAnimationSignals(); p->ConnectOtherSignals(); @@ -637,6 +671,42 @@ void MainWindowImpl::ConfigureMapStyles() } } +void MainWindowImpl::ConfigureUiSettings() +{ + auto& uiSettings = settings::UiSettings::Instance(); + + level2ProductsGroup_->SetExpanded( + uiSettings.level2_products_expanded().GetValue()); + level2SettingsGroup_->SetExpanded( + uiSettings.level2_settings_expanded().GetValue()); + level3ProductsGroup_->SetExpanded( + uiSettings.level3_products_expanded().GetValue()); + mapSettingsGroup_->SetExpanded( + uiSettings.map_settings_expanded().GetValue()); + timelineGroup_->SetExpanded(uiSettings.timeline_expanded().GetValue()); + + connect(level2ProductsGroup_, + &ui::CollapsibleGroup::StateChanged, + [&](bool expanded) + { uiSettings.level2_products_expanded().StageValue(expanded); }); + connect(level2SettingsGroup_, + &ui::CollapsibleGroup::StateChanged, + [&](bool expanded) + { uiSettings.level2_settings_expanded().StageValue(expanded); }); + connect(level3ProductsGroup_, + &ui::CollapsibleGroup::StateChanged, + [&](bool expanded) + { uiSettings.level3_products_expanded().StageValue(expanded); }); + connect(mapSettingsGroup_, + &ui::CollapsibleGroup::StateChanged, + [&](bool expanded) + { uiSettings.map_settings_expanded().StageValue(expanded); }); + connect(timelineGroup_, + &ui::CollapsibleGroup::StateChanged, + [&](bool expanded) + { uiSettings.timeline_expanded().StageValue(expanded); }); +} + void MainWindowImpl::ConnectMapSignals() { for (const auto& mapWidget : maps_) @@ -1011,11 +1081,11 @@ void MainWindowImpl::UpdateRadarProductSettings() if (activeMap_->GetRadarProductGroup() == common::RadarProductGroup::Level2) { level2SettingsWidget_->UpdateSettings(activeMap_); - level2SettingsWidget_->setVisible(true); + level2SettingsGroup_->setVisible(true); } else { - level2SettingsWidget_->setVisible(false); + level2SettingsGroup_->setVisible(false); } } diff --git a/scwx-qt/source/scwx/qt/main/main_window.ui b/scwx-qt/source/scwx/qt/main/main_window.ui index 64cab927..369c8d28 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.ui +++ b/scwx-qt/source/scwx/qt/main/main_window.ui @@ -76,7 +76,6 @@ &View - @@ -121,7 +120,7 @@ QFrame::NoFrame - Qt::ScrollBarAlwaysOff + Qt::ScrollBarAsNeeded QAbstractScrollArea::AdjustToContents @@ -134,8 +133,8 @@ 0 0 - 175 - 696 + 157 + 702 @@ -240,60 +239,6 @@ - - - - Radar Products - - - - - - Level 2 - - - - - - - - - - Qt::Horizontal - - - - - - - Level 3 - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - @@ -470,11 +415,6 @@ &Check for Updates - - - A&nimation Toolbox - - diff --git a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp index 2572ed2a..c504e15e 100644 --- a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -96,6 +97,7 @@ void Shutdown() dataChanged |= general_settings().Shutdown(); dataChanged |= map_settings().Shutdown(); + dataChanged |= settings::UiSettings::Instance().Shutdown(); if (dataChanged) { @@ -128,6 +130,7 @@ static boost::json::value ConvertSettingsToJson() general_settings().WriteJson(settingsJson); map_settings().WriteJson(settingsJson); palette_settings().WriteJson(settingsJson); + settings::UiSettings::Instance().WriteJson(settingsJson); return settingsJson; } @@ -139,6 +142,7 @@ static void GenerateDefaultSettings() general_settings().SetDefaults(); map_settings().SetDefaults(); palette_settings().SetDefaults(); + settings::UiSettings::Instance().SetDefaults(); } static bool LoadSettings(const boost::json::object& settingsJson) @@ -150,6 +154,7 @@ static bool LoadSettings(const boost::json::object& settingsJson) jsonDirty |= !general_settings().ReadJson(settingsJson); jsonDirty |= !map_settings().ReadJson(settingsJson); jsonDirty |= !palette_settings().ReadJson(settingsJson); + jsonDirty |= !settings::UiSettings::Instance().ReadJson(settingsJson); return jsonDirty; } diff --git a/scwx-qt/source/scwx/qt/settings/ui_settings.cpp b/scwx-qt/source/scwx/qt/settings/ui_settings.cpp new file mode 100644 index 00000000..dc131d96 --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/ui_settings.cpp @@ -0,0 +1,104 @@ +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +static const std::string logPrefix_ = "scwx::qt::settings::ui_settings"; + +class UiSettingsImpl +{ +public: + explicit UiSettingsImpl() + { + level2ProductsExpanded_.SetDefault(false); + level2SettingsExpanded_.SetDefault(true); + level3ProductsExpanded_.SetDefault(true); + mapSettingsExpanded_.SetDefault(true); + timelineExpanded_.SetDefault(true); + } + + ~UiSettingsImpl() {} + + SettingsVariable level2ProductsExpanded_ {"level2_products_expanded"}; + SettingsVariable level2SettingsExpanded_ {"level2_settings_expanded"}; + SettingsVariable level3ProductsExpanded_ {"level3_products_expanded"}; + SettingsVariable mapSettingsExpanded_ {"map_settings_expanded"}; + SettingsVariable timelineExpanded_ {"timeline_expanded"}; +}; + +UiSettings::UiSettings() : + SettingsCategory("ui"), p(std::make_unique()) +{ + RegisterVariables({&p->level2ProductsExpanded_, + &p->level2SettingsExpanded_, + &p->level3ProductsExpanded_, + &p->mapSettingsExpanded_, + &p->timelineExpanded_}); + SetDefaults(); +} +UiSettings::~UiSettings() = default; + +UiSettings::UiSettings(UiSettings&&) noexcept = default; +UiSettings& UiSettings::operator=(UiSettings&&) noexcept = default; + +SettingsVariable& UiSettings::level2_products_expanded() const +{ + return p->level2ProductsExpanded_; +} + +SettingsVariable& UiSettings::level2_settings_expanded() const +{ + return p->level2SettingsExpanded_; +} + +SettingsVariable& UiSettings::level3_products_expanded() const +{ + return p->level3ProductsExpanded_; +} + +SettingsVariable& UiSettings::map_settings_expanded() const +{ + return p->mapSettingsExpanded_; +} + +SettingsVariable& UiSettings::timeline_expanded() const +{ + return p->timelineExpanded_; +} + +bool UiSettings::Shutdown() +{ + bool dataChanged = false; + + // Commit settings that are managed separate from the settings dialog + dataChanged |= p->level2ProductsExpanded_.Commit(); + dataChanged |= p->level2SettingsExpanded_.Commit(); + dataChanged |= p->level3ProductsExpanded_.Commit(); + dataChanged |= p->mapSettingsExpanded_.Commit(); + dataChanged |= p->timelineExpanded_.Commit(); + + return dataChanged; +} + +UiSettings& UiSettings::Instance() +{ + static UiSettings uiSettings_; + return uiSettings_; +} + +bool operator==(const UiSettings& lhs, const UiSettings& rhs) +{ + return (lhs.p->level2ProductsExpanded_ == rhs.p->level2ProductsExpanded_ && + lhs.p->level2SettingsExpanded_ == rhs.p->level2SettingsExpanded_ && + lhs.p->level3ProductsExpanded_ == rhs.p->level3ProductsExpanded_ && + lhs.p->mapSettingsExpanded_ == rhs.p->mapSettingsExpanded_ && + lhs.p->timelineExpanded_ == rhs.p->timelineExpanded_); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/ui_settings.hpp b/scwx-qt/source/scwx/qt/settings/ui_settings.hpp new file mode 100644 index 00000000..e3045bcb --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/ui_settings.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +class UiSettingsImpl; + +class UiSettings : public SettingsCategory +{ +public: + explicit UiSettings(); + ~UiSettings(); + + UiSettings(const UiSettings&) = delete; + UiSettings& operator=(const UiSettings&) = delete; + + UiSettings(UiSettings&&) noexcept; + UiSettings& operator=(UiSettings&&) noexcept; + + SettingsVariable& level2_products_expanded() const; + SettingsVariable& level2_settings_expanded() const; + SettingsVariable& level3_products_expanded() const; + SettingsVariable& map_settings_expanded() const; + SettingsVariable& timeline_expanded() const; + + bool Shutdown(); + + static UiSettings& Instance(); + + friend bool operator==(const UiSettings& lhs, const UiSettings& rhs); + +private: + std::unique_ptr p; +}; + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.cpp b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.cpp index 3d391407..34b1001a 100644 --- a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.cpp @@ -51,7 +51,7 @@ public: }; AnimationDockWidget::AnimationDockWidget(QWidget* parent) : - QDockWidget(parent), + QFrame(parent), p {std::make_unique(this)}, ui(new Ui::AnimationDockWidget) { diff --git a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.hpp b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.hpp index 8b64d0c6..abc79c88 100644 --- a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.hpp +++ b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.hpp @@ -4,7 +4,7 @@ #include -#include +#include namespace Ui { @@ -20,7 +20,7 @@ namespace ui class AnimationDockWidgetImpl; -class AnimationDockWidget : public QDockWidget +class AnimationDockWidget : public QFrame { Q_OBJECT diff --git a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.ui b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.ui index 33485032..1c79eb48 100644 --- a/scwx-qt/source/scwx/qt/ui/animation_dock_widget.ui +++ b/scwx-qt/source/scwx/qt/ui/animation_dock_widget.ui @@ -1,353 +1,304 @@ AnimationDockWidget - + 0 0 - 200 - 543 + 189 + 264 - - Animation Toolbox + + QFrame::StyledPanel - - - - - - QFrame::NoFrame - - + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Auto Update: Enabled + + + + + + + Live View + + + true + + + + + + + Archive View + + + + + + + QAbstractSpinBox::CorrectToNearestValue + + + + 0 + 0 + 0 + 1991 + 6 + 1 + + + + yyyy-MM-dd + + + true + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + 0 - - Qt::ScrollBarAlwaysOff + + 0 - - true + + 0 - - - - 0 - 0 - 182 - 506 - - - - - 0 + + 0 + + + + + QAbstractSpinBox::CorrectToNearestValue - - 0 + + HH:mm - - 0 + + + + + + UTC - - 0 + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractSpinBox::CorrectToNearestValue - - - - Timeline - - - - - - Auto Update: Enabled - - - - - - - Live View - - - true - - - - - - - Archive View - - - - - - - QAbstractSpinBox::CorrectToNearestValue - - - - 0 - 0 - 0 - 1991 - 6 - 1 - - - - yyyy-MM-dd - - - true - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractSpinBox::CorrectToNearestValue - - - HH:mm - - - - - - - UTC - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractSpinBox::CorrectToNearestValue - - - min - - - 1 - - - 1440 - - - 30 - - - - - - - Loop Time - - - - - - - Loop Speed - - - - - - - QAbstractSpinBox::CorrectToNearestValue - - - x - - - 1.000000000000000 - - - 1.000000000000000 - - - - - - - Loop Delay - - - - - - - sec - - - 1 - - - 15.000000000000000 - - - 0.100000000000000 - - - 2.500000000000000 - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 1 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - ... - - - - :/res/icons/font-awesome-6/backward-step-solid.svg:/res/icons/font-awesome-6/backward-step-solid.svg - - - - - - - ... - - - - :/res/icons/font-awesome-6/angle-left-solid.svg:/res/icons/font-awesome-6/angle-left-solid.svg - - - - - - - ... - - - - :/res/icons/font-awesome-6/play-solid.svg:/res/icons/font-awesome-6/play-solid.svg - - - - - - - ... - - - - :/res/icons/font-awesome-6/angle-right-solid.svg:/res/icons/font-awesome-6/angle-right-solid.svg - - - - - - - ... - - - - :/res/icons/font-awesome-6/forward-step-solid.svg:/res/icons/font-awesome-6/forward-step-solid.svg - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - + + min + + + 1 + + + 1440 + + + 30 + + + + + + + Loop Speed + + + + + + + Loop Delay + + + + + + + sec + + + 1 + + + 15.000000000000000 + + + 0.100000000000000 + + + 2.500000000000000 + + + + + + + QAbstractSpinBox::CorrectToNearestValue + + + x + + + 1.000000000000000 + + + 1.000000000000000 + + + + + + + Loop Time + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + ... + + + + :/res/icons/font-awesome-6/backward-step-solid.svg:/res/icons/font-awesome-6/backward-step-solid.svg + + + + + + + ... + + + + :/res/icons/font-awesome-6/angle-left-solid.svg:/res/icons/font-awesome-6/angle-left-solid.svg + + + + + + + ... + + + + :/res/icons/font-awesome-6/play-solid.svg:/res/icons/font-awesome-6/play-solid.svg + + + + + + + ... + + + + :/res/icons/font-awesome-6/angle-right-solid.svg:/res/icons/font-awesome-6/angle-right-solid.svg + + + + + + + ... + + + + :/res/icons/font-awesome-6/forward-step-solid.svg:/res/icons/font-awesome-6/forward-step-solid.svg + + + + + + + diff --git a/scwx-qt/source/scwx/qt/ui/collapsible_group.cpp b/scwx-qt/source/scwx/qt/ui/collapsible_group.cpp new file mode 100644 index 00000000..a66d9703 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/collapsible_group.cpp @@ -0,0 +1,102 @@ +#include "collapsible_group.hpp" +#include "ui_collapsible_group.h" + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class CollapsibleGroupImpl +{ +public: + explicit CollapsibleGroupImpl(CollapsibleGroup* self) : self_ {self} {} + ~CollapsibleGroupImpl() = default; + + void Initialize(); + + const QIcon kCollapsedIcon_ { + ":/res/icons/font-awesome-6/square-caret-right-regular.svg"}; + const QIcon kExpandedIcon_ { + ":/res/icons/font-awesome-6/square-caret-down-regular.svg"}; + + const std::map kIcon_ {{false, kCollapsedIcon_}, + {true, kExpandedIcon_}}; + + CollapsibleGroup* self_; + + bool expanded_ {true}; +}; + +CollapsibleGroup::CollapsibleGroup(QWidget* parent) : + QFrame(parent), + p {std::make_unique(this)}, + ui(new Ui::CollapsibleGroup) +{ + ui->setupUi(this); + p->Initialize(); +} + +CollapsibleGroup::CollapsibleGroup(const QString& title, QWidget* parent) : + QFrame(parent), + p {std::make_unique(this)}, + ui(new Ui::CollapsibleGroup) +{ + ui->setupUi(this); + ui->titleButton->setText(title); + p->Initialize(); +} + +CollapsibleGroup::~CollapsibleGroup() +{ + delete ui; +} + +void CollapsibleGroupImpl::Initialize() +{ + QObject::connect( + self_->ui->titleButton, + &QAbstractButton::clicked, + self_, + [this]() { self_->SetExpanded(!expanded_); }, + Qt::DirectConnection); + + self_->SetExpanded(true); +} + +QLayout* CollapsibleGroup::GetContentsLayout() +{ + return ui->contentsFrame->layout(); +} + +void CollapsibleGroup::SetContentsLayout(QLayout* layout) +{ + ui->contentsFrame->setLayout(layout); +} + +void CollapsibleGroup::SetTitle(const QString& title) +{ + ui->titleButton->setText(title); +} + +void CollapsibleGroup::SetExpanded(bool expanded) +{ + // Update icon + ui->titleButton->setIcon(p->kIcon_.at(expanded)); + + // Update contents visibility + ui->contentsFrame->setVisible(expanded); + + // Update internal state + if (p->expanded_ != expanded) + { + p->expanded_ = expanded; + + Q_EMIT StateChanged(expanded); + } +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/collapsible_group.hpp b/scwx-qt/source/scwx/qt/ui/collapsible_group.hpp new file mode 100644 index 00000000..65966b48 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/collapsible_group.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +namespace Ui +{ +class CollapsibleGroup; +} + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class CollapsibleGroupImpl; + +class CollapsibleGroup : public QFrame +{ + Q_OBJECT + +public: + explicit CollapsibleGroup(QWidget* parent = nullptr); + explicit CollapsibleGroup(const QString& title, QWidget* parent = nullptr); + ~CollapsibleGroup(); + + QLayout* GetContentsLayout(); + void SetContentsLayout(QLayout* contents); + void SetTitle(const QString& title); + +public slots: + void SetExpanded(bool expanded); + +signals: + void StateChanged(bool expanded); + +private: + friend class CollapsibleGroupImpl; + std::unique_ptr p; + Ui::CollapsibleGroup* ui; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/collapsible_group.ui b/scwx-qt/source/scwx/qt/ui/collapsible_group.ui new file mode 100644 index 00000000..1c7f670e --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/collapsible_group.ui @@ -0,0 +1,64 @@ + + + CollapsibleGroup + + + + 0 + 0 + 400 + 300 + + + + Frame + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + text-align: left; + + + Title + + + + :/res/icons/font-awesome-6/square-caret-right-regular.svg + :/res/icons/font-awesome-6/square-caret-down-regular.svg:/res/icons/font-awesome-6/square-caret-right-regular.svg + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + + + + + + diff --git a/test/data b/test/data index 875afa5e..b2fa7d86 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 875afa5ead329536f802096ca1d2ef1010a7cc6b +Subproject commit b2fa7d866800902f4c092c567017c832bcdbe702