mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-21 21:55:38 +00:00
Code cleanup and code documentation
This commit is contained in:
parent
ac91da6995
commit
672026632d
|
@ -18,11 +18,12 @@ Some key points:
|
|||
* Comments should be proper sentences, starting with a capital letter and ending with a dot
|
||||
* Use K&R placements of braces, read the Linux Kernel coding style document for clarifications
|
||||
* Always use spaces between keywords and opening brackets, i.e. `if ()`, `for ()`, `while ()` etc.
|
||||
* Use `std::string` instead of `char *` or `char []` unless there is a very specific reason not to
|
||||
* Use `std::string` instead of `char *` or `char []` unless there is a very specific reason requiring the latter
|
||||
* If the arguments (and initializer list) for a function or class exceeds 4 items, arrange them vertically to make the code easier to read
|
||||
* Always declare one variable per line, never combine multiple declarations of the same type
|
||||
* Name local variables with the first word in small letters and the proceeding words starting with capital letters, e.g. myExampleVariable
|
||||
* Name member variables starting with a small 'm', e.g. mMyMemberVariable
|
||||
* Don't pad variable declarations with spaces to make them align in columns, I'm sure it's well intended but it looks terrible
|
||||
* Use the same naming convention for functions as for local variables, e.g. someFunction()
|
||||
* Inline functions can be used but don't overdo it by using them for functions that won't be called very frequently
|
||||
* Never put more than one statement on a single line, except for lambda expressions
|
||||
|
|
1
NEWS.md
1
NEWS.md
|
@ -31,4 +31,5 @@ v1.0.0
|
|||
* Game images were sometimes scaled incorrectly
|
||||
* Non-transparent favorite icons were not rendered correctly
|
||||
* Restart and power-off menu entries not working (i.e. on a desktop OS)
|
||||
* Toggling the screensaver didn't work as expected
|
||||
* Lots and lots of small bugs and inconsistencies fixed
|
||||
|
|
14
README.md
14
README.md
|
@ -3,26 +3,22 @@ EmulationStation Desktop Edition
|
|||
|
||||
EmulationStation Desktop Edition is a cross-platform graphical front-end for emulators with controller and keyboard navigation.
|
||||
|
||||
This is a fork intended for use primarily on desktop computers where EmulationStation is not the primary interface for the computer.
|
||||
|
||||
As such, this fork will not provide full control over emulator settings or emulator button mappings or provide system utility functions and similar. Instead it's assumed that the emulators and the overall environment has been properly configured upfront.
|
||||
This is a fork intended for use primarily on desktop computers where EmulationStation is not the primary interface for the computer. As such, this software will not provide full control over emulator settings or emulator button mappings or provide system utility functions and similar. Instead it's assumed that the emulators and the overall environment has been properly configured upfront.
|
||||
|
||||
The software comes preconfigured for use primarily with [RetroArch](https://www.retroarch.com), although this can certainly be changed as all emulator settings are fully configurable, even on a per-game basis.
|
||||
|
||||
** Help needed: **
|
||||
**Help needed:**
|
||||
|
||||
Apart from code commits, help is especially needed for thorough testing of the software and for working on the RBSimple-DE theme.
|
||||
|
||||
It's impossible for me to test every game system (RBSimple-DE has support for almost a 100 different systems!) so it would be especially useful to hear about any issues with starting games using the default es_systems.cfg configuration file and also if there are any issues regarding scraping for certain systems.
|
||||
|
||||
In general, a review of the es_systems.cfg file including the supported file extensions would be great:
|
||||
|
||||
[es_systems.cfg_unix](resources/templates/es_systems.cfg_unix
|
||||
In general, a review of the [es_systems.cfg](resources/templates/es_systems.cfg_unix) file including the supported file extensions would be great.
|
||||
|
||||
As for RBSimple-DE there are quite some missing graphic files and other customizations for a number of game systems. \
|
||||
Check out [MISSING.md](themes/rbsimple-DE/MISSING.md) for more details of what needs to be added.
|
||||
|
||||
Finally, if someone could make a proper port to the Macintosh Operating System, that would be great as then all of the three major desktop operating systems would be supported! There is some code present specifically for macOS but I've been unable to test it.
|
||||
Finally, if someone could make a proper port to the Macintosh Operating System, that would be great as then all of the three major desktop operating systems would be supported. There is some code present specifically for macOS but I've been unable to test it.
|
||||
|
||||
|
||||
General information
|
||||
|
@ -34,8 +30,6 @@ General information
|
|||
|
||||
[DEVNOTES.md](DEVNOTES.md) is the place to go if you're interested in participating in the development of EmulationStation Desktop Edition.
|
||||
|
||||
Or just go ahead and browse the repository for additional information, or maybe more important, to see the actual source code :)
|
||||
|
||||
|
||||
What it can do
|
||||
==============
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// FileFilterIndex.cpp
|
||||
//
|
||||
// Gamelist filters.
|
||||
//
|
||||
|
||||
#include "FileFilterIndex.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
|
@ -10,9 +16,16 @@
|
|||
#define INCLUDE_UNKNOWN false;
|
||||
|
||||
FileFilterIndex::FileFilterIndex()
|
||||
: filterByFavorites(false), filterByGenre(false), filterByHidden(false), filterByKidGame(false), filterByPlayers(false), filterByPubDev(false), filterByRatings(false)
|
||||
: filterByFavorites(false),
|
||||
filterByGenre(false),
|
||||
filterByHidden(false),
|
||||
filterByKidGame(false),
|
||||
filterByPlayers(false),
|
||||
filterByPubDev(false),
|
||||
filterByRatings(false)
|
||||
{
|
||||
clearAllFilters();
|
||||
|
||||
FilterDataDecl filterDecls[] = {
|
||||
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
||||
{ FAVORITES_FILTER, &favoritesIndexAllKeys, &filterByFavorites, &favoritesIndexFilteredKeys,"favorite", false, "", "FAVORITES" },
|
||||
|
@ -24,7 +37,8 @@ FileFilterIndex::FileFilterIndex()
|
|||
{ HIDDEN_FILTER, &hiddenIndexAllKeys, &filterByHidden, &hiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN" }
|
||||
};
|
||||
|
||||
filterDataDecl = std::vector<FilterDataDecl>(filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||
filterDataDecl = std::vector<FilterDataDecl>(filterDecls, filterDecls +
|
||||
sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||
}
|
||||
|
||||
FileFilterIndex::~FileFilterIndex()
|
||||
|
@ -39,8 +53,7 @@ std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
|
|||
|
||||
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
||||
{
|
||||
struct IndexImportStructure
|
||||
{
|
||||
struct IndexImportStructure {
|
||||
std::map<std::string, int>* destinationIndex;
|
||||
std::map<std::string, int>* sourceIndex;
|
||||
};
|
||||
|
@ -55,24 +68,26 @@ void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
|||
{ &kidGameIndexAllKeys, &(indexToImport->kidGameIndexAllKeys) },
|
||||
};
|
||||
|
||||
std::vector<IndexImportStructure> indexImportDecl = std::vector<IndexImportStructure>(indexStructDecls, indexStructDecls + sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
||||
std::vector<IndexImportStructure> indexImportDecl =
|
||||
std::vector<IndexImportStructure>(indexStructDecls, indexStructDecls +
|
||||
sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
||||
|
||||
for (std::vector<IndexImportStructure>::const_iterator indexesIt = indexImportDecl.cbegin(); indexesIt != indexImportDecl.cend(); ++indexesIt )
|
||||
for (std::vector<IndexImportStructure>::const_iterator indexesIt =
|
||||
indexImportDecl.cbegin(); indexesIt != indexImportDecl.cend(); ++indexesIt )
|
||||
{
|
||||
for (std::map<std::string, int>::const_iterator sourceIt = (*indexesIt).sourceIndex->cbegin(); sourceIt != (*indexesIt).sourceIndex->cend(); ++sourceIt )
|
||||
{
|
||||
if ((*indexesIt).destinationIndex->find((*sourceIt).first) == (*indexesIt).destinationIndex->cend())
|
||||
{
|
||||
// entry doesn't exist
|
||||
for (std::map<std::string, int>::const_iterator sourceIt =
|
||||
(*indexesIt).sourceIndex->cbegin(); sourceIt !=
|
||||
(*indexesIt).sourceIndex->cend(); ++sourceIt ) {
|
||||
if ((*indexesIt).destinationIndex->find((*sourceIt).first) ==
|
||||
(*indexesIt).destinationIndex->cend())
|
||||
// Entry doesn't exist.
|
||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::resetIndex()
|
||||
{
|
||||
clearAllFilters();
|
||||
|
@ -85,13 +100,12 @@ void FileFilterIndex::resetIndex()
|
|||
clearIndex(kidGameIndexAllKeys);
|
||||
}
|
||||
|
||||
std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType type, bool getSecondary)
|
||||
std::string FileFilterIndex::getIndexableKey(FileData* game,
|
||||
FilterIndexType type, bool getSecondary)
|
||||
{
|
||||
std::string key = "";
|
||||
switch(type)
|
||||
{
|
||||
case GENRE_FILTER:
|
||||
{
|
||||
switch (type) {
|
||||
case GENRE_FILTER: {
|
||||
key = Utils::String::toUpper(game->metadata.get("genre"));
|
||||
key = Utils::String::trim(key);
|
||||
if (getSecondary && !key.empty()) {
|
||||
|
@ -99,26 +113,20 @@ std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType typ
|
|||
std::string newKey;
|
||||
getline(f, newKey, '/');
|
||||
if (!newKey.empty() && newKey != key)
|
||||
{
|
||||
key = newKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = std::string();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLAYER_FILTER:
|
||||
{
|
||||
case PLAYER_FILTER: {
|
||||
if (getSecondary)
|
||||
break;
|
||||
|
||||
key = game->metadata.get("players");
|
||||
break;
|
||||
}
|
||||
case PUBDEV_FILTER:
|
||||
{
|
||||
case PUBDEV_FILTER: {
|
||||
key = Utils::String::toUpper(game->metadata.get("publisher"));
|
||||
key = Utils::String::trim(key);
|
||||
|
||||
|
@ -128,11 +136,9 @@ std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType typ
|
|||
key = Utils::String::toUpper(game->metadata.get("publisher"));
|
||||
break;
|
||||
}
|
||||
case RATINGS_FILTER:
|
||||
{
|
||||
case RATINGS_FILTER: {
|
||||
int ratingNumber = 0;
|
||||
if (!getSecondary)
|
||||
{
|
||||
if (!getSecondary) {
|
||||
std::string ratingString = game->metadata.get("rating");
|
||||
if (!ratingString.empty()) {
|
||||
try {
|
||||
|
@ -142,30 +148,27 @@ std::string FileFilterIndex::getIndexableKey(FileData* game, FilterIndexType typ
|
|||
|
||||
key = std::to_string(ratingNumber) + " STARS";
|
||||
}
|
||||
catch (int e)
|
||||
{
|
||||
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): " << ratingString << ", " << e;
|
||||
catch (int e) {
|
||||
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): " <<
|
||||
ratingString << ", " << e;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FAVORITES_FILTER:
|
||||
{
|
||||
case FAVORITES_FILTER: {
|
||||
if (game->getType() != GAME)
|
||||
return "FALSE";
|
||||
key = Utils::String::toUpper(game->metadata.get("favorite"));
|
||||
break;
|
||||
}
|
||||
case HIDDEN_FILTER:
|
||||
{
|
||||
case HIDDEN_FILTER: {
|
||||
if (game->getType() != GAME)
|
||||
return "FALSE";
|
||||
key = Utils::String::toUpper(game->metadata.get("hidden"));
|
||||
break;
|
||||
}
|
||||
case KIDGAME_FILTER:
|
||||
{
|
||||
case KIDGAME_FILTER: {
|
||||
if (game->getType() != GAME)
|
||||
return "FALSE";
|
||||
key = Utils::String::toUpper(game->metadata.get("kidgame"));
|
||||
|
@ -203,21 +206,20 @@ void FileFilterIndex::removeFromIndex(FileData* game)
|
|||
|
||||
void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>* values)
|
||||
{
|
||||
// test if it exists before setting
|
||||
if(type == NONE)
|
||||
{
|
||||
// Test if it exists before setting.
|
||||
if (type == NONE) {
|
||||
clearAllFilters();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin(); it != filterDataDecl.cend(); ++it ) {
|
||||
if ((*it).type == type)
|
||||
{
|
||||
else {
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||
it != filterDataDecl.cend(); ++it ) {
|
||||
if ((*it).type == type) {
|
||||
FilterDataDecl filterData = (*it);
|
||||
*(filterData.filteredByRef) = values->size() > 0;
|
||||
filterData.currentFilteredKeys->clear();
|
||||
for (std::vector<std::string>::const_iterator vit = values->cbegin(); vit != values->cend(); ++vit ) {
|
||||
// check if exists
|
||||
for (std::vector<std::string>::const_iterator vit =
|
||||
values->cbegin(); vit != values->cend(); ++vit ) {
|
||||
// Check if exists.
|
||||
if (filterData.allIndexKeys->find(*vit) != filterData.allIndexKeys->cend()) {
|
||||
filterData.currentFilteredKeys->push_back(std::string(*vit));
|
||||
}
|
||||
|
@ -230,8 +232,8 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>*
|
|||
|
||||
void FileFilterIndex::clearAllFilters()
|
||||
{
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin(); it != filterDataDecl.cend(); ++it )
|
||||
{
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||
it != filterDataDecl.cend(); ++it ) {
|
||||
FilterDataDecl filterData = (*it);
|
||||
*(filterData.filteredByRef) = false;
|
||||
filterData.currentFilteredKeys->clear();
|
||||
|
@ -247,15 +249,13 @@ void FileFilterIndex::resetFilters()
|
|||
|
||||
void FileFilterIndex::setUIModeFilters()
|
||||
{
|
||||
if(!Settings::getInstance()->getBool("ForceDisableFilters")){
|
||||
if (UIModeController::getInstance()->isUIModeKiosk())
|
||||
{
|
||||
if (!Settings::getInstance()->getBool("ForceDisableFilters")){
|
||||
if (UIModeController::getInstance()->isUIModeKiosk()) {
|
||||
filterByHidden = true;
|
||||
std::vector<std::string> val = { "FALSE" };
|
||||
setFilter(HIDDEN_FILTER, &val);
|
||||
}
|
||||
if (UIModeController::getInstance()->isUIModeKid())
|
||||
{
|
||||
if (UIModeController::getInstance()->isUIModeKid()) {
|
||||
filterByKidGame = true;
|
||||
std::vector<std::string> val = { "TRUE" };
|
||||
setFilter(KIDGAME_FILTER, &val);
|
||||
|
@ -291,79 +291,68 @@ void FileFilterIndex::debugPrintIndexes()
|
|||
|
||||
bool FileFilterIndex::showFile(FileData* game)
|
||||
{
|
||||
// this shouldn't happen, but just in case let's get it out of the way
|
||||
// This shouldn't happen, but just in case let's get it out of the way.
|
||||
if (!isFiltered())
|
||||
return true;
|
||||
|
||||
// if folder, needs further inspection - i.e. see if folder contains at least one element
|
||||
// that should be shown
|
||||
// If folder, needs further inspection - i.e. see if folder contains at least one element
|
||||
// that should be shown.
|
||||
if (game->getType() == FOLDER) {
|
||||
std::vector<FileData*> children = game->getChildren();
|
||||
// iterate through all of the children, until there's a match
|
||||
|
||||
for (std::vector<FileData*>::const_iterator it = children.cbegin(); it != children.cend(); ++it ) {
|
||||
// Iterate through all of the children, until there's a match.
|
||||
for (std::vector<FileData*>::const_iterator it = children.cbegin();
|
||||
it != children.cend(); ++it ) {
|
||||
if (showFile(*it))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool keepGoing = false;
|
||||
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin(); it != filterDataDecl.cend(); ++it ) {
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||
it != filterDataDecl.cend(); ++it ) {
|
||||
FilterDataDecl filterData = (*it);
|
||||
if(*(filterData.filteredByRef))
|
||||
{
|
||||
// try to find a match
|
||||
if (*(filterData.filteredByRef)) {
|
||||
// Try to find a match.
|
||||
std::string key = getIndexableKey(game, filterData.type, false);
|
||||
keepGoing = isKeyBeingFilteredBy(key, filterData.type);
|
||||
|
||||
// if we didn't find a match, try for secondary keys - i.e. publisher and dev, or first genre
|
||||
if (!keepGoing)
|
||||
{
|
||||
// If we didn't find a match, try for secondary keys - i.e.
|
||||
// publisher and dev, or first genre.
|
||||
if (!keepGoing) {
|
||||
if (!filterData.hasSecondaryKey)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::string secKey = getIndexableKey(game, filterData.type, true);
|
||||
if (secKey != UNKNOWN_LABEL)
|
||||
{
|
||||
keepGoing = isKeyBeingFilteredBy(secKey, filterData.type);
|
||||
}
|
||||
}
|
||||
// if still nothing, then it's not a match
|
||||
// If still nothing, then it's not a match.
|
||||
if (!keepGoing)
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return keepGoing;
|
||||
}
|
||||
|
||||
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
||||
{
|
||||
const FilterIndexType filterTypes[7] = { FAVORITES_FILTER, GENRE_FILTER, PLAYER_FILTER, PUBDEV_FILTER, RATINGS_FILTER,HIDDEN_FILTER, KIDGAME_FILTER };
|
||||
std::vector<std::string> filterKeysList[7] = { favoritesIndexFilteredKeys, genreIndexFilteredKeys, playersIndexFilteredKeys, pubDevIndexFilteredKeys, ratingsIndexFilteredKeys, hiddenIndexFilteredKeys, kidGameIndexFilteredKeys };
|
||||
const FilterIndexType filterTypes[7] = { FAVORITES_FILTER, GENRE_FILTER,
|
||||
PLAYER_FILTER, PUBDEV_FILTER, RATINGS_FILTER,HIDDEN_FILTER, KIDGAME_FILTER };
|
||||
std::vector<std::string> filterKeysList[7] = { favoritesIndexFilteredKeys,
|
||||
genreIndexFilteredKeys, playersIndexFilteredKeys, pubDevIndexFilteredKeys,
|
||||
ratingsIndexFilteredKeys, hiddenIndexFilteredKeys, kidGameIndexFilteredKeys };
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (filterTypes[i] == type)
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator it = filterKeysList[i].cbegin(); it != filterKeysList[i].cend(); ++it )
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (filterTypes[i] == type) {
|
||||
for (std::vector<std::string>::const_iterator it = filterKeysList[i].cbegin();
|
||||
it != filterKeysList[i].cend(); ++it ) {
|
||||
if (key == (*it))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -372,35 +361,31 @@ void FileFilterIndex::manageGenreEntryInIndex(FileData* game, bool remove)
|
|||
|
||||
std::string key = getIndexableKey(game, GENRE_FILTER, false);
|
||||
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
|
||||
// only add unknown in pubdev IF both dev and pub are empty
|
||||
if (!includeUnknown && (key == UNKNOWN_LABEL || key == "BIOS")) {
|
||||
// no valid genre info found
|
||||
// Only add unknown in pubdev IF both dev and pub are empty.
|
||||
if (!includeUnknown && (key == UNKNOWN_LABEL || key == "BIOS"))
|
||||
// No valid genre info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&genreIndexAllKeys, key, remove);
|
||||
|
||||
key = getIndexableKey(game, GENRE_FILTER, true);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
{
|
||||
manageIndexEntry(&genreIndexAllKeys, key, remove);
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::managePlayerEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, PLAYER_FILTER, false);
|
||||
|
||||
// only add unknown in pubdev IF both dev and pub are empty
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid player info found
|
||||
// Only add unknown in pubdev IF both dev and pub are empty.
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
// No valid player info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&playersIndexAllKeys, key, remove);
|
||||
}
|
||||
|
@ -410,35 +395,32 @@ void FileFilterIndex::managePubDevEntryInIndex(FileData* game, bool remove)
|
|||
std::string pub = getIndexableKey(game, PUBDEV_FILTER, false);
|
||||
std::string dev = getIndexableKey(game, PUBDEV_FILTER, true);
|
||||
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
bool unknownPub = false;
|
||||
bool unknownDev = false;
|
||||
|
||||
if (pub == UNKNOWN_LABEL) {
|
||||
if (pub == UNKNOWN_LABEL)
|
||||
unknownPub = true;
|
||||
}
|
||||
if (dev == UNKNOWN_LABEL) {
|
||||
unknownDev = true;
|
||||
}
|
||||
|
||||
if (!includeUnknown && unknownDev && unknownPub) {
|
||||
// no valid rating info found
|
||||
if (dev == UNKNOWN_LABEL)
|
||||
unknownDev = true;
|
||||
|
||||
if (!includeUnknown && unknownDev && unknownPub)
|
||||
// No valid rating info found.
|
||||
return;
|
||||
}
|
||||
|
||||
if (unknownDev && unknownPub) {
|
||||
// if no info at all
|
||||
// If no info at all.
|
||||
manageIndexEntry(&pubDevIndexAllKeys, pub, remove);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
if (!unknownDev) {
|
||||
// if no info at all
|
||||
// If no info at all.
|
||||
manageIndexEntry(&pubDevIndexAllKeys, dev, remove);
|
||||
}
|
||||
if (!unknownPub) {
|
||||
// if no info at all
|
||||
// If no info at all.
|
||||
manageIndexEntry(&pubDevIndexAllKeys, pub, remove);
|
||||
}
|
||||
}
|
||||
|
@ -448,87 +430,82 @@ void FileFilterIndex::manageRatingsEntryInIndex(FileData* game, bool remove)
|
|||
{
|
||||
std::string key = getIndexableKey(game, RATINGS_FILTER, false);
|
||||
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid rating info found
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
// No valid rating info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&ratingsIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageFavoritesEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, FAVORITES_FILTER, false);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid favorites info found
|
||||
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
// No valid favorites info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&favoritesIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageHiddenEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, HIDDEN_FILTER, false);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid hidden info found
|
||||
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
// No valid hidden info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&hiddenIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageKidGameEntryInIndex(FileData* game, bool remove)
|
||||
{
|
||||
// flag for including unknowns
|
||||
// Flag for including unknowns.
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
std::string key = getIndexableKey(game, KIDGAME_FILTER, false);
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL) {
|
||||
// no valid kidgame info found
|
||||
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
// No valid kidgame info found.
|
||||
return;
|
||||
}
|
||||
|
||||
manageIndexEntry(&kidGameIndexAllKeys, key, remove);
|
||||
}
|
||||
|
||||
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index, std::string key, bool remove) {
|
||||
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
||||
std::string key, bool remove)
|
||||
{
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
return;
|
||||
|
||||
if (remove) {
|
||||
// removing entry
|
||||
if (index->find(key) == index->cend())
|
||||
{
|
||||
// this shouldn't happen
|
||||
// Removing entry.
|
||||
if (index->find(key) == index->cend()) {
|
||||
// This shouldn't happen.
|
||||
LOG(LogInfo) << "Couldn't find entry in index! " << key;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
(index->at(key))--;
|
||||
if(index->at(key) <= 0) {
|
||||
if (index->at(key) <= 0) {
|
||||
index->erase(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// adding entry
|
||||
else {
|
||||
// Adding entry.
|
||||
if (index->find(key) == index->cend())
|
||||
{
|
||||
(*index)[key] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
(index->at(key))++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::clearIndex(std::map<std::string, int> indexMap)
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// FileFilterIndex.h
|
||||
//
|
||||
// Gamelist filters.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_FILE_FILTER_INDEX_H
|
||||
#define ES_APP_FILE_FILTER_INDEX_H
|
||||
|
@ -7,8 +13,7 @@
|
|||
|
||||
class FileData;
|
||||
|
||||
enum FilterIndexType
|
||||
{
|
||||
enum FilterIndexType {
|
||||
NONE,
|
||||
GENRE_FILTER,
|
||||
PLAYER_FILTER,
|
||||
|
@ -19,16 +24,15 @@ enum FilterIndexType
|
|||
KIDGAME_FILTER
|
||||
};
|
||||
|
||||
struct FilterDataDecl
|
||||
{
|
||||
FilterIndexType type; // type of filter
|
||||
std::map<std::string, int>* allIndexKeys; // all possible filters for this type
|
||||
bool* filteredByRef; // is it filtered by this type
|
||||
std::vector<std::string>* currentFilteredKeys; // current keys being filtered for
|
||||
std::string primaryKey; // primary key in metadata
|
||||
bool hasSecondaryKey; // has secondary key for comparison
|
||||
std::string secondaryKey; // what's the secondary key
|
||||
std::string menuLabel; // text to show in menu
|
||||
struct FilterDataDecl {
|
||||
FilterIndexType type; // Type of filter.
|
||||
std::map<std::string, int>* allIndexKeys; // All possible filters for this type.
|
||||
bool* filteredByRef; // Is it filtered by this type?
|
||||
std::vector<std::string>* currentFilteredKeys; // Current keys being filtered for.
|
||||
std::string primaryKey; // Primary key in metadata.
|
||||
bool hasSecondaryKey; // Has secondary key for comparison.
|
||||
std::string secondaryKey; // What's the secondary key.
|
||||
std::string menuLabel; // Text to show in menu.
|
||||
};
|
||||
|
||||
class FileFilterIndex
|
||||
|
@ -42,7 +46,8 @@ public:
|
|||
void clearAllFilters();
|
||||
void debugPrintIndexes();
|
||||
bool showFile(FileData* game);
|
||||
bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev || filterByRatings || filterByFavorites || filterByHidden || filterByKidGame); };
|
||||
bool isFiltered() { return (filterByGenre || filterByPlayers || filterByPubDev ||
|
||||
filterByRatings || filterByFavorites || filterByHidden || filterByKidGame); };
|
||||
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
|
||||
std::vector<FilterDataDecl>& getFilterDataDecls();
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// FileSorts.cpp
|
||||
//
|
||||
// Gamelist sorting functions.
|
||||
// Actual sorting takes place in FileData.
|
||||
//
|
||||
|
||||
#include "FileSorts.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
|
@ -36,12 +43,14 @@ namespace FileSorts
|
|||
FileData::SortType(&compareSystem, false, "system, descending")
|
||||
};
|
||||
|
||||
const std::vector<FileData::SortType> SortTypes(typesArr, typesArr + sizeof(typesArr)/sizeof(typesArr[0]));
|
||||
const std::vector<FileData::SortType> SortTypes(typesArr, typesArr +
|
||||
sizeof(typesArr)/sizeof(typesArr[0]));
|
||||
|
||||
//returns if file1 should come before file2
|
||||
// Returns if file1 should come before file2.
|
||||
bool compareName(const FileData* file1, const FileData* file2)
|
||||
{
|
||||
// we compare the actual metadata name, as collection files have the system appended which messes up the order
|
||||
// We compare the actual metadata name, as collection files have the system
|
||||
// appended which messes up the order.
|
||||
std::string name1 = Utils::String::toUpper(file1->metadata.get("sortname"));
|
||||
std::string name2 = Utils::String::toUpper(file2->metadata.get("sortname"));
|
||||
if(name1.empty()){
|
||||
|
@ -62,17 +71,15 @@ namespace FileSorts
|
|||
{
|
||||
//only games have playcount metadata
|
||||
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
|
||||
{
|
||||
return (file1)->metadata.getInt("playcount") < (file2)->metadata.getInt("playcount");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compareLastPlayed(const FileData* file1, const FileData* file2)
|
||||
{
|
||||
// since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
||||
// as it's a lot faster than the time casts and then time comparisons
|
||||
// Since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
||||
// which is a lot faster than the time casts and the time comparisons.
|
||||
return (file1)->metadata.get("lastplayed") < (file2)->metadata.get("lastplayed");
|
||||
}
|
||||
|
||||
|
@ -83,8 +90,8 @@ namespace FileSorts
|
|||
|
||||
bool compareReleaseDate(const FileData* file1, const FileData* file2)
|
||||
{
|
||||
// since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
||||
// as it's a lot faster than the time casts and then time comparisons
|
||||
// Since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
||||
// which is a lot faster than the time casts and the time comparisons.
|
||||
return (file1)->metadata.get("releasedate") < (file2)->metadata.get("releasedate");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// FileSorts.h
|
||||
//
|
||||
// Gamelist sorting functions.
|
||||
// Actual sorting takes place in FileData.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_FILE_SORTS_H
|
||||
#define ES_APP_FILE_SORTS_H
|
||||
|
|
|
@ -88,7 +88,6 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type,
|
|||
mdl.set(iter->key, iter->defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
return mdl;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,8 +71,6 @@ public:
|
|||
// An example will be written if the file doesn't exist.
|
||||
static bool loadConfig();
|
||||
static void writeExampleConfig(const std::string& path);
|
||||
// If forWrite, will only return ~/.emulationstation/es_systems.cfg,
|
||||
// never /etc/emulationstation/es_systems.cfg.
|
||||
static std::string getConfigPath(bool forWrite);
|
||||
|
||||
static std::vector<SystemData*> sSystemVector;
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// GuiCollectionSystemsOptions.cpp
|
||||
//
|
||||
// User interface for the game collection settings.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
|
||||
#include "guis/GuiCollectionSystemsOptions.h"
|
||||
|
||||
#include "components/OptionListComponent.h"
|
||||
|
@ -10,7 +17,8 @@
|
|||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
|
||||
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window) : GuiComponent(window), mMenu(window, "GAME COLLECTION SETTINGS")
|
||||
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window)
|
||||
: GuiComponent(window), mMenu(window, "GAME COLLECTION SETTINGS")
|
||||
{
|
||||
initializeMenu();
|
||||
}
|
||||
|
@ -19,15 +27,13 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
|||
{
|
||||
addChild(&mMenu);
|
||||
|
||||
// get collections
|
||||
|
||||
// Get collections.
|
||||
addSystemsToMenu();
|
||||
|
||||
// add "Create New Custom Collection from Theme"
|
||||
|
||||
std::vector<std::string> unusedFolders = CollectionSystemManager::get()->getUnusedSystemsFromTheme();
|
||||
if (unusedFolders.size() > 0)
|
||||
{
|
||||
// Add "Create New Custom Collection from Theme".
|
||||
std::vector<std::string> unusedFolders =
|
||||
CollectionSystemManager::get()->getUnusedSystemsFromTheme();
|
||||
if (unusedFolders.size() > 0) {
|
||||
addEntry("CREATE NEW CUSTOM COLLECTION FROM THEME", 0x777777FF, true,
|
||||
[this, unusedFolders] {
|
||||
auto s = new GuiSettings(mWindow, "SELECT THEME FOLDER");
|
||||
|
@ -35,9 +41,8 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
|||
folderThemes = std::make_shared< OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SELECT THEME FOLDER", true);
|
||||
|
||||
// add Custom Systems
|
||||
for(auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ )
|
||||
{
|
||||
// Add custom systems.
|
||||
for(auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ ) {
|
||||
ComponentListRow row;
|
||||
std::string name = *it;
|
||||
|
||||
|
@ -46,7 +51,8 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
|||
};
|
||||
row.makeAcceptInputHandler(createCollectionCall);
|
||||
|
||||
auto themeFolder = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
auto themeFolder = std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
row.addElement(themeFolder, true);
|
||||
s->addRow(row);
|
||||
}
|
||||
|
@ -55,21 +61,24 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
|||
}
|
||||
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||
bracket->setImage(":/graphics/arrow.svg");
|
||||
bracket->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
row.addElement(bracket, false);
|
||||
auto createCustomCollection = [this](const std::string& newVal) {
|
||||
std::string name = newVal;
|
||||
// we need to store the first Gui and remove it, as it'll be deleted by the actual Gui
|
||||
// We need to store the first GUI and remove it, as it'll
|
||||
// be deleted by the actual GUI.
|
||||
Window* window = mWindow;
|
||||
GuiComponent* topGui = window->peekGui();
|
||||
window->removeGui(topGui);
|
||||
createCollection(name);
|
||||
};
|
||||
row.makeAcceptInputHandler([this, createCustomCollection] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "New Collection Name", "", createCustomCollection, false, "SAVE"));
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(),
|
||||
"New Collection Name", "", createCustomCollection, false, "SAVE"));
|
||||
});
|
||||
|
||||
mMenu.addRow(row);
|
||||
|
@ -79,42 +88,44 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
|||
mMenu.addWithLabel("SORT FAVORITES ON TOP FOR CUSTOM COLLECTIONS", sortFavFirstCustomSwitch);
|
||||
|
||||
bundleCustomCollections = std::make_shared<SwitchComponent>(mWindow);
|
||||
bundleCustomCollections->setState(Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
|
||||
bundleCustomCollections->setState(Settings::getInstance()->
|
||||
getBool("UseCustomCollectionsSystem"));
|
||||
mMenu.addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", bundleCustomCollections);
|
||||
|
||||
toggleSystemNameInCollections = std::make_shared<SwitchComponent>(mWindow);
|
||||
toggleSystemNameInCollections->setState(Settings::getInstance()->getBool("CollectionShowSystemInfo"));
|
||||
toggleSystemNameInCollections->setState(Settings::getInstance()->
|
||||
getBool("CollectionShowSystemInfo"));
|
||||
mMenu.addWithLabel("SHOW SYSTEM NAMES IN COLLECTIONS", toggleSystemNameInCollections);
|
||||
|
||||
if(CollectionSystemManager::get()->isEditing())
|
||||
{
|
||||
if(CollectionSystemManager::get()->isEditing()) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" + Utils::String::toUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" +
|
||||
Utils::String::toUpper(CollectionSystemManager::get()->getEditingCollection()) +
|
||||
"' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiCollectionSystemsOptions::exitEditMode, this));
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
||||
mMenu.addButton("BACK", "back", std::bind(&GuiCollectionSystemsOptions::applySettings, this));
|
||||
|
||||
mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, Renderer::getScreenHeight() * 0.15f);
|
||||
mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2,
|
||||
Renderer::getScreenHeight() * 0.15f);
|
||||
}
|
||||
|
||||
void GuiCollectionSystemsOptions::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
|
||||
void GuiCollectionSystemsOptions::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
|
||||
// Populate the list.
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
|
||||
|
||||
if(add_arrow)
|
||||
{
|
||||
if(add_arrow) {
|
||||
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
|
||||
row.addElement(bracket, false);
|
||||
}
|
||||
|
||||
row.makeAcceptInputHandler(func);
|
||||
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
||||
|
@ -122,8 +133,10 @@ void GuiCollectionSystemsOptions::createCollection(std::string inName) {
|
|||
std::string name = CollectionSystemManager::get()->getValidNewCollectionName(inName);
|
||||
SystemData* newSys = CollectionSystemManager::get()->addNewCustomCollection(name);
|
||||
customOptionList->add(name, name, true);
|
||||
std::string outAuto = Utils::String::vectorToCommaString(autoOptionList->getSelectedObjects());
|
||||
std::string outCustom = Utils::String::vectorToCommaString(customOptionList->getSelectedObjects());
|
||||
std::string outAuto = Utils::String::vectorToCommaString(
|
||||
autoOptionList->getSelectedObjects());
|
||||
std::string outCustom = Utils::String::vectorToCommaString(
|
||||
customOptionList->getSelectedObjects());
|
||||
updateSettings(outAuto, outCustom);
|
||||
ViewController::get()->goToSystemView(newSys);
|
||||
|
||||
|
@ -142,40 +155,42 @@ void GuiCollectionSystemsOptions::exitEditMode()
|
|||
|
||||
GuiCollectionSystemsOptions::~GuiCollectionSystemsOptions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GuiCollectionSystemsOptions::addSystemsToMenu()
|
||||
{
|
||||
std::map<std::string, CollectionSystemData> autoSystems =
|
||||
CollectionSystemManager::get()->getAutoCollectionSystems();
|
||||
|
||||
std::map<std::string, CollectionSystemData> autoSystems = CollectionSystemManager::get()->getAutoCollectionSystems();
|
||||
autoOptionList = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
|
||||
autoOptionList = std::make_shared< OptionListComponent<std::string> >(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
|
||||
// add Auto Systems
|
||||
for(std::map<std::string, CollectionSystemData>::const_iterator it = autoSystems.cbegin() ; it != autoSystems.cend() ; it++ )
|
||||
{
|
||||
// Add automatic systems.
|
||||
for(std::map<std::string, CollectionSystemData>::const_iterator it = autoSystems.cbegin();
|
||||
it != autoSystems.cend() ; it++ )
|
||||
autoOptionList->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled);
|
||||
}
|
||||
mMenu.addWithLabel("AUTOMATIC GAME COLLECTIONS", autoOptionList);
|
||||
|
||||
std::map<std::string, CollectionSystemData> customSystems = CollectionSystemManager::get()->getCustomCollectionSystems();
|
||||
std::map<std::string, CollectionSystemData> customSystems =
|
||||
CollectionSystemManager::get()->getCustomCollectionSystems();
|
||||
|
||||
customOptionList = std::make_shared< OptionListComponent<std::string> >(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
customOptionList = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
|
||||
// add Custom Systems
|
||||
for(std::map<std::string, CollectionSystemData>::const_iterator it = customSystems.cbegin() ; it != customSystems.cend() ; it++ )
|
||||
{
|
||||
// Add custom systems.
|
||||
for(std::map<std::string, CollectionSystemData>::const_iterator it = customSystems.cbegin();
|
||||
it != customSystems.cend() ; it++ )
|
||||
customOptionList->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled);
|
||||
}
|
||||
mMenu.addWithLabel("CUSTOM GAME COLLECTIONS", customOptionList);
|
||||
}
|
||||
|
||||
void GuiCollectionSystemsOptions::applySettings()
|
||||
{
|
||||
std::string outAuto = Utils::String::vectorToCommaString(autoOptionList->getSelectedObjects());
|
||||
std::string outAuto = Utils::String::vectorToCommaString(
|
||||
autoOptionList->getSelectedObjects());
|
||||
std::string prevAuto = Settings::getInstance()->getString("CollectionSystemsAuto");
|
||||
std::string outCustom = Utils::String::vectorToCommaString(customOptionList->getSelectedObjects());
|
||||
std::string outCustom = Utils::String::vectorToCommaString(
|
||||
customOptionList->getSelectedObjects());
|
||||
std::string prevCustom = Settings::getInstance()->getString("CollectionSystemsCustom");
|
||||
bool outSort = sortFavFirstCustomSwitch->getState();
|
||||
bool prevSort = Settings::getInstance()->getBool("FavFirstCustom");
|
||||
|
@ -183,22 +198,25 @@ void GuiCollectionSystemsOptions::applySettings()
|
|||
bool prevBundle = Settings::getInstance()->getBool("UseCustomCollectionsSystem");
|
||||
bool prevShow = Settings::getInstance()->getBool("CollectionShowSystemInfo");
|
||||
bool outShow = toggleSystemNameInCollections->getState();
|
||||
bool needUpdateSettings = prevAuto != outAuto || prevCustom != outCustom || outSort != prevSort || outBundle != prevBundle || prevShow != outShow ;
|
||||
bool needUpdateSettings = prevAuto != outAuto || prevCustom != outCustom || outSort !=
|
||||
prevSort || outBundle != prevBundle || prevShow != outShow ;
|
||||
|
||||
if (needUpdateSettings)
|
||||
{
|
||||
updateSettings(outAuto, outCustom);
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void GuiCollectionSystemsOptions::updateSettings(std::string newAutoSettings, std::string newCustomSettings)
|
||||
void GuiCollectionSystemsOptions::updateSettings(std::string newAutoSettings,
|
||||
std::string newCustomSettings)
|
||||
{
|
||||
Settings::getInstance()->setString("CollectionSystemsAuto", newAutoSettings);
|
||||
Settings::getInstance()->setString("CollectionSystemsCustom", newCustomSettings);
|
||||
Settings::getInstance()->setBool("FavFirstCustom", sortFavFirstCustomSwitch->getState());
|
||||
Settings::getInstance()->setBool("UseCustomCollectionsSystem", bundleCustomCollections->getState());
|
||||
Settings::getInstance()->setBool("CollectionShowSystemInfo", toggleSystemNameInCollections->getState());
|
||||
Settings::getInstance()->setBool("UseCustomCollectionsSystem",
|
||||
bundleCustomCollections->getState());
|
||||
Settings::getInstance()->setBool("CollectionShowSystemInfo",
|
||||
toggleSystemNameInCollections->getState());
|
||||
Settings::getInstance()->saveFile();
|
||||
CollectionSystemManager::get()->loadEnabledListFromSettings();
|
||||
CollectionSystemManager::get()->updateSystemsList();
|
||||
|
@ -209,14 +227,12 @@ void GuiCollectionSystemsOptions::updateSettings(std::string newAutoSettings, st
|
|||
bool GuiCollectionSystemsOptions::input(InputConfig* config, Input input)
|
||||
{
|
||||
bool consumed = GuiComponent::input(config, input);
|
||||
|
||||
if(consumed)
|
||||
return true;
|
||||
|
||||
if(config->isMappedTo("b", input) && input.value != 0)
|
||||
{
|
||||
applySettings();
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
//
|
||||
// GuiCollectionSystemsOptions.h
|
||||
//
|
||||
// User interface for the game collection settings.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_GUIS_GUI_COLLECTION_SYSTEM_OPTIONS_H
|
||||
#define ES_APP_GUIS_GUI_COLLECTION_SYSTEM_OPTIONS_H
|
||||
|
@ -23,7 +30,8 @@ private:
|
|||
void initializeMenu();
|
||||
void applySettings();
|
||||
void addSystemsToMenu();
|
||||
void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
|
||||
void addEntry(const char* name, unsigned int color,
|
||||
bool add_arrow, const std::function<void()>& func);
|
||||
void updateSettings(std::string newAutoSettings, std::string newCustomSettings);
|
||||
void createCollection(std::string inName);
|
||||
void exitEditMode();
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
//
|
||||
// GuiGeneralScreensaverOptions.cpp
|
||||
//
|
||||
// User interface for the screensaver options.
|
||||
// Based on the GuiScreenSaverOptions template.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
|
||||
#include "guis/GuiGeneralScreensaverOptions.h"
|
||||
|
||||
#include "components/OptionListComponent.h"
|
||||
|
@ -8,57 +16,72 @@
|
|||
#include "guis/GuiVideoScreensaverOptions.h"
|
||||
#include "Settings.h"
|
||||
|
||||
GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const char* title) : GuiScreensaverOptions(window, title)
|
||||
GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const char* title)
|
||||
: GuiScreensaverOptions(window, title)
|
||||
{
|
||||
// screensaver time
|
||||
// Screensaver time.
|
||||
auto screensaver_time = std::make_shared<SliderComponent>(mWindow, 0.f, 30.f, 1.f, "m");
|
||||
screensaver_time->setValue((float)(Settings::getInstance()->getInt("ScreenSaverTime") / (1000 * 60)));
|
||||
screensaver_time->setValue((float)(Settings::getInstance()->
|
||||
getInt("ScreenSaverTime") / (1000 * 60)));
|
||||
addWithLabel("SCREENSAVER AFTER", screensaver_time);
|
||||
addSaveFunc([screensaver_time] {
|
||||
Settings::getInstance()->setInt("ScreenSaverTime", (int)Math::round(screensaver_time->getValue()) * (1000 * 60));
|
||||
Settings::getInstance()->setInt("ScreenSaverTime",
|
||||
(int)Math::round(screensaver_time->getValue()) * (1000 * 60));
|
||||
PowerSaver::updateTimeouts();
|
||||
});
|
||||
|
||||
// Allow ScreenSaver Controls - ScreenSaverControls
|
||||
// Allow ScreenSaver Controls - ScreenSaverControls.
|
||||
auto ss_controls = std::make_shared<SwitchComponent>(mWindow);
|
||||
ss_controls->setState(Settings::getInstance()->getBool("ScreenSaverControls"));
|
||||
addWithLabel("SCREENSAVER CONTROLS", ss_controls);
|
||||
addSaveFunc([ss_controls] { Settings::getInstance()->setBool("ScreenSaverControls", ss_controls->getState()); });
|
||||
addSaveFunc([ss_controls] { Settings::getInstance()->setBool("ScreenSaverControls",
|
||||
ss_controls->getState()); });
|
||||
|
||||
// screensaver behavior
|
||||
auto screensaver_behavior = std::make_shared< OptionListComponent<std::string> >(mWindow, getHelpStyle(), "SCREENSAVER BEHAVIOR", false);
|
||||
// Screensaver behavior.
|
||||
auto screensaver_behavior = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SCREENSAVER BEHAVIOR", false);
|
||||
std::vector<std::string> screensavers;
|
||||
screensavers.push_back("dim");
|
||||
screensavers.push_back("black");
|
||||
screensavers.push_back("random video");
|
||||
screensavers.push_back("slideshow");
|
||||
for(auto it = screensavers.cbegin(); it != screensavers.cend(); it++)
|
||||
screensaver_behavior->add(*it, *it, Settings::getInstance()->getString("ScreenSaverBehavior") == *it);
|
||||
screensaver_behavior->add(*it, *it, Settings::getInstance()->
|
||||
getString("ScreenSaverBehavior") == *it);
|
||||
addWithLabel("SCREENSAVER BEHAVIOR", screensaver_behavior);
|
||||
addSaveFunc([this, screensaver_behavior] {
|
||||
if (Settings::getInstance()->getString("ScreenSaverBehavior") != "random video" && screensaver_behavior->getSelected() == "random video") {
|
||||
// if before it wasn't risky but now there's a risk of problems, show warning
|
||||
if (Settings::getInstance()->getString("ScreenSaverBehavior") !=
|
||||
"random video" && screensaver_behavior->getSelected() == "random video") {
|
||||
// If before it wasn't risky but now there's a risk of problems, show warning.
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"The \"Random Video\" screensaver shows videos from your gamelist.\n\nIf you do not have videos, or if in several consecutive attempts the games it selects don't have videos it will default to black.\n\nMore options in the \"UI Settings\" > \"Video Screensaver\" menu.",
|
||||
"THE \"RANDOM VIDEO\" SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS.\n\nIF YOU DO NOT "
|
||||
"HAVE ANY VIDEOS, THE SCREENSAVER\nWILL DEFAULT TO \"BLACK\".\n\nSEE MORE "
|
||||
"OPTIONS IN THE MENU \"UI SETTINGS\" >\n\"SCREENSAVER SETTINGS\" > "
|
||||
"\"VIDEO SCREENSAVER SETTINGS\".",
|
||||
"OK", [] { return; }));
|
||||
}
|
||||
Settings::getInstance()->setString("ScreenSaverBehavior", screensaver_behavior->getSelected());
|
||||
Settings::getInstance()->setString("ScreenSaverBehavior",
|
||||
screensaver_behavior->getSelected());
|
||||
PowerSaver::updateTimeouts();
|
||||
});
|
||||
|
||||
ComponentListRow row;
|
||||
|
||||
// show filtered menu
|
||||
// Show filtered menu.
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGeneralScreensaverOptions::openVideoScreensaverOptions, this));
|
||||
row.makeAcceptInputHandler(std::bind(
|
||||
&GuiGeneralScreensaverOptions::openVideoScreensaverOptions, this));
|
||||
addRow(row);
|
||||
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "SLIDESHOW SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"SLIDESHOW SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions, this));
|
||||
row.makeAcceptInputHandler(std::bind(
|
||||
&GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions, this));
|
||||
addRow(row);
|
||||
}
|
||||
|
||||
|
@ -73,4 +96,3 @@ void GuiGeneralScreensaverOptions::openVideoScreensaverOptions() {
|
|||
void GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions() {
|
||||
mWindow->pushGui(new GuiSlideshowScreensaverOptions(mWindow, "SLIDESHOW SCREENSAVER"));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
//
|
||||
// GuiGeneralScreensaverOptions.h
|
||||
//
|
||||
// User interface for the screensaver options.
|
||||
// Based on the GuiScreenSaverOptions template.
|
||||
// Submenu to the GuiMenu main menu.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_GUIS_GUI_GENERAL_SCREENSAVER_OPTIONS_H
|
||||
#define ES_APP_GUIS_GUI_GENERAL_SCREENSAVER_OPTIONS_H
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// GuiInfoPopup.cpp
|
||||
//
|
||||
// Popup window used for user notifications.
|
||||
//
|
||||
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
|
||||
#include "components/ComponentGrid.h"
|
||||
|
@ -5,25 +11,28 @@
|
|||
#include "components/TextComponent.h"
|
||||
#include <SDL_timer.h>
|
||||
|
||||
GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration) :
|
||||
GuiComponent(window), mMessage(message), mDuration(duration), running(true)
|
||||
GuiInfoPopup::GuiInfoPopup(
|
||||
Window* window,
|
||||
std::string message,
|
||||
int duration)
|
||||
: GuiComponent(window),
|
||||
mMessage(message),
|
||||
mDuration(duration),
|
||||
running(true)
|
||||
{
|
||||
mFrame = new NinePatchComponent(window);
|
||||
float maxWidth = Renderer::getScreenWidth() * 0.9f;
|
||||
float maxHeight = Renderer::getScreenHeight() * 0.2f;
|
||||
|
||||
std::shared_ptr<TextComponent> s = std::make_shared<TextComponent>(mWindow,
|
||||
"",
|
||||
Font::get(FONT_SIZE_MINI),
|
||||
0x444444FF,
|
||||
ALIGN_CENTER);
|
||||
std::shared_ptr<TextComponent> s = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_MINI), 0x444444FF, ALIGN_CENTER);
|
||||
|
||||
// we do this to force the text container to resize and return an actual expected popup size
|
||||
// We do this to force the text container to resize and return the actual expected popup size.
|
||||
s->setSize(0,0);
|
||||
s->setText(message);
|
||||
mSize = s->getSize();
|
||||
|
||||
// confirm the size isn't larger than the screen width, otherwise cap it
|
||||
// Confirm that the size isn't larger than the screen width, otherwise cap it.
|
||||
if (mSize.x() > maxWidth) {
|
||||
s->setSize(maxWidth, mSize[1]);
|
||||
mSize[0] = maxWidth;
|
||||
|
@ -33,7 +42,7 @@ GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration) :
|
|||
mSize[1] = maxHeight;
|
||||
}
|
||||
|
||||
// add a padding to the box
|
||||
// Add a padding to the box.
|
||||
int paddingX = (int) (Renderer::getScreenWidth() * 0.03f);
|
||||
int paddingY = (int) (Renderer::getScreenHeight() * 0.02f);
|
||||
mSize[0] = mSize.x() + paddingX;
|
||||
|
@ -48,7 +57,7 @@ GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration) :
|
|||
mFrame->fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
addChild(mFrame);
|
||||
|
||||
// we only init the actual time when we first start to render
|
||||
// We only initialize the actual time when we first start to render.
|
||||
mStartTime = 0;
|
||||
|
||||
mGrid = new ComponentGrid(window, Vector2i(1, 3));
|
||||
|
@ -59,16 +68,14 @@ GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration) :
|
|||
|
||||
GuiInfoPopup::~GuiInfoPopup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GuiInfoPopup::render(const Transform4x4f& /*parentTrans*/)
|
||||
{
|
||||
// we use identity as we want to render on a specific window position, not on the view
|
||||
// We use Identity() as we want to render on a specific window position, not on the view.
|
||||
Transform4x4f trans = getTransform() * Transform4x4f::Identity();
|
||||
if(running && updateState())
|
||||
{
|
||||
// if we're still supposed to be rendering it
|
||||
if (running && updateState()) {
|
||||
// If we're still supposed to be rendering it.
|
||||
Renderer::setMatrix(trans);
|
||||
renderChildren(trans);
|
||||
}
|
||||
|
@ -78,38 +85,33 @@ bool GuiInfoPopup::updateState()
|
|||
{
|
||||
int curTime = SDL_GetTicks();
|
||||
|
||||
// we only init the actual time when we first start to render
|
||||
if(mStartTime == 0)
|
||||
{
|
||||
// We only initialize the actual time when we first start to render.
|
||||
if (mStartTime == 0)
|
||||
mStartTime = curTime;
|
||||
}
|
||||
|
||||
// compute fade in effect
|
||||
if (curTime - mStartTime > mDuration)
|
||||
{
|
||||
// we're past the popup duration, no need to render
|
||||
// Compute fade-in effect.
|
||||
if (curTime - mStartTime > mDuration) {
|
||||
// We're past the popup duration, no need to render.
|
||||
running = false;
|
||||
return false;
|
||||
}
|
||||
else if (curTime < mStartTime) {
|
||||
// if SDL reset
|
||||
// If SDL reset.
|
||||
running = false;
|
||||
return false;
|
||||
}
|
||||
else if (curTime - mStartTime <= 500) {
|
||||
alpha = ((curTime - mStartTime)*255/500);
|
||||
}
|
||||
else if (curTime - mStartTime < mDuration - 500)
|
||||
{
|
||||
else if (curTime - mStartTime < mDuration - 500) {
|
||||
alpha = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
alpha = ((-(curTime - mStartTime - mDuration)*255)/500);
|
||||
}
|
||||
mGrid->setOpacity((unsigned char)alpha);
|
||||
|
||||
// apply fade in effect to popup frame
|
||||
// Apply fade-in effect to popup frame.
|
||||
mFrame->setEdgeColor(0xFFFFFF00 | (unsigned char)(alpha));
|
||||
mFrame->setCenterColor(0xFFFFFF00 | (unsigned char)(alpha));
|
||||
return true;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// GuiInfoPopup.h
|
||||
//
|
||||
// Popup window used for user notifications.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_GUIS_GUI_INFO_POPUP_H
|
||||
#define ES_APP_GUIS_GUI_INFO_POPUP_H
|
||||
|
@ -15,6 +21,7 @@ public:
|
|||
~GuiInfoPopup();
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
inline void stop() { running = false; };
|
||||
|
||||
private:
|
||||
std::string mMessage;
|
||||
int mDuration;
|
||||
|
|
|
@ -299,12 +299,12 @@ void GuiMenu::openUISettings()
|
|||
s->addSaveFunc([ UImodeSelection, window, this] {
|
||||
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";
|
||||
std::string msg = "YOU ARE CHANGING THE UI TO A RESTRICTED MODE:\n\"" +
|
||||
Utils::String::toUpper(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?";
|
||||
msg += "DO YOU WANT TO PROCEED?";
|
||||
window->pushGui(new GuiMsgBox(window, this->getHelpStyle(), msg,
|
||||
"YES", [selectedMode] {
|
||||
LOG(LogDebug) << "Setting UI mode to " << selectedMode;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// GuiScreensaverOptions.cpp
|
||||
//
|
||||
// User interface template for the screensaver option GUIs.
|
||||
//
|
||||
|
||||
#include "guis/GuiScreensaverOptions.h"
|
||||
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
|
@ -6,10 +12,10 @@
|
|||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
|
||||
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const char* title) : GuiComponent(window), mMenu(window, title)
|
||||
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const char* title)
|
||||
: GuiComponent(window), mMenu(window, title)
|
||||
{
|
||||
addChild(&mMenu);
|
||||
|
||||
mMenu.addButton("BACK", "back", [this] { delete this; });
|
||||
|
||||
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||
|
@ -60,12 +66,14 @@ std::vector<HelpPrompt> GuiScreensaverOptions::getHelpPrompts()
|
|||
return prompts;
|
||||
}
|
||||
|
||||
void GuiScreensaverOptions::addEditableTextComponent(ComponentListRow row, const std::string label, std::shared_ptr<GuiComponent> ed, std::string value)
|
||||
void GuiScreensaverOptions::addEditableTextComponent(ComponentListRow row,
|
||||
const std::string label, std::shared_ptr<GuiComponent> ed, std::string value)
|
||||
{
|
||||
row.elements.clear();
|
||||
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label), Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
row.addElement(lbl, true); // label
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label),
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
row.addElement(lbl, true); // Label.
|
||||
|
||||
row.addElement(ed, true);
|
||||
|
||||
|
@ -78,9 +86,11 @@ void GuiScreensaverOptions::addEditableTextComponent(ComponentListRow row, const
|
|||
bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight()));
|
||||
row.addElement(bracket, false);
|
||||
|
||||
auto updateVal = [ed](const std::string& newVal) { ed->setValue(newVal); }; // ok callback (apply new value to ed)
|
||||
// OK callback (apply new value to ed).
|
||||
auto updateVal = [ed](const std::string& newVal) { ed->setValue(newVal); };
|
||||
row.makeAcceptInputHandler([this, label, ed, updateVal] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label, ed->getValue(), updateVal, false));
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label,
|
||||
ed->getValue(), updateVal, false));
|
||||
});
|
||||
assert(ed);
|
||||
addRow(row);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// GuiScreensaverOptions.h
|
||||
//
|
||||
// User interface template for the screensaver option GUIs.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_APP_GUIS_GUI_SCREENSAVER_OPTIONS_H
|
||||
#define ES_APP_GUIS_GUI_SCREENSAVER_OPTIONS_H
|
||||
|
@ -9,13 +15,15 @@ class GuiScreensaverOptions : public GuiComponent
|
|||
{
|
||||
public:
|
||||
GuiScreensaverOptions(Window* window, const char* title);
|
||||
virtual ~GuiScreensaverOptions(); // just calls save();
|
||||
virtual ~GuiScreensaverOptions(); // Just calls save()
|
||||
|
||||
virtual void save();
|
||||
inline void addRow(const ComponentListRow& row) { mMenu.addRow(row); };
|
||||
inline void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
|
||||
inline void addWithLabel(const std::string& label,
|
||||
const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
|
||||
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
||||
void addEditableTextComponent(ComponentListRow row, const std::string label, std::shared_ptr<GuiComponent> ed, std::string value);
|
||||
void addEditableTextComponent(ComponentListRow row,
|
||||
const std::string label, std::shared_ptr<GuiComponent> ed, std::string value);
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
//
|
||||
// Scripting.cpp
|
||||
//
|
||||
// Executes custom scripts for various events in EmulationStation.
|
||||
// By calling fireEvent() the scripts inside the directory corresponding to the
|
||||
// argument 'eventName' will be executed with arg1 and arg2 as the script arguments.
|
||||
//
|
||||
// The scripts are searched for in $HOME/.emulationstation/scripts/<eventName>.
|
||||
// For example, if the event is called 'game-start', all scripts inside the directory
|
||||
// $HOME/.emulationstation/scripts/game-start/ will be executed.
|
||||
//
|
||||
|
||||
#include "Scripting.h"
|
||||
#include "Log.h"
|
||||
#include "Platform.h"
|
||||
|
@ -12,25 +24,21 @@ namespace Scripting
|
|||
std::list<std::string> scriptDirList;
|
||||
std::string test;
|
||||
|
||||
// check in exepath
|
||||
test = Utils::FileSystem::getExePath() + "/scripts/" + eventName;
|
||||
if(Utils::FileSystem::exists(test))
|
||||
scriptDirList.push_back(test);
|
||||
|
||||
// check in homepath
|
||||
// Check in homepath.
|
||||
test = Utils::FileSystem::getHomePath() + "/.emulationstation/scripts/" + eventName;
|
||||
if(Utils::FileSystem::exists(test))
|
||||
scriptDirList.push_back(test);
|
||||
|
||||
for(std::list<std::string>::const_iterator dirIt = scriptDirList.cbegin(); dirIt != scriptDirList.cend(); ++dirIt) {
|
||||
for(std::list<std::string>::const_iterator dirIt = scriptDirList.cbegin();
|
||||
dirIt != scriptDirList.cend(); ++dirIt) {
|
||||
std::list<std::string> scripts = Utils::FileSystem::getDirContent(*dirIt);
|
||||
for (std::list<std::string>::const_iterator it = scripts.cbegin(); it != scripts.cend(); ++it) {
|
||||
// append folder to path
|
||||
for (std::list<std::string>::const_iterator it = scripts.cbegin();
|
||||
it != scripts.cend(); ++it) {
|
||||
// Append folder to path.
|
||||
std::string script = *it + " \"" + arg1 + "\" \"" + arg2 + "\"";
|
||||
LOG(LogDebug) << " executing: " << script;
|
||||
runSystemCommand(script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Scripting::
|
||||
}
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
//
|
||||
// Scripting.h
|
||||
//
|
||||
// Executes custom scripts for various events in EmulationStation.
|
||||
// By calling fireEvent() the scripts inside the directory corresponding to the
|
||||
// argument 'eventName' will be executed with arg1 and arg2 as the script arguments.
|
||||
//
|
||||
// The scripts are searched for in $HOME/.emulationstation/scripts/<eventName>.
|
||||
// For example, if the event is called 'game-start', all scripts inside the directory
|
||||
// $HOME/.emulationstation/scripts/game-start/ will be executed.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_SCRIPTING_H
|
||||
#define ES_CORE_SCRIPTING_H
|
||||
|
@ -6,7 +18,8 @@
|
|||
|
||||
namespace Scripting
|
||||
{
|
||||
void fireEvent(const std::string& eventName, const std::string& arg1="", const std::string& arg2="");
|
||||
} // Scripting::
|
||||
void fireEvent(const std::string& eventName,
|
||||
const std::string& arg1="", const std::string& arg2="");
|
||||
}
|
||||
|
||||
#endif //ES_CORE_SCRIPTING_H
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
//
|
||||
// ThemeData.cpp
|
||||
//
|
||||
// Theme handling.
|
||||
// Finds available themes on the file system and loads these,
|
||||
// including the parsing of individual theme components
|
||||
// (includes, features, variables, views, elements).
|
||||
//
|
||||
|
||||
#include "ThemeData.h"
|
||||
|
@ -417,7 +419,6 @@ void ThemeData::parseView(const pugi::xml_node& root, ThemeView& view)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ThemeData::parseElement(const pugi::xml_node& root,
|
||||
const std::map<std::string, ElementPropertyType>& typeMap, ThemeElement& element)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
//
|
||||
// ThemeData.h
|
||||
//
|
||||
// Theme handling.
|
||||
// Finds available themes on the file system and loads these,
|
||||
// including the parsing of individual theme components
|
||||
// (includes, features, variables, views, elements).
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
@ -148,7 +150,6 @@ private:
|
|||
};
|
||||
|
||||
public:
|
||||
|
||||
ThemeData();
|
||||
|
||||
// Throws ThemeException.
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// FileSystemUtil.cpp
|
||||
//
|
||||
// Low-level filesystem functions.
|
||||
//
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
@ -5,8 +11,8 @@
|
|||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
// because windows...
|
||||
#ifdef WIN32
|
||||
// Because windows...
|
||||
#include <direct.h>
|
||||
#include <Windows.h>
|
||||
#define getcwd _getcwd
|
||||
|
@ -16,27 +22,28 @@
|
|||
#define unlink _unlink
|
||||
#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
|
||||
#else // _WIN32
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
|
||||
// Try to ascertain the install prefix as defined when CMake was run.
|
||||
// Try to get the install prefix as defined when CMake was run.
|
||||
// The installPrefix directory is the value set for CMAKE_INSTALL_DIRECTORY during build.
|
||||
// The datarootdir directory is the value set for CMAKE_INSTALL_DATAROOTDIR during build.
|
||||
// If not defined, the default prefix path '/usr/local' and the default datarootdir
|
||||
// directory 'share' will be used, i.e. combining to '/usr/local/share'.
|
||||
#ifdef __unix__
|
||||
#ifdef ES_INSTALL_PREFIX
|
||||
std::string installPrefix = ES_INSTALL_PREFIX;
|
||||
#else
|
||||
std::string installPrefix = "/usr/local";
|
||||
#endif
|
||||
|
||||
#ifdef ES_DATAROOTDIR
|
||||
std::string dataRootDir = ES_DATAROOTDIR;
|
||||
#else
|
||||
std::string dataRootDir = "share";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
|
@ -45,91 +52,76 @@ namespace Utils
|
|||
static std::string homePath = "";
|
||||
static std::string exePath = "";
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
static std::string convertFromWideString(const std::wstring wstring)
|
||||
{
|
||||
int numBytes = WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(), (int)wstring.length(), nullptr, 0, nullptr, nullptr);
|
||||
int numBytes = WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(),
|
||||
(int)wstring.length(), nullptr, 0, nullptr, nullptr);
|
||||
std::string string;
|
||||
|
||||
string.resize(numBytes);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(), (int)wstring.length(), (char*)string.c_str(), numBytes, nullptr, nullptr);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstring.c_str(), (int)wstring.length(),
|
||||
(char*)string.c_str(), numBytes, nullptr, nullptr);
|
||||
|
||||
return std::string(string);
|
||||
|
||||
} // convertFromWideString
|
||||
#endif // _WIN32
|
||||
}
|
||||
#endif
|
||||
|
||||
stringList getDirContent(const std::string& _path, const bool _recursive)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
stringList contentList;
|
||||
|
||||
// only parse the directory, if it's a directory
|
||||
if(isDirectory(path))
|
||||
{
|
||||
// Only parse the directory, if it's a directory.
|
||||
if (isDirectory(path)) {
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
WIN32_FIND_DATAW findData;
|
||||
std::string wildcard = path + "/*";
|
||||
HANDLE hFind = FindFirstFileW(std::wstring(wildcard.begin(), wildcard.end()).c_str(), &findData);
|
||||
HANDLE hFind = FindFirstFileW(std::wstring(wildcard.begin(),
|
||||
wildcard.end()).c_str(), &findData);
|
||||
|
||||
if(hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// loop over all files in the directory
|
||||
do
|
||||
{
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
// Loop over all files in the directory.
|
||||
do {
|
||||
std::string name = convertFromWideString(findData.cFileName);
|
||||
|
||||
// ignore "." and ".."
|
||||
if((name != ".") && (name != ".."))
|
||||
{
|
||||
// Ignore "." and ".."
|
||||
if ((name != ".") && (name != "..")) {
|
||||
std::string fullName(getGenericPath(path + "/" + name));
|
||||
contentList.push_back(fullName);
|
||||
|
||||
if(_recursive && isDirectory(fullName))
|
||||
if (_recursive && isDirectory(fullName))
|
||||
contentList.merge(getDirContent(fullName, true));
|
||||
}
|
||||
}
|
||||
while(FindNextFileW(hFind, &findData));
|
||||
|
||||
while (FindNextFileW(hFind, &findData));
|
||||
FindClose(hFind);
|
||||
}
|
||||
#else // _WIN32
|
||||
#else
|
||||
DIR* dir = opendir(path.c_str());
|
||||
|
||||
if(dir != NULL)
|
||||
{
|
||||
if (dir != NULL) {
|
||||
struct dirent* entry;
|
||||
|
||||
// loop over all files in the directory
|
||||
while((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Loop over all files in the directory.
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
std::string name(entry->d_name);
|
||||
|
||||
// ignore "." and ".."
|
||||
if((name != ".") && (name != ".."))
|
||||
{
|
||||
// Ignore "." and ".."
|
||||
if ((name != ".") && (name != "..")) {
|
||||
std::string fullName(getGenericPath(path + "/" + name));
|
||||
contentList.push_back(fullName);
|
||||
|
||||
if(_recursive && isDirectory(fullName))
|
||||
if (_recursive && isDirectory(fullName))
|
||||
contentList.merge(getDirContent(fullName, true));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// sort the content list
|
||||
contentList.sort();
|
||||
|
||||
// return the content list
|
||||
return contentList;
|
||||
|
||||
} // getDirContent
|
||||
}
|
||||
|
||||
stringList getPathList(const std::string& _path)
|
||||
{
|
||||
|
@ -138,108 +130,105 @@ namespace Utils
|
|||
size_t start = 0;
|
||||
size_t end = 0;
|
||||
|
||||
// split at '/'
|
||||
while((end = path.find("/", start)) != std::string::npos)
|
||||
{
|
||||
if(end != start)
|
||||
// Split at '/'
|
||||
while ((end = path.find("/", start)) != std::string::npos) {
|
||||
if (end != start)
|
||||
pathList.push_back(std::string(path, start, end - start));
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
// add last folder / file to pathList
|
||||
if(start != path.size())
|
||||
// Add last folder / file to pathList.
|
||||
if (start != path.size())
|
||||
pathList.push_back(std::string(path, start, path.size() - start));
|
||||
|
||||
// return the path list
|
||||
return pathList;
|
||||
|
||||
} // getPathList
|
||||
}
|
||||
|
||||
void setHomePath(const std::string& _path)
|
||||
{
|
||||
homePath = getGenericPath(_path);
|
||||
|
||||
} // setHomePath
|
||||
}
|
||||
|
||||
std::string getHomePath()
|
||||
{
|
||||
// only construct the homepath once
|
||||
if(homePath.length())
|
||||
// Only construct the homepath once.
|
||||
if (homePath.length())
|
||||
return homePath;
|
||||
|
||||
// check if "getExePath()/.emulationstation/es_systems.cfg" exists
|
||||
if(Utils::FileSystem::exists(getExePath() + "/.emulationstation/es_systems.cfg"))
|
||||
homePath = getExePath();
|
||||
|
||||
// check for HOME environment variable
|
||||
if(!homePath.length())
|
||||
{
|
||||
char* envHome = getenv("HOME");
|
||||
if(envHome)
|
||||
// Check for HOME environment variable.
|
||||
if (!homePath.length()) {
|
||||
std::string envHome = getenv("HOME");
|
||||
if (envHome.length())
|
||||
homePath = getGenericPath(envHome);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// on Windows we need to check HOMEDRIVE and HOMEPATH
|
||||
if(!homePath.length())
|
||||
{
|
||||
char* envHomeDrive = getenv("HOMEDRIVE");
|
||||
char* envHomePath = getenv("HOMEPATH");
|
||||
if(envHomeDrive && envHomePath)
|
||||
homePath = getGenericPath(std::string(envHomeDrive) + "/" + envHomePath);
|
||||
#if defined(_WIN32)
|
||||
// On Windows we need to check HOMEDRIVE and HOMEPATH.
|
||||
if (!homePath.length()) {
|
||||
std::string envHomeDrive = getenv("HOMEDRIVE");
|
||||
std::string envHomePath = getenv("HOMEPATH");
|
||||
if (envHomeDrive.length() && envHomePath.length())
|
||||
homePath = getGenericPath(envHomeDrive + "/" + envHomePath);
|
||||
}
|
||||
#endif // _WIN32
|
||||
#endif // _WIN32
|
||||
|
||||
// no homepath found, fall back to current working directory
|
||||
if(!homePath.length())
|
||||
// No homepath found, fall back to current working directory.
|
||||
if (!homePath.length())
|
||||
homePath = getCWDPath();
|
||||
|
||||
// return constructed homepath
|
||||
return homePath;
|
||||
|
||||
} // getHomePath
|
||||
}
|
||||
|
||||
std::string getCWDPath()
|
||||
{
|
||||
char temp[512];
|
||||
|
||||
// return current working directory path
|
||||
// Return current working directory.
|
||||
return (getcwd(temp, 512) ? getGenericPath(temp) : "");
|
||||
|
||||
} // getCWDPath
|
||||
}
|
||||
|
||||
void setExePath(const std::string& _path)
|
||||
{
|
||||
constexpr int path_max = 32767;
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
std::wstring result(path_max, 0);
|
||||
if(GetModuleFileNameW(nullptr, &result[0], path_max) != 0)
|
||||
if (GetModuleFileNameW(nullptr, &result[0], path_max) != 0)
|
||||
exePath = convertFromWideString(result);
|
||||
#else
|
||||
#else
|
||||
std::string result(path_max, 0);
|
||||
if(readlink("/proc/self/exe", &result[0], path_max) != -1)
|
||||
if (readlink("/proc/self/exe", &result[0], path_max) != -1)
|
||||
exePath = result;
|
||||
#endif
|
||||
#endif
|
||||
exePath = getCanonicalPath(exePath);
|
||||
|
||||
// Fallback to argv[0] if everything else fails
|
||||
// Fallback to argv[0] if everything else fails.
|
||||
if (exePath.empty())
|
||||
exePath = getCanonicalPath(_path);
|
||||
if(isRegularFile(exePath))
|
||||
if (isRegularFile(exePath))
|
||||
exePath = getParent(exePath);
|
||||
|
||||
} // setExePath
|
||||
}
|
||||
|
||||
std::string getExePath()
|
||||
{
|
||||
// return constructed exepath
|
||||
return exePath;
|
||||
|
||||
} // getExePath
|
||||
}
|
||||
|
||||
std::string getInstallPrefixPath()
|
||||
{
|
||||
// There seems to be a bug in CMake that when deleting the CMakeCache.txt
|
||||
// file and running cmake, the ES_DATAROOTDIR is not populated, i.e. this fails:
|
||||
// add_definitions(-DES_DATAROOTDIR="${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
// Re-running cmake a second time populates it correctly. But ES_INSTALL_PREFIX
|
||||
// is always populated correctly on my machine which is very strange.
|
||||
// Anyway, as an extra precaution, let's set datarootdir to 'share' if it's blank,
|
||||
// as that's what most people would want anyway. When this bug has been fixed in
|
||||
// CMake this code can be removed.
|
||||
// Just in case, let's set installPrefix to '/usr/local' if blank as well as a
|
||||
// fallback precaution as maybe some make environments won't handle this
|
||||
// correctly either.
|
||||
if (!installPrefix.length())
|
||||
installPrefix = "/usr/local";
|
||||
if (!dataRootDir.length())
|
||||
dataRootDir = "share";
|
||||
return installPrefix + "/" + dataRootDir;
|
||||
}
|
||||
|
||||
|
@ -247,11 +236,11 @@ namespace Utils
|
|||
{
|
||||
std::string path = _path;
|
||||
size_t offset = std::string::npos;
|
||||
#if defined(_WIN32)
|
||||
// convert '/' to '\\'
|
||||
while((offset = path.find('/')) != std::string::npos)
|
||||
#if defined(_WIN32)
|
||||
// Convert '/' to '\\'
|
||||
while ((offset = path.find('/')) != std::string::npos)
|
||||
path.replace(offset, 1, "\\");
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -260,120 +249,108 @@ namespace Utils
|
|||
std::string path = _path;
|
||||
size_t offset = std::string::npos;
|
||||
|
||||
// remove "\\\\?\\"
|
||||
if((path.find("\\\\?\\")) == 0)
|
||||
// Remove "\\\\?\\"
|
||||
if ((path.find("\\\\?\\")) == 0)
|
||||
path.erase(0, 4);
|
||||
|
||||
// convert '\\' to '/'
|
||||
while((offset = path.find('\\')) != std::string::npos)
|
||||
// Convert '\\' to '/'
|
||||
while ((offset = path.find('\\')) != std::string::npos)
|
||||
path.replace(offset, 1 ,"/");
|
||||
|
||||
// remove double '/'
|
||||
while((offset = path.find("//")) != std::string::npos)
|
||||
// Remove double '/'
|
||||
while ((offset = path.find("//")) != std::string::npos)
|
||||
path.erase(offset, 1);
|
||||
|
||||
// remove trailing '/' when the path is more than a simple '/'
|
||||
while(path.length() > 1 && ((offset = path.find_last_of('/')) == (path.length() - 1)))
|
||||
// Remove trailing '/' when the path is more than a simple '/'
|
||||
while (path.length() > 1 && ((offset = path.find_last_of('/')) == (path.length() - 1)))
|
||||
path.erase(offset, 1);
|
||||
|
||||
// return generic path
|
||||
return path;
|
||||
|
||||
} // getGenericPath
|
||||
}
|
||||
|
||||
std::string getEscapedPath(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
#if defined(_WIN32)
|
||||
// windows escapes stuff by just putting everything in quotes
|
||||
#if defined(_WIN32)
|
||||
// Windows escapes stuff by just putting everything in quotes.
|
||||
return '"' + getPreferredPath(path) + '"';
|
||||
#else // _WIN32
|
||||
// insert a backslash before most characters that would mess up a bash path
|
||||
#else
|
||||
// Insert a backslash before most characters that would mess up a bash path.
|
||||
const char* invalidChars = "\\ '\"!$^&*(){}[]?;<>";
|
||||
const char* invalidChar = invalidChars;
|
||||
|
||||
while(*invalidChar)
|
||||
{
|
||||
while (*invalidChar) {
|
||||
size_t start = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
while((offset = path.find(*invalidChar, start)) != std::string::npos)
|
||||
{
|
||||
while ((offset = path.find(*invalidChar, start)) != std::string::npos) {
|
||||
start = offset + 1;
|
||||
|
||||
if((offset == 0) || (path[offset - 1] != '\\'))
|
||||
{
|
||||
if ((offset == 0) || (path[offset - 1] != '\\')) {
|
||||
path.insert(offset, 1, '\\');
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
++invalidChar;
|
||||
}
|
||||
|
||||
// return escaped path
|
||||
return path;
|
||||
#endif // _WIN32
|
||||
|
||||
} // getEscapedPath
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getCanonicalPath(const std::string& _path)
|
||||
{
|
||||
// temporary hack for builtin resources
|
||||
if((_path[0] == ':') && (_path[1] == '/'))
|
||||
// Hack for builtin resources.
|
||||
if ((_path[0] == ':') && (_path[1] == '/'))
|
||||
return _path;
|
||||
|
||||
std::string path = exists(_path) ? getAbsolutePath(_path) : getGenericPath(_path);
|
||||
|
||||
// cleanup path
|
||||
// Cleanup path.
|
||||
bool scan = true;
|
||||
while(scan)
|
||||
{
|
||||
while (scan) {
|
||||
stringList pathList = getPathList(path);
|
||||
|
||||
path.clear();
|
||||
scan = false;
|
||||
|
||||
for(stringList::const_iterator it = pathList.cbegin(); it != pathList.cend(); ++it)
|
||||
{
|
||||
// ignore empty
|
||||
if((*it).empty())
|
||||
for (stringList::const_iterator it = pathList.cbegin();
|
||||
it != pathList.cend(); ++it) {
|
||||
// Ignore empty.
|
||||
if ((*it).empty())
|
||||
continue;
|
||||
|
||||
// remove "/./"
|
||||
if((*it) == ".")
|
||||
// Remove "/./"
|
||||
if ((*it) == ".")
|
||||
continue;
|
||||
|
||||
// resolve "/../"
|
||||
if((*it) == "..")
|
||||
{
|
||||
// Resolve "/../"
|
||||
if ((*it) == "..") {
|
||||
path = getParent(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
// append folder to path
|
||||
#if defined(_WIN32)
|
||||
// Append folder to path.
|
||||
path += (path.size() == 0) ? (*it) : ("/" + (*it));
|
||||
#else // _WIN32
|
||||
// append folder to path
|
||||
#else
|
||||
// Append folder to path.
|
||||
path += ("/" + (*it));
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
|
||||
// resolve symlink
|
||||
if(isSymlink(path))
|
||||
{
|
||||
// Resolve symlink.
|
||||
if (isSymlink(path)) {
|
||||
std::string resolved = resolveSymlink(path);
|
||||
|
||||
if(resolved.empty())
|
||||
if (resolved.empty())
|
||||
return "";
|
||||
|
||||
if(isAbsolute(resolved))
|
||||
if (isAbsolute(resolved))
|
||||
path = resolved;
|
||||
else
|
||||
path = getParent(path) + "/" + resolved;
|
||||
|
||||
for(++it; it != pathList.cend(); ++it)
|
||||
for (++it; it != pathList.cend(); ++it)
|
||||
path += (path.size() == 0) ? (*it) : ("/" + (*it));
|
||||
|
||||
scan = true;
|
||||
|
@ -381,316 +358,290 @@ namespace Utils
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return canonical path
|
||||
return path;
|
||||
|
||||
} // getCanonicalPath
|
||||
}
|
||||
|
||||
std::string getAbsolutePath(const std::string& _path, const std::string& _base)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
std::string base = isAbsolute(_base) ? getGenericPath(_base) : getAbsolutePath(_base);
|
||||
|
||||
// return absolute path
|
||||
// Return absolute path.
|
||||
return isAbsolute(path) ? path : getGenericPath(base + "/" + path);
|
||||
|
||||
} // getAbsolutePath
|
||||
}
|
||||
|
||||
std::string getParent(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
size_t offset = std::string::npos;
|
||||
|
||||
// find last '/' and erase it
|
||||
if((offset = path.find_last_of('/')) != std::string::npos)
|
||||
// Find last '/' and erase it.
|
||||
if ((offset = path.find_last_of('/')) != std::string::npos)
|
||||
return path.erase(offset);
|
||||
|
||||
// no parent found
|
||||
// No parent found.
|
||||
return path;
|
||||
|
||||
} // getParent
|
||||
}
|
||||
|
||||
std::string getFileName(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
size_t offset = std::string::npos;
|
||||
|
||||
// find last '/' and return the filename
|
||||
if((offset = path.find_last_of('/')) != std::string::npos)
|
||||
// Find last '/' and return the filename.
|
||||
if ((offset = path.find_last_of('/')) != std::string::npos)
|
||||
return ((path[offset + 1] == 0) ? "." : std::string(path, offset + 1));
|
||||
|
||||
// no '/' found, entire path is a filename
|
||||
// No '/' found, entire path is a filename.
|
||||
return path;
|
||||
|
||||
} // getFileName
|
||||
}
|
||||
|
||||
std::string getStem(const std::string& _path)
|
||||
{
|
||||
std::string fileName = getFileName(_path);
|
||||
size_t offset = std::string::npos;
|
||||
|
||||
// empty fileName
|
||||
if(fileName == ".")
|
||||
// Empty fileName.
|
||||
if (fileName == ".")
|
||||
return fileName;
|
||||
|
||||
// find last '.' and erase the extension
|
||||
if((offset = fileName.find_last_of('.')) != std::string::npos)
|
||||
// Find last '.' and erase the extension.
|
||||
if ((offset = fileName.find_last_of('.')) != std::string::npos)
|
||||
return fileName.erase(offset);
|
||||
|
||||
// no '.' found, filename has no extension
|
||||
// No '.' found, filename has no extension.
|
||||
return fileName;
|
||||
|
||||
} // getStem
|
||||
}
|
||||
|
||||
std::string getExtension(const std::string& _path)
|
||||
{
|
||||
std::string fileName = getFileName(_path);
|
||||
size_t offset = std::string::npos;
|
||||
|
||||
// empty fileName
|
||||
if(fileName == ".")
|
||||
// Empty fileName.
|
||||
if (fileName == ".")
|
||||
return fileName;
|
||||
|
||||
// find last '.' and return the extension
|
||||
if((offset = fileName.find_last_of('.')) != std::string::npos)
|
||||
// Find last '.' and return the extension.
|
||||
if ((offset = fileName.find_last_of('.')) != std::string::npos)
|
||||
return std::string(fileName, offset);
|
||||
|
||||
// no '.' found, filename has no extension
|
||||
// No '.' found, filename has no extension.
|
||||
return ".";
|
||||
}
|
||||
|
||||
} // getExtension
|
||||
|
||||
std::string resolveRelativePath(const std::string& _path, const std::string& _relativeTo, const bool _allowHome)
|
||||
std::string resolveRelativePath(const std::string& _path,
|
||||
const std::string& _relativeTo, const bool _allowHome)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
std::string relativeTo = isDirectory(_relativeTo) ? getGenericPath(_relativeTo) : getParent(_relativeTo);
|
||||
std::string relativeTo = isDirectory(_relativeTo) ?
|
||||
getGenericPath(_relativeTo) : getParent(_relativeTo);
|
||||
|
||||
// nothing to resolve
|
||||
if(!path.length())
|
||||
// Nothing to resolve.
|
||||
if (!path.length())
|
||||
return path;
|
||||
|
||||
// replace '.' with relativeTo
|
||||
if((path[0] == '.') && (path[1] == '/'))
|
||||
// Replace '.' with relativeTo.
|
||||
if ((path[0] == '.') && (path[1] == '/'))
|
||||
return (relativeTo + &(path[1]));
|
||||
|
||||
// replace '~' with homePath
|
||||
if(_allowHome && (path[0] == '~') && (path[1] == '/'))
|
||||
// Replace '~' with homePath.
|
||||
if (_allowHome && (path[0] == '~') && (path[1] == '/'))
|
||||
return (getHomePath() + &(path[1]));
|
||||
|
||||
// nothing to resolve
|
||||
// Nothing to resolve.
|
||||
return path;
|
||||
}
|
||||
|
||||
} // resolveRelativePath
|
||||
|
||||
std::string createRelativePath(const std::string& _path, const std::string& _relativeTo, const bool _allowHome)
|
||||
std::string createRelativePath(const std::string& _path,
|
||||
const std::string& _relativeTo, const bool _allowHome)
|
||||
{
|
||||
bool contains = false;
|
||||
std::string path = removeCommonPath(_path, _relativeTo, contains);
|
||||
|
||||
// success
|
||||
if(contains)
|
||||
if (contains)
|
||||
return ("./" + path);
|
||||
|
||||
if(_allowHome)
|
||||
{
|
||||
if (_allowHome) {
|
||||
path = removeCommonPath(_path, getHomePath(), contains);
|
||||
|
||||
// success
|
||||
if(contains)
|
||||
if (contains)
|
||||
return ("~/" + path);
|
||||
}
|
||||
|
||||
// nothing to resolve
|
||||
return path;
|
||||
}
|
||||
|
||||
} // createRelativePath
|
||||
|
||||
std::string removeCommonPath(const std::string& _path, const std::string& _common, bool& _contains)
|
||||
std::string removeCommonPath(const std::string& _path,
|
||||
const std::string& _common, bool& _contains)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
std::string common = isDirectory(_common) ? getGenericPath(_common) : getParent(_common);
|
||||
std::string common = isDirectory(_common) ?
|
||||
getGenericPath(_common) : getParent(_common);
|
||||
|
||||
// check if path contains common
|
||||
if(path.find(common) == 0)
|
||||
{
|
||||
// Check if path contains common.
|
||||
if (path.find(common) == 0) {
|
||||
_contains = true;
|
||||
return path.substr(common.length() + 1);
|
||||
}
|
||||
|
||||
// it didn't
|
||||
// It didn't.
|
||||
_contains = false;
|
||||
return path;
|
||||
|
||||
} // removeCommonPath
|
||||
}
|
||||
|
||||
std::string resolveSymlink(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
std::string resolved;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE hFile = CreateFile(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
#if defined(_WIN32)
|
||||
HANDLE hFile = CreateFile(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ,
|
||||
0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
|
||||
if(hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0, FILE_NAME_NORMALIZED) + 1);
|
||||
if(GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(), (DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0)
|
||||
{
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
resolved.resize(GetFinalPathNameByHandle(hFile, nullptr, 0,
|
||||
FILE_NAME_NORMALIZED) + 1);
|
||||
if (GetFinalPathNameByHandle(hFile, (LPSTR)resolved.data(),
|
||||
(DWORD)resolved.size(), FILE_NAME_NORMALIZED) > 0) {
|
||||
resolved.resize(resolved.size() - 1);
|
||||
resolved = getGenericPath(resolved);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
#else // _WIN32
|
||||
#else
|
||||
struct stat info;
|
||||
|
||||
// check if lstat succeeded
|
||||
if(lstat(path.c_str(), &info) == 0)
|
||||
{
|
||||
// Check if lstat succeeded.
|
||||
if (lstat(path.c_str(), &info) == 0) {
|
||||
resolved.resize(info.st_size);
|
||||
if(readlink(path.c_str(), (char*)resolved.data(), resolved.size()) > 0)
|
||||
if (readlink(path.c_str(), (char*)resolved.data(), resolved.size()) > 0)
|
||||
resolved = getGenericPath(resolved);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// return resolved path
|
||||
#endif
|
||||
return resolved;
|
||||
|
||||
} // resolveSymlink
|
||||
}
|
||||
|
||||
bool removeFile(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
// don't remove if it doesn't exists
|
||||
if(!exists(path))
|
||||
// Don't remove if it doesn't exists.
|
||||
if (!exists(path))
|
||||
return true;
|
||||
|
||||
// try to remove file
|
||||
// Try to remove file.
|
||||
return (unlink(path.c_str()) == 0);
|
||||
|
||||
} // removeFile
|
||||
}
|
||||
|
||||
bool createDirectory(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
// don't create if it already exists
|
||||
if(exists(path))
|
||||
// Don't create if it already exists.
|
||||
if (exists(path))
|
||||
return true;
|
||||
|
||||
// try to create directory
|
||||
if(mkdir(path.c_str(), 0755) == 0)
|
||||
// Try to create directory.
|
||||
if (mkdir(path.c_str(), 0755) == 0)
|
||||
return true;
|
||||
|
||||
// failed to create directory, try to create the parent
|
||||
// Failed to create directory, try to create the parent.
|
||||
std::string parent = getParent(path);
|
||||
|
||||
// only try to create parent if it's not identical to path
|
||||
if(parent != path)
|
||||
// Only try to create parent if it's not identical to path.
|
||||
if (parent != path)
|
||||
createDirectory(parent);
|
||||
|
||||
// try to create directory again now that the parent should exist
|
||||
// Try to create directory again now that the parent should exist.
|
||||
return (mkdir(path.c_str(), 0755) == 0);
|
||||
|
||||
} // createDirectory
|
||||
}
|
||||
|
||||
bool exists(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
struct stat64 info;
|
||||
|
||||
// check if stat64 succeeded
|
||||
return (stat64(path.c_str(), &info) == 0);
|
||||
|
||||
} // exists
|
||||
}
|
||||
|
||||
bool isAbsolute(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
return ((path.size() > 1) && (path[1] == ':'));
|
||||
#else // _WIN32
|
||||
#else
|
||||
return ((path.size() > 0) && (path[0] == '/'));
|
||||
#endif // _WIN32
|
||||
|
||||
} // isAbsolute
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isRegularFile(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
struct stat64 info;
|
||||
|
||||
// check if stat64 succeeded
|
||||
if(stat64(path.c_str(), &info) != 0)
|
||||
if (stat64(path.c_str(), &info) != 0)
|
||||
return false;
|
||||
|
||||
// check for S_IFREG attribute
|
||||
// Check for S_IFREG attribute.
|
||||
return (S_ISREG(info.st_mode));
|
||||
|
||||
} // isRegularFile
|
||||
}
|
||||
|
||||
bool isDirectory(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
struct stat info;
|
||||
|
||||
// check if stat succeeded
|
||||
if(stat(path.c_str(), &info) != 0)
|
||||
if (stat(path.c_str(), &info) != 0)
|
||||
return false;
|
||||
|
||||
// check for S_IFDIR attribute
|
||||
// Check for S_IFDIR attribute.
|
||||
return (S_ISDIR(info.st_mode));
|
||||
|
||||
} // isDirectory
|
||||
}
|
||||
|
||||
bool isSymlink(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
#if defined(_WIN32)
|
||||
// check for symlink attribute
|
||||
#if defined(_WIN32)
|
||||
// Check for symlink attribute.
|
||||
const DWORD Attributes = GetFileAttributes(path.c_str());
|
||||
if((Attributes != INVALID_FILE_ATTRIBUTES) && (Attributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
if ((Attributes != INVALID_FILE_ATTRIBUTES) &&
|
||||
(Attributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
return true;
|
||||
#else // _WIN32
|
||||
#else
|
||||
struct stat info;
|
||||
|
||||
// check if lstat succeeded
|
||||
if(lstat(path.c_str(), &info) != 0)
|
||||
if (lstat(path.c_str(), &info) != 0)
|
||||
return false;
|
||||
|
||||
// check for S_IFLNK attribute
|
||||
// Check for S_IFLNK attribute.
|
||||
return (S_ISLNK(info.st_mode));
|
||||
#endif // _WIN32
|
||||
#endif
|
||||
|
||||
// not a symlink
|
||||
// Not a symlink.
|
||||
return false;
|
||||
|
||||
} // isSymlink
|
||||
}
|
||||
|
||||
bool isHidden(const std::string& _path)
|
||||
{
|
||||
std::string path = getGenericPath(_path);
|
||||
|
||||
#if defined(_WIN32)
|
||||
// check for hidden attribute
|
||||
#if defined(_WIN32)
|
||||
// Check for hidden attribute.
|
||||
const DWORD Attributes = GetFileAttributes(path.c_str());
|
||||
if((Attributes != INVALID_FILE_ATTRIBUTES) && (Attributes & FILE_ATTRIBUTE_HIDDEN))
|
||||
if ((Attributes != INVALID_FILE_ATTRIBUTES) && (Attributes & FILE_ATTRIBUTE_HIDDEN))
|
||||
return true;
|
||||
#endif // _WIN32
|
||||
#endif // _WIN32
|
||||
|
||||
// filenames starting with . are hidden in linux, we do this check for windows as well
|
||||
if(getFileName(path)[0] == '.')
|
||||
// Filenames starting with . are hidden in Linux, but
|
||||
// we do this check for windows as well.
|
||||
if (getFileName(path)[0] == '.')
|
||||
return true;
|
||||
|
||||
// not hidden
|
||||
return false;
|
||||
|
||||
} // isHidden
|
||||
}
|
||||
|
||||
} // FileSystem::
|
||||
|
||||
} // Utils::
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//
|
||||
// FileSystemUtil.h
|
||||
//
|
||||
// Low-level filesystem functions.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef ES_CORE_UTILS_FILE_SYSTEM_UTIL_H
|
||||
#define ES_CORE_UTILS_FILE_SYSTEM_UTIL_H
|
||||
|
@ -11,38 +17,41 @@ namespace Utils
|
|||
{
|
||||
typedef std::list<std::string> stringList;
|
||||
|
||||
stringList getDirContent (const std::string& _path, const bool _recursive = false);
|
||||
stringList getPathList (const std::string& _path);
|
||||
void setHomePath (const std::string& _path);
|
||||
std::string getHomePath ();
|
||||
std::string getCWDPath ();
|
||||
void setExePath (const std::string& _path);
|
||||
std::string getExePath ();
|
||||
stringList getDirContent(const std::string& _path,
|
||||
const bool _recursive = false);
|
||||
stringList getPathList(const std::string& _path);
|
||||
void setHomePath(const std::string& _path);
|
||||
std::string getHomePath();
|
||||
std::string getCWDPath();
|
||||
void setExePath(const std::string& _path);
|
||||
std::string getExePath();
|
||||
std::string getInstallPrefixPath ();
|
||||
std::string getPreferredPath (const std::string& _path);
|
||||
std::string getGenericPath (const std::string& _path);
|
||||
std::string getEscapedPath (const std::string& _path);
|
||||
std::string getCanonicalPath (const std::string& _path);
|
||||
std::string getAbsolutePath (const std::string& _path, const std::string& _base = getCWDPath());
|
||||
std::string getParent (const std::string& _path);
|
||||
std::string getFileName (const std::string& _path);
|
||||
std::string getStem (const std::string& _path);
|
||||
std::string getExtension (const std::string& _path);
|
||||
std::string resolveRelativePath(const std::string& _path, const std::string& _relativeTo, const bool _allowHome);
|
||||
std::string createRelativePath (const std::string& _path, const std::string& _relativeTo, const bool _allowHome);
|
||||
std::string removeCommonPath (const std::string& _path, const std::string& _common, bool& _contains);
|
||||
std::string resolveSymlink (const std::string& _path);
|
||||
bool removeFile (const std::string& _path);
|
||||
bool createDirectory (const std::string& _path);
|
||||
bool exists (const std::string& _path);
|
||||
bool isAbsolute (const std::string& _path);
|
||||
bool isRegularFile (const std::string& _path);
|
||||
bool isDirectory (const std::string& _path);
|
||||
bool isSymlink (const std::string& _path);
|
||||
bool isHidden (const std::string& _path);
|
||||
|
||||
} // FileSystem::
|
||||
|
||||
} // Utils::
|
||||
std::string getPreferredPath(const std::string& _path);
|
||||
std::string getGenericPath(const std::string& _path);
|
||||
std::string getEscapedPath(const std::string& _path);
|
||||
std::string getCanonicalPath(const std::string& _path);
|
||||
std::string getAbsolutePath(const std::string& _path,
|
||||
const std::string& _base = getCWDPath());
|
||||
std::string getParent(const std::string& _path);
|
||||
std::string getFileName(const std::string& _path);
|
||||
std::string getStem(const std::string& _path);
|
||||
std::string getExtension(const std::string& _path);
|
||||
std::string resolveRelativePath(const std::string& _path,
|
||||
const std::string& _relativeTo, const bool _allowHome);
|
||||
std::string createRelativePath(const std::string& _path,
|
||||
const std::string& _relativeTo, const bool _allowHome);
|
||||
std::string removeCommonPath(const std::string& _path,
|
||||
const std::string& _common, bool& _contains);
|
||||
std::string resolveSymlink(const std::string& _path);
|
||||
bool removeFile(const std::string& _path);
|
||||
bool createDirectory(const std::string& _path);
|
||||
bool exists(const std::string& _path);
|
||||
bool isAbsolute(const std::string& _path);
|
||||
bool isRegularFile(const std::string& _path);
|
||||
bool isDirectory(const std::string& _path);
|
||||
bool isSymlink(const std::string& _path);
|
||||
bool isHidden(const std::string& _path);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ES_CORE_UTILS_FILE_SYSTEM_UTIL_H
|
||||
|
|
Loading…
Reference in a new issue