mirror of https://github.com/PCSX2/pcsx2.git
Qt: Handle sliders in per-game settings
This commit is contained in:
parent
7fae0f499f
commit
dceac5372a
|
@ -259,37 +259,107 @@ namespace SettingWidgetBinder
|
||||||
template <>
|
template <>
|
||||||
struct SettingAccessor<QSlider>
|
struct SettingAccessor<QSlider>
|
||||||
{
|
{
|
||||||
|
static bool isNullable(const QSlider* widget) { return widget->property(NULLABLE_PROPERTY).toBool(); }
|
||||||
|
|
||||||
static bool getBoolValue(const QSlider* widget) { return widget->value() > 0; }
|
static bool getBoolValue(const QSlider* widget) { return widget->value() > 0; }
|
||||||
static void setBoolValue(QSlider* widget, bool value) { widget->setValue(value ? 1 : 0); }
|
static void setBoolValue(QSlider* widget, bool value) { widget->setValue(value ? 1 : 0); }
|
||||||
static void makeNullableBool(QSlider* widget, bool globalSetting) { widget->setEnabled(false); }
|
static void makeNullableBool(QSlider* widget, bool globalSetting)
|
||||||
static std::optional<bool> getNullableBoolValue(const QSlider* widget) { return getBoolValue(widget); }
|
{
|
||||||
static void setNullableBoolValue(QSlider* widget, std::optional<bool> value) { setBoolValue(widget, value.value_or(false)); }
|
widget->setProperty(NULLABLE_PROPERTY, QVariant(true));
|
||||||
|
widget->setProperty(GLOBAL_VALUE_PROPERTY, QVariant(globalSetting));
|
||||||
|
}
|
||||||
|
static std::optional<bool> getNullableBoolValue(const QSlider* widget)
|
||||||
|
{
|
||||||
|
if (widget->property(IS_NULL_PROPERTY).toBool())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return getBoolValue(widget);
|
||||||
|
}
|
||||||
|
static void setNullableBoolValue(QSlider* widget, std::optional<bool> value)
|
||||||
|
{
|
||||||
|
widget->setProperty(IS_NULL_PROPERTY, QVariant(!value.has_value()));
|
||||||
|
setBoolValue(widget, value.has_value() ? value.value() : widget->property(GLOBAL_VALUE_PROPERTY).toBool());
|
||||||
|
}
|
||||||
|
|
||||||
static int getIntValue(const QSlider* widget) { return widget->value(); }
|
static int getIntValue(const QSlider* widget) { return widget->value(); }
|
||||||
static void setIntValue(QSlider* widget, int value) { widget->setValue(value); }
|
static void setIntValue(QSlider* widget, int value) { widget->setValue(value); }
|
||||||
static void makeNullableInt(QSlider* widget, int globalValue) { widget->setEnabled(false); }
|
static void makeNullableInt(QSlider* widget, int globalValue)
|
||||||
static std::optional<int> getNullableIntValue(const QSlider* widget) { return getIntValue(widget); }
|
{
|
||||||
static void setNullableIntValue(QSlider* widget, std::optional<int> value) { setIntValue(widget, value.value_or(0)); }
|
widget->setProperty(NULLABLE_PROPERTY, QVariant(true));
|
||||||
|
widget->setProperty(GLOBAL_VALUE_PROPERTY, QVariant(globalValue));
|
||||||
|
}
|
||||||
|
static std::optional<int> getNullableIntValue(const QSlider* widget)
|
||||||
|
{
|
||||||
|
if (widget->property(IS_NULL_PROPERTY).toBool())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return getIntValue(widget);
|
||||||
|
}
|
||||||
|
static void setNullableIntValue(QSlider* widget, std::optional<int> value)
|
||||||
|
{
|
||||||
|
widget->setProperty(IS_NULL_PROPERTY, QVariant(!value.has_value()));
|
||||||
|
setIntValue(widget, value.has_value() ? value.value() : widget->property(GLOBAL_VALUE_PROPERTY).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
static float getFloatValue(const QSlider* widget) { return static_cast<float>(widget->value()); }
|
static float getFloatValue(const QSlider* widget) { return static_cast<float>(widget->value()); }
|
||||||
static void setFloatValue(QSlider* widget, float value) { widget->setValue(static_cast<int>(value)); }
|
static void setFloatValue(QSlider* widget, float value) { widget->setValue(static_cast<int>(value)); }
|
||||||
static void makeNullableFloat(QSlider* widget, float globalValue) { widget->setEnabled(false); }
|
static void makeNullableFloat(QSlider* widget, float globalValue) { widget->setEnabled(false); }
|
||||||
static std::optional<float> getNullableFloatValue(const QSlider* widget) { return getFloatValue(widget); }
|
static std::optional<float> getNullableFloatValue(const QSlider* widget)
|
||||||
static void setNullableFloatValue(QSlider* widget, std::optional<float> value) { setFloatValue(widget, value.value_or(0.0f)); }
|
{
|
||||||
|
if (widget->property(IS_NULL_PROPERTY).toBool())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return getFloatValue(widget);
|
||||||
|
}
|
||||||
|
static void setNullableFloatValue(QSlider* widget, std::optional<float> value)
|
||||||
|
{
|
||||||
|
widget->setProperty(IS_NULL_PROPERTY, QVariant(!value.has_value()));
|
||||||
|
setFloatValue(widget, value.has_value() ? value.value() : widget->property(GLOBAL_VALUE_PROPERTY).toFloat());
|
||||||
|
}
|
||||||
|
|
||||||
static QString getStringValue(const QSlider* widget) { return QString::number(widget->value()); }
|
static QString getStringValue(const QSlider* widget) { return QString::number(widget->value()); }
|
||||||
static void setStringValue(QSlider* widget, const QString& value) { widget->setValue(value.toInt()); }
|
static void setStringValue(QSlider* widget, const QString& value) { widget->setValue(value.toInt()); }
|
||||||
static void makeNullableString(QSlider* widget, const QString& globalValue) { widget->setEnabled(false); }
|
static void makeNullableString(QSlider* widget, const QString& globalValue) { widget->setEnabled(false); }
|
||||||
static std::optional<QString> getNullableStringValue(const QSlider* widget) { return getStringValue(widget); }
|
static std::optional<QString> getNullableStringValue(const QSlider* widget)
|
||||||
|
{
|
||||||
|
if (widget->property(IS_NULL_PROPERTY).toBool())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return getStringValue(widget);
|
||||||
|
}
|
||||||
static void setNullableStringValue(QSlider* widget, std::optional<QString> value)
|
static void setNullableStringValue(QSlider* widget, std::optional<QString> value)
|
||||||
{
|
{
|
||||||
setStringValue(widget, value.value_or(QString()));
|
widget->setProperty(IS_NULL_PROPERTY, QVariant(!value.has_value()));
|
||||||
|
setStringValue(widget, value.has_value() ? value.value() : widget->property(GLOBAL_VALUE_PROPERTY).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
static void connectValueChanged(QSlider* widget, F func)
|
static void connectValueChanged(QSlider* widget, F func)
|
||||||
{
|
{
|
||||||
widget->connect(widget, &QSlider::valueChanged, func);
|
if (!isNullable(widget))
|
||||||
|
{
|
||||||
|
widget->connect(widget, &QSlider::valueChanged, func);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
widget->connect(widget, &QSlider::customContextMenuRequested, widget, [widget, func](const QPoint& pt) {
|
||||||
|
QMenu menu(widget);
|
||||||
|
widget->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, widget,
|
||||||
|
[widget, func = std::move(func)]() {
|
||||||
|
const bool old = widget->blockSignals(true);
|
||||||
|
setNullableIntValue(widget, std::nullopt);
|
||||||
|
widget->blockSignals(old);
|
||||||
|
func();
|
||||||
|
});
|
||||||
|
menu.exec(widget->mapToGlobal(pt));
|
||||||
|
});
|
||||||
|
widget->connect(widget, &QSlider::valueChanged, widget, [widget, func = std::move(func)]() {
|
||||||
|
if (widget->property(IS_NULL_PROPERTY).toBool())
|
||||||
|
widget->setProperty(IS_NULL_PROPERTY, QVariant(false));
|
||||||
|
func();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -670,6 +740,87 @@ namespace SettingWidgetBinder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename WidgetType>
|
||||||
|
static inline void BindWidgetAndLabelToIntSetting(SettingsInterface* sif, WidgetType* widget, QLabel* label,
|
||||||
|
const QString& label_suffix, std::string section, std::string key,
|
||||||
|
int default_value, int option_offset = 0)
|
||||||
|
{
|
||||||
|
using Accessor = SettingAccessor<WidgetType>;
|
||||||
|
|
||||||
|
const s32 global_value =
|
||||||
|
Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), static_cast<s32>(default_value)) - option_offset;
|
||||||
|
|
||||||
|
if (sif)
|
||||||
|
{
|
||||||
|
QFont orig_font(label->font());
|
||||||
|
QFont bold_font(orig_font);
|
||||||
|
bold_font.setBold(true);
|
||||||
|
|
||||||
|
Accessor::makeNullableInt(widget, global_value);
|
||||||
|
|
||||||
|
int sif_value;
|
||||||
|
if (sif->GetIntValue(section.c_str(), key.c_str(), &sif_value))
|
||||||
|
{
|
||||||
|
Accessor::setNullableIntValue(widget, sif_value - option_offset);
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(sif_value).arg(label_suffix));
|
||||||
|
label->setFont(bold_font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Accessor::setNullableIntValue(widget, std::nullopt);
|
||||||
|
if (label)
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessor::connectValueChanged(widget, [sif, widget, label, label_suffix, section = std::move(section),
|
||||||
|
key = std::move(key), option_offset, global_value,
|
||||||
|
bold_font = std::move(bold_font), orig_font = std::move(orig_font)]() {
|
||||||
|
if (std::optional<int> new_value = Accessor::getNullableIntValue(widget); new_value.has_value())
|
||||||
|
{
|
||||||
|
sif->SetIntValue(section.c_str(), key.c_str(), new_value.value() + option_offset);
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
label->setFont(bold_font);
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(new_value.value()).arg(label_suffix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sif->DeleteValue(section.c_str(), key.c_str());
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
label->setFont(orig_font);
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sif->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Accessor::setIntValue(widget, static_cast<int>(global_value));
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
||||||
|
|
||||||
|
Accessor::connectValueChanged(
|
||||||
|
widget, [widget, label, label_suffix, section = std::move(section), key = std::move(key), option_offset]() {
|
||||||
|
const int new_value = Accessor::getIntValue(widget);
|
||||||
|
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
g_emu_thread->applySettings();
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
label->setText(QStringLiteral("%1%2").arg(new_value).arg(label_suffix));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename WidgetType>
|
template <typename WidgetType>
|
||||||
static inline void BindWidgetToFloatSetting(
|
static inline void BindWidgetToFloatSetting(
|
||||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||||
|
@ -1088,78 +1239,4 @@ namespace SettingWidgetBinder
|
||||||
|
|
||||||
widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed));
|
widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
|
|
||||||
std::string section, std::string key, s32 default_value)
|
|
||||||
{
|
|
||||||
s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
|
||||||
|
|
||||||
//Clamp in case setting was updated manually using INI
|
|
||||||
global_value = std::clamp(global_value, slider->minimum(), slider->maximum());
|
|
||||||
|
|
||||||
if (sif)
|
|
||||||
{
|
|
||||||
const QFont orig_font(label->font());
|
|
||||||
QFont bold_font(orig_font);
|
|
||||||
bold_font.setBold(true);
|
|
||||||
|
|
||||||
s32 current_value = sif->GetOptionalIntValue(section.c_str(), key.c_str()).value_or(global_value);
|
|
||||||
current_value = std::clamp(current_value, slider->minimum(), slider->maximum());
|
|
||||||
|
|
||||||
slider->setValue(current_value);
|
|
||||||
|
|
||||||
label->setText(QStringLiteral("%1%2").arg(current_value).arg(label_suffix));
|
|
||||||
if (current_value == global_value)
|
|
||||||
label->setFont(orig_font);
|
|
||||||
else
|
|
||||||
label->setFont(bold_font);
|
|
||||||
|
|
||||||
slider->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
slider->connect(slider, &QSpinBox::customContextMenuRequested, slider,
|
|
||||||
[sif, slider, label, label_suffix, orig_font = std::move(orig_font), section, key, default_value](const QPoint& pt) {
|
|
||||||
QMenu menu(slider);
|
|
||||||
slider->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, slider,
|
|
||||||
[sif, slider, label, label_suffix, orig_font, section, key, default_value]() {
|
|
||||||
s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
|
||||||
global_value = std::clamp(global_value, slider->minimum(), slider->maximum());
|
|
||||||
|
|
||||||
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
|
||||||
label->setFont(orig_font);
|
|
||||||
|
|
||||||
if (sif->ContainsValue(section.c_str(), key.c_str()))
|
|
||||||
{
|
|
||||||
sif->DeleteValue(section.c_str(), key.c_str());
|
|
||||||
sif->Save();
|
|
||||||
g_emu_thread->reloadGameSettings();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
menu.exec(slider->mapToGlobal(pt));
|
|
||||||
});
|
|
||||||
|
|
||||||
slider->connect(slider, &QSlider::valueChanged, slider,
|
|
||||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key), orig_font = std::move(orig_font),
|
|
||||||
bold_font = std::move(bold_font)](int value) {
|
|
||||||
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
|
|
||||||
|
|
||||||
if (label->font() != bold_font)
|
|
||||||
label->setFont(bold_font);
|
|
||||||
sif->SetIntValue(section.c_str(), key.c_str(), value);
|
|
||||||
sif->Save();
|
|
||||||
g_emu_thread->reloadGameSettings();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
slider->setValue(global_value);
|
|
||||||
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
|
||||||
|
|
||||||
slider->connect(slider, &QSlider::valueChanged, slider,
|
|
||||||
[label, label_suffix, section = std::move(section), key = std::move(key)](int value) {
|
|
||||||
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
|
|
||||||
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), value);
|
|
||||||
Host::CommitBaseSettingChanges();
|
|
||||||
g_emu_thread->applySettings();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace SettingWidgetBinder
|
} // namespace SettingWidgetBinder
|
||||||
|
|
|
@ -43,10 +43,10 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent
|
||||||
expansionModeChanged();
|
expansionModeChanged();
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.outputModule, "SPU2/Output", "OutputModule", DEFAULT_OUTPUT_MODULE);
|
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.outputModule, "SPU2/Output", "OutputModule", DEFAULT_OUTPUT_MODULE);
|
||||||
SettingWidgetBinder::BindSliderToIntSetting(
|
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(
|
||||||
//: Measuring unit that will appear after the number selected in its option. Adapt the space depending on your language's rules.
|
//: Measuring unit that will appear after the number selected in its option. Adapt the space depending on your language's rules.
|
||||||
sif, m_ui.targetLatency, m_ui.targetLatencyLabel, tr(" ms"), "SPU2/Output", "Latency", DEFAULT_TARGET_LATENCY);
|
sif, m_ui.targetLatency, m_ui.targetLatencyLabel, tr(" ms"), "SPU2/Output", "Latency", DEFAULT_TARGET_LATENCY);
|
||||||
SettingWidgetBinder::BindSliderToIntSetting(
|
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(
|
||||||
sif, m_ui.outputLatency, m_ui.outputLatencyLabel, tr(" ms"), "SPU2/Output", "OutputLatency", DEFAULT_OUTPUT_LATENCY);
|
sif, m_ui.outputLatency, m_ui.outputLatencyLabel, tr(" ms"), "SPU2/Output", "OutputLatency", DEFAULT_OUTPUT_LATENCY);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.outputLatencyMinimal, "SPU2/Output", "OutputLatencyMinimal", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.outputLatencyMinimal, "SPU2/Output", "OutputLatencyMinimal", false);
|
||||||
connect(m_ui.outputModule, &QComboBox::currentIndexChanged, this, &AudioSettingsWidget::outputModuleChanged);
|
connect(m_ui.outputModule, &QComboBox::currentIndexChanged, this, &AudioSettingsWidget::outputModuleChanged);
|
||||||
|
@ -72,11 +72,11 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingWidgetBinder::BindSliderToIntSetting(sif, m_ui.sequenceLength, m_ui.sequenceLengthLabel, tr(" ms"), "Soundtouch",
|
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(sif, m_ui.sequenceLength, m_ui.sequenceLengthLabel, tr(" ms"), "Soundtouch",
|
||||||
"SequenceLengthMS", DEFAULT_SOUNDTOUCH_SEQUENCE_LENGTH);
|
"SequenceLengthMS", DEFAULT_SOUNDTOUCH_SEQUENCE_LENGTH);
|
||||||
SettingWidgetBinder::BindSliderToIntSetting(
|
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(
|
||||||
sif, m_ui.seekWindowSize, m_ui.seekWindowSizeLabel, tr(" ms"), "Soundtouch", "SeekWindowMS", DEFAULT_SOUNDTOUCH_SEEK_WINDOW);
|
sif, m_ui.seekWindowSize, m_ui.seekWindowSizeLabel, tr(" ms"), "Soundtouch", "SeekWindowMS", DEFAULT_SOUNDTOUCH_SEEK_WINDOW);
|
||||||
SettingWidgetBinder::BindSliderToIntSetting(
|
SettingWidgetBinder::BindWidgetAndLabelToIntSetting(
|
||||||
sif, m_ui.overlap, m_ui.overlapLabel, tr(" ms"), "Soundtouch", "OverlapMS", DEFAULT_SOUNDTOUCH_OVERLAP);
|
sif, m_ui.overlap, m_ui.overlapLabel, tr(" ms"), "Soundtouch", "OverlapMS", DEFAULT_SOUNDTOUCH_OVERLAP);
|
||||||
connect(m_ui.resetTimestretchDefaults, &QPushButton::clicked, this, &AudioSettingsWidget::resetTimestretchDefaults);
|
connect(m_ui.resetTimestretchDefaults, &QPushButton::clicked, this, &AudioSettingsWidget::resetTimestretchDefaults);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue