diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 9e59f9c88..dfe881f98 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -344,7 +344,17 @@ void FileData::launchGame(Window* window) // window->deinit(); - std::string command = mEnvData->mLaunchCommand; + std::string command = ""; + + // Check if there is a launch string override for the game and the corresponding option has been set + if(Settings::getInstance()->getBool("LaunchstringOverride") && !metadata.get("launchstring").empty()) + { + command = metadata.get("launchstring"); + } + else + { + command = mEnvData->mLaunchCommand; + } const std::string rom = Utils::FileSystem::getEscapedPath(getPath()); const std::string basename = Utils::FileSystem::getStem(getPath()); diff --git a/es-app/src/MetaData.cpp b/es-app/src/MetaData.cpp index f02207b80..5279ad15c 100644 --- a/es-app/src/MetaData.cpp +++ b/es-app/src/MetaData.cpp @@ -5,37 +5,37 @@ #include MetaDataDecl gameDecls[] = { - // key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd - {"name", MD_STRING, "", false, "name", "enter game name"}, - {"sortname", MD_STRING, "", false, "sortname", "enter game sort name"}, - {"desc", MD_MULTILINE_STRING, "", false, "description", "enter description"}, - {"rating", MD_RATING, "0.000000", false, "rating", "enter rating"}, - {"releasedate", MD_DATE, "not-a-date-time", false, "release date", "enter release date"}, - {"developer", MD_STRING, "unknown", false, "developer", "enter game developer"}, - {"publisher", MD_STRING, "unknown", false, "publisher", "enter game publisher"}, - {"genre", MD_STRING, "unknown", false, "genre", "enter game genre"}, - {"players", MD_INT, "1", false, "players", "enter number of players"}, - {"favorite", MD_BOOL, "false", false, "favorite", "enter favorite off/on"}, - {"completed", MD_BOOL, "false", false, "completed", "enter completed off/on"}, - {"hidden", MD_BOOL, "false", false, "hidden", "enter hidden off/on" }, - {"kidgame", MD_BOOL, "false", false, "kidgame", "enter kidgame off/on" }, - {"launcher", MD_STRING, "", false, "launcher", "enter launcher override"}, - {"playcount", MD_INT, "0", false, "play count", "enter number of times played"}, - {"lastplayed", MD_TIME, "0", true, "last played", "enter last played date"} + // key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd + {"name", MD_STRING, "", false, "name", "enter game name"}, + {"sortname", MD_STRING, "", false, "sortname", "enter game sort name"}, + {"desc", MD_MULTILINE_STRING, "", false, "description", "enter description"}, + {"rating", MD_RATING, "0.000000", false, "rating", "enter rating"}, + {"releasedate", MD_DATE, "not-a-date-time", false, "release date", "enter release date"}, + {"developer", MD_STRING, "unknown", false, "developer", "enter game developer"}, + {"publisher", MD_STRING, "unknown", false, "publisher", "enter game publisher"}, + {"genre", MD_STRING, "unknown", false, "genre", "enter game genre"}, + {"players", MD_INT, "1", false, "players", "enter number of players"}, + {"favorite", MD_BOOL, "false", false, "favorite", "enter favorite off/on"}, + {"completed", MD_BOOL, "false", false, "completed", "enter completed off/on"}, + {"hidden", MD_BOOL, "false", false, "hidden", "enter hidden off/on"}, + {"kidgame", MD_BOOL, "false", false, "kidgame", "enter kidgame off/on"}, + {"launchstring", MD_LAUNCHSTRING, "", false, "launch string", "enter game launch string (emulator override)"}, + {"playcount", MD_INT, "0", false, "play count", "enter number of times played"}, + {"lastplayed", MD_TIME, "0", true, "last played", "enter last played date"} }; const std::vector gameMDD(gameDecls, gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0])); MetaDataDecl folderDecls[] = { - {"name", MD_STRING, "", false, "name", "enter game name"}, - {"sortname", MD_STRING, "", false, "sortname", "enter game sort name"}, - {"desc", MD_MULTILINE_STRING, "", false, "description", "enter description"}, - {"rating", MD_RATING, "0.000000", false, "rating", "enter rating"}, - {"releasedate", MD_DATE, "not-a-date-time", false, "release date", "enter release date"}, - {"developer", MD_STRING, "unknown", false, "developer", "enter game developer"}, - {"publisher", MD_STRING, "unknown", false, "publisher", "enter game publisher"}, - {"genre", MD_STRING, "unknown", false, "genre", "enter game genre"}, - {"players", MD_INT, "1", false, "players", "enter number of players"} + {"name", MD_STRING, "", false, "name", "enter game name"}, + {"sortname", MD_STRING, "", false, "sortname", "enter game sort name"}, + {"desc", MD_MULTILINE_STRING, "", false, "description", "enter description"}, + {"rating", MD_RATING, "0.000000", false, "rating", "enter rating"}, + {"releasedate", MD_DATE, "not-a-date-time", false, "release date", "enter release date"}, + {"developer", MD_STRING, "unknown", false, "developer", "enter game developer"}, + {"publisher", MD_STRING, "unknown", false, "publisher", "enter game publisher"}, + {"genre", MD_STRING, "unknown", false, "genre", "enter game genre"}, + {"players", MD_INT, "1", false, "players", "enter number of players"} }; const std::vector folderMDD(folderDecls, folderDecls + sizeof(folderDecls) / sizeof(folderDecls[0])); diff --git a/es-app/src/MetaData.h b/es-app/src/MetaData.h index 65560c676..489970705 100644 --- a/es-app/src/MetaData.h +++ b/es-app/src/MetaData.h @@ -17,6 +17,7 @@ enum MetaDataType //specialized types MD_MULTILINE_STRING, + MD_LAUNCHSTRING, MD_PATH, MD_RATING, MD_DATE, diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index ffa80742f..0528ec287 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -470,6 +470,12 @@ void GuiMenu::openOtherSettings() s->addWithLabel("SEARCH FOR LOCAL ART", local_art); s->addSaveFunc([local_art] { Settings::getInstance()->setBool("LocalArt", local_art->getState()); }); + // Allow overriding of the launch string per game (the option to disable this is intended primarily for testing purposes) + auto launchstring_override = std::make_shared(mWindow); + launchstring_override->setState(Settings::getInstance()->getBool("LaunchstringOverride")); + s->addWithLabel("PER GAME OVERRIDE OF LAUNCH STRING", launchstring_override); + s->addSaveFunc([launchstring_override] { Settings::getInstance()->setBool("LaunchstringOverride", launchstring_override->getState()); }); + // hidden files auto hidden_files = std::make_shared(mWindow); hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles")); diff --git a/es-app/src/guis/GuiMetaDataEd.cpp b/es-app/src/guis/GuiMetaDataEd.cpp index edfde7355..a05008f35 100644 --- a/es-app/src/guis/GuiMetaDataEd.cpp +++ b/es-app/src/guis/GuiMetaDataEd.cpp @@ -10,6 +10,7 @@ #include "guis/GuiGameScraper.h" #include "guis/GuiMsgBox.h" #include "guis/GuiTextEditPopup.h" +#include "guis/GuiComplexTextEditPopup.h" #include "resources/Font.h" #include "utils/StringUtil.h" #include "views/ViewController.h" @@ -55,6 +56,17 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector if(iter->isStatistic) continue; + // Don't show the launch string override entry if this option has been disabled in the settings + if(!Settings::getInstance()->getBool("LaunchstringOverride") && iter->type == MD_LAUNCHSTRING) + { + ed = std::make_shared(window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT); + assert(ed); + ed->setValue(mMetaData->get(iter->key)); + mEditors.push_back(ed); + + continue; + } + // create ed and add it (and any related components) to mMenu // ed's value will be set below ComponentListRow row; @@ -105,6 +117,32 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector row.addElement(ed, false); break; } + case MD_LAUNCHSTRING: + { + ed = std::make_shared(window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT); + row.addElement(ed, true); + + auto spacer = std::make_shared(mWindow); + spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0); + row.addElement(spacer, false); + + auto bracket = std::make_shared(mWindow); + bracket->setImage(":/arrow.svg"); + bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight())); + row.addElement(bracket, false); + + bool multiLine = false; + const std::string title = iter->displayPrompt; + auto updateVal = [ed](const std::string& newVal) { ed->setValue(newVal); }; // ok callback (apply new value to ed) + + std::string staticTextString = "Default value from es_systems.cfg:"; + std::string defaultLaunchString = scraperParams.system->getSystemEnvData()->mLaunchCommand; + + row.makeAcceptInputHandler([this, title, staticTextString, defaultLaunchString, ed, updateVal, multiLine] { + mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, title, staticTextString, defaultLaunchString, ed->getValue(), updateVal, multiLine)); + }); + break; + } case MD_MULTILINE_STRING: default: { @@ -188,6 +226,7 @@ void GuiMetaDataEd::save() { if(mMetaDataDecl.at(i).isStatistic) continue; + mMetaData->set(mMetaDataDecl.at(i).key, mEditors.at(i)->getValue()); } diff --git a/es-core/CMakeLists.txt b/es-core/CMakeLists.txt index 050305557..6feb9bd5e 100644 --- a/es-core/CMakeLists.txt +++ b/es-core/CMakeLists.txt @@ -54,6 +54,7 @@ set(CORE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.h ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.h ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiComplexTextEditPopup.h # Math ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Misc.h @@ -128,6 +129,7 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiInputConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMsgBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiTextEditPopup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiComplexTextEditPopup.cpp # Math ${CMAKE_CURRENT_SOURCE_DIR}/src/math/Misc.cpp diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index da1ccb1a5..84fd283f4 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -143,6 +143,7 @@ void Settings::setDefaults() mBoolMap["UseCustomCollectionsSystem"] = true; mBoolMap["FavoritesFirst"] = true; + mBoolMap["LaunchstringOverride"] = true; mBoolMap["LocalArt"] = false; diff --git a/es-core/src/guis/GuiComplexTextEditPopup.cpp b/es-core/src/guis/GuiComplexTextEditPopup.cpp new file mode 100644 index 000000000..c3d666ae6 --- /dev/null +++ b/es-core/src/guis/GuiComplexTextEditPopup.cpp @@ -0,0 +1,80 @@ +#include "guis/GuiComplexTextEditPopup.h" + +#include "components/ButtonComponent.h" +#include "components/MenuComponent.h" +#include "components/TextEditComponent.h" + +GuiComplexTextEditPopup::GuiComplexTextEditPopup(Window* window, const std::string& title, const std::string& infoString1, const std::string& infoString2, + const std::string& initValue, const std::function& okCallback, bool multiLine, const char* acceptBtnText) + : GuiComponent(window), mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 5)), mMultiLine(multiLine) +{ + addChild(&mBackground); + addChild(&mGrid); + + mTitle = std::make_shared(mWindow, Utils::String::toUpper(title), Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER); + mInfoString1 = std::make_shared(mWindow, infoString1, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER); + mInfoString2 = std::make_shared(mWindow, infoString2, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER); + + mText = std::make_shared(mWindow); + mText->setValue(initValue); + + if(!multiLine) + mText->setCursor(initValue.size()); + + std::vector< std::shared_ptr > buttons; + buttons.push_back(std::make_shared(mWindow, acceptBtnText, acceptBtnText, [this, okCallback] { okCallback(mText->getValue()); delete this; })); + buttons.push_back(std::make_shared(mWindow, "LOAD", "load default string", [this, infoString2] { mText->setValue(infoString2); })); + buttons.push_back(std::make_shared(mWindow, "CLEAR", "clear string", [this] { mText->setValue(""); })); + buttons.push_back(std::make_shared(mWindow, "CANCEL", "discard changes", [this] { delete this; })); + + mButtonGrid = makeButtonGrid(mWindow, buttons); + + mGrid.setEntry(mTitle, Vector2i(0, 0), false, true); + mGrid.setEntry(mInfoString1, Vector2i(0, 1), false, true); + mGrid.setEntry(mInfoString2, Vector2i(0, 2), false, true); + mGrid.setEntry(mText, Vector2i(0, 3), true, false, Vector2i(1, 1), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM); + mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false); + mGrid.setRowHeightPerc(1, 0.15, true); + + float textHeight = mText->getFont()->getHeight(); + if(multiLine) + textHeight *= 6; + mText->setSize(0, textHeight); + + setSize(Renderer::getScreenWidth() * 0.75f, mTitle->getFont()->getHeight() + textHeight + mButtonGrid->getSize().y() + 220); + setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2); +} + +void GuiComplexTextEditPopup::onSizeChanged() +{ + mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32)); + + mText->setSize(mSize.x() - 40, mText->getSize().y()); + + // update grid + mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y()); + mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y() / mSize.y()); + mGrid.setSize(mSize); +} + +bool GuiComplexTextEditPopup::input(InputConfig* config, Input input) +{ + if(GuiComponent::input(config, input)) + return true; + + // pressing back when not text editing closes us + if(config->isMappedTo("b", input) && input.value) + { + delete this; + return true; + } + + return false; +} + +std::vector GuiComplexTextEditPopup::getHelpPrompts() +{ + std::vector prompts = mGrid.getHelpPrompts(); + prompts.push_back(HelpPrompt("b", "back")); + return prompts; +} diff --git a/es-core/src/guis/GuiComplexTextEditPopup.h b/es-core/src/guis/GuiComplexTextEditPopup.h new file mode 100644 index 000000000..3d1d1a75a --- /dev/null +++ b/es-core/src/guis/GuiComplexTextEditPopup.h @@ -0,0 +1,35 @@ +#pragma once +#ifndef ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H +#define ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H + +#include "components/ComponentGrid.h" +#include "components/NinePatchComponent.h" +#include "GuiComponent.h" + +class TextComponent; +class TextEditComponent; + +class GuiComplexTextEditPopup : public GuiComponent +{ +public: + GuiComplexTextEditPopup(Window* window, const std::string& title, const std::string& infoString1, const std::string& infoString2, + const std::string& initValue, const std::function& okCallback, bool multiLine, const char* acceptBtnText = "OK"); + + bool input(InputConfig* config, Input input); + void onSizeChanged(); + std::vector getHelpPrompts() override; + +private: + NinePatchComponent mBackground; + ComponentGrid mGrid; + + std::shared_ptr mTitle; + std::shared_ptr mInfoString1; + std::shared_ptr mInfoString2; + std::shared_ptr mText; + std::shared_ptr mButtonGrid; + + bool mMultiLine; +}; + +#endif // ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H