mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 22:10:05 +00:00
Refactoring widget functionality out of SettingsVariable into new SettingsInterface
This commit is contained in:
parent
ab91bf9e8d
commit
70565969dc
6 changed files with 340 additions and 194 deletions
228
scwx-qt/source/scwx/qt/settings/settings_interface.cpp
Normal file
228
scwx-qt/source/scwx/qt/settings/settings_interface.cpp
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
#define SETTINGS_INTERFACE_IMPLEMENTATION
|
||||
|
||||
#include <scwx/qt/settings/settings_interface.hpp>
|
||||
#include <scwx/qt/settings/settings_variable.hpp>
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QCoreApplication>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <QWidget>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace settings
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::settings::settings_interface";
|
||||
|
||||
template<class T>
|
||||
class SettingsInterface<T>::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl()
|
||||
{
|
||||
context_->moveToThread(QCoreApplication::instance()->thread());
|
||||
}
|
||||
|
||||
~Impl() {}
|
||||
|
||||
void UpdateEditWidget();
|
||||
void UpdateResetButton();
|
||||
|
||||
SettingsVariable<T>* variable_ {nullptr};
|
||||
bool stagedValid_ {true};
|
||||
|
||||
std::unique_ptr<QObject> context_ {std::make_unique<QObject>()};
|
||||
QWidget* editWidget_ {nullptr};
|
||||
QAbstractButton* resetButton_ {nullptr};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
SettingsInterface<T>::SettingsInterface() : p(std::make_unique<Impl>())
|
||||
{
|
||||
}
|
||||
template<class T>
|
||||
SettingsInterface<T>::~SettingsInterface() = default;
|
||||
|
||||
template<class T>
|
||||
SettingsInterface<T>::SettingsInterface(SettingsInterface&&) noexcept = default;
|
||||
template<class T>
|
||||
SettingsInterface<T>&
|
||||
SettingsInterface<T>::operator=(SettingsInterface&&) noexcept = default;
|
||||
|
||||
template<class T>
|
||||
void SettingsInterface<T>::SetSettingsVariable(SettingsVariable<T>& variable)
|
||||
{
|
||||
p->variable_ = &variable;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsInterface<T>::SetEditWidget(QWidget* widget)
|
||||
{
|
||||
if (p->editWidget_ != nullptr)
|
||||
{
|
||||
QObject::disconnect(p->editWidget_, nullptr, p->context_.get(), nullptr);
|
||||
}
|
||||
|
||||
p->editWidget_ = widget;
|
||||
|
||||
if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(widget))
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
// If the line is edited (not programatically changed), stage the new
|
||||
// value
|
||||
QObject::connect(lineEdit,
|
||||
&QLineEdit::textEdited,
|
||||
p->context_.get(),
|
||||
[this](const QString& text)
|
||||
{
|
||||
// Attempt to stage the value
|
||||
p->stagedValid_ =
|
||||
p->variable_->StageValue(text.toStdString());
|
||||
p->UpdateResetButton();
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (QSpinBox* spinBox = dynamic_cast<QSpinBox*>(widget))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
const std::optional<T> minimum = p->variable_->GetMinimum();
|
||||
const std::optional<T> maximum = p->variable_->GetMaximum();
|
||||
|
||||
if (minimum.has_value())
|
||||
{
|
||||
spinBox->setMinimum(static_cast<int>(*minimum));
|
||||
}
|
||||
if (maximum.has_value())
|
||||
{
|
||||
spinBox->setMaximum(static_cast<int>(*maximum));
|
||||
}
|
||||
|
||||
// If the spin box is edited, stage a changed value
|
||||
QObject::connect(
|
||||
spinBox,
|
||||
&QSpinBox::valueChanged,
|
||||
p->context_.get(),
|
||||
[this](int i)
|
||||
{
|
||||
const T value = p->variable_->GetValue();
|
||||
const std::optional<T> staged = p->variable_->GetStaged();
|
||||
|
||||
// If there is a value staged, and the new value is the same as
|
||||
// the current value, reset the staged value
|
||||
if (staged.has_value() && static_cast<T>(i) == value)
|
||||
{
|
||||
p->variable_->Reset();
|
||||
p->stagedValid_ = true;
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
// If there is no staged value, or if the new value is different
|
||||
// than what is staged, attempt to stage the value
|
||||
else if (!staged.has_value() || static_cast<T>(i) != *staged)
|
||||
{
|
||||
p->stagedValid_ = p->variable_->StageValue(static_cast<T>(i));
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
// Otherwise, don't process an unchanged value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
p->UpdateEditWidget();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsInterface<T>::SetResetButton(QAbstractButton* button)
|
||||
{
|
||||
if (p->resetButton_ != nullptr)
|
||||
{
|
||||
QObject::disconnect(p->resetButton_, nullptr, p->context_.get(), nullptr);
|
||||
}
|
||||
|
||||
p->resetButton_ = button;
|
||||
|
||||
QObject::connect(p->resetButton_,
|
||||
&QAbstractButton::clicked,
|
||||
p->context_.get(),
|
||||
[this]()
|
||||
{
|
||||
T defaultValue = p->variable_->GetDefault();
|
||||
|
||||
if (p->variable_->GetValue() == defaultValue)
|
||||
{
|
||||
// If the current value is default, reset the staged
|
||||
// value
|
||||
p->variable_->Reset();
|
||||
p->stagedValid_ = true;
|
||||
p->UpdateEditWidget();
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stage the default value
|
||||
p->stagedValid_ =
|
||||
p->variable_->StageValue(defaultValue);
|
||||
p->UpdateEditWidget();
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
});
|
||||
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsInterface<T>::Impl::UpdateEditWidget()
|
||||
{
|
||||
// Use the staged value if present, otherwise the current value
|
||||
const std::optional<T> staged = variable_->GetStaged();
|
||||
const T value = variable_->GetValue();
|
||||
const T& displayValue = staged.has_value() ? *staged : value;
|
||||
|
||||
if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editWidget_))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
lineEdit->setText(QString::number(displayValue));
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
lineEdit->setText(QString::fromStdString(displayValue));
|
||||
}
|
||||
}
|
||||
else if (QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editWidget_))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
spinBox->setValue(static_cast<int>(displayValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsInterface<T>::Impl::UpdateResetButton()
|
||||
{
|
||||
const std::optional<T> staged = variable_->GetStaged();
|
||||
const T defaultValue = variable_->GetDefault();
|
||||
const T value = variable_->GetValue();
|
||||
|
||||
if (resetButton_ != nullptr)
|
||||
{
|
||||
if (staged.has_value())
|
||||
{
|
||||
resetButton_->setVisible(!stagedValid_ || *staged != defaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetButton_->setVisible(value != defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace settings
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
71
scwx-qt/source/scwx/qt/settings/settings_interface.hpp
Normal file
71
scwx-qt/source/scwx/qt/settings/settings_interface.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class QAbstractButton;
|
||||
class QWidget;
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace settings
|
||||
{
|
||||
|
||||
template<class T>
|
||||
class SettingsVariable;
|
||||
|
||||
template<class T>
|
||||
class SettingsInterface
|
||||
{
|
||||
public:
|
||||
explicit SettingsInterface();
|
||||
~SettingsInterface();
|
||||
|
||||
SettingsInterface(const SettingsInterface&) = delete;
|
||||
SettingsInterface& operator=(const SettingsInterface&) = delete;
|
||||
|
||||
SettingsInterface(SettingsInterface&&) noexcept;
|
||||
SettingsInterface& operator=(SettingsInterface&&) noexcept;
|
||||
|
||||
/**
|
||||
* Sets the settings variable associated with the interface. This must be
|
||||
* set prior to setting any widgets.
|
||||
*
|
||||
* @param variable Settings variable
|
||||
*/
|
||||
void SetSettingsVariable(SettingsVariable<T>& variable);
|
||||
|
||||
/**
|
||||
* Sets the edit widget from the settings dialog.
|
||||
*
|
||||
* @param widget Edit widget
|
||||
*/
|
||||
void SetEditWidget(QWidget* widget);
|
||||
|
||||
/**
|
||||
* Sets the reset button from the settings dialog.
|
||||
*
|
||||
* @param button Reset button
|
||||
*/
|
||||
void SetResetButton(QAbstractButton* button);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
#ifdef SETTINGS_INTERFACE_IMPLEMENTATION
|
||||
template class SettingsInterface<bool>;
|
||||
template class SettingsInterface<std::int64_t>;
|
||||
template class SettingsInterface<std::string>;
|
||||
|
||||
// Containers are not to be used directly
|
||||
template class SettingsInterface<std::vector<std::int64_t>>;
|
||||
#endif
|
||||
|
||||
} // namespace settings
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -5,11 +5,6 @@
|
|||
|
||||
#include <boost/json.hpp>
|
||||
#include <fmt/ostream.h>
|
||||
#include <QAbstractButton>
|
||||
#include <QCoreApplication>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
#include <QWidget>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -25,28 +20,15 @@ template<class T>
|
|||
class SettingsVariable<T>::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl()
|
||||
{
|
||||
context_->moveToThread(QCoreApplication::instance()->thread());
|
||||
}
|
||||
|
||||
explicit Impl() {}
|
||||
~Impl() {}
|
||||
|
||||
void UpdateEditWidget();
|
||||
void UpdateResetButton();
|
||||
|
||||
T value_ {};
|
||||
T default_ {};
|
||||
std::optional<T> staged_ {};
|
||||
std::optional<T> minimum_ {};
|
||||
std::optional<T> maximum_ {};
|
||||
std::function<bool(const T&)> validator_ {nullptr};
|
||||
|
||||
bool stagedValid_ {true};
|
||||
|
||||
std::unique_ptr<QObject> context_ {std::make_unique<QObject>()};
|
||||
QWidget* editWidget_ {nullptr};
|
||||
QAbstractButton* resetButton_ {nullptr};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
|
@ -143,19 +125,15 @@ void SettingsVariable<T>::SetValueToDefault()
|
|||
template<class T>
|
||||
bool SettingsVariable<T>::StageValue(const T& value)
|
||||
{
|
||||
bool validated = false;
|
||||
|
||||
if (Validate(value))
|
||||
{
|
||||
p->staged_ = value;
|
||||
p->stagedValid_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->stagedValid_ = false;
|
||||
p->staged_ = value;
|
||||
validated = true;
|
||||
}
|
||||
|
||||
p->UpdateResetButton();
|
||||
|
||||
return p->stagedValid_;
|
||||
return validated;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
@ -165,7 +143,6 @@ void SettingsVariable<T>::Commit()
|
|||
{
|
||||
p->value_ = std::move(*p->staged_);
|
||||
p->staged_.reset();
|
||||
p->stagedValid_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,10 +150,12 @@ template<class T>
|
|||
void SettingsVariable<T>::Reset()
|
||||
{
|
||||
p->staged_.reset();
|
||||
p->stagedValid_ = true;
|
||||
}
|
||||
|
||||
p->UpdateEditWidget();
|
||||
p->UpdateResetButton();
|
||||
template<class T>
|
||||
std::optional<T> SettingsVariable<T>::GetStaged() const
|
||||
{
|
||||
return p->staged_;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
@ -268,139 +247,6 @@ void SettingsVariable<T>::WriteValue(boost::json::object& json) const
|
|||
json[name()] = boost::json::value_from<T&>(p->value_);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsVariable<T>::SetEditWidget(QWidget* widget)
|
||||
{
|
||||
p->editWidget_ = widget;
|
||||
|
||||
if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(widget))
|
||||
{
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
// If the line is edited (not programatically changed), stage the new
|
||||
// value
|
||||
QObject::connect(lineEdit,
|
||||
&QLineEdit::textEdited,
|
||||
p->context_.get(),
|
||||
[this](const QString& text)
|
||||
{
|
||||
// Attempt to stage the value
|
||||
StageValue(text.toStdString());
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (QSpinBox* spinBox = dynamic_cast<QSpinBox*>(widget))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
if (p->minimum_.has_value())
|
||||
{
|
||||
spinBox->setMinimum(static_cast<int>(*p->minimum_));
|
||||
}
|
||||
if (p->maximum_.has_value())
|
||||
{
|
||||
spinBox->setMaximum(static_cast<int>(*p->maximum_));
|
||||
}
|
||||
|
||||
// If the spin box is edited, stage a changed value
|
||||
QObject::connect(spinBox,
|
||||
&QSpinBox::valueChanged,
|
||||
p->context_.get(),
|
||||
[this](int i)
|
||||
{
|
||||
// If there is a value staged, and the new value is
|
||||
// the same as the current value, reset the staged
|
||||
// value
|
||||
if (p->staged_.has_value() &&
|
||||
static_cast<T>(i) == p->value_)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
// If there is no staged value, or if the new value
|
||||
// is different than what is staged, attempt to
|
||||
// stage the value
|
||||
else if (!p->staged_.has_value() ||
|
||||
static_cast<T>(i) != *p->staged_)
|
||||
{
|
||||
StageValue(static_cast<T>(i));
|
||||
}
|
||||
// Otherwise, don't process an unchanged value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
p->UpdateEditWidget();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsVariable<T>::SetResetButton(QAbstractButton* button)
|
||||
{
|
||||
p->resetButton_ = button;
|
||||
|
||||
QObject::connect(p->resetButton_,
|
||||
&QAbstractButton::clicked,
|
||||
p->context_.get(),
|
||||
[this]()
|
||||
{
|
||||
if (p->value_ == p->default_)
|
||||
{
|
||||
// If the current value is default, reset the staged
|
||||
// value
|
||||
Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stage the default value
|
||||
StageValue(p->default_);
|
||||
p->UpdateEditWidget();
|
||||
}
|
||||
});
|
||||
|
||||
p->UpdateResetButton();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsVariable<T>::Impl::UpdateEditWidget()
|
||||
{
|
||||
// Use the staged value if present, otherwise the current value
|
||||
T& value = staged_.has_value() ? *staged_ : value_;
|
||||
|
||||
if (QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editWidget_))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
lineEdit->setText(QString::number(value));
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
lineEdit->setText(QString::fromStdString(value));
|
||||
}
|
||||
}
|
||||
else if (QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editWidget_))
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>)
|
||||
{
|
||||
spinBox->setValue(static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SettingsVariable<T>::Impl::UpdateResetButton()
|
||||
{
|
||||
if (resetButton_ != nullptr)
|
||||
{
|
||||
if (staged_.has_value())
|
||||
{
|
||||
resetButton_->setVisible(!stagedValid_ || *staged_ != default_);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetButton_->setVisible(value_ != default_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool SettingsVariable<T>::Equals(const SettingsVariableBase& o) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,6 +81,13 @@ public:
|
|||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Gets the staged value of the settings variable, if defined.
|
||||
*
|
||||
* @return Optional staged value
|
||||
*/
|
||||
std::optional<T> GetStaged() const;
|
||||
|
||||
/**
|
||||
* Validate the value against the defined parameters of the settings
|
||||
* variable.
|
||||
|
|
@ -158,20 +165,6 @@ public:
|
|||
*/
|
||||
virtual void WriteValue(boost::json::object& json) const override;
|
||||
|
||||
/**
|
||||
* Sets the edit widget from the settings dialog.
|
||||
*
|
||||
* @param widget Edit widget
|
||||
*/
|
||||
void SetEditWidget(QWidget* widget);
|
||||
|
||||
/**
|
||||
* Sets the reset button from the settings dialog.
|
||||
*
|
||||
* @param button Reset button
|
||||
*/
|
||||
void SetResetButton(QAbstractButton* button);
|
||||
|
||||
protected:
|
||||
virtual bool Equals(const SettingsVariableBase& o) const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <scwx/awips/phenomenon.hpp>
|
||||
#include <scwx/qt/config/radar_site.hpp>
|
||||
#include <scwx/qt/manager/settings_manager.hpp>
|
||||
#include <scwx/qt/settings/settings_interface.hpp>
|
||||
|
||||
#include <QToolButton>
|
||||
|
||||
|
|
@ -51,6 +52,12 @@ public:
|
|||
void SetupPalettesAlertsTab();
|
||||
|
||||
SettingsDialog* self_;
|
||||
|
||||
settings::SettingsInterface<std::string> defaultRadarSite_ {};
|
||||
settings::SettingsInterface<int64_t> gridWidth_ {};
|
||||
settings::SettingsInterface<int64_t> gridHeight_ {};
|
||||
settings::SettingsInterface<std::string> mapboxApiKey_ {};
|
||||
settings::SettingsInterface<bool> debugEnabled_ {};
|
||||
};
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget* parent) :
|
||||
|
|
@ -104,25 +111,24 @@ void SettingsDialogImpl::SetupGeneralTab()
|
|||
settings::GeneralSettings& generalSettings =
|
||||
manager::SettingsManager::general_settings();
|
||||
|
||||
generalSettings.default_radar_site().SetEditWidget(
|
||||
self_->ui->radarSiteComboBox);
|
||||
generalSettings.default_radar_site().SetResetButton(
|
||||
self_->ui->resetRadarSiteButton);
|
||||
defaultRadarSite_.SetSettingsVariable(generalSettings.default_radar_site());
|
||||
defaultRadarSite_.SetEditWidget(self_->ui->radarSiteComboBox);
|
||||
defaultRadarSite_.SetResetButton(self_->ui->resetRadarSiteButton);
|
||||
|
||||
generalSettings.grid_width().SetEditWidget(self_->ui->gridWidthSpinBox);
|
||||
generalSettings.grid_width().SetResetButton(self_->ui->resetGridWidthButton);
|
||||
gridWidth_.SetSettingsVariable(generalSettings.grid_width());
|
||||
gridWidth_.SetEditWidget(self_->ui->gridWidthSpinBox);
|
||||
gridWidth_.SetResetButton(self_->ui->resetGridWidthButton);
|
||||
|
||||
generalSettings.grid_height().SetEditWidget(self_->ui->gridHeightSpinBox);
|
||||
generalSettings.grid_height().SetResetButton(
|
||||
self_->ui->resetGridHeightButton);
|
||||
gridHeight_.SetSettingsVariable(generalSettings.grid_height());
|
||||
gridHeight_.SetEditWidget(self_->ui->gridHeightSpinBox);
|
||||
gridHeight_.SetResetButton(self_->ui->resetGridHeightButton);
|
||||
|
||||
generalSettings.mapbox_api_key().SetEditWidget(
|
||||
self_->ui->mapboxApiKeyLineEdit);
|
||||
generalSettings.mapbox_api_key().SetResetButton(
|
||||
self_->ui->resetMapboxApiKeyButton);
|
||||
mapboxApiKey_.SetSettingsVariable(generalSettings.mapbox_api_key());
|
||||
mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit);
|
||||
mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton);
|
||||
|
||||
generalSettings.debug_enabled().SetEditWidget(
|
||||
self_->ui->debugEnabledCheckBox);
|
||||
debugEnabled_.SetSettingsVariable(generalSettings.debug_enabled());
|
||||
debugEnabled_.SetEditWidget(self_->ui->debugEnabledCheckBox);
|
||||
}
|
||||
|
||||
void SettingsDialogImpl::SetupPalettesColorTablesTab()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue