Qt: Add volume reset button

This commit is contained in:
Stenzek 2024-04-25 13:21:12 +10:00
parent 7548113afd
commit 5e9a47f82b
No known key found for this signature in database
6 changed files with 118 additions and 36 deletions

View File

@ -4821,10 +4821,10 @@ void FullscreenUI::DrawAudioSettingsPage()
DrawIntRangeSetting(bsi, FSUI_CSTR("Output Volume"), DrawIntRangeSetting(bsi, FSUI_CSTR("Output Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host."), "Audio", "OutputVolume", 100, 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"), DrawIntRangeSetting(bsi, FSUI_CSTR("Fast Forward Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host when fast forwarding."), "Audio", 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"), DrawToggleSetting(bsi, FSUI_CSTR("Mute All Sound"),
FSUI_CSTR("Prevents the emulator from producing any audible sound."), "Audio", "OutputMuted", FSUI_CSTR("Prevents the emulator from producing any audible sound."), "Audio", "OutputMuted",
false); false);

View File

@ -518,7 +518,7 @@ DEFINE_HOTKEY("AudioVolumeUp", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOO
{ {
g_settings.audio_output_muted = false; g_settings.audio_output_muted = false;
const s32 volume = std::min<s32>(System::GetAudioOutputVolume() + 10, 100); const s32 volume = std::min<s32>(System::GetAudioOutputVolume() + 10, 200);
g_settings.audio_output_volume = volume; g_settings.audio_output_volume = volume;
g_settings.audio_fast_forward_volume = volume; g_settings.audio_fast_forward_volume = volume;
SPU::GetOutputStream()->SetOutputVolume(volume); SPU::GetOutputStream()->SetOutputVolume(volume);

View File

@ -84,6 +84,8 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsWindow* dialog, QWidget* parent
tr("%"), "Audio", "FastForwardVolume", 100); tr("%"), "Audio", "FastForwardVolume", 100);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.muted, "Audio", "OutputMuted", false); 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( dialog->registerWidgetHelp(
m_ui.audioBackend, tr("Audio Backend"), QStringLiteral("Cubeb"), 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"), 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 " tr("These settings fine-tune the behavior of the SoundTouch audio time stretcher when "
"running outside of 100% speed.")); "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; AudioSettingsWidget::~AudioSettingsWidget() = default;
@ -478,4 +486,30 @@ void AudioSettingsWidget::onStretchSettingsClicked()
}); });
dlg.exec(); dlg.exec();
} }
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);
}
}

View File

@ -42,6 +42,7 @@ private:
AudioBackend getEffectiveBackend() const; AudioBackend getEffectiveBackend() const;
AudioExpansionMode getEffectiveExpansionMode() const; AudioExpansionMode getEffectiveExpansionMode() const;
u32 getEffectiveExpansionBlockSize() const; u32 getEffectiveExpansionBlockSize() const;
void resetVolume(bool fast_forward);
Ui::AudioSettingsWidget m_ui; Ui::AudioSettingsWidget m_ui;
SettingsWindow* m_dialog; SettingsWindow* m_dialog;

View File

@ -246,6 +246,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="resetVolume">
<property name="toolTip">
<string>Stretch Settings</string>
</property>
<property name="icon">
<iconset theme="refresh-line"/>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
@ -285,6 +295,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="resetFastForwardVolume">
<property name="toolTip">
<string>Stretch Settings</string>
</property>
<property name="icon">
<iconset theme="refresh-line"/>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">

View File

@ -34,7 +34,6 @@ namespace SettingWidgetBinder {
static constexpr const char* NULLABLE_PROPERTY = "SettingWidgetBinder_isNullable"; static constexpr const char* NULLABLE_PROPERTY = "SettingWidgetBinder_isNullable";
static constexpr const char* IS_NULL_PROPERTY = "SettingWidgetBinder_isNull"; static constexpr const char* IS_NULL_PROPERTY = "SettingWidgetBinder_isNull";
static constexpr const char* GLOBAL_VALUE_PROPERTY = "SettingWidgetBinder_globalValue"; static constexpr const char* GLOBAL_VALUE_PROPERTY = "SettingWidgetBinder_globalValue";
static constexpr const char* IS_UPDATING_PROPERTY = "SettingWidgetBinder_isUpdating";
template<typename T> template<typename T>
struct SettingAccessor struct SettingAccessor
@ -351,39 +350,25 @@ struct SettingAccessor<QSlider>
template<typename F> template<typename F>
static void connectValueChanged(QSlider* widget, F func) static void connectValueChanged(QSlider* widget, F func)
{ {
if (!isNullable(widget) || widget->contextMenuPolicy() == Qt::CustomContextMenu) if (!isNullable(widget))
{ {
widget->connect(widget, &QSlider::valueChanged, func); widget->connect(widget, &QSlider::valueChanged, func);
} }
else 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->setContextMenuPolicy(Qt::CustomContextMenu);
widget->connect(widget, &QSlider::customContextMenuRequested, widget, [widget, func](const QPoint& pt) { widget->connect(widget, &QSlider::customContextMenuRequested, widget, [widget, func](const QPoint& pt) {
QMenu menu(widget); QMenu menu(widget);
widget->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, widget, widget->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, widget,
[widget, func = std::move(func)]() { [widget, func = std::move(func)]() {
if (widget->property(IS_UPDATING_PROPERTY).toBool())
return;
const bool old = widget->blockSignals(true); const bool old = widget->blockSignals(true);
setNullableIntValue(widget, std::nullopt); setNullableIntValue(widget, std::nullopt);
widget->blockSignals(old); widget->blockSignals(old);
func(); 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)); menu.exec(widget->mapToGlobal(pt));
}); });
widget->connect(widget, &QSlider::valueChanged, widget, [widget, func = std::move(func)]() { 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()) if (widget->property(IS_NULL_PROPERTY).toBool())
widget->setProperty(IS_NULL_PROPERTY, QVariant(false)); widget->setProperty(IS_NULL_PROPERTY, QVariant(false));
func(); func();
@ -786,42 +771,84 @@ static void BindWidgetToIntSetting(SettingsInterface* sif, WidgetType* widget, s
} }
} }
template<typename T> template<typename WidgetType>
static inline void BindWidgetAndLabelToIntSetting(SettingsInterface* sif, T* slider, QLabel* label, static inline void BindWidgetAndLabelToIntSetting(SettingsInterface* sif, WidgetType* widget, QLabel* label,
const QString& label_suffix, std::string section, std::string key, const QString& label_suffix, std::string section, std::string key,
s32 default_value) int default_value, int option_offset = 0)
{ {
using Accessor = SettingAccessor<T>; using Accessor = SettingAccessor<WidgetType>;
const s32 global_value =
Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), static_cast<s32>(default_value)) - option_offset;
BindWidgetToIntSetting(sif, slider, std::move(section), std::move(key), default_value);
if (sif) if (sif)
{ {
QFont orig_font(label->font()); QFont orig_font(label->font());
QFont bold_font(orig_font); QFont bold_font(orig_font);
bold_font.setBold(true); bold_font.setBold(true);
Accessor::connectValueChanged( Accessor::makeNullableInt(widget, global_value);
slider, [slider, label, label_suffix, bold_font = std::move(bold_font), orig_font = std::move(orig_font)]() {
std::optional<int> value = Accessor::getNullableIntValue(slider); int sif_value;
if (value.has_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->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->setFont(orig_font);
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix)); label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
} }
}); }
sif->Save();
g_emu_thread->reloadGameSettings();
});
} }
else else
{ {
Accessor::connectValueChanged(slider, [slider, label, label_suffix]() { Accessor::setIntValue(widget, static_cast<int>(global_value));
const int global_value = Accessor::getIntValue(slider);
if (label)
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix)); 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));
});
} }
} }