feat(service-menu): pobla AUDIO amb toggles i sliders de volum

This commit is contained in:
2026-05-24 11:49:14 +02:00
parent 71c43ec6fe
commit 56d7d4af52
6 changed files with 148 additions and 5 deletions
+7
View File
@@ -61,6 +61,13 @@ service_menu:
video_vsync: "VSYNC"
video_aa: "ANTIALIAS"
video_postfx: "POSTPROCESSAT"
# Items del submenu AUDIO
audio_master: "AUDIO"
audio_master_volume: "VOLUM GENERAL"
audio_music: "MUSICA"
audio_music_volume: "VOLUM MUSICA"
audio_sound: "EFECTES"
audio_sound_volume: "VOLUM EFECTES"
# Valors comuns
value_on: "ACTIU"
value_off: "INACTIU"
+7
View File
@@ -60,6 +60,13 @@ service_menu:
video_vsync: "VSYNC"
video_aa: "ANTIALIAS"
video_postfx: "POSTPROCESS"
# Items of AUDIO submenu
audio_master: "AUDIO"
audio_master_volume: "MASTER VOLUME"
audio_music: "MUSIC"
audio_music_volume: "MUSIC VOLUME"
audio_sound: "SOUNDS"
audio_sound_volume: "SOUND VOLUME"
# Common values
value_on: "ON"
value_off: "OFF"
+17 -4
View File
@@ -238,14 +238,27 @@ auto Audio::effectiveVolume(float volume, bool channel_enabled) const -> float {
return (enabled_ && channel_enabled) ? volume * config_.volume : 0.0F;
}
// Estableix el volum dels sons (float 0.0..1.0)
// Estableix el volum dels sons (float 0.0..1.0). Actualitza el valor cachejat
// a config_ perquè els getters i les re-aplicacions internes (enableSound,
// setMasterVolume) puguin tornar al volum que l'usuari va triar.
void Audio::setSoundVolume(float sound_volume, Group group) {
engine_->setSoundVolume(effectiveVolume(sound_volume, sound_enabled_), static_cast<int>(group));
config_.sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME);
engine_->setSoundVolume(effectiveVolume(config_.sound_volume, sound_enabled_), static_cast<int>(group));
}
// Estableix el volum de la música (float 0.0..1.0)
// Estableix el volum de la música (float 0.0..1.0). Cf. setSoundVolume.
void Audio::setMusicVolume(float music_volume) {
engine_->setMusicVolume(effectiveVolume(music_volume, music_enabled_));
config_.music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME);
engine_->setMusicVolume(effectiveVolume(config_.music_volume, music_enabled_));
}
// Estableix el volum master (multiplicador aplicat a sound + music). Re-aplica
// els canals perquè el canvi tingui efecte immediat sense esperar al següent
// setSoundVolume/setMusicVolume explícit.
void Audio::setMasterVolume(float master_volume) {
config_.volume = std::clamp(master_volume, MIN_VOLUME, MAX_VOLUME);
setSoundVolume(config_.sound_volume);
setMusicVolume(config_.music_volume);
}
// Aplica una nueva configuración (substitueix la config cachejada i reaplica enables/volums)
+8
View File
@@ -101,6 +101,14 @@ class Audio {
// --- Control de volum (API interna: float 0.0..1.0) ---
void setSoundVolume(float volume, Group group = Group::ALL); // Ajusta el volum dels efectes
void setMusicVolume(float volume); // Ajusta el volum de la música
void setMasterVolume(float volume); // Ajusta el master (re-aplica sound + music)
// Getters dels volums actuals (lectura de la config_ cachejada). Reflexen
// el valor que l'usuari ha triat l'última vegada, independent del gating
// d'enabled/channel.
[[nodiscard]] auto getMasterVolume() const -> float { return config_.volume; }
[[nodiscard]] auto getSoundVolume() const -> float { return config_.sound_volume; }
[[nodiscard]] auto getMusicVolume() const -> float { return config_.music_volume; }
// --- Helpers de conversió para la capa de presentació ---
// UI (menús, notificacions) manega enters 0..100; internament viu float 0..1.
+108 -1
View File
@@ -11,6 +11,7 @@
#include "core/audio/audio.hpp"
#include "core/config/engine_config.hpp"
#include "core/defaults/audio.hpp"
#include "core/defaults/service_menu.hpp"
#include "core/locale/locale.hpp"
#include "core/rendering/sdl_manager.hpp"
@@ -116,7 +117,7 @@ namespace System {
root.title_key = "service_menu.title";
root.items = {
makeSubmenu("service_menu.video", [this] { pushPage(buildVideoPage()); }),
makeSubmenu("service_menu.audio", [this] { pushSubmenuPlaceholder("service_menu.audio"); }),
makeSubmenu("service_menu.audio", [this] { pushPage(buildAudioPage()); }),
makeSubmenu("service_menu.options", [this] { pushSubmenuPlaceholder("service_menu.options"); }),
makeSubmenu("service_menu.system", [this] { pushSubmenuPlaceholder("service_menu.system"); }),
};
@@ -197,6 +198,112 @@ namespace System {
return page;
}
auto ServiceMenu::buildAudioPage() -> Page {
auto on_off_text = [](bool v) -> std::string {
return Locale::get().text(v ? "service_menu.value_on" : "service_menu.value_off");
};
// Aplica un step de volum (±VOLUME_STEP) a un valor 0..1 i retorna el
// resultat clampat. El motor s'encarrega d'aplicar-lo amb el getter.
auto step_volume = [](float current, int dir) -> float {
const float STEP = Defaults::Audio::VOLUME_STEP;
return std::clamp(current + (static_cast<float>(dir) * STEP), 0.0F, 1.0F);
};
Page page;
page.title_key = "service_menu.audio";
page.items = {
// AUDIO (master ON/OFF)
Item{
.kind = Kind::TOGGLE,
.label_key = "service_menu.audio_master",
.selectable = true,
.on_activate = {},
.get_value_text = [on_off_text] {
const Audio* a = Audio::get();
return on_off_text(a != nullptr && a->isEnabled()); },
.on_change = [](int) {
if (auto* a = Audio::get(); a != nullptr) {
a->toggleEnabled();
} },
},
// VOLUM GENERAL (master)
Item{
.kind = Kind::INT_RANGE,
.label_key = "service_menu.audio_master_volume",
.selectable = true,
.on_activate = {},
.get_value_text = [] {
const Audio* a = Audio::get();
const float V = (a != nullptr) ? a->getMasterVolume() : 0.0F;
return std::to_string(Audio::toPercent(V)); },
.on_change = [step_volume](int dir) {
if (auto* a = Audio::get(); a != nullptr) {
a->setMasterVolume(step_volume(a->getMasterVolume(), dir));
} },
},
// MUSICA ON/OFF
Item{
.kind = Kind::TOGGLE,
.label_key = "service_menu.audio_music",
.selectable = true,
.on_activate = {},
.get_value_text = [on_off_text] {
const Audio* a = Audio::get();
return on_off_text(a != nullptr && a->isMusicEnabled()); },
.on_change = [](int) {
if (auto* a = Audio::get(); a != nullptr) {
a->toggleMusic();
} },
},
// VOLUM MUSICA
Item{
.kind = Kind::INT_RANGE,
.label_key = "service_menu.audio_music_volume",
.selectable = true,
.on_activate = {},
.get_value_text = [] {
const Audio* a = Audio::get();
const float V = (a != nullptr) ? a->getMusicVolume() : 0.0F;
return std::to_string(Audio::toPercent(V)); },
.on_change = [step_volume](int dir) {
if (auto* a = Audio::get(); a != nullptr) {
a->setMusicVolume(step_volume(a->getMusicVolume(), dir));
} },
},
// SONS ON/OFF
Item{
.kind = Kind::TOGGLE,
.label_key = "service_menu.audio_sound",
.selectable = true,
.on_activate = {},
.get_value_text = [on_off_text] {
const Audio* a = Audio::get();
return on_off_text(a != nullptr && a->isSoundEnabled()); },
.on_change = [](int) {
if (auto* a = Audio::get(); a != nullptr) {
a->toggleSound();
} },
},
// VOLUM SONS
Item{
.kind = Kind::INT_RANGE,
.label_key = "service_menu.audio_sound_volume",
.selectable = true,
.on_activate = {},
.get_value_text = [] {
const Audio* a = Audio::get();
const float V = (a != nullptr) ? a->getSoundVolume() : 0.0F;
return std::to_string(Audio::toPercent(V)); },
.on_change = [step_volume](int dir) {
if (auto* a = Audio::get(); a != nullptr) {
a->setSoundVolume(step_volume(a->getSoundVolume(), dir));
} },
},
};
return page;
}
void ServiceMenu::pushPage(Page page) {
stack_.push_back(std::move(page));
// El cursor salta a una pagina nova: enganxem el highlight per a
+1
View File
@@ -88,6 +88,7 @@ namespace System {
void buildRootPage();
void pushSubmenuPlaceholder(const std::string& title_key);
[[nodiscard]] auto buildVideoPage() const -> Page;
[[nodiscard]] static auto buildAudioPage() -> Page;
void pushPage(Page page);
void popPage();
void moveCursor(int direction);