2020-09-15 20:57:54 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
2024-06-16 20:05:54 +00:00
|
|
|
// ES-DE Frontend
|
2020-06-21 12:25:28 +00:00
|
|
|
// GuiMenu.cpp
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Main menu.
|
|
|
|
// Some submenus are covered in separate source files.
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "guis/GuiMenu.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2022-04-11 22:18:51 +00:00
|
|
|
#if defined(_WIN64)
|
|
|
|
// Why this is needed here is anyone's guess but without it the compilation fails.
|
|
|
|
#include <winsock2.h>
|
|
|
|
#endif
|
|
|
|
|
2023-12-16 11:30:13 +00:00
|
|
|
#include "ApplicationVersion.h"
|
2021-07-07 18:03:42 +00:00
|
|
|
#include "CollectionSystemsManager.h"
|
|
|
|
#include "FileFilterIndex.h"
|
|
|
|
#include "FileSorts.h"
|
|
|
|
#include "Scripting.h"
|
|
|
|
#include "SystemData.h"
|
2022-01-17 20:53:23 +00:00
|
|
|
#include "UIModeController.h"
|
2021-07-07 18:03:42 +00:00
|
|
|
#include "VolumeControl.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "components/OptionListComponent.h"
|
|
|
|
#include "components/SliderComponent.h"
|
|
|
|
#include "components/SwitchComponent.h"
|
2021-08-22 13:26:38 +00:00
|
|
|
#include "guis/GuiAlternativeEmulators.h"
|
2017-06-12 16:38:59 +00:00
|
|
|
#include "guis/GuiCollectionSystemsOptions.h"
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "guis/GuiDetectDevice.h"
|
2021-05-16 11:12:31 +00:00
|
|
|
#include "guis/GuiMediaViewerOptions.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "guis/GuiMsgBox.h"
|
2023-07-24 15:07:18 +00:00
|
|
|
#include "guis/GuiOrphanedDataCleanup.h"
|
2020-06-06 11:10:33 +00:00
|
|
|
#include "guis/GuiScraperMenu.h"
|
2021-05-16 11:12:31 +00:00
|
|
|
#include "guis/GuiScreensaverOptions.h"
|
2021-09-17 20:23:41 +00:00
|
|
|
#include "guis/GuiTextEditKeyboardPopup.h"
|
|
|
|
#include "guis/GuiTextEditPopup.h"
|
2023-02-13 19:38:23 +00:00
|
|
|
#include "guis/GuiThemeDownloader.h"
|
2024-06-29 19:24:28 +00:00
|
|
|
#include "utils/LocalizationUtil.h"
|
2022-01-10 17:56:04 +00:00
|
|
|
#include "utils/PlatformUtil.h"
|
2020-06-26 16:03:55 +00:00
|
|
|
|
2024-01-14 11:36:21 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
#include "InputOverlay.h"
|
2024-05-20 17:49:28 +00:00
|
|
|
#include "utils/PlatformUtilAndroid.h"
|
2024-01-14 11:36:21 +00:00
|
|
|
#endif
|
|
|
|
|
2020-06-26 16:03:55 +00:00
|
|
|
#include <SDL2/SDL_events.h>
|
2021-07-07 18:03:42 +00:00
|
|
|
#include <algorithm>
|
2020-06-26 16:03:55 +00:00
|
|
|
|
2022-01-19 17:01:54 +00:00
|
|
|
GuiMenu::GuiMenu()
|
2023-02-21 17:26:53 +00:00
|
|
|
: mRenderer {Renderer::getInstance()}
|
2024-06-29 19:24:28 +00:00
|
|
|
, mMenu {_("MAIN MENU")}
|
2023-08-13 22:02:20 +00:00
|
|
|
, mThemeDownloaderReloadCounter {0}
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2023-05-07 20:56:24 +00:00
|
|
|
const bool isFullUI {UIModeController::getInstance()->isUIModeFull()};
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("SCRAPER"), mMenuColorPrimary, true, [this] { openScraperOptions(); });
|
2020-06-06 11:10:33 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("UI SETTINGS"), mMenuColorPrimary, true, [this] { openUIOptions(); });
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("SOUND SETTINGS"), mMenuColorPrimary, true, [this] { openSoundOptions(); });
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2021-05-23 08:35:59 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("INPUT DEVICE SETTINGS"), mMenuColorPrimary, true,
|
2023-05-07 20:56:24 +00:00
|
|
|
[this] { openInputDeviceOptions(); });
|
2021-05-23 08:35:59 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("GAME COLLECTION SETTINGS"), mMenuColorPrimary, true,
|
2021-07-07 18:03:42 +00:00
|
|
|
[this] { openCollectionSystemOptions(); });
|
2017-09-08 14:49:47 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("OTHER SETTINGS"), mMenuColorPrimary, true, [this] { openOtherOptions(); });
|
2017-09-08 14:49:47 +00:00
|
|
|
|
2023-07-20 19:59:28 +00:00
|
|
|
if (isFullUI)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("UTILITIES"), mMenuColorPrimary, true, [this] { openUtilities(); });
|
2023-07-20 19:59:28 +00:00
|
|
|
|
2020-12-17 22:45:29 +00:00
|
|
|
if (!Settings::getInstance()->getBool("ForceKiosk") &&
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getString("UIMode") != "kiosk") {
|
2024-05-20 17:49:28 +00:00
|
|
|
#if defined(__APPLE__)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("QUIT ES-DE"), mMenuColorPrimary, false, [this] { openQuitMenu(); });
|
2024-05-20 17:49:28 +00:00
|
|
|
#elif defined(__ANDROID__)
|
|
|
|
if (!AndroidVariables::sIsHomeApp)
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("QUIT ES-DE"), mMenuColorPrimary, false, [this] { openQuitMenu(); });
|
2023-03-12 11:05:31 +00:00
|
|
|
#else
|
2020-12-17 22:45:29 +00:00
|
|
|
if (Settings::getInstance()->getBool("ShowQuitMenu"))
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("QUIT"), mMenuColorPrimary, true, [this] { openQuitMenu(); });
|
2020-12-17 22:45:29 +00:00
|
|
|
else
|
2024-07-04 16:53:13 +00:00
|
|
|
addEntry(_("QUIT ES-DE"), mMenuColorPrimary, false, [this] { openQuitMenu(); });
|
2023-03-12 11:05:31 +00:00
|
|
|
#endif
|
2020-12-17 22:45:29 +00:00
|
|
|
}
|
2017-09-08 14:49:47 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
addChild(&mMenu);
|
|
|
|
addVersionInfo();
|
|
|
|
setSize(mMenu.getSize());
|
2023-02-21 17:26:53 +00:00
|
|
|
setPosition((mRenderer->getScreenWidth() - mSize.x) / 2.0f,
|
|
|
|
std::round(mRenderer->getScreenHeight() * 0.13f));
|
2017-09-08 14:49:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
GuiMenu::~GuiMenu()
|
|
|
|
{
|
2023-10-18 15:52:28 +00:00
|
|
|
if (ViewController::getInstance()->getState().viewing != ViewController::ViewMode::NOTHING) {
|
|
|
|
// This is required for the situation where scrolling started just before the menu
|
|
|
|
// was openened. Without this, the scrolling would run until manually stopped after
|
|
|
|
// the menu has been closed.
|
|
|
|
ViewController::getInstance()->stopScrolling();
|
2022-02-19 16:04:23 +00:00
|
|
|
|
2023-10-18 15:52:28 +00:00
|
|
|
ViewController::getInstance()->startViewVideos();
|
|
|
|
}
|
2020-09-15 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-22 12:29:43 +00:00
|
|
|
void GuiMenu::openScraperOptions()
|
|
|
|
{
|
|
|
|
// Open the scraper menu.
|
2024-07-04 16:53:13 +00:00
|
|
|
mWindow->pushGui(new GuiScraperMenu(_("SCRAPER")));
|
2021-08-22 12:29:43 +00:00
|
|
|
}
|
2017-09-08 14:49:47 +00:00
|
|
|
|
2021-05-22 20:48:44 +00:00
|
|
|
void GuiMenu::openUIOptions()
|
2017-09-08 14:49:47 +00:00
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("UI SETTINGS"));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2022-01-31 22:53:32 +00:00
|
|
|
// Theme options section.
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator> themes {
|
|
|
|
ThemeData::getThemes()};
|
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
selectedTheme;
|
2022-01-31 22:53:32 +00:00
|
|
|
|
2024-07-04 16:53:13 +00:00
|
|
|
auto theme =
|
|
|
|
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("THEME"), false);
|
2022-02-01 17:06:32 +00:00
|
|
|
|
2023-03-31 21:00:23 +00:00
|
|
|
ComponentListRow themeDownloaderInputRow;
|
|
|
|
themeDownloaderInputRow.elements.clear();
|
2024-07-04 16:53:13 +00:00
|
|
|
themeDownloaderInputRow.addElement(std::make_shared<TextComponent>(_("THEME DOWNLOADER"),
|
2023-04-29 09:47:37 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM),
|
2023-05-07 20:56:24 +00:00
|
|
|
mMenuColorPrimary),
|
2023-04-29 09:47:37 +00:00
|
|
|
true);
|
2023-05-07 20:56:24 +00:00
|
|
|
themeDownloaderInputRow.addElement(mMenu.makeArrow(), false);
|
2023-03-31 21:00:23 +00:00
|
|
|
|
|
|
|
themeDownloaderInputRow.makeAcceptInputHandler(
|
|
|
|
std::bind(&GuiMenu::openThemeDownloader, this, s));
|
|
|
|
s->addRow(themeDownloaderInputRow);
|
2023-02-13 19:38:23 +00:00
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
// Theme.
|
|
|
|
if (!themes.empty()) {
|
|
|
|
selectedTheme = themes.find(Settings::getInstance()->getString("Theme"));
|
|
|
|
if (selectedTheme == themes.cend())
|
|
|
|
selectedTheme = themes.cbegin();
|
|
|
|
std::vector<std::pair<std::string, std::pair<std::string, ThemeData::Theme>>> themesSorted;
|
2023-01-20 17:37:32 +00:00
|
|
|
std::string sortName;
|
2023-08-14 20:40:32 +00:00
|
|
|
for (auto& theme : themes) {
|
2023-01-20 17:37:32 +00:00
|
|
|
if (theme.second.capabilities.themeName != "")
|
|
|
|
sortName = theme.second.capabilities.themeName;
|
|
|
|
else
|
|
|
|
sortName = theme.first;
|
2023-08-14 20:40:32 +00:00
|
|
|
themesSorted.emplace_back(std::make_pair(Utils::String::toUpper(sortName),
|
|
|
|
std::make_pair(theme.first, theme.second)));
|
2023-01-20 17:37:32 +00:00
|
|
|
}
|
2023-08-14 20:40:32 +00:00
|
|
|
std::sort(themesSorted.begin(), themesSorted.end(),
|
2023-01-20 17:37:32 +00:00
|
|
|
[](const auto& a, const auto& b) { return a.first < b.first; });
|
2023-08-14 20:40:32 +00:00
|
|
|
for (auto it = themesSorted.cbegin(); it != themesSorted.cend(); ++it) {
|
|
|
|
// If required, abbreviate the theme name so it doesn't overlap the setting name.
|
2023-01-20 17:37:32 +00:00
|
|
|
const float maxNameLength {mSize.x * 0.62f};
|
|
|
|
std::string themeName {(*it).first};
|
2023-08-14 20:40:32 +00:00
|
|
|
theme->add(themeName, it->second.first, (*it).second.first == selectedTheme->first,
|
|
|
|
maxNameLength);
|
|
|
|
}
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("THEME"), theme);
|
2023-08-14 20:40:32 +00:00
|
|
|
s->addSaveFunc([this, theme, s] {
|
|
|
|
if (theme->getSelected() != Settings::getInstance()->getString("Theme")) {
|
|
|
|
Scripting::fireEvent("theme-changed", theme->getSelected(),
|
|
|
|
Settings::getInstance()->getString("Theme"));
|
2023-08-15 17:54:36 +00:00
|
|
|
// Handle the situation where the previously selected theme has been deleted
|
2024-01-28 17:50:26 +00:00
|
|
|
// using the theme downloader. In this case attempt to fall back to linear-es-de
|
2023-08-15 17:54:36 +00:00
|
|
|
// and if this theme doesn't exist then select the first available one.
|
|
|
|
auto themes = ThemeData::getThemes();
|
|
|
|
if (themes.find(theme->getSelected()) == themes.end()) {
|
2024-01-28 17:50:26 +00:00
|
|
|
if (themes.find("linear-es-de") != themes.end())
|
|
|
|
Settings::getInstance()->setString("Theme", "linear-es-de");
|
2023-08-15 17:54:36 +00:00
|
|
|
else
|
|
|
|
Settings::getInstance()->setString("Theme", themes.begin()->first);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Settings::getInstance()->setString("Theme", theme->getSelected());
|
|
|
|
}
|
2023-08-14 20:40:32 +00:00
|
|
|
mWindow->setChangedTheme();
|
2022-01-31 22:53:32 +00:00
|
|
|
// This is required so that the custom collection system does not disappear
|
2023-08-14 20:40:32 +00:00
|
|
|
// if the user is editing a custom collection when switching themes.
|
2022-03-24 22:05:23 +00:00
|
|
|
if (CollectionSystemsManager::getInstance()->isEditing())
|
2022-01-31 22:53:32 +00:00
|
|
|
CollectionSystemsManager::getInstance()->exitEditMode();
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setNeedsGoToStart();
|
2022-03-24 22:05:23 +00:00
|
|
|
s->setNeedsCollectionsUpdate();
|
2022-01-31 22:53:32 +00:00
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2022-01-31 22:53:32 +00:00
|
|
|
|
|
|
|
// Theme variants.
|
2024-07-04 16:53:13 +00:00
|
|
|
auto themeVariant = std::make_shared<OptionListComponent<std::string>>(
|
|
|
|
getHelpStyle(), _("THEME VARIANT"), false);
|
|
|
|
s->addWithLabel(_("THEME VARIANT"), themeVariant);
|
2022-02-01 17:06:32 +00:00
|
|
|
s->addSaveFunc([themeVariant, s] {
|
|
|
|
if (themeVariant->getSelected() != Settings::getInstance()->getString("ThemeVariant")) {
|
|
|
|
Settings::getInstance()->setString("ThemeVariant", themeVariant->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
2022-02-01 17:06:32 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
auto themeVariantsFunc = [=](const std::string& selectedTheme,
|
|
|
|
const std::string& selectedVariant) {
|
2023-08-14 20:40:32 +00:00
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
currentSet {themes.find(selectedTheme)};
|
|
|
|
if (currentSet == themes.cend())
|
2022-02-01 17:06:32 +00:00
|
|
|
return;
|
|
|
|
// We need to recreate the OptionListComponent entries.
|
|
|
|
themeVariant->clearEntries();
|
|
|
|
int selectableVariants {0};
|
|
|
|
for (auto& variant : currentSet->second.capabilities.variants) {
|
|
|
|
if (variant.selectable)
|
|
|
|
++selectableVariants;
|
|
|
|
}
|
|
|
|
if (selectableVariants > 0) {
|
|
|
|
for (auto& variant : currentSet->second.capabilities.variants) {
|
|
|
|
if (variant.selectable) {
|
|
|
|
// If required, abbreviate the variant name so it doesn't overlap the
|
|
|
|
// setting name.
|
2022-12-07 17:09:05 +00:00
|
|
|
const float maxNameLength {mSize.x * 0.62f};
|
2024-07-04 16:53:13 +00:00
|
|
|
themeVariant->add(Utils::String::toUpper(variant.label), variant.name,
|
|
|
|
variant.name == selectedVariant, maxNameLength);
|
2022-02-01 17:06:32 +00:00
|
|
|
}
|
2022-01-31 22:53:32 +00:00
|
|
|
}
|
2022-02-01 17:06:32 +00:00
|
|
|
if (themeVariant->getSelectedObjects().size() == 0)
|
|
|
|
themeVariant->selectEntry(0);
|
|
|
|
}
|
|
|
|
else {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeVariant->add(_("NONE DEFINED"), "none", true);
|
2022-02-01 17:06:32 +00:00
|
|
|
themeVariant->setEnabled(false);
|
|
|
|
themeVariant->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeVariant->getParent()
|
|
|
|
->getChild(themeVariant->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
themeVariantsFunc(Settings::getInstance()->getString("Theme"),
|
2022-02-01 17:06:32 +00:00
|
|
|
Settings::getInstance()->getString("ThemeVariant"));
|
2022-01-31 22:53:32 +00:00
|
|
|
|
2022-10-31 18:32:13 +00:00
|
|
|
// Theme color schemes.
|
|
|
|
auto themeColorScheme = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("THEME COLOR SCHEME"), false);
|
|
|
|
s->addWithLabel(_("THEME COLOR SCHEME"), themeColorScheme);
|
2022-10-31 18:32:13 +00:00
|
|
|
s->addSaveFunc([themeColorScheme, s] {
|
|
|
|
if (themeColorScheme->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("ThemeColorScheme")) {
|
|
|
|
Settings::getInstance()->setString("ThemeColorScheme", themeColorScheme->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto themeColorSchemesFunc = [=](const std::string& selectedTheme,
|
|
|
|
const std::string& selectedColorScheme) {
|
2023-08-14 20:40:32 +00:00
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
currentSet {themes.find(selectedTheme)};
|
|
|
|
if (currentSet == themes.cend())
|
2022-10-31 18:32:13 +00:00
|
|
|
return;
|
|
|
|
// We need to recreate the OptionListComponent entries.
|
|
|
|
themeColorScheme->clearEntries();
|
|
|
|
if (currentSet->second.capabilities.colorSchemes.size() > 0) {
|
|
|
|
for (auto& colorScheme : currentSet->second.capabilities.colorSchemes) {
|
|
|
|
// If required, abbreviate the color scheme name so it doesn't overlap the
|
|
|
|
// setting name.
|
2022-12-07 17:09:05 +00:00
|
|
|
const float maxNameLength {mSize.x * 0.52f};
|
2024-07-04 16:53:13 +00:00
|
|
|
themeColorScheme->add(Utils::String::toUpper(colorScheme.label), colorScheme.name,
|
2022-10-31 18:32:13 +00:00
|
|
|
colorScheme.name == selectedColorScheme, maxNameLength);
|
|
|
|
}
|
|
|
|
if (themeColorScheme->getSelectedObjects().size() == 0)
|
|
|
|
themeColorScheme->selectEntry(0);
|
|
|
|
}
|
|
|
|
else {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeColorScheme->add(_("NONE DEFINED"), "none", true);
|
2022-10-31 18:32:13 +00:00
|
|
|
themeColorScheme->setEnabled(false);
|
|
|
|
themeColorScheme->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeColorScheme->getParent()
|
|
|
|
->getChild(themeColorScheme->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
themeColorSchemesFunc(Settings::getInstance()->getString("Theme"),
|
2022-10-31 18:32:13 +00:00
|
|
|
Settings::getInstance()->getString("ThemeColorScheme"));
|
|
|
|
|
2023-12-20 20:58:40 +00:00
|
|
|
// Theme font sizes.
|
|
|
|
auto themeFontSize = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("THEME FONT SIZE"), false);
|
|
|
|
s->addWithLabel(_("THEME FONT SIZE"), themeFontSize);
|
2023-12-20 20:58:40 +00:00
|
|
|
s->addSaveFunc([themeFontSize, s] {
|
|
|
|
if (themeFontSize->getSelected() != Settings::getInstance()->getString("ThemeFontSize")) {
|
|
|
|
Settings::getInstance()->setString("ThemeFontSize", themeFontSize->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto themeFontSizeFunc = [=](const std::string& selectedTheme,
|
|
|
|
const std::string& selectedFontSize) {
|
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
currentSet {themes.find(selectedTheme)};
|
|
|
|
if (currentSet == themes.cend())
|
|
|
|
return;
|
|
|
|
// We need to recreate the OptionListComponent entries.
|
|
|
|
themeFontSize->clearEntries();
|
|
|
|
if (currentSet->second.capabilities.fontSizes.size() > 0) {
|
|
|
|
for (auto& fontSize : currentSet->second.capabilities.fontSizes)
|
2024-07-04 16:53:13 +00:00
|
|
|
themeFontSize->add(
|
|
|
|
Utils::String::toUpper(_(ThemeData::getFontSizeLabel(fontSize).c_str())),
|
|
|
|
fontSize, fontSize == selectedFontSize);
|
2023-12-20 20:58:40 +00:00
|
|
|
if (themeFontSize->getSelectedObjects().size() == 0)
|
|
|
|
themeFontSize->selectEntry(0);
|
|
|
|
}
|
|
|
|
else {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeFontSize->add(_("NONE DEFINED"), "none", true);
|
2023-12-20 20:58:40 +00:00
|
|
|
themeFontSize->setEnabled(false);
|
|
|
|
themeFontSize->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeFontSize->getParent()
|
|
|
|
->getChild(themeFontSize->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
themeFontSizeFunc(Settings::getInstance()->getString("Theme"),
|
|
|
|
Settings::getInstance()->getString("ThemeFontSize"));
|
|
|
|
|
2022-01-31 22:53:32 +00:00
|
|
|
// Theme aspect ratios.
|
|
|
|
auto themeAspectRatio = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("THEME ASPECT RATIO"), false);
|
|
|
|
s->addWithLabel(_("THEME ASPECT RATIO"), themeAspectRatio);
|
2022-02-01 17:06:32 +00:00
|
|
|
s->addSaveFunc([themeAspectRatio, s] {
|
|
|
|
if (themeAspectRatio->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("ThemeAspectRatio")) {
|
|
|
|
Settings::getInstance()->setString("ThemeAspectRatio", themeAspectRatio->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
auto themeAspectRatiosFunc = [=](const std::string& selectedTheme,
|
|
|
|
const std::string& selectedAspectRatio) {
|
2023-08-14 20:40:32 +00:00
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
currentSet {themes.find(selectedTheme)};
|
|
|
|
if (currentSet == themes.cend())
|
2022-02-01 17:06:32 +00:00
|
|
|
return;
|
|
|
|
// We need to recreate the OptionListComponent entries.
|
|
|
|
themeAspectRatio->clearEntries();
|
|
|
|
if (currentSet->second.capabilities.aspectRatios.size() > 0) {
|
2024-07-04 16:53:13 +00:00
|
|
|
for (auto& aspectRatio : currentSet->second.capabilities.aspectRatios) {
|
|
|
|
themeAspectRatio->add(
|
|
|
|
Utils::String::toUpper(_(ThemeData::getAspectRatioLabel(aspectRatio).c_str())),
|
|
|
|
aspectRatio, aspectRatio == selectedAspectRatio);
|
|
|
|
}
|
2022-02-01 17:06:32 +00:00
|
|
|
if (themeAspectRatio->getSelectedObjects().size() == 0)
|
|
|
|
themeAspectRatio->selectEntry(0);
|
|
|
|
}
|
|
|
|
else {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeAspectRatio->add(_("NONE DEFINED"), "none", true);
|
2022-02-01 17:06:32 +00:00
|
|
|
themeAspectRatio->setEnabled(false);
|
|
|
|
themeAspectRatio->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeAspectRatio->getParent()
|
|
|
|
->getChild(themeAspectRatio->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
themeAspectRatiosFunc(Settings::getInstance()->getString("Theme"),
|
2022-02-01 17:06:32 +00:00
|
|
|
Settings::getInstance()->getString("ThemeAspectRatio"));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2023-01-16 21:43:56 +00:00
|
|
|
// Theme transitions.
|
|
|
|
auto themeTransitions = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("THEME TRANSITIONS"), false);
|
2023-01-16 21:43:56 +00:00
|
|
|
std::string selectedThemeTransitions {Settings::getInstance()->getString("ThemeTransitions")};
|
2024-07-04 16:53:13 +00:00
|
|
|
themeTransitions->add(_("AUTOMATIC"), "automatic", selectedThemeTransitions == "automatic");
|
2023-01-08 16:00:36 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
2023-01-16 21:43:56 +00:00
|
|
|
// configuration file. Simply set theme transitions to "automatic" in this case.
|
|
|
|
if (themeTransitions->getSelectedObjects().size() == 0)
|
|
|
|
themeTransitions->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("THEME TRANSITIONS"), themeTransitions);
|
2023-01-16 21:43:56 +00:00
|
|
|
s->addSaveFunc([themeTransitions, s] {
|
|
|
|
if (themeTransitions->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("ThemeTransitions")) {
|
|
|
|
Settings::getInstance()->setString("ThemeTransitions", themeTransitions->getSelected());
|
2023-01-08 16:00:36 +00:00
|
|
|
ThemeData::setThemeTransitions();
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-01-16 21:43:56 +00:00
|
|
|
auto themeTransitionsFunc = [=](const std::string& selectedTheme,
|
|
|
|
const std::string& selectedThemeTransitions) {
|
2023-08-14 20:40:32 +00:00
|
|
|
std::map<std::string, ThemeData::Theme, ThemeData::StringComparator>::const_iterator
|
|
|
|
currentSet {themes.find(selectedTheme)};
|
|
|
|
if (currentSet == themes.cend())
|
2023-01-08 16:00:36 +00:00
|
|
|
return;
|
|
|
|
// We need to recreate the OptionListComponent entries.
|
2023-01-16 21:43:56 +00:00
|
|
|
themeTransitions->clearEntries();
|
2024-07-04 16:53:13 +00:00
|
|
|
themeTransitions->add(_("AUTOMATIC"), "automatic", "automatic" == selectedThemeTransitions);
|
2023-07-30 16:17:27 +00:00
|
|
|
if (currentSet->second.capabilities.transitions.size() == 1 &&
|
|
|
|
currentSet->second.capabilities.transitions.front().selectable) {
|
|
|
|
std::string label;
|
|
|
|
if (currentSet->second.capabilities.transitions.front().label == "")
|
2024-07-04 16:53:13 +00:00
|
|
|
label = _("THEME PROFILE");
|
2023-07-30 16:17:27 +00:00
|
|
|
else
|
|
|
|
label = currentSet->second.capabilities.transitions.front().label;
|
|
|
|
const std::string transitions {
|
|
|
|
currentSet->second.capabilities.transitions.front().name};
|
2024-07-04 17:34:04 +00:00
|
|
|
themeTransitions->add(Utils::String::toUpper(label), transitions,
|
|
|
|
transitions == selectedThemeTransitions);
|
2023-07-30 16:17:27 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (size_t i {0}; i < currentSet->second.capabilities.transitions.size(); ++i) {
|
|
|
|
if (!currentSet->second.capabilities.transitions[i].selectable)
|
|
|
|
continue;
|
|
|
|
std::string label;
|
|
|
|
if (currentSet->second.capabilities.transitions[i].label == "")
|
2024-07-04 16:53:13 +00:00
|
|
|
label = _("THEME PROFILE") + " " + std::to_string(i + 1);
|
2023-07-30 16:17:27 +00:00
|
|
|
else
|
|
|
|
label = currentSet->second.capabilities.transitions[i].label;
|
|
|
|
const std::string transitions {currentSet->second.capabilities.transitions[i].name};
|
2024-07-04 17:34:04 +00:00
|
|
|
themeTransitions->add(Utils::String::toUpper(label), transitions,
|
|
|
|
transitions == selectedThemeTransitions);
|
2023-07-30 16:17:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
|
|
|
|
"builtin-instant") ==
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeTransitions->add(_("INSTANT (BUILT-IN)"), "builtin-instant",
|
2023-07-30 16:17:27 +00:00
|
|
|
"builtin-instant" == selectedThemeTransitions);
|
|
|
|
}
|
|
|
|
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
|
|
|
|
"builtin-slide") ==
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeTransitions->add(_("SLIDE (BUILT-IN)"), "builtin-slide",
|
2023-07-30 16:17:27 +00:00
|
|
|
"builtin-slide" == selectedThemeTransitions);
|
|
|
|
}
|
|
|
|
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
|
|
|
|
"builtin-fade") ==
|
|
|
|
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
|
2024-07-04 16:53:13 +00:00
|
|
|
themeTransitions->add(_("FADE (BUILT-IN)"), "builtin-fade",
|
2023-07-30 16:17:27 +00:00
|
|
|
"builtin-fade" == selectedThemeTransitions);
|
|
|
|
}
|
|
|
|
if (themeTransitions->getSelectedObjects().size() == 0)
|
|
|
|
themeTransitions->selectEntry(0);
|
|
|
|
|
|
|
|
if (themeTransitions->getNumEntries() == 1) {
|
2023-01-16 21:43:56 +00:00
|
|
|
themeTransitions->setEnabled(false);
|
|
|
|
themeTransitions->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeTransitions->getParent()
|
|
|
|
->getChild(themeTransitions->getChildIndex() - 1)
|
2023-01-08 16:00:36 +00:00
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
else {
|
2023-07-30 16:17:27 +00:00
|
|
|
themeTransitions->setEnabled(true);
|
|
|
|
themeTransitions->setOpacity(1.0f);
|
|
|
|
themeTransitions->getParent()
|
|
|
|
->getChild(themeTransitions->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
2023-01-08 16:00:36 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
themeTransitionsFunc(Settings::getInstance()->getString("Theme"),
|
2023-01-16 21:43:56 +00:00
|
|
|
Settings::getInstance()->getString("ThemeTransitions"));
|
2023-01-08 16:00:36 +00:00
|
|
|
|
2024-07-02 21:57:44 +00:00
|
|
|
// Application language.
|
|
|
|
auto applicationLanguage = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("APPLICATION LANGUAGE"), false);
|
2024-07-02 21:57:44 +00:00
|
|
|
std::string selectedApplicationLanguage {
|
|
|
|
Settings::getInstance()->getString("ApplicationLanguage")};
|
2024-07-04 16:53:13 +00:00
|
|
|
applicationLanguage->add(_("AUTOMATIC"), "automatic",
|
|
|
|
selectedApplicationLanguage == "automatic");
|
2024-07-20 11:24:37 +00:00
|
|
|
applicationLanguage->add("ENGLISH (UNITED STATES)", "en_US",
|
|
|
|
selectedApplicationLanguage == "en_US");
|
|
|
|
applicationLanguage->add("ENGLISH (UNITED KINGDOM)", "en_GB",
|
|
|
|
selectedApplicationLanguage == "en_GB");
|
2024-07-20 11:31:21 +00:00
|
|
|
applicationLanguage->add("ITALIANO", "it_IT", selectedApplicationLanguage == "it_IT");
|
2024-07-04 16:53:13 +00:00
|
|
|
applicationLanguage->add("SVENSKA", "sv_SE", selectedApplicationLanguage == "sv_SE");
|
2024-07-13 10:32:16 +00:00
|
|
|
applicationLanguage->add("简体中文", "zh_CN", selectedApplicationLanguage == "zh_CN");
|
2024-07-02 21:57:44 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the application langauge to "automatic" in this case.
|
|
|
|
if (applicationLanguage->getSelectedObjects().size() == 0)
|
|
|
|
applicationLanguage->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("APPLICATION LANGUAGE"), applicationLanguage);
|
2024-07-02 21:57:44 +00:00
|
|
|
s->addSaveFunc([this, applicationLanguage, s] {
|
|
|
|
if (applicationLanguage->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("ApplicationLanguage")) {
|
|
|
|
Settings::getInstance()->setString("ApplicationLanguage",
|
|
|
|
applicationLanguage->getSelected());
|
|
|
|
Utils::Localization::setLocale();
|
2024-07-04 16:53:13 +00:00
|
|
|
mWindow->updateSplashScreenText();
|
2024-07-02 21:57:44 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
s->setNeedsRescanROMDirectory();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-12-07 17:09:05 +00:00
|
|
|
// Quick system select (navigate between systems in the gamelist view).
|
|
|
|
auto quickSystemSelect = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("QUICK SYSTEM SELECT"), false);
|
2022-12-07 17:09:05 +00:00
|
|
|
std::string selectedQuickSelect {Settings::getInstance()->getString("QuickSystemSelect")};
|
2024-07-04 16:53:13 +00:00
|
|
|
quickSystemSelect->add(_("LEFT/RIGHT OR SHOULDERS"), "leftrightshoulders",
|
2022-12-07 17:09:05 +00:00
|
|
|
selectedQuickSelect == "leftrightshoulders");
|
2024-07-04 16:53:13 +00:00
|
|
|
quickSystemSelect->add(_("LEFT/RIGHT OR TRIGGERS"), "leftrighttriggers",
|
2022-12-07 17:09:05 +00:00
|
|
|
selectedQuickSelect == "leftrighttriggers");
|
2024-07-04 16:53:13 +00:00
|
|
|
quickSystemSelect->add(_("SHOULDERS"), "shoulders", selectedQuickSelect == "shoulders");
|
|
|
|
quickSystemSelect->add(_("TRIGGERS"), "triggers", selectedQuickSelect == "triggers");
|
|
|
|
quickSystemSelect->add(_("LEFT/RIGHT"), "leftright", selectedQuickSelect == "leftright");
|
|
|
|
quickSystemSelect->add(_("DISABLED"), "disabled", selectedQuickSelect == "disabled");
|
2022-12-07 17:09:05 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the quick system select to "leftrightshoulders" in this case.
|
|
|
|
if (quickSystemSelect->getSelectedObjects().size() == 0)
|
|
|
|
quickSystemSelect->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("QUICK SYSTEM SELECT"), quickSystemSelect);
|
2022-12-07 17:09:05 +00:00
|
|
|
s->addSaveFunc([quickSystemSelect, s] {
|
|
|
|
if (quickSystemSelect->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("QuickSystemSelect")) {
|
|
|
|
Settings::getInstance()->setString("QuickSystemSelect",
|
|
|
|
quickSystemSelect->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-31 22:53:32 +00:00
|
|
|
// Optionally start in selected system/gamelist.
|
|
|
|
auto startupSystem = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("GAMELIST ON STARTUP"), false);
|
|
|
|
startupSystem->add(_("NONE"), "", Settings::getInstance()->getString("StartupSystem") == "");
|
2022-01-31 22:53:32 +00:00
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
|
|
|
it != SystemData::sSystemVector.cend(); ++it) {
|
2022-12-07 17:09:05 +00:00
|
|
|
// If required, abbreviate the system name so it doesn't overlap the setting name.
|
|
|
|
float maxNameLength {mSize.x * 0.51f};
|
2024-07-18 13:07:41 +00:00
|
|
|
std::string sysName {(*it)->getFullName()};
|
|
|
|
if ((*it)->isCollection() && (sysName == "collections" || sysName == "all games" ||
|
|
|
|
sysName == "favorites" || sysName == "last played")) {
|
|
|
|
sysName = _(sysName.c_str());
|
|
|
|
}
|
|
|
|
startupSystem->add(Utils::String::toUpper(sysName), (*it)->getName(),
|
2022-12-07 17:09:05 +00:00
|
|
|
Settings::getInstance()->getString("StartupSystem") == (*it)->getName(),
|
|
|
|
maxNameLength);
|
2022-01-31 22:53:32 +00:00
|
|
|
}
|
|
|
|
// This can probably not happen but as an extra precaution select the "NONE" entry if no
|
|
|
|
// entry is selected.
|
|
|
|
if (startupSystem->getSelectedObjects().size() == 0)
|
|
|
|
startupSystem->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("GAMELIST ON STARTUP"), startupSystem);
|
2022-01-31 22:53:32 +00:00
|
|
|
s->addSaveFunc([startupSystem, s] {
|
|
|
|
if (startupSystem->getSelected() != Settings::getInstance()->getString("StartupSystem")) {
|
|
|
|
Settings::getInstance()->setString("StartupSystem", startupSystem->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-08-13 19:32:54 +00:00
|
|
|
// Systems sorting.
|
|
|
|
auto systemsSorting = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("SYSTEMS SORTING"), false);
|
2023-08-13 19:32:54 +00:00
|
|
|
std::string selectedSystemsSorting {Settings::getInstance()->getString("SystemsSorting")};
|
2024-07-04 16:53:13 +00:00
|
|
|
systemsSorting->add(_("FULL NAMES OR CUSTOM"), "default", selectedSystemsSorting == "default");
|
|
|
|
systemsSorting->add(_("RELEASE YEAR"), "year", selectedSystemsSorting == "year");
|
|
|
|
systemsSorting->add(_("MANUFACTURER, RELEASE YEAR"), "manufacturer_year",
|
2023-08-13 19:32:54 +00:00
|
|
|
selectedSystemsSorting == "manufacturer_year");
|
2024-07-04 16:53:13 +00:00
|
|
|
systemsSorting->add(_("HW TYPE, RELEASE YEAR"), "hwtype_year",
|
2023-08-13 19:32:54 +00:00
|
|
|
selectedSystemsSorting == "hwtype_year");
|
2024-07-04 16:53:13 +00:00
|
|
|
systemsSorting->add(_("MANUFACTURER, HW TYPE, REL. YEAR"), "manufacturer_hwtype_year",
|
2023-08-13 19:32:54 +00:00
|
|
|
selectedSystemsSorting == "manufacturer_hwtype_year");
|
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the systems sorting to "default" in this case.
|
|
|
|
if (systemsSorting->getSelectedObjects().size() == 0)
|
|
|
|
systemsSorting->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("SYSTEMS SORTING"), systemsSorting);
|
2023-08-13 22:02:20 +00:00
|
|
|
s->addSaveFunc([this, systemsSorting, s] {
|
2023-08-13 19:32:54 +00:00
|
|
|
if (systemsSorting->getSelected() != Settings::getInstance()->getString("SystemsSorting")) {
|
|
|
|
Settings::getInstance()->setString("SystemsSorting", systemsSorting->getSelected());
|
|
|
|
s->setNeedsSaving();
|
2023-08-13 22:02:20 +00:00
|
|
|
if (mThemeDownloaderReloadCounter == 0)
|
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
else
|
|
|
|
++mThemeDownloaderReloadCounter;
|
2023-08-13 19:32:54 +00:00
|
|
|
s->setNeedsRescanROMDirectory();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-31 22:53:32 +00:00
|
|
|
// Default gamelist sort order.
|
|
|
|
std::string sortOrder;
|
2022-09-03 10:44:49 +00:00
|
|
|
auto defaultSortOrder = std::make_shared<OptionListComponent<const FileData::SortType*>>(
|
2024-07-19 08:40:04 +00:00
|
|
|
getHelpStyle(), _("GAMES DEFAULT SORT ORDER [short]"), false);
|
2022-01-31 22:53:32 +00:00
|
|
|
// Exclude the System sort options.
|
2022-09-03 10:44:49 +00:00
|
|
|
unsigned int numSortTypes {static_cast<unsigned int>(FileSorts::SortTypes.size() - 2)};
|
2023-08-13 16:19:25 +00:00
|
|
|
for (unsigned int i {0}; i < numSortTypes; ++i) {
|
2022-01-31 22:53:32 +00:00
|
|
|
if (FileSorts::SortTypes[i].description ==
|
|
|
|
Settings::getInstance()->getString("DefaultSortOrder")) {
|
|
|
|
sortOrder = FileSorts::SortTypes[i].description;
|
|
|
|
break;
|
2021-10-09 11:09:14 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2022-01-31 22:53:32 +00:00
|
|
|
// If an invalid sort order was defined in es_settings.xml, then apply the default
|
2023-08-13 16:19:25 +00:00
|
|
|
// sort order "name, ascending".
|
|
|
|
if (sortOrder == "") {
|
2022-01-31 22:53:32 +00:00
|
|
|
sortOrder = Settings::getInstance()->getDefaultString("DefaultSortOrder");
|
2023-08-13 16:19:25 +00:00
|
|
|
Settings::getInstance()->setString("DefaultSortOrder", sortOrder);
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
for (unsigned int i {0}; i < numSortTypes; ++i) {
|
2022-09-03 10:44:49 +00:00
|
|
|
const FileData::SortType& sort {FileSorts::SortTypes[i]};
|
2022-01-31 22:53:32 +00:00
|
|
|
if (sort.description == sortOrder)
|
2024-07-04 16:53:13 +00:00
|
|
|
defaultSortOrder->add(Utils::String::toUpper(_(sort.description.c_str())), &sort, true);
|
2022-01-31 22:53:32 +00:00
|
|
|
else
|
2024-07-04 16:53:13 +00:00
|
|
|
defaultSortOrder->add(Utils::String::toUpper(_(sort.description.c_str())), &sort,
|
|
|
|
false);
|
2022-01-31 22:53:32 +00:00
|
|
|
}
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("GAMES DEFAULT SORT ORDER"), defaultSortOrder);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([defaultSortOrder, sortOrder, s] {
|
|
|
|
std::string selectedSortOrder {defaultSortOrder.get()->getSelected()->description};
|
2022-01-31 22:53:32 +00:00
|
|
|
if (selectedSortOrder != sortOrder) {
|
|
|
|
Settings::getInstance()->setString("DefaultSortOrder", selectedSortOrder);
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsSorting();
|
|
|
|
s->setNeedsSortingCollections();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-05-07 20:56:24 +00:00
|
|
|
// Menu color scheme.
|
|
|
|
auto menuColorScheme = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("MENU COLOR SCHEME"), false);
|
2023-05-07 20:56:24 +00:00
|
|
|
const std::string selectedMenuColor {Settings::getInstance()->getString("MenuColorScheme")};
|
2024-07-04 16:53:13 +00:00
|
|
|
menuColorScheme->add(_("DARK"), "dark", selectedMenuColor == "dark");
|
|
|
|
menuColorScheme->add(_("LIGHT"), "light", selectedMenuColor == "light");
|
2023-05-07 20:56:24 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
2023-07-13 15:29:57 +00:00
|
|
|
// configuration file. Simply set the menu color scheme to "dark" in this case.
|
2023-05-07 20:56:24 +00:00
|
|
|
if (menuColorScheme->getSelectedObjects().size() == 0)
|
|
|
|
menuColorScheme->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("MENU COLOR SCHEME"), menuColorScheme);
|
2023-08-13 22:02:20 +00:00
|
|
|
s->addSaveFunc([this, menuColorScheme, s] {
|
2023-05-07 20:56:24 +00:00
|
|
|
if (menuColorScheme->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("MenuColorScheme")) {
|
|
|
|
Settings::getInstance()->setString("MenuColorScheme", menuColorScheme->getSelected());
|
|
|
|
ViewController::getInstance()->setMenuColors();
|
2023-08-13 19:32:54 +00:00
|
|
|
s->setNeedsSaving();
|
2023-08-13 22:02:20 +00:00
|
|
|
if (mThemeDownloaderReloadCounter == 0)
|
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
else
|
|
|
|
++mThemeDownloaderReloadCounter;
|
2023-05-07 20:56:24 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-31 22:53:32 +00:00
|
|
|
// Open menu effect.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto menuOpeningEffect = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 16:53:13 +00:00
|
|
|
getHelpStyle(), _("MENU OPENING ANIMATION"), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
std::string selectedMenuEffect {Settings::getInstance()->getString("MenuOpeningEffect")};
|
2024-07-04 16:53:13 +00:00
|
|
|
menuOpeningEffect->add(_("SCALE-UP"), "scale-up", selectedMenuEffect == "scale-up");
|
|
|
|
menuOpeningEffect->add(_("NONE"), "none", selectedMenuEffect == "none");
|
2022-01-31 22:53:32 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the opening effect to "scale-up" in this case.
|
2022-09-03 10:44:49 +00:00
|
|
|
if (menuOpeningEffect->getSelectedObjects().size() == 0)
|
|
|
|
menuOpeningEffect->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("MENU OPENING ANIMATION"), menuOpeningEffect);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([menuOpeningEffect, s] {
|
|
|
|
if (menuOpeningEffect->getSelected() !=
|
2022-01-31 22:53:32 +00:00
|
|
|
Settings::getInstance()->getString("MenuOpeningEffect")) {
|
|
|
|
Settings::getInstance()->setString("MenuOpeningEffect",
|
2022-09-03 10:44:49 +00:00
|
|
|
menuOpeningEffect->getSelected());
|
2022-01-31 22:53:32 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Launch screen duration.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto launchScreenDuration = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 17:34:04 +00:00
|
|
|
getHelpStyle(), _("LAUNCH SCREEN DURATION"), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
std::string selectedDuration {Settings::getInstance()->getString("LaunchScreenDuration")};
|
2024-07-04 16:53:13 +00:00
|
|
|
launchScreenDuration->add(_("NORMAL"), "normal", selectedDuration == "normal");
|
|
|
|
launchScreenDuration->add(_("BRIEF"), "brief", selectedDuration == "brief");
|
|
|
|
launchScreenDuration->add(_("LONG"), "long", selectedDuration == "long");
|
|
|
|
launchScreenDuration->add(_("DISABLED"), "disabled", selectedDuration == "disabled");
|
2022-01-31 22:53:32 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the duration to "normal" in this case.
|
2022-09-03 10:44:49 +00:00
|
|
|
if (launchScreenDuration->getSelectedObjects().size() == 0)
|
|
|
|
launchScreenDuration->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("LAUNCH SCREEN DURATION"), launchScreenDuration);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([launchScreenDuration, s] {
|
|
|
|
if (launchScreenDuration->getSelected() !=
|
2022-01-31 22:53:32 +00:00
|
|
|
Settings::getInstance()->getString("LaunchScreenDuration")) {
|
|
|
|
Settings::getInstance()->setString("LaunchScreenDuration",
|
2022-09-03 10:44:49 +00:00
|
|
|
launchScreenDuration->getSelected());
|
2022-01-31 22:53:32 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// UI mode.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto uiMode =
|
2024-07-04 16:53:13 +00:00
|
|
|
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), _("UI MODE"), false);
|
2020-12-17 22:45:29 +00:00
|
|
|
std::string setMode;
|
|
|
|
if (Settings::getInstance()->getBool("ForceKiosk"))
|
|
|
|
setMode = "kiosk";
|
|
|
|
else if (Settings::getInstance()->getBool("ForceKid"))
|
|
|
|
setMode = "kid";
|
|
|
|
else
|
|
|
|
setMode = Settings::getInstance()->getString("UIMode");
|
2024-07-04 16:53:13 +00:00
|
|
|
uiMode->add(_("FULL"), "full", setMode == "full");
|
|
|
|
uiMode->add(_("KIOSK"), "kiosk", setMode == "kiosk");
|
|
|
|
uiMode->add(_("KID"), "kid", setMode == "kid");
|
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the UI mode to "full" in this case.
|
|
|
|
if (uiMode->getSelectedObjects().size() == 0)
|
|
|
|
uiMode->selectEntry(0);
|
|
|
|
s->addWithLabel(_("UI MODE"), uiMode);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([uiMode, this, s] {
|
|
|
|
std::string selectedMode {uiMode->getSelected()};
|
2021-01-05 09:45:32 +00:00
|
|
|
// If any of the force flags are set, then always apply and save the setting.
|
|
|
|
if (selectedMode == Settings::getInstance()->getString("UIMode") &&
|
2021-07-07 18:03:42 +00:00
|
|
|
!Settings::getInstance()->getBool("ForceFull") &&
|
|
|
|
!Settings::getInstance()->getBool("ForceKiosk") &&
|
|
|
|
!Settings::getInstance()->getBool("ForceKid")) {
|
2021-01-05 09:45:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (selectedMode != "full") {
|
2024-07-16 14:50:46 +00:00
|
|
|
std::string msg;
|
2021-01-17 10:11:07 +00:00
|
|
|
if (selectedMode == "kiosk") {
|
2024-07-16 14:50:46 +00:00
|
|
|
msg = Utils::String::format(
|
|
|
|
_("THIS CHANGES THE UI TO THE RESTRICTED MODE\n'KIOSK'\n"
|
|
|
|
"THIS WILL HIDE MOST MENU OPTIONS\n"
|
|
|
|
"TO UNLOCK AND RETURN TO THE FULL UI, ENTER THIS CODE:\n%s\n\n"
|
|
|
|
"DO YOU WANT TO PROCEED?"),
|
|
|
|
UIModeController::getInstance()->getFormattedPassKeyStr().c_str());
|
2021-01-17 10:11:07 +00:00
|
|
|
}
|
|
|
|
else {
|
2024-07-16 14:50:46 +00:00
|
|
|
msg = Utils::String::format(
|
|
|
|
_("THIS CHANGES THE UI TO THE RESTRICTED MODE\n'KID'\n"
|
|
|
|
"THIS ONLY ENABLES GAMES THAT HAVE BEEN FLAGGED\n"
|
|
|
|
"AS SUITABLE FOR CHILDREN\n"
|
|
|
|
"TO UNLOCK AND RETURN TO THE FULL UI, ENTER THIS CODE:\n%s\n\n"
|
|
|
|
"DO YOU WANT TO PROCEED?"),
|
|
|
|
UIModeController::getInstance()->getFormattedPassKeyStr().c_str());
|
2021-01-17 10:11:07 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
2024-07-16 14:50:46 +00:00
|
|
|
this->getHelpStyle(), msg, _("YES"),
|
2021-07-07 18:03:42 +00:00
|
|
|
[this, selectedMode] {
|
|
|
|
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '"
|
|
|
|
<< selectedMode << "'.";
|
|
|
|
Settings::getInstance()->setString("UIMode", selectedMode);
|
|
|
|
Settings::getInstance()->setBool("ForceFull", false);
|
|
|
|
Settings::getInstance()->setBool("ForceKiosk", false);
|
|
|
|
Settings::getInstance()->setBool("ForceKid", false);
|
|
|
|
Settings::getInstance()->saveFile();
|
2023-01-14 19:09:52 +00:00
|
|
|
if (CollectionSystemsManager::getInstance()->isEditing())
|
|
|
|
CollectionSystemsManager::getInstance()->exitEditMode();
|
2021-07-07 18:03:42 +00:00
|
|
|
UIModeController::getInstance()->setCurrentUIMode(selectedMode);
|
|
|
|
for (auto it = SystemData::sSystemVector.cbegin();
|
2021-11-17 16:35:34 +00:00
|
|
|
it != SystemData::sSystemVector.cend(); ++it) {
|
2021-07-07 18:03:42 +00:00
|
|
|
if ((*it)->getThemeFolder() == "custom-collections") {
|
|
|
|
for (FileData* customSystem :
|
|
|
|
(*it)->getRootFolder()->getChildrenListToDisplay())
|
|
|
|
customSystem->getSystem()->getIndex()->resetFilters();
|
|
|
|
}
|
|
|
|
(*it)->sortSystem();
|
|
|
|
(*it)->getIndex()->resetFilters();
|
2021-01-05 09:45:32 +00:00
|
|
|
}
|
2022-01-04 20:49:22 +00:00
|
|
|
ViewController::getInstance()->reloadAll();
|
|
|
|
ViewController::getInstance()->goToSystem(SystemData::sSystemVector.front(),
|
|
|
|
false);
|
2021-07-07 18:03:42 +00:00
|
|
|
mWindow->invalidateCachedBackground();
|
|
|
|
},
|
2024-07-16 14:50:46 +00:00
|
|
|
_("NO"), nullptr, "", nullptr, nullptr, true));
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
2021-01-05 09:45:32 +00:00
|
|
|
else {
|
2021-07-07 18:03:42 +00:00
|
|
|
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" << selectedMode
|
|
|
|
<< "'.";
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setString("UIMode", uiMode->getSelected());
|
2020-12-17 22:45:29 +00:00
|
|
|
Settings::getInstance()->setBool("ForceFull", false);
|
|
|
|
Settings::getInstance()->setBool("ForceKiosk", false);
|
|
|
|
Settings::getInstance()->setBool("ForceKid", false);
|
2021-01-05 09:45:32 +00:00
|
|
|
UIModeController::getInstance()->setCurrentUIMode("full");
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2021-01-05 09:45:32 +00:00
|
|
|
s->setNeedsSorting();
|
|
|
|
s->setNeedsSortingCollections();
|
|
|
|
s->setNeedsResetFilters();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setNeedsGoToSystem(SystemData::sSystemVector.front());
|
2021-03-21 17:46:45 +00:00
|
|
|
s->setInvalidateCachedBackground();
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-03-06 18:27:59 +00:00
|
|
|
// Random entry button.
|
|
|
|
auto randomEntryButton = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-04 17:34:04 +00:00
|
|
|
getHelpStyle(), _("RANDOM ENTRY BUTTON"), false);
|
2023-03-06 18:27:59 +00:00
|
|
|
const std::string selectedRandomEntryButton {
|
|
|
|
Settings::getInstance()->getString("RandomEntryButton")};
|
2024-07-04 16:53:13 +00:00
|
|
|
randomEntryButton->add(_("GAMES ONLY"), "games", selectedRandomEntryButton == "games");
|
|
|
|
randomEntryButton->add(_("GAMES AND SYSTEMS"), "gamessystems",
|
2023-03-06 18:27:59 +00:00
|
|
|
selectedRandomEntryButton == "gamessystems");
|
2024-07-04 16:53:13 +00:00
|
|
|
randomEntryButton->add(_("DISABLED"), "disabled", selectedRandomEntryButton == "disabled");
|
2023-03-06 18:27:59 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the random entry button to "games" in this case.
|
|
|
|
if (randomEntryButton->getSelectedObjects().size() == 0)
|
|
|
|
randomEntryButton->selectEntry(0);
|
2024-07-04 16:53:13 +00:00
|
|
|
s->addWithLabel(_("RANDOM ENTRY BUTTON"), randomEntryButton);
|
2023-03-06 18:27:59 +00:00
|
|
|
s->addSaveFunc([randomEntryButton, s] {
|
|
|
|
if (randomEntryButton->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("RandomEntryButton")) {
|
|
|
|
Settings::getInstance()->setString("RandomEntryButton",
|
|
|
|
randomEntryButton->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-08-22 12:29:43 +00:00
|
|
|
// Media viewer.
|
2022-09-03 10:44:49 +00:00
|
|
|
ComponentListRow mediaViewerRow;
|
|
|
|
mediaViewerRow.elements.clear();
|
2024-07-04 16:53:13 +00:00
|
|
|
mediaViewerRow.addElement(std::make_shared<TextComponent>(_("MEDIA VIEWER SETTINGS"),
|
2023-05-07 20:56:24 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM),
|
|
|
|
mMenuColorPrimary),
|
2022-09-03 10:44:49 +00:00
|
|
|
true);
|
2023-05-07 20:56:24 +00:00
|
|
|
mediaViewerRow.addElement(mMenu.makeArrow(), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
mediaViewerRow.makeAcceptInputHandler(std::bind(&GuiMenu::openMediaViewerOptions, this));
|
|
|
|
s->addRow(mediaViewerRow);
|
2021-08-22 12:29:43 +00:00
|
|
|
|
|
|
|
// Screensaver.
|
2022-09-03 10:44:49 +00:00
|
|
|
ComponentListRow screensaverRow;
|
|
|
|
screensaverRow.elements.clear();
|
2024-07-04 16:53:13 +00:00
|
|
|
screensaverRow.addElement(std::make_shared<TextComponent>(_("SCREENSAVER SETTINGS"),
|
2023-05-07 20:56:24 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM),
|
|
|
|
mMenuColorPrimary),
|
2022-09-03 10:44:49 +00:00
|
|
|
true);
|
2023-05-07 20:56:24 +00:00
|
|
|
screensaverRow.addElement(mMenu.makeArrow(), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
screensaverRow.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
|
|
|
|
s->addRow(screensaverRow);
|
2021-08-22 12:29:43 +00:00
|
|
|
|
2023-01-31 18:26:39 +00:00
|
|
|
// Enable theme variant triggers.
|
|
|
|
auto themeVariantTriggers = std::make_shared<SwitchComponent>();
|
|
|
|
themeVariantTriggers->setState(Settings::getInstance()->getBool("ThemeVariantTriggers"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE THEME VARIANT TRIGGERS"), themeVariantTriggers);
|
2023-01-31 18:26:39 +00:00
|
|
|
s->addSaveFunc([themeVariantTriggers, s] {
|
|
|
|
if (themeVariantTriggers->getState() !=
|
|
|
|
Settings::getInstance()->getBool("ThemeVariantTriggers")) {
|
|
|
|
Settings::getInstance()->setBool("ThemeVariantTriggers",
|
|
|
|
themeVariantTriggers->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-03-18 18:46:45 +00:00
|
|
|
// Blur background when the menu is open.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto menuBlurBackground = std::make_shared<SwitchComponent>();
|
2023-02-21 17:39:56 +00:00
|
|
|
if (mRenderer->getScreenRotation() == 90 || mRenderer->getScreenRotation() == 270) {
|
|
|
|
// TODO: Add support for non-blurred background when rotating screen 90 or 270 degrees.
|
|
|
|
menuBlurBackground->setState(true);
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("BLUR BACKGROUND WHEN MENU IS OPEN"), menuBlurBackground);
|
2023-02-21 17:39:56 +00:00
|
|
|
menuBlurBackground->setEnabled(false);
|
|
|
|
menuBlurBackground->setOpacity(DISABLED_OPACITY);
|
|
|
|
menuBlurBackground->getParent()
|
|
|
|
->getChild(menuBlurBackground->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
menuBlurBackground->setState(Settings::getInstance()->getBool("MenuBlurBackground"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("BLUR BACKGROUND WHEN MENU IS OPEN"), menuBlurBackground);
|
2023-02-21 17:39:56 +00:00
|
|
|
s->addSaveFunc([menuBlurBackground, s] {
|
|
|
|
if (menuBlurBackground->getState() !=
|
|
|
|
Settings::getInstance()->getBool("MenuBlurBackground")) {
|
|
|
|
Settings::getInstance()->setBool("MenuBlurBackground",
|
|
|
|
menuBlurBackground->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setInvalidateCachedBackground();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-09-13 12:28:06 +00:00
|
|
|
|
2020-07-28 17:44:17 +00:00
|
|
|
// Sort folders on top of the gamelists.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto foldersOnTop = std::make_shared<SwitchComponent>();
|
|
|
|
foldersOnTop->setState(Settings::getInstance()->getBool("FoldersOnTop"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("SORT FOLDERS ON TOP OF GAMELISTS"), foldersOnTop);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([foldersOnTop, s] {
|
|
|
|
if (foldersOnTop->getState() != Settings::getInstance()->getBool("FoldersOnTop")) {
|
|
|
|
Settings::getInstance()->setBool("FoldersOnTop", foldersOnTop->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsSorting();
|
2021-03-21 17:46:45 +00:00
|
|
|
s->setInvalidateCachedBackground();
|
2020-07-28 17:44:17 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Sort favorites on top of non-favorites in the gamelists.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto favoritesFirst = std::make_shared<SwitchComponent>();
|
|
|
|
favoritesFirst->setState(Settings::getInstance()->getBool("FavoritesFirst"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("SORT FAVORITE GAMES ABOVE NON-FAVORITES"), favoritesFirst);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([favoritesFirst, s] {
|
|
|
|
if (favoritesFirst->getState() != Settings::getInstance()->getBool("FavoritesFirst")) {
|
|
|
|
Settings::getInstance()->setBool("FavoritesFirst", favoritesFirst->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsSorting();
|
|
|
|
s->setNeedsSortingCollections();
|
2021-03-21 17:46:45 +00:00
|
|
|
s->setInvalidateCachedBackground();
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-10-25 20:29:54 +00:00
|
|
|
// Enable gamelist star markings for favorite games.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto favoritesStar = std::make_shared<SwitchComponent>();
|
|
|
|
favoritesStar->setState(Settings::getInstance()->getBool("FavoritesStar"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ADD STAR MARKINGS TO FAVORITE GAMES"), favoritesStar);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([favoritesStar, s] {
|
|
|
|
if (favoritesStar->getState() != Settings::getInstance()->getBool("FavoritesStar")) {
|
|
|
|
Settings::getInstance()->setBool("FavoritesStar", favoritesStar->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
2021-03-21 17:46:45 +00:00
|
|
|
s->setInvalidateCachedBackground();
|
2020-10-25 20:29:54 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-01-12 21:41:28 +00:00
|
|
|
// Enable quick list scrolling overlay.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto listScrollOverlay = std::make_shared<SwitchComponent>();
|
|
|
|
listScrollOverlay->setState(Settings::getInstance()->getBool("ListScrollOverlay"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE TEXTLIST QUICK SCROLLING OVERLAY"), listScrollOverlay);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([listScrollOverlay, s] {
|
|
|
|
if (listScrollOverlay->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("ListScrollOverlay")) {
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setBool("ListScrollOverlay", listScrollOverlay->getState());
|
2021-01-12 21:41:28 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-17 20:23:41 +00:00
|
|
|
// Enable virtual (on-screen) keyboard.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto virtualKeyboard = std::make_shared<SwitchComponent>();
|
|
|
|
virtualKeyboard->setState(Settings::getInstance()->getBool("VirtualKeyboard"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE VIRTUAL KEYBOARD"), virtualKeyboard);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([virtualKeyboard, s] {
|
|
|
|
if (virtualKeyboard->getState() != Settings::getInstance()->getBool("VirtualKeyboard")) {
|
|
|
|
Settings::getInstance()->setBool("VirtualKeyboard", virtualKeyboard->getState());
|
2021-09-17 20:23:41 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setInvalidateCachedBackground();
|
2024-02-01 22:25:43 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
if (Settings::getInstance()->getBool("VirtualKeyboard"))
|
|
|
|
SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "0");
|
|
|
|
else
|
|
|
|
SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "1");
|
|
|
|
#endif
|
2021-09-17 20:23:41 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-10-31 09:01:19 +00:00
|
|
|
// Enable the 'Y' button for tagging games as favorites.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto favoritesAddButton = std::make_shared<SwitchComponent>();
|
|
|
|
favoritesAddButton->setState(Settings::getInstance()->getBool("FavoritesAddButton"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE TOGGLE FAVORITES BUTTON"), favoritesAddButton);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([favoritesAddButton, s] {
|
2020-10-31 09:01:19 +00:00
|
|
|
if (Settings::getInstance()->getBool("FavoritesAddButton") !=
|
2022-09-03 10:44:49 +00:00
|
|
|
favoritesAddButton->getState()) {
|
|
|
|
Settings::getInstance()->setBool("FavoritesAddButton", favoritesAddButton->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2020-10-31 09:01:19 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// Gamelist filters.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto gamelistFilters = std::make_shared<SwitchComponent>();
|
|
|
|
gamelistFilters->setState(Settings::getInstance()->getBool("GamelistFilters"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE GAMELIST FILTERS"), gamelistFilters);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([gamelistFilters, s] {
|
|
|
|
if (Settings::getInstance()->getBool("GamelistFilters") != gamelistFilters->getState()) {
|
|
|
|
Settings::getInstance()->setBool("GamelistFilters", gamelistFilters->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
s->setNeedsReloading();
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
});
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// On-screen help prompts.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto showHelpPrompts = std::make_shared<SwitchComponent>();
|
|
|
|
showHelpPrompts->setState(Settings::getInstance()->getBool("ShowHelpPrompts"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("DISPLAY ON-SCREEN HELP"), showHelpPrompts);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([showHelpPrompts, s] {
|
|
|
|
if (Settings::getInstance()->getBool("ShowHelpPrompts") != showHelpPrompts->getState()) {
|
|
|
|
Settings::getInstance()->setBool("ShowHelpPrompts", showHelpPrompts->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
// When the theme entries are scrolled or selected, update the relevant rows.
|
|
|
|
auto scrollThemeFunc = [=](const std::string& themeName, bool firstRun = false) {
|
|
|
|
auto selectedTheme = themes.find(themeName);
|
|
|
|
if (selectedTheme == themes.cend())
|
2022-02-12 16:47:59 +00:00
|
|
|
return;
|
|
|
|
if (!firstRun) {
|
|
|
|
themeVariantsFunc(themeName, themeVariant->getSelected());
|
2022-10-31 18:32:13 +00:00
|
|
|
themeColorSchemesFunc(themeName, themeColorScheme->getSelected());
|
2023-12-20 20:58:40 +00:00
|
|
|
themeFontSizeFunc(themeName, themeFontSize->getSelected());
|
2022-02-12 16:47:59 +00:00
|
|
|
themeAspectRatiosFunc(themeName, themeAspectRatio->getSelected());
|
2023-01-16 21:43:56 +00:00
|
|
|
themeTransitionsFunc(themeName, themeTransitions->getSelected());
|
2022-02-12 16:47:59 +00:00
|
|
|
}
|
|
|
|
int selectableVariants {0};
|
2023-08-14 20:40:32 +00:00
|
|
|
for (auto& variant : selectedTheme->second.capabilities.variants) {
|
2022-02-12 16:47:59 +00:00
|
|
|
if (variant.selectable)
|
|
|
|
++selectableVariants;
|
|
|
|
}
|
2023-07-30 16:17:27 +00:00
|
|
|
if (selectableVariants > 0) {
|
2022-02-12 16:47:59 +00:00
|
|
|
themeVariant->setEnabled(true);
|
|
|
|
themeVariant->setOpacity(1.0f);
|
|
|
|
themeVariant->getParent()
|
|
|
|
->getChild(themeVariant->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
themeVariant->setEnabled(false);
|
|
|
|
themeVariant->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeVariant->getParent()
|
|
|
|
->getChild(themeVariant->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
2023-08-14 20:40:32 +00:00
|
|
|
if (selectedTheme->second.capabilities.colorSchemes.size() > 0) {
|
2022-10-31 18:32:13 +00:00
|
|
|
themeColorScheme->setEnabled(true);
|
|
|
|
themeColorScheme->setOpacity(1.0f);
|
|
|
|
themeColorScheme->getParent()
|
|
|
|
->getChild(themeColorScheme->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
themeColorScheme->setEnabled(false);
|
|
|
|
themeColorScheme->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeColorScheme->getParent()
|
|
|
|
->getChild(themeColorScheme->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
2023-12-20 20:58:40 +00:00
|
|
|
if (selectedTheme->second.capabilities.fontSizes.size() > 0) {
|
|
|
|
themeFontSize->setEnabled(true);
|
|
|
|
themeFontSize->setOpacity(1.0f);
|
|
|
|
themeFontSize->getParent()
|
|
|
|
->getChild(themeFontSize->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
themeFontSize->setEnabled(false);
|
|
|
|
themeFontSize->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeFontSize->getParent()
|
|
|
|
->getChild(themeFontSize->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
2023-08-14 20:40:32 +00:00
|
|
|
if (selectedTheme->second.capabilities.aspectRatios.size() > 0) {
|
2022-02-12 16:47:59 +00:00
|
|
|
themeAspectRatio->setEnabled(true);
|
|
|
|
themeAspectRatio->setOpacity(1.0f);
|
|
|
|
themeAspectRatio->getParent()
|
|
|
|
->getChild(themeAspectRatio->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
themeAspectRatio->setEnabled(false);
|
|
|
|
themeAspectRatio->setOpacity(DISABLED_OPACITY);
|
|
|
|
themeAspectRatio->getParent()
|
|
|
|
->getChild(themeAspectRatio->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-08-14 20:40:32 +00:00
|
|
|
scrollThemeFunc(selectedTheme->first, true);
|
|
|
|
theme->setCallback(scrollThemeFunc);
|
2022-02-12 16:47:59 +00:00
|
|
|
|
2021-10-24 12:11:19 +00:00
|
|
|
s->setSize(mSize);
|
2020-06-21 12:25:28 +00:00
|
|
|
mWindow->pushGui(s);
|
2017-09-08 14:49:47 +00:00
|
|
|
}
|
|
|
|
|
2021-05-22 20:48:44 +00:00
|
|
|
void GuiMenu::openSoundOptions()
|
2020-11-05 17:18:11 +00:00
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("SOUND SETTINGS"));
|
2020-11-05 17:18:11 +00:00
|
|
|
|
2023-12-23 23:06:43 +00:00
|
|
|
// TODO: Implement system volume support for macOS and Android.
|
2023-12-23 23:05:39 +00:00
|
|
|
#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(__FreeBSD__) && \
|
|
|
|
!defined(__OpenBSD__) && !defined(__NetBSD__)
|
2020-11-05 17:18:11 +00:00
|
|
|
// System volume.
|
2022-01-04 20:21:26 +00:00
|
|
|
// The reason to create the VolumeControl object every time instead of making it a singleton
|
|
|
|
// is that this is the easiest way to detect new default audio devices or changes to the
|
|
|
|
// audio volume done by the operating system. And we don't really need this object laying
|
|
|
|
// around anyway as it's only used here.
|
|
|
|
VolumeControl volumeControl;
|
2022-09-03 10:44:49 +00:00
|
|
|
int currentVolume {volumeControl.getVolume()};
|
2022-01-04 20:21:26 +00:00
|
|
|
|
2022-09-27 15:43:27 +00:00
|
|
|
auto systemVolume = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
|
2022-01-04 20:21:26 +00:00
|
|
|
systemVolume->setValue(static_cast<float>(currentVolume));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("SYSTEM VOLUME"), systemVolume);
|
2022-01-04 20:21:26 +00:00
|
|
|
s->addSaveFunc([systemVolume, currentVolume] {
|
|
|
|
// No need to create the VolumeControl object unless the volume has actually been changed.
|
|
|
|
if (static_cast<int>(systemVolume->getValue()) != currentVolume) {
|
|
|
|
VolumeControl volumeControl;
|
|
|
|
volumeControl.setVolume(static_cast<int>(std::round(systemVolume->getValue())));
|
|
|
|
}
|
2020-11-05 17:18:11 +00:00
|
|
|
});
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-11-05 17:18:11 +00:00
|
|
|
|
2020-12-20 15:41:58 +00:00
|
|
|
// Volume for navigation sounds.
|
2022-09-27 15:43:27 +00:00
|
|
|
auto soundVolumeNavigation = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
|
2022-09-03 10:44:49 +00:00
|
|
|
soundVolumeNavigation->setValue(
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeNavigation")));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("NAVIGATION SOUNDS VOLUME"), soundVolumeNavigation);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([soundVolumeNavigation, s] {
|
|
|
|
if (soundVolumeNavigation->getValue() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeNavigation"))) {
|
2020-12-20 15:41:58 +00:00
|
|
|
Settings::getInstance()->setInt("SoundVolumeNavigation",
|
2022-09-03 10:44:49 +00:00
|
|
|
static_cast<int>(soundVolumeNavigation->getValue()));
|
2020-12-20 15:41:58 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Volume for videos.
|
2022-09-27 15:43:27 +00:00
|
|
|
auto soundVolumeVideos = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
|
2022-09-03 10:44:49 +00:00
|
|
|
soundVolumeVideos->setValue(
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeVideos")));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("VIDEO PLAYER VOLUME"), soundVolumeVideos);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([soundVolumeVideos, s] {
|
|
|
|
if (soundVolumeVideos->getValue() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeVideos"))) {
|
2020-12-20 15:41:58 +00:00
|
|
|
Settings::getInstance()->setInt("SoundVolumeVideos",
|
2022-09-03 10:44:49 +00:00
|
|
|
static_cast<int>(soundVolumeVideos->getValue()));
|
2020-12-20 15:41:58 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
if (UIModeController::getInstance()->isUIModeFull()) {
|
2021-05-16 11:12:31 +00:00
|
|
|
// Play audio for gamelist videos.
|
2022-02-20 15:07:27 +00:00
|
|
|
auto viewsVideoAudio = std::make_shared<SwitchComponent>();
|
|
|
|
viewsVideoAudio->setState(Settings::getInstance()->getBool("ViewsVideoAudio"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("PLAY AUDIO FOR GAMELIST AND SYSTEM VIEW VIDEOS"), viewsVideoAudio);
|
2022-02-20 15:07:27 +00:00
|
|
|
s->addSaveFunc([viewsVideoAudio, s] {
|
|
|
|
if (viewsVideoAudio->getState() !=
|
|
|
|
Settings::getInstance()->getBool("ViewsVideoAudio")) {
|
|
|
|
Settings::getInstance()->setBool("ViewsVideoAudio", viewsVideoAudio->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
// Play audio for media viewer videos.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto mediaViewerVideoAudio = std::make_shared<SwitchComponent>();
|
|
|
|
mediaViewerVideoAudio->setState(Settings::getInstance()->getBool("MediaViewerVideoAudio"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("PLAY AUDIO FOR MEDIA VIEWER VIDEOS"), mediaViewerVideoAudio);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([mediaViewerVideoAudio, s] {
|
|
|
|
if (mediaViewerVideoAudio->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("MediaViewerVideoAudio")) {
|
2021-05-16 11:12:31 +00:00
|
|
|
Settings::getInstance()->setBool("MediaViewerVideoAudio",
|
2022-09-03 10:44:49 +00:00
|
|
|
mediaViewerVideoAudio->getState());
|
2021-05-16 11:12:31 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Play audio for screensaver videos.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto screensaverVideoAudio = std::make_shared<SwitchComponent>();
|
|
|
|
screensaverVideoAudio->setState(Settings::getInstance()->getBool("ScreensaverVideoAudio"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("PLAY AUDIO FOR SCREENSAVER VIDEOS"), screensaverVideoAudio);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([screensaverVideoAudio, s] {
|
|
|
|
if (screensaverVideoAudio->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("ScreensaverVideoAudio")) {
|
2021-05-16 11:12:31 +00:00
|
|
|
Settings::getInstance()->setBool("ScreensaverVideoAudio",
|
2022-09-03 10:44:49 +00:00
|
|
|
screensaverVideoAudio->getState());
|
2021-05-16 11:12:31 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// Navigation sounds.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto navigationSounds = std::make_shared<SwitchComponent>();
|
|
|
|
navigationSounds->setState(Settings::getInstance()->getBool("NavigationSounds"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE NAVIGATION SOUNDS"), navigationSounds);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([navigationSounds, s] {
|
|
|
|
if (navigationSounds->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("NavigationSounds")) {
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setBool("NavigationSounds", navigationSounds->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-24 12:11:19 +00:00
|
|
|
s->setSize(mSize);
|
2020-11-05 17:18:11 +00:00
|
|
|
mWindow->pushGui(s);
|
|
|
|
}
|
|
|
|
|
2021-05-23 08:35:59 +00:00
|
|
|
void GuiMenu::openInputDeviceOptions()
|
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("INPUT DEVICE SETTINGS"));
|
2021-05-23 08:35:59 +00:00
|
|
|
|
2021-05-23 17:12:31 +00:00
|
|
|
// Controller type.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto inputControllerType = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-12 21:02:36 +00:00
|
|
|
getHelpStyle(), _("CONTROLLER TYPE"), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
std::string selectedPlayer {Settings::getInstance()->getString("InputControllerType")};
|
|
|
|
inputControllerType->add("XBOX", "xbox", selectedPlayer == "xbox");
|
|
|
|
inputControllerType->add("XBOX 360", "xbox360", selectedPlayer == "xbox360");
|
2023-01-21 12:45:54 +00:00
|
|
|
inputControllerType->add("PLAYSTATION 1/2/3", "ps123", selectedPlayer == "ps123");
|
2022-09-03 10:44:49 +00:00
|
|
|
inputControllerType->add("PLAYSTATION 4", "ps4", selectedPlayer == "ps4");
|
|
|
|
inputControllerType->add("PLAYSTATION 5", "ps5", selectedPlayer == "ps5");
|
2023-01-21 11:58:16 +00:00
|
|
|
inputControllerType->add("SWITCH PRO", "switchpro", selectedPlayer == "switchpro");
|
2022-09-03 10:44:49 +00:00
|
|
|
inputControllerType->add("SNES", "snes", selectedPlayer == "snes");
|
2021-05-23 17:12:31 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the controller type to "xbox" in this case.
|
2022-09-03 10:44:49 +00:00
|
|
|
if (inputControllerType->getSelectedObjects().size() == 0)
|
|
|
|
inputControllerType->selectEntry(0);
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("CONTROLLER TYPE"), inputControllerType);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([inputControllerType, s] {
|
|
|
|
if (inputControllerType->getSelected() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getString("InputControllerType")) {
|
2021-05-23 17:12:31 +00:00
|
|
|
Settings::getInstance()->setString("InputControllerType",
|
2022-09-03 10:44:49 +00:00
|
|
|
inputControllerType->getSelected());
|
2021-05-23 17:12:31 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-13 15:14:46 +00:00
|
|
|
#if defined(__ANDROID__)
|
2024-01-14 11:36:21 +00:00
|
|
|
// Touch overlay size.
|
|
|
|
auto touchOverlaySize = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-12 21:02:36 +00:00
|
|
|
getHelpStyle(), _("TOUCH OVERLAY SIZE"), false);
|
2024-01-14 11:36:21 +00:00
|
|
|
std::string selectedOverlaySize {Settings::getInstance()->getString("InputTouchOverlaySize")};
|
2024-07-12 21:02:36 +00:00
|
|
|
touchOverlaySize->add(_("MEDIUM"), "medium", selectedOverlaySize == "medium");
|
|
|
|
touchOverlaySize->add(_("LARGE"), "large", selectedOverlaySize == "large");
|
|
|
|
touchOverlaySize->add(_("SMALL"), "small", selectedOverlaySize == "small");
|
|
|
|
touchOverlaySize->add(_("EXTRA SMALL"), "x-small", selectedOverlaySize == "x-small");
|
2024-01-14 11:36:21 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the overlay size to "medium" in this case.
|
|
|
|
if (touchOverlaySize->getSelectedObjects().size() == 0)
|
|
|
|
touchOverlaySize->selectEntry(0);
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("TOUCH OVERLAY SIZE"), touchOverlaySize);
|
2024-01-14 11:36:21 +00:00
|
|
|
s->addSaveFunc([touchOverlaySize, s] {
|
|
|
|
if (touchOverlaySize->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("InputTouchOverlaySize")) {
|
|
|
|
Settings::getInstance()->setString("InputTouchOverlaySize",
|
|
|
|
touchOverlaySize->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
InputOverlay::getInstance().createButtons();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-29 21:37:45 +00:00
|
|
|
// Touch overlay opacity.
|
|
|
|
auto touchOverlayOpacity = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-12 21:02:36 +00:00
|
|
|
getHelpStyle(), _("TOUCH OVERLAY OPACITY"), false);
|
2024-01-29 21:37:45 +00:00
|
|
|
std::string selectedOverlayOpacity {
|
|
|
|
Settings::getInstance()->getString("InputTouchOverlayOpacity")};
|
2024-07-12 21:02:36 +00:00
|
|
|
touchOverlayOpacity->add(_("NORMAL"), "normal", selectedOverlayOpacity == "normal");
|
|
|
|
touchOverlayOpacity->add(_("LOW"), "low", selectedOverlayOpacity == "low");
|
|
|
|
touchOverlayOpacity->add(_("VERY LOW"), "verylow", selectedOverlayOpacity == "verylow");
|
2024-01-29 21:37:45 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the overlay opacity to "normal" in this case.
|
|
|
|
if (touchOverlayOpacity->getSelectedObjects().size() == 0)
|
|
|
|
touchOverlayOpacity->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("TOUCH OVERLAY OPACITY"), touchOverlayOpacity);
|
2024-01-29 21:37:45 +00:00
|
|
|
s->addSaveFunc([touchOverlayOpacity, s] {
|
|
|
|
if (touchOverlayOpacity->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("InputTouchOverlayOpacity")) {
|
|
|
|
Settings::getInstance()->setString("InputTouchOverlayOpacity",
|
|
|
|
touchOverlayOpacity->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
InputOverlay::getInstance().createButtons();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-14 20:55:09 +00:00
|
|
|
// Touch overlay fade-out timer.
|
|
|
|
auto touchOverlayFadeTime = std::make_shared<SliderComponent>(0.0f, 20.0f, 1.0f, "s");
|
|
|
|
touchOverlayFadeTime->setValue(
|
|
|
|
static_cast<float>(Settings::getInstance()->getInt("InputTouchOverlayFadeTime")));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("TOUCH OVERLAY FADE-OUT TIME"), touchOverlayFadeTime);
|
2024-01-14 20:55:09 +00:00
|
|
|
s->addSaveFunc([touchOverlayFadeTime, s] {
|
|
|
|
if (touchOverlayFadeTime->getValue() !=
|
|
|
|
static_cast<float>(Settings::getInstance()->getInt("InputTouchOverlayFadeTime"))) {
|
|
|
|
Settings::getInstance()->setInt("InputTouchOverlayFadeTime",
|
|
|
|
static_cast<int>(touchOverlayFadeTime->getValue()));
|
|
|
|
InputOverlay::getInstance().resetFadeTimer();
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-13 15:14:46 +00:00
|
|
|
// Whether to enable the touch overlay.
|
|
|
|
auto inputTouchOverlay = std::make_shared<SwitchComponent>();
|
|
|
|
inputTouchOverlay->setState(Settings::getInstance()->getBool("InputTouchOverlay"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ENABLE TOUCH OVERLAY"), inputTouchOverlay);
|
2024-01-13 15:14:46 +00:00
|
|
|
s->addSaveFunc([inputTouchOverlay, s] {
|
|
|
|
if (Settings::getInstance()->getBool("InputTouchOverlay") !=
|
|
|
|
inputTouchOverlay->getState()) {
|
|
|
|
Settings::getInstance()->setBool("InputTouchOverlay", inputTouchOverlay->getState());
|
2024-01-14 12:30:45 +00:00
|
|
|
if (Settings::getInstance()->getBool("InputTouchOverlay"))
|
|
|
|
InputOverlay::getInstance().createButtons();
|
|
|
|
else
|
|
|
|
InputOverlay::getInstance().clearButtons();
|
2024-01-13 15:14:46 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2024-01-14 11:36:21 +00:00
|
|
|
|
|
|
|
if (!Settings::getInstance()->getBool("InputTouchOverlay")) {
|
|
|
|
touchOverlaySize->setEnabled(false);
|
|
|
|
touchOverlaySize->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlaySize->getParent()
|
|
|
|
->getChild(touchOverlaySize->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
2024-01-14 20:55:09 +00:00
|
|
|
|
2024-01-29 21:37:45 +00:00
|
|
|
touchOverlayOpacity->setEnabled(false);
|
|
|
|
touchOverlayOpacity->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlayOpacity->getParent()
|
|
|
|
->getChild(touchOverlayOpacity->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
|
2024-01-14 20:55:09 +00:00
|
|
|
touchOverlayFadeTime->setEnabled(false);
|
|
|
|
touchOverlayFadeTime->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlayFadeTime->getParent()
|
|
|
|
->getChild(touchOverlayFadeTime->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
2024-01-14 11:36:21 +00:00
|
|
|
}
|
|
|
|
|
2024-01-14 20:55:09 +00:00
|
|
|
auto inputTouchOverlayCallback = [this, inputTouchOverlay, touchOverlaySize,
|
2024-01-29 21:37:45 +00:00
|
|
|
touchOverlayOpacity, touchOverlayFadeTime]() {
|
2024-01-14 12:06:33 +00:00
|
|
|
if (!inputTouchOverlay->getState()) {
|
|
|
|
const std::string message {
|
2024-07-12 21:02:36 +00:00
|
|
|
_("DON'T DISABLE THE TOUCH OVERLAY UNLESS YOU ARE USING A CONTROLLER OR YOU WILL "
|
|
|
|
"LOCK YOURSELF OUT OF THE APP. IF THIS HAPPENS YOU WILL NEED TO TEMPORARILY "
|
|
|
|
"PLUG IN A CONTROLLER OR A KEYBOARD TO ENABLE THIS SETTING AGAIN, OR YOU "
|
|
|
|
"COULD CLEAR THE ES-DE STORAGE IN THE ANDROID APP SETTINGS TO FORCE THE "
|
|
|
|
"CONFIGURATOR TO RUN ON NEXT STARTUP")};
|
2024-01-14 12:06:33 +00:00
|
|
|
|
|
|
|
Window* window {mWindow};
|
|
|
|
window->pushGui(
|
2024-07-13 10:32:16 +00:00
|
|
|
new GuiMsgBox(getHelpStyle(), message, _("OK"), nullptr, "", nullptr, "", nullptr,
|
2024-01-14 12:06:33 +00:00
|
|
|
nullptr, true, true,
|
|
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
|
|
0.84f :
|
|
|
|
0.54f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
|
|
|
}
|
|
|
|
|
2024-01-14 11:36:21 +00:00
|
|
|
if (touchOverlaySize->getEnabled()) {
|
|
|
|
touchOverlaySize->setEnabled(false);
|
|
|
|
touchOverlaySize->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlaySize->getParent()
|
|
|
|
->getChild(touchOverlaySize->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
2024-01-14 20:55:09 +00:00
|
|
|
|
2024-01-29 21:37:45 +00:00
|
|
|
touchOverlayOpacity->setEnabled(false);
|
|
|
|
touchOverlayOpacity->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlayOpacity->getParent()
|
|
|
|
->getChild(touchOverlayOpacity->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
|
2024-01-14 20:55:09 +00:00
|
|
|
touchOverlayFadeTime->setEnabled(false);
|
|
|
|
touchOverlayFadeTime->setOpacity(DISABLED_OPACITY);
|
|
|
|
touchOverlayFadeTime->getParent()
|
|
|
|
->getChild(touchOverlayFadeTime->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
2024-01-14 11:36:21 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
touchOverlaySize->setEnabled(true);
|
|
|
|
touchOverlaySize->setOpacity(1.0f);
|
|
|
|
touchOverlaySize->getParent()
|
|
|
|
->getChild(touchOverlaySize->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
2024-01-14 20:55:09 +00:00
|
|
|
|
2024-01-29 21:37:45 +00:00
|
|
|
touchOverlayOpacity->setEnabled(true);
|
|
|
|
touchOverlayOpacity->setOpacity(1.0f);
|
|
|
|
touchOverlayOpacity->getParent()
|
|
|
|
->getChild(touchOverlayOpacity->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
|
2024-01-14 20:55:09 +00:00
|
|
|
touchOverlayFadeTime->setEnabled(true);
|
|
|
|
touchOverlayFadeTime->setOpacity(1.0f);
|
|
|
|
touchOverlayFadeTime->getParent()
|
|
|
|
->getChild(touchOverlayFadeTime->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
2024-01-14 11:36:21 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
inputTouchOverlay->setCallback(inputTouchOverlayCallback);
|
2024-01-13 15:14:46 +00:00
|
|
|
#endif
|
|
|
|
|
2021-05-23 09:45:45 +00:00
|
|
|
// Whether to only accept input from the first controller.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto inputOnlyFirstController = std::make_shared<SwitchComponent>();
|
|
|
|
inputOnlyFirstController->setState(
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("InputOnlyFirstController"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("ONLY ACCEPT INPUT FROM FIRST CONTROLLER"), inputOnlyFirstController);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([inputOnlyFirstController, s] {
|
2021-05-23 09:45:45 +00:00
|
|
|
if (Settings::getInstance()->getBool("InputOnlyFirstController") !=
|
2022-09-03 10:44:49 +00:00
|
|
|
inputOnlyFirstController->getState()) {
|
2021-05-23 09:45:45 +00:00
|
|
|
Settings::getInstance()->setBool("InputOnlyFirstController",
|
2022-09-03 10:44:49 +00:00
|
|
|
inputOnlyFirstController->getState());
|
2021-05-23 09:45:45 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-01-17 21:31:10 +00:00
|
|
|
// Whether to swap the A/B and X/Y buttons.
|
|
|
|
auto inputSwapButtons = std::make_shared<SwitchComponent>();
|
|
|
|
inputSwapButtons->setState(Settings::getInstance()->getBool("InputSwapButtons"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("SWAP THE A/B AND X/Y BUTTONS"), inputSwapButtons);
|
2024-01-17 21:31:10 +00:00
|
|
|
s->addSaveFunc([inputSwapButtons, s] {
|
|
|
|
if (Settings::getInstance()->getBool("InputSwapButtons") != inputSwapButtons->getState()) {
|
|
|
|
Settings::getInstance()->setBool("InputSwapButtons", inputSwapButtons->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-09-19 17:05:06 +00:00
|
|
|
// Whether to ignore keyboard input (except the quit shortcut).
|
|
|
|
auto inputIgnoreKeyboard = std::make_shared<SwitchComponent>();
|
|
|
|
inputIgnoreKeyboard->setState(Settings::getInstance()->getBool("InputIgnoreKeyboard"));
|
2024-07-12 21:02:36 +00:00
|
|
|
s->addWithLabel(_("IGNORE KEYBOARD INPUT"), inputIgnoreKeyboard);
|
2022-09-19 17:05:06 +00:00
|
|
|
s->addSaveFunc([inputIgnoreKeyboard, s] {
|
|
|
|
if (Settings::getInstance()->getBool("InputIgnoreKeyboard") !=
|
|
|
|
inputIgnoreKeyboard->getState()) {
|
|
|
|
Settings::getInstance()->setBool("InputIgnoreKeyboard",
|
|
|
|
inputIgnoreKeyboard->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-05-23 08:35:59 +00:00
|
|
|
// Configure keyboard and controllers.
|
2022-09-03 10:44:49 +00:00
|
|
|
ComponentListRow configureInputRow;
|
|
|
|
configureInputRow.elements.clear();
|
|
|
|
configureInputRow.addElement(
|
2024-07-12 21:02:36 +00:00
|
|
|
std::make_shared<TextComponent>(_("CONFIGURE KEYBOARD AND CONTROLLERS"),
|
2023-05-07 20:56:24 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary),
|
2021-07-07 18:03:42 +00:00
|
|
|
true);
|
2023-05-07 20:56:24 +00:00
|
|
|
configureInputRow.addElement(mMenu.makeArrow(), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
configureInputRow.makeAcceptInputHandler(std::bind(&GuiMenu::openConfigInput, this, s));
|
|
|
|
s->addRow(configureInputRow);
|
2021-05-23 08:35:59 +00:00
|
|
|
|
2021-10-24 12:11:19 +00:00
|
|
|
s->setSize(mSize);
|
2021-05-23 08:35:59 +00:00
|
|
|
mWindow->pushGui(s);
|
|
|
|
}
|
|
|
|
|
2021-06-28 16:12:08 +00:00
|
|
|
void GuiMenu::openConfigInput(GuiSettings* settings)
|
2021-05-23 08:35:59 +00:00
|
|
|
{
|
2021-06-28 16:12:08 +00:00
|
|
|
// Always save the settings before starting the input configuration, in case the
|
|
|
|
// controller type was changed.
|
|
|
|
settings->save();
|
|
|
|
// Also unset the save flag so that a double saving does not take place when closing
|
|
|
|
// the input device settings menu later on.
|
|
|
|
settings->setNeedsSaving(false);
|
|
|
|
|
2023-09-10 12:09:39 +00:00
|
|
|
std::string message {
|
2024-07-12 21:02:36 +00:00
|
|
|
_("THE KEYBOARD AND CONTROLLERS ARE AUTOMATICALLY CONFIGURED, BUT USING THIS "
|
2024-07-14 21:46:33 +00:00
|
|
|
"TOOL YOU CAN OVERRIDE THE DEFAULT BUTTON MAPPINGS (THIS WILL NOT AFFECT THE HELP "
|
|
|
|
"PROMPTS)")};
|
2021-05-23 08:35:59 +00:00
|
|
|
|
2022-01-19 17:01:54 +00:00
|
|
|
Window* window {mWindow};
|
2021-07-07 18:03:42 +00:00
|
|
|
window->pushGui(new GuiMsgBox(
|
2024-07-12 21:02:36 +00:00
|
|
|
getHelpStyle(), message, _("PROCEED"),
|
|
|
|
[window] { window->pushGui(new GuiDetectDevice(false, false, nullptr)); }, _("CANCEL"),
|
2023-09-17 09:47:58 +00:00
|
|
|
nullptr, "", nullptr, nullptr, false, true,
|
2023-09-10 12:09:39 +00:00
|
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
|
|
0.84f :
|
|
|
|
0.54f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
2021-05-23 08:35:59 +00:00
|
|
|
}
|
|
|
|
|
2021-05-22 20:48:44 +00:00
|
|
|
void GuiMenu::openOtherOptions()
|
2017-09-08 14:49:47 +00:00
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("OTHER SETTINGS"));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-08-22 13:26:38 +00:00
|
|
|
// Alternative emulators GUI.
|
|
|
|
ComponentListRow alternativeEmulatorsRow;
|
|
|
|
alternativeEmulatorsRow.elements.clear();
|
2024-07-13 10:32:16 +00:00
|
|
|
alternativeEmulatorsRow.addElement(std::make_shared<TextComponent>(_("ALTERNATIVE EMULATORS"),
|
2022-01-19 17:01:54 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM),
|
2023-05-07 20:56:24 +00:00
|
|
|
mMenuColorPrimary),
|
2022-01-19 17:01:54 +00:00
|
|
|
true);
|
2023-05-07 20:56:24 +00:00
|
|
|
alternativeEmulatorsRow.addElement(mMenu.makeArrow(), false);
|
2021-08-22 13:26:38 +00:00
|
|
|
alternativeEmulatorsRow.makeAcceptInputHandler(
|
2022-01-19 17:01:54 +00:00
|
|
|
std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); }));
|
2021-08-22 13:26:38 +00:00
|
|
|
s->addRow(alternativeEmulatorsRow);
|
|
|
|
|
2021-08-22 12:29:43 +00:00
|
|
|
// Game media directory.
|
|
|
|
ComponentListRow rowMediaDir;
|
2023-05-07 20:56:24 +00:00
|
|
|
auto mediaDirectory = std::make_shared<TextComponent>(
|
2024-07-13 10:32:16 +00:00
|
|
|
_("GAME MEDIA DIRECTORY"), Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary);
|
2022-01-19 17:01:54 +00:00
|
|
|
auto bracketMediaDirectory = std::make_shared<ImageComponent>();
|
2021-08-22 12:29:43 +00:00
|
|
|
bracketMediaDirectory->setResize(
|
2022-01-16 11:09:55 +00:00
|
|
|
glm::vec2 {0.0f, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()});
|
2022-08-30 18:26:48 +00:00
|
|
|
bracketMediaDirectory->setImage(":/graphics/arrow.svg");
|
2023-05-07 20:56:24 +00:00
|
|
|
bracketMediaDirectory->setColorShift(mMenuColorPrimary);
|
2022-09-03 10:44:49 +00:00
|
|
|
rowMediaDir.addElement(mediaDirectory, true);
|
2021-08-22 12:29:43 +00:00
|
|
|
rowMediaDir.addElement(bracketMediaDirectory, false);
|
2024-07-13 10:32:16 +00:00
|
|
|
std::string titleMediaDir {_("ENTER GAME MEDIA DIRECTORY")};
|
|
|
|
std::string mediaDirectoryStaticText {_("Default directory:")};
|
2023-12-19 16:35:58 +00:00
|
|
|
std::string defaultDirectoryText {Utils::FileSystem::getAppDataDirectory() +
|
|
|
|
"/downloaded_media"};
|
2022-09-03 10:44:49 +00:00
|
|
|
std::string initValueMediaDir {Settings::getInstance()->getString("MediaDirectory")};
|
|
|
|
bool multiLineMediaDir {false};
|
2021-08-22 12:29:43 +00:00
|
|
|
auto updateValMediaDir = [this](const std::string& newVal) {
|
|
|
|
Settings::getInstance()->setString("MediaDirectory", newVal);
|
|
|
|
Settings::getInstance()->saveFile();
|
2022-01-04 20:49:22 +00:00
|
|
|
ViewController::getInstance()->reloadAll();
|
2021-08-22 12:29:43 +00:00
|
|
|
mWindow->invalidateCachedBackground();
|
|
|
|
};
|
2023-02-09 23:25:22 +00:00
|
|
|
rowMediaDir.makeAcceptInputHandler([this, s, titleMediaDir, mediaDirectoryStaticText,
|
2021-08-22 12:29:43 +00:00
|
|
|
defaultDirectoryText, initValueMediaDir, updateValMediaDir,
|
|
|
|
multiLineMediaDir] {
|
2021-09-17 20:23:41 +00:00
|
|
|
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
|
|
|
|
mWindow->pushGui(new GuiTextEditKeyboardPopup(
|
2023-02-09 23:25:22 +00:00
|
|
|
getHelpStyle(), s->getMenu().getPosition().y, titleMediaDir,
|
|
|
|
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
2024-07-13 10:32:16 +00:00
|
|
|
multiLineMediaDir, _("SAVE"), _("SAVE CHANGES?"), mediaDirectoryStaticText,
|
|
|
|
defaultDirectoryText, _("load default directory")));
|
2021-09-17 20:23:41 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mWindow->pushGui(new GuiTextEditPopup(
|
2022-01-19 17:01:54 +00:00
|
|
|
getHelpStyle(), titleMediaDir, Settings::getInstance()->getString("MediaDirectory"),
|
2024-07-13 10:32:16 +00:00
|
|
|
updateValMediaDir, multiLineMediaDir, _("SAVE"), _("SAVE CHANGES?"),
|
|
|
|
mediaDirectoryStaticText, defaultDirectoryText, _("load default directory")));
|
2021-09-17 20:23:41 +00:00
|
|
|
}
|
2021-08-22 12:29:43 +00:00
|
|
|
});
|
|
|
|
s->addRow(rowMediaDir);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Maximum VRAM.
|
2022-10-30 08:11:59 +00:00
|
|
|
auto maxVram = std::make_shared<SliderComponent>(128.0f, 2048.0f, 16.0f, "MiB");
|
2022-09-03 10:44:49 +00:00
|
|
|
maxVram->setValue(static_cast<float>(Settings::getInstance()->getInt("MaxVRAM")));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("VRAM LIMIT"), maxVram);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([maxVram, s] {
|
|
|
|
if (maxVram->getValue() != Settings::getInstance()->getInt("MaxVRAM")) {
|
2020-11-05 17:18:11 +00:00
|
|
|
Settings::getInstance()->setInt("MaxVRAM",
|
2022-09-03 10:44:49 +00:00
|
|
|
static_cast<int>(std::round(maxVram->getValue())));
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2023-01-09 16:55:54 +00:00
|
|
|
#if !defined(USE_OPENGLES)
|
|
|
|
// Anti-aliasing (MSAA).
|
|
|
|
auto antiAliasing = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-13 10:32:16 +00:00
|
|
|
getHelpStyle(), _("ANTI-ALIASING (MSAA)"), false);
|
2023-01-09 16:55:54 +00:00
|
|
|
const std::string& selectedAntiAliasing {
|
|
|
|
std::to_string(Settings::getInstance()->getInt("AntiAliasing"))};
|
2024-07-13 10:32:16 +00:00
|
|
|
antiAliasing->add(_("DISABLED"), "0", selectedAntiAliasing == "0");
|
|
|
|
antiAliasing->add(_("2X"), "2", selectedAntiAliasing == "2");
|
|
|
|
antiAliasing->add(_("4X"), "4", selectedAntiAliasing == "4");
|
2023-01-09 16:55:54 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set anti-aliasing to "0" in this case.
|
|
|
|
if (antiAliasing->getSelectedObjects().size() == 0)
|
|
|
|
antiAliasing->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ANTI-ALIASING (MSAA) (REQUIRES RESTART)"), antiAliasing);
|
2023-01-10 21:11:38 +00:00
|
|
|
s->addSaveFunc([antiAliasing, s] {
|
2023-01-09 16:55:54 +00:00
|
|
|
if (antiAliasing->getSelected() !=
|
|
|
|
std::to_string(Settings::getInstance()->getInt("AntiAliasing"))) {
|
|
|
|
Settings::getInstance()->setInt("AntiAliasing",
|
|
|
|
atoi(antiAliasing->getSelected().c_str()));
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
#endif
|
|
|
|
|
2021-01-24 22:44:50 +00:00
|
|
|
// Display/monitor.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto displayIndex = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-13 10:32:16 +00:00
|
|
|
getHelpStyle(), _("DISPLAY/MONITOR INDEX"), false);
|
2022-09-03 10:44:49 +00:00
|
|
|
std::vector<std::string> displayIndexEntry;
|
|
|
|
displayIndexEntry.push_back("1");
|
|
|
|
displayIndexEntry.push_back("2");
|
|
|
|
displayIndexEntry.push_back("3");
|
|
|
|
displayIndexEntry.push_back("4");
|
|
|
|
for (auto it = displayIndexEntry.cbegin(); it != displayIndexEntry.cend(); ++it)
|
|
|
|
displayIndex->add(*it, *it,
|
|
|
|
Settings::getInstance()->getInt("DisplayIndex") == atoi((*it).c_str()));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("DISPLAY/MONITOR INDEX (REQUIRES RESTART)"), displayIndex);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([displayIndex, s] {
|
|
|
|
if (atoi(displayIndex->getSelected().c_str()) !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getInt("DisplayIndex")) {
|
2021-01-24 22:44:50 +00:00
|
|
|
Settings::getInstance()->setInt("DisplayIndex",
|
2022-09-03 10:44:49 +00:00
|
|
|
atoi(displayIndex->getSelected().c_str()));
|
2021-01-24 22:44:50 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
// Screen contents rotation.
|
2024-07-13 10:32:16 +00:00
|
|
|
auto screenRotate = std::make_shared<OptionListComponent<std::string>>(
|
|
|
|
getHelpStyle(), _("ROTATE SCREEN"), false);
|
2023-02-06 22:38:35 +00:00
|
|
|
const std::string& selectedScreenRotate {
|
|
|
|
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))};
|
2024-07-13 10:32:16 +00:00
|
|
|
screenRotate->add(_("DISABLED"), "0", selectedScreenRotate == "0");
|
|
|
|
screenRotate->add(_("90 DEGREES"), "90", selectedScreenRotate == "90");
|
|
|
|
screenRotate->add(_("180 DEGREES"), "180", selectedScreenRotate == "180");
|
|
|
|
screenRotate->add(_("270 DEGREES"), "270", selectedScreenRotate == "270");
|
2023-02-06 22:38:35 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set screen rotation to "0" in this case.
|
|
|
|
if (screenRotate->getSelectedObjects().size() == 0)
|
|
|
|
screenRotate->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ROTATE SCREEN (REQUIRES RESTART)"), screenRotate);
|
2023-02-06 22:38:35 +00:00
|
|
|
s->addSaveFunc([screenRotate, s] {
|
|
|
|
if (screenRotate->getSelected() !=
|
|
|
|
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))) {
|
|
|
|
Settings::getInstance()->setInt("ScreenRotate",
|
|
|
|
atoi(screenRotate->getSelected().c_str()));
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-05-31 20:06:47 +00:00
|
|
|
// Keyboard quit shortcut.
|
|
|
|
auto keyboardQuitShortcut = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-13 10:32:16 +00:00
|
|
|
getHelpStyle(), _("KEYBOARD QUIT SHORTCUT"), false);
|
2022-05-31 20:06:47 +00:00
|
|
|
std::string selectedShortcut {Settings::getInstance()->getString("KeyboardQuitShortcut")};
|
2021-08-11 10:09:58 +00:00
|
|
|
#if defined(_WIN64) || defined(__unix__)
|
2024-07-13 10:32:16 +00:00
|
|
|
keyboardQuitShortcut->add("ALT + F4", "AltF4", selectedShortcut == "AltF4");
|
|
|
|
keyboardQuitShortcut->add("CTRL + Q", "CtrlQ", selectedShortcut == "CtrlQ");
|
|
|
|
keyboardQuitShortcut->add("ALT + Q", "AltQ", selectedShortcut == "AltQ");
|
2021-08-11 10:09:58 +00:00
|
|
|
#endif
|
|
|
|
#if defined(__APPLE__)
|
2022-05-31 20:06:47 +00:00
|
|
|
keyboardQuitShortcut->add("\u2318 + Q", "CmdQ", selectedShortcut == "CmdQ");
|
2024-07-13 10:32:16 +00:00
|
|
|
keyboardQuitShortcut->add("CTRL + Q", "CtrlQ", selectedShortcut == "CtrlQ");
|
|
|
|
keyboardQuitShortcut->add("ALT + Q", "AltQ", selectedShortcut == "AltQ");
|
2021-08-11 10:09:58 +00:00
|
|
|
#endif
|
2022-05-31 20:06:47 +00:00
|
|
|
keyboardQuitShortcut->add("F4", "F4", selectedShortcut == "F4");
|
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set the keyboard quit shortcut to the first entry in this case.
|
|
|
|
if (keyboardQuitShortcut->getSelectedObjects().size() == 0)
|
|
|
|
keyboardQuitShortcut->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("KEYBOARD QUIT SHORTCUT"), keyboardQuitShortcut);
|
2022-05-31 20:06:47 +00:00
|
|
|
s->addSaveFunc([keyboardQuitShortcut, s] {
|
|
|
|
if (keyboardQuitShortcut->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("KeyboardQuitShortcut")) {
|
|
|
|
Settings::getInstance()->setString("KeyboardQuitShortcut",
|
|
|
|
keyboardQuitShortcut->getSelected());
|
2021-07-07 12:28:09 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// When to save game metadata.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto saveGamelistsMode = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-19 08:40:04 +00:00
|
|
|
getHelpStyle(), _("WHEN TO SAVE GAME METADATA [short]"), false);
|
2024-07-13 10:32:16 +00:00
|
|
|
saveGamelistsMode->add(_("ALWAYS"), "always",
|
|
|
|
Settings::getInstance()->getString("SaveGamelistsMode") == "always");
|
|
|
|
saveGamelistsMode->add(_("ON EXIT"), "on exit",
|
|
|
|
Settings::getInstance()->getString("SaveGamelistsMode") == "on exit");
|
|
|
|
saveGamelistsMode->add(_("NEVER"), "never",
|
|
|
|
Settings::getInstance()->getString("SaveGamelistsMode") == "never");
|
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set save game metadata to "always" in this case.
|
2024-07-14 08:39:27 +00:00
|
|
|
if (saveGamelistsMode->getSelectedObjects().size() == 0)
|
|
|
|
saveGamelistsMode->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("WHEN TO SAVE GAME METADATA"), saveGamelistsMode);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([saveGamelistsMode, s] {
|
|
|
|
if (saveGamelistsMode->getSelected() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getString("SaveGamelistsMode")) {
|
2020-10-19 15:16:57 +00:00
|
|
|
Settings::getInstance()->setString("SaveGamelistsMode",
|
2022-09-03 10:44:49 +00:00
|
|
|
saveGamelistsMode->getSelected());
|
2021-07-07 18:03:42 +00:00
|
|
|
// Always save the gamelist.xml files if switching to "always" as there may
|
2020-10-19 15:16:57 +00:00
|
|
|
// be changes that will otherwise be lost.
|
|
|
|
if (Settings::getInstance()->getString("SaveGamelistsMode") == "always") {
|
|
|
|
for (auto it = SystemData::sSystemVector.cbegin();
|
2021-11-17 16:35:34 +00:00
|
|
|
it != SystemData::sSystemVector.cend(); ++it)
|
2020-10-19 15:16:57 +00:00
|
|
|
(*it)->writeMetaData();
|
|
|
|
}
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2020-10-19 15:16:57 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
});
|
|
|
|
|
2023-02-18 11:42:19 +00:00
|
|
|
#if defined(APPLICATION_UPDATER)
|
|
|
|
// Application updater frequency.
|
|
|
|
auto applicationUpdaterFrequency = std::make_shared<OptionListComponent<std::string>>(
|
2024-07-13 10:32:16 +00:00
|
|
|
getHelpStyle(), _("APPLICATION UPDATES"), false);
|
2023-02-18 11:42:19 +00:00
|
|
|
const std::string& selectedUpdaterFrequency {
|
|
|
|
Settings::getInstance()->getString("ApplicationUpdaterFrequency")};
|
2024-07-13 10:32:16 +00:00
|
|
|
applicationUpdaterFrequency->add(_("ALWAYS"), "always", selectedUpdaterFrequency == "always");
|
|
|
|
applicationUpdaterFrequency->add(_("DAILY"), "daily", selectedUpdaterFrequency == "daily");
|
|
|
|
applicationUpdaterFrequency->add(_("WEEKLY"), "weekly", selectedUpdaterFrequency == "weekly");
|
|
|
|
applicationUpdaterFrequency->add(_("MONTHLY"), "monthly",
|
|
|
|
selectedUpdaterFrequency == "monthly");
|
|
|
|
applicationUpdaterFrequency->add(_("NEVER"), "never", selectedUpdaterFrequency == "never");
|
2023-02-18 11:42:19 +00:00
|
|
|
// If there are no objects returned, then there must be a manually modified entry in the
|
|
|
|
// configuration file. Simply set updater frequency to "always" in this case.
|
|
|
|
if (applicationUpdaterFrequency->getSelectedObjects().size() == 0)
|
|
|
|
applicationUpdaterFrequency->selectEntry(0);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("CHECK FOR APPLICATION UPDATES"), applicationUpdaterFrequency);
|
2023-02-18 11:42:19 +00:00
|
|
|
s->addSaveFunc([applicationUpdaterFrequency, s] {
|
|
|
|
if (applicationUpdaterFrequency->getSelected() !=
|
|
|
|
Settings::getInstance()->getString("ApplicationUpdaterFrequency")) {
|
|
|
|
Settings::getInstance()->setString("ApplicationUpdaterFrequency",
|
|
|
|
applicationUpdaterFrequency->getSelected());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
#endif
|
|
|
|
|
2024-02-25 11:26:32 +00:00
|
|
|
#if defined(APPLICATION_UPDATER) && !defined(__ANDROID__)
|
2023-02-21 17:26:53 +00:00
|
|
|
#if defined(IS_PRERELEASE)
|
|
|
|
// Add a dummy entry to indicate that this setting is always enabled when running a prerelease.
|
|
|
|
auto applicationUpdaterPrereleases = std::make_shared<SwitchComponent>();
|
|
|
|
applicationUpdaterPrereleases->setState(true);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("INCLUDE PRERELEASES IN UPDATE CHECKS"), applicationUpdaterPrereleases);
|
2023-02-21 17:26:53 +00:00
|
|
|
applicationUpdaterPrereleases->setEnabled(false);
|
|
|
|
applicationUpdaterPrereleases->setOpacity(DISABLED_OPACITY);
|
|
|
|
applicationUpdaterPrereleases->getParent()
|
|
|
|
->getChild(applicationUpdaterPrereleases->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
#else
|
2023-02-18 11:42:19 +00:00
|
|
|
// Whether to include prereleases when checking for application updates.
|
|
|
|
auto applicationUpdaterPrereleases = std::make_shared<SwitchComponent>();
|
|
|
|
applicationUpdaterPrereleases->setState(
|
|
|
|
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("INCLUDE PRERELEASES IN UPDATE CHECKS"), applicationUpdaterPrereleases);
|
2023-02-18 11:42:19 +00:00
|
|
|
s->addSaveFunc([applicationUpdaterPrereleases, s] {
|
|
|
|
if (applicationUpdaterPrereleases->getState() !=
|
|
|
|
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases")) {
|
|
|
|
Settings::getInstance()->setBool("ApplicationUpdaterPrereleases",
|
|
|
|
applicationUpdaterPrereleases->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
#endif
|
2023-02-21 17:26:53 +00:00
|
|
|
#endif
|
2023-02-18 11:42:19 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(_WIN64)
|
2021-11-12 18:49:24 +00:00
|
|
|
// Hide taskbar during the program session.
|
2022-01-19 17:01:54 +00:00
|
|
|
auto hide_taskbar = std::make_shared<SwitchComponent>();
|
2020-07-18 11:21:44 +00:00
|
|
|
hide_taskbar->setState(Settings::getInstance()->getBool("HideTaskbar"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("HIDE TASKBAR (REQUIRES RESTART)"), hide_taskbar);
|
2020-11-05 17:18:11 +00:00
|
|
|
s->addSaveFunc([hide_taskbar, s] {
|
2021-07-07 18:03:42 +00:00
|
|
|
if (hide_taskbar->getState() != Settings::getInstance()->getBool("HideTaskbar")) {
|
|
|
|
Settings::getInstance()->setBool("HideTaskbar", hide_taskbar->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-07-19 20:08:14 +00:00
|
|
|
|
2024-05-19 17:09:04 +00:00
|
|
|
#if !defined(__ANDROID__) && !defined(DEINIT_ON_LAUNCH)
|
2020-07-19 20:08:14 +00:00
|
|
|
// Run ES in the background when a game has been launched.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto runInBackground = std::make_shared<SwitchComponent>();
|
|
|
|
runInBackground->setState(Settings::getInstance()->getBool("RunInBackground"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("RUN IN BACKGROUND (WHILE GAME IS LAUNCHED)"), runInBackground);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([runInBackground, s] {
|
|
|
|
if (runInBackground->getState() != Settings::getInstance()->getBool("RunInBackground")) {
|
|
|
|
Settings::getInstance()->setBool("RunInBackground", runInBackground->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2023-12-23 22:14:25 +00:00
|
|
|
#endif
|
2020-07-18 11:21:44 +00:00
|
|
|
|
2021-11-07 22:54:52 +00:00
|
|
|
#if defined(VIDEO_HW_DECODING)
|
2021-07-14 17:13:25 +00:00
|
|
|
// Whether to enable hardware decoding for the FFmpeg video player.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto videoHardwareDecoding = std::make_shared<SwitchComponent>();
|
|
|
|
videoHardwareDecoding->setState(Settings::getInstance()->getBool("VideoHardwareDecoding"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("VIDEO HARDWARE DECODING (EXPERIMENTAL)"), videoHardwareDecoding);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([videoHardwareDecoding, s] {
|
|
|
|
if (videoHardwareDecoding->getState() !=
|
2021-07-14 17:13:25 +00:00
|
|
|
Settings::getInstance()->getBool("VideoHardwareDecoding")) {
|
|
|
|
Settings::getInstance()->setBool("VideoHardwareDecoding",
|
2022-09-03 10:44:49 +00:00
|
|
|
videoHardwareDecoding->getState());
|
2021-07-14 17:13:25 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
#endif
|
2021-06-30 16:08:13 +00:00
|
|
|
|
2021-05-29 08:55:40 +00:00
|
|
|
// Whether to upscale the video frame rate to 60 FPS.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto videoUpscaleFrameRate = std::make_shared<SwitchComponent>();
|
|
|
|
videoUpscaleFrameRate->setState(Settings::getInstance()->getBool("VideoUpscaleFrameRate"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("UPSCALE VIDEO FRAME RATE TO 60 FPS"), videoUpscaleFrameRate);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([videoUpscaleFrameRate, s] {
|
|
|
|
if (videoUpscaleFrameRate->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("VideoUpscaleFrameRate")) {
|
|
|
|
Settings::getInstance()->setBool("VideoUpscaleFrameRate",
|
2022-09-03 10:44:49 +00:00
|
|
|
videoUpscaleFrameRate->getState());
|
2021-05-29 08:55:40 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-04 09:21:55 +00:00
|
|
|
// Whether to enable alternative emulators per game (the option to disable this is intended
|
|
|
|
// primarily for testing purposes).
|
2022-01-19 17:01:54 +00:00
|
|
|
auto alternativeEmulatorPerGame = std::make_shared<SwitchComponent>();
|
2021-09-04 09:21:55 +00:00
|
|
|
alternativeEmulatorPerGame->setState(
|
|
|
|
Settings::getInstance()->getBool("AlternativeEmulatorPerGame"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ENABLE ALTERNATIVE EMULATORS PER GAME"), alternativeEmulatorPerGame);
|
2021-09-04 09:21:55 +00:00
|
|
|
s->addSaveFunc([alternativeEmulatorPerGame, s] {
|
|
|
|
if (alternativeEmulatorPerGame->getState() !=
|
|
|
|
Settings::getInstance()->getBool("AlternativeEmulatorPerGame")) {
|
|
|
|
Settings::getInstance()->setBool("AlternativeEmulatorPerGame",
|
|
|
|
alternativeEmulatorPerGame->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2021-11-10 21:38:25 +00:00
|
|
|
s->setNeedsReloading();
|
|
|
|
s->setInvalidateCachedBackground();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// Show hidden files.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto showHiddenFiles = std::make_shared<SwitchComponent>();
|
|
|
|
showHiddenFiles->setState(Settings::getInstance()->getBool("ShowHiddenFiles"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("SHOW HIDDEN FILES AND FOLDERS"), showHiddenFiles);
|
2023-08-14 17:10:16 +00:00
|
|
|
s->addSaveFunc([this, showHiddenFiles, s] {
|
2022-09-03 10:44:49 +00:00
|
|
|
if (showHiddenFiles->getState() != Settings::getInstance()->getBool("ShowHiddenFiles")) {
|
|
|
|
Settings::getInstance()->setBool("ShowHiddenFiles", showHiddenFiles->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2023-08-14 17:10:16 +00:00
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
s->setNeedsRescanROMDirectory();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
|
|
|
});
|
2020-07-26 20:19:29 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// Show hidden games.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto showHiddenGames = std::make_shared<SwitchComponent>();
|
|
|
|
showHiddenGames->setState(Settings::getInstance()->getBool("ShowHiddenGames"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("SHOW HIDDEN GAMES"), showHiddenGames);
|
2023-08-14 17:10:16 +00:00
|
|
|
s->addSaveFunc([this, showHiddenGames, s] {
|
2022-09-03 10:44:49 +00:00
|
|
|
if (showHiddenGames->getState() != Settings::getInstance()->getBool("ShowHiddenGames")) {
|
|
|
|
Settings::getInstance()->setBool("ShowHiddenGames", showHiddenGames->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2023-08-14 17:10:16 +00:00
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
s->setNeedsRescanROMDirectory();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
2020-07-26 20:19:29 +00:00
|
|
|
});
|
|
|
|
|
2020-07-15 16:02:11 +00:00
|
|
|
// Custom event scripts, fired using Scripting::fireEvent().
|
2022-09-03 10:44:49 +00:00
|
|
|
auto customEventScripts = std::make_shared<SwitchComponent>();
|
|
|
|
customEventScripts->setState(Settings::getInstance()->getBool("CustomEventScripts"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ENABLE CUSTOM EVENT SCRIPTS"), customEventScripts);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([customEventScripts, s] {
|
|
|
|
if (customEventScripts->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("CustomEventScripts")) {
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setBool("CustomEventScripts", customEventScripts->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-08-14 21:22:50 +00:00
|
|
|
// Only show games included in the gamelist.xml files.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto parseGamelistOnly = std::make_shared<SwitchComponent>();
|
|
|
|
parseGamelistOnly->setState(Settings::getInstance()->getBool("ParseGamelistOnly"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ONLY SHOW GAMES FROM GAMELIST.XML FILES"), parseGamelistOnly);
|
2023-08-14 17:10:16 +00:00
|
|
|
s->addSaveFunc([this, parseGamelistOnly, s] {
|
2022-09-03 10:44:49 +00:00
|
|
|
if (parseGamelistOnly->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("ParseGamelistOnly")) {
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setBool("ParseGamelistOnly", parseGamelistOnly->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
2023-08-14 17:10:16 +00:00
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
|
|
|
s->setNeedsRescanROMDirectory();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-02-14 16:28:43 +00:00
|
|
|
// Strip extra MAME name info.
|
|
|
|
auto mameNameStripExtraInfo = std::make_shared<SwitchComponent>();
|
|
|
|
mameNameStripExtraInfo->setState(Settings::getInstance()->getBool("MAMENameStripExtraInfo"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("STRIP EXTRA MAME NAME INFO (REQUIRES RESTART)"), mameNameStripExtraInfo);
|
2023-02-14 16:28:43 +00:00
|
|
|
s->addSaveFunc([mameNameStripExtraInfo, s] {
|
|
|
|
if (Settings::getInstance()->getBool("MAMENameStripExtraInfo") !=
|
|
|
|
mameNameStripExtraInfo->getState()) {
|
|
|
|
Settings::getInstance()->setBool("MAMENameStripExtraInfo",
|
|
|
|
mameNameStripExtraInfo->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-12-23 23:37:42 +00:00
|
|
|
#if defined(__unix__) && !defined(__ANDROID__)
|
2021-02-22 20:13:06 +00:00
|
|
|
// Whether to disable desktop composition.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto disableComposition = std::make_shared<SwitchComponent>();
|
|
|
|
disableComposition->setState(Settings::getInstance()->getBool("DisableComposition"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("DISABLE DESKTOP COMPOSITION (REQUIRES RESTART)"), disableComposition);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([disableComposition, s] {
|
|
|
|
if (disableComposition->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("DisableComposition")) {
|
2022-09-03 10:44:49 +00:00
|
|
|
Settings::getInstance()->setBool("DisableComposition", disableComposition->getState());
|
2021-02-22 20:13:06 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2021-02-22 20:13:06 +00:00
|
|
|
|
2024-04-08 20:07:52 +00:00
|
|
|
#if defined(__ANDROID__)
|
2024-05-20 17:49:28 +00:00
|
|
|
if (!AndroidVariables::sIsHomeApp) {
|
|
|
|
// Whether swiping or pressing back should exit the application.
|
|
|
|
auto backEventAppExit = std::make_shared<SwitchComponent>();
|
|
|
|
backEventAppExit->setState(Settings::getInstance()->getBool("BackEventAppExit"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("BACK BUTTON/BACK SWIPE EXITS APP"), backEventAppExit);
|
2024-05-20 17:49:28 +00:00
|
|
|
s->addSaveFunc([backEventAppExit, s] {
|
|
|
|
if (backEventAppExit->getState() !=
|
|
|
|
Settings::getInstance()->getBool("BackEventAppExit")) {
|
|
|
|
Settings::getInstance()->setBool("BackEventAppExit", backEventAppExit->getState());
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If we're running as the Android home app then we don't allow the application to quit,
|
|
|
|
// so simply add a disabled dummy switch in this case.
|
|
|
|
auto backEventAppExit = std::make_shared<SwitchComponent>();
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("BACK BUTTON/BACK SWIPE EXITS APP"), backEventAppExit);
|
2024-05-20 17:49:28 +00:00
|
|
|
backEventAppExit->setEnabled(false);
|
|
|
|
backEventAppExit->setState(false);
|
|
|
|
backEventAppExit->setOpacity(DISABLED_OPACITY);
|
|
|
|
backEventAppExit->getParent()
|
|
|
|
->getChild(backEventAppExit->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
2024-04-08 20:07:52 +00:00
|
|
|
#endif
|
|
|
|
|
2023-10-02 17:59:13 +00:00
|
|
|
if (Settings::getInstance()->getBool("DebugFlag")) {
|
|
|
|
// If the --debug command line option was passed then create a dummy entry.
|
|
|
|
auto debugMode = std::make_shared<SwitchComponent>();
|
|
|
|
debugMode->setState(true);
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("DEBUG MODE"), debugMode);
|
2023-10-02 17:59:13 +00:00
|
|
|
debugMode->setEnabled(false);
|
|
|
|
debugMode->setOpacity(DISABLED_OPACITY);
|
|
|
|
debugMode->getParent()
|
|
|
|
->getChild(debugMode->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Debug mode.
|
|
|
|
auto debugMode = std::make_shared<SwitchComponent>();
|
|
|
|
debugMode->setState(Settings::getInstance()->getBool("DebugMode"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("DEBUG MODE"), debugMode);
|
2023-10-02 17:59:13 +00:00
|
|
|
s->addSaveFunc([debugMode, s] {
|
|
|
|
if (debugMode->getState() != Settings::getInstance()->getBool("DebugMode")) {
|
|
|
|
if (!Settings::getInstance()->getBool("DebugMode")) {
|
|
|
|
Settings::getInstance()->setBool("DebugMode", true);
|
|
|
|
Settings::getInstance()->setBool("Debug", true);
|
|
|
|
Log::setReportingLevel(LogDebug);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Settings::getInstance()->setBool("DebugMode", false);
|
|
|
|
Settings::getInstance()->setBool("Debug", false);
|
|
|
|
Log::setReportingLevel(LogInfo);
|
|
|
|
}
|
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
// GPU statistics overlay.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto displayGpuStatistics = std::make_shared<SwitchComponent>();
|
|
|
|
displayGpuStatistics->setState(Settings::getInstance()->getBool("DisplayGPUStatistics"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("DISPLAY GPU STATISTICS OVERLAY"), displayGpuStatistics);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([displayGpuStatistics, s] {
|
|
|
|
if (displayGpuStatistics->getState() !=
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("DisplayGPUStatistics")) {
|
2020-11-05 17:18:11 +00:00
|
|
|
Settings::getInstance()->setBool("DisplayGPUStatistics",
|
2022-09-03 10:44:49 +00:00
|
|
|
displayGpuStatistics->getState());
|
2020-11-05 17:18:11 +00:00
|
|
|
s->setNeedsSaving();
|
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-12-17 22:45:29 +00:00
|
|
|
// Whether to enable the menu in Kid mode.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto enableMenuKidMode = std::make_shared<SwitchComponent>();
|
|
|
|
enableMenuKidMode->setState(Settings::getInstance()->getBool("EnableMenuKidMode"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("ENABLE MENU IN KID MODE"), enableMenuKidMode);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([enableMenuKidMode, s] {
|
2020-12-17 22:45:29 +00:00
|
|
|
if (Settings::getInstance()->getBool("EnableMenuKidMode") !=
|
2022-09-03 10:44:49 +00:00
|
|
|
enableMenuKidMode->getState()) {
|
|
|
|
Settings::getInstance()->setBool("EnableMenuKidMode", enableMenuKidMode->getState());
|
2020-12-17 22:45:29 +00:00
|
|
|
s->setNeedsSaving();
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
// macOS requires root privileges to reboot and power off so it doesn't make much
|
|
|
|
// sense to enable this setting and menu entry for that operating system.
|
2023-12-23 22:28:22 +00:00
|
|
|
#if !defined(__APPLE__) && !defined(__ANDROID__)
|
2020-12-17 22:45:29 +00:00
|
|
|
// Whether to show the quit menu with the options to reboot and shutdown the computer.
|
2022-09-03 10:44:49 +00:00
|
|
|
auto showQuitMenu = std::make_shared<SwitchComponent>();
|
|
|
|
showQuitMenu->setState(Settings::getInstance()->getBool("ShowQuitMenu"));
|
2024-07-13 10:32:16 +00:00
|
|
|
s->addWithLabel(_("SHOW QUIT MENU (REBOOT AND POWER OFF ENTRIES)"), showQuitMenu);
|
2022-09-03 10:44:49 +00:00
|
|
|
s->addSaveFunc([this, showQuitMenu, s] {
|
|
|
|
if (showQuitMenu->getState() != Settings::getInstance()->getBool("ShowQuitMenu")) {
|
|
|
|
Settings::getInstance()->setBool("ShowQuitMenu", showQuitMenu->getState());
|
2020-12-17 22:45:29 +00:00
|
|
|
s->setNeedsSaving();
|
2023-08-13 22:02:20 +00:00
|
|
|
s->setNeedsCloseMenu([this] { delete this; });
|
2020-11-05 17:18:11 +00:00
|
|
|
}
|
|
|
|
});
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2024-02-25 11:26:32 +00:00
|
|
|
#if defined(APPLICATION_UPDATER) && !defined(__ANDROID__) && !defined(IS_PRERELEASE)
|
2023-02-20 16:49:46 +00:00
|
|
|
auto applicationUpdaterFrequencyFunc =
|
|
|
|
[applicationUpdaterPrereleases](const std::string& frequency) {
|
|
|
|
if (frequency == "never") {
|
|
|
|
applicationUpdaterPrereleases->setEnabled(false);
|
|
|
|
applicationUpdaterPrereleases->setOpacity(DISABLED_OPACITY);
|
|
|
|
applicationUpdaterPrereleases->getParent()
|
|
|
|
->getChild(applicationUpdaterPrereleases->getChildIndex() - 1)
|
|
|
|
->setOpacity(DISABLED_OPACITY);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
applicationUpdaterPrereleases->setEnabled(true);
|
|
|
|
applicationUpdaterPrereleases->setOpacity(1.0f);
|
|
|
|
applicationUpdaterPrereleases->getParent()
|
|
|
|
->getChild(applicationUpdaterPrereleases->getChildIndex() - 1)
|
|
|
|
->setOpacity(1.0f);
|
|
|
|
}
|
|
|
|
};
|
2023-02-18 11:42:19 +00:00
|
|
|
|
2023-02-20 16:49:46 +00:00
|
|
|
applicationUpdaterFrequencyFunc(applicationUpdaterFrequency->getSelected());
|
2023-02-18 11:42:19 +00:00
|
|
|
applicationUpdaterFrequency->setCallback(applicationUpdaterFrequencyFunc);
|
|
|
|
#endif
|
|
|
|
|
2021-10-24 12:11:19 +00:00
|
|
|
s->setSize(mSize);
|
2020-06-21 12:25:28 +00:00
|
|
|
mWindow->pushGui(s);
|
2017-09-08 14:49:47 +00:00
|
|
|
}
|
2017-06-01 20:08:44 +00:00
|
|
|
|
2023-07-20 19:59:28 +00:00
|
|
|
void GuiMenu::openUtilities()
|
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("UTILITIES"));
|
2023-07-20 19:59:28 +00:00
|
|
|
|
|
|
|
HelpStyle style {getHelpStyle()};
|
|
|
|
|
|
|
|
ComponentListRow row;
|
2024-07-13 17:14:34 +00:00
|
|
|
row.addElement(std::make_shared<TextComponent>(_("ORPHANED DATA CLEANUP"),
|
2023-07-24 15:07:18 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary),
|
|
|
|
true);
|
|
|
|
row.addElement(mMenu.makeArrow(), false);
|
|
|
|
row.makeAcceptInputHandler(std::bind(
|
|
|
|
[this] { mWindow->pushGui(new GuiOrphanedDataCleanup([&]() { close(true); })); }));
|
|
|
|
s->addRow(row);
|
|
|
|
|
|
|
|
row.elements.clear();
|
2024-07-13 17:14:34 +00:00
|
|
|
row.addElement(std::make_shared<TextComponent>(_("CREATE/UPDATE SYSTEM DIRECTORIES"),
|
2023-07-24 15:07:18 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary),
|
|
|
|
true);
|
|
|
|
|
|
|
|
// This transparent dummy arrow is only here to enable the "select" help prompt.
|
|
|
|
auto dummyArrow = mMenu.makeArrow();
|
|
|
|
dummyArrow->setOpacity(0.0f);
|
|
|
|
row.addElement(dummyArrow, false);
|
|
|
|
|
2023-08-14 17:10:16 +00:00
|
|
|
row.makeAcceptInputHandler([this] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
|
|
getHelpStyle(),
|
2024-07-13 17:14:34 +00:00
|
|
|
_("THIS WILL CREATE ALL GAME SYSTEM DIRECTORIES INSIDE YOUR ROM FOLDER AND IT WILL "
|
|
|
|
"ALSO UPDATE ALL SYSTEMINFO.TXT FILES. THIS IS A SAFE OPERATION THAT WILL NOT DELETE "
|
|
|
|
"OR MODIFY YOUR GAME FILES. TO DECREASE APPLICATION STARTUP TIMES IT'S RECOMMENDED "
|
|
|
|
"TO DELETE THE SYSTEM DIRECTORIES YOU DON'T NEED AFTER RUNNING THIS UTILITY"),
|
|
|
|
_("PROCEED"),
|
2023-08-14 17:10:16 +00:00
|
|
|
[this] {
|
|
|
|
if (!SystemData::createSystemDirectories()) {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
2024-07-13 17:14:34 +00:00
|
|
|
getHelpStyle(), _("THE SYSTEM DIRECTORIES WERE SUCCESSFULLY CREATED"),
|
|
|
|
_("OK"),
|
2023-08-14 17:10:16 +00:00
|
|
|
[this] {
|
|
|
|
if (CollectionSystemsManager::getInstance()->isEditing())
|
|
|
|
CollectionSystemsManager::getInstance()->exitEditMode();
|
|
|
|
mWindow->stopInfoPopup();
|
|
|
|
GuiMenu::close(true);
|
|
|
|
// Write any gamelist.xml changes before proceeding with the rescan.
|
|
|
|
if (Settings::getInstance()->getString("SaveGamelistsMode") ==
|
|
|
|
"on exit") {
|
|
|
|
for (auto system : SystemData::sSystemVector)
|
|
|
|
system->writeMetaData();
|
|
|
|
}
|
|
|
|
ViewController::getInstance()->rescanROMDirectory();
|
|
|
|
},
|
2023-09-17 09:47:58 +00:00
|
|
|
"", nullptr, "", nullptr, nullptr, true));
|
2023-08-14 17:10:16 +00:00
|
|
|
}
|
|
|
|
else {
|
2024-07-13 10:32:16 +00:00
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
|
|
getHelpStyle(),
|
2024-07-13 17:14:34 +00:00
|
|
|
_("ERROR CREATING SYSTEM DIRECTORIES, PERMISSION PROBLEMS OR "
|
|
|
|
"DISK FULL? SEE THE LOG FILE FOR MORE DETAILS"),
|
2024-07-13 10:32:16 +00:00
|
|
|
_("OK"), nullptr, "", nullptr, "", nullptr, nullptr, true, true,
|
|
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
|
|
0.70f :
|
|
|
|
0.44f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
2023-08-14 17:10:16 +00:00
|
|
|
}
|
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("CANCEL"), nullptr, "", nullptr, nullptr, false, true,
|
2023-08-14 17:10:16 +00:00
|
|
|
(mRenderer->getIsVerticalOrientation() ?
|
|
|
|
0.80f :
|
|
|
|
0.52f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
|
|
|
});
|
|
|
|
|
|
|
|
s->addRow(row);
|
|
|
|
|
|
|
|
row.elements.clear();
|
2024-07-13 17:14:34 +00:00
|
|
|
row.addElement(std::make_shared<TextComponent>(_("RESCAN ROM DIRECTORY"),
|
2023-08-14 17:10:16 +00:00
|
|
|
Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary),
|
|
|
|
true);
|
|
|
|
|
|
|
|
// This transparent dummy arrow is only here to enable the "select" help prompt.
|
|
|
|
row.addElement(dummyArrow, false);
|
|
|
|
|
|
|
|
row.makeAcceptInputHandler([this] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
|
|
getHelpStyle(),
|
2024-07-13 17:14:34 +00:00
|
|
|
_("THIS WILL RESCAN YOUR ROM DIRECTORY FOR CHANGES SUCH AS ADDED OR REMOVED GAMES AND "
|
|
|
|
"SYSTEMS"),
|
|
|
|
_("PROCEED"),
|
2023-08-14 17:10:16 +00:00
|
|
|
[this] {
|
2023-07-20 19:59:28 +00:00
|
|
|
if (CollectionSystemsManager::getInstance()->isEditing())
|
|
|
|
CollectionSystemsManager::getInstance()->exitEditMode();
|
2023-08-14 17:10:16 +00:00
|
|
|
mWindow->stopInfoPopup();
|
2023-07-20 19:59:28 +00:00
|
|
|
GuiMenu::close(true);
|
2023-07-24 15:07:18 +00:00
|
|
|
// Write any gamelist.xml changes before proceeding with the rescan.
|
2023-07-21 10:00:22 +00:00
|
|
|
if (Settings::getInstance()->getString("SaveGamelistsMode") == "on exit") {
|
2023-07-20 19:59:28 +00:00
|
|
|
for (auto system : SystemData::sSystemVector)
|
|
|
|
system->writeMetaData();
|
|
|
|
}
|
2023-07-24 15:07:18 +00:00
|
|
|
ViewController::getInstance()->rescanROMDirectory();
|
2023-07-20 19:59:28 +00:00
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("CANCEL"), nullptr, "", nullptr, nullptr, false, true,
|
2023-09-10 12:09:39 +00:00
|
|
|
(mRenderer->getIsVerticalOrientation() ?
|
2023-10-26 20:17:45 +00:00
|
|
|
0.76f :
|
2023-09-10 12:09:39 +00:00
|
|
|
0.52f * (1.778f / mRenderer->getScreenAspectRatio()))));
|
2023-07-20 19:59:28 +00:00
|
|
|
});
|
|
|
|
s->addRow(row);
|
|
|
|
|
|
|
|
s->setSize(mSize);
|
|
|
|
mWindow->pushGui(s);
|
|
|
|
}
|
|
|
|
|
2017-09-08 14:49:47 +00:00
|
|
|
void GuiMenu::openQuitMenu()
|
|
|
|
{
|
2024-01-06 11:57:00 +00:00
|
|
|
#if defined(__APPLE__) || defined(__ANDROID__)
|
|
|
|
if (true) {
|
|
|
|
#else
|
2020-12-17 22:45:29 +00:00
|
|
|
if (!Settings::getInstance()->getBool("ShowQuitMenu")) {
|
2024-01-06 11:57:00 +00:00
|
|
|
#endif
|
2021-07-07 18:03:42 +00:00
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
2024-07-13 17:14:34 +00:00
|
|
|
this->getHelpStyle(), _("REALLY QUIT?"), _("YES"),
|
2021-07-07 18:03:42 +00:00
|
|
|
[this] {
|
|
|
|
close(true);
|
2022-01-10 17:43:17 +00:00
|
|
|
Utils::Platform::quitES();
|
2021-07-07 18:03:42 +00:00
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("NO"), nullptr));
|
2020-12-17 22:45:29 +00:00
|
|
|
}
|
|
|
|
else {
|
2024-07-04 16:53:13 +00:00
|
|
|
auto s = new GuiSettings(_("QUIT"));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2022-01-19 17:01:54 +00:00
|
|
|
Window* window {mWindow};
|
2022-09-03 10:44:49 +00:00
|
|
|
HelpStyle style {getHelpStyle()};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-12-17 22:45:29 +00:00
|
|
|
ComponentListRow row;
|
|
|
|
|
|
|
|
row.makeAcceptInputHandler([window, this] {
|
2021-07-07 18:03:42 +00:00
|
|
|
window->pushGui(new GuiMsgBox(
|
2024-07-13 17:14:34 +00:00
|
|
|
this->getHelpStyle(), _("REALLY QUIT?"), _("YES"),
|
2021-07-07 18:03:42 +00:00
|
|
|
[this] {
|
2020-12-17 22:45:29 +00:00
|
|
|
close(true);
|
2022-01-10 17:43:17 +00:00
|
|
|
Utils::Platform::quitES();
|
2021-07-07 18:03:42 +00:00
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("NO"), nullptr));
|
2020-12-17 22:45:29 +00:00
|
|
|
});
|
2024-07-13 17:14:34 +00:00
|
|
|
auto quitText = std::make_shared<TextComponent>(
|
|
|
|
_("QUIT ES-DE"), Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary);
|
2021-10-14 20:21:21 +00:00
|
|
|
quitText->setSelectable(true);
|
|
|
|
row.addElement(quitText, true);
|
2020-12-17 22:45:29 +00:00
|
|
|
s->addRow(row);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
row.elements.clear();
|
|
|
|
row.makeAcceptInputHandler([window, this] {
|
2021-07-07 18:03:42 +00:00
|
|
|
window->pushGui(new GuiMsgBox(
|
2024-07-13 17:14:34 +00:00
|
|
|
this->getHelpStyle(), _("REALLY REBOOT?"), _("YES"),
|
2021-07-07 18:03:42 +00:00
|
|
|
[] {
|
2022-01-10 17:43:17 +00:00
|
|
|
if (Utils::Platform::quitES(Utils::Platform::QuitMode::REBOOT) != 0) {
|
2020-06-21 12:25:28 +00:00
|
|
|
LOG(LogWarning) << "Reboot terminated with non-zero result!";
|
2020-06-25 17:52:38 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("NO"), nullptr));
|
2020-06-21 12:25:28 +00:00
|
|
|
});
|
2023-05-07 20:56:24 +00:00
|
|
|
auto rebootText = std::make_shared<TextComponent>(
|
2024-07-13 17:14:34 +00:00
|
|
|
_("REBOOT SYSTEM"), Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary);
|
2021-10-14 20:21:21 +00:00
|
|
|
rebootText->setSelectable(true);
|
|
|
|
row.addElement(rebootText, true);
|
2020-06-21 12:25:28 +00:00
|
|
|
s->addRow(row);
|
|
|
|
|
|
|
|
row.elements.clear();
|
|
|
|
row.makeAcceptInputHandler([window, this] {
|
2021-07-07 18:03:42 +00:00
|
|
|
window->pushGui(new GuiMsgBox(
|
2024-07-13 17:14:34 +00:00
|
|
|
this->getHelpStyle(), _("REALLY POWER OFF?"), _("YES"),
|
2021-07-07 18:03:42 +00:00
|
|
|
[] {
|
2022-01-10 17:43:17 +00:00
|
|
|
if (Utils::Platform::quitES(Utils::Platform::QuitMode::POWEROFF) != 0) {
|
2020-06-21 12:25:28 +00:00
|
|
|
LOG(LogWarning) << "Power off terminated with non-zero result!";
|
2020-06-25 17:52:38 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
},
|
2024-07-13 17:14:34 +00:00
|
|
|
_("NO"), nullptr));
|
2020-06-21 12:25:28 +00:00
|
|
|
});
|
2021-10-14 20:21:21 +00:00
|
|
|
auto powerOffText = std::make_shared<TextComponent>(
|
2024-07-13 17:14:34 +00:00
|
|
|
_("POWER OFF SYSTEM"), Font::get(FONT_SIZE_MEDIUM), mMenuColorPrimary);
|
2021-10-14 20:21:21 +00:00
|
|
|
powerOffText->setSelectable(true);
|
|
|
|
row.addElement(powerOffText, true);
|
2020-06-21 12:25:28 +00:00
|
|
|
s->addRow(row);
|
|
|
|
|
2021-10-24 12:11:19 +00:00
|
|
|
s->setSize(mSize);
|
2020-12-17 22:45:29 +00:00
|
|
|
mWindow->pushGui(s);
|
|
|
|
}
|
2017-09-08 14:49:47 +00:00
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2017-09-08 14:49:47 +00:00
|
|
|
void GuiMenu::addVersionInfo()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
|
2023-05-07 20:56:24 +00:00
|
|
|
mVersion.setColor(mMenuColorTertiary);
|
2022-04-19 15:27:04 +00:00
|
|
|
|
2023-12-25 22:23:39 +00:00
|
|
|
const std::string applicationName {"ES-DE"};
|
|
|
|
|
2023-02-18 11:42:19 +00:00
|
|
|
#if defined(IS_PRERELEASE)
|
2024-06-16 20:05:54 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
mVersion.setText(applicationName + " " + Utils::String::toUpper(PROGRAM_VERSION_STRING) + "-" +
|
|
|
|
std::to_string(ANDROID_VERSION_CODE) + " (Built " + __DATE__ + ")");
|
|
|
|
#else
|
2024-02-25 11:26:32 +00:00
|
|
|
mVersion.setText(applicationName + " " + Utils::String::toUpper(PROGRAM_VERSION_STRING) +
|
2023-12-25 22:23:39 +00:00
|
|
|
" (Built " + __DATE__ + ")");
|
2024-06-16 20:05:54 +00:00
|
|
|
#endif
|
2024-02-25 21:46:14 +00:00
|
|
|
#else
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
mVersion.setText(applicationName + " " + Utils::String::toUpper(PROGRAM_VERSION_STRING) + "-" +
|
|
|
|
std::to_string(ANDROID_VERSION_CODE));
|
2022-04-19 15:27:04 +00:00
|
|
|
#else
|
2024-02-25 11:26:32 +00:00
|
|
|
mVersion.setText(applicationName + " " + Utils::String::toUpper(PROGRAM_VERSION_STRING));
|
2024-02-25 21:46:14 +00:00
|
|
|
#endif
|
2022-04-19 15:27:04 +00:00
|
|
|
#endif
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mVersion.setHorizontalAlignment(ALIGN_CENTER);
|
|
|
|
addChild(&mVersion);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2023-02-13 19:38:23 +00:00
|
|
|
void GuiMenu::openThemeDownloader(GuiSettings* settings)
|
|
|
|
{
|
2023-03-31 21:00:23 +00:00
|
|
|
auto updateFunc = [&, settings]() {
|
2023-08-14 17:10:16 +00:00
|
|
|
LOG(LogDebug) << "GuiMenu::openThemeDownloader(): Themes were updated, reloading menu";
|
2023-08-13 22:02:20 +00:00
|
|
|
mThemeDownloaderReloadCounter = 1;
|
2023-03-31 21:00:23 +00:00
|
|
|
delete settings;
|
2023-08-13 22:02:20 +00:00
|
|
|
if (mThemeDownloaderReloadCounter != 1) {
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
openUIOptions();
|
|
|
|
mWindow->invalidateCachedBackground();
|
|
|
|
}
|
2023-03-31 21:00:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
mWindow->pushGui(new GuiThemeDownloader(updateFunc));
|
2023-02-13 19:38:23 +00:00
|
|
|
}
|
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
void GuiMenu::openMediaViewerOptions()
|
|
|
|
{
|
2024-07-19 08:40:04 +00:00
|
|
|
mWindow->pushGui(new GuiMediaViewerOptions(_("MEDIA VIEWER SETTINGS [short]")));
|
2021-05-16 11:12:31 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 19:27:41 +00:00
|
|
|
void GuiMenu::openScreensaverOptions()
|
|
|
|
{
|
2024-07-19 08:40:04 +00:00
|
|
|
mWindow->pushGui(new GuiScreensaverOptions(_("SCREENSAVER SETTINGS [short]")));
|
2017-06-12 16:38:59 +00:00
|
|
|
}
|
|
|
|
|
2021-05-22 20:48:44 +00:00
|
|
|
void GuiMenu::openCollectionSystemOptions()
|
2020-11-06 19:27:41 +00:00
|
|
|
{
|
2024-07-04 16:53:13 +00:00
|
|
|
mWindow->pushGui(new GuiCollectionSystemsOptions(_("GAME COLLECTION SETTINGS")));
|
2017-06-01 20:08:44 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
void GuiMenu::onSizeChanged()
|
|
|
|
{
|
2021-08-16 16:25:01 +00:00
|
|
|
mVersion.setSize(mSize.x, 0.0f);
|
|
|
|
mVersion.setPosition(0.0f, mSize.y - mVersion.getSize().y);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
void GuiMenu::addEntry(const std::string& name,
|
|
|
|
unsigned int color,
|
|
|
|
bool add_arrow,
|
|
|
|
const std::function<void()>& func)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2022-09-03 10:44:49 +00:00
|
|
|
std::shared_ptr<Font> font {Font::get(FONT_SIZE_MEDIUM)};
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Populate the list.
|
|
|
|
ComponentListRow row;
|
2022-01-19 17:01:54 +00:00
|
|
|
row.addElement(std::make_shared<TextComponent>(name, font, color), true);
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (add_arrow) {
|
2023-05-07 20:56:24 +00:00
|
|
|
std::shared_ptr<ImageComponent> bracket {mMenu.makeArrow()};
|
2020-06-21 12:25:28 +00:00
|
|
|
row.addElement(bracket, false);
|
|
|
|
}
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
row.makeAcceptInputHandler(func);
|
|
|
|
mMenu.addRow(row);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2020-06-09 18:03:31 +00:00
|
|
|
void GuiMenu::close(bool closeAllWindows)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::function<void()> closeFunc;
|
|
|
|
if (!closeAllWindows) {
|
|
|
|
closeFunc = [this] { delete this; };
|
|
|
|
}
|
|
|
|
else {
|
2022-01-19 17:01:54 +00:00
|
|
|
Window* window {mWindow};
|
2021-09-19 12:37:10 +00:00
|
|
|
closeFunc = [window] {
|
2022-01-04 20:49:22 +00:00
|
|
|
while (window->peekGui() != ViewController::getInstance())
|
2020-06-21 12:25:28 +00:00
|
|
|
delete window->peekGui();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
closeFunc();
|
2020-06-09 18:03:31 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
bool GuiMenu::input(InputConfig* config, Input input)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (GuiComponent::input(config, input))
|
|
|
|
return true;
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2022-09-03 10:44:49 +00:00
|
|
|
const bool isStart {config->isMappedTo("start", input)};
|
2020-06-21 12:25:28 +00:00
|
|
|
if (input.value != 0 && (config->isMappedTo("b", input) || isStart)) {
|
|
|
|
close(isStart);
|
|
|
|
return true;
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return false;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> GuiMenu::getHelpPrompts()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::vector<HelpPrompt> prompts;
|
2024-07-13 17:14:34 +00:00
|
|
|
prompts.push_back(HelpPrompt("up/down", _("choose")));
|
|
|
|
prompts.push_back(HelpPrompt("a", _("select")));
|
|
|
|
prompts.push_back(HelpPrompt("b", _("close menu")));
|
|
|
|
prompts.push_back(HelpPrompt("start", _("close menu")));
|
2020-06-21 12:25:28 +00:00
|
|
|
return prompts;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|