ES-DE/es-app/src/guis/GuiMenu.cpp

1837 lines
86 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// GuiMenu.cpp
//
// Main menu.
// Some submenus are covered in separate source files.
//
#include "guis/GuiMenu.h"
2017-11-01 22:21:10 +00:00
#if defined(_WIN64)
// Why this is needed here is anyone's guess but without it the compilation fails.
#include <winsock2.h>
#endif
#include "CollectionSystemsManager.h"
#include "EmulationStation.h"
#include "FileFilterIndex.h"
#include "FileSorts.h"
#include "Scripting.h"
#include "SystemData.h"
#include "UIModeController.h"
#include "VolumeControl.h"
2017-11-01 22:21:10 +00:00
#include "components/OptionListComponent.h"
#include "components/SliderComponent.h"
#include "components/SwitchComponent.h"
#include "guis/GuiAlternativeEmulators.h"
#include "guis/GuiCollectionSystemsOptions.h"
#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"
#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"
2022-01-10 17:56:04 +00:00
#include "utils/PlatformUtil.h"
#include <SDL2/SDL_events.h>
#include <algorithm>
GuiMenu::GuiMenu()
: mMenu {"MAIN MENU"}
{
bool isFullUI {UIModeController::getInstance()->isUIModeFull()};
if (isFullUI)
addEntry("SCRAPER", 0x777777FF, true, [this] { openScraperOptions(); });
if (isFullUI)
addEntry("UI SETTINGS", 0x777777FF, true, [this] { openUIOptions(); });
addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundOptions(); });
if (isFullUI)
addEntry("INPUT DEVICE SETTINGS", 0x777777FF, true, [this] { openInputDeviceOptions(); });
if (isFullUI)
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true,
[this] { openCollectionSystemOptions(); });
if (isFullUI)
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherOptions(); });
if (!Settings::getInstance()->getBool("ForceKiosk") &&
Settings::getInstance()->getString("UIMode") != "kiosk") {
if (Settings::getInstance()->getBool("ShowQuitMenu"))
addEntry("QUIT", 0x777777FF, true, [this] { openQuitMenu(); });
else
addEntry("QUIT EMULATIONSTATION", 0x777777FF, false, [this] { openQuitMenu(); });
}
addChild(&mMenu);
addVersionInfo();
setSize(mMenu.getSize());
setPosition((Renderer::getScreenWidth() - mSize.x) / 2.0f,
std::round(Renderer::getScreenHeight() * 0.13f));
}
GuiMenu::~GuiMenu()
{
// 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();
ViewController::getInstance()->startViewVideos();
}
void GuiMenu::openScraperOptions()
{
// Open the scraper menu.
mWindow->pushGui(new GuiScraperMenu("SCRAPER"));
}
void GuiMenu::openUIOptions()
{
auto s = new GuiSettings("UI SETTINGS");
// Theme options section.
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator> themeSets {
ThemeData::getThemeSets()};
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
selectedSet;
2022-09-03 10:44:49 +00:00
auto themeSet =
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "THEME SET", false);
2023-02-13 19:38:23 +00:00
// TODO: Enable and possibly move somewhere else when the theme downloader is implemented.
// ComponentListRow themeDownloaderInputRow;
// themeDownloaderInputRow.elements.clear();
// themeDownloaderInputRow.addElement(std::make_shared<TextComponent>("THEME DOWNLOADER",
// Font::get(FONT_SIZE_MEDIUM),
// 0x777777FF),
// true);
// themeDownloaderInputRow.addElement(makeArrow(), false);
// themeDownloaderInputRow.makeAcceptInputHandler(
// std::bind(&GuiMenu::openThemeDownloader, this, s));
// s->addRow(themeDownloaderInputRow);
// Theme set.
if (!themeSets.empty()) {
selectedSet = themeSets.find(Settings::getInstance()->getString("ThemeSet"));
if (selectedSet == themeSets.cend())
selectedSet = themeSets.cbegin();
std::vector<std::pair<std::string, std::pair<std::string, ThemeData::ThemeSet>>>
themeSetsSorted;
std::string sortName;
for (auto& theme : themeSets) {
if (theme.second.capabilities.themeName != "")
sortName = theme.second.capabilities.themeName;
else
sortName = theme.first;
themeSetsSorted.emplace_back(std::make_pair(Utils::String::toUpper(sortName),
std::make_pair(theme.first, theme.second)));
}
std::sort(themeSetsSorted.begin(), themeSetsSorted.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
for (auto it = themeSetsSorted.cbegin(); it != themeSetsSorted.cend(); ++it) {
// If required, abbreviate the theme set name so it doesn't overlap the setting name.
const float maxNameLength {mSize.x * 0.62f};
std::string themeName {(*it).first};
if ((*it).second.second.capabilities.legacyTheme)
themeName.append(" [LEGACY]");
themeSet->add(themeName, it->second.first, (*it).second.first == selectedSet->first,
maxNameLength);
}
2022-09-03 10:44:49 +00:00
s->addWithLabel("THEME SET", themeSet);
s->addSaveFunc([this, themeSet, s] {
if (themeSet->getSelected() != Settings::getInstance()->getString("ThemeSet")) {
Scripting::fireEvent("theme-changed", themeSet->getSelected(),
Settings::getInstance()->getString("ThemeSet"));
2022-09-03 10:44:49 +00:00
Settings::getInstance()->setString("ThemeSet", themeSet->getSelected());
mWindow->setChangedThemeSet();
// This is required so that the custom collection system does not disappear
// if the user is editing a custom collection when switching theme sets.
if (CollectionSystemsManager::getInstance()->isEditing())
CollectionSystemsManager::getInstance()->exitEditMode();
s->setNeedsSaving();
s->setNeedsReloading();
s->setNeedsGoToStart();
s->setNeedsCollectionsUpdate();
s->setInvalidateCachedBackground();
}
});
}
// Theme variants.
auto themeVariant =
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "THEME VARIANT", false);
s->addWithLabel("THEME VARIANT", themeVariant);
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
}
});
auto themeVariantsFunc = [=](const std::string& selectedTheme,
const std::string& selectedVariant) {
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
currentSet {themeSets.find(selectedTheme)};
if (currentSet == themeSets.cend())
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.
const float maxNameLength {mSize.x * 0.62f};
themeVariant->add(variant.label, variant.name, variant.name == selectedVariant,
maxNameLength);
}
}
if (themeVariant->getSelectedObjects().size() == 0)
themeVariant->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeVariant->add("Legacy theme set", "none", true);
else
themeVariant->add("None defined", "none", true);
themeVariant->setEnabled(false);
themeVariant->setOpacity(DISABLED_OPACITY);
themeVariant->getParent()
->getChild(themeVariant->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
};
themeVariantsFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeVariant"));
2022-10-31 18:32:13 +00:00
// Theme color schemes.
auto themeColorScheme = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "THEME COLOR SCHEME", false);
s->addWithLabel("THEME COLOR SCHEME", themeColorScheme);
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) {
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
currentSet {themeSets.find(selectedTheme)};
if (currentSet == themeSets.cend())
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.
const float maxNameLength {mSize.x * 0.52f};
2022-10-31 18:32:13 +00:00
themeColorScheme->add(colorScheme.label, colorScheme.name,
colorScheme.name == selectedColorScheme, maxNameLength);
}
if (themeColorScheme->getSelectedObjects().size() == 0)
themeColorScheme->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeColorScheme->add("Legacy theme set", "none", true);
else
themeColorScheme->add("None defined", "none", true);
themeColorScheme->setEnabled(false);
themeColorScheme->setOpacity(DISABLED_OPACITY);
themeColorScheme->getParent()
->getChild(themeColorScheme->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
};
themeColorSchemesFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeColorScheme"));
// Theme aspect ratios.
auto themeAspectRatio = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "THEME ASPECT RATIO", false);
s->addWithLabel("THEME ASPECT RATIO", themeAspectRatio);
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) {
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
currentSet {themeSets.find(selectedTheme)};
if (currentSet == themeSets.cend())
return;
// We need to recreate the OptionListComponent entries.
themeAspectRatio->clearEntries();
if (currentSet->second.capabilities.aspectRatios.size() > 0) {
for (auto& aspectRatio : currentSet->second.capabilities.aspectRatios)
themeAspectRatio->add(ThemeData::getAspectRatioLabel(aspectRatio), aspectRatio,
aspectRatio == selectedAspectRatio);
if (themeAspectRatio->getSelectedObjects().size() == 0)
themeAspectRatio->selectEntry(0);
}
else {
if (currentSet->second.capabilities.legacyTheme)
themeAspectRatio->add("Legacy theme set", "none", true);
else
themeAspectRatio->add("None defined", "none", true);
themeAspectRatio->setEnabled(false);
themeAspectRatio->setOpacity(DISABLED_OPACITY);
themeAspectRatio->getParent()
->getChild(themeAspectRatio->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
};
themeAspectRatiosFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeAspectRatio"));
// Theme transitions.
auto themeTransitions = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "THEME TRANSITIONS", false);
std::string selectedThemeTransitions {Settings::getInstance()->getString("ThemeTransitions")};
themeTransitions->add("AUTOMATIC", "automatic", selectedThemeTransitions == "automatic");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set theme transitions to "automatic" in this case.
if (themeTransitions->getSelectedObjects().size() == 0)
themeTransitions->selectEntry(0);
s->addWithLabel("THEME TRANSITIONS", themeTransitions);
s->addSaveFunc([themeTransitions, s] {
if (themeTransitions->getSelected() !=
Settings::getInstance()->getString("ThemeTransitions")) {
Settings::getInstance()->setString("ThemeTransitions", themeTransitions->getSelected());
ThemeData::setThemeTransitions();
s->setNeedsSaving();
}
});
auto themeTransitionsFunc = [=](const std::string& selectedTheme,
const std::string& selectedThemeTransitions) {
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
currentSet {themeSets.find(selectedTheme)};
if (currentSet == themeSets.cend())
return;
// We need to recreate the OptionListComponent entries.
themeTransitions->clearEntries();
if (currentSet->second.capabilities.legacyTheme) {
themeTransitions->add("Legacy theme set", "automatic", true);
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
themeTransitions->add("AUTOMATIC", "automatic",
"automatic" == selectedThemeTransitions);
if (currentSet->second.capabilities.transitions.size() == 1 &&
currentSet->second.capabilities.transitions.front().selectable) {
std::string label;
if (currentSet->second.capabilities.transitions.front().label == "")
label = "THEME PROFILE";
else
label = currentSet->second.capabilities.transitions.front().label;
const std::string transitions {
currentSet->second.capabilities.transitions.front().name};
themeTransitions->add(label, transitions, transitions == selectedThemeTransitions);
}
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 == "")
label = "THEME PROFILE " + std::to_string(i + 1);
else
label = currentSet->second.capabilities.transitions[i].label;
const std::string transitions {
currentSet->second.capabilities.transitions[i].name};
themeTransitions->add(label, transitions,
transitions == selectedThemeTransitions);
}
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-instant") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("INSTANT (BUILT-IN)", "builtin-instant",
"builtin-instant" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-slide") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("SLIDE (BUILT-IN)", "builtin-slide",
"builtin-slide" == selectedThemeTransitions);
}
if (std::find(currentSet->second.capabilities.suppressedTransitionProfiles.cbegin(),
currentSet->second.capabilities.suppressedTransitionProfiles.cend(),
"builtin-fade") ==
currentSet->second.capabilities.suppressedTransitionProfiles.cend()) {
themeTransitions->add("FADE (BUILT-IN)", "builtin-fade",
"builtin-fade" == selectedThemeTransitions);
}
if (themeTransitions->getSelectedObjects().size() == 0)
themeTransitions->selectEntry(0);
if (themeTransitions->getNumEntries() == 1) {
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
themeTransitions->setEnabled(true);
themeTransitions->setOpacity(1.0f);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(1.0f);
}
}
};
themeTransitionsFunc(Settings::getInstance()->getString("ThemeSet"),
Settings::getInstance()->getString("ThemeTransitions"));
// Legacy gamelist view style.
2022-09-03 10:44:49 +00:00
auto gamelistViewStyle = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY GAMELIST VIEW STYLE", false);
2022-09-03 10:44:49 +00:00
std::string selectedViewStyle {Settings::getInstance()->getString("GamelistViewStyle")};
gamelistViewStyle->add("AUTOMATIC", "automatic", selectedViewStyle == "automatic");
gamelistViewStyle->add("BASIC", "basic", selectedViewStyle == "basic");
gamelistViewStyle->add("DETAILED", "detailed", selectedViewStyle == "detailed");
gamelistViewStyle->add("VIDEO", "video", selectedViewStyle == "video");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set the view style to "automatic" in this case.
2022-09-03 10:44:49 +00:00
if (gamelistViewStyle->getSelectedObjects().size() == 0)
gamelistViewStyle->selectEntry(0);
s->addWithLabel("LEGACY GAMELIST VIEW STYLE", gamelistViewStyle);
s->addSaveFunc([gamelistViewStyle, s] {
if (gamelistViewStyle->getSelected() !=
Settings::getInstance()->getString("GamelistViewStyle")) {
2020-11-05 17:18:11 +00:00
Settings::getInstance()->setString("GamelistViewStyle",
2022-09-03 10:44:49 +00:00
gamelistViewStyle->getSelected());
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
s->setNeedsReloading();
s->setInvalidateCachedBackground();
2020-11-05 17:18:11 +00:00
}
});
// Legacy theme transitions.
auto legacyThemeTransitions = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LEGACY THEME TRANSITIONS", false);
const std::string& selectedLegacyThemeTransitions {
Settings::getInstance()->getString("LegacyThemeTransitions")};
legacyThemeTransitions->add("INSTANT", "builtin-instant",
selectedLegacyThemeTransitions == "builtin-instant");
legacyThemeTransitions->add("SLIDE", "builtin-slide",
selectedLegacyThemeTransitions == "builtin-slide");
legacyThemeTransitions->add("FADE", "builtin-fade",
selectedLegacyThemeTransitions == "builtin-fade");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set legacy theme transitions to "builtin-instant" in this case.
if (legacyThemeTransitions->getSelectedObjects().size() == 0)
legacyThemeTransitions->selectEntry(0);
s->addWithLabel("LEGACY THEME TRANSITIONS", legacyThemeTransitions);
s->addSaveFunc([legacyThemeTransitions, s] {
if (legacyThemeTransitions->getSelected() !=
Settings::getInstance()->getString("LegacyThemeTransitions")) {
Settings::getInstance()->setString("LegacyThemeTransitions",
legacyThemeTransitions->getSelected());
ThemeData::setThemeTransitions();
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
}
});
// Quick system select (navigate between systems in the gamelist view).
auto quickSystemSelect = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "QUICK SYSTEM SELECT", false);
std::string selectedQuickSelect {Settings::getInstance()->getString("QuickSystemSelect")};
quickSystemSelect->add("LEFT/RIGHT OR SHOULDERS", "leftrightshoulders",
selectedQuickSelect == "leftrightshoulders");
quickSystemSelect->add("LEFT/RIGHT OR TRIGGERS", "leftrighttriggers",
selectedQuickSelect == "leftrighttriggers");
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");
// 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);
s->addWithLabel("QUICK SYSTEM SELECT", quickSystemSelect);
s->addSaveFunc([quickSystemSelect, s] {
if (quickSystemSelect->getSelected() !=
Settings::getInstance()->getString("QuickSystemSelect")) {
Settings::getInstance()->setString("QuickSystemSelect",
quickSystemSelect->getSelected());
s->setNeedsSaving();
}
});
// Optionally start in selected system/gamelist.
auto startupSystem = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "GAMELIST ON STARTUP", false);
startupSystem->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == "");
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
it != SystemData::sSystemVector.cend(); ++it) {
// If required, abbreviate the system name so it doesn't overlap the setting name.
float maxNameLength {mSize.x * 0.51f};
startupSystem->add((*it)->getFullName(), (*it)->getName(),
Settings::getInstance()->getString("StartupSystem") == (*it)->getName(),
maxNameLength);
}
// 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);
s->addWithLabel("GAMELIST ON STARTUP", startupSystem);
s->addSaveFunc([startupSystem, s] {
if (startupSystem->getSelected() != Settings::getInstance()->getString("StartupSystem")) {
Settings::getInstance()->setString("StartupSystem", startupSystem->getSelected());
s->setNeedsSaving();
}
});
// Default gamelist sort order.
std::string sortOrder;
2022-09-03 10:44:49 +00:00
auto defaultSortOrder = std::make_shared<OptionListComponent<const FileData::SortType*>>(
getHelpStyle(), "DEFAULT SORT ORDER", false);
// Exclude the System sort options.
2022-09-03 10:44:49 +00:00
unsigned int numSortTypes {static_cast<unsigned int>(FileSorts::SortTypes.size() - 2)};
for (unsigned int i = 0; i < numSortTypes; ++i) {
if (FileSorts::SortTypes[i].description ==
Settings::getInstance()->getString("DefaultSortOrder")) {
sortOrder = FileSorts::SortTypes[i].description;
break;
}
}
// If an invalid sort order was defined in es_settings.xml, then apply the default
// sort order 'filename, ascending'.
if (sortOrder == "")
sortOrder = Settings::getInstance()->getDefaultString("DefaultSortOrder");
for (unsigned int i = 0; i < numSortTypes; ++i) {
2022-09-03 10:44:49 +00:00
const FileData::SortType& sort {FileSorts::SortTypes[i]};
if (sort.description == sortOrder)
2022-09-03 10:44:49 +00:00
defaultSortOrder->add(sort.description, &sort, true);
else
2022-09-03 10:44:49 +00:00
defaultSortOrder->add(sort.description, &sort, false);
}
2022-09-03 10:44:49 +00:00
s->addWithLabel("DEFAULT SORT ORDER", defaultSortOrder);
s->addSaveFunc([defaultSortOrder, sortOrder, s] {
std::string selectedSortOrder {defaultSortOrder.get()->getSelected()->description};
if (selectedSortOrder != sortOrder) {
Settings::getInstance()->setString("DefaultSortOrder", selectedSortOrder);
s->setNeedsSaving();
s->setNeedsSorting();
s->setNeedsSortingCollections();
s->setInvalidateCachedBackground();
}
});
// Open menu effect.
2022-09-03 10:44:49 +00:00
auto menuOpeningEffect = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "MENU OPENING EFFECT", false);
2022-09-03 10:44:49 +00:00
std::string selectedMenuEffect {Settings::getInstance()->getString("MenuOpeningEffect")};
menuOpeningEffect->add("SCALE-UP", "scale-up", selectedMenuEffect == "scale-up");
menuOpeningEffect->add("NONE", "none", selectedMenuEffect == "none");
// 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);
s->addWithLabel("MENU OPENING EFFECT", menuOpeningEffect);
s->addSaveFunc([menuOpeningEffect, s] {
if (menuOpeningEffect->getSelected() !=
Settings::getInstance()->getString("MenuOpeningEffect")) {
Settings::getInstance()->setString("MenuOpeningEffect",
2022-09-03 10:44:49 +00:00
menuOpeningEffect->getSelected());
s->setNeedsSaving();
}
});
// Launch screen duration.
2022-09-03 10:44:49 +00:00
auto launchScreenDuration = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "LAUNCH SCREEN DURATION", false);
2022-09-03 10:44:49 +00:00
std::string selectedDuration {Settings::getInstance()->getString("LaunchScreenDuration")};
launchScreenDuration->add("NORMAL", "normal", selectedDuration == "normal");
launchScreenDuration->add("BRIEF", "brief", selectedDuration == "brief");
launchScreenDuration->add("LONG", "long", selectedDuration == "long");
launchScreenDuration->add("DISABLED", "disabled", selectedDuration == "disabled");
// 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);
s->addWithLabel("LAUNCH SCREEN DURATION", launchScreenDuration);
s->addSaveFunc([launchScreenDuration, s] {
if (launchScreenDuration->getSelected() !=
Settings::getInstance()->getString("LaunchScreenDuration")) {
Settings::getInstance()->setString("LaunchScreenDuration",
2022-09-03 10:44:49 +00:00
launchScreenDuration->getSelected());
s->setNeedsSaving();
}
});
// UI mode.
2022-09-03 10:44:49 +00:00
auto uiMode =
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "UI MODE", false);
2020-11-05 17:18:11 +00:00
std::vector<std::string> uiModes;
uiModes.push_back("full");
uiModes.push_back("kiosk");
uiModes.push_back("kid");
std::string setMode;
if (Settings::getInstance()->getBool("ForceKiosk"))
setMode = "kiosk";
else if (Settings::getInstance()->getBool("ForceKid"))
setMode = "kid";
else
setMode = Settings::getInstance()->getString("UIMode");
for (auto it = uiModes.cbegin(); it != uiModes.cend(); ++it)
2022-09-03 10:44:49 +00:00
uiMode->add(*it, *it, setMode == *it);
s->addWithLabel("UI MODE", uiMode);
s->addSaveFunc([uiMode, this, s] {
std::string selectedMode {uiMode->getSelected()};
// If any of the force flags are set, then always apply and save the setting.
if (selectedMode == Settings::getInstance()->getString("UIMode") &&
!Settings::getInstance()->getBool("ForceFull") &&
!Settings::getInstance()->getBool("ForceKiosk") &&
!Settings::getInstance()->getBool("ForceKid")) {
return;
}
else if (selectedMode != "full") {
2022-09-03 10:44:49 +00:00
std::string msg {"YOU ARE CHANGING THE UI TO THE RESTRICTED MODE\n'" +
Utils::String::toUpper(selectedMode) + "'\n"};
if (selectedMode == "kiosk") {
2022-09-03 10:44:49 +00:00
msg.append("THIS WILL HIDE MOST MENU OPTIONS TO PREVENT\n");
msg.append("CHANGES TO THE SYSTEM\n");
}
else {
2022-09-03 10:44:49 +00:00
msg.append("THIS WILL LIMIT THE AVAILABLE GAMES TO THE ONES\n");
msg.append("FLAGGED SUITABLE FOR CHILDREN\n");
}
2022-09-03 10:44:49 +00:00
msg.append("TO UNLOCK AND RETURN TO THE FULL UI, ENTER THIS CODE: \n");
msg.append(UIModeController::getInstance()->getFormattedPassKeyStr() + "\n\n");
msg.append("DO YOU WANT TO PROCEED?");
mWindow->pushGui(new GuiMsgBox(
this->getHelpStyle(), msg, "YES",
[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();
if (CollectionSystemsManager::getInstance()->isEditing())
CollectionSystemsManager::getInstance()->exitEditMode();
UIModeController::getInstance()->setCurrentUIMode(selectedMode);
for (auto it = SystemData::sSystemVector.cbegin();
it != SystemData::sSystemVector.cend(); ++it) {
if ((*it)->getThemeFolder() == "custom-collections") {
for (FileData* customSystem :
(*it)->getRootFolder()->getChildrenListToDisplay())
customSystem->getSystem()->getIndex()->resetFilters();
}
(*it)->sortSystem();
(*it)->getIndex()->resetFilters();
}
ViewController::getInstance()->reloadAll();
ViewController::getInstance()->goToSystem(SystemData::sSystemVector.front(),
false);
mWindow->invalidateCachedBackground();
},
"NO", nullptr));
2020-11-05 17:18:11 +00:00
}
else {
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" << selectedMode
<< "'.";
2022-09-03 10:44:49 +00:00
Settings::getInstance()->setString("UIMode", uiMode->getSelected());
Settings::getInstance()->setBool("ForceFull", false);
Settings::getInstance()->setBool("ForceKiosk", false);
Settings::getInstance()->setBool("ForceKid", false);
UIModeController::getInstance()->setCurrentUIMode("full");
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
s->setNeedsSorting();
s->setNeedsSortingCollections();
s->setNeedsResetFilters();
s->setNeedsReloading();
s->setNeedsGoToSystem(SystemData::sSystemVector.front());
s->setInvalidateCachedBackground();
}
});
// Media viewer.
2022-09-03 10:44:49 +00:00
ComponentListRow mediaViewerRow;
mediaViewerRow.elements.clear();
mediaViewerRow.addElement(std::make_shared<TextComponent>(
"MEDIA VIEWER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
true);
mediaViewerRow.addElement(makeArrow(), false);
mediaViewerRow.makeAcceptInputHandler(std::bind(&GuiMenu::openMediaViewerOptions, this));
s->addRow(mediaViewerRow);
// Screensaver.
2022-09-03 10:44:49 +00:00
ComponentListRow screensaverRow;
screensaverRow.elements.clear();
screensaverRow.addElement(std::make_shared<TextComponent>(
"SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
true);
screensaverRow.addElement(makeArrow(), false);
screensaverRow.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
s->addRow(screensaverRow);
// Enable theme variant triggers.
auto themeVariantTriggers = std::make_shared<SwitchComponent>();
themeVariantTriggers->setState(Settings::getInstance()->getBool("ThemeVariantTriggers"));
s->addWithLabel("ENABLE THEME VARIANT TRIGGERS", themeVariantTriggers);
s->addSaveFunc([themeVariantTriggers, s] {
if (themeVariantTriggers->getState() !=
Settings::getInstance()->getBool("ThemeVariantTriggers")) {
Settings::getInstance()->setBool("ThemeVariantTriggers",
themeVariantTriggers->getState());
s->setNeedsSaving();
s->setNeedsReloading();
s->setInvalidateCachedBackground();
}
});
// Blur background when the menu is open.
2022-09-03 10:44:49 +00:00
auto menuBlurBackground = std::make_shared<SwitchComponent>();
menuBlurBackground->setState(Settings::getInstance()->getBool("MenuBlurBackground"));
s->addWithLabel("BLUR BACKGROUND WHEN MENU IS OPEN", menuBlurBackground);
s->addSaveFunc([menuBlurBackground, s] {
if (menuBlurBackground->getState() !=
Settings::getInstance()->getBool("MenuBlurBackground")) {
2022-09-03 10:44:49 +00:00
Settings::getInstance()->setBool("MenuBlurBackground", menuBlurBackground->getState());
s->setNeedsSaving();
s->setInvalidateCachedBackground();
}
});
// Display pillarboxes (and letterboxes) for videos in the gamelists.
auto gamelistVideoPillarbox = std::make_shared<SwitchComponent>();
gamelistVideoPillarbox->setState(Settings::getInstance()->getBool("GamelistVideoPillarbox"));
s->addWithLabel("DISPLAY PILLARBOXES FOR GAMELIST VIDEOS", gamelistVideoPillarbox);
s->addSaveFunc([gamelistVideoPillarbox, s] {
if (gamelistVideoPillarbox->getState() !=
Settings::getInstance()->getBool("GamelistVideoPillarbox")) {
Settings::getInstance()->setBool("GamelistVideoPillarbox",
gamelistVideoPillarbox->getState());
s->setNeedsSaving();
}
});
2020-11-05 17:18:11 +00:00
// Render scanlines for videos in the gamelists.
auto gamelistVideoScanlines = std::make_shared<SwitchComponent>();
gamelistVideoScanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines"));
s->addWithLabel("RENDER SCANLINES FOR GAMELIST VIDEOS", gamelistVideoScanlines);
s->addSaveFunc([gamelistVideoScanlines, s] {
if (gamelistVideoScanlines->getState() !=
Settings::getInstance()->getBool("GamelistVideoScanlines")) {
2020-11-05 17:18:11 +00:00
Settings::getInstance()->setBool("GamelistVideoScanlines",
gamelistVideoScanlines->getState());
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
}
});
// 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"));
s->addWithLabel("SORT FOLDERS ON TOP OF GAMELISTS", foldersOnTop);
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();
s->setInvalidateCachedBackground();
}
});
// 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"));
s->addWithLabel("SORT FAVORITE GAMES ABOVE NON-FAVORITES", favoritesFirst);
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();
s->setInvalidateCachedBackground();
}
});
// 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"));
s->addWithLabel("ADD STAR MARKINGS TO FAVORITE GAMES", favoritesStar);
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();
s->setInvalidateCachedBackground();
}
});
// 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"));
s->addWithLabel("ENABLE TEXTLIST QUICK SCROLLING OVERLAY", listScrollOverlay);
2022-09-03 10:44:49 +00:00
s->addSaveFunc([listScrollOverlay, s] {
if (listScrollOverlay->getState() !=
Settings::getInstance()->getBool("ListScrollOverlay")) {
2022-09-03 10:44:49 +00:00
Settings::getInstance()->setBool("ListScrollOverlay", listScrollOverlay->getState());
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"));
s->addWithLabel("ENABLE VIRTUAL KEYBOARD", virtualKeyboard);
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();
}
});
// 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"));
s->addWithLabel("ENABLE TOGGLE FAVORITES BUTTON", favoritesAddButton);
s->addSaveFunc([favoritesAddButton, s] {
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();
}
});
// Enable the thumbstick click buttons for jumping to a random system or game.
2022-09-03 10:44:49 +00:00
auto randomAddButton = std::make_shared<SwitchComponent>();
randomAddButton->setState(Settings::getInstance()->getBool("RandomAddButton"));
s->addWithLabel("ENABLE RANDOM SYSTEM OR GAME BUTTON", randomAddButton);
s->addSaveFunc([randomAddButton, s] {
if (Settings::getInstance()->getBool("RandomAddButton") != randomAddButton->getState()) {
Settings::getInstance()->setBool("RandomAddButton", randomAddButton->getState());
s->setNeedsSaving();
}
});
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"));
s->addWithLabel("ENABLE GAMELIST FILTERS", gamelistFilters);
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-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"));
s->addWithLabel("DISPLAY ON-SCREEN HELP", showHelpPrompts);
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();
}
});
// When the theme set entries are scrolled or selected, update the relevant rows.
auto scrollThemeSetFunc = [=](const std::string& themeName, bool firstRun = false) {
auto selectedSet = themeSets.find(themeName);
if (selectedSet == themeSets.cend())
return;
if (!firstRun) {
themeVariantsFunc(themeName, themeVariant->getSelected());
2022-10-31 18:32:13 +00:00
themeColorSchemesFunc(themeName, themeColorScheme->getSelected());
themeAspectRatiosFunc(themeName, themeAspectRatio->getSelected());
themeTransitionsFunc(themeName, themeTransitions->getSelected());
}
int selectableVariants {0};
for (auto& variant : selectedSet->second.capabilities.variants) {
if (variant.selectable)
++selectableVariants;
}
if (!selectedSet->second.capabilities.legacyTheme && selectableVariants > 0) {
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);
}
2022-10-31 18:32:13 +00:00
if (!selectedSet->second.capabilities.legacyTheme &&
selectedSet->second.capabilities.colorSchemes.size() > 0) {
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);
}
if (!selectedSet->second.capabilities.legacyTheme &&
selectedSet->second.capabilities.aspectRatios.size() > 0) {
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);
}
if (!selectedSet->second.capabilities.legacyTheme) {
2022-09-03 10:44:49 +00:00
gamelistViewStyle->setEnabled(false);
gamelistViewStyle->setOpacity(DISABLED_OPACITY);
gamelistViewStyle->getParent()
->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->setEnabled(false);
legacyThemeTransitions->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->getParent()
->getChild(legacyThemeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
// Pillarboxes are theme-controlled for newer themes.
gamelistVideoPillarbox->setEnabled(false);
gamelistVideoPillarbox->setOpacity(DISABLED_OPACITY);
gamelistVideoPillarbox->getParent()
->getChild(gamelistVideoPillarbox->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
// Scanlines are theme-controlled for newer themes.
gamelistVideoScanlines->setEnabled(false);
gamelistVideoScanlines->setOpacity(DISABLED_OPACITY);
gamelistVideoScanlines->getParent()
->getChild(gamelistVideoScanlines->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
else {
2022-09-03 10:44:49 +00:00
gamelistViewStyle->setEnabled(true);
gamelistViewStyle->setOpacity(1.0f);
gamelistViewStyle->getParent()
->getChild(gamelistViewStyle->getChildIndex() - 1)
->setOpacity(1.0f);
themeTransitions->setEnabled(false);
themeTransitions->setOpacity(DISABLED_OPACITY);
themeTransitions->getParent()
->getChild(themeTransitions->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
legacyThemeTransitions->setEnabled(true);
legacyThemeTransitions->setOpacity(1.0f);
legacyThemeTransitions->getParent()
->getChild(legacyThemeTransitions->getChildIndex() - 1)
->setOpacity(1.0f);
gamelistVideoPillarbox->setEnabled(true);
gamelistVideoPillarbox->setOpacity(1.0f);
gamelistVideoPillarbox->getParent()
->getChild(gamelistVideoPillarbox->getChildIndex() - 1)
->setOpacity(1.0f);
gamelistVideoScanlines->setEnabled(true);
gamelistVideoScanlines->setOpacity(1.0f);
gamelistVideoScanlines->getParent()
->getChild(gamelistVideoScanlines->getChildIndex() - 1)
->setOpacity(1.0f);
}
};
scrollThemeSetFunc(selectedSet->first, true);
2022-09-03 10:44:49 +00:00
themeSet->setCallback(scrollThemeSetFunc);
s->setSize(mSize);
mWindow->pushGui(s);
}
void GuiMenu::openSoundOptions()
2020-11-05 17:18:11 +00:00
{
auto s = new GuiSettings("SOUND SETTINGS");
2020-11-05 17:18:11 +00:00
2021-10-18 16:12:19 +00:00
// TODO: Hide the volume slider on macOS and BSD Unix until the volume control logic has been
// implemented for these operating systems.
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
2020-11-05 17:18:11 +00:00
// System volume.
// 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()};
auto systemVolume = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
systemVolume->setValue(static_cast<float>(currentVolume));
s->addWithLabel("SYSTEM VOLUME", systemVolume);
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
});
#endif
2020-11-05 17:18:11 +00:00
// Volume for navigation sounds.
auto soundVolumeNavigation = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
2022-09-03 10:44:49 +00:00
soundVolumeNavigation->setValue(
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeNavigation")));
2022-09-03 10:44:49 +00:00
s->addWithLabel("NAVIGATION SOUNDS VOLUME", soundVolumeNavigation);
s->addSaveFunc([soundVolumeNavigation, s] {
if (soundVolumeNavigation->getValue() !=
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeNavigation"))) {
Settings::getInstance()->setInt("SoundVolumeNavigation",
2022-09-03 10:44:49 +00:00
static_cast<int>(soundVolumeNavigation->getValue()));
s->setNeedsSaving();
}
});
// Volume for videos.
auto soundVolumeVideos = std::make_shared<SliderComponent>(0.0f, 100.0f, 1.0f, "%");
2022-09-03 10:44:49 +00:00
soundVolumeVideos->setValue(
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeVideos")));
2022-09-03 10:44:49 +00:00
s->addWithLabel("VIDEO PLAYER VOLUME", soundVolumeVideos);
s->addSaveFunc([soundVolumeVideos, s] {
if (soundVolumeVideos->getValue() !=
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeVideos"))) {
Settings::getInstance()->setInt("SoundVolumeVideos",
2022-09-03 10:44:49 +00:00
static_cast<int>(soundVolumeVideos->getValue()));
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.
auto viewsVideoAudio = std::make_shared<SwitchComponent>();
viewsVideoAudio->setState(Settings::getInstance()->getBool("ViewsVideoAudio"));
s->addWithLabel("PLAY AUDIO FOR GAMELIST AND SYSTEM VIEW VIDEOS", viewsVideoAudio);
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"));
s->addWithLabel("PLAY AUDIO FOR MEDIA VIEWER VIDEOS", mediaViewerVideoAudio);
s->addSaveFunc([mediaViewerVideoAudio, s] {
if (mediaViewerVideoAudio->getState() !=
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"));
s->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEOS", screensaverVideoAudio);
s->addSaveFunc([screensaverVideoAudio, s] {
if (screensaverVideoAudio->getState() !=
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"));
s->addWithLabel("ENABLE NAVIGATION SOUNDS", navigationSounds);
s->addSaveFunc([navigationSounds, s] {
if (navigationSounds->getState() !=
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();
}
});
}
s->setSize(mSize);
2020-11-05 17:18:11 +00:00
mWindow->pushGui(s);
}
void GuiMenu::openInputDeviceOptions()
{
auto s = new GuiSettings("INPUT DEVICE SETTINGS");
// Controller type.
2022-09-03 10:44:49 +00:00
auto inputControllerType = std::make_shared<OptionListComponent<std::string>>(
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");
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");
// 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);
s->addWithLabel("CONTROLLER TYPE", inputControllerType);
s->addSaveFunc([inputControllerType, s] {
if (inputControllerType->getSelected() !=
Settings::getInstance()->getString("InputControllerType")) {
Settings::getInstance()->setString("InputControllerType",
2022-09-03 10:44:49 +00:00
inputControllerType->getSelected());
s->setNeedsSaving();
}
});
// 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(
Settings::getInstance()->getBool("InputOnlyFirstController"));
2022-09-03 10:44:49 +00:00
s->addWithLabel("ONLY ACCEPT INPUT FROM FIRST CONTROLLER", inputOnlyFirstController);
s->addSaveFunc([inputOnlyFirstController, s] {
if (Settings::getInstance()->getBool("InputOnlyFirstController") !=
2022-09-03 10:44:49 +00:00
inputOnlyFirstController->getState()) {
Settings::getInstance()->setBool("InputOnlyFirstController",
2022-09-03 10:44:49 +00:00
inputOnlyFirstController->getState());
s->setNeedsSaving();
}
});
// Whether to ignore keyboard input (except the quit shortcut).
auto inputIgnoreKeyboard = std::make_shared<SwitchComponent>();
inputIgnoreKeyboard->setState(Settings::getInstance()->getBool("InputIgnoreKeyboard"));
s->addWithLabel("IGNORE KEYBOARD INPUT", inputIgnoreKeyboard);
s->addSaveFunc([inputIgnoreKeyboard, s] {
if (Settings::getInstance()->getBool("InputIgnoreKeyboard") !=
inputIgnoreKeyboard->getState()) {
Settings::getInstance()->setBool("InputIgnoreKeyboard",
inputIgnoreKeyboard->getState());
s->setNeedsSaving();
}
});
// Configure keyboard and controllers.
2022-09-03 10:44:49 +00:00
ComponentListRow configureInputRow;
configureInputRow.elements.clear();
configureInputRow.addElement(
std::make_shared<TextComponent>("CONFIGURE KEYBOARD AND CONTROLLERS",
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
true);
2022-09-03 10:44:49 +00:00
configureInputRow.addElement(makeArrow(), false);
configureInputRow.makeAcceptInputHandler(std::bind(&GuiMenu::openConfigInput, this, s));
s->addRow(configureInputRow);
s->setSize(mSize);
mWindow->pushGui(s);
}
void GuiMenu::openConfigInput(GuiSettings* settings)
{
// 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);
std::string message;
if (Renderer::getIsVerticalOrientation()) {
message = "THE KEYBOARD AND CONTROLLERS ARE\n"
"AUTOMATICALLY CONFIGURED, BUT USING\n"
"THIS CONFIGURATION TOOL YOU CAN\n"
"OVERRIDE THE DEFAULT BUTTON MAPPINGS\n"
"(THIS WILL NOT AFFECT THE HELP PROMPTS)\n"
"CONTINUE?";
}
else {
message = "THE KEYBOARD AND CONTROLLERS ARE AUTOMATICALLY\n"
"CONFIGURED, BUT USING THIS CONFIGURATION TOOL\n"
"YOU CAN OVERRIDE THE DEFAULT BUTTON MAPPINGS\n"
"(THIS WILL NOT AFFECT THE HELP PROMPTS)\n"
"CONTINUE?";
}
Window* window {mWindow};
window->pushGui(new GuiMsgBox(
getHelpStyle(), message, "YES",
[window] { window->pushGui(new GuiDetectDevice(false, false, nullptr)); }, "NO", nullptr));
}
void GuiMenu::openOtherOptions()
{
auto s = new GuiSettings("OTHER SETTINGS");
// Alternative emulators GUI.
ComponentListRow alternativeEmulatorsRow;
alternativeEmulatorsRow.elements.clear();
alternativeEmulatorsRow.addElement(std::make_shared<TextComponent>("ALTERNATIVE EMULATORS",
Font::get(FONT_SIZE_MEDIUM),
0x777777FF),
true);
alternativeEmulatorsRow.addElement(makeArrow(), false);
alternativeEmulatorsRow.makeAcceptInputHandler(
std::bind([this] { mWindow->pushGui(new GuiAlternativeEmulators); }));
s->addRow(alternativeEmulatorsRow);
// Game media directory.
ComponentListRow rowMediaDir;
2022-09-03 10:44:49 +00:00
auto mediaDirectory = std::make_shared<TextComponent>("GAME MEDIA DIRECTORY",
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
auto bracketMediaDirectory = std::make_shared<ImageComponent>();
bracketMediaDirectory->setResize(
glm::vec2 {0.0f, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()});
bracketMediaDirectory->setImage(":/graphics/arrow.svg");
2022-09-03 10:44:49 +00:00
rowMediaDir.addElement(mediaDirectory, true);
rowMediaDir.addElement(bracketMediaDirectory, false);
2022-09-03 10:44:49 +00:00
std::string titleMediaDir {"ENTER GAME MEDIA DIRECTORY"};
std::string mediaDirectoryStaticText {"Default directory:"};
std::string defaultDirectoryText {"~/.emulationstation/downloaded_media/"};
std::string initValueMediaDir {Settings::getInstance()->getString("MediaDirectory")};
bool multiLineMediaDir {false};
auto updateValMediaDir = [this](const std::string& newVal) {
Settings::getInstance()->setString("MediaDirectory", newVal);
Settings::getInstance()->saveFile();
ViewController::getInstance()->reloadAll();
mWindow->invalidateCachedBackground();
};
rowMediaDir.makeAcceptInputHandler([this, s, titleMediaDir, mediaDirectoryStaticText,
defaultDirectoryText, initValueMediaDir, updateValMediaDir,
multiLineMediaDir] {
2021-09-17 20:23:41 +00:00
if (Settings::getInstance()->getBool("VirtualKeyboard")) {
mWindow->pushGui(new GuiTextEditKeyboardPopup(
getHelpStyle(), s->getMenu().getPosition().y, titleMediaDir,
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
multiLineMediaDir, "SAVE", "SAVE CHANGES?", mediaDirectoryStaticText,
defaultDirectoryText, "load default directory"));
2021-09-17 20:23:41 +00:00
}
else {
mWindow->pushGui(new GuiTextEditPopup(
getHelpStyle(), titleMediaDir, Settings::getInstance()->getString("MediaDirectory"),
updateValMediaDir, multiLineMediaDir, "SAVE", "SAVE CHANGES?",
mediaDirectoryStaticText, defaultDirectoryText, "load default directory"));
2021-09-17 20:23:41 +00:00
}
});
s->addRow(rowMediaDir);
// Maximum VRAM.
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")));
s->addWithLabel("VRAM LIMIT", maxVram);
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();
}
});
#if !defined(USE_OPENGLES)
// Anti-aliasing (MSAA).
auto antiAliasing = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "ANTI-ALIASING (MSAA)", false);
const std::string& selectedAntiAliasing {
std::to_string(Settings::getInstance()->getInt("AntiAliasing"))};
antiAliasing->add("DISABLED", "0", selectedAntiAliasing == "0");
antiAliasing->add("2X", "2", selectedAntiAliasing == "2");
antiAliasing->add("4X", "4", selectedAntiAliasing == "4");
// 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);
s->addWithLabel("ANTI-ALIASING (MSAA) (REQUIRES RESTART)", antiAliasing);
2023-01-10 21:11:38 +00:00
s->addSaveFunc([antiAliasing, s] {
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>>(
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()));
s->addWithLabel("DISPLAY/MONITOR INDEX (REQUIRES RESTART)", displayIndex);
s->addSaveFunc([displayIndex, s] {
if (atoi(displayIndex->getSelected().c_str()) !=
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();
}
});
// Screen contents rotation.
auto screenRotate =
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "ROTATE SCREEN", false);
const std::string& selectedScreenRotate {
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))};
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");
// 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);
s->addWithLabel("ROTATE SCREEN (REQUIRES RESTART)", screenRotate);
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();
}
});
// Keyboard quit shortcut.
auto keyboardQuitShortcut = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "KEYBOARD QUIT SHORTCUT", false);
std::string selectedShortcut {Settings::getInstance()->getString("KeyboardQuitShortcut")};
2021-08-11 10:09:58 +00:00
#if defined(_WIN64) || defined(__unix__)
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__)
keyboardQuitShortcut->add("\u2318 + Q", "CmdQ", selectedShortcut == "CmdQ");
keyboardQuitShortcut->add("Ctrl + Q", "CtrlQ", selectedShortcut == "CtrlQ");
keyboardQuitShortcut->add("Alt + Q", "AltQ", selectedShortcut == "AltQ");
2021-08-11 10:09:58 +00:00
#endif
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);
s->addWithLabel("KEYBOARD QUIT SHORTCUT", keyboardQuitShortcut);
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();
}
});
// When to save game metadata.
2022-09-03 10:44:49 +00:00
auto saveGamelistsMode = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "WHEN TO SAVE METADATA", false);
std::vector<std::string> saveModes;
saveModes.push_back("on exit");
saveModes.push_back("always");
saveModes.push_back("never");
for (auto it = saveModes.cbegin(); it != saveModes.cend(); ++it) {
2022-09-03 10:44:49 +00:00
saveGamelistsMode->add(*it, *it,
Settings::getInstance()->getString("SaveGamelistsMode") == *it);
}
2022-09-03 10:44:49 +00:00
s->addWithLabel("WHEN TO SAVE GAME METADATA", saveGamelistsMode);
s->addSaveFunc([saveGamelistsMode, s] {
if (saveGamelistsMode->getSelected() !=
Settings::getInstance()->getString("SaveGamelistsMode")) {
Settings::getInstance()->setString("SaveGamelistsMode",
2022-09-03 10:44:49 +00:00
saveGamelistsMode->getSelected());
// Always save the gamelist.xml files if switching to "always" as there may
// be changes that will otherwise be lost.
if (Settings::getInstance()->getString("SaveGamelistsMode") == "always") {
for (auto it = SystemData::sSystemVector.cbegin();
it != SystemData::sSystemVector.cend(); ++it)
(*it)->writeMetaData();
}
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
}
});
#if defined(APPLICATION_UPDATER)
// Application updater frequency.
auto applicationUpdaterFrequency = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "APPLICATION UPDATES", false);
const std::string& selectedUpdaterFrequency {
Settings::getInstance()->getString("ApplicationUpdaterFrequency")};
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");
// 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);
s->addWithLabel("CHECK FOR APPLICATION UPDATES", applicationUpdaterFrequency);
s->addSaveFunc([applicationUpdaterFrequency, s] {
if (applicationUpdaterFrequency->getSelected() !=
Settings::getInstance()->getString("ApplicationUpdaterFrequency")) {
Settings::getInstance()->setString("ApplicationUpdaterFrequency",
applicationUpdaterFrequency->getSelected());
s->setNeedsSaving();
}
});
#endif
#if defined(APPLICATION_UPDATER) && !defined(IS_PRERELEASE)
// Whether to include prereleases when checking for application updates.
auto applicationUpdaterPrereleases = std::make_shared<SwitchComponent>();
applicationUpdaterPrereleases->setState(
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases"));
s->addWithLabel("INCLUDE PRERELEASES IN UPDATE CHECKS", applicationUpdaterPrereleases);
s->addSaveFunc([applicationUpdaterPrereleases, s] {
if (applicationUpdaterPrereleases->getState() !=
Settings::getInstance()->getBool("ApplicationUpdaterPrereleases")) {
Settings::getInstance()->setBool("ApplicationUpdaterPrereleases",
applicationUpdaterPrereleases->getState());
s->setNeedsSaving();
}
});
#endif
#if defined(_WIN64)
// Hide taskbar during the program session.
auto hide_taskbar = std::make_shared<SwitchComponent>();
hide_taskbar->setState(Settings::getInstance()->getBool("HideTaskbar"));
s->addWithLabel("HIDE TASKBAR (REQUIRES RESTART)", hide_taskbar);
2020-11-05 17:18:11 +00:00
s->addSaveFunc([hide_taskbar, s] {
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();
}
});
#endif
// 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"));
s->addWithLabel("RUN IN BACKGROUND (WHILE GAME IS LAUNCHED)", runInBackground);
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();
}
});
#if defined(VIDEO_HW_DECODING)
// 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"));
s->addWithLabel("VIDEO HARDWARE DECODING (EXPERIMENTAL)", videoHardwareDecoding);
s->addSaveFunc([videoHardwareDecoding, s] {
if (videoHardwareDecoding->getState() !=
Settings::getInstance()->getBool("VideoHardwareDecoding")) {
Settings::getInstance()->setBool("VideoHardwareDecoding",
2022-09-03 10:44:49 +00:00
videoHardwareDecoding->getState());
s->setNeedsSaving();
}
});
#endif
// 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"));
s->addWithLabel("UPSCALE VIDEO FRAME RATE TO 60 FPS", videoUpscaleFrameRate);
s->addSaveFunc([videoUpscaleFrameRate, s] {
if (videoUpscaleFrameRate->getState() !=
Settings::getInstance()->getBool("VideoUpscaleFrameRate")) {
Settings::getInstance()->setBool("VideoUpscaleFrameRate",
2022-09-03 10:44:49 +00:00
videoUpscaleFrameRate->getState());
s->setNeedsSaving();
}
});
// Whether to enable alternative emulators per game (the option to disable this is intended
// primarily for testing purposes).
auto alternativeEmulatorPerGame = std::make_shared<SwitchComponent>();
alternativeEmulatorPerGame->setState(
Settings::getInstance()->getBool("AlternativeEmulatorPerGame"));
s->addWithLabel("ENABLE ALTERNATIVE EMULATORS PER GAME", alternativeEmulatorPerGame);
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();
s->setNeedsReloading();
s->setInvalidateCachedBackground();
2020-11-05 17:18:11 +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"));
s->addWithLabel("SHOW HIDDEN FILES AND FOLDERS (REQUIRES RESTART)", showHiddenFiles);
s->addSaveFunc([showHiddenFiles, s] {
if (showHiddenFiles->getState() != Settings::getInstance()->getBool("ShowHiddenFiles")) {
Settings::getInstance()->setBool("ShowHiddenFiles", showHiddenFiles->getState());
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
}
});
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"));
s->addWithLabel("SHOW HIDDEN GAMES (REQUIRES RESTART)", showHiddenGames);
s->addSaveFunc([showHiddenGames, s] {
if (showHiddenGames->getState() != Settings::getInstance()->getBool("ShowHiddenGames")) {
Settings::getInstance()->setBool("ShowHiddenGames", showHiddenGames->getState());
2020-11-05 17:18:11 +00:00
s->setNeedsSaving();
}
});
// 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"));
s->addWithLabel("ENABLE CUSTOM EVENT SCRIPTS", customEventScripts);
s->addSaveFunc([customEventScripts, s] {
if (customEventScripts->getState() !=
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();
}
});
// Only show ROMs 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"));
s->addWithLabel("ONLY SHOW ROMS FROM GAMELIST.XML FILES", parseGamelistOnly);
s->addSaveFunc([parseGamelistOnly, s] {
if (parseGamelistOnly->getState() !=
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();
}
});
// Strip extra MAME name info.
auto mameNameStripExtraInfo = std::make_shared<SwitchComponent>();
mameNameStripExtraInfo->setState(Settings::getInstance()->getBool("MAMENameStripExtraInfo"));
s->addWithLabel("STRIP EXTRA MAME NAME INFO (REQUIRES RESTART)", mameNameStripExtraInfo);
s->addSaveFunc([mameNameStripExtraInfo, s] {
if (Settings::getInstance()->getBool("MAMENameStripExtraInfo") !=
mameNameStripExtraInfo->getState()) {
Settings::getInstance()->setBool("MAMENameStripExtraInfo",
mameNameStripExtraInfo->getState());
s->setNeedsSaving();
}
});
#if defined(__unix__)
// 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"));
s->addWithLabel("DISABLE DESKTOP COMPOSITION (REQUIRES RESTART)", disableComposition);
s->addSaveFunc([disableComposition, s] {
if (disableComposition->getState() !=
Settings::getInstance()->getBool("DisableComposition")) {
2022-09-03 10:44:49 +00:00
Settings::getInstance()->setBool("DisableComposition", disableComposition->getState());
s->setNeedsSaving();
}
});
#endif
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"));
s->addWithLabel("DISPLAY GPU STATISTICS OVERLAY", displayGpuStatistics);
s->addSaveFunc([displayGpuStatistics, s] {
if (displayGpuStatistics->getState() !=
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();
}
});
// 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"));
s->addWithLabel("ENABLE MENU IN KID MODE", enableMenuKidMode);
s->addSaveFunc([enableMenuKidMode, s] {
if (Settings::getInstance()->getBool("EnableMenuKidMode") !=
2022-09-03 10:44:49 +00:00
enableMenuKidMode->getState()) {
Settings::getInstance()->setBool("EnableMenuKidMode", enableMenuKidMode->getState());
s->setNeedsSaving();
2020-11-05 17:18:11 +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.
#if !defined(__APPLE__)
// 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"));
s->addWithLabel("SHOW QUIT MENU (REBOOT AND POWER OFF ENTRIES)", showQuitMenu);
s->addSaveFunc([this, showQuitMenu, s] {
if (showQuitMenu->getState() != Settings::getInstance()->getBool("ShowQuitMenu")) {
Settings::getInstance()->setBool("ShowQuitMenu", showQuitMenu->getState());
s->setNeedsSaving();
GuiMenu::close(false);
2020-11-05 17:18:11 +00:00
}
});
#endif
#if defined(APPLICATION_UPDATER) && !defined(IS_PRERELEASE)
auto applicationUpdaterFrequencyFunc = [applicationUpdaterFrequency,
applicationUpdaterPrereleases](const std::string&) {
if (applicationUpdaterFrequency->getSelected() == "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);
}
};
applicationUpdaterFrequencyFunc(std::string());
applicationUpdaterFrequency->setCallback(applicationUpdaterFrequencyFunc);
#endif
s->setSize(mSize);
mWindow->pushGui(s);
}
void GuiMenu::openQuitMenu()
{
if (!Settings::getInstance()->getBool("ShowQuitMenu")) {
mWindow->pushGui(new GuiMsgBox(
this->getHelpStyle(), "REALLY QUIT?", "YES",
[this] {
close(true);
Utils::Platform::quitES();
},
"NO", nullptr));
}
else {
auto s = new GuiSettings("QUIT");
Window* window {mWindow};
2022-09-03 10:44:49 +00:00
HelpStyle style {getHelpStyle()};
ComponentListRow row;
row.makeAcceptInputHandler([window, this] {
window->pushGui(new GuiMsgBox(
this->getHelpStyle(), "REALLY QUIT?", "YES",
[this] {
close(true);
Utils::Platform::quitES();
},
"NO", nullptr));
});
auto quitText = std::make_shared<TextComponent>("QUIT EMULATIONSTATION",
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
quitText->setSelectable(true);
row.addElement(quitText, true);
s->addRow(row);
row.elements.clear();
row.makeAcceptInputHandler([window, this] {
window->pushGui(new GuiMsgBox(
this->getHelpStyle(), "REALLY REBOOT?", "YES",
[] {
if (Utils::Platform::quitES(Utils::Platform::QuitMode::REBOOT) != 0) {
LOG(LogWarning) << "Reboot terminated with non-zero result!";
}
},
"NO", nullptr));
});
auto rebootText = std::make_shared<TextComponent>("REBOOT SYSTEM",
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
rebootText->setSelectable(true);
row.addElement(rebootText, true);
s->addRow(row);
row.elements.clear();
row.makeAcceptInputHandler([window, this] {
window->pushGui(new GuiMsgBox(
this->getHelpStyle(), "REALLY POWER OFF?", "YES",
[] {
if (Utils::Platform::quitES(Utils::Platform::QuitMode::POWEROFF) != 0) {
LOG(LogWarning) << "Power off terminated with non-zero result!";
}
},
"NO", nullptr));
});
auto powerOffText = std::make_shared<TextComponent>(
"POWER OFF SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
powerOffText->setSelectable(true);
row.addElement(powerOffText, true);
s->addRow(row);
s->setSize(mSize);
mWindow->pushGui(s);
}
}
void GuiMenu::addVersionInfo()
{
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
mVersion.setColor(0x5E5E5EFF);
#if defined(IS_PRERELEASE)
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING) +
" (Built " + __DATE__ + ")");
#else
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING));
#endif
mVersion.setHorizontalAlignment(ALIGN_CENTER);
addChild(&mVersion);
}
2023-02-13 19:38:23 +00:00
void GuiMenu::openThemeDownloader(GuiSettings* settings)
{
mWindow->pushGui(new GuiThemeDownloader());
}
2021-05-16 11:12:31 +00:00
void GuiMenu::openMediaViewerOptions()
{
mWindow->pushGui(new GuiMediaViewerOptions("MEDIA VIEWER SETTINGS"));
2021-05-16 11:12:31 +00:00
}
void GuiMenu::openScreensaverOptions()
{
mWindow->pushGui(new GuiScreensaverOptions("SCREENSAVER SETTINGS"));
}
void GuiMenu::openCollectionSystemOptions()
{
mWindow->pushGui(new GuiCollectionSystemsOptions("GAME COLLECTION SETTINGS"));
}
void GuiMenu::onSizeChanged()
{
mVersion.setSize(mSize.x, 0.0f);
mVersion.setPosition(0.0f, mSize.y - mVersion.getSize().y);
}
void GuiMenu::addEntry(const std::string& name,
unsigned int color,
bool add_arrow,
const std::function<void()>& func)
{
2022-09-03 10:44:49 +00:00
std::shared_ptr<Font> font {Font::get(FONT_SIZE_MEDIUM)};
// Populate the list.
ComponentListRow row;
row.addElement(std::make_shared<TextComponent>(name, font, color), true);
if (add_arrow) {
std::shared_ptr<ImageComponent> bracket {makeArrow()};
row.addElement(bracket, false);
}
row.makeAcceptInputHandler(func);
mMenu.addRow(row);
}
void GuiMenu::close(bool closeAllWindows)
{
std::function<void()> closeFunc;
if (!closeAllWindows) {
closeFunc = [this] { delete this; };
}
else {
Window* window {mWindow};
closeFunc = [window] {
while (window->peekGui() != ViewController::getInstance())
delete window->peekGui();
};
}
closeFunc();
}
bool GuiMenu::input(InputConfig* config, Input input)
{
if (GuiComponent::input(config, input))
return true;
2022-09-03 10:44:49 +00:00
const bool isStart {config->isMappedTo("start", input)};
if (input.value != 0 && (config->isMappedTo("b", input) || isStart)) {
close(isStart);
return true;
}
return false;
}
std::vector<HelpPrompt> GuiMenu::getHelpPrompts()
{
std::vector<HelpPrompt> prompts;
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"));
return prompts;
}