Merge pull request #66 from dpaulat/feature/collapsible-groups

Collapsible Groups
This commit is contained in:
Dan Paulat 2023-07-09 09:00:18 -04:00 committed by GitHub
commit 809adfd422
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 766 additions and 427 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M384 432c8.8 0 16-7.2 16-16l0-320c0-8.8-7.2-16-16-16L64 80c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l320 0zm64-16c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32l320 0c35.3 0 64 28.7 64 64l0 320zM224 352c-6.7 0-13-2.8-17.6-7.7l-104-112c-6.5-7-8.2-17.2-4.4-25.9s12.5-14.4 22-14.4l208 0c9.5 0 18.2 5.7 22 14.4s2.1 18.9-4.4 25.9l-104 112c-4.5 4.9-10.9 7.7-17.6 7.7z"/></svg>

After

Width:  |  Height:  |  Size: 641 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M400 96c0-8.8-7.2-16-16-16L64 80c-8.8 0-16 7.2-16 16l0 320c0 8.8 7.2 16 16 16l320 0c8.8 0 16-7.2 16-16l0-320zM384 32c35.3 0 64 28.7 64 64l0 320c0 35.3-28.7 64-64 64L64 480c-35.3 0-64-28.7-64-64L0 96C0 60.7 28.7 32 64 32l320 0zM320 256c0 6.7-2.8 13-7.7 17.6l-112 104c-7 6.5-17.2 8.2-25.9 4.4s-14.4-12.5-14.4-22l0-208c0-9.5 5.7-18.2 14.4-22s18.9-2.1 25.9 4.4l112 104c4.9 4.5 7.7 10.9 7.7 17.6z"/></svg>

After

Width:  |  Height:  |  Size: 639 B

View file

@ -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

View file

@ -28,6 +28,8 @@
<file>res/icons/font-awesome-6/play-solid.svg</file>
<file>res/icons/font-awesome-6/rotate-left-solid.svg</file>
<file>res/icons/font-awesome-6/sliders-solid.svg</file>
<file>res/icons/font-awesome-6/square-caret-down-regular.svg</file>
<file>res/icons/font-awesome-6/square-caret-right-regular.svg</file>
<file>res/icons/font-awesome-6/square-minus-regular.svg</file>
<file>res/icons/font-awesome-6/square-plus-regular.svg</file>
<file>res/palettes/wct/CC.pal</file>

View file

@ -13,10 +13,12 @@
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/map/map_widget.hpp>
#include <scwx/qt/model/radar_product_model.hpp>
#include <scwx/qt/ui/alert_dock_widget.hpp>
#include <scwx/qt/ui/flow_layout.hpp>
#include <scwx/qt/settings/ui_settings.hpp>
#include <scwx/qt/ui/about_dialog.hpp>
#include <scwx/qt/ui/alert_dock_widget.hpp>
#include <scwx/qt/ui/animation_dock_widget.hpp>
#include <scwx/qt/ui/collapsible_group.hpp>
#include <scwx/qt/ui/flow_layout.hpp>
#include <scwx/qt/ui/imgui_debug_dialog.hpp>
#include <scwx/qt/ui/level2_products_widget.hpp>
#include <scwx/qt/ui/level2_settings_widget.hpp>
@ -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->level2ProductsGroup_->GetContentsLayout()->addWidget(
p->level2ProductsWidget_);
delete ui->level2ProductFrame;
ui->level2ProductFrame = 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->level3ProductsGroup_->GetContentsLayout()->addWidget(
p->level3ProductsWidget_);
delete ui->level3ProductFrame;
ui->level3ProductFrame = 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);
}
}

View file

@ -76,7 +76,6 @@
<string>&amp;View</string>
</property>
<addaction name="actionRadarToolbox"/>
<addaction name="actionAnimationToolbox"/>
<addaction name="actionResourceExplorer"/>
<addaction name="actionAlerts"/>
</widget>
@ -121,7 +120,7 @@
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
@ -134,8 +133,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>175</width>
<height>696</height>
<width>157</width>
<height>702</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
@ -240,60 +239,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="radarProductGroupBox">
<property name="title">
<string>Radar Products</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="level2Label">
<property name="text">
<string>Level 2</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="level2ProductFrame" native="true"/>
</item>
<item>
<widget class="Line" name="level2Separator">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="level3Label">
<property name="text">
<string>Level 3</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="level3ProductFrame" native="true"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="settingsFrame" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<spacer name="radarToolboxSpacer">
<property name="orientation">
@ -470,11 +415,6 @@
<string>&amp;Check for Updates</string>
</property>
</action>
<action name="actionAnimationToolbox">
<property name="text">
<string>A&amp;nimation Toolbox</string>
</property>
</action>
</widget>
<resources>
<include location="../../../../scwx-qt.qrc"/>

View file

@ -1,5 +1,6 @@
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/settings/ui_settings.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/util/logger.hpp>
@ -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;
}

View file

@ -0,0 +1,104 @@
#include <scwx/qt/settings/ui_settings.hpp>
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<bool> level2ProductsExpanded_ {"level2_products_expanded"};
SettingsVariable<bool> level2SettingsExpanded_ {"level2_settings_expanded"};
SettingsVariable<bool> level3ProductsExpanded_ {"level3_products_expanded"};
SettingsVariable<bool> mapSettingsExpanded_ {"map_settings_expanded"};
SettingsVariable<bool> timelineExpanded_ {"timeline_expanded"};
};
UiSettings::UiSettings() :
SettingsCategory("ui"), p(std::make_unique<UiSettingsImpl>())
{
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<bool>& UiSettings::level2_products_expanded() const
{
return p->level2ProductsExpanded_;
}
SettingsVariable<bool>& UiSettings::level2_settings_expanded() const
{
return p->level2SettingsExpanded_;
}
SettingsVariable<bool>& UiSettings::level3_products_expanded() const
{
return p->level3ProductsExpanded_;
}
SettingsVariable<bool>& UiSettings::map_settings_expanded() const
{
return p->mapSettingsExpanded_;
}
SettingsVariable<bool>& 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

View file

@ -0,0 +1,48 @@
#pragma once
#include <scwx/qt/settings/settings_category.hpp>
#include <scwx/qt/settings/settings_variable.hpp>
#include <memory>
#include <string>
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<bool>& level2_products_expanded() const;
SettingsVariable<bool>& level2_settings_expanded() const;
SettingsVariable<bool>& level3_products_expanded() const;
SettingsVariable<bool>& map_settings_expanded() const;
SettingsVariable<bool>& timeline_expanded() const;
bool Shutdown();
static UiSettings& Instance();
friend bool operator==(const UiSettings& lhs, const UiSettings& rhs);
private:
std::unique_ptr<UiSettingsImpl> p;
};
} // namespace settings
} // namespace qt
} // namespace scwx

View file

@ -51,7 +51,7 @@ public:
};
AnimationDockWidget::AnimationDockWidget(QWidget* parent) :
QDockWidget(parent),
QFrame(parent),
p {std::make_unique<AnimationDockWidgetImpl>(this)},
ui(new Ui::AnimationDockWidget)
{

View file

@ -4,7 +4,7 @@
#include <chrono>
#include <QDockWidget>
#include <QFrame>
namespace Ui
{
@ -20,7 +20,7 @@ namespace ui
class AnimationDockWidgetImpl;
class AnimationDockWidget : public QDockWidget
class AnimationDockWidget : public QFrame
{
Q_OBJECT

View file

@ -1,44 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AnimationDockWidget</class>
<widget class="QDockWidget" name="AnimationDockWidget">
<widget class="QFrame" name="AnimationDockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>200</width>
<height>543</height>
<width>189</width>
<height>264</height>
</rect>
</property>
<property name="windowTitle">
<string>Animation Toolbox</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
<enum>QFrame::StyledPanel</enum>
</property>
<property name="lineWidth">
<number>0</number>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>182</width>
<height>506</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
@ -51,12 +29,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="timelineGroupBox">
<property name="title">
<string>Timeline</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="autoUpdateLabel">
<property name="text">
@ -185,13 +157,6 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="loopTimeLabel">
<property name="text">
<string>Loop Time</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="loopSpeedLabel">
<property name="text">
@ -199,22 +164,6 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="loopSpeedSpinBox">
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="suffix">
<string>x</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="loopDelayLabel">
<property name="text">
@ -241,6 +190,29 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="loopSpeedSpinBox">
<property name="correctionMode">
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
</property>
<property name="suffix">
<string>x</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="loopTimeLabel">
<property name="text">
<string>Loop Time</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -328,27 +300,6 @@
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<resources>
<include location="../../../../scwx-qt.qrc"/>
</resources>

View file

@ -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<bool, const QIcon&> kIcon_ {{false, kCollapsedIcon_},
{true, kExpandedIcon_}};
CollapsibleGroup* self_;
bool expanded_ {true};
};
CollapsibleGroup::CollapsibleGroup(QWidget* parent) :
QFrame(parent),
p {std::make_unique<CollapsibleGroupImpl>(this)},
ui(new Ui::CollapsibleGroup)
{
ui->setupUi(this);
p->Initialize();
}
CollapsibleGroup::CollapsibleGroup(const QString& title, QWidget* parent) :
QFrame(parent),
p {std::make_unique<CollapsibleGroupImpl>(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

View file

@ -0,0 +1,46 @@
#pragma once
#include <QFrame>
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<CollapsibleGroupImpl> p;
Ui::CollapsibleGroup* ui;
};
} // namespace ui
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CollapsibleGroup</class>
<widget class="QFrame" name="CollapsibleGroup">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="titleButton">
<property name="styleSheet">
<string notr="true">text-align: left;</string>
</property>
<property name="text">
<string>Title</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/square-caret-right-regular.svg</normaloff>
<normalon>:/res/icons/font-awesome-6/square-caret-down-regular.svg</normalon>:/res/icons/font-awesome-6/square-caret-right-regular.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="contentsFrame">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QVBoxLayout" name="contentsLayout"/>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../../scwx-qt.qrc"/>
</resources>
<connections/>
</ui>

@ -1 +1 @@
Subproject commit 875afa5ead329536f802096ca1d2ef1010a7cc6b
Subproject commit b2fa7d866800902f4c092c567017c832bcdbe702