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/ConfigChoice.cpp
Config/ConfigControls/ConfigChoice.h
Config/ConfigControls/ConfigControl.h
Config/ConfigControls/ConfigInteger.cpp
Config/ConfigControls/ConfigInteger.h
Config/ConfigControls/ConfigRadio.cpp

View File

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

View File

@ -5,85 +5,65 @@
#include <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigChoice::ConfigChoice(const QStringList& options, const Config::Info<int>& setting)
: m_setting(setting)
: ConfigControl(setting.GetLocation()), m_setting(setting)
{
addItems(options);
setCurrentIndex(ReadValue(setting));
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)
{
Config::SetBaseOrCurrent(m_setting, choice);
SaveValue(m_setting, choice);
}
void ConfigChoice::OnConfigChanged()
{
setCurrentIndex(ReadValue(m_setting));
}
ConfigStringChoice::ConfigStringChoice(const std::vector<std::string>& options,
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)
addItem(QString::fromStdString(op));
Connect();
Load();
connect(this, &QComboBox::currentIndexChanged, this, &ConfigStringChoice::Update);
}
ConfigStringChoice::ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options,
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)
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);
Load();
}
void ConfigStringChoice::Update(int index)
{
if (m_text_is_data)
{
Config::SetBaseOrCurrent(m_setting, itemText(index).toStdString());
}
SaveValue(m_setting, itemText(index).toStdString());
else
{
Config::SetBaseOrCurrent(m_setting, itemData(index).toString().toStdString());
}
SaveValue(m_setting, itemData(index).toString().toStdString());
}
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 QSignalBlocker blocker(this);
setCurrentIndex(index);
}
void ConfigStringChoice::OnConfigChanged()
{
Load();
}

View File

@ -7,23 +7,31 @@
#include <utility>
#include <vector>
#include "DolphinQt/Config/ConfigControls/ConfigControl.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
public:
ConfigChoice(const QStringList& options, const Config::Info<int>& setting);
protected:
void OnConfigChanged() override;
private:
void Update(int choice);
Config::Info<int> m_setting;
};
class ConfigStringChoice : public ToolTipComboBox
class ConfigStringChoice final : public ConfigControl<ToolTipComboBox>
{
Q_OBJECT
public:
@ -32,11 +40,13 @@ public:
ConfigStringChoice(const std::vector<std::pair<QString, QString>>& options,
const Config::Info<std::string>& setting);
protected:
void OnConfigChanged() override;
private:
void Connect();
void Update(int index);
void Load();
Config::Info<std::string> m_setting;
const Config::Info<std::string>& m_setting;
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 <QSignalBlocker>
#include "Common/Config/Config.h"
#include "DolphinQt/Settings.h"
ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum,
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 int steps = std::round(range / step);
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);
setMaximum(steps);
@ -24,25 +19,21 @@ ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum,
setValue(current_value);
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)
{
const float current_value = (m_step * value) + m_minimum;
Config::SetBaseOrCurrent(m_setting, current_value);
SaveValue(m_setting, current_value);
}
float ConfigFloatSlider::GetValue() const
{
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
#include "DolphinQt/Config/ConfigControls/ConfigControl.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h"
namespace Config
@ -13,7 +14,7 @@ class Info;
// Automatically converts an int slider into a float one.
// Do not read the int values or ranges directly from it.
class ConfigFloatSlider : public ToolTipSlider
class ConfigFloatSlider final : public ConfigControl<ToolTipSlider>
{
Q_OBJECT
public:
@ -23,6 +24,9 @@ public:
// Returns the adjusted float value
float GetValue() const;
protected:
void OnConfigChanged() override;
private:
float m_minimum;
float m_step;

View File

@ -3,33 +3,23 @@
#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)
: ToolTipSpinBox(), m_setting(setting)
: ConfigControl(setting.GetLocation()), m_setting(setting)
{
setMinimum(minimum);
setMaximum(maximum);
setSingleStep(step);
setValue(Config::Get(setting));
setValue(ReadValue(setting));
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)
{
Config::SetBaseOrCurrent(m_setting, value);
SaveValue(m_setting, value);
}
void ConfigInteger::OnConfigChanged()
{
setValue(ReadValue(m_setting));
}

View File

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

View File

@ -3,33 +3,20 @@
#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)
: 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(&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()
{
if (isChecked())
{
Config::SetBaseOrCurrent(m_setting, m_value);
SaveValue(m_setting, m_value);
emit OnSelected(m_value);
}
else
@ -37,3 +24,8 @@ void ConfigRadioInt::Update()
emit OnDeselected(m_value);
}
}
void ConfigRadioInt::OnConfigChanged()
{
setChecked(ReadValue(m_setting) == m_value);
}

View File

@ -3,11 +3,16 @@
#pragma once
#include "DolphinQt/Config/ConfigControls/ConfigControl.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
public:
@ -19,9 +24,12 @@ signals:
void OnSelected(int new_value);
void OnDeselected(int old_value);
protected:
void OnConfigChanged() override;
private:
void Update();
Config::Info<int> m_setting;
const Config::Info<int>& m_setting;
int m_value;
};

View File

@ -3,34 +3,24 @@
#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)
: ToolTipSlider(Qt::Horizontal), m_setting(setting)
: ConfigControl(Qt::Horizontal, setting.GetLocation()), m_setting(setting)
{
setMinimum(minimum);
setMaximum(maximum);
setTickInterval(tick);
setValue(Config::Get(setting));
setValue(ReadValue(setting));
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)
{
Config::SetBaseOrCurrent(m_setting, value);
SaveValue(m_setting, value);
}
void ConfigSlider::OnConfigChanged()
{
setValue(ReadValue(m_setting));
}

View File

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

View File

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