Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/duckstation-qt/controllersettingwidgetbinder.h
4802 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#pragma once
5
6
#include "qthost.h"
7
#include "settingwidgetbinder.h"
8
9
#include "core/host.h"
10
11
#include <QtCore/QtCore>
12
#include <QtGui/QAction>
13
#include <QtWidgets/QCheckBox>
14
#include <QtWidgets/QComboBox>
15
#include <QtWidgets/QDoubleSpinBox>
16
#include <QtWidgets/QLineEdit>
17
#include <QtWidgets/QSlider>
18
#include <QtWidgets/QSpinBox>
19
#include <optional>
20
#include <type_traits>
21
22
/// This nastyness is required because input profiles aren't overlaid settings like the rest of them, it's
23
/// input profile *or* global, not both.
24
namespace ControllerSettingWidgetBinder {
25
/// Interface specific method of BindWidgetToBoolSetting().
26
template<typename WidgetType>
27
inline void BindWidgetToInputProfileBool(SettingsInterface* sif, WidgetType* widget, std::string section,
28
std::string key, bool default_value)
29
{
30
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
31
32
if (sif)
33
{
34
const bool value = sif->GetBoolValue(section.c_str(), key.c_str(), default_value);
35
Accessor::setBoolValue(widget, value);
36
37
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
38
const bool new_value = Accessor::getBoolValue(widget);
39
sif->SetBoolValue(section.c_str(), key.c_str(), new_value);
40
QtHost::SaveGameSettings(sif, false);
41
g_emu_thread->reloadInputProfile();
42
});
43
}
44
else
45
{
46
const bool value = Host::GetBaseBoolSettingValue(section.c_str(), key.c_str(), default_value);
47
Accessor::setBoolValue(widget, value);
48
49
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
50
const bool new_value = Accessor::getBoolValue(widget);
51
Host::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
52
Host::CommitBaseSettingChanges();
53
g_emu_thread->applySettings();
54
});
55
}
56
}
57
58
/// Interface specific method of BindWidgetToIntSetting().
59
template<typename WidgetType>
60
inline void BindWidgetToInputProfileInt(SettingsInterface* sif, WidgetType* widget, std::string section,
61
std::string key, int default_value, int option_offset = 0)
62
{
63
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
64
65
if (sif)
66
{
67
const int value = sif->GetIntValue(section.c_str(), key.c_str(), default_value) - option_offset;
68
Accessor::setIntValue(widget, value);
69
70
Accessor::connectValueChanged(widget,
71
[sif, widget, section = std::move(section), key = std::move(key), option_offset]() {
72
const int new_value = Accessor::getIntValue(widget);
73
sif->SetIntValue(section.c_str(), key.c_str(), new_value + option_offset);
74
QtHost::SaveGameSettings(sif, false);
75
g_emu_thread->reloadInputProfile();
76
});
77
}
78
else
79
{
80
const int value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value) - option_offset;
81
Accessor::setIntValue(widget, value);
82
83
Accessor::connectValueChanged(
84
widget, [widget, section = std::move(section), key = std::move(key), option_offset]() {
85
const int new_value = Accessor::getIntValue(widget);
86
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
87
Host::CommitBaseSettingChanges();
88
g_emu_thread->applySettings();
89
});
90
}
91
}
92
93
/// Interface specific method of BindWidgetToFloatSetting().
94
template<typename WidgetType>
95
inline void BindWidgetToInputProfileFloat(SettingsInterface* sif, WidgetType* widget, std::string section,
96
std::string key, float default_value)
97
{
98
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
99
100
if (sif)
101
{
102
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
103
Accessor::setFloatValue(widget, value);
104
105
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
106
const float new_value = Accessor::getFloatValue(widget);
107
sif->SetFloatValue(section.c_str(), key.c_str(), new_value);
108
QtHost::SaveGameSettings(sif, false);
109
g_emu_thread->reloadInputProfile();
110
});
111
}
112
else
113
{
114
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
115
Accessor::setFloatValue(widget, value);
116
117
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
118
const float new_value = Accessor::getFloatValue(widget);
119
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
120
Host::CommitBaseSettingChanges();
121
g_emu_thread->applySettings();
122
});
123
}
124
}
125
126
/// Interface specific method of BindWidgetToNormalizedSetting().
127
template<typename WidgetType>
128
inline void BindWidgetToInputProfileNormalized(SettingsInterface* sif, WidgetType* widget, std::string section,
129
std::string key, float range, float default_value)
130
{
131
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
132
133
if (sif)
134
{
135
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
136
Accessor::setIntValue(widget, static_cast<int>(value * range));
137
138
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), range]() {
139
const int new_value = Accessor::getIntValue(widget);
140
sif->SetFloatValue(section.c_str(), key.c_str(), static_cast<float>(new_value) / range);
141
QtHost::SaveGameSettings(sif, false);
142
g_emu_thread->reloadInputProfile();
143
});
144
}
145
else
146
{
147
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
148
Accessor::setIntValue(widget, static_cast<int>(value * range));
149
150
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), range]() {
151
const float new_value = (static_cast<float>(Accessor::getIntValue(widget)) / range);
152
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
153
Host::CommitBaseSettingChanges();
154
g_emu_thread->applySettings();
155
});
156
}
157
}
158
159
/// Interface specific method of BindWidgetToStringSetting().
160
template<typename WidgetType>
161
inline void BindWidgetToInputProfileString(SettingsInterface* sif, WidgetType* widget, std::string section,
162
std::string key, std::string default_value = std::string())
163
{
164
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
165
166
if (sif)
167
{
168
const QString value(
169
QString::fromStdString(sif->GetStringValue(section.c_str(), key.c_str(), default_value.c_str())));
170
171
Accessor::setStringValue(widget, value);
172
173
Accessor::connectValueChanged(widget, [widget, sif, section = std::move(section), key = std::move(key)]() {
174
sif->SetStringValue(section.c_str(), key.c_str(), Accessor::getStringValue(widget).toUtf8().constData());
175
QtHost::SaveGameSettings(sif, false);
176
g_emu_thread->reloadInputProfile();
177
});
178
}
179
else
180
{
181
const QString value(
182
QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
183
184
Accessor::setStringValue(widget, value);
185
186
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
187
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(),
188
Accessor::getStringValue(widget).toUtf8().constData());
189
Host::CommitBaseSettingChanges();
190
g_emu_thread->applySettings();
191
});
192
}
193
}
194
195
/// Interface specific method of BindWidgetToEnumSetting().
196
template<typename WidgetType, typename DataType, typename ValueCountType>
197
inline void BindWidgetToInputProfileEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section,
198
std::string key,
199
std::optional<DataType> (*from_string_function)(const char* str),
200
const char* (*to_string_function)(DataType value),
201
const char* (*to_display_name_function)(DataType value),
202
DataType default_value, ValueCountType value_count)
203
{
204
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
205
using UnderlyingType = std::underlying_type_t<DataType>;
206
207
for (UnderlyingType i = 0; i < static_cast<UnderlyingType>(value_count); i++)
208
Accessor::addOption(widget, to_display_name_function(static_cast<DataType>(i)));
209
210
const std::string value =
211
sif ? sif->GetStringValue(section.c_str(), key.c_str(), to_string_function(default_value)) :
212
Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), to_string_function(default_value));
213
const std::optional<DataType> typed_value = from_string_function(value.c_str());
214
if (typed_value.has_value())
215
Accessor::setIntValue(widget, static_cast<int>(static_cast<UnderlyingType>(typed_value.value())));
216
else
217
Accessor::setIntValue(widget, static_cast<int>(static_cast<UnderlyingType>(default_value)));
218
219
if (sif)
220
{
221
Accessor::connectValueChanged(
222
widget, [sif, widget, section = std::move(section), key = std::move(key), to_string_function]() {
223
const DataType value = static_cast<DataType>(static_cast<UnderlyingType>(Accessor::getIntValue(widget)));
224
const char* string_value = to_string_function(value);
225
sif->SetStringValue(section.c_str(), key.c_str(), string_value);
226
QtHost::SaveGameSettings(sif, true);
227
g_emu_thread->reloadInputProfile();
228
});
229
}
230
else
231
{
232
Accessor::connectValueChanged(
233
widget, [widget, section = std::move(section), key = std::move(key), to_string_function]() {
234
const DataType value = static_cast<DataType>(static_cast<UnderlyingType>(Accessor::getIntValue(widget)));
235
const char* string_value = to_string_function(value);
236
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), string_value);
237
Host::CommitBaseSettingChanges();
238
g_emu_thread->applySettings();
239
});
240
}
241
}
242
} // namespace ControllerSettingWidgetBinder
243
244