mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 15:45:38 +00:00
Added support for launching game files inside folders without having to enter the folder.
This commit is contained in:
parent
9c485aeef8
commit
45af7441e9
|
@ -23,6 +23,7 @@
|
|||
#include "utils/PlatformUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "views/GamelistView.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -1233,12 +1234,19 @@ void FileData::launchGame()
|
|||
// Update number of times the game has been launched.
|
||||
FileData* gameToUpdate = getSourceFileData();
|
||||
|
||||
int timesPlayed = gameToUpdate->metadata.getInt("playcount") + 1;
|
||||
int timesPlayed {gameToUpdate->metadata.getInt("playcount") + 1};
|
||||
gameToUpdate->metadata.set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
|
||||
|
||||
// Update last played time.
|
||||
gameToUpdate->metadata.set("lastplayed", Utils::Time::DateTime(Utils::Time::now()));
|
||||
|
||||
// If the cursor is a folder, the "launch file" functionality must have been used, so set
|
||||
// the lastplayed timestamp for this folder to the same as the launched game.
|
||||
FileData* cursor {
|
||||
ViewController::getInstance()->getGamelistView(gameToUpdate->getSystem())->getCursor()};
|
||||
if (cursor->getType() == FOLDER)
|
||||
cursor->metadata.set("lastplayed", gameToUpdate->metadata.get("lastplayed"));
|
||||
|
||||
// If the parent is a folder and it's not the root of the system, then update its lastplayed
|
||||
// timestamp to the same time as the game that was just launched.
|
||||
if (gameToUpdate->getParent()->getType() == FOLDER &&
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace
|
|||
// The statistic entries must be placed at the bottom or otherwise there will be problems with
|
||||
// saving the values in GuiMetaDataEd.
|
||||
MetaDataDecl gameDecls[] {
|
||||
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape
|
||||
// Key Type Default value Statistic Name in GuiMetaDataEd Prompt in GuiMetaDataEd Scrape
|
||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
||||
{"sortname", MD_STRING, "", false, "sortname", "enter sortname", false},
|
||||
{"collectionsortname", MD_STRING, "", false, "custom collections sortname", "enter collections sortname", false},
|
||||
|
@ -46,6 +46,7 @@ namespace
|
|||
};
|
||||
|
||||
MetaDataDecl folderDecls[] {
|
||||
// Key Type Default value Statistic Name in GuiMetaDataEd Prompt in GuiMetaDataEd Scrape
|
||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
||||
{"desc", MD_MULTILINE_STRING, "", false, "description", "enter description", true},
|
||||
{"rating", MD_RATING, "0", false, "rating", "enter rating", true},
|
||||
|
@ -62,6 +63,7 @@ namespace
|
|||
{"nomultiscrape", MD_BOOL, "false", false, "exclude from multi-scraper", "enter no multi-scrape off/on", false},
|
||||
{"hidemetadata", MD_BOOL, "false", false, "hide metadata fields", "enter hide metadata off/on", false},
|
||||
{"controller", MD_CONTROLLER, "", false, "controller", "select controller", true},
|
||||
{"launchfile", MD_LAUNCH_FILE, "", false, "launch file", "select launch file", false},
|
||||
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date", false}
|
||||
};
|
||||
// clang-format on
|
||||
|
|
|
@ -34,6 +34,7 @@ enum MetaDataType {
|
|||
MD_MULTILINE_STRING,
|
||||
MD_CONTROLLER,
|
||||
MD_ALT_EMULATOR,
|
||||
MD_LAUNCH_FILE,
|
||||
MD_PATH,
|
||||
MD_RATING,
|
||||
MD_DATE,
|
||||
|
|
|
@ -212,12 +212,28 @@ void Screensaver::nextGame()
|
|||
void Screensaver::launchGame()
|
||||
{
|
||||
if (mCurrentGame != nullptr) {
|
||||
// If the game is inside a folder where a "launch file" entry is present, then jump to
|
||||
// that folder instead of to the actual game file. Also check the complete hierarchy in
|
||||
// case launch file entries are set on multiple levels of the folder structure.
|
||||
FileData* entry {mCurrentGame};
|
||||
FileData* selectGame {mCurrentGame};
|
||||
FileData* launchFolder {nullptr};
|
||||
|
||||
while (entry != nullptr) {
|
||||
entry = entry->getParent();
|
||||
if (entry != nullptr && entry->metadata.get("launchfile") != "")
|
||||
launchFolder = entry;
|
||||
}
|
||||
|
||||
if (launchFolder != nullptr)
|
||||
selectGame = launchFolder;
|
||||
|
||||
// Launching game
|
||||
ViewController::getInstance()->triggerGameLaunch(mCurrentGame);
|
||||
ViewController::getInstance()->goToGamelist(mCurrentGame->getSystem());
|
||||
GamelistView* view {
|
||||
ViewController::getInstance()->getGamelistView(mCurrentGame->getSystem()).get()};
|
||||
view->setCursor(mCurrentGame);
|
||||
view->setCursor(selectGame);
|
||||
view->stopListScrolling();
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
ViewController::getInstance()->pauseViewVideos();
|
||||
|
@ -227,6 +243,18 @@ void Screensaver::launchGame()
|
|||
void Screensaver::goToGame()
|
||||
{
|
||||
if (mCurrentGame != nullptr) {
|
||||
FileData* entry {mCurrentGame};
|
||||
FileData* launchFolder {nullptr};
|
||||
|
||||
while (entry != nullptr) {
|
||||
entry = entry->getParent();
|
||||
if (entry != nullptr && entry->metadata.get("launchfile") != "")
|
||||
launchFolder = entry;
|
||||
}
|
||||
|
||||
if (launchFolder != nullptr)
|
||||
mCurrentGame = launchFolder;
|
||||
|
||||
// Go to the game in the gamelist view, but don't launch it.
|
||||
ViewController::getInstance()->goToGamelist(mCurrentGame->getSystem());
|
||||
GamelistView* view {
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
// metadata edit interface is covered by GuiMetaDataEd.
|
||||
//
|
||||
|
||||
#if defined(_WIN64)
|
||||
// Why this is needed here is anyone's guess but without it the compilation fails.
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include "GuiGamelistOptions.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
|
@ -33,6 +38,7 @@ GuiGamelistOptions::GuiGamelistOptions(SystemData* system)
|
|||
, mCancelled {false}
|
||||
, mIsCustomCollection {false}
|
||||
, mIsCustomCollectionGroup {false}
|
||||
, mLaunchFileOverride {false}
|
||||
, mCustomCollectionSystem {nullptr}
|
||||
{
|
||||
addChild(&mMenu);
|
||||
|
@ -228,6 +234,19 @@ GuiGamelistOptions::GuiGamelistOptions(SystemData* system)
|
|||
}
|
||||
}
|
||||
|
||||
if (file->getType() == FOLDER && file->metadata.get("launchfile") != "") {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>("ENTER FOLDER (OVERRIDE LAUNCH FILE)",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.makeAcceptInputHandler([this, file] {
|
||||
mLaunchFileOverride = true;
|
||||
getGamelist()->enterDirectory(file);
|
||||
delete this;
|
||||
});
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
||||
// Buttons. The logic to apply or cancel settings are handled by the destructor.
|
||||
if ((!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() == 0) ||
|
||||
system->getName() == "recent") {
|
||||
|
@ -308,7 +327,8 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
|||
}
|
||||
}
|
||||
|
||||
if (mSystem->getRootFolder()->getChildren().size() != 0 && mSystem->getName() != "recent")
|
||||
if (mSystem->getRootFolder()->getChildren().size() != 0 && mSystem->getName() != "recent" &&
|
||||
!mLaunchFileOverride)
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ private:
|
|||
bool mCancelled;
|
||||
bool mIsCustomCollection;
|
||||
bool mIsCustomCollectionGroup;
|
||||
bool mLaunchFileOverride;
|
||||
SystemData* mCustomCollectionSystem;
|
||||
std::vector<std::string> mFirstLetterIndex;
|
||||
std::string mCurrentFirstCharacter;
|
||||
|
|
|
@ -52,6 +52,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
, mMediaFilesUpdated {false}
|
||||
, mSavedMediaAndAborted {false}
|
||||
, mInvalidEmulatorEntry {false}
|
||||
, mInvalidLaunchFileEntry {false}
|
||||
{
|
||||
if (ViewController::getInstance()->getState().getSystem()->isCustomCollection() ||
|
||||
ViewController::getInstance()->getState().getSystem()->getThemeFolder() ==
|
||||
|
@ -70,9 +71,9 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true, glm::ivec2 {2, 2});
|
||||
|
||||
// Extract possible subfolders from the path.
|
||||
std::string folderPath =
|
||||
std::string folderPath {
|
||||
Utils::String::replace(Utils::FileSystem::getParent(scraperParams.game->getPath()),
|
||||
scraperParams.system->getSystemEnvData()->mStartPath, "");
|
||||
scraperParams.system->getSystemEnvData()->mStartPath, "")};
|
||||
|
||||
if (folderPath.size() >= 2) {
|
||||
folderPath.erase(0, 1);
|
||||
|
@ -112,8 +113,8 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
// Populate list.
|
||||
for (auto it = mdd.cbegin(); it != mdd.cend(); ++it) {
|
||||
std::shared_ptr<GuiComponent> ed;
|
||||
std::string currentKey = it->key;
|
||||
std::string originalValue = mMetaData->get(it->key);
|
||||
std::string currentKey {it->key};
|
||||
std::string originalValue {mMetaData->get(it->key)};
|
||||
std::string gamePath;
|
||||
|
||||
// Only display the custom collections sortname entry if we're editing the game
|
||||
|
@ -162,7 +163,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
|
||||
ed = std::make_shared<RatingComponent>(true);
|
||||
ed->setChangedColor(ICONCOLOR_USERMARKED);
|
||||
const float height = lbl->getSize().y * 0.71f;
|
||||
const float height {lbl->getSize().y * 0.71f};
|
||||
ed->setSize(0.0f, height);
|
||||
row.addElement(ed, false, true);
|
||||
|
||||
|
@ -200,7 +201,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
bracket->setResize(glm::vec2 {0.0f, lbl->getFont()->getLetterHeight()});
|
||||
row.addElement(bracket, false);
|
||||
|
||||
const std::string title = it->displayPrompt;
|
||||
const std::string title {it->displayPrompt};
|
||||
|
||||
// OK callback (apply new value to ed).
|
||||
auto updateVal = [ed, originalValue](const std::string& newVal) {
|
||||
|
@ -212,15 +213,15 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
};
|
||||
|
||||
row.makeAcceptInputHandler([this, title, ed, updateVal] {
|
||||
GuiSettings* s = new GuiSettings(title);
|
||||
GuiSettings* s {new GuiSettings(title)};
|
||||
|
||||
for (auto controller : mControllerBadges) {
|
||||
std::string selectedLabel = ed->getValue();
|
||||
std::string selectedLabel {ed->getValue()};
|
||||
std::string label;
|
||||
ComponentListRow row;
|
||||
|
||||
std::shared_ptr<TextComponent> labelText = std::make_shared<TextComponent>(
|
||||
label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
std::shared_ptr<TextComponent> labelText {std::make_shared<TextComponent>(
|
||||
label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF)};
|
||||
labelText->setSelectable(true);
|
||||
labelText->setValue(controller.displayName);
|
||||
|
||||
|
@ -243,9 +244,9 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
// If a value is set, then display "Clear entry" as the last entry.
|
||||
if (ed->getValue() != "") {
|
||||
ComponentListRow row;
|
||||
std::shared_ptr<TextComponent> clearText = std::make_shared<TextComponent>(
|
||||
std::shared_ptr<TextComponent> clearText {std::make_shared<TextComponent>(
|
||||
ViewController::CROSSEDCIRCLE_CHAR + " CLEAR ENTRY",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF)};
|
||||
clearText->setSelectable(true);
|
||||
row.addElement(clearText, true);
|
||||
row.makeAcceptInputHandler([s, ed] {
|
||||
|
@ -282,7 +283,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
bracket->setResize(glm::vec2 {0.0f, lbl->getFont()->getLetterHeight()});
|
||||
row.addElement(bracket, false);
|
||||
|
||||
const std::string title = it->displayPrompt;
|
||||
const std::string title {it->displayPrompt};
|
||||
|
||||
// OK callback (apply new value to ed).
|
||||
auto updateVal = [this, ed, originalValue](const std::string& newVal) {
|
||||
|
@ -313,10 +314,10 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
scraperParams.system->getSystemEnvData()->mLaunchCommands.size() > 1) {
|
||||
row.makeAcceptInputHandler([this, title, scraperParams, ed, updateVal,
|
||||
originalValue] {
|
||||
GuiSettings* s = nullptr;
|
||||
GuiSettings* s {nullptr};
|
||||
|
||||
bool singleEntry =
|
||||
scraperParams.system->getSystemEnvData()->mLaunchCommands.size() == 1;
|
||||
bool singleEntry {
|
||||
scraperParams.system->getSystemEnvData()->mLaunchCommands.size() == 1};
|
||||
|
||||
if (mInvalidEmulatorEntry && singleEntry)
|
||||
s = new GuiSettings("CLEAR INVALID ENTRY");
|
||||
|
@ -326,8 +327,8 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
if (!mInvalidEmulatorEntry && ed->getValue() == "" && singleEntry)
|
||||
return;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> launchCommands =
|
||||
scraperParams.system->getSystemEnvData()->mLaunchCommands;
|
||||
std::vector<std::pair<std::string, std::string>> launchCommands {
|
||||
scraperParams.system->getSystemEnvData()->mLaunchCommands};
|
||||
|
||||
if (ed->getValue() != "" && mInvalidEmulatorEntry && singleEntry)
|
||||
launchCommands.push_back(std::make_pair(
|
||||
|
@ -342,7 +343,7 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
ViewController::EXCLAMATION_CHAR + " " + originalValue)
|
||||
continue;
|
||||
|
||||
std::string selectedLabel = ed->getValue();
|
||||
std::string selectedLabel {ed->getValue()};
|
||||
std::string label;
|
||||
ComponentListRow row;
|
||||
|
||||
|
@ -351,9 +352,9 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
else
|
||||
label = entry.second;
|
||||
|
||||
std::shared_ptr<TextComponent> labelText =
|
||||
std::shared_ptr<TextComponent> labelText {
|
||||
std::make_shared<TextComponent>(label, Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF);
|
||||
0x777777FF)};
|
||||
labelText->setSelectable(true);
|
||||
|
||||
if (scraperParams.system->getAlternativeEmulator() == "" &&
|
||||
|
@ -404,6 +405,110 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MD_LAUNCH_FILE: {
|
||||
ed = std::make_shared<TextComponent>(
|
||||
"", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
row.addElement(ed, true);
|
||||
|
||||
auto spacer = std::make_shared<GuiComponent>();
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0.0f);
|
||||
row.addElement(spacer, false);
|
||||
|
||||
auto bracket = std::make_shared<ImageComponent>();
|
||||
bracket->setImage(":/graphics/arrow.svg");
|
||||
bracket->setResize(glm::vec2 {0.0f, lbl->getFont()->getLetterHeight()});
|
||||
row.addElement(bracket, false);
|
||||
|
||||
const std::string title {it->displayPrompt};
|
||||
|
||||
std::vector<FileData*> children;
|
||||
if (originalValue != "")
|
||||
mInvalidLaunchFileEntry = true;
|
||||
|
||||
for (auto child : mScraperParams.game->getChildrenRecursive()) {
|
||||
if (child->getType() == GAME && child->getCountAsGame() &&
|
||||
!child->getHidden()) {
|
||||
children.emplace_back(child);
|
||||
std::string filePath {child->getPath()};
|
||||
std::string systemPath {child->getSystem()->getRootFolder()->getPath() +
|
||||
"/" + mScraperParams.game->getFileName() + "/"};
|
||||
if (Utils::String::replace(filePath, systemPath, "") == originalValue)
|
||||
mInvalidLaunchFileEntry = false;
|
||||
}
|
||||
}
|
||||
|
||||
// OK callback (apply new value to ed).
|
||||
auto updateVal = [this, ed, originalValue](const std::string& newVal) {
|
||||
mInvalidLaunchFileEntry = false;
|
||||
ed->setValue(newVal);
|
||||
if (newVal == originalValue)
|
||||
ed->setColor(DEFAULT_TEXTCOLOR);
|
||||
else
|
||||
ed->setColor(TEXTCOLOR_USERMARKED);
|
||||
};
|
||||
|
||||
row.makeAcceptInputHandler([this, children, title, ed, updateVal] {
|
||||
GuiSettings* s {new GuiSettings(title)};
|
||||
|
||||
for (auto child : children) {
|
||||
std::string selectedLabel {ed->getValue()};
|
||||
std::string label;
|
||||
ComponentListRow row;
|
||||
|
||||
std::string filePath {child->getPath()};
|
||||
std::string systemPath {child->getSystem()->getRootFolder()->getPath() +
|
||||
"/" + mScraperParams.game->getFileName() + "/"};
|
||||
|
||||
filePath = Utils::String::replace(filePath, systemPath, "");
|
||||
|
||||
std::shared_ptr<TextComponent> labelText {std::make_shared<TextComponent>(
|
||||
label, Font::get(FONT_SIZE_MEDIUM), 0x777777FF)};
|
||||
labelText->setSelectable(true);
|
||||
labelText->setValue(filePath);
|
||||
|
||||
label = filePath;
|
||||
|
||||
row.addElement(labelText, true);
|
||||
|
||||
row.makeAcceptInputHandler([s, updateVal, filePath] {
|
||||
updateVal(filePath);
|
||||
delete s;
|
||||
});
|
||||
|
||||
// Select the row that corresponds to the selected label.
|
||||
if (selectedLabel == label)
|
||||
s->addRow(row, true);
|
||||
else
|
||||
s->addRow(row, false);
|
||||
}
|
||||
|
||||
// If a value is set, then display "Clear entry" as the last entry.
|
||||
if (ed->getValue() != "") {
|
||||
ComponentListRow row;
|
||||
std::shared_ptr<TextComponent> clearText {std::make_shared<TextComponent>(
|
||||
ViewController::CROSSEDCIRCLE_CHAR + " CLEAR ENTRY",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF)};
|
||||
clearText->setSelectable(true);
|
||||
row.addElement(clearText, true);
|
||||
row.makeAcceptInputHandler([this, s, ed] {
|
||||
mInvalidLaunchFileEntry = false;
|
||||
ed->setValue("");
|
||||
delete s;
|
||||
});
|
||||
s->addRow(row, false);
|
||||
}
|
||||
|
||||
float aspectValue {1.778f / Renderer::getScreenAspectRatio()};
|
||||
float maxWidthModifier {glm::clamp(0.64f * aspectValue, 0.42f, 0.92f)};
|
||||
float maxWidth {Renderer::getScreenWidth() * maxWidthModifier};
|
||||
|
||||
s->setMenuSize(glm::vec2 {maxWidth, s->getMenuSize().y});
|
||||
s->setMenuPosition(
|
||||
glm::vec3 {(s->getSize().x - maxWidth) / 2.0f, mPosition.y, mPosition.z});
|
||||
mWindow->pushGui(s);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MD_MULTILINE_STRING:
|
||||
default: {
|
||||
// MD_STRING.
|
||||
|
@ -420,8 +525,8 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
bracket->setResize(glm::vec2 {0.0f, lbl->getFont()->getLetterHeight()});
|
||||
row.addElement(bracket, false);
|
||||
|
||||
bool multiLine = it->type == MD_MULTILINE_STRING;
|
||||
const std::string title = it->displayPrompt;
|
||||
bool multiLine {it->type == MD_MULTILINE_STRING};
|
||||
const std::string title {it->displayPrompt};
|
||||
|
||||
gamePath = Utils::FileSystem::getStem(mScraperParams.game->getPath());
|
||||
|
||||
|
@ -488,11 +593,14 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
assert(ed);
|
||||
mList->addRow(row);
|
||||
|
||||
if (it->type == MD_ALT_EMULATOR && mInvalidEmulatorEntry == true) {
|
||||
if (it->type == MD_ALT_EMULATOR && mInvalidEmulatorEntry) {
|
||||
ed->setValue(ViewController::EXCLAMATION_CHAR + " " + originalValue);
|
||||
}
|
||||
else if (it->type == MD_LAUNCH_FILE && mInvalidLaunchFileEntry) {
|
||||
ed->setValue(ViewController::EXCLAMATION_CHAR + " " + originalValue);
|
||||
}
|
||||
else if (it->type == MD_CONTROLLER && mMetaData->get(it->key) != "") {
|
||||
std::string displayName = BadgeComponent::getDisplayName(mMetaData->get(it->key));
|
||||
std::string displayName {BadgeComponent::getDisplayName(mMetaData->get(it->key))};
|
||||
if (displayName != "unknown")
|
||||
ed->setValue(displayName);
|
||||
else
|
||||
|
@ -639,6 +747,9 @@ void GuiMetaDataEd::save()
|
|||
if (key == "altemulator" && mInvalidEmulatorEntry == true)
|
||||
continue;
|
||||
|
||||
if (key == "launchfile" && mInvalidLaunchFileEntry)
|
||||
continue;
|
||||
|
||||
if (key == "controller" && mEditors.at(i)->getValue() != "") {
|
||||
std::string shortName = BadgeComponent::getShortName(mEditors.at(i)->getValue());
|
||||
if (shortName != "unknown")
|
||||
|
@ -807,7 +918,10 @@ void GuiMetaDataEd::close()
|
|||
|
||||
const std::string& key {mMetaDataDecl.at(i + offset).key};
|
||||
|
||||
if (key == "altemulator" && mInvalidEmulatorEntry == true)
|
||||
if (key == "altemulator" && mInvalidEmulatorEntry)
|
||||
continue;
|
||||
|
||||
if (key == "launchfile" && mInvalidLaunchFileEntry)
|
||||
continue;
|
||||
|
||||
std::string mMetaDataValue {mMetaData->get(key)};
|
||||
|
|
|
@ -73,6 +73,7 @@ private:
|
|||
bool mMediaFilesUpdated;
|
||||
bool mSavedMediaAndAborted;
|
||||
bool mInvalidEmulatorEntry;
|
||||
bool mInvalidLaunchFileEntry;
|
||||
};
|
||||
|
||||
#endif // ES_APP_GUIS_GUI_META_DATA_ED_H
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
// Gamelist base class with utility functions and other low-level logic.
|
||||
//
|
||||
|
||||
#if defined(_WIN64)
|
||||
// Why this is needed here is anyone's guess but without it the compilation fails.
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include "views/GamelistBase.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
|
@ -73,12 +78,33 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
// It's a folder.
|
||||
if (cursor->getChildren().size() > 0) {
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
// If a "launch file" entry has been set on the folder, then check if it
|
||||
// corresponds to an actual child entry, and if so then launch this child
|
||||
// instead of entering the folder.
|
||||
if (!CollectionSystemsManager::getInstance()->isEditing() &&
|
||||
cursor->metadata.get("launchfile") != "") {
|
||||
std::string launchFile;
|
||||
launchFile.append(cursor->getPath())
|
||||
.append("/")
|
||||
.append(Utils::String::replace(cursor->metadata.get("launchfile"), "\\",
|
||||
"/"));
|
||||
for (auto child : cursor->getChildrenRecursive()) {
|
||||
if (child->getPath() == launchFile) {
|
||||
pauseViewVideos();
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
stopListScrolling();
|
||||
launch(child);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(SELECTSOUND);
|
||||
mCursorStack.push(cursor);
|
||||
populateList(cursor->getChildrenListToDisplay(), cursor);
|
||||
|
||||
FileData* newCursor {nullptr};
|
||||
std::vector<FileData*> listEntries = cursor->getChildrenListToDisplay();
|
||||
std::vector<FileData*> listEntries {cursor->getChildrenListToDisplay()};
|
||||
// Check if there is an entry in the cursor stack history matching any entry
|
||||
// in the currect folder. If so, select that entry.
|
||||
for (auto it = mCursorStackHistory.begin(); // Line break.
|
||||
|
@ -469,6 +495,41 @@ bool GamelistBase::input(InputConfig* config, Input input)
|
|||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
void GamelistBase::enterDirectory(FileData* cursor)
|
||||
{
|
||||
assert(cursor->getType() == FOLDER);
|
||||
|
||||
if (cursor->getChildren().size() > 0) {
|
||||
ViewController::getInstance()->cancelViewTransitions();
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(SELECTSOUND);
|
||||
mCursorStack.push(cursor);
|
||||
populateList(cursor->getChildrenListToDisplay(), cursor);
|
||||
|
||||
FileData* newCursor {nullptr};
|
||||
std::vector<FileData*> listEntries = cursor->getChildrenListToDisplay();
|
||||
// Check if there is an entry in the cursor stack history matching any entry
|
||||
// in the currect folder. If so, select that entry.
|
||||
for (auto it = mCursorStackHistory.begin(); it != mCursorStackHistory.end(); ++it) {
|
||||
if (std::find(listEntries.begin(), listEntries.end(), *it) != listEntries.end()) {
|
||||
newCursor = *it;
|
||||
mCursorStackHistory.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there was no match in the cursor history, simply select the first entry.
|
||||
if (!newCursor)
|
||||
newCursor = getCursor();
|
||||
setCursor(newCursor);
|
||||
stopListScrolling();
|
||||
if (mRoot->getSystem()->getThemeFolder() == "custom-collections")
|
||||
updateHelpPrompts();
|
||||
}
|
||||
else {
|
||||
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||
}
|
||||
}
|
||||
|
||||
void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* firstEntry)
|
||||
{
|
||||
mFirstGameEntry = nullptr;
|
||||
|
@ -537,10 +598,18 @@ void GamelistBase::populateList(const std::vector<FileData*>& files, FileData* f
|
|||
}
|
||||
else if ((*it)->getType() == FOLDER &&
|
||||
mRoot->getSystem()->getName() != "collections") {
|
||||
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
||||
name = "# " + (*it)->getName();
|
||||
else
|
||||
name = ViewController::FOLDER_CHAR + " " + (*it)->getName();
|
||||
if (Settings::getInstance()->getBool("SpecialCharsASCII")) {
|
||||
if ((*it)->metadata.get("launchfile") != "")
|
||||
name = "> " + (*it)->getName();
|
||||
else
|
||||
name = "# " + (*it)->getName();
|
||||
}
|
||||
else {
|
||||
if ((*it)->metadata.get("launchfile") != "")
|
||||
name = ViewController::FOLDERLINK_CHAR + " " + (*it)->getName();
|
||||
else
|
||||
name = ViewController::FOLDER_CHAR + " " + (*it)->getName();
|
||||
}
|
||||
}
|
||||
else {
|
||||
name = inCollectionPrefix + (*it)->getName();
|
||||
|
|
|
@ -34,6 +34,7 @@ public:
|
|||
void setCursor(FileData*);
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void enterDirectory(FileData* cursor);
|
||||
|
||||
FileData* getNextEntry() { return mPrimary->getNext(); }
|
||||
FileData* getPreviousEntry() { return mPrimary->getPrevious(); }
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#define ES_APP_VIEWS_GAMELIST_VIEW_H
|
||||
|
||||
#include "views/GamelistBase.h"
|
||||
|
||||
#include "renderers/Renderer.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
class GamelistView : public GamelistBase
|
||||
|
|
|
@ -132,6 +132,7 @@ public:
|
|||
static inline const std::string FAVORITE_CHAR {Utils::String::wideStringToString(L"\uf005")};
|
||||
static inline const std::string FILTER_CHAR {Utils::String::wideStringToString(L"\uf0b0")};
|
||||
static inline const std::string FOLDER_CHAR {Utils::String::wideStringToString(L"\uf07C")};
|
||||
static inline const std::string FOLDERLINK_CHAR {Utils::String::wideStringToString(L"\uf090")};
|
||||
static inline const std::string GEAR_CHAR {Utils::String::wideStringToString(L"\uf013")};
|
||||
static inline const std::string KEYBOARD_CHAR {Utils::String::wideStringToString(L"\uf11c")};
|
||||
static inline const std::string TICKMARK_CHAR {Utils::String::wideStringToString(L"\uf14A")};
|
||||
|
@ -142,6 +143,7 @@ public:
|
|||
static inline const std::string FAVORITE_CHAR {"\uf005"};
|
||||
static inline const std::string FILTER_CHAR {"\uf0b0"};
|
||||
static inline const std::string FOLDER_CHAR {"\uf07C"};
|
||||
static inline const std::string FOLDERLINK_CHAR {"\uf090"};
|
||||
static inline const std::string GEAR_CHAR {"\uf013"};
|
||||
static inline const std::string KEYBOARD_CHAR {"\uf11c"};
|
||||
static inline const std::string TICKMARK_CHAR {"\uf14a"};
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_WIN64)
|
||||
// Why this is needed here is anyone's guess but without it the compilation fails.
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
namespace pugi
|
||||
{
|
||||
class xml_node;
|
||||
|
|
Loading…
Reference in a new issue