From 74bbd4b62e095de66d2fbff87a847da6a7a0adaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 24 Oct 2026 01:40:44 +0200 Subject: [PATCH] UI: Use ChoiceGroup on more settings-like screens Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/ControlMappingScreen.cpp | 22 +++++++-------- UI/CustomButtonMappingScreen.cpp | 14 +++++----- UI/CwCheatScreen.cpp | 18 ++++++------ UI/DevScreens.cpp | 8 +++--- UI/DriverManagerScreen.cpp | 6 ++-- UI/RemoteISOScreen.cpp | 20 +++++++------- UI/RetroAchievementScreens.cpp | 47 ++++++++++++++++---------------- UI/TabbedDialogScreen.cpp | 6 ++-- UI/TiltAnalogSettingsScreen.cpp | 32 +++++++++++----------- 9 files changed, 87 insertions(+), 86 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 7523041d8d..75681fbf97 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -528,34 +528,34 @@ void AnalogCalibrationScreen::CreateSettingsViews(UI::ViewGroup *scrollContents) using namespace UI; auto co = GetI18NCategory(I18NCat::CONTROLS); - scrollContents->Add(new ItemHeader(co->T("Analog Settings"))); + ChoiceGroup *analogSettings = scrollContents->Add(new ChoiceGroup(co->T("Analog Settings"))); // TODO: Would be nicer if these didn't pop up... - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 0.5f, 0.15f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0")); - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, 0.0f, co->T("Low end radius"), 0.01f, screenManager(), "/ 1.0")); - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 2.0f, 1.1f, co->T("Sensitivity (scale)", "Sensitivity"), 0.01f, screenManager(), "x")); + analogSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogDeadzone, 0.0f, 0.5f, 0.15f, co->T("Deadzone radius"), 0.01f, screenManager(), "/ 1.0")); + analogSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogInverseDeadzone, 0.0f, 1.0f, 0.0f, co->T("Low end radius"), 0.01f, screenManager(), "/ 1.0")); + analogSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogSensitivity, 0.0f, 2.0f, 1.1f, co->T("Sensitivity (scale)", "Sensitivity"), 0.01f, screenManager(), "x")); // Legacy circular toggle. Disabled when deadzone shape is set to Circle, since that already provides circular behavior. - CheckBox *circularCheck = scrollContents->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular stick input"))); + CheckBox *circularCheck = analogSettings->Add(new CheckBox(&g_Config.bAnalogIsCircular, co->T("Circular stick input"))); circularCheck->SetEnabledFunc([] { return g_Config.iAnalogDeadzoneShape != 0; // Disabled when shape is Circle (redundant) }); - scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.1f, 20.0f, 8.0f, co->T("Auto-rotation speed"), 1.0f, screenManager())); + analogSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAutoRotSpeed, 0.1f, 20.0f, 8.0f, co->T("Auto-rotation speed"), 1.0f, screenManager())); // Advanced deadzone settings (Steam Input-style). - scrollContents->Add(new ItemHeader(co->T("Advanced Deadzone Settings"))); + ChoiceGroup *deadzoneSettings = scrollContents->Add(new ChoiceGroup(co->T("Advanced Deadzone Settings"))); static const char *deadzoneShapes[] = { "Circle", "Square", "Cross" }; - scrollContents->Add(new PopupMultiChoice(&g_Config.iAnalogDeadzoneShape, co->T("Deadzone shape"), deadzoneShapes, 0, ARRAY_SIZE(deadzoneShapes), I18NCat::CONTROLS, screenManager())); + deadzoneSettings->Add(new PopupMultiChoice(&g_Config.iAnalogDeadzoneShape, co->T("Deadzone shape"), deadzoneShapes, 0, ARRAY_SIZE(deadzoneShapes), I18NCat::CONTROLS, screenManager())); - PopupSliderChoiceFloat *axialDZ = scrollContents->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAxialDeadzone, 0.0f, 0.5f, 0.0f, co->T("Axial anti-deadzone"), 0.01f, screenManager(), "/ 1.0")); + PopupSliderChoiceFloat *axialDZ = deadzoneSettings->Add(new PopupSliderChoiceFloat(&g_Config.fAnalogAxialDeadzone, 0.0f, 0.5f, 0.0f, co->T("Axial anti-deadzone"), 0.01f, screenManager(), "/ 1.0")); axialDZ->SetEnabledFunc([] { return g_Config.iAnalogDeadzoneShape == 2; // Only enabled for Cross shape }); static const char *responseCurves[] = { "Linear", "Aggressive", "Relaxed", "Wide" }; - scrollContents->Add(new PopupMultiChoice(&g_Config.iAnalogResponseCurve, co->T("Response curve"), responseCurves, 0, ARRAY_SIZE(responseCurves), I18NCat::CONTROLS, screenManager())); + deadzoneSettings->Add(new PopupMultiChoice(&g_Config.iAnalogResponseCurve, co->T("Response curve"), responseCurves, 0, ARRAY_SIZE(responseCurves), I18NCat::CONTROLS, screenManager())); - scrollContents->Add(new Choice(co->T("Reset to defaults")))->OnClick.Handle(this, &AnalogCalibrationScreen::OnResetToDefaults); + scrollContents->Add(new ChoiceGroup(""))->Add(new Choice(co->T("Reset to defaults")))->OnClick.Handle(this, &AnalogCalibrationScreen::OnResetToDefaults); } void AnalogCalibrationScreen::CreateContentViews(UI::ViewGroup *parent) { diff --git a/UI/CustomButtonMappingScreen.cpp b/UI/CustomButtonMappingScreen.cpp index 08c479d8d0..3abef446c1 100644 --- a/UI/CustomButtonMappingScreen.cpp +++ b/UI/CustomButtonMappingScreen.cpp @@ -162,10 +162,10 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) { LinearLayout *vertLayout = new LinearLayout(ORIENT_VERTICAL); rightScroll->Add(vertLayout); - vertLayout->Add(new ItemHeader(co->T("Button style"))); - vertLayout->Add(new CheckBox(show, co->T("Visible"))); + ChoiceGroup *styleSettings = vertLayout->Add(new ChoiceGroup(co->T("Button style"))); + styleSettings->Add(new CheckBox(show, co->T("Visible"))); - Choice *icon = vertLayout->Add(new Choice(co->T("Icon"))); + Choice *icon = styleSettings->Add(new Choice(co->T("Icon"))); icon->SetIconRight(ImageID(customKeyImages[cfg->image].i), 1.0f, customKeyImages[cfg->image].r*PI/180, false, false); // Set right icon on the choice icon->OnClick.Add([=](UI::EventParams &e) { auto iconScreen = new ButtonIconScreen(co->T("Icon"), &(cfg->image)); @@ -175,7 +175,7 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) { screenManager()->push(iconScreen); }); - Choice *shape = vertLayout->Add(new Choice(co->T("Shape"))); + Choice *shape = styleSettings->Add(new Choice(co->T("Shape"))); shape->SetIconRight(ImageID(customKeyShapes[cfg->shape].l), 0.6f, customKeyShapes[cfg->shape].r*PI/180, customKeyShapes[cfg->shape].f, false); // Set right icon on the choice shape->OnClick.Add([=](UI::EventParams &e) { auto shape = new ButtonShapeScreen(co->T("Shape"), &(cfg->shape)); @@ -185,9 +185,9 @@ void CustomButtonMappingScreen::CreateDialogViews(UI::ViewGroup *parent) { screenManager()->push(shape); }); - vertLayout->Add(new ItemHeader(co->T("Button Binding"))); - vertLayout->Add(new CheckBox(&(cfg->toggle), co->T("Toggle mode"))); - vertLayout->Add(new CheckBox(&(cfg->repeat), co->T("Repeat mode"))); + ChoiceGroup *bindingSettings = vertLayout->Add(new ChoiceGroup(co->T("Button Binding"))); + bindingSettings->Add(new CheckBox(&(cfg->toggle), co->T("Toggle mode"))); + bindingSettings->Add(new CheckBox(&(cfg->repeat), co->T("Repeat mode"))); const int cellSize = 400; UI::GridLayoutSettings gridsettings(cellSize, 64, 5); diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index bb3b1587a5..4ccb296ea2 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -223,9 +223,9 @@ void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) { auto mm = GetI18NCategory(I18NCat::MAINMENU); //leftColumn->Add(new Choice(cw->T("Add Cheat")))->OnClick.Handle(this, &CwCheatScreen::OnAddCheat); - leftColumn->Add(new ItemHeader(cw->T("Import Cheats"))); + ChoiceGroup *importGroup = leftColumn->Add(new ChoiceGroup(cw->T("Import Cheats"))); - leftColumn->Add(new Choice(cw->T("Download cheat database")))->OnClick.Add([this](UI::EventParams &) { + importGroup->Add(new Choice(cw->T("Download cheat database")))->OnClick.Add([this](UI::EventParams &) { screenManager()->push(new CwCheatDownloadPopupScreen()); }); @@ -235,11 +235,11 @@ void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) { std::string title = StringFromFormat(cw->T_cstr("Import from %s"), "PSP/Cheats/cheat.db"); - leftColumn->Add(new Choice(title))->OnClick.Handle(this, &CwCheatScreen::OnImportCheat); - leftColumn->Add(new Choice(mm->T("Browse"), ImageID("I_FOLDER_OPEN")))->OnClick.Handle(this, &CwCheatScreen::OnImportBrowse); + importGroup->Add(new Choice(title))->OnClick.Handle(this, &CwCheatScreen::OnImportCheat); + importGroup->Add(new Choice(mm->T("Browse"), ImageID("I_FOLDER_OPEN")))->OnClick.Handle(this, &CwCheatScreen::OnImportBrowse); - leftColumn->Add(new ItemHeader(di->T("Options"))); - Choice *searchChoice = leftColumn->Add(new Choice(di->T("Search"), ImageID("I_SEARCH"))); + ChoiceGroup *optionsGroup = leftColumn->Add(new ChoiceGroup(di->T("Options"))); + Choice *searchChoice = optionsGroup->Add(new Choice(di->T("Search"), ImageID("I_SEARCH"))); searchChoice->OnClick.Add([this, searchChoice, screenManager = screenManager(), token = GetRequesterToken()](UI::EventParams &) { auto di = GetI18NCategory(I18NCat::DIALOG); AskForInput(screenManager, token, searchChoice, di->T("Search"), [this](const std::string &text, bool success) { @@ -251,10 +251,10 @@ void CwCheatScreen::CreateSettingsViews(UI::ViewGroup *leftColumn) { }); }); #if !defined(MOBILE_DEVICE) - leftColumn->Add(new Choice(cw->T("Edit Cheat File")))->OnClick.Handle(this, &CwCheatScreen::OnEditCheatFile); + optionsGroup->Add(new Choice(cw->T("Edit Cheat File")))->OnClick.Handle(this, &CwCheatScreen::OnEditCheatFile); #endif - leftColumn->Add(new Choice(di->T("Disable All")))->OnClick.Handle(this, &CwCheatScreen::OnDisableAll); - leftColumn->Add(new PopupSliderChoice(&g_Config.iCwCheatRefreshIntervalMs, 1, 1000, 77, cw->T("Refresh interval"), 1, screenManager()))->SetFormat(di->T("%d ms")); + optionsGroup->Add(new Choice(di->T("Disable All")))->OnClick.Handle(this, &CwCheatScreen::OnDisableAll); + optionsGroup->Add(new PopupSliderChoice(&g_Config.iCwCheatRefreshIntervalMs, 1, 1000, 77, cw->T("Refresh interval"), 1, screenManager()))->SetFormat(di->T("%d ms")); } void CwCheatScreen::CreateContentViews(UI::ViewGroup *parent) { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index cdd9846c80..d8bcef71af 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -456,11 +456,11 @@ void JitDebugScreen::CreateViews() { topbar->Add(new Choice(di->T("Enable All")))->OnClick.Handle(this, &JitDebugScreen::OnEnableAll); vert->Add(topbar); - vert->Add(new ItemHeader(dev->T("Disabled JIT functionality"))); + ChoiceGroup *disabledFlags = vert->Add(new ChoiceGroup(dev->T("Disabled JIT functionality"))); for (auto flag : jitDisableFlags) { // Do not add translation of these. - vert->Add(new BitCheckBox(&g_Config.uJitDisableFlags, (uint32_t)flag.flag, flag.name)); + disabledFlags->Add(new BitCheckBox(&g_Config.uJitDisableFlags, (uint32_t)flag.flag, flag.name)); } } @@ -639,11 +639,11 @@ void FrameDumpTestScreen::CreateTabs() { auto dev = GetI18NCategory(I18NCat::DEVELOPER); AddTab("General", dev->T("Dumps"), [this](UI::LinearLayout *parent) { - parent->Add(new ItemHeader("GE Frame Dumps")); + ChoiceGroup *dumps = parent->Add(new ChoiceGroup("GE Frame Dumps")); for (auto &file : files_) { std::string url = framedumpsBaseUrl + file; - Choice *c = parent->Add(new Choice(file)); + Choice *c = dumps->Add(new Choice(file)); c->SetTag(url); c->OnClick.Add([this, url = Path(url)](UI::EventParams &e) { INFO_LOG(Log::Common, "Trying to launch '%s'", url.c_str()); diff --git a/UI/DriverManagerScreen.cpp b/UI/DriverManagerScreen.cpp index 62d9d68692..b42868fcd3 100644 --- a/UI/DriverManagerScreen.cpp +++ b/UI/DriverManagerScreen.cpp @@ -165,9 +165,9 @@ void DriverManagerScreen::CreateDriverTab(UI::ViewGroup *drivers) { auto di = GetI18NCategory(I18NCat::DIALOG); auto gr = GetI18NCategory(I18NCat::GRAPHICS); - drivers->Add(new ItemHeader(gr->T("AdrenoTools driver manager"))); - auto customDriverInstallChoice = drivers->Add(new Choice(gr->T("Install custom driver..."))); - drivers->Add(new Choice(di->T("More info")))->OnClick.Add([=](UI::EventParams &e) { + ChoiceGroup *driverManagerGroup = drivers->Add(new ChoiceGroup(gr->T("AdrenoTools driver manager"))); + auto customDriverInstallChoice = driverManagerGroup->Add(new Choice(gr->T("Install custom driver..."))); + driverManagerGroup->Add(new Choice(di->T("More info")))->OnClick.Add([=](UI::EventParams &e) { System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/reference/custom-drivers/"); }); diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 0917204f39..b349a0bf75 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -382,19 +382,19 @@ void RemoteISOScreen::CreateSettingsTab(UI::ViewGroup *remoteisoSettings) { auto ri = GetI18NCategory(I18NCat::REMOTEISO); - remoteisoSettings->Add(new ItemHeader(ri->T("Remote disc streaming"))); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteShareOnStartup, ri->T("Share on PPSSPP startup")))->OnClick.Add([](UI::EventParams &e) { + ChoiceGroup *streamingSettings = remoteisoSettings->Add(new ChoiceGroup(ri->T("Remote disc streaming"))); + streamingSettings->Add(new CheckBox(&g_Config.bRemoteShareOnStartup, ri->T("Share on PPSSPP startup")))->OnClick.Add([](UI::EventParams &e) { if (g_Config.bRemoteShareOnStartup) { System_RequestLocalNetworkPermission(); } }); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteISOManual, ri->T("Manual Mode Client", "Manually configure client"))); - remoteisoSettings->Add(new CheckBox(&g_Config.bRemoteTab, ri->T("Show Remote tab on main screen"))); + streamingSettings->Add(new CheckBox(&g_Config.bRemoteISOManual, ri->T("Manual Mode Client", "Manually configure client"))); + streamingSettings->Add(new CheckBox(&g_Config.bRemoteTab, ri->T("Show Remote tab on main screen"))); if (System_GetPropertyBool(SYSPROP_HAS_FOLDER_BROWSER)) { static const char *shareTypes[] = { "Recent games", "Choose directory" }; - remoteisoSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager())); - FolderChooserChoice *folderChooser = remoteisoSettings->Add(new FolderChooserChoice(GetRequesterToken(), &g_Config.sRemoteISOSharedDir, ri->T("Files to share"))); + streamingSettings->Add(new PopupMultiChoice(&g_Config.iRemoteISOShareType, ri->T("Files to share"), shareTypes, 0, ARRAY_SIZE(shareTypes), I18NCat::REMOTEISO, screenManager())); + FolderChooserChoice *folderChooser = streamingSettings->Add(new FolderChooserChoice(GetRequesterToken(), &g_Config.sRemoteISOSharedDir, ri->T("Files to share"))); folderChooser->SetEnabledFunc([=]() { return g_Config.iRemoteISOShareType == (int)RemoteISOShareType::LOCAL_FOLDER; }); @@ -404,10 +404,10 @@ void RemoteISOScreen::CreateSettingsTab(UI::ViewGroup *remoteisoSettings) { } UI::Choice *remoteServer = new PopupTextInputChoice(GetRequesterToken(), &g_Config.sLastRemoteISOServer, ri->T("Remote Server"), "", 255, screenManager()); - remoteisoSettings->Add(remoteServer); + streamingSettings->Add(remoteServer); remoteServer->SetEnabledPtr(&g_Config.bRemoteISOManual); - PopupSliderChoice *remotePort = remoteisoSettings->Add(new PopupSliderChoice(&g_Config.iLastRemoteISOPort, 0, 65535, 0, ri->T("Remote Port"), 1, screenManager())); + PopupSliderChoice *remotePort = streamingSettings->Add(new PopupSliderChoice(&g_Config.iLastRemoteISOPort, 0, 65535, 0, ri->T("Remote Port"), 1, screenManager())); remotePort->SetEnabledPtr(&g_Config.bRemoteISOManual); UI::Choice *remoteSubdir; @@ -416,11 +416,11 @@ void RemoteISOScreen::CreateSettingsTab(UI::ViewGroup *remoteisoSettings) { remoteSubdirInput->OnChange.Handle(this, &RemoteISOScreen::OnChangeRemoteISOSubdir); remoteSubdir = remoteSubdirInput; } - remoteisoSettings->Add(remoteSubdir); + streamingSettings->Add(remoteSubdir); remoteSubdir->SetEnabledPtr(&g_Config.bRemoteISOManual); PopupSliderChoice *portChoice = new PopupSliderChoice(&g_Config.iRemoteISOPort, 0, 65535, 0, ri->T("Local Server Port", "Local Server Port"), 100, screenManager()); - remoteisoSettings->Add(portChoice); + streamingSettings->Add(portChoice); portChoice->SetDisabledPtr(&serverRunning_); } diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index f8d91817db..c83d721c9b 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -442,19 +442,19 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) } using namespace UI; - viewGroup->Add(new ItemHeader(di->T("Settings"))); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsEnable, ac->T("Achievements enabled")))->OnClick.Add([this](UI::EventParams &e) -> void { + ChoiceGroup *settingsGroup = viewGroup->Add(new ChoiceGroup(di->T("Settings"))); + settingsGroup->Add(new CheckBox(&g_Config.bAchievementsEnable, ac->T("Achievements enabled")))->OnClick.Add([this](UI::EventParams &e) -> void { Achievements::UpdateSettings(); RecreateViews(); }); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsHardcoreMode, ac->T("Hardcore Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + settingsGroup->Add(new CheckBox(&g_Config.bAchievementsHardcoreMode, ac->T("Hardcore Mode (no savestates)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + settingsGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new ItemHeader(di->T("Links"))); - viewGroup->Add(new Choice(ac->T("RetroAchievements website"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &) -> void { + ChoiceGroup *linksGroup = viewGroup->Add(new ChoiceGroup(di->T("Links"))); + linksGroup->Add(new Choice(ac->T("RetroAchievements website"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &) -> void { System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.retroachievements.org/"); }); - viewGroup->Add(new Choice(ac->T("How to use RetroAchievements"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &) -> void { + linksGroup->Add(new Choice(ac->T("How to use RetroAchievements"), ImageID("I_LINK_OUT")))->OnClick.Add([](UI::EventParams &) -> void { System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/reference/retro-achievements"); }); } @@ -466,25 +466,25 @@ void RetroAchievementsSettingsScreen::CreateCustomizeTab(UI::ViewGroup *viewGrou viewGroup->Add(new PaneTitleBar(Path(), ac->T("Customize"), "/docs/reference/retro-achievements/")); using namespace UI; - viewGroup->Add(new ItemHeader(ac->T("Sound Effects"))); + ChoiceGroup *soundSettings = viewGroup->Add(new ChoiceGroup(ac->T("Sound Effects"))); if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) { - viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED)); - viewGroup->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED)); + soundSettings->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED)); + soundSettings->Add(new AudioFileChooser(GetRequesterToken(), &g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED)); } - PopupSliderChoice *achievementVolume = viewGroup->Add(new PopupSliderChoice(&g_Config.iAchievementVolume, VOLUME_OFF, VOLUMEHI_FULL, MultiplierToVolume100(0.6f), ac->T("Achievement sound volume"), screenManager())); + PopupSliderChoice *achievementVolume = soundSettings->Add(new PopupSliderChoice(&g_Config.iAchievementVolume, VOLUME_OFF, VOLUMEHI_FULL, MultiplierToVolume100(0.6f), ac->T("Achievement sound volume"), screenManager())); achievementVolume->SetFormat("%d%%"); achievementVolume->SetEnabledPtr(&g_Config.bEnableSound); achievementVolume->SetZeroLabel(a->T("Mute")); static const char *positions[] = { "None", "Bottom Left", "Bottom Center", "Bottom Right", "Top Left", "Top Center", "Top Right", "Center Left", "Center Right" }; - viewGroup->Add(new ItemHeader(ac->T("Notifications"))); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardStartedOrFailedPos, ac->T("Leaderboard attempt started or failed"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardSubmittedPos, ac->T("Leaderboard result submitted"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardTrackerPos, ac->T("Leaderboard tracker"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsUnlockedPos, ac->T("Achievement unlocked"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsChallengePos, ac->T("Challenge indicator"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsProgressPos, ac->T("Achievement progress"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + ChoiceGroup *notificationSettings = viewGroup->Add(new ChoiceGroup(ac->T("Notifications"))); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardStartedOrFailedPos, ac->T("Leaderboard attempt started or failed"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardSubmittedPos, ac->T("Leaderboard result submitted"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardTrackerPos, ac->T("Leaderboard tracker"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsUnlockedPos, ac->T("Achievement unlocked"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsChallengePos, ac->T("Challenge indicator"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); + notificationSettings->Add(new PopupMultiChoice(&g_Config.iAchievementsProgressPos, ac->T("Achievement progress"), positions, -1, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable); } void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *viewGroup) { @@ -494,13 +494,14 @@ void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *vie using namespace UI; viewGroup->Add(new PaneTitleBar(Path(), sy->T("Developer Tools"), "/docs/reference/retro-achievements/")); + ChoiceGroup *devSettings = viewGroup->Add(new ChoiceGroup("")); #ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION - viewGroup->Add(new CheckBox(&g_Config.bAchievementsEnableRAIntegration, ac->T("Enable RAIntegration (for achievement development)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + devSettings->Add(new CheckBox(&g_Config.bAchievementsEnableRAIntegration, ac->T("Enable RAIntegration (for achievement development)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); #endif - viewGroup->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficial, ac->T("Unofficial achievements")))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")))->SetEnabledPtr(&g_Config.bAchievementsEnable); - viewGroup->Add(new CheckBox(&g_Config.bAchievementsSaveStateInHardcoreMode, ac->T("Allow Save State in Hardcore Mode (but not Load State)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + devSettings->Add(new CheckBox(&g_Config.bAchievementsEncoreMode, ac->T("Encore Mode")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + devSettings->Add(new CheckBox(&g_Config.bAchievementsUnofficial, ac->T("Unofficial achievements")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + devSettings->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")))->SetEnabledPtr(&g_Config.bAchievementsEnable); + devSettings->Add(new CheckBox(&g_Config.bAchievementsSaveStateInHardcoreMode, ac->T("Allow Save State in Hardcore Mode (but not Load State)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); } void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h) { diff --git a/UI/TabbedDialogScreen.cpp b/UI/TabbedDialogScreen.cpp index 81eae5bc48..649e76f946 100644 --- a/UI/TabbedDialogScreen.cpp +++ b/UI/TabbedDialogScreen.cpp @@ -130,12 +130,12 @@ void UITabbedBaseDialogScreen::CreateViews() { AddTab("GameSettingsSearch", ms->T("Search"), ImageID("I_SEARCH"), [this](UI::LinearLayout *searchSettings) { auto se = GetI18NCategory(I18NCat::SEARCH); - searchSettings->Add(new ItemHeader(se->T("Find settings"))); - searchSettings->Add(new PopupTextInputChoice(GetRequesterToken(), &searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([this](UI::EventParams &e) { + ChoiceGroup *searchGroup = searchSettings->Add(new ChoiceGroup(se->T("Find settings"))); + searchGroup->Add(new PopupTextInputChoice(GetRequesterToken(), &searchFilter_, se->T("Filter"), "", 64, screenManager()))->OnChange.Add([this](UI::EventParams &e) { System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, StripSpaces(searchFilter_)); }); - clearSearchChoice_ = searchSettings->Add(new Choice(se->T("Clear filter"))); + clearSearchChoice_ = searchGroup->Add(new Choice(se->T("Clear filter"))); clearSearchChoice_->OnClick.Add([](UI::EventParams &e) { System_PostUIMessage(UIMessage::GAMESETTINGS_SEARCH, ""); }); diff --git a/UI/TiltAnalogSettingsScreen.cpp b/UI/TiltAnalogSettingsScreen.cpp index 6b10eecdde..846ebed8ff 100644 --- a/UI/TiltAnalogSettingsScreen.cpp +++ b/UI/TiltAnalogSettingsScreen.cpp @@ -100,9 +100,9 @@ void TiltAnalogSettingsScreen::CreateSettingsViews(UI::ViewGroup *settings) { return g_Config.iTiltInputType != 0; }; - settings->Add(new ItemHeader(co->T("Tilt control setup"))); - CheckBox *enabled = settings->Add(new CheckBox(&g_Config.bTiltInputEnabled, co->T("Enabled"))); - PopupMultiChoice *typeChoice = settings->Add(new PopupMultiChoice(&g_Config.iTiltInputType, co->T("Tilt Input Type"), g_tiltTypes, 0, g_numTiltTypes, I18NCat::CONTROLS, screenManager())); + ChoiceGroup *setupSettings = settings->Add(new ChoiceGroup(co->T("Tilt control setup"))); + CheckBox *enabled = setupSettings->Add(new CheckBox(&g_Config.bTiltInputEnabled, co->T("Enabled"))); + PopupMultiChoice *typeChoice = setupSettings->Add(new PopupMultiChoice(&g_Config.iTiltInputType, co->T("Tilt Input Type"), g_tiltTypes, 0, g_numTiltTypes, I18NCat::CONTROLS, screenManager())); if (g_Config.iTiltInputType != 0) { typeChoice->HideChoice(0); // The null choice is no longer relevant since we added an enabled toggle } @@ -115,28 +115,28 @@ void TiltAnalogSettingsScreen::CreateSettingsViews(UI::ViewGroup *settings) { }); typeChoice->SetEnabledPtr(&g_Config.bTiltInputEnabled); if (System_GetPropertyBool(SYSPROP_HAS_GYRO)) { - settings->Add(new CheckBox(&g_Config.bTiltUseGyro, co->T("Use gyroscope")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + setupSettings->Add(new CheckBox(&g_Config.bTiltUseGyro, co->T("Use gyroscope")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); } - settings->Add(new ItemHeader(co->T("Calibration"))); + ChoiceGroup *calibrationSettings = settings->Add(new ChoiceGroup(co->T("Calibration"))); Choice *calibrate = new Choice(co->T("Calibrate")); calibrate->OnClick.Handle(this, &TiltAnalogSettingsScreen::OnCalibrate); calibrate->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(calibrate); + calibrationSettings->Add(calibrate); SettingHint *calibrationInfo = new SettingHint(co->T("To Calibrate", "Hold device at your preferred angle and press Calibrate."), calibrate); - settings->Add(calibrationInfo); + calibrationSettings->Add(calibrationInfo); - settings->Add(new ItemHeader(co->T("Sensitivity"))); + ChoiceGroup *sensitivitySettings = settings->Add(new ChoiceGroup(co->T("Sensitivity"))); if (TiltTypeIsAnalog(g_Config.iTiltInputType)) { - settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(new CheckBox(&g_Config.bTiltCircularDeadzone, co->T("Circular deadzone")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + sensitivitySettings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltAnalogDeadzoneRadius, 0.0f, 0.8f, 0.0f, co->T("Deadzone radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + sensitivitySettings->Add(new PopupSliderChoiceFloat(&g_Config.fTiltInverseDeadzone, 0.0f, 0.8f, 0.0f, co->T("Low end radius"), 0.02f, screenManager(), "/ 1.0"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + sensitivitySettings->Add(new CheckBox(&g_Config.bTiltCircularDeadzone, co->T("Circular deadzone")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); } - settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, 60, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityY, 0, 100, 60, co->T("Tilt Sensitivity along Y axis"), screenManager(), "%"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + sensitivitySettings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityX, 0, 100, 60, co->T("Tilt Sensitivity along X axis"), screenManager(), "%"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + sensitivitySettings->Add(new PopupSliderChoice(&g_Config.iTiltSensitivityY, 0, 100, 60, co->T("Tilt Sensitivity along Y axis"), screenManager(), "%"))->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(new ItemHeader(co->T("Invert Axes"))); - settings->Add(new CheckBox(&g_Config.bInvertTiltX, co->T("Invert Tilt along X axis")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); - settings->Add(new CheckBox(&g_Config.bInvertTiltY, co->T("Invert Tilt along Y axis")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + ChoiceGroup *invertSettings = settings->Add(new ChoiceGroup(co->T("Invert Axes"))); + invertSettings->Add(new CheckBox(&g_Config.bInvertTiltX, co->T("Invert Tilt along X axis")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); + invertSettings->Add(new CheckBox(&g_Config.bInvertTiltY, co->T("Invert Tilt along Y axis")))->SetEnabledPtr(&g_Config.bTiltInputEnabled); } void TiltAnalogSettingsScreen::OnCalibrate(UI::EventParams &e) {