diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index a0f4be705..9ebe9858e 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -4821,10 +4821,10 @@ void FullscreenUI::DrawAudioSettingsPage() DrawIntRangeSetting(bsi, FSUI_CSTR("Output Volume"), FSUI_CSTR("Controls the volume of the audio played on the host."), "Audio", "OutputVolume", 100, - 0, 100, "%d%%"); + 0, 200, "%d%%"); DrawIntRangeSetting(bsi, FSUI_CSTR("Fast Forward Volume"), FSUI_CSTR("Controls the volume of the audio played on the host when fast forwarding."), "Audio", - "FastForwardVolume", 100, 0, 100, "%d%%"); + "FastForwardVolume", 200, 0, 100, "%d%%"); DrawToggleSetting(bsi, FSUI_CSTR("Mute All Sound"), FSUI_CSTR("Prevents the emulator from producing any audible sound."), "Audio", "OutputMuted", false); diff --git a/src/core/hotkeys.cpp b/src/core/hotkeys.cpp index c7cf8b50d..e0c99fa6b 100644 --- a/src/core/hotkeys.cpp +++ b/src/core/hotkeys.cpp @@ -518,7 +518,7 @@ DEFINE_HOTKEY("AudioVolumeUp", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOO { g_settings.audio_output_muted = false; - const s32 volume = std::min(System::GetAudioOutputVolume() + 10, 100); + const s32 volume = std::min(System::GetAudioOutputVolume() + 10, 200); g_settings.audio_output_volume = volume; g_settings.audio_fast_forward_volume = volume; SPU::GetOutputStream()->SetOutputVolume(volume); diff --git a/src/duckstation-qt/audiosettingswidget.cpp b/src/duckstation-qt/audiosettingswidget.cpp index d292d8cd6..707c84a4c 100644 --- a/src/duckstation-qt/audiosettingswidget.cpp +++ b/src/duckstation-qt/audiosettingswidget.cpp @@ -84,6 +84,8 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent tr("%"), "Audio", "FastForwardVolume", 100); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.muted, "Audio", "OutputMuted", false); } + connect(m_ui.resetVolume, &QToolButton::clicked, this, [this]() { resetVolume(false); }); + connect(m_ui.resetFastForwardVolume, &QToolButton::clicked, this, [this]() { resetVolume(true); }); dialog->registerWidgetHelp( m_ui.audioBackend, tr("Audio Backend"), QStringLiteral("Cubeb"), @@ -117,6 +119,12 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent dialog->registerWidgetHelp(m_ui.stretchSettings, tr("Stretch Settings"), tr("N/A"), tr("These settings fine-tune the behavior of the SoundTouch audio time stretcher when " "running outside of 100% speed.")); + dialog->registerWidgetHelp(m_ui.resetVolume, tr("Reset Volume"), tr("N/A"), + m_dialog->isPerGameSettings() ? tr("Resets volume back to the global/inherited setting.") : + tr("Resets volume back to the default, i.e. full.")); + dialog->registerWidgetHelp(m_ui.resetFastForwardVolume, tr("Reset Fast Forward Volume"), tr("N/A"), + m_dialog->isPerGameSettings() ? tr("Resets volume back to the global/inherited setting.") : + tr("Resets volume back to the default, i.e. full.")); } AudioSettingsWidget::~AudioSettingsWidget() = default; @@ -478,4 +486,30 @@ void AudioSettingsWidget::onStretchSettingsClicked() }); dlg.exec(); -} \ No newline at end of file +} + +void AudioSettingsWidget::resetVolume(bool fast_forward) +{ + const char* key = fast_forward ? "FastForwardVolume" : "OutputVolume"; + QSlider* const slider = fast_forward ? m_ui.fastForwardVolume : m_ui.volume; + QLabel* const label = fast_forward ? m_ui.fastForwardVolumeLabel : m_ui.volumeLabel; + + if (m_dialog->isPerGameSettings()) + { + m_dialog->removeSettingValue("Audio", key); + + const int value = m_dialog->getEffectiveIntValue("Audio", key, 100); + QSignalBlocker sb(slider); + slider->setValue(value); + label->setText(QStringLiteral("%1%2").arg(value).arg(tr("%"))); + + // remove bold font if it was previously overridden + QFont font(label->font()); + font.setBold(false); + label->setFont(font); + } + else + { + slider->setValue(100); + } +} diff --git a/src/duckstation-qt/audiosettingswidget.h b/src/duckstation-qt/audiosettingswidget.h index 61a94e615..1b23d5d54 100644 --- a/src/duckstation-qt/audiosettingswidget.h +++ b/src/duckstation-qt/audiosettingswidget.h @@ -42,6 +42,7 @@ private: AudioBackend getEffectiveBackend() const; AudioExpansionMode getEffectiveExpansionMode() const; u32 getEffectiveExpansionBlockSize() const; + void resetVolume(bool fast_forward); Ui::AudioSettingsWidget m_ui; SettingsWindow* m_dialog; diff --git a/src/duckstation-qt/audiosettingswidget.ui b/src/duckstation-qt/audiosettingswidget.ui index 2038a5d78..d03773e96 100644 --- a/src/duckstation-qt/audiosettingswidget.ui +++ b/src/duckstation-qt/audiosettingswidget.ui @@ -246,6 +246,16 @@ + + + + Stretch Settings + + + + + + @@ -285,6 +295,16 @@ + + + + Stretch Settings + + + + + + diff --git a/src/duckstation-qt/settingwidgetbinder.h b/src/duckstation-qt/settingwidgetbinder.h index b16016e45..149ae89d1 100644 --- a/src/duckstation-qt/settingwidgetbinder.h +++ b/src/duckstation-qt/settingwidgetbinder.h @@ -34,7 +34,6 @@ namespace SettingWidgetBinder { static constexpr const char* NULLABLE_PROPERTY = "SettingWidgetBinder_isNullable"; static constexpr const char* IS_NULL_PROPERTY = "SettingWidgetBinder_isNull"; static constexpr const char* GLOBAL_VALUE_PROPERTY = "SettingWidgetBinder_globalValue"; -static constexpr const char* IS_UPDATING_PROPERTY = "SettingWidgetBinder_isUpdating"; template struct SettingAccessor @@ -351,39 +350,25 @@ struct SettingAccessor template static void connectValueChanged(QSlider* widget, F func) { - if (!isNullable(widget) || widget->contextMenuPolicy() == Qt::CustomContextMenu) + if (!isNullable(widget)) { widget->connect(widget, &QSlider::valueChanged, func); } else { - // How much do I hate this? A _lot_. We need to be able to run handlers (e.g. for labels), which get connected to - // valueChanged() above, but the user changing the control also triggers valueChanged()... so catch the recursion. - widget->setProperty(IS_UPDATING_PROPERTY, QVariant(false)); - 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)]() { - if (widget->property(IS_UPDATING_PROPERTY).toBool()) - return; - const bool old = widget->blockSignals(true); setNullableIntValue(widget, std::nullopt); widget->blockSignals(old); func(); - - widget->setProperty(IS_UPDATING_PROPERTY, QVariant(true)); - emit widget->valueChanged(widget->value()); - widget->setProperty(IS_UPDATING_PROPERTY, QVariant(false)); }); menu.exec(widget->mapToGlobal(pt)); }); widget->connect(widget, &QSlider::valueChanged, widget, [widget, func = std::move(func)]() { - if (widget->property(IS_UPDATING_PROPERTY).toBool()) - return; - if (widget->property(IS_NULL_PROPERTY).toBool()) widget->setProperty(IS_NULL_PROPERTY, QVariant(false)); func(); @@ -786,42 +771,84 @@ static void BindWidgetToIntSetting(SettingsInterface* sif, WidgetType* widget, s } } -template -static inline void BindWidgetAndLabelToIntSetting(SettingsInterface* sif, T* slider, QLabel* label, +template +static inline void BindWidgetAndLabelToIntSetting(SettingsInterface* sif, WidgetType* widget, QLabel* label, const QString& label_suffix, std::string section, std::string key, - s32 default_value) + int default_value, int option_offset = 0) { - using Accessor = SettingAccessor; + using Accessor = SettingAccessor; + + const s32 global_value = + Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), static_cast(default_value)) - option_offset; - BindWidgetToIntSetting(sif, slider, std::move(section), std::move(key), default_value); if (sif) { QFont orig_font(label->font()); QFont bold_font(orig_font); bold_font.setBold(true); - Accessor::connectValueChanged( - slider, [slider, label, label_suffix, bold_font = std::move(bold_font), orig_font = std::move(orig_font)]() { - std::optional value = Accessor::getNullableIntValue(slider); - if (value.has_value()) + 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 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(value.value()).arg(label_suffix)); + label->setText(QStringLiteral("%1%2").arg(new_value.value()).arg(label_suffix)); } - else + } + else + { + sif->DeleteValue(section.c_str(), key.c_str()); + if (label) { - const int global_value = Accessor::getIntValue(slider); label->setFont(orig_font); label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix)); } - }); + } + + sif->Save(); + g_emu_thread->reloadGameSettings(); + }); } else { - Accessor::connectValueChanged(slider, [slider, label, label_suffix]() { - const int global_value = Accessor::getIntValue(slider); + Accessor::setIntValue(widget, static_cast(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)); + }); } }