DolphinQt: Refactor, add ConfigControl class

This reduces code duplication in the different ConfigControls. This is
helpful for the next commit, which will modify the now deduplicated
code.
This commit is contained in:
TryTwo 2024-09-17 23:29:13 -07:00 committed by JosJuice
parent 0a84d93a8e
commit 08df9a66e0
15 changed files with 189 additions and 147 deletions

View File

@ -52,6 +52,7 @@ add_executable(dolphin-emu
Config/ConfigControls/ConfigBool.h Config/ConfigControls/ConfigBool.h
Config/ConfigControls/ConfigChoice.cpp Config/ConfigControls/ConfigChoice.cpp
Config/ConfigControls/ConfigChoice.h Config/ConfigControls/ConfigChoice.h
Config/ConfigControls/ConfigControl.h
Config/ConfigControls/ConfigInteger.cpp Config/ConfigControls/ConfigInteger.cpp
Config/ConfigControls/ConfigInteger.h Config/ConfigControls/ConfigInteger.h
Config/ConfigControls/ConfigRadio.cpp Config/ConfigControls/ConfigRadio.cpp

View File

@ -3,31 +3,22 @@
#include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigBool.h"
#include <QEvent>
#include <QFont>
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigBool::ConfigBool(const QString& label, const Config::Info<bool>& setting, bool reverse) ConfigBool::ConfigBool(const QString& label, const Config::Info<bool>& setting, bool reverse)
: ToolTipCheckBox(label), m_setting(setting), m_reverse(reverse) : ConfigControl(label, setting.GetLocation()), m_setting(setting), m_reverse(reverse)
{ {
setChecked(ReadValue(setting) ^ reverse);
connect(this, &QCheckBox::toggled, this, &ConfigBool::Update); connect(this, &QCheckBox::toggled, this, &ConfigBool::Update);
setChecked(Config::Get(m_setting) ^ reverse);
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
setChecked(Config::Get(m_setting) ^ m_reverse);
});
} }
void ConfigBool::Update() void ConfigBool::Update()
{ {
Config::SetBaseOrCurrent(m_setting, static_cast<bool>(isChecked() ^ m_reverse)); const bool value = static_cast<bool>(isChecked() ^ m_reverse);
SaveValue(m_setting, value);
}
void ConfigBool::OnConfigChanged()
{
setChecked(ReadValue(m_setting) ^ m_reverse);
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
namespace Config namespace Config
@ -11,12 +12,15 @@ template <typename T>
class Info; class Info;
} }
class ConfigBool : public ToolTipCheckBox class ConfigBool final : public ConfigControl<ToolTipCheckBox>
{ {
Q_OBJECT Q_OBJECT
public: public:
ConfigBool(const QString& label, const Config::Info<bool>& setting, bool reverse = false); ConfigBool(const QString& label, const Config::Info<bool>& setting, bool reverse = false);
protected:
void OnConfigChanged() override;
private: private:
void Update(); void Update();

View File

@ -5,85 +5,65 @@
#include <QSignalBlocker> #include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigChoice::ConfigChoice(const QStringList& options, const Config::Info<int>& setting) ConfigChoice::ConfigChoice(const QStringList& options, const Config::Info<int>& setting)
: m_setting(setting) : ConfigControl(setting.GetLocation()), m_setting(setting)
{ {
addItems(options); addItems(options);
setCurrentIndex(ReadValue(setting));
connect(this, &QComboBox::currentIndexChanged, this, &ConfigChoice::Update); connect(this, &QComboBox::currentIndexChanged, this, &ConfigChoice::Update);
setCurrentIndex(Config::Get(m_setting));
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
setCurrentIndex(Config::Get(m_setting));
});
} }
void ConfigChoice::Update(int choice) void ConfigChoice::Update(int choice)
{ {
Config::SetBaseOrCurrent(m_setting, choice); SaveValue(m_setting, choice);
}
void ConfigChoice::OnConfigChanged()
{
setCurrentIndex(ReadValue(m_setting));
} }
ConfigStringChoice::ConfigStringChoice(const std::vector<std::string>& options, ConfigStringChoice::ConfigStringChoice(const std::vector<std::string>& options,
const Config::Info<std::string>& setting) const Config::Info<std::string>& setting)
: m_setting(setting), m_text_is_data(true) : ConfigControl(setting.GetLocation()), m_setting(setting), m_text_is_data(true)
{ {
for (const auto& op : options) for (const auto& op : options)
addItem(QString::fromStdString(op)); addItem(QString::fromStdString(op));
Connect();
Load(); Load();
connect(this, &QComboBox::currentIndexChanged, this, &ConfigStringChoice::Update);
} }
ConfigStringChoice::ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options, ConfigStringChoice::ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options,
const Config::Info<std::string>& setting) const Config::Info<std::string>& setting)
: m_setting(setting), m_text_is_data(false) : ConfigControl(setting.GetLocation()), m_setting(setting), m_text_is_data(false)
{ {
for (const auto& [option_text, option_data] : options) for (const auto& [option_text, option_data] : options)
addItem(option_text, option_data); addItem(option_text, option_data);
Connect();
Load();
}
void ConfigStringChoice::Connect()
{
const auto on_config_changed = [this]() {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
Load();
};
connect(&Settings::Instance(), &Settings::ConfigChanged, this, on_config_changed);
connect(this, &QComboBox::currentIndexChanged, this, &ConfigStringChoice::Update); connect(this, &QComboBox::currentIndexChanged, this, &ConfigStringChoice::Update);
Load();
} }
void ConfigStringChoice::Update(int index) void ConfigStringChoice::Update(int index)
{ {
if (m_text_is_data) if (m_text_is_data)
{ SaveValue(m_setting, itemText(index).toStdString());
Config::SetBaseOrCurrent(m_setting, itemText(index).toStdString());
}
else else
{ SaveValue(m_setting, itemData(index).toString().toStdString());
Config::SetBaseOrCurrent(m_setting, itemData(index).toString().toStdString());
}
} }
void ConfigStringChoice::Load() void ConfigStringChoice::Load()
{ {
const QString setting_value = QString::fromStdString(Config::Get(m_setting)); const QString setting_value = QString::fromStdString(ReadValue(m_setting));
const int index = m_text_is_data ? findText(setting_value) : findData(setting_value); const int index = m_text_is_data ? findText(setting_value) : findData(setting_value);
const QSignalBlocker blocker(this); const QSignalBlocker blocker(this);
setCurrentIndex(index); setCurrentIndex(index);
} }
void ConfigStringChoice::OnConfigChanged()
{
Load();
}

View File

@ -7,23 +7,31 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h" #include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"
#include "Common/Config/Config.h" namespace Config
{
template <typename T>
class Info;
}
class ConfigChoice : public ToolTipComboBox class ConfigChoice final : public ConfigControl<ToolTipComboBox>
{ {
Q_OBJECT Q_OBJECT
public: public:
ConfigChoice(const QStringList& options, const Config::Info<int>& setting); ConfigChoice(const QStringList& options, const Config::Info<int>& setting);
protected:
void OnConfigChanged() override;
private: private:
void Update(int choice); void Update(int choice);
Config::Info<int> m_setting; Config::Info<int> m_setting;
}; };
class ConfigStringChoice : public ToolTipComboBox class ConfigStringChoice final : public ConfigControl<ToolTipComboBox>
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -32,11 +40,13 @@ public:
ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options, ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options,
const Config::Info<std::string>& setting); const Config::Info<std::string>& setting);
protected:
void OnConfigChanged() override;
private: private:
void Connect();
void Update(int index); void Update(int index);
void Load(); void Load();
Config::Info<std::string> m_setting; const Config::Info<std::string>& m_setting;
bool m_text_is_data = false; bool m_text_is_data = false;
}; };

View File

@ -0,0 +1,72 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QFont>
#include <QMouseEvent>
#include <QSignalBlocker>
#include "Common/Config/Enums.h"
#include "DolphinQt/Settings.h"
namespace Config
{
template <typename T>
class Info;
struct Location;
} // namespace Config
template <class Derived>
class ConfigControl : public Derived
{
public:
ConfigControl(const Config::Location& location) : m_location(location) { ConnectConfig(); }
ConfigControl(const QString& label, const Config::Location& location)
: Derived(label), m_location(location)
{
ConnectConfig();
}
ConfigControl(const Qt::Orientation& orient, const Config::Location& location)
: Derived(orient), m_location(location)
{
ConnectConfig();
}
const Config::Location GetLocation() const { return m_location; }
protected:
void ConnectConfig()
{
Derived::connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = Derived::font();
bf.setBold(IsConfigLocal());
Derived::setFont(bf);
const QSignalBlocker blocker(this);
OnConfigChanged();
});
}
template <typename T>
void SaveValue(const Config::Info<T>& setting, const T& value)
{
Config::SetBaseOrCurrent(setting, value);
}
template <typename T>
const T ReadValue(const Config::Info<T>& setting) const
{
return Config::Get(setting);
}
virtual void OnConfigChanged() {};
private:
bool IsConfigLocal() const
{
return Config::GetActiveLayerForConfig(m_location) != Config::LayerType::Base;
}
const Config::Location m_location;
};

View File

@ -3,20 +3,15 @@
#include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" #include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h"
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum, ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum,
const Config::Info<float>& setting, float step) const Config::Info<float>& setting, float step)
: ToolTipSlider(Qt::Horizontal), m_minimum(minimum), m_step(step), m_setting(setting) : ConfigControl(Qt::Horizontal, setting.GetLocation()), m_minimum(minimum), m_step(step),
m_setting(setting)
{ {
const float range = maximum - minimum; const float range = maximum - minimum;
const int steps = std::round(range / step); const int steps = std::round(range / step);
const int interval = std::round(range / steps); const int interval = std::round(range / steps);
const int current_value = std::round((Config::Get(m_setting) - minimum) / step); const int current_value = std::round((ReadValue(setting) - minimum) / step);
setMinimum(0); setMinimum(0);
setMaximum(steps); setMaximum(steps);
@ -24,25 +19,21 @@ ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum,
setValue(current_value); setValue(current_value);
connect(this, &ConfigFloatSlider::valueChanged, this, &ConfigFloatSlider::Update); connect(this, &ConfigFloatSlider::valueChanged, this, &ConfigFloatSlider::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
const int value = std::round((Config::Get(m_setting) - m_minimum) / m_step);
setValue(value);
});
} }
void ConfigFloatSlider::Update(int value) void ConfigFloatSlider::Update(int value)
{ {
const float current_value = (m_step * value) + m_minimum; const float current_value = (m_step * value) + m_minimum;
Config::SetBaseOrCurrent(m_setting, current_value);
SaveValue(m_setting, current_value);
} }
float ConfigFloatSlider::GetValue() const float ConfigFloatSlider::GetValue() const
{ {
return (m_step * value()) + m_minimum; return (m_step * value()) + m_minimum;
} }
void ConfigFloatSlider::OnConfigChanged()
{
setValue(std::round((ReadValue(m_setting) - m_minimum) / m_step));
}

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h" #include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"
namespace Config namespace Config
@ -13,7 +14,7 @@ class Info;
// Automatically converts an int slider into a float one. // Automatically converts an int slider into a float one.
// Do not read the int values or ranges directly from it. // Do not read the int values or ranges directly from it.
class ConfigFloatSlider : public ToolTipSlider class ConfigFloatSlider final : public ConfigControl<ToolTipSlider>
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -23,6 +24,9 @@ public:
// Returns the adjusted float value // Returns the adjusted float value
float GetValue() const; float GetValue() const;
protected:
void OnConfigChanged() override;
private: private:
float m_minimum; float m_minimum;
float m_step; float m_step;

View File

@ -3,33 +3,23 @@
#include "DolphinQt/Config/ConfigControls/ConfigInteger.h" #include "DolphinQt/Config/ConfigControls/ConfigInteger.h"
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigInteger::ConfigInteger(int minimum, int maximum, const Config::Info<int>& setting, int step) ConfigInteger::ConfigInteger(int minimum, int maximum, const Config::Info<int>& setting, int step)
: ToolTipSpinBox(), m_setting(setting) : ConfigControl(setting.GetLocation()), m_setting(setting)
{ {
setMinimum(minimum); setMinimum(minimum);
setMaximum(maximum); setMaximum(maximum);
setSingleStep(step); setSingleStep(step);
setValue(ReadValue(setting));
setValue(Config::Get(setting));
connect(this, &ConfigInteger::valueChanged, this, &ConfigInteger::Update); connect(this, &ConfigInteger::valueChanged, this, &ConfigInteger::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
setValue(Config::Get(m_setting));
});
} }
void ConfigInteger::Update(int value) void ConfigInteger::Update(int value)
{ {
Config::SetBaseOrCurrent(m_setting, value); SaveValue(m_setting, value);
}
void ConfigInteger::OnConfigChanged()
{
setValue(ReadValue(m_setting));
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipSpinBox.h" #include "DolphinQt/Config/ToolTipControls/ToolTipSpinBox.h"
namespace Config namespace Config
@ -11,13 +12,16 @@ template <typename T>
class Info; class Info;
} }
class ConfigInteger : public ToolTipSpinBox class ConfigInteger final : public ConfigControl<ToolTipSpinBox>
{ {
Q_OBJECT Q_OBJECT
public: public:
ConfigInteger(int minimum, int maximum, const Config::Info<int>& setting, int step = 1); ConfigInteger(int minimum, int maximum, const Config::Info<int>& setting, int step = 1);
void Update(int value); void Update(int value);
protected:
void OnConfigChanged() override;
private: private:
const Config::Info<int>& m_setting; const Config::Info<int>& m_setting;
}; };

View File

@ -3,33 +3,20 @@
#include "DolphinQt/Config/ConfigControls/ConfigRadio.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h"
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigRadioInt::ConfigRadioInt(const QString& label, const Config::Info<int>& setting, int value) ConfigRadioInt::ConfigRadioInt(const QString& label, const Config::Info<int>& setting, int value)
: ToolTipRadioButton(label), m_setting(setting), m_value(value) : ConfigControl(label, setting.GetLocation()), m_setting(setting), m_value(value)
{ {
setChecked(Config::Get(m_setting) == m_value); setChecked(ReadValue(setting) == value);
connect(this, &QRadioButton::toggled, this, &ConfigRadioInt::Update); connect(this, &QRadioButton::toggled, this, &ConfigRadioInt::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
setChecked(Config::Get(m_setting) == m_value);
});
} }
void ConfigRadioInt::Update() void ConfigRadioInt::Update()
{ {
if (isChecked()) if (isChecked())
{ {
Config::SetBaseOrCurrent(m_setting, m_value); SaveValue(m_setting, m_value);
emit OnSelected(m_value); emit OnSelected(m_value);
} }
else else
@ -37,3 +24,8 @@ void ConfigRadioInt::Update()
emit OnDeselected(m_value); emit OnDeselected(m_value);
} }
} }
void ConfigRadioInt::OnConfigChanged()
{
setChecked(ReadValue(m_setting) == m_value);
}

View File

@ -3,11 +3,16 @@
#pragma once #pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipRadioButton.h" #include "DolphinQt/Config/ToolTipControls/ToolTipRadioButton.h"
#include "Common/Config/Config.h" namespace Config
{
template <typename T>
class Info;
}
class ConfigRadioInt : public ToolTipRadioButton class ConfigRadioInt final : public ConfigControl<ToolTipRadioButton>
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -19,9 +24,12 @@ signals:
void OnSelected(int new_value); void OnSelected(int new_value);
void OnDeselected(int old_value); void OnDeselected(int old_value);
protected:
void OnConfigChanged() override;
private: private:
void Update(); void Update();
Config::Info<int> m_setting; const Config::Info<int>& m_setting;
int m_value; int m_value;
}; };

View File

@ -3,34 +3,24 @@
#include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h"
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigSlider::ConfigSlider(int minimum, int maximum, const Config::Info<int>& setting, int tick) ConfigSlider::ConfigSlider(int minimum, int maximum, const Config::Info<int>& setting, int tick)
: ToolTipSlider(Qt::Horizontal), m_setting(setting) : ConfigControl(Qt::Horizontal, setting.GetLocation()), m_setting(setting)
{ {
setMinimum(minimum); setMinimum(minimum);
setMaximum(maximum); setMaximum(maximum);
setTickInterval(tick); setTickInterval(tick);
setValue(ReadValue(setting));
setValue(Config::Get(setting));
connect(this, &ConfigSlider::valueChanged, this, &ConfigSlider::Update); connect(this, &ConfigSlider::valueChanged, this, &ConfigSlider::Update);
connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this] {
QFont bf = font();
bf.setBold(Config::GetActiveLayerForConfig(m_setting) != Config::LayerType::Base);
setFont(bf);
const QSignalBlocker blocker(this);
setValue(Config::Get(m_setting));
});
} }
void ConfigSlider::Update(int value) void ConfigSlider::Update(int value)
{ {
Config::SetBaseOrCurrent(m_setting, value); SaveValue(m_setting, value);
}
void ConfigSlider::OnConfigChanged()
{
setValue(ReadValue(m_setting));
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h" #include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"
namespace Config namespace Config
@ -11,13 +12,16 @@ template <typename T>
class Info; class Info;
} }
class ConfigSlider : public ToolTipSlider class ConfigSlider final : public ConfigControl<ToolTipSlider>
{ {
Q_OBJECT Q_OBJECT
public: public:
ConfigSlider(int minimum, int maximum, const Config::Info<int>& setting, int tick = 0); ConfigSlider(int minimum, int maximum, const Config::Info<int>& setting, int tick = 0);
void Update(int value); void Update(int value);
protected:
void OnConfigChanged() override;
private: private:
const Config::Info<int>& m_setting; const Config::Info<int>& m_setting;
}; };

View File

@ -241,6 +241,7 @@
--> -->
<ItemGroup> <ItemGroup>
<ClInclude Include="Config\CheatCodeEditor.h" /> <ClInclude Include="Config\CheatCodeEditor.h" />
<ClInclude Include="Config\ConfigControls\ConfigControl.h" />
<ClInclude Include="Config\GameConfigEdit.h" /> <ClInclude Include="Config\GameConfigEdit.h" />
<ClInclude Include="Config\Mapping\MappingCommon.h" /> <ClInclude Include="Config\Mapping\MappingCommon.h" />
<ClInclude Include="Config\Mapping\MappingIndicator.h" /> <ClInclude Include="Config\Mapping\MappingIndicator.h" />