GuiSystemSettings::GuiSystemSettings(Window* window) : GuiComponent(window), mMenu(window, "SYSTEM SETTINGS"), mVersion(window) { // SYSTEM SETTINGS // UPDATES > // NETWORK SETTINGS > // STORAGE > // [version] addEntry("SYSTEM UPDATE", 0x777777FF, true, [this, window] { auto s = new GuiSettings(mWindow, "SYSTEM UPDATE"); ComponentListRow row; auto cb = [this] { system("./systemupdate.sh"); SDL_Event ev; ev.type = SDL_QUIT; SDL_PushEvent(&ev); }; row.addElement(std::make_shared<TextComponent>(mWindow, "GET LATEST BINARY", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.makeAcceptInputHandler(cb); s->addRow(row); mWindow->pushGui(s); }); /// Change network settings addEntry("NETWORK SETTINGS", 0x777777FF, true, [this, window] { mWindow->pushGui(new GuiWifi(mWindow)); }); addEntry("EMULATORS", 0x777777FF, true, [this, window] { mWindow->pushGui(new GuiEmulatorList(window)); }); /// See storage on internal memory card. addEntry("STORAGE", 0x777777FF, true, [this] { mWindow->pushGui(new GuiStorageInfo(mWindow)); }); mVersion.setFont(Font::get(FONT_SIZE_SMALL)); mVersion.setColor(0xAAAAFFFF); mVersion.setText("BUILD " + strToUpper(PROGRAM_BUILT_STRING)); mVersion.setAlignment(ALIGN_CENTER); addChild(&mMenu); addChild(&mVersion); setSize(mMenu.getSize()); setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f); }
void GuiSystemSettings::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func) { std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM); // populate the list ComponentListRow row; row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true); if(add_arrow) { std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow); row.addElement(bracket, false); } row.makeAcceptInputHandler(func); mMenu.addRow(row); }
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : GuiComponent(window), mSystem(system), mMenu(window, "OPTIONS") { addChild(&mMenu); // jump to letter char curChar = toupper(getGamelist()->getCursor()->getName()[0]); if(curChar < 'A' || curChar > 'Z') curChar = 'A'; mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO LETTER", false); for(char c = 'A'; c <= 'Z'; c++) mJumpToLetterList->add(std::string(1, c), c, c == curChar); ComponentListRow row; row.addElement(std::make_shared<TextComponent>(mWindow, "JUMP TO LETTER", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.addElement(mJumpToLetterList, false); row.input_handler = [&](InputConfig* config, Input input) { if(config->isMappedTo("a", input) && input.value) { jumpToLetter(); return true; } else if(mJumpToLetterList->input(config, input)) { return true; } return false; }; mMenu.addRow(row); // sort list by mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false); for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) { const FileData::SortType& sort = FileSorts::SortTypes.at(i); mListSort->add(sort.description, &sort, i == system->sortId); } mMenu.addWithLabel("SORT GAMES BY", mListSort); // edit game metadata row.elements.clear(); row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.addElement(makeArrow(mWindow), false); row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this)); mMenu.addRow(row); // center the menu setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2); }
GuiMetaDataEd::GuiMetaDataEd(Window* window, const FileData& file, const std::function<void()>& saveCallback, const std::function<void()>& deleteFunc) : GuiComponent(window), mFile(file), mMetaData(mFile.get_metadata()), mMetaDataDecl(mMetaData.getMDD()), mScraperParams(mFile.getSystem(), mFile), mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 3)), mSavedCallback(saveCallback), mDeleteFunc(deleteFunc) { addChild(&mBackground); addChild(&mGrid); mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5)); mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA", Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER); mSubtitle = std::make_shared<TextComponent>(mWindow, strToUpper(mScraperParams.game.getPath().filename().generic_string()), Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER); mHeaderGrid->setEntry(mTitle, Vector2i(0, 1), false, true); mHeaderGrid->setEntry(mSubtitle, Vector2i(0, 3), false, true); mGrid.setEntry(mHeaderGrid, Vector2i(0, 0), false, true); mList = std::make_shared<ComponentList>(mWindow); mGrid.setEntry(mList, Vector2i(0, 1), true, true); // populate list for(auto iter = mMetaDataDecl.begin(); iter != mMetaDataDecl.end(); iter++) { std::shared_ptr<GuiComponent> ed; // don't add statistics if(iter->isStatistic) continue; // create ed and add it (and any related components) to mMenu // ed's value will be set below ComponentListRow row; auto lbl = std::make_shared<TextComponent>(mWindow, strToUpper(iter->displayName), Font::get(FONT_SIZE_SMALL), 0x777777FF); row.addElement(lbl, true); // label switch(iter->type) { case MD_RATING: { ed = std::make_shared<RatingComponent>(window); const float height = lbl->getSize().y() * 0.71f; ed->setSize(0, height); row.addElement(ed, false, true); auto spacer = std::make_shared<GuiComponent>(mWindow); spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0); row.addElement(spacer, false); // pass input to the actual RatingComponent instead of the spacer row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1, std::placeholders::_2); break; } case MD_DATE: { ed = std::make_shared<DateTimeComponent>(window); row.addElement(ed, false); auto spacer = std::make_shared<GuiComponent>(mWindow); spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0); row.addElement(spacer, false); // pass input to the actual DateTimeComponent instead of the spacer row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1, std::placeholders::_2); break; } case MD_TIME: { ed = std::make_shared<DateTimeComponent>(window, DateTimeComponent::DISP_RELATIVE_TO_NOW); row.addElement(ed, false); break; } case MD_MULTILINE_STRING: default: { // MD_STRING ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT); row.addElement(ed, true); auto spacer = std::make_shared<GuiComponent>(mWindow); spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0); row.addElement(spacer, false); auto bracket = std::make_shared<ImageComponent>(mWindow); bracket->setImage(":/arrow.svg"); bracket->setResize(Eigen::Vector2f(0, lbl->getFont()->getLetterHeight())); row.addElement(bracket, false); bool multiLine = iter->type == MD_MULTILINE_STRING; const std::string title = iter->displayPrompt; auto updateVal = [ed](const std::string& newVal) { ed->setValue(newVal); }; // ok callback (apply new value to ed) row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] { mWindow->pushGui(new GuiTextEditPopup(mWindow, title, ed->getValue(), updateVal, multiLine)); }); break; } } assert(ed); mList->addRow(row); ed->setValue(mMetaData.get(iter->key)); mEditors.push_back(ed); } std::vector< std::shared_ptr<ButtonComponent> > buttons; if(!mScraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SCRAPE", "scrape", std::bind(&GuiMetaDataEd::fetch, this))); buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save", [&] { save(); delete this; })); buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel", [&] { delete this; })); if(mDeleteFunc) { auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; }; auto deleteBtnFunc = [this, deleteFileAndSelf] { mWindow->pushGui(new GuiMsgBox(mWindow, "THIS WILL DELETE A FILE!\nARE YOU SURE?", "YES", deleteFileAndSelf, "NO", nullptr)); }; buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE", "delete", deleteBtnFunc)); } mButtons = makeButtonGrid(mWindow, buttons); mGrid.setEntry(mButtons, Vector2i(0, 2), true, false); // resize + center setSize(Renderer::getScreenWidth() * 0.5f, Renderer::getScreenHeight() * 0.82f); setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2); }
GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll, const std::function<void()>& okCallback) : GuiComponent(window), mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 7)), mTargetConfig(target), mHoldingInput(false), mBusyAnim(window) { LOG(LogInfo) << "Configuring device " << target->getDeviceId() << " (" << target->getDeviceName() << ")."; if(reconfigureAll) target->clear(); mConfiguringAll = reconfigureAll; mConfiguringRow = mConfiguringAll; addChild(&mBackground); addChild(&mGrid); // 0 is a spacer row mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false); mTitle = std::make_shared<TextComponent>(mWindow, "CONFIGURING", Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER); mGrid.setEntry(mTitle, Vector2i(0, 1), false, true); std::stringstream ss; if(target->getDeviceId() == DEVICE_KEYBOARD) ss << "KEYBOARD"; else ss << "GAMEPAD " << (target->getDeviceId() + 1); mSubtitle1 = std::make_shared<TextComponent>(mWindow, strToUpper(ss.str()), Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER); mGrid.setEntry(mSubtitle1, Vector2i(0, 2), false, true); mSubtitle2 = std::make_shared<TextComponent>(mWindow, "HOLD ANY BUTTON TO SKIP", Font::get(FONT_SIZE_SMALL), 0x99999900, ALIGN_CENTER); mGrid.setEntry(mSubtitle2, Vector2i(0, 3), false, true); // 4 is a spacer row mList = std::make_shared<ComponentList>(mWindow); mGrid.setEntry(mList, Vector2i(0, 5), true, true); for(int i = 0; i < inputCount; i++) { ComponentListRow row; // icon auto icon = std::make_shared<ImageComponent>(mWindow); icon->setImage(inputIcon[i]); icon->setColorShift(0x777777FF); icon->setResize(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight() * 1.25f); row.addElement(icon, false); // spacer between icon and text auto spacer = std::make_shared<GuiComponent>(mWindow); spacer->setSize(16, 0); row.addElement(spacer, false); auto text = std::make_shared<TextComponent>(mWindow, inputDispName[i], Font::get(FONT_SIZE_MEDIUM), 0x777777FF); row.addElement(text, true); auto mapping = std::make_shared<TextComponent>(mWindow, "-NOT DEFINED-", Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT), 0x999999FF, ALIGN_RIGHT); setNotDefined(mapping); // overrides text and color set above row.addElement(mapping, true); mMappings.push_back(mapping); row.input_handler = [this, i, mapping](InputConfig* config, Input input) -> bool { // ignore input not from our target device if(config != mTargetConfig) return false; // if we're not configuring, start configuring when A is pressed if(!mConfiguringRow) { if(config->isMappedTo("a", input) && input.value) { mList->stopScrolling(); mConfiguringRow = true; setPress(mapping); return true; } // we're not configuring and they didn't press A to start, so ignore this return false; } // we are configuring if(input.value != 0) { // input down // if we're already holding something, ignore this, otherwise plan to map this input if(mHoldingInput) return true; mHoldingInput = true; mHeldInput = input; mHeldTime = 0; mHeldInputId = i; return true; }else{ // input up // make sure we were holding something and we let go of what we were previously holding if(!mHoldingInput || mHeldInput.device != input.device || mHeldInput.id != input.id || mHeldInput.type != input.type) return true; mHoldingInput = false; if(assign(mHeldInput, i)) rowDone(); // if successful, move cursor/stop configuring - if not, we'll just try again return true; } }; mList->addRow(row); } // only show "HOLD TO SKIP" if this input is skippable mList->setCursorChangedCallback([this](CursorState state) { bool skippable = inputSkippable[mList->getCursorId()]; mSubtitle2->setOpacity(skippable * 255); }); // make the first one say "PRESS ANYTHING" if we're re-configuring everything if(mConfiguringAll) setPress(mMappings.front()); // buttons std::vector< std::shared_ptr<ButtonComponent> > buttons; buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "OK", "ok", [this, okCallback] { InputManager::getInstance()->writeDeviceConfig(mTargetConfig); // save InputManager::getInstance()->doOnFinish(); // execute possible onFinish commands if(okCallback) okCallback(); delete this; })); mButtonGrid = makeButtonGrid(mWindow, buttons); mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false); setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.75f); setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2); }
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : GuiComponent(window), mSystem(system), mMenu(window, "OPTIONS") { LOG(LogDebug) << "GUIGamelistOptions::GuiGamelistOptions()"; addChild(&mMenu); // jump to letter char curChar = toupper(getGamelist()->getCursor()->getName()[0]); if(curChar < 'A' || curChar > 'Z') curChar = 'A'; mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO LETTER", false); for(char c = 'A'; c <= 'Z'; c++) mJumpToLetterList->add(std::string(1, c), c, c == curChar); ComponentListRow row; row.addElement(std::make_shared<TextComponent>(mWindow, "JUMP TO LETTER", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.addElement(mJumpToLetterList, false); row.input_handler = [&](InputConfig* config, Input input) { if(config->isMappedTo("a", input) && input.value) { jumpToLetter(); return true; } else if(mJumpToLetterList->input(config, input)) { return true; } return false; }; mMenu.addRow(row); row.elements.clear(); row.addElement(std::make_shared<TextComponent>(mWindow, "SURPRISE ME!", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.input_handler = [&](InputConfig* config, Input input) { if(config->isMappedTo("a", input) && input.value) { SurpriseMe(); return true; } return false; }; mMenu.addRow(row); // sort list by mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false); for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) { const FileData::SortType& sort = FileSorts::SortTypes.at(i); mListSort->add(sort.description, &sort, i == 0); // TODO - actually make the sort type persistent } mMenu.addWithLabel("SORT GAMES BY", mListSort); // Show favorites-only auto favorite_only = std::make_shared<SwitchComponent>(mWindow); favorite_only->setState(Settings::getInstance()->getBool("FavoritesOnly")); mMenu.addWithLabel("FAVORITES ONLY", favorite_only); addSaveFunc([favorite_only, this] { Settings::getInstance()->setBool("FavoritesOnly", favorite_only->getState()); mFavoriteStateChanged = true; }); // edit game metadata - only in Full UI mode if(Settings::getInstance()->getString("UIMode") == "Full") { row.elements.clear(); row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); row.addElement(makeArrow(mWindow), false); row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this)); mMenu.addRow(row); } // center the menu setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2); }