#include "guis/GuiMenu.h" #include "components/OptionListComponent.h" #include "components/SliderComponent.h" #include "components/SwitchComponent.h" #include "guis/GuiCollectionSystemsOptions.h" #include "guis/GuiDetectDevice.h" #include "guis/GuiGeneralScreensaverOptions.h" #include "guis/GuiMsgBox.h" #include "guis/GuiScraperStart.h" #include "guis/GuiSettings.h" #include "views/UIModeController.h" #include "views/ViewController.h" #include "CollectionSystemManager.h" #include "EmulationStation.h" #include "SystemData.h" #include "VolumeControl.h" #include #include GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MENU"), mVersion(window) { bool isFullUI = UIModeController::getInstance()->isUIModeFull(); if (isFullUI) addEntry("SCRAPER", 0x777777FF, true, [this] { openScraperSettings(); }); addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundSettings(); }); if (isFullUI) addEntry("UI SETTINGS", 0x777777FF, true, [this] { openUISettings(); }); if (isFullUI) addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true, [this] { openCollectionSystemSettings(); }); if (isFullUI) addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherSettings(); }); if (isFullUI) addEntry("CONFIGURE INPUT", 0x777777FF, true, [this] { openConfigInput(); }); addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); }); addChild(&mMenu); addVersionInfo(); setSize(mMenu.getSize()); setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f); } void GuiMenu::openScraperSettings() { auto s = new GuiSettings(mWindow, "SCRAPER"); // scrape from auto scraper_list = std::make_shared< OptionListComponent< std::string > >(mWindow, "SCRAPE FROM", false); std::vector scrapers = getScraperList(); // Select either the first entry of the one read from the settings, just in case the scraper from settings has vanished. for(auto it = scrapers.cbegin(); it != scrapers.cend(); it++) scraper_list->add(*it, *it, *it == Settings::getInstance()->getString("Scraper")); s->addWithLabel("SCRAPE FROM", scraper_list); s->addSaveFunc([scraper_list] { Settings::getInstance()->setString("Scraper", scraper_list->getSelected()); }); // scrape ratings auto scrape_ratings = std::make_shared(mWindow); scrape_ratings->setState(Settings::getInstance()->getBool("ScrapeRatings")); s->addWithLabel("SCRAPE RATINGS", scrape_ratings); s->addSaveFunc([scrape_ratings] { Settings::getInstance()->setBool("ScrapeRatings", scrape_ratings->getState()); }); // scrape now ComponentListRow row; auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); }; std::function openAndSave = openScrapeNow; openAndSave = [s, openAndSave] { s->save(); openAndSave(); }; row.makeAcceptInputHandler(openAndSave); auto scrape_now = std::make_shared(mWindow, "SCRAPE NOW", Font::get(FONT_SIZE_MEDIUM), 0x777777FF); auto bracket = makeArrow(mWindow); row.addElement(scrape_now, true); row.addElement(bracket, false); s->addRow(row); mWindow->pushGui(s); } void GuiMenu::openSoundSettings() { auto s = new GuiSettings(mWindow, "SOUND SETTINGS"); // volume auto volume = std::make_shared(mWindow, 0.f, 100.f, 1.f, "%"); volume->setValue((float)VolumeControl::getInstance()->getVolume()); s->addWithLabel("SYSTEM VOLUME", volume); s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)Math::round(volume->getValue())); }); if (UIModeController::getInstance()->isUIModeFull()) { #if defined(__linux__) // audio card auto audio_card = std::make_shared< OptionListComponent >(mWindow, "AUDIO CARD", false); std::vector audio_cards; #ifdef _RPI_ // RPi Specific Audio Cards audio_cards.push_back("local"); audio_cards.push_back("hdmi"); audio_cards.push_back("both"); #endif audio_cards.push_back("default"); audio_cards.push_back("sysdefault"); audio_cards.push_back("dmix"); audio_cards.push_back("hw"); audio_cards.push_back("plughw"); audio_cards.push_back("null"); if (Settings::getInstance()->getString("AudioCard") != "") { if(std::find(audio_cards.begin(), audio_cards.end(), Settings::getInstance()->getString("AudioCard")) == audio_cards.end()) { audio_cards.push_back(Settings::getInstance()->getString("AudioCard")); } } for(auto ac = audio_cards.cbegin(); ac != audio_cards.cend(); ac++) audio_card->add(*ac, *ac, Settings::getInstance()->getString("AudioCard") == *ac); s->addWithLabel("AUDIO CARD", audio_card); s->addSaveFunc([audio_card] { Settings::getInstance()->setString("AudioCard", audio_card->getSelected()); VolumeControl::getInstance()->deinit(); VolumeControl::getInstance()->init(); }); // volume control device auto vol_dev = std::make_shared< OptionListComponent >(mWindow, "AUDIO DEVICE", false); std::vector transitions; transitions.push_back("PCM"); transitions.push_back("Speaker"); transitions.push_back("Master"); transitions.push_back("Digital"); transitions.push_back("Analogue"); if (Settings::getInstance()->getString("AudioDevice") != "") { if(std::find(transitions.begin(), transitions.end(), Settings::getInstance()->getString("AudioDevice")) == transitions.end()) { transitions.push_back(Settings::getInstance()->getString("AudioDevice")); } } for(auto it = transitions.cbegin(); it != transitions.cend(); it++) vol_dev->add(*it, *it, Settings::getInstance()->getString("AudioDevice") == *it); s->addWithLabel("AUDIO DEVICE", vol_dev); s->addSaveFunc([vol_dev] { Settings::getInstance()->setString("AudioDevice", vol_dev->getSelected()); VolumeControl::getInstance()->deinit(); VolumeControl::getInstance()->init(); }); #endif // disable sounds auto sounds_enabled = std::make_shared(mWindow); sounds_enabled->setState(Settings::getInstance()->getBool("EnableSounds")); s->addWithLabel("ENABLE NAVIGATION SOUNDS", sounds_enabled); s->addSaveFunc([sounds_enabled] { if (sounds_enabled->getState() && !Settings::getInstance()->getBool("EnableSounds") && PowerSaver::getMode() == PowerSaver::INSTANT) { Settings::getInstance()->setString("PowerSaverMode", "default"); PowerSaver::init(); } Settings::getInstance()->setBool("EnableSounds", sounds_enabled->getState()); }); auto video_audio = std::make_shared(mWindow); video_audio->setState(Settings::getInstance()->getBool("VideoAudio")); s->addWithLabel("ENABLE VIDEO AUDIO", video_audio); s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("VideoAudio", video_audio->getState()); }); #ifdef _RPI_ // OMX player Audio Device auto omx_audio_dev = std::make_shared< OptionListComponent >(mWindow, "OMX PLAYER AUDIO DEVICE", false); std::vector omx_cards; // RPi Specific Audio Cards omx_cards.push_back("local"); omx_cards.push_back("hdmi"); omx_cards.push_back("both"); omx_cards.push_back("alsa:hw:0,0"); omx_cards.push_back("alsa:hw:1,0"); if (Settings::getInstance()->getString("OMXAudioDev") != "") { if (std::find(omx_cards.begin(), omx_cards.end(), Settings::getInstance()->getString("OMXAudioDev")) == omx_cards.end()) { omx_cards.push_back(Settings::getInstance()->getString("OMXAudioDev")); } } for (auto it = omx_cards.cbegin(); it != omx_cards.cend(); it++) omx_audio_dev->add(*it, *it, Settings::getInstance()->getString("OMXAudioDev") == *it); s->addWithLabel("OMX PLAYER AUDIO DEVICE", omx_audio_dev); s->addSaveFunc([omx_audio_dev] { if (Settings::getInstance()->getString("OMXAudioDev") != omx_audio_dev->getSelected()) Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected()); }); #endif } mWindow->pushGui(s); } void GuiMenu::openUISettings() { auto s = new GuiSettings(mWindow, "UI SETTINGS"); //UI mode auto UImodeSelection = std::make_shared< OptionListComponent >(mWindow, "UI MODE", false); std::vector UImodes = UIModeController::getInstance()->getUIModes(); for (auto it = UImodes.cbegin(); it != UImodes.cend(); it++) UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it); s->addWithLabel("UI MODE", UImodeSelection); Window* window = mWindow; s->addSaveFunc([ UImodeSelection, window] { std::string selectedMode = UImodeSelection->getSelected(); if (selectedMode != "Full") { std::string msg = "You are changing the UI to a restricted mode:\n" + selectedMode + "\n"; msg += "This will hide most menu-options to prevent changes to the system.\n"; msg += "To unlock and return to the full UI, enter this code: \n"; msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n"; msg += "Do you want to proceed?"; window->pushGui(new GuiMsgBox(window, msg, "YES", [selectedMode] { LOG(LogDebug) << "Setting UI mode to " << selectedMode; Settings::getInstance()->setString("UIMode", selectedMode); Settings::getInstance()->saveFile(); }, "NO",nullptr)); } }); // screensaver ComponentListRow screensaver_row; screensaver_row.elements.clear(); screensaver_row.addElement(std::make_shared(mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); screensaver_row.addElement(makeArrow(mWindow), false); screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this)); s->addRow(screensaver_row); // quick system select (left/right in game list view) auto quick_sys_select = std::make_shared(mWindow); quick_sys_select->setState(Settings::getInstance()->getBool("QuickSystemSelect")); s->addWithLabel("QUICK SYSTEM SELECT", quick_sys_select); s->addSaveFunc([quick_sys_select] { Settings::getInstance()->setBool("QuickSystemSelect", quick_sys_select->getState()); }); // carousel transition option auto move_carousel = std::make_shared(mWindow); move_carousel->setState(Settings::getInstance()->getBool("MoveCarousel")); s->addWithLabel("CAROUSEL TRANSITIONS", move_carousel); s->addSaveFunc([move_carousel] { if (move_carousel->getState() && !Settings::getInstance()->getBool("MoveCarousel") && PowerSaver::getMode() == PowerSaver::INSTANT) { Settings::getInstance()->setString("PowerSaverMode", "default"); PowerSaver::init(); } Settings::getInstance()->setBool("MoveCarousel", move_carousel->getState()); }); // transition style auto transition_style = std::make_shared< OptionListComponent >(mWindow, "TRANSITION STYLE", false); std::vector transitions; transitions.push_back("fade"); transitions.push_back("slide"); transitions.push_back("instant"); for(auto it = transitions.cbegin(); it != transitions.cend(); it++) transition_style->add(*it, *it, Settings::getInstance()->getString("TransitionStyle") == *it); s->addWithLabel("TRANSITION STYLE", transition_style); s->addSaveFunc([transition_style] { if (Settings::getInstance()->getString("TransitionStyle") == "instant" && transition_style->getSelected() != "instant" && PowerSaver::getMode() == PowerSaver::INSTANT) { Settings::getInstance()->setString("PowerSaverMode", "default"); PowerSaver::init(); } Settings::getInstance()->setString("TransitionStyle", transition_style->getSelected()); }); // theme set auto themeSets = ThemeData::getThemeSets(); if(!themeSets.empty()) { std::map::const_iterator selectedSet = themeSets.find(Settings::getInstance()->getString("ThemeSet")); if(selectedSet == themeSets.cend()) selectedSet = themeSets.cbegin(); auto theme_set = std::make_shared< OptionListComponent >(mWindow, "THEME SET", false); for(auto it = themeSets.cbegin(); it != themeSets.cend(); it++) theme_set->add(it->first, it->first, it == selectedSet); s->addWithLabel("THEME SET", theme_set); Window* window = mWindow; s->addSaveFunc([window, theme_set] { bool needReload = false; if(Settings::getInstance()->getString("ThemeSet") != theme_set->getSelected()) needReload = true; Settings::getInstance()->setString("ThemeSet", theme_set->getSelected()); if(needReload) { CollectionSystemManager::get()->updateSystemsList(); ViewController::get()->goToStart(); ViewController::get()->reloadAll(); // TODO - replace this with some sort of signal-based implementation } }); } // GameList view style auto gamelist_style = std::make_shared< OptionListComponent >(mWindow, "GAMELIST VIEW STYLE", false); std::vector styles; styles.push_back("automatic"); styles.push_back("basic"); styles.push_back("detailed"); styles.push_back("video"); styles.push_back("grid"); for (auto it = styles.cbegin(); it != styles.cend(); it++) gamelist_style->add(*it, *it, Settings::getInstance()->getString("GamelistViewStyle") == *it); s->addWithLabel("GAMELIST VIEW STYLE", gamelist_style); s->addSaveFunc([gamelist_style] { bool needReload = false; if (Settings::getInstance()->getString("GamelistViewStyle") != gamelist_style->getSelected()) needReload = true; Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected()); if (needReload) ViewController::get()->reloadAll(); }); // Optionally start in selected system auto systemfocus_list = std::make_shared< OptionListComponent >(mWindow, "START ON SYSTEM", false); systemfocus_list->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == ""); for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); it++) { if ("retropie" != (*it)->getName()) { systemfocus_list->add((*it)->getName(), (*it)->getName(), Settings::getInstance()->getString("StartupSystem") == (*it)->getName()); } } s->addWithLabel("START ON SYSTEM", systemfocus_list); s->addSaveFunc([systemfocus_list] { Settings::getInstance()->setString("StartupSystem", systemfocus_list->getSelected()); }); // show help auto show_help = std::make_shared(mWindow); show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts")); s->addWithLabel("ON-SCREEN HELP", show_help); s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", show_help->getState()); }); // enable filters (ForceDisableFilters) auto enable_filter = std::make_shared(mWindow); enable_filter->setState(!Settings::getInstance()->getBool("ForceDisableFilters")); s->addWithLabel("ENABLE FILTERS", enable_filter); s->addSaveFunc([enable_filter] { bool filter_is_enabled = !Settings::getInstance()->getBool("ForceDisableFilters"); Settings::getInstance()->setBool("ForceDisableFilters", !enable_filter->getState()); if (enable_filter->getState() != filter_is_enabled) ViewController::get()->ReloadAndGoToStart(); }); mWindow->pushGui(s); } void GuiMenu::openOtherSettings() { auto s = new GuiSettings(mWindow, "OTHER SETTINGS"); // maximum vram auto max_vram = std::make_shared(mWindow, 0.f, 1000.f, 10.f, "Mb"); max_vram->setValue((float)(Settings::getInstance()->getInt("MaxVRAM"))); s->addWithLabel("VRAM LIMIT", max_vram); s->addSaveFunc([max_vram] { Settings::getInstance()->setInt("MaxVRAM", (int)Math::round(max_vram->getValue())); }); // power saver auto power_saver = std::make_shared< OptionListComponent >(mWindow, "POWER SAVER MODES", false); std::vector modes; modes.push_back("disabled"); modes.push_back("default"); modes.push_back("enhanced"); modes.push_back("instant"); for (auto it = modes.cbegin(); it != modes.cend(); it++) power_saver->add(*it, *it, Settings::getInstance()->getString("PowerSaverMode") == *it); s->addWithLabel("POWER SAVER MODES", power_saver); s->addSaveFunc([this, power_saver] { if (Settings::getInstance()->getString("PowerSaverMode") != "instant" && power_saver->getSelected() == "instant") { Settings::getInstance()->setString("TransitionStyle", "instant"); Settings::getInstance()->setBool("MoveCarousel", false); Settings::getInstance()->setBool("EnableSounds", false); } Settings::getInstance()->setString("PowerSaverMode", power_saver->getSelected()); PowerSaver::init(); }); // gamelists auto save_gamelists = std::make_shared(mWindow); save_gamelists->setState(Settings::getInstance()->getBool("SaveGamelistsOnExit")); s->addWithLabel("SAVE METADATA ON EXIT", save_gamelists); s->addSaveFunc([save_gamelists] { Settings::getInstance()->setBool("SaveGamelistsOnExit", save_gamelists->getState()); }); auto parse_gamelists = std::make_shared(mWindow); parse_gamelists->setState(Settings::getInstance()->getBool("ParseGamelistOnly")); s->addWithLabel("PARSE GAMESLISTS ONLY", parse_gamelists); s->addSaveFunc([parse_gamelists] { Settings::getInstance()->setBool("ParseGamelistOnly", parse_gamelists->getState()); }); // hidden files auto hidden_files = std::make_shared(mWindow); hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles")); s->addWithLabel("SHOW HIDDEN FILES", hidden_files); s->addSaveFunc([hidden_files] { Settings::getInstance()->setBool("ShowHiddenFiles", hidden_files->getState()); }); #ifdef _RPI_ // Video Player - VideoOmxPlayer auto omx_player = std::make_shared(mWindow); omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer")); s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", omx_player); s->addSaveFunc([omx_player] { // need to reload all views to re-create the right video components bool needReload = false; if(Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState()) needReload = true; Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState()); if(needReload) ViewController::get()->reloadAll(); }); #endif // framerate auto framerate = std::make_shared(mWindow); framerate->setState(Settings::getInstance()->getBool("DrawFramerate")); s->addWithLabel("SHOW FRAMERATE", framerate); s->addSaveFunc([framerate] { Settings::getInstance()->setBool("DrawFramerate", framerate->getState()); }); mWindow->pushGui(s); } void GuiMenu::openConfigInput() { Window* window = mWindow; window->pushGui(new GuiMsgBox(window, "ARE YOU SURE YOU WANT TO CONFIGURE INPUT?", "YES", [window] { window->pushGui(new GuiDetectDevice(window, false, nullptr)); }, "NO", nullptr) ); } void GuiMenu::openQuitMenu() { auto s = new GuiSettings(mWindow, "QUIT"); Window* window = mWindow; ComponentListRow row; if (UIModeController::getInstance()->isUIModeFull()) { row.makeAcceptInputHandler([window] { window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES", [] { if(quitES("/tmp/es-restart") != 0) LOG(LogWarning) << "Restart terminated with non-zero result!"; }, "NO", nullptr)); }); row.addElement(std::make_shared(window, "RESTART EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); s->addRow(row); if(Settings::getInstance()->getBool("ShowExit")) { row.elements.clear(); row.makeAcceptInputHandler([window] { window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES", [] { SDL_Event ev; ev.type = SDL_QUIT; SDL_PushEvent(&ev); }, "NO", nullptr)); }); row.addElement(std::make_shared(window, "QUIT EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); s->addRow(row); } } row.elements.clear(); row.makeAcceptInputHandler([window] { window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES", [] { if (quitES("/tmp/es-sysrestart") != 0) LOG(LogWarning) << "Restart terminated with non-zero result!"; }, "NO", nullptr)); }); row.addElement(std::make_shared(window, "RESTART SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); s->addRow(row); row.elements.clear(); row.makeAcceptInputHandler([window] { window->pushGui(new GuiMsgBox(window, "REALLY SHUTDOWN?", "YES", [] { if (quitES("/tmp/es-shutdown") != 0) LOG(LogWarning) << "Shutdown terminated with non-zero result!"; }, "NO", nullptr)); }); row.addElement(std::make_shared(window, "SHUTDOWN SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); s->addRow(row); mWindow->pushGui(s); } void GuiMenu::addVersionInfo() { std::string buildDate = (Settings::getInstance()->getBool("Debug") ? std::string( " (" + Utils::String::toUpper(PROGRAM_BUILT_STRING) + ")") : ("")); mVersion.setFont(Font::get(FONT_SIZE_SMALL)); mVersion.setColor(0x5E5E5EFF); mVersion.setText("EMULATIONSTATION V" + Utils::String::toUpper(PROGRAM_VERSION_STRING) + buildDate); mVersion.setHorizontalAlignment(ALIGN_CENTER); addChild(&mVersion); } void GuiMenu::openScreensaverOptions() { mWindow->pushGui(new GuiGeneralScreensaverOptions(mWindow, "SCREENSAVER SETTINGS")); } void GuiMenu::openCollectionSystemSettings() { mWindow->pushGui(new GuiCollectionSystemsOptions(mWindow)); } void GuiMenu::onSizeChanged() { mVersion.setSize(mSize.x(), 0); mVersion.setPosition(0, mSize.y() - mVersion.getSize().y()); } void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function& func) { std::shared_ptr font = Font::get(FONT_SIZE_MEDIUM); // populate the list ComponentListRow row; row.addElement(std::make_shared(mWindow, name, font, color), true); if(add_arrow) { std::shared_ptr bracket = makeArrow(mWindow); row.addElement(bracket, false); } row.makeAcceptInputHandler(func); mMenu.addRow(row); } bool GuiMenu::input(InputConfig* config, Input input) { if(GuiComponent::input(config, input)) return true; if((config->isMappedTo("b", input) || config->isMappedTo("start", input)) && input.value != 0) { delete this; return true; } return false; } HelpStyle GuiMenu::getHelpStyle() { HelpStyle style = HelpStyle(); style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system"); return style; } std::vector GuiMenu::getHelpPrompts() { std::vector prompts; prompts.push_back(HelpPrompt("up/down", "choose")); prompts.push_back(HelpPrompt("a", "select")); prompts.push_back(HelpPrompt("start", "close")); return prompts; }