mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-03-06 14:27:43 +00:00
Formatted the es-app source tree using clang-format.
This commit is contained in:
parent
745cf6ff92
commit
af5e32e121
|
@ -21,19 +21,19 @@
|
|||
|
||||
#include "CollectionSystemsManager.h"
|
||||
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "FileData.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "ThemeData.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <pugixml.hpp>
|
||||
|
@ -47,8 +47,10 @@ std::string myCollectionsName = "collections";
|
|||
// saving and deletion of a CollectionSystemsManager instance.
|
||||
CollectionSystemsManager* CollectionSystemsManager::sInstance = nullptr;
|
||||
|
||||
CollectionSystemsManager::CollectionSystemsManager(Window* window) : mWindow(window)
|
||||
CollectionSystemsManager::CollectionSystemsManager(Window* window)
|
||||
: mWindow(window)
|
||||
{
|
||||
// clang-format off
|
||||
CollectionSystemDecl systemDecls[] = {
|
||||
// Type Name Long name Theme folder isCustom
|
||||
{ AUTO_ALL_GAMES, "all", "all games", "auto-allgames", false },
|
||||
|
@ -56,10 +58,11 @@ CollectionSystemsManager::CollectionSystemsManager(Window* window) : mWindow(win
|
|||
{ AUTO_FAVORITES, "favorites", "favorites", "auto-favorites", false },
|
||||
{ CUSTOM_COLLECTION, myCollectionsName, "collections", "custom-collections", true }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Create a map of the collections.
|
||||
std::vector<CollectionSystemDecl> tempSystemDecl = std::vector<CollectionSystemDecl>
|
||||
(systemDecls, systemDecls + sizeof(systemDecls) / sizeof(systemDecls[0]));
|
||||
std::vector<CollectionSystemDecl> tempSystemDecl = std::vector<CollectionSystemDecl>(
|
||||
systemDecls, systemDecls + sizeof(systemDecls) / sizeof(systemDecls[0]));
|
||||
|
||||
for (std::vector<CollectionSystemDecl>::const_iterator it = tempSystemDecl.cbegin();
|
||||
it != tempSystemDecl.cend(); it++)
|
||||
|
@ -95,8 +98,8 @@ CollectionSystemsManager::~CollectionSystemsManager()
|
|||
removeCollectionsFromDisplayedSystems();
|
||||
|
||||
// Delete all custom collections.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = mCustomCollectionSystemsData.cbegin();
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
mCustomCollectionSystemsData.cbegin();
|
||||
it != mCustomCollectionSystemsData.cend(); it++)
|
||||
delete it->second.system;
|
||||
|
||||
|
@ -105,10 +108,9 @@ CollectionSystemsManager::~CollectionSystemsManager()
|
|||
delete mCustomCollectionsBundle;
|
||||
|
||||
// Delete the auto collections systems.
|
||||
for (auto it = mAutoCollectionSystemsData.cbegin();
|
||||
it != mAutoCollectionSystemsData.cend(); it++) {
|
||||
for (auto it = mAutoCollectionSystemsData.cbegin(); // Line break.
|
||||
it != mAutoCollectionSystemsData.cend(); it++)
|
||||
delete (*it).second.system;
|
||||
}
|
||||
|
||||
delete mCollectionEnvData;
|
||||
sInstance = nullptr;
|
||||
|
@ -136,8 +138,8 @@ void CollectionSystemsManager::saveCustomCollection(SystemData* sys)
|
|||
{
|
||||
const std::string rompath = FileData::getROMDirectory();
|
||||
std::string name = sys->getName();
|
||||
std::unordered_map<std::string, FileData*>
|
||||
games = sys->getRootFolder()->getChildrenByFilename();
|
||||
std::unordered_map<std::string, FileData*> games =
|
||||
sys->getRootFolder()->getChildrenByFilename();
|
||||
bool found = mCustomCollectionSystemsData.find(name) != mCustomCollectionSystemsData.cend();
|
||||
|
||||
if (found) {
|
||||
|
@ -155,13 +157,13 @@ void CollectionSystemsManager::saveCustomCollection(SystemData* sys)
|
|||
std::ifstream configFileIn;
|
||||
std::ofstream configFileOut;
|
||||
|
||||
#if defined(_WIN64)
|
||||
configFileIn.open(Utils::String::
|
||||
stringToWideString(getCustomCollectionConfigPath(name)).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
configFileIn.open(
|
||||
Utils::String::stringToWideString(getCustomCollectionConfigPath(name)).c_str());
|
||||
#else
|
||||
configFileIn.open(getCustomCollectionConfigPath(name));
|
||||
#endif
|
||||
for (std::string gameEntry; getline(configFileIn, gameEntry); ) {
|
||||
#endif
|
||||
for (std::string gameEntry; getline(configFileIn, gameEntry);) {
|
||||
std::string gamePath = Utils::String::replace(gameEntry, "%ROMPATH%", rompath);
|
||||
gamePath = Utils::String::replace(gamePath, "//", "/");
|
||||
// Only add the entry if it's not a regular file or a symlink, in other words
|
||||
|
@ -172,8 +174,8 @@ void CollectionSystemsManager::saveCustomCollection(SystemData* sys)
|
|||
}
|
||||
configFileIn.close();
|
||||
|
||||
for (std::unordered_map<std::string, FileData*>::const_iterator
|
||||
it = games.cbegin(); it != games.cend(); it++) {
|
||||
for (std::unordered_map<std::string, FileData*>::const_iterator it = games.cbegin();
|
||||
it != games.cend(); it++) {
|
||||
std::string path = it->first;
|
||||
// If the ROM path of the game begins with the path from the setting
|
||||
// ROMDirectory (or the default ROM directory), then replace it with %ROMPATH%.
|
||||
|
@ -189,12 +191,12 @@ void CollectionSystemsManager::saveCustomCollection(SystemData* sys)
|
|||
auto last = std::unique(fileGameEntries.begin(), fileGameEntries.end());
|
||||
fileGameEntries.erase(last, fileGameEntries.end());
|
||||
|
||||
#if defined(_WIN64)
|
||||
configFileOut.open(Utils::String::
|
||||
stringToWideString(getCustomCollectionConfigPath(name)).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
configFileOut.open(
|
||||
Utils::String::stringToWideString(getCustomCollectionConfigPath(name)).c_str());
|
||||
#else
|
||||
configFileOut.open(getCustomCollectionConfigPath(name));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (auto it = fileGameEntries.cbegin(); it != fileGameEntries.cend(); it++)
|
||||
configFileOut << (*it) << std::endl;
|
||||
|
@ -231,12 +233,11 @@ void CollectionSystemsManager::loadEnabledListFromSettings()
|
|||
Settings::getInstance()->getString("CollectionSystemsAuto"), ",", true);
|
||||
|
||||
// Iterate the map.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator
|
||||
it = mAutoCollectionSystemsData.begin();
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator it =
|
||||
mAutoCollectionSystemsData.begin();
|
||||
it != mAutoCollectionSystemsData.end(); it++) {
|
||||
|
||||
it->second.isEnabled = (std::find(autoSelected.cbegin(),
|
||||
autoSelected.cend(), it->first) != autoSelected.cend());
|
||||
it->second.isEnabled = (std::find(autoSelected.cbegin(), autoSelected.cend(), it->first) !=
|
||||
autoSelected.cend());
|
||||
}
|
||||
|
||||
mHasEnabledCustomCollection = false;
|
||||
|
@ -246,12 +247,11 @@ void CollectionSystemsManager::loadEnabledListFromSettings()
|
|||
Settings::getInstance()->getString("CollectionSystemsCustom"), ",", true);
|
||||
|
||||
// Iterate the map.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator
|
||||
it = mCustomCollectionSystemsData.begin();
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator it =
|
||||
mCustomCollectionSystemsData.begin();
|
||||
it != mCustomCollectionSystemsData.end(); it++) {
|
||||
|
||||
it->second.isEnabled = (std::find(customSelected.cbegin(),
|
||||
customSelected.cend(), it->first) != customSelected.cend());
|
||||
it->second.isEnabled = (std::find(customSelected.cbegin(), customSelected.cend(),
|
||||
it->first) != customSelected.cend());
|
||||
if (it->second.isEnabled)
|
||||
mHasEnabledCustomCollection = true;
|
||||
}
|
||||
|
@ -269,8 +269,8 @@ void CollectionSystemsManager::updateSystemsList()
|
|||
FileData* rootFolder = mCustomCollectionsBundle->getRootFolder();
|
||||
// Sort the bundled custom collections.
|
||||
if (rootFolder->getChildren().size() > 0) {
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->
|
||||
getSortTypeString()), Settings::getInstance()->getBool("FavFirstCustom"));
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
Settings::getInstance()->getBool("FavFirstCustom"));
|
||||
SystemData::sSystemVector.push_back(mCustomCollectionsBundle);
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ void CollectionSystemsManager::updateSystemsList()
|
|||
addEnabledCollectionsToDisplayedSystems(&mAutoCollectionSystemsData);
|
||||
|
||||
// Create views for collections, before reload.
|
||||
for (auto sysIt = SystemData::sSystemVector.cbegin();
|
||||
for (auto sysIt = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
sysIt != SystemData::sSystemVector.cend(); sysIt++) {
|
||||
if ((*sysIt)->isCollection())
|
||||
ViewController::get()->getGameListView((*sysIt));
|
||||
|
@ -311,12 +311,11 @@ void CollectionSystemsManager::refreshCollectionSystems(FileData* file,
|
|||
}
|
||||
|
||||
std::map<std::string, CollectionSystemData> allCollections;
|
||||
allCollections.insert(mAutoCollectionSystemsData.cbegin(),
|
||||
mAutoCollectionSystemsData.cend());
|
||||
allCollections.insert(mAutoCollectionSystemsData.cbegin(), mAutoCollectionSystemsData.cend());
|
||||
allCollections.insert(mCustomCollectionSystemsData.cbegin(),
|
||||
mCustomCollectionSystemsData.cend());
|
||||
|
||||
for (auto sysDataIt = allCollections.cbegin();
|
||||
for (auto sysDataIt = allCollections.cbegin(); // Line break.
|
||||
sysDataIt != allCollections.cend(); sysDataIt++) {
|
||||
if (sysDataIt->second.isEnabled || (refreshDisabledAutoCollections &&
|
||||
!sysDataIt->second.system->isGroupedCustomCollection()))
|
||||
|
@ -363,32 +362,35 @@ void CollectionSystemsManager::updateCollectionSystem(FileData* file, Collection
|
|||
// Found it, and we are removing it.
|
||||
if (name == "favorites" && file->metadata.get("favorite") == "false") {
|
||||
// Need to check if it is still marked as favorite, if not remove it.
|
||||
ViewController::get()->
|
||||
getGameListView(curSys).get()->remove(collectionEntry, false);
|
||||
ViewController::get()->getGameListView(curSys).get()->remove(collectionEntry,
|
||||
false);
|
||||
}
|
||||
else if (name == "recent" && file->metadata.get("lastplayed") == "0") {
|
||||
// If lastplayed is set to 0 it means the entry has been cleared, and the
|
||||
// game should therefore be removed.
|
||||
ViewController::get()->
|
||||
getGameListView(curSys).get()->remove(collectionEntry, false);
|
||||
ViewController::get()->getGameListView(curSys).get()->remove(collectionEntry,
|
||||
false);
|
||||
ViewController::get()->onFileChanged(rootFolder, true);
|
||||
}
|
||||
else if (curSys->isCollection() && !file->getCountAsGame()) {
|
||||
// If the countasgame flag has been set to false, then remove the game.
|
||||
if (curSys->isGroupedCustomCollection()) {
|
||||
ViewController::get()->getGameListView(curSys->getRootFolder()->getParent()->
|
||||
getSystem()).get()->remove(collectionEntry, false);
|
||||
ViewController::get()
|
||||
->getGameListView(curSys->getRootFolder()->getParent()->getSystem())
|
||||
.get()
|
||||
->remove(collectionEntry, false);
|
||||
FileData* parentRootFolder =
|
||||
rootFolder->getParent()->getSystem()->getRootFolder();
|
||||
parentRootFolder->sort(parentRootFolder->getSortTypeFromString(
|
||||
parentRootFolder->getSortTypeString()), mFavoritesSorting);
|
||||
parentRootFolder->getSortTypeString()),
|
||||
mFavoritesSorting);
|
||||
}
|
||||
else {
|
||||
ViewController::get()->
|
||||
getGameListView(curSys).get()->remove(collectionEntry, false);
|
||||
ViewController::get()->getGameListView(curSys).get()->remove(collectionEntry,
|
||||
false);
|
||||
}
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(
|
||||
rootFolder->getSortTypeString()), mFavoritesSorting);
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
mFavoritesSorting);
|
||||
}
|
||||
else {
|
||||
// Re-index with new metadata.
|
||||
|
@ -402,10 +404,12 @@ void CollectionSystemsManager::updateCollectionSystem(FileData* file, Collection
|
|||
if ((name == "recent" && file->metadata.get("playcount") > "0" &&
|
||||
file->getCountAsGame() && includeFileInAutoCollections(file)) ||
|
||||
(name == "favorites" && file->metadata.get("favorite") == "true" &&
|
||||
file->getCountAsGame()))
|
||||
file->getCountAsGame())) {
|
||||
addGame = true;
|
||||
else if (name == "all" && file->getCountAsGame())
|
||||
}
|
||||
else if (name == "all" && file->getCountAsGame()) {
|
||||
addGame = true;
|
||||
}
|
||||
if (addGame) {
|
||||
CollectionFileData* newGame = new CollectionFileData(file, curSys);
|
||||
rootFolder->addChild(newGame);
|
||||
|
@ -424,14 +428,13 @@ void CollectionSystemsManager::updateCollectionSystem(FileData* file, Collection
|
|||
}
|
||||
// If the game doesn't exist in the current system and it's a custom
|
||||
// collection, then skip the sorting.
|
||||
else if (sysData.decl.isCustom &&
|
||||
children.find(file->getFullPath()) != children.cend()) {
|
||||
else if (sysData.decl.isCustom && children.find(file->getFullPath()) != children.cend()) {
|
||||
// For custom collections, update either the actual system or its parent depending
|
||||
// on whether the collection is grouped or not.
|
||||
if (rootFolder->getSystem()->isGroupedCustomCollection()) {
|
||||
rootFolder->getParent()->sort(rootFolder->getParent()->
|
||||
getSortTypeFromString(rootFolder->getParent()->
|
||||
getSortTypeString()), mFavoritesSorting);
|
||||
rootFolder->getParent()->sort(rootFolder->getParent()->getSortTypeFromString(
|
||||
rootFolder->getParent()->getSortTypeString()),
|
||||
mFavoritesSorting);
|
||||
}
|
||||
else {
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
|
@ -453,11 +456,11 @@ void CollectionSystemsManager::updateCollectionSystem(FileData* file, Collection
|
|||
// and therefore jump to the first line. The two seconds is incredibly generous
|
||||
// as normally it would rather be some milliseconds, but who knows what special
|
||||
// circumstances could cause a slight delay so let's keep a large margin.
|
||||
if (Utils::Time::now() -
|
||||
Utils::Time::stringToTime(file->metadata.get("lastplayed")) < 2) {
|
||||
auto nTime = Utils::Time::now();
|
||||
if (nTime - Utils::Time::stringToTime(file->metadata.get("lastplayed")) < 2) {
|
||||
// Select the first row of the gamelist (the game just played).
|
||||
IGameListView* gameList = ViewController::get()->
|
||||
getGameListView(getSystemToView(sysData.system)).get();
|
||||
IGameListView* gameList =
|
||||
ViewController::get()->getGameListView(getSystemToView(sysData.system)).get();
|
||||
gameList->setCursor(gameList->getFirstEntry());
|
||||
}
|
||||
}
|
||||
|
@ -482,8 +485,7 @@ void CollectionSystemsManager::deleteCollectionFiles(FileData* file)
|
|||
|
||||
// Find games in collection systems.
|
||||
std::map<std::string, CollectionSystemData> allCollections;
|
||||
allCollections.insert(mAutoCollectionSystemsData.cbegin(),
|
||||
mAutoCollectionSystemsData.cend());
|
||||
allCollections.insert(mAutoCollectionSystemsData.cbegin(), mAutoCollectionSystemsData.cend());
|
||||
allCollections.insert(mCustomCollectionSystemsData.cbegin(),
|
||||
mCustomCollectionSystemsData.cend());
|
||||
|
||||
|
@ -496,8 +498,10 @@ void CollectionSystemsManager::deleteCollectionFiles(FileData* file)
|
|||
if (found) {
|
||||
FileData* collectionEntry = children.at(key);
|
||||
SystemData* systemViewToUpdate = getSystemToView(sysDataIt->second.system);
|
||||
ViewController::get()->getGameListView(systemViewToUpdate).get()->
|
||||
remove(collectionEntry, false);
|
||||
ViewController::get()
|
||||
->getGameListView(systemViewToUpdate)
|
||||
.get()
|
||||
->remove(collectionEntry, false);
|
||||
if (sysDataIt->second.decl.isCustom)
|
||||
saveCustomCollection(sysDataIt->second.system);
|
||||
}
|
||||
|
@ -543,20 +547,18 @@ std::string CollectionSystemsManager::getValidNewCollectionName(std::string inNa
|
|||
|
||||
if (index == 0) {
|
||||
size_t remove = std::string::npos;
|
||||
|
||||
// Get valid name.
|
||||
while ((remove = name.find_first_not_of(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-[]()' "))
|
||||
!= std::string::npos)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-[]()' ")) !=
|
||||
std::string::npos)
|
||||
name.erase(remove, 1);
|
||||
}
|
||||
else {
|
||||
name += " (" + std::to_string(index) + ")";
|
||||
}
|
||||
|
||||
if (name == "") {
|
||||
if (name == "")
|
||||
name = "new collection";
|
||||
}
|
||||
|
||||
name = Utils::String::toLower(name);
|
||||
|
||||
|
@ -580,13 +582,13 @@ std::string CollectionSystemsManager::getValidNewCollectionName(std::string inNa
|
|||
for (auto sysIt = systemsInUse.cbegin(); sysIt != systemsInUse.cend(); sysIt++) {
|
||||
if (*sysIt == name) {
|
||||
if (index > 0)
|
||||
name = name.substr(0, name.size()-4);
|
||||
return getValidNewCollectionName(name, index+1);
|
||||
name = name.substr(0, name.size() - 4);
|
||||
return getValidNewCollectionName(name, index + 1);
|
||||
}
|
||||
}
|
||||
// If it matches one of the custom collections reserved names then return it.
|
||||
if (mCollectionSystemDeclsIndex.find(name) != mCollectionSystemDeclsIndex.cend())
|
||||
return getValidNewCollectionName(name, index+1);
|
||||
return getValidNewCollectionName(name, index + 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -607,9 +609,11 @@ void CollectionSystemsManager::setEditMode(std::string collectionName, bool show
|
|||
mEditingCollectionSystemData = sysData;
|
||||
|
||||
if (showPopup) {
|
||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow, "EDITING THE '" +
|
||||
Utils::String::toUpper(collectionName) +
|
||||
"' COLLECTION, ADD/REMOVE GAMES WITH 'Y'", 10000);
|
||||
GuiInfoPopup* s =
|
||||
new GuiInfoPopup(mWindow,
|
||||
"EDITING '" + Utils::String::toUpper(collectionName) +
|
||||
"' COLLECTION, ADD/REMOVE GAMES WITH 'Y'",
|
||||
10000);
|
||||
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
|
@ -618,8 +622,10 @@ void CollectionSystemsManager::setEditMode(std::string collectionName, bool show
|
|||
void CollectionSystemsManager::exitEditMode(bool showPopup)
|
||||
{
|
||||
if (showPopup) {
|
||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow, "FINISHED EDITING THE '" +
|
||||
Utils::String::toUpper(mEditingCollection) + "' COLLECTION", 4000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
mWindow,
|
||||
"FINISHED EDITING '" + Utils::String::toUpper(mEditingCollection) + "' COLLECTION",
|
||||
4000);
|
||||
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
|
@ -628,8 +634,7 @@ void CollectionSystemsManager::exitEditMode(bool showPopup)
|
|||
mEditingCollection = "Favorites";
|
||||
|
||||
// Remove all tick marks from the games that are part of the collection.
|
||||
for (auto it = SystemData::sSystemVector.begin();
|
||||
it != SystemData::sSystemVector.end(); it++) {
|
||||
for (auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++) {
|
||||
ViewController::get()->getGameListView((*it))->onFileChanged(
|
||||
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
||||
}
|
||||
|
@ -637,8 +642,8 @@ void CollectionSystemsManager::exitEditMode(bool showPopup)
|
|||
mEditingCollectionSystemData->system->onMetaDataSavePoint();
|
||||
}
|
||||
|
||||
bool CollectionSystemsManager::inCustomCollection(
|
||||
const std::string& collectionName, FileData* gameFile)
|
||||
bool CollectionSystemsManager::inCustomCollection(const std::string& collectionName,
|
||||
FileData* gameFile)
|
||||
{
|
||||
auto collectionEntry = mCustomCollectionSystemsData.find(collectionName);
|
||||
|
||||
|
@ -647,7 +652,6 @@ bool CollectionSystemsManager::inCustomCollection(
|
|||
collectionEntry->second.system->getRootFolder()->getChildrenByFilename();
|
||||
return children.find(gameFile->getFullPath()) != children.cend();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -666,8 +670,8 @@ bool CollectionSystemsManager::toggleGameInCollection(FileData* file)
|
|||
|
||||
std::string key = file->getFullPath();
|
||||
FileData* rootFolder = sysData->getRootFolder();
|
||||
const std::unordered_map<std::string, FileData*>&
|
||||
children = rootFolder->getChildrenByFilename();
|
||||
const std::unordered_map<std::string, FileData*>& children =
|
||||
rootFolder->getChildrenByFilename();
|
||||
bool found = children.find(key) != children.cend();
|
||||
FileFilterIndex* fileIndex = sysData->getIndex();
|
||||
std::string name = sysData->getName();
|
||||
|
@ -678,10 +682,12 @@ bool CollectionSystemsManager::toggleGameInCollection(FileData* file)
|
|||
adding = false;
|
||||
// If we found it, we need to remove it.
|
||||
FileData* collectionEntry = children.at(key);
|
||||
ViewController::get()->getGameListView(systemViewToUpdate).get()->
|
||||
remove(collectionEntry, false);
|
||||
systemViewToUpdate->getRootFolder()->sort(rootFolder->getSortTypeFromString(
|
||||
rootFolder->getSortTypeString()),
|
||||
ViewController::get()
|
||||
->getGameListView(systemViewToUpdate)
|
||||
.get()
|
||||
->remove(collectionEntry, false);
|
||||
systemViewToUpdate->getRootFolder()->sort(
|
||||
rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
Settings::getInstance()->getBool("FavFirstCustom"));
|
||||
ViewController::get()->reloadGameListView(systemViewToUpdate);
|
||||
|
||||
|
@ -692,8 +698,8 @@ bool CollectionSystemsManager::toggleGameInCollection(FileData* file)
|
|||
CollectionFileData* newGame = new CollectionFileData(file, sysData);
|
||||
rootFolder->addChild(newGame);
|
||||
|
||||
systemViewToUpdate->getRootFolder()->sort(rootFolder->getSortTypeFromString(
|
||||
rootFolder->getSortTypeString()),
|
||||
systemViewToUpdate->getRootFolder()->sort(
|
||||
rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
Settings::getInstance()->getBool("FavFirstCustom"));
|
||||
ViewController::get()->onFileChanged(systemViewToUpdate->getRootFolder(), true);
|
||||
fileIndex->addToIndex(newGame);
|
||||
|
@ -722,17 +728,23 @@ bool CollectionSystemsManager::toggleGameInCollection(FileData* file)
|
|||
file->getSourceFileData()->getSystem()->onMetaDataSavePoint();
|
||||
refreshCollectionSystems(file->getSourceFileData());
|
||||
if (mAutoCollectionSystemsData["favorites"].isEnabled)
|
||||
ViewController::get()->
|
||||
reloadGameListView(mAutoCollectionSystemsData["favorites"].system);
|
||||
ViewController::get()->reloadGameListView(
|
||||
mAutoCollectionSystemsData["favorites"].system);
|
||||
}
|
||||
if (adding) {
|
||||
s = new GuiInfoPopup(
|
||||
mWindow,
|
||||
"ADDED '" + Utils::String::toUpper(Utils::String::removeParenthesis(name)) +
|
||||
"' TO '" + Utils::String::toUpper(sysName) + "'",
|
||||
4000);
|
||||
}
|
||||
else {
|
||||
s = new GuiInfoPopup(
|
||||
mWindow,
|
||||
"REMOVED '" + Utils::String::toUpper(Utils::String::removeParenthesis(name)) +
|
||||
"' FROM '" + Utils::String::toUpper(sysName) + "'",
|
||||
4000);
|
||||
}
|
||||
if (adding)
|
||||
s = new GuiInfoPopup(mWindow, "ADDED '" +
|
||||
Utils::String::toUpper(Utils::String::removeParenthesis(name)) +
|
||||
"' TO '" + Utils::String::toUpper(sysName) + "'", 4000);
|
||||
else
|
||||
s = new GuiInfoPopup(mWindow, "REMOVED '" +
|
||||
Utils::String::toUpper(Utils::String::removeParenthesis(name)) +
|
||||
"' FROM '" + Utils::String::toUpper(sysName) + "'", 4000);
|
||||
mWindow->setInfoPopup(s);
|
||||
return true;
|
||||
}
|
||||
|
@ -745,8 +757,8 @@ SystemData* CollectionSystemsManager::getSystemToView(SystemData* sys)
|
|||
FileData* rootFolder = sys->getRootFolder();
|
||||
|
||||
FileData* bundleRootFolder = mCustomCollectionsBundle->getRootFolder();
|
||||
const std::unordered_map<std::string, FileData*>&
|
||||
bundleChildren = bundleRootFolder->getChildrenByFilename();
|
||||
const std::unordered_map<std::string, FileData*>& bundleChildren =
|
||||
bundleRootFolder->getChildrenByFilename();
|
||||
|
||||
// Is the rootFolder bundled in the "My Collections" system?
|
||||
bool sysFoundInBundle = bundleChildren.find(rootFolder->getKey()) != bundleChildren.cend();
|
||||
|
@ -780,7 +792,7 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
|
|||
if (gameCount > 1) {
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::mt19937 engine { randDev() };
|
||||
unsigned int target;
|
||||
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
|
@ -800,23 +812,25 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
|
|||
if (gameCount > 0) {
|
||||
if (Settings::getInstance()->getBool("CollectionShowSystemInfo")) {
|
||||
switch (gameCount) {
|
||||
case 1:
|
||||
case 1: {
|
||||
desc = "This collection contains 1 game: '" +
|
||||
gamesList[0]->metadata.get("name") + " [" +
|
||||
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]'";
|
||||
break;
|
||||
case 2:
|
||||
}
|
||||
case 2: {
|
||||
desc = "This collection contains 2 games: '" +
|
||||
gamesList[0]->metadata.get("name") + " [" +
|
||||
gamesList[0]->getSourceFileData()->getSystem()->getName() +
|
||||
"]' and '" + gamesList[1]->metadata.get("name") + " [" +
|
||||
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]' and '" +
|
||||
gamesList[1]->metadata.get("name") + " [" +
|
||||
gamesList[1]->getSourceFileData()->getSystem()->getName() + "]'";
|
||||
break;
|
||||
default:
|
||||
desc = "This collection contains " + std::to_string(gameCount) +
|
||||
" games: '" + gamesList[0]->metadata.get("name") +
|
||||
" [" + gamesList[0]->getSourceFileData()->getSystem()->getName() +
|
||||
"]', '" + gamesList[1]->metadata.get("name") + " [" +
|
||||
}
|
||||
default: {
|
||||
desc = "This collection contains " + std::to_string(gameCount) + " games: '" +
|
||||
gamesList[0]->metadata.get("name") + " [" +
|
||||
gamesList[0]->getSourceFileData()->getSystem()->getName() + "]', '" +
|
||||
gamesList[1]->metadata.get("name") + " [" +
|
||||
gamesList[1]->getSourceFileData()->getSystem()->getName() + "]' and '" +
|
||||
gamesList[2]->metadata.get("name") + " [" +
|
||||
gamesList[2]->getSourceFileData()->getSystem()->getName() + "]'";
|
||||
|
@ -824,27 +838,31 @@ FileData* CollectionSystemsManager::updateCollectionFolderMetadata(SystemData* s
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (gameCount) {
|
||||
case 1:
|
||||
case 1: {
|
||||
desc = "This collection contains 1 game: '" +
|
||||
gamesList[0]->metadata.get("name") + " '";
|
||||
break;
|
||||
case 2:
|
||||
}
|
||||
case 2: {
|
||||
desc = "This collection contains 2 games: '" +
|
||||
gamesList[0]->metadata.get("name") +
|
||||
"' and '" + gamesList[1]->metadata.get("name") + "'";
|
||||
gamesList[0]->metadata.get("name") + "' and '" +
|
||||
gamesList[1]->metadata.get("name") + "'";
|
||||
break;
|
||||
default:
|
||||
desc = "This collection contains " + std::to_string(gameCount) +
|
||||
" games: '" + gamesList[0]->metadata.get("name") +
|
||||
"', '" + gamesList[1]->metadata.get("name") + "' and '" +
|
||||
}
|
||||
default: {
|
||||
desc = "This collection contains " + std::to_string(gameCount) + " games: '" +
|
||||
gamesList[0]->metadata.get("name") + "', '" +
|
||||
gamesList[1]->metadata.get("name") + "' and '" +
|
||||
gamesList[2]->metadata.get("name") + "'";
|
||||
desc += (gameCount == 3 ? "" : ", among others");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx->isFiltered())
|
||||
desc += "\n\n'" + rootFolder->getSystem()->getFullName() +
|
||||
|
@ -877,7 +895,7 @@ std::vector<std::string> CollectionSystemsManager::getUnusedSystemsFromTheme()
|
|||
systemsInUse.insert(systemsInUse.cend(), customSys.cbegin(), customSys.cend());
|
||||
systemsInUse.insert(systemsInUse.cend(), userSys.cbegin(), userSys.cend());
|
||||
|
||||
for (auto sysIt = themeSys.cbegin(); sysIt != themeSys.cend(); ) {
|
||||
for (auto sysIt = themeSys.cbegin(); sysIt != themeSys.cend();) {
|
||||
if (std::find(systemsInUse.cbegin(), systemsInUse.cend(), *sysIt) != systemsInUse.cend())
|
||||
sysIt = themeSys.erase(sysIt);
|
||||
else
|
||||
|
@ -920,10 +938,12 @@ void CollectionSystemsManager::deleteCustomCollection(std::string collectionName
|
|||
std::string configFile = getCustomCollectionConfigPath(collectionName);
|
||||
Utils::FileSystem::removeFile(configFile);
|
||||
LOG(LogDebug) << "CollectionSystemsManager::deleteCustomCollection(): Deleted the "
|
||||
"configuration file '" << configFile << "'.";
|
||||
"configuration file '"
|
||||
<< configFile << "'.";
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow, "DELETED THE COLLECTION '" +
|
||||
Utils::String::toUpper(collectionName) + "'", 5000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
mWindow, "DELETED COLLECTION '" + Utils::String::toUpper(collectionName) + "'",
|
||||
5000);
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
else {
|
||||
|
@ -941,16 +961,16 @@ void CollectionSystemsManager::reactivateCustomCollectionEntry(FileData* game)
|
|||
// matching entries for the game passed as the parameter. If so, then enable it in each
|
||||
// of those collections. This is done also for disabled collections, as otherwise the
|
||||
// game would be missing if the collection was enabled during the program session.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = mCustomCollectionSystemsData.cbegin();
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
mCustomCollectionSystemsData.cbegin();
|
||||
it != mCustomCollectionSystemsData.cend(); it++) {
|
||||
std::string path = getCustomCollectionConfigPath(it->first);
|
||||
if (Utils::FileSystem::exists(path)) {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::ifstream input(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
std::ifstream input(path);
|
||||
#endif
|
||||
#endif
|
||||
for (std::string gameKey; getline(input, gameKey);) {
|
||||
if (gameKey == gamePath) {
|
||||
setEditMode(it->first, false);
|
||||
|
@ -966,11 +986,12 @@ void CollectionSystemsManager::reactivateCustomCollectionEntry(FileData* game)
|
|||
|
||||
void CollectionSystemsManager::repopulateCollection(SystemData* sysData)
|
||||
{
|
||||
for (auto it = mAutoCollectionSystemsData.cbegin();
|
||||
for (auto it = mAutoCollectionSystemsData.cbegin(); // Line break.
|
||||
it != mAutoCollectionSystemsData.cend(); it++) {
|
||||
if ((*it).second.system == sysData) {
|
||||
LOG(LogDebug) << "CollectionSystemsManager::repopulateCollection(): "
|
||||
"Repopulating auto collection \"" << it->first << "\"";
|
||||
"Repopulating auto collection \""
|
||||
<< it->first << "\"";
|
||||
|
||||
CollectionSystemData* autoSystem = &mAutoCollectionSystemsData[it->first];
|
||||
std::vector<FileData*> systemEntries =
|
||||
|
@ -1005,18 +1026,19 @@ void CollectionSystemsManager::repopulateCollection(SystemData* sysData)
|
|||
autoView->setCursor(autoView->getLastEntry());
|
||||
}
|
||||
else {
|
||||
autoView->setCursor(autoSystem->system->getRootFolder()->
|
||||
getChildrenRecursive().front());
|
||||
autoView->setCursor(
|
||||
autoSystem->system->getRootFolder()->getChildrenRecursive().front());
|
||||
autoView->setCursor(autoView->getFirstEntry());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = mCustomCollectionSystemsData.cbegin();
|
||||
for (auto it = mCustomCollectionSystemsData.cbegin(); // Line break.
|
||||
it != mCustomCollectionSystemsData.cend(); it++) {
|
||||
if ((*it).second.system == sysData) {
|
||||
LOG(LogDebug) << "CollectionSystemsManager::repopulateCollection(): "
|
||||
"Repopulating custom collection '" << it->first << "'.";
|
||||
"Repopulating custom collection '"
|
||||
<< it->first << "'.";
|
||||
|
||||
CollectionSystemData* customSystem = &mCustomCollectionSystemsData[it->first];
|
||||
std::vector<FileData*> systemEntries =
|
||||
|
@ -1035,8 +1057,8 @@ void CollectionSystemsManager::repopulateCollection(SystemData* sysData)
|
|||
populateCustomCollection(customSystem);
|
||||
|
||||
auto autoView = ViewController::get()->getGameListView(customSystem->system).get();
|
||||
autoView->setCursor(customSystem->system->getRootFolder()->
|
||||
getChildrenRecursive().front());
|
||||
autoView->setCursor(
|
||||
customSystem->system->getRootFolder()->getChildrenRecursive().front());
|
||||
autoView->setCursor(autoView->getFirstEntry());
|
||||
}
|
||||
}
|
||||
|
@ -1044,8 +1066,8 @@ void CollectionSystemsManager::repopulateCollection(SystemData* sysData)
|
|||
|
||||
void CollectionSystemsManager::initAutoCollectionSystems()
|
||||
{
|
||||
for (std::map<std::string, CollectionSystemDecl, stringComparator>::const_iterator
|
||||
it = mCollectionSystemDeclsIndex.cbegin();
|
||||
for (std::map<std::string, CollectionSystemDecl, stringComparator>::const_iterator it =
|
||||
mCollectionSystemDeclsIndex.cbegin();
|
||||
it != mCollectionSystemDeclsIndex.cend(); it++) {
|
||||
CollectionSystemDecl sysDecl = it->second;
|
||||
|
||||
|
@ -1071,11 +1093,13 @@ SystemData* CollectionSystemsManager::getAllGamesCollection()
|
|||
return allSysData->system;
|
||||
}
|
||||
|
||||
SystemData* CollectionSystemsManager::createNewCollectionEntry(
|
||||
std::string name, CollectionSystemDecl sysDecl, bool index, bool custom)
|
||||
SystemData* CollectionSystemsManager::createNewCollectionEntry(std::string name,
|
||||
CollectionSystemDecl sysDecl,
|
||||
bool index,
|
||||
bool custom)
|
||||
{
|
||||
SystemData* newSys = new SystemData(name, sysDecl.longName,
|
||||
mCollectionEnvData, sysDecl.themeFolder, true, custom);
|
||||
SystemData* newSys = new SystemData(name, sysDecl.longName, mCollectionEnvData,
|
||||
sysDecl.themeFolder, true, custom);
|
||||
|
||||
CollectionSystemData newCollectionData;
|
||||
newCollectionData.system = newSys;
|
||||
|
@ -1099,7 +1123,7 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD
|
|||
CollectionSystemDecl sysDecl = sysData->decl;
|
||||
FileData* rootFolder = newSys->getRootFolder();
|
||||
FileFilterIndex* index = newSys->getIndex();
|
||||
for (auto sysIt = SystemData::sSystemVector.cbegin();
|
||||
for (auto sysIt = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
sysIt != SystemData::sSystemVector.cend(); sysIt++) {
|
||||
// We won't iterate all collections.
|
||||
if ((*sysIt)->isGameSystem() && !(*sysIt)->isCollection()) {
|
||||
|
@ -1108,17 +1132,20 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD
|
|||
bool include = includeFileInAutoCollections((*gameIt));
|
||||
|
||||
switch (sysDecl.type) {
|
||||
case AUTO_LAST_PLAYED:
|
||||
case AUTO_LAST_PLAYED: {
|
||||
include = include && (*gameIt)->metadata.get("playcount") > "0";
|
||||
break;
|
||||
case AUTO_FAVORITES:
|
||||
}
|
||||
case AUTO_FAVORITES: {
|
||||
// We may still want to add files we don't want in auto collections
|
||||
// to "favorites".
|
||||
include = (*gameIt)->metadata.get("favorite") == "true";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (include) {
|
||||
// Exclude files that are set not to be counted as games.
|
||||
|
@ -1132,6 +1159,7 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rootFolder->getName() == "recent")
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString("last played, ascending"));
|
||||
else
|
||||
|
@ -1148,12 +1176,14 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD
|
|||
// The following is needed to avoid a crash when repopulating the system as the previous
|
||||
// cursor pointer may point to a random memory address.
|
||||
auto recentGamelist = ViewController::get()->getGameListView(rootFolder->getSystem()).get();
|
||||
recentGamelist->setCursor(rootFolder->getSystem()->getRootFolder()->
|
||||
getChildrenRecursive().front());
|
||||
recentGamelist->setCursor(
|
||||
rootFolder->getSystem()->getRootFolder()->getChildrenRecursive().front());
|
||||
recentGamelist->setCursor(recentGamelist->getFirstEntry());
|
||||
if (rootFolder->getChildren().size() > 0)
|
||||
ViewController::get()->getGameListView(rootFolder->getSystem()).get()->
|
||||
onFileChanged(rootFolder->getChildren().front(), false);
|
||||
ViewController::get()
|
||||
->getGameListView(rootFolder->getSystem())
|
||||
.get()
|
||||
->onFileChanged(rootFolder->getChildren().front(), false);
|
||||
}
|
||||
|
||||
sysData->isPopulated = true;
|
||||
|
@ -1176,15 +1206,16 @@ void CollectionSystemsManager::populateCustomCollection(CollectionSystemData* sy
|
|||
FileFilterIndex* index = newSys->getIndex();
|
||||
|
||||
// Get configuration for this custom collection.
|
||||
#if defined (_WIN64)
|
||||
|
||||
#if defined(_WIN64)
|
||||
std::ifstream input(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
std::ifstream input(path);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Get all files map.
|
||||
std::unordered_map<std::string,FileData*>
|
||||
allFilesMap = getAllGamesCollection()->getRootFolder()->getChildrenByFilename();
|
||||
std::unordered_map<std::string, FileData*> allFilesMap =
|
||||
getAllGamesCollection()->getRootFolder()->getChildrenByFilename();
|
||||
|
||||
// Get the ROM directory, either as configured in es_settings.xml, or if no value
|
||||
// is set there, then use the default hardcoded path.
|
||||
|
@ -1200,15 +1231,16 @@ void CollectionSystemsManager::populateCustomCollection(CollectionSystemData* sy
|
|||
gameKey = Utils::String::replace(gameKey, "%ROMPATH%", rompath);
|
||||
gameKey = Utils::String::replace(gameKey, "//", "/");
|
||||
|
||||
std::unordered_map<std::string,FileData*>::const_iterator it = allFilesMap.find(gameKey);
|
||||
std::unordered_map<std::string, FileData*>::const_iterator it = allFilesMap.find(gameKey);
|
||||
if (it != allFilesMap.cend()) {
|
||||
CollectionFileData* newGame = new CollectionFileData(it->second, newSys);
|
||||
rootFolder->addChild(newGame);
|
||||
index->addToIndex(newGame);
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << "File \"" << gameKey <<
|
||||
"\" does not exist, is hidden, or is not counted as a game, ignoring entry";
|
||||
LOG(LogWarning)
|
||||
<< "File \"" << gameKey
|
||||
<< "\" does not exist, is hidden, or is not counted as a game, ignoring entry";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1252,7 @@ void CollectionSystemsManager::removeCollectionsFromDisplayedSystems()
|
|||
{
|
||||
// Remove all collection Systems.
|
||||
for (auto sysIt = SystemData::sSystemVector.cbegin();
|
||||
sysIt != SystemData::sSystemVector.cend(); ) {
|
||||
sysIt != SystemData::sSystemVector.cend();) {
|
||||
if ((*sysIt)->isCollection())
|
||||
sysIt = SystemData::sSystemVector.erase(sysIt);
|
||||
else
|
||||
|
@ -1244,8 +1276,9 @@ void CollectionSystemsManager::addEnabledCollectionsToDisplayedSystems(
|
|||
std::map<std::string, CollectionSystemData, stringComparator>* colSystemData)
|
||||
{
|
||||
// Add auto enabled collections.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator
|
||||
it = colSystemData->begin(); it != colSystemData->end(); it++) {
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::iterator it =
|
||||
colSystemData->begin();
|
||||
it != colSystemData->end(); it++) {
|
||||
if (it->second.isEnabled) {
|
||||
// Check if populated, otherwise populate.
|
||||
if (!it->second.isPopulated) {
|
||||
|
@ -1263,12 +1296,12 @@ void CollectionSystemsManager::addEnabledCollectionsToDisplayedSystems(
|
|||
// If this is a non-bundled custom collection, then sort it.
|
||||
if (it->second.decl.isCustom == true) {
|
||||
FileData* rootFolder = it->second.system->getRootFolder();
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(
|
||||
rootFolder->getSortTypeString()),
|
||||
rootFolder->sort(
|
||||
rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
Settings::getInstance()->getBool("FavFirstCustom"));
|
||||
// Jump to the first row of the game list, assuming it's not empty.
|
||||
IGameListView* gameList = ViewController::get()->
|
||||
getGameListView((it->second.system)).get();
|
||||
IGameListView* gameList =
|
||||
ViewController::get()->getGameListView((it->second.system)).get();
|
||||
if (!gameList->getCursor()->isPlaceHolder()) {
|
||||
gameList->setCursor(gameList->getFirstEntry());
|
||||
}
|
||||
|
@ -1294,11 +1327,11 @@ std::vector<std::string> CollectionSystemsManager::getSystemsFromConfig()
|
|||
return systems;
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!res)
|
||||
return systems;
|
||||
|
@ -1309,8 +1342,8 @@ std::vector<std::string> CollectionSystemsManager::getSystemsFromConfig()
|
|||
if (!systemList)
|
||||
return systems;
|
||||
|
||||
for (pugi::xml_node system = systemList.child("system");
|
||||
system; system = system.next_sibling("system")) {
|
||||
for (pugi::xml_node system = systemList.child("system"); system;
|
||||
system = system.next_sibling("system")) {
|
||||
// Theme folder.
|
||||
std::string themeFolder = system.child("theme").text().get();
|
||||
systems.push_back(themeFolder);
|
||||
|
@ -1328,8 +1361,8 @@ std::vector<std::string> CollectionSystemsManager::getSystemsFromTheme()
|
|||
if (themeSets.empty())
|
||||
return systems; // No theme sets available.
|
||||
|
||||
std::map<std::string, ThemeSet>::const_iterator
|
||||
set = themeSets.find(Settings::getInstance()->getString("ThemeSet"));
|
||||
std::map<std::string, ThemeSet>::const_iterator set =
|
||||
themeSets.find(Settings::getInstance()->getString("ThemeSet"));
|
||||
if (set == themeSets.cend()) {
|
||||
// Currently selected theme set is missing, so just pick the first available set.
|
||||
set = themeSets.cbegin();
|
||||
|
@ -1341,12 +1374,12 @@ std::vector<std::string> CollectionSystemsManager::getSystemsFromTheme()
|
|||
if (Utils::FileSystem::exists(themePath)) {
|
||||
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(themePath);
|
||||
|
||||
for (Utils::FileSystem::stringList::const_iterator
|
||||
it = dirContent.cbegin(); it != dirContent.cend(); it++) {
|
||||
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
|
||||
it != dirContent.cend(); it++) {
|
||||
if (Utils::FileSystem::isDirectory(*it)) {
|
||||
// ... here you have a directory.
|
||||
std::string folder = *it;
|
||||
folder = folder.substr(themePath.size()+1);
|
||||
folder = folder.substr(themePath.size() + 1);
|
||||
|
||||
if (Utils::FileSystem::exists(set->second.getThemePath(folder)))
|
||||
systems.push_back(folder);
|
||||
|
@ -1362,19 +1395,17 @@ std::vector<std::string> CollectionSystemsManager::getCollectionsFromConfigFolde
|
|||
std::vector<std::string> systems;
|
||||
std::string configPath = getCollectionsFolder();
|
||||
|
||||
if (Utils::FileSystem::exists(configPath))
|
||||
{
|
||||
Utils::FileSystem::stringList dirContent =
|
||||
Utils::FileSystem::getDirContent(configPath);
|
||||
for (Utils::FileSystem::stringList::const_iterator
|
||||
it = dirContent.cbegin(); it != dirContent.cend(); it++) {
|
||||
if (Utils::FileSystem::exists(configPath)) {
|
||||
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(configPath);
|
||||
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
|
||||
it != dirContent.cend(); it++) {
|
||||
if (Utils::FileSystem::isRegularFile(*it)) {
|
||||
// It's a file.
|
||||
std::string filename = Utils::FileSystem::getFileName(*it);
|
||||
// Need to confirm filename matches config format.
|
||||
if (filename != "custom-.cfg" && Utils::String::startsWith(
|
||||
filename, "custom-") && Utils::String::endsWith(filename, ".cfg")) {
|
||||
filename = filename.substr(7, filename.size()-11);
|
||||
if (filename != "custom-.cfg" && Utils::String::startsWith(filename, "custom-") &&
|
||||
Utils::String::endsWith(filename, ".cfg")) {
|
||||
filename = filename.substr(7, filename.size() - 11);
|
||||
systems.push_back(filename);
|
||||
}
|
||||
else {
|
||||
|
@ -1390,8 +1421,8 @@ std::vector<std::string> CollectionSystemsManager::getCollectionsFromConfigFolde
|
|||
std::vector<std::string> CollectionSystemsManager::getCollectionThemeFolders(bool custom)
|
||||
{
|
||||
std::vector<std::string> systems;
|
||||
for (std::map<std::string, CollectionSystemDecl, stringComparator>::const_iterator
|
||||
it = mCollectionSystemDeclsIndex.cbegin();
|
||||
for (std::map<std::string, CollectionSystemDecl, stringComparator>::const_iterator it =
|
||||
mCollectionSystemDeclsIndex.cbegin();
|
||||
it != mCollectionSystemDeclsIndex.cend(); it++) {
|
||||
CollectionSystemDecl sysDecl = it->second;
|
||||
if (sysDecl.isCustom == custom)
|
||||
|
@ -1403,8 +1434,8 @@ std::vector<std::string> CollectionSystemsManager::getCollectionThemeFolders(boo
|
|||
std::vector<std::string> CollectionSystemsManager::getUserCollectionThemeFolders()
|
||||
{
|
||||
std::vector<std::string> systems;
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = mCustomCollectionSystemsData.cbegin();
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
mCustomCollectionSystemsData.cbegin();
|
||||
it != mCustomCollectionSystemsData.cend(); it++)
|
||||
systems.push_back(it->second.decl.themeFolder);
|
||||
return systems;
|
||||
|
|
|
@ -34,7 +34,7 @@ class Window;
|
|||
struct SystemEnvironmentData;
|
||||
|
||||
enum CollectionSystemType {
|
||||
AUTO_ALL_GAMES,
|
||||
AUTO_ALL_GAMES, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
AUTO_LAST_PLAYED,
|
||||
AUTO_FAVORITES,
|
||||
CUSTOM_COLLECTION
|
||||
|
@ -115,13 +115,17 @@ public:
|
|||
// Repopulate the collection, which is basically a forced update of its complete content.
|
||||
void repopulateCollection(SystemData* sysData);
|
||||
|
||||
inline std::map<std::string, CollectionSystemData, stringComparator>
|
||||
getAutoCollectionSystems() { return mAutoCollectionSystemsData; };
|
||||
inline std::map<std::string, CollectionSystemData, stringComparator>
|
||||
getCustomCollectionSystems() { return mCustomCollectionSystemsData; };
|
||||
inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; };
|
||||
inline bool isEditing() { return mIsEditingCustom; };
|
||||
inline std::string getEditingCollection() { return mEditingCollection; };
|
||||
std::map<std::string, CollectionSystemData, stringComparator> getAutoCollectionSystems()
|
||||
{
|
||||
return mAutoCollectionSystemsData;
|
||||
}
|
||||
std::map<std::string, CollectionSystemData, stringComparator> getCustomCollectionSystems()
|
||||
{
|
||||
return mCustomCollectionSystemsData;
|
||||
}
|
||||
SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; }
|
||||
bool isEditing() { return mIsEditingCustom; }
|
||||
std::string getEditingCollection() { return mEditingCollection; }
|
||||
|
||||
private:
|
||||
static CollectionSystemsManager* sInstance;
|
||||
|
@ -143,7 +147,9 @@ private:
|
|||
SystemData* getAllGamesCollection();
|
||||
// Create a new empty collection system based on the name and declaration.
|
||||
SystemData* createNewCollectionEntry(std::string name,
|
||||
CollectionSystemDecl sysDecl, bool index = true, bool custom = false);
|
||||
CollectionSystemDecl sysDecl,
|
||||
bool index = true,
|
||||
bool custom = false);
|
||||
// Populate an automatic collection system.
|
||||
void populateAutoCollection(CollectionSystemData* sysData);
|
||||
// Populate a custom collection system.
|
||||
|
@ -151,8 +157,8 @@ private:
|
|||
|
||||
// Functions to handle System View removal and insertion of collections:
|
||||
void removeCollectionsFromDisplayedSystems();
|
||||
void addEnabledCollectionsToDisplayedSystems(std::map<std::string,
|
||||
CollectionSystemData, stringComparator>* colSystemData);
|
||||
void addEnabledCollectionsToDisplayedSystems(
|
||||
std::map<std::string, CollectionSystemData, stringComparator>* colSystemData);
|
||||
|
||||
// Auxiliary functions:
|
||||
std::vector<std::string> getSystemsFromConfig();
|
||||
|
|
|
@ -10,14 +10,16 @@
|
|||
|
||||
// These numbers and strings need to be manually updated for a new version.
|
||||
// Do this version number update as the very last commit for the new release version.
|
||||
// clang-format off
|
||||
#define PROGRAM_VERSION_MAJOR 1
|
||||
#define PROGRAM_VERSION_MINOR 0
|
||||
#define PROGRAM_VERSION_MINOR 1
|
||||
#define PROGRAM_VERSION_MAINTENANCE 0
|
||||
// clang-format on
|
||||
#define PROGRAM_VERSION_STRING "1.1.0-rc-dev"
|
||||
|
||||
#define PROGRAM_BUILT_STRING __DATE__ " - " __TIME__
|
||||
|
||||
#define RESOURCE_VERSION_STRING "1,1,0\0"
|
||||
#define RESOURCE_VERSION PROGRAM_VERSION_MAJOR,PROGRAM_VERSION_MINOR,PROGRAM_VERSION_MAINTENANCE
|
||||
#define RESOURCE_VERSION PROGRAM_VERSION_MAJOR, PROGRAM_VERSION_MINOR, PROGRAM_VERSION_MAINTENANCE
|
||||
|
||||
#endif // ES_APP_EMULATION_STATION_H
|
||||
|
|
|
@ -10,12 +10,6 @@
|
|||
|
||||
#include "FileData.h"
|
||||
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
|
@ -26,24 +20,29 @@
|
|||
#include "Scripting.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
FileData::FileData(
|
||||
FileType type,
|
||||
FileData::FileData(FileType type,
|
||||
const std::string& path,
|
||||
SystemEnvironmentData* envData,
|
||||
SystemData* system)
|
||||
: mType(type),
|
||||
mPath(path),
|
||||
mSystem(system),
|
||||
mEnvData(envData),
|
||||
mSourceFileData(nullptr),
|
||||
mParent(nullptr),
|
||||
mOnlyFolders(false),
|
||||
mDeletionFlag(false),
|
||||
: mType(type)
|
||||
, mPath(path)
|
||||
, mSystem(system)
|
||||
, mEnvData(envData)
|
||||
, mSourceFileData(nullptr)
|
||||
, mParent(nullptr)
|
||||
, mOnlyFolders(false)
|
||||
, mDeletionFlag(false)
|
||||
// Metadata is set in the constructor.
|
||||
metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA)
|
||||
, metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA)
|
||||
{
|
||||
// Metadata needs at least a name field (since that's what getName() will return).
|
||||
if (metadata.get("name").empty()) {
|
||||
|
@ -51,8 +50,7 @@ FileData::FileData(
|
|||
system->hasPlatformId(PlatformIds::SNK_NEO_GEO)) &&
|
||||
metadata.getType() != FOLDER_METADATA) {
|
||||
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
||||
metadata.set("name",
|
||||
MameNames::getInstance()->getCleanName(getCleanName()));
|
||||
metadata.set("name", MameNames::getInstance()->getCleanName(getCleanName()));
|
||||
}
|
||||
else {
|
||||
if (metadata.getType() == FOLDER_METADATA && Utils::FileSystem::isHidden(mPath)) {
|
||||
|
@ -89,6 +87,7 @@ std::string FileData::getCleanName() const
|
|||
|
||||
const std::string& FileData::getName()
|
||||
{
|
||||
// Return metadata name.
|
||||
return metadata.get("name");
|
||||
}
|
||||
|
||||
|
@ -144,14 +143,13 @@ const std::vector<FileData*> FileData::getChildrenRecursive() const
|
|||
{
|
||||
std::vector<FileData*> childrenRecursive;
|
||||
|
||||
for (auto it = mChildrenByFilename.cbegin();
|
||||
it != mChildrenByFilename.cend(); it++) {
|
||||
for (auto it = mChildrenByFilename.cbegin(); it != mChildrenByFilename.cend(); it++) {
|
||||
childrenRecursive.push_back((*it).second);
|
||||
// Recurse through any subdirectories.
|
||||
if ((*it).second->getType() == FOLDER) {
|
||||
std::vector<FileData*> childrenSubdirectory = (*it).second->getChildrenRecursive();
|
||||
childrenRecursive.insert(childrenRecursive.end(),
|
||||
childrenSubdirectory.begin(), childrenSubdirectory.end());
|
||||
childrenRecursive.insert(childrenRecursive.end(), childrenSubdirectory.begin(),
|
||||
childrenSubdirectory.end());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,13 +169,13 @@ const std::string FileData::getROMDirectory()
|
|||
// Expand home path if ~ is used.
|
||||
romDirPath = Utils::FileSystem::expandHomePath(romDirPath);
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
if (romDirPath.back() != '\\')
|
||||
romDirPath = romDirPath + "\\";
|
||||
#else
|
||||
#else
|
||||
if (romDirPath.back() != '/')
|
||||
romDirPath = romDirPath + "/";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// If %ESPATH% is used for the ROM path configuration, then expand it to the binary
|
||||
|
@ -202,8 +200,8 @@ const std::string FileData::getMediaDirectory()
|
|||
|
||||
// If %ESPATH% is used for the media directory configuration, then expand it to the
|
||||
// binary directory of ES-DE.
|
||||
mediaDirPath = Utils::String::replace(
|
||||
mediaDirPath, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||
mediaDirPath =
|
||||
Utils::String::replace(mediaDirPath, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||
|
||||
if (mediaDirPath.back() != '/')
|
||||
mediaDirPath = mediaDirPath + "/";
|
||||
|
@ -219,8 +217,8 @@ const std::string FileData::getMediafilePath(std::string subdirectory, std::stri
|
|||
|
||||
// Extract possible subfolders from the path.
|
||||
if (mEnvData->mStartPath != "")
|
||||
subFolders = Utils::String::replace(
|
||||
Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||
subFolders =
|
||||
Utils::String::replace(Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||
|
||||
const std::string tempPath = getMediaDirectory() + mSystemName + "/" + subdirectory +
|
||||
subFolders + "/" + getDisplayName();
|
||||
|
@ -253,31 +251,37 @@ const std::string FileData::getImagePath() const
|
|||
|
||||
const std::string FileData::get3DBoxPath() const
|
||||
{
|
||||
// Return path to the 3D box image.
|
||||
return getMediafilePath("3dboxes", "3dbox");
|
||||
}
|
||||
|
||||
const std::string FileData::getCoverPath() const
|
||||
{
|
||||
// Return path to the cover image.
|
||||
return getMediafilePath("covers", "cover");
|
||||
}
|
||||
|
||||
const std::string FileData::getMarqueePath() const
|
||||
{
|
||||
// Return path to the marquee image.
|
||||
return getMediafilePath("marquees", "marquee");
|
||||
}
|
||||
|
||||
const std::string FileData::getMiximagePath() const
|
||||
{
|
||||
// Return path to the miximage.
|
||||
return getMediafilePath("miximages", "miximage");
|
||||
}
|
||||
|
||||
const std::string FileData::getScreenshotPath() const
|
||||
{
|
||||
// Return path to the screenshot image.
|
||||
return getMediafilePath("screenshots", "screenshot");
|
||||
}
|
||||
|
||||
const std::string FileData::getThumbnailPath() const
|
||||
{
|
||||
// Return path to the thumbnail image.
|
||||
return getMediafilePath("thumbnails", "thumbnail");
|
||||
}
|
||||
|
||||
|
@ -288,8 +292,8 @@ const std::string FileData::getVideoPath() const
|
|||
|
||||
// Extract possible subfolders from the path.
|
||||
if (mEnvData->mStartPath != "")
|
||||
subFolders = Utils::String::replace(
|
||||
Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||
subFolders =
|
||||
Utils::String::replace(Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||
|
||||
const std::string tempPath =
|
||||
getMediaDirectory() + mSystemName + "/videos" + subFolders + "/" + getDisplayName();
|
||||
|
@ -322,7 +326,8 @@ const std::vector<FileData*>& FileData::getChildrenListToDisplay()
|
|||
}
|
||||
|
||||
std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask,
|
||||
bool displayedOnly, bool countAllGames) const
|
||||
bool displayedOnly,
|
||||
bool countAllGames) const
|
||||
{
|
||||
std::vector<FileData*> out;
|
||||
FileFilterIndex* idx = mSystem->getIndex();
|
||||
|
@ -354,7 +359,8 @@ std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask,
|
|||
}
|
||||
|
||||
std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
||||
bool excludeRecursively, bool respectExclusions) const
|
||||
bool excludeRecursively,
|
||||
bool respectExclusions) const
|
||||
{
|
||||
std::vector<FileData*> out;
|
||||
|
||||
|
@ -383,17 +389,14 @@ std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
|||
return out;
|
||||
}
|
||||
|
||||
std::string FileData::getKey() {
|
||||
return getFileName();
|
||||
}
|
||||
std::string FileData::getKey() { return getFileName(); }
|
||||
|
||||
const bool FileData::isArcadeAsset()
|
||||
{
|
||||
const std::string stem = Utils::FileSystem::getStem(mPath);
|
||||
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
||||
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
||||
(MameNames::getInstance()->isBios(stem) ||
|
||||
MameNames::getInstance()->isDevice(stem)));
|
||||
(MameNames::getInstance()->isBios(stem) || MameNames::getInstance()->isDevice(stem)));
|
||||
}
|
||||
|
||||
const bool FileData::isArcadeGame()
|
||||
|
@ -401,14 +404,10 @@ const bool FileData::isArcadeGame()
|
|||
const std::string stem = Utils::FileSystem::getStem(mPath);
|
||||
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
||||
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
||||
(!MameNames::getInstance()->isBios(stem) &&
|
||||
!MameNames::getInstance()->isDevice(stem)));
|
||||
(!MameNames::getInstance()->isBios(stem) && !MameNames::getInstance()->isDevice(stem)));
|
||||
}
|
||||
|
||||
FileData* FileData::getSourceFileData()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
FileData* FileData::getSourceFileData() { return this; }
|
||||
|
||||
void FileData::addChild(FileData* file)
|
||||
{
|
||||
|
@ -657,16 +656,16 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator,
|
|||
|
||||
// Sort favorite games and the other games separately.
|
||||
if (foldersOnTop && mOnlyFolders) {
|
||||
std::stable_sort(mChildrenFavoritesFolders.begin(),
|
||||
mChildrenFavoritesFolders.end(), comparator);
|
||||
std::stable_sort(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end(),
|
||||
comparator);
|
||||
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator);
|
||||
}
|
||||
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(), comparator);
|
||||
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
|
||||
|
||||
// Iterate through any child favorite folders.
|
||||
for (auto it = mChildrenFavoritesFolders.cbegin(); it !=
|
||||
mChildrenFavoritesFolders.cend(); it++) {
|
||||
for (auto it = mChildrenFavoritesFolders.cbegin(); // Line break.
|
||||
it != mChildrenFavoritesFolders.cend(); it++) {
|
||||
if ((*it)->getChildren().size() > 0)
|
||||
(*it)->sortFavoritesOnTop(comparator, gameCount);
|
||||
}
|
||||
|
@ -731,7 +730,8 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
|||
mGameCount = gameCount;
|
||||
}
|
||||
|
||||
FileData::SortType FileData::getSortTypeFromString(std::string desc) {
|
||||
FileData::SortType FileData::getSortTypeFromString(std::string desc)
|
||||
{
|
||||
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
||||
|
||||
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||
|
@ -752,10 +752,12 @@ void FileData::launchGame(Window* window)
|
|||
// Check if there is a launch command override for the game
|
||||
// and the corresponding option to use it has been set.
|
||||
if (Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
||||
!metadata.get("launchcommand").empty())
|
||||
!metadata.get("launchcommand").empty()) {
|
||||
command = metadata.get("launchcommand");
|
||||
else
|
||||
}
|
||||
else {
|
||||
command = mEnvData->mLaunchCommand;
|
||||
}
|
||||
|
||||
std::string commandRaw = command;
|
||||
|
||||
|
@ -794,14 +796,14 @@ void FileData::launchGame(Window* window)
|
|||
// Hack to show an error message if there was no emulator entry in es_find_rules.xml.
|
||||
if (binaryPath.substr(0, 18) == "NO EMULATOR RULE: ") {
|
||||
std::string emulatorEntry = binaryPath.substr(18, binaryPath.size() - 18);
|
||||
LOG(LogError) << "Couldn't launch game, either there is no emulator entry for \"" <<
|
||||
emulatorEntry << "\" in es_find_rules.xml or there are no systempath or staticpath "
|
||||
"rules defined";
|
||||
LOG(LogError)
|
||||
<< "Couldn't launch game, either there is no emulator entry for \"" << emulatorEntry
|
||||
<< "\" in es_find_rules.xml or there are no systempath or staticpath rules defined";
|
||||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: MISSING EMULATOR CONFIGURATION FOR '" +
|
||||
emulatorEntry + "'", 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
window, "ERROR: MISSING EMULATOR CONFIGURATION FOR '" + emulatorEntry + "'", 6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
|
@ -810,20 +812,23 @@ void FileData::launchGame(Window* window)
|
|||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: COULDN'T FIND EMULATOR, HAS IT " \
|
||||
"BEEN PROPERLY INSTALLED?", 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||
"ERROR: COULDN'T FIND EMULATOR, HAS IT "
|
||||
"BEEN PROPERLY INSTALLED?",
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
#if defined(_WIN64)
|
||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \"" <<
|
||||
Utils::String::replace(Utils::String::replace(
|
||||
binaryPath, "%ESPATH%", esPath), "/", "\\") << "\"";
|
||||
#else
|
||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \"" <<
|
||||
Utils::String::replace(binaryPath, "%ESPATH%", esPath) << "\"";
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \""
|
||||
<< Utils::String::replace(
|
||||
Utils::String::replace(binaryPath, "%ESPATH%", esPath), "/", "\\")
|
||||
<< "\"";
|
||||
#else
|
||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \""
|
||||
<< Utils::String::replace(binaryPath, "%ESPATH%", esPath) << "\"";
|
||||
#endif
|
||||
}
|
||||
|
||||
// If %EMUPATH% is used in es_systems.xml for this system, then check that the core
|
||||
|
@ -834,8 +839,8 @@ void FileData::launchGame(Window* window)
|
|||
unsigned int quotationMarkPos = 0;
|
||||
if (command.find("\"%EMUPATH%", emuPathPos - 1) != std::string::npos) {
|
||||
hasQuotationMark = true;
|
||||
quotationMarkPos = static_cast<unsigned int>(
|
||||
command.find("\"", emuPathPos + 9) - emuPathPos);
|
||||
quotationMarkPos =
|
||||
static_cast<unsigned int>(command.find("\"", emuPathPos + 9) - emuPathPos);
|
||||
}
|
||||
size_t spacePos = command.find(" ", emuPathPos + quotationMarkPos);
|
||||
std::string coreRaw;
|
||||
|
@ -850,15 +855,16 @@ void FileData::launchGame(Window* window)
|
|||
}
|
||||
if (!Utils::FileSystem::isRegularFile(coreFile) &&
|
||||
!Utils::FileSystem::isSymlink(coreFile)) {
|
||||
LOG(LogError) << "Couldn't launch game, emulator core file \"" <<
|
||||
Utils::FileSystem::getFileName(coreFile) << "\" not found";
|
||||
LOG(LogError) << "Couldn't launch game, emulator core file \""
|
||||
<< Utils::FileSystem::getFileName(coreFile) << "\" not found";
|
||||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
window,
|
||||
"ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
||||
Utils::String::toUpper(Utils::FileSystem::getFileName(coreFile)) +
|
||||
"'", 6000);
|
||||
Utils::String::toUpper(Utils::FileSystem::getFileName(coreFile)) + "'",
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
|
@ -877,8 +883,10 @@ void FileData::launchGame(Window* window)
|
|||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: INVALID ENTRY IN SYSTEMS " \
|
||||
"CONFIGURATION FILE", 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||
"ERROR: INVALID ENTRY IN SYSTEMS "
|
||||
"CONFIGURATION FILE",
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
|
@ -886,13 +894,13 @@ void FileData::launchGame(Window* window)
|
|||
|
||||
// Error handling in case of no core find rule.
|
||||
if (coreEntry != "" && emulatorCorePaths.empty()) {
|
||||
LOG(LogError) << "Couldn't launch game, either there is no core entry for \"" <<
|
||||
coreEntry << "\" in es_find_rules.xml or there are no corepath rules defined";
|
||||
LOG(LogError) << "Couldn't launch game, either there is no core entry for \"" << coreEntry
|
||||
<< "\" in es_find_rules.xml or there are no corepath rules defined";
|
||||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: MISSING CORE CONFIGURATION FOR '" +
|
||||
coreEntry + "'", 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
window, "ERROR: MISSING CORE CONFIGURATION FOR '" + coreEntry + "'", 6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
|
@ -915,30 +923,31 @@ void FileData::launchGame(Window* window)
|
|||
if (separatorPos != std::string::npos) {
|
||||
coreName = command.substr(coreFilePos + 2, separatorPos - (coreFilePos + 2));
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::string coreFile = Utils::FileSystem::expandHomePath(path + "\\" + coreName);
|
||||
#else
|
||||
#else
|
||||
std::string coreFile = Utils::FileSystem::expandHomePath(path + "/" + coreName);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Expand %EMUPATH% if it has been used in the %CORE_ variable.
|
||||
size_t stringPos = coreFile.find("%EMUPATH%");
|
||||
if (stringPos != std::string::npos) {
|
||||
#if defined (_WIN64)
|
||||
coreFile = Utils::String::replace(coreFile.replace(stringPos, 9,
|
||||
Utils::FileSystem::getParent(binaryPath)), "/", "\\");
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
coreFile = Utils::String::replace(
|
||||
coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath)), "/",
|
||||
"\\");
|
||||
#else
|
||||
coreFile = coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Expand %ESPATH% if it has been used in the %CORE_ variable.
|
||||
stringPos = coreFile.find("%ESPATH%");
|
||||
if (stringPos != std::string::npos) {
|
||||
coreFile = coreFile.replace(stringPos, 8, esPath);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
coreFile = Utils::String::replace(coreFile, "/", "\\");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Utils::FileSystem::isRegularFile(coreFile) ||
|
||||
|
@ -948,11 +957,11 @@ void FileData::launchGame(Window* window)
|
|||
if (coreFile.find(" ") != std::string::npos)
|
||||
coreFile = Utils::FileSystem::getEscapedPath(coreFile);
|
||||
command.replace(coreEntryPos, separatorPos - coreEntryPos, coreFile);
|
||||
#if !defined(_WIN64)
|
||||
#if !defined(_WIN64)
|
||||
// Remove any quotation marks as it would make the launch function fail.
|
||||
if (command.find("\"") != std::string::npos)
|
||||
command = Utils::String::replace(command, "\"", "");
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -961,23 +970,28 @@ void FileData::launchGame(Window* window)
|
|||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: INVALID ENTRY IN SYSTEMS " \
|
||||
"CONFIGURATION FILE", 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||
"ERROR: INVALID ENTRY IN SYSTEMS "
|
||||
"CONFIGURATION FILE",
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!foundCoreFile && coreName.size() > 0) {
|
||||
LOG(LogError) << "Couldn't launch game, emulator core file \"" <<
|
||||
coreName.substr(0, coreName.size()) << "\" not found";
|
||||
LOG(LogError) << "Couldn't launch game, emulator core file \""
|
||||
<< coreName.substr(0, coreName.size()) << "\" not found";
|
||||
LOG(LogError) << "Raw emulator launch command:";
|
||||
LOG(LogError) << commandRaw;
|
||||
LOG(LogError) <<
|
||||
"Tried to find the core file using these paths as defined by es_find_rules.xml:";
|
||||
LOG(LogError)
|
||||
<< "Tried to find the core file using these paths as defined by es_find_rules.xml:";
|
||||
LOG(LogError) << Utils::String::vectorToDelimitedString(emulatorCorePaths, ", ");
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
||||
Utils::String::toUpper(coreName.substr(0, coreName.size()) + "'"), 6000);
|
||||
GuiInfoPopup* s =
|
||||
new GuiInfoPopup(window,
|
||||
"ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
||||
Utils::String::toUpper(coreName.substr(0, coreName.size()) + "'"),
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
return;
|
||||
}
|
||||
|
@ -990,12 +1004,13 @@ void FileData::launchGame(Window* window)
|
|||
// swapBuffers() is called here to turn the screen black to eliminate some potential
|
||||
// flickering and to avoid showing the game launch message briefly when returning
|
||||
// from the game.
|
||||
#if defined(_WIN64)
|
||||
|
||||
#if defined(_WIN64)
|
||||
if (!(Settings::getInstance()->getBool("LaunchWorkaround") ||
|
||||
ViewController::get()->runInBackground(mSystem)))
|
||||
#else
|
||||
#else
|
||||
if (!ViewController::get()->runInBackground(mSystem))
|
||||
#endif
|
||||
#endif
|
||||
Renderer::swapBuffers();
|
||||
|
||||
Scripting::fireEvent("game-start", romPath, getSourceFileData()->metadata.get("name"));
|
||||
|
@ -1004,28 +1019,31 @@ void FileData::launchGame(Window* window)
|
|||
LOG(LogDebug) << "Raw emulator launch command:";
|
||||
LOG(LogDebug) << commandRaw;
|
||||
LOG(LogInfo) << "Expanded emulator launch command:";
|
||||
|
||||
LOG(LogInfo) << command;
|
||||
|
||||
// Possibly keep ES-DE running in the background while the game is launched.
|
||||
#if defined(_WIN64)
|
||||
|
||||
#if defined(_WIN64)
|
||||
returnValue = launchGameWindows(Utils::String::stringToWideString(command),
|
||||
ViewController::get()->runInBackground(mSystem));
|
||||
#else
|
||||
#else
|
||||
returnValue = launchGameUnix(command, ViewController::get()->runInBackground(mSystem));
|
||||
#endif
|
||||
#endif
|
||||
// Notify the user in case of a failed game launch using a popup window.
|
||||
if (returnValue != 0) {
|
||||
LOG(LogWarning) << "...launch terminated with nonzero return value " << returnValue;
|
||||
|
||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR LAUNCHING GAME '" +
|
||||
Utils::String::toUpper(metadata.get("name")) + "' (ERROR CODE " +
|
||||
Utils::String::toUpper(std::to_string(returnValue) + ")"), 6000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
window,
|
||||
"ERROR LAUNCHING GAME '" + Utils::String::toUpper(metadata.get("name")) +
|
||||
"' (ERROR CODE " + Utils::String::toUpper(std::to_string(returnValue) + ")"),
|
||||
6000);
|
||||
window->setInfoPopup(s);
|
||||
}
|
||||
else {
|
||||
// Stop showing the game launch notification.
|
||||
window->stopInfoPopup();
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// For some game systems or if the "RunInBackground" setting has been enabled, keep
|
||||
// ES-DE running while the game is launched. This pauses any video and keeps the
|
||||
// screensaver from getting activated.
|
||||
|
@ -1035,7 +1053,7 @@ void FileData::launchGame(Window* window)
|
|||
// Normalize deltaTime so that the screensaver does not start immediately
|
||||
// when returning from the game.
|
||||
window->normalizeNextUpdate();
|
||||
#else
|
||||
#else
|
||||
// For some game systems we need to keep ES-DE running while the game is launched.
|
||||
// This pauses any video and keeps the screensaver from getting activated.
|
||||
if (ViewController::get()->runInBackground(mSystem))
|
||||
|
@ -1043,7 +1061,7 @@ void FileData::launchGame(Window* window)
|
|||
// Normalize deltaTime so that the screensaver does not start immediately
|
||||
// when returning from the game.
|
||||
window->normalizeNextUpdate();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
Scripting::fireEvent("game-end", romPath, getSourceFileData()->metadata.get("name"));
|
||||
|
@ -1062,8 +1080,8 @@ void FileData::launchGame(Window* window)
|
|||
|
||||
// If the parent is a folder and it's not the root of the system, then update its lastplayed
|
||||
// timestamp to the same time as the game that was just launched.
|
||||
if (gameToUpdate->getParent()->getType() == FOLDER && gameToUpdate->getParent()->getName() !=
|
||||
gameToUpdate->getSystem()->getFullName()) {
|
||||
if (gameToUpdate->getParent()->getType() == FOLDER &&
|
||||
gameToUpdate->getParent()->getName() != gameToUpdate->getSystem()->getFullName()) {
|
||||
gameToUpdate->getParent()->metadata.set("lastplayed",
|
||||
gameToUpdate->metadata.get("lastplayed"));
|
||||
}
|
||||
|
@ -1086,9 +1104,9 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
|
||||
// Method 1, emulator binary is defined using find rules:
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::vector<std::string> emulatorWinRegistryPaths;
|
||||
#endif
|
||||
#endif
|
||||
std::vector<std::string> emulatorSystemPaths;
|
||||
std::vector<std::string> emulatorStaticPaths;
|
||||
std::string emulatorEntry;
|
||||
|
@ -1101,10 +1119,10 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
}
|
||||
|
||||
if (emulatorEntry != "") {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
emulatorWinRegistryPaths =
|
||||
SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryPaths;
|
||||
#endif
|
||||
#endif
|
||||
emulatorSystemPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].systemPaths;
|
||||
emulatorStaticPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].staticPaths;
|
||||
}
|
||||
|
@ -1113,7 +1131,7 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
if (emulatorEntry != "" && emulatorSystemPaths.empty() && emulatorStaticPaths.empty())
|
||||
return "NO EMULATOR RULE: " + emulatorEntry;
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
for (std::string path : emulatorWinRegistryPaths) {
|
||||
// Search for the emulator using the App Paths keys in the Windows Registry.
|
||||
std::string registryKeyPath =
|
||||
|
@ -1126,33 +1144,19 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
DWORD pathSize = 1024;
|
||||
|
||||
// First look in HKEY_CURRENT_USER.
|
||||
keyStatus = RegOpenKeyEx(
|
||||
HKEY_CURRENT_USER,
|
||||
registryKeyPath.c_str(),
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
keyStatus = RegOpenKeyEx(HKEY_CURRENT_USER, registryKeyPath.c_str(), 0, KEY_QUERY_VALUE,
|
||||
®istryKey);
|
||||
|
||||
// If not found, then try in HKEY_LOCAL_MACHINE.
|
||||
if (keyStatus != ERROR_SUCCESS) {
|
||||
keyStatus = RegOpenKeyEx(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
registryKeyPath.c_str(),
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
®istryKey);
|
||||
keyStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKeyPath.c_str(), 0,
|
||||
KEY_QUERY_VALUE, ®istryKey);
|
||||
}
|
||||
|
||||
// If the key exists, then try to retrieve the value.
|
||||
if (keyStatus == ERROR_SUCCESS) {
|
||||
pathStatus = RegGetValue(
|
||||
registryKey,
|
||||
nullptr,
|
||||
nullptr,
|
||||
RRF_RT_REG_SZ,
|
||||
nullptr,
|
||||
®istryPath,
|
||||
&pathSize);
|
||||
pathStatus = RegGetValue(registryKey, nullptr, nullptr, RRF_RT_REG_SZ, nullptr,
|
||||
®istryPath, &pathSize);
|
||||
}
|
||||
else {
|
||||
RegCloseKey(registryKey);
|
||||
|
@ -1171,25 +1175,24 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
}
|
||||
RegCloseKey(registryKey);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
for (std::string path : emulatorSystemPaths) {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::wstring pathWide = Utils::String::stringToWideString(path);
|
||||
// Search for the emulator using the PATH environmental variable.
|
||||
DWORD size = SearchPathW(nullptr, pathWide.c_str(), L".exe", 0, nullptr, nullptr);
|
||||
|
||||
if (size) {
|
||||
std::vector<wchar_t> pathBuffer(static_cast<size_t>(size) + 1 );
|
||||
std::vector<wchar_t> pathBuffer(static_cast<size_t>(size) + 1);
|
||||
wchar_t* fileName = nullptr;
|
||||
|
||||
SearchPathW(nullptr, pathWide.c_str(), L".exe", size + 1 ,
|
||||
pathBuffer.data(), &fileName);
|
||||
SearchPathW(nullptr, pathWide.c_str(), L".exe", size + 1, pathBuffer.data(), &fileName);
|
||||
std::wstring pathString = pathBuffer.data();
|
||||
|
||||
if (pathString.length()) {
|
||||
exePath = Utils::String::wideStringToString(pathString.substr(0,
|
||||
pathString.size() - std::wstring(fileName).size()));
|
||||
exePath = Utils::String::wideStringToString(
|
||||
pathString.substr(0, pathString.size() - std::wstring(fileName).size()));
|
||||
exePath.pop_back();
|
||||
}
|
||||
}
|
||||
|
@ -1198,14 +1201,14 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
command.replace(0, endPos + 1, exePath);
|
||||
return exePath;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
exePath = Utils::FileSystem::getPathToBinary(path);
|
||||
if (exePath != "") {
|
||||
exePath += "/" + path;
|
||||
command.replace(0, endPos + 1, exePath);
|
||||
return exePath;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
for (std::string path : emulatorStaticPaths) {
|
||||
|
@ -1214,11 +1217,10 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
path = Utils::String::replace(path, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||
// Likewise for the %ROMPATH% variable which expands to the configured ROM directory.
|
||||
path = Utils::String::replace(path, "%ROMPATH%", getROMDirectory());
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
path = Utils::String::replace(path, "/", "\\");
|
||||
#endif
|
||||
if (Utils::FileSystem::isRegularFile(path) ||
|
||||
Utils::FileSystem::isSymlink(path)) {
|
||||
#endif
|
||||
if (Utils::FileSystem::isRegularFile(path) || Utils::FileSystem::isSymlink(path)) {
|
||||
command.replace(0, endPos + 1, path);
|
||||
return path;
|
||||
}
|
||||
|
@ -1228,9 +1230,9 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
|
||||
// If %ESPATH% is used, then expand it to the binary directory of ES-DE.
|
||||
command = Utils::String::replace(command, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
command = Utils::String::replace(command, "/", "\\");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If the first character is a quotation mark, then we need to extract up to the
|
||||
// next quotation mark, otherwise we'll only extract up to the first space character.
|
||||
|
@ -1242,21 +1244,21 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
emuExecutable = command.substr(0, command.find(' '));
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::wstring emuExecutableWide = Utils::String::stringToWideString(emuExecutable);
|
||||
// Search for the emulator using the PATH environmental variable.
|
||||
DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr);
|
||||
|
||||
if (size) {
|
||||
std::vector<wchar_t> pathBuffer(static_cast<size_t>(size) + 1 );
|
||||
std::vector<wchar_t> pathBuffer(static_cast<size_t>(size) + 1);
|
||||
wchar_t* fileName = nullptr;
|
||||
|
||||
SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", size + 1 ,
|
||||
pathBuffer.data(), &fileName);
|
||||
SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", size + 1, pathBuffer.data(),
|
||||
&fileName);
|
||||
|
||||
exePath = Utils::String::wideStringToString(pathBuffer.data());
|
||||
}
|
||||
#else
|
||||
#else
|
||||
if (Utils::FileSystem::isRegularFile(emuExecutable) ||
|
||||
Utils::FileSystem::isSymlink(emuExecutable)) {
|
||||
exePath = emuExecutable;
|
||||
|
@ -1266,14 +1268,16 @@ std::string FileData::findEmulatorPath(std::string& command)
|
|||
if (exePath != "")
|
||||
exePath += "/" + emuExecutable;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return exePath;
|
||||
}
|
||||
|
||||
CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
||||
: FileData(file->getSourceFileData()->getType(), file->getSourceFileData()->getPath(),
|
||||
file->getSourceFileData()->getSystemEnvData(), system)
|
||||
: FileData(file->getSourceFileData()->getType(),
|
||||
file->getSourceFileData()->getPath(),
|
||||
file->getSourceFileData()->getSystemEnvData(),
|
||||
system)
|
||||
{
|
||||
// We use this constructor to create a clone of the filedata, and change its system.
|
||||
mSourceFileData = file->getSourceFileData();
|
||||
|
@ -1291,15 +1295,6 @@ CollectionFileData::~CollectionFileData()
|
|||
mParent = nullptr;
|
||||
}
|
||||
|
||||
std::string CollectionFileData::getKey() {
|
||||
return getFullPath();
|
||||
}
|
||||
|
||||
FileData* CollectionFileData::getSourceFileData()
|
||||
{
|
||||
return mSourceFileData;
|
||||
}
|
||||
|
||||
void CollectionFileData::refreshMetadata()
|
||||
{
|
||||
metadata = mSourceFileData->metadata;
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#ifndef ES_APP_FILE_DATA_H
|
||||
#define ES_APP_FILE_DATA_H
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "MetaData.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
|
@ -30,8 +30,10 @@ enum FileType {
|
|||
class FileData
|
||||
{
|
||||
public:
|
||||
FileData(FileType type, const std::string& path,
|
||||
SystemEnvironmentData* envData, SystemData* system);
|
||||
FileData(FileType type,
|
||||
const std::string& path,
|
||||
SystemEnvironmentData* envData,
|
||||
SystemData* system);
|
||||
|
||||
virtual ~FileData();
|
||||
|
||||
|
@ -41,17 +43,19 @@ public:
|
|||
const bool getKidgame();
|
||||
const bool getHidden();
|
||||
const bool getCountAsGame();
|
||||
const std::pair<unsigned int, unsigned int> getGameCount() { return mGameCount; };
|
||||
const std::pair<unsigned int, unsigned int> getGameCount() { return mGameCount; }
|
||||
const bool getExcludeFromScraper();
|
||||
const std::vector<FileData*> getChildrenRecursive() const;
|
||||
inline FileType getType() const { return mType; }
|
||||
inline const std::string& getPath() const { return mPath; }
|
||||
inline FileData* getParent() const { return mParent; }
|
||||
inline const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const
|
||||
{ return mChildrenByFilename; }
|
||||
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
|
||||
inline SystemData* getSystem() const { return mSystem; }
|
||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||
FileType getType() const { return mType; }
|
||||
const std::string& getPath() const { return mPath; }
|
||||
FileData* getParent() const { return mParent; }
|
||||
const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const
|
||||
{
|
||||
return mChildrenByFilename;
|
||||
}
|
||||
const std::vector<FileData*>& getChildren() const { return mChildren; }
|
||||
SystemData* getSystem() const { return mSystem; }
|
||||
SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||
const bool getOnlyFoldersFlag() { return mOnlyFolders; }
|
||||
const bool getHasFoldersFlag() { return mHasFolders; }
|
||||
static const std::string getROMDirectory();
|
||||
|
@ -66,29 +70,31 @@ public:
|
|||
const std::string getThumbnailPath() const;
|
||||
const std::string getVideoPath() const;
|
||||
|
||||
bool getDeletionFlag() { return mDeletionFlag; };
|
||||
void setDeletionFlag(bool setting) { mDeletionFlag = setting; };
|
||||
bool getDeletionFlag() { return mDeletionFlag; }
|
||||
void setDeletionFlag(bool setting) { mDeletionFlag = setting; }
|
||||
|
||||
const std::vector<FileData*>& getChildrenListToDisplay();
|
||||
std::vector<FileData*> getFilesRecursive(unsigned int typeMask,
|
||||
bool displayedOnly = false, bool countAllGames = true) const;
|
||||
std::vector<FileData*> getScrapeFilesRecursive(bool includeFolders, bool excludeRecursively,
|
||||
bool displayedOnly = false,
|
||||
bool countAllGames = true) const;
|
||||
std::vector<FileData*> getScrapeFilesRecursive(bool includeFolders,
|
||||
bool excludeRecursively,
|
||||
bool respectExclusions) const;
|
||||
|
||||
void addChild(FileData* file); // Error if mType != FOLDER
|
||||
void removeChild(FileData* file); //Error if mType != FOLDER
|
||||
void removeChild(FileData* file); // Error if mType != FOLDER
|
||||
|
||||
inline bool isPlaceHolder() { return mType == PLACEHOLDER; };
|
||||
bool isPlaceHolder() { return mType == PLACEHOLDER; }
|
||||
|
||||
virtual inline void refreshMetadata() { return; };
|
||||
virtual void refreshMetadata() { return; }
|
||||
|
||||
virtual std::string getKey();
|
||||
const bool isArcadeAsset();
|
||||
const bool isArcadeGame();
|
||||
inline std::string getFullPath() { return getPath(); };
|
||||
inline std::string getFileName() { return Utils::FileSystem::getFileName(getPath()); };
|
||||
std::string getFullPath() { return getPath(); }
|
||||
std::string getFileName() { return Utils::FileSystem::getFileName(getPath()); }
|
||||
virtual FileData* getSourceFileData();
|
||||
inline std::string getSystemName() const { return mSystemName; };
|
||||
std::string getSystemName() const { return mSystemName; }
|
||||
|
||||
// Returns our best guess at the "real" name for this file.
|
||||
std::string getDisplayName() const;
|
||||
|
@ -104,7 +110,10 @@ public:
|
|||
ComparisonFunction* comparisonFunction;
|
||||
std::string description;
|
||||
SortType(ComparisonFunction* sortFunction, const std::string& sortDescription)
|
||||
: comparisonFunction(sortFunction), description(sortDescription) {}
|
||||
: comparisonFunction(sortFunction)
|
||||
, description(sortDescription)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void sort(ComparisonFunction& comparator, std::pair<unsigned int, unsigned int>& gameCount);
|
||||
|
@ -115,8 +124,8 @@ public:
|
|||
// Only count the games, a cheaper alternative to a full sort when that is not required.
|
||||
void countGames(std::pair<unsigned int, unsigned int>& gameCount);
|
||||
|
||||
inline void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||
inline std::string getSortTypeString() { return mSortTypeString; }
|
||||
void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||
std::string getSortTypeString() { return mSortTypeString; }
|
||||
FileData::SortType getSortTypeFromString(std::string desc);
|
||||
|
||||
protected:
|
||||
|
@ -130,7 +139,7 @@ private:
|
|||
std::string mPath;
|
||||
SystemEnvironmentData* mEnvData;
|
||||
SystemData* mSystem;
|
||||
std::unordered_map<std::string,FileData*> mChildrenByFilename;
|
||||
std::unordered_map<std::string, FileData*> mChildrenByFilename;
|
||||
std::vector<FileData*> mChildren;
|
||||
std::vector<FileData*> mFilteredChildren;
|
||||
// The pair includes all games, and favorite games.
|
||||
|
@ -148,8 +157,8 @@ public:
|
|||
~CollectionFileData();
|
||||
const std::string& getName();
|
||||
void refreshMetadata();
|
||||
FileData* getSourceFileData();
|
||||
std::string getKey();
|
||||
FileData* getSourceFileData() { return mSourceFileData; }
|
||||
std::string getKey() { return getFullPath(); }
|
||||
|
||||
private:
|
||||
// Needs to be updated when metadata changes.
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
#include "FileFilterIndex.h"
|
||||
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
|
@ -21,19 +21,20 @@
|
|||
#define INCLUDE_UNKNOWN false;
|
||||
|
||||
FileFilterIndex::FileFilterIndex()
|
||||
: mFilterByText(false),
|
||||
mFilterByFavorites(false),
|
||||
mFilterByGenre(false),
|
||||
mFilterByPlayers(false),
|
||||
mFilterByPubDev(false),
|
||||
mFilterByRatings(false),
|
||||
mFilterByKidGame(false),
|
||||
mFilterByCompleted(false),
|
||||
mFilterByBroken(false),
|
||||
mFilterByHidden(false)
|
||||
: mFilterByText(false)
|
||||
, mFilterByFavorites(false)
|
||||
, mFilterByGenre(false)
|
||||
, mFilterByPlayers(false)
|
||||
, mFilterByPubDev(false)
|
||||
, mFilterByRatings(false)
|
||||
, mFilterByKidGame(false)
|
||||
, mFilterByCompleted(false)
|
||||
, mFilterByBroken(false)
|
||||
, mFilterByHidden(false)
|
||||
{
|
||||
clearAllFilters();
|
||||
|
||||
// clang-format off
|
||||
FilterDataDecl filterDecls[] = {
|
||||
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
||||
{ FAVORITES_FILTER, &mFavoritesIndexAllKeys, &mFilterByFavorites, &mFavoritesIndexFilteredKeys, "favorite", false, "", "FAVORITES" },
|
||||
|
@ -46,21 +47,18 @@ FileFilterIndex::FileFilterIndex()
|
|||
{ BROKEN_FILTER, &mBrokenIndexAllKeys, &mFilterByBroken, &mBrokenIndexFilteredKeys, "broken", false, "", "BROKEN" },
|
||||
{ HIDDEN_FILTER, &mHiddenIndexAllKeys, &mFilterByHidden, &mHiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN" }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
filterDataDecl = std::vector<FilterDataDecl>(filterDecls, filterDecls +
|
||||
sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||
filterDataDecl = std::vector<FilterDataDecl>(
|
||||
filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||
}
|
||||
|
||||
FileFilterIndex::~FileFilterIndex()
|
||||
{
|
||||
// Reset the index when destroyed.
|
||||
resetIndex();
|
||||
}
|
||||
|
||||
std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
|
||||
{
|
||||
return filterDataDecl;
|
||||
}
|
||||
|
||||
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
||||
{
|
||||
struct IndexImportStructure {
|
||||
|
@ -80,24 +78,25 @@ void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
|||
{ &mHiddenIndexAllKeys, &(indexToImport->mHiddenIndexAllKeys) },
|
||||
};
|
||||
|
||||
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++) {
|
||||
(*indexesIt).sourceIndex->cbegin();
|
||||
sourceIt != (*indexesIt).sourceIndex->cend(); sourceIt++) {
|
||||
if ((*indexesIt).destinationIndex->find((*sourceIt).first) ==
|
||||
(*indexesIt).destinationIndex->cend())
|
||||
(*indexesIt).destinationIndex->cend()) {
|
||||
// Entry doesn't exist.
|
||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
|
||||
else
|
||||
}
|
||||
else {
|
||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::resetIndex()
|
||||
|
@ -115,7 +114,8 @@ void FileFilterIndex::resetIndex()
|
|||
}
|
||||
|
||||
std::string FileFilterIndex::getIndexableKey(FileData* game,
|
||||
FilterIndexType type, bool getSecondary)
|
||||
FilterIndexType type,
|
||||
bool getSecondary)
|
||||
{
|
||||
std::string key = "";
|
||||
switch (type) {
|
||||
|
@ -166,8 +166,8 @@ std::string FileFilterIndex::getIndexableKey(FileData* game,
|
|||
// These values should only exist if a third party application has
|
||||
// been used for scraping the ratings, or if the gamelist.xml file
|
||||
// has been manually edited.
|
||||
ratingNumber = static_cast<int>(
|
||||
(ceilf(stof(ratingString) / 0.1f) / 10) * 5);
|
||||
ratingNumber =
|
||||
static_cast<int>((ceilf(stof(ratingString) / 0.1f) / 10.0f) * 5.0f);
|
||||
|
||||
if (ratingNumber < 0)
|
||||
ratingNumber = 0;
|
||||
|
@ -179,8 +179,8 @@ std::string FileFilterIndex::getIndexableKey(FileData* game,
|
|||
std::to_string(ratingNumber) + ".5 STARS";
|
||||
}
|
||||
catch (int e) {
|
||||
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): " <<
|
||||
ratingString << ", " << e;
|
||||
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): "
|
||||
<< ratingString << ", " << e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,8 +259,8 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>*
|
|||
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++) {
|
||||
for (std::vector<std::string>::const_iterator vit = values->cbegin();
|
||||
vit != values->cend(); vit++) {
|
||||
// Check if it exists.
|
||||
if (filterData.allIndexKeys->find(*vit) != filterData.allIndexKeys->cend()) {
|
||||
filterData.currentFilteredKeys->push_back(std::string(*vit));
|
||||
|
@ -272,15 +272,15 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>*
|
|||
return;
|
||||
}
|
||||
|
||||
void FileFilterIndex::setTextFilter(std::string textFilter)
|
||||
{
|
||||
void FileFilterIndex::setTextFilter(std::string textFilter)
|
||||
{
|
||||
mTextFilter = textFilter;
|
||||
|
||||
if (textFilter == "")
|
||||
mFilterByText = false;
|
||||
else
|
||||
mFilterByText = true;
|
||||
};
|
||||
};
|
||||
|
||||
void FileFilterIndex::clearAllFilters()
|
||||
{
|
||||
|
@ -312,19 +312,19 @@ void FileFilterIndex::setKidModeFilters()
|
|||
void FileFilterIndex::debugPrintIndexes()
|
||||
{
|
||||
LOG(LogInfo) << "Printing Indexes...";
|
||||
for (auto x: mFavoritesIndexAllKeys) {
|
||||
for (auto x : mFavoritesIndexAllKeys) {
|
||||
LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x: mGenreIndexAllKeys) {
|
||||
for (auto x : mGenreIndexAllKeys) {
|
||||
LOG(LogInfo) << "Genre Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x: mPlayersIndexAllKeys) {
|
||||
for (auto x : mPlayersIndexAllKeys) {
|
||||
LOG(LogInfo) << "Multiplayer Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x: mPubDevIndexAllKeys) {
|
||||
for (auto x : mPubDevIndexAllKeys) {
|
||||
LOG(LogInfo) << "PubDev Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x: mRatingsIndexAllKeys) {
|
||||
for (auto x : mRatingsIndexAllKeys) {
|
||||
LOG(LogInfo) << "Ratings Index: " << x.first << ": " << x.second;
|
||||
}
|
||||
for (auto x : mKidGameIndexAllKeys) {
|
||||
|
@ -348,8 +348,8 @@ bool FileFilterIndex::showFile(FileData* game)
|
|||
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++) {
|
||||
for (std::vector<FileData*>::const_iterator it = children.cbegin(); it != children.cend();
|
||||
it++) {
|
||||
if (showFile(*it))
|
||||
return true;
|
||||
}
|
||||
|
@ -361,8 +361,8 @@ bool FileFilterIndex::showFile(FileData* game)
|
|||
|
||||
// Name filters take precedence over all other filters, so if there is no match for
|
||||
// the game name, then always return false.
|
||||
if (mTextFilter != "" && !(Utils::String::toUpper(game->
|
||||
getName()).find(mTextFilter) != std::string::npos)) {
|
||||
if (mTextFilter != "" &&
|
||||
!(Utils::String::toUpper(game->getName()).find(mTextFilter) != std::string::npos)) {
|
||||
return false;
|
||||
}
|
||||
else if (mTextFilter != "") {
|
||||
|
@ -419,13 +419,14 @@ bool FileFilterIndex::isFiltered()
|
|||
|
||||
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
||||
{
|
||||
const FilterIndexType filterTypes[9] = { FAVORITES_FILTER, GENRE_FILTER,
|
||||
PLAYER_FILTER, PUBDEV_FILTER, RATINGS_FILTER, KIDGAME_FILTER,
|
||||
const FilterIndexType filterTypes[9] = { FAVORITES_FILTER, GENRE_FILTER, PLAYER_FILTER,
|
||||
PUBDEV_FILTER, RATINGS_FILTER, KIDGAME_FILTER,
|
||||
COMPLETED_FILTER, BROKEN_FILTER, HIDDEN_FILTER };
|
||||
std::vector<std::string> filterKeysList[9] = { mFavoritesIndexFilteredKeys,
|
||||
mGenreIndexFilteredKeys, mPlayersIndexFilteredKeys, mPubDevIndexFilteredKeys,
|
||||
mRatingsIndexFilteredKeys, mKidGameIndexFilteredKeys, mCompletedIndexFilteredKeys,
|
||||
mBrokenIndexFilteredKeys, mHiddenIndexFilteredKeys };
|
||||
std::vector<std::string> filterKeysList[9] = {
|
||||
mFavoritesIndexFilteredKeys, mGenreIndexFilteredKeys, mPlayersIndexFilteredKeys,
|
||||
mPubDevIndexFilteredKeys, mRatingsIndexFilteredKeys, mKidGameIndexFilteredKeys,
|
||||
mCompletedIndexFilteredKeys, mBrokenIndexFilteredKeys, mHiddenIndexFilteredKeys
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (filterTypes[i] == type) {
|
||||
|
@ -589,7 +590,8 @@ void FileFilterIndex::manageHiddenEntryInIndex(FileData* game, bool remove)
|
|||
}
|
||||
|
||||
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
||||
std::string key, bool remove)
|
||||
std::string key,
|
||||
bool remove)
|
||||
{
|
||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||
|
@ -600,7 +602,7 @@ void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
|||
if (index->find(key) == index->cend()) {
|
||||
// Disabled for now as this could happen because default values are assigned as
|
||||
// filters, for example 'FALSE' for favorites and kidgames for non-game entries.
|
||||
// LOG(LogDebug) << "Couldn't find entry in index! " << key;
|
||||
// LOG(LogDebug) << "Couldn't find entry in index! " << key;
|
||||
}
|
||||
else {
|
||||
(index->at(key))--;
|
||||
|
@ -617,8 +619,3 @@ void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
|||
(index->at(key))++;
|
||||
}
|
||||
}
|
||||
|
||||
void FileFilterIndex::clearIndex(std::map<std::string, int>& indexMap)
|
||||
{
|
||||
indexMap.clear();
|
||||
}
|
||||
|
|
|
@ -52,13 +52,13 @@ public:
|
|||
void removeFromIndex(FileData* game);
|
||||
void setFilter(FilterIndexType type, std::vector<std::string>* values);
|
||||
void setTextFilter(std::string textFilter);
|
||||
std::string getTextFilter() { return mTextFilter; };
|
||||
std::string getTextFilter() { return mTextFilter; }
|
||||
void clearAllFilters();
|
||||
void debugPrintIndexes();
|
||||
bool showFile(FileData* game);
|
||||
bool isFiltered();
|
||||
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
|
||||
std::vector<FilterDataDecl>& getFilterDataDecls();
|
||||
std::vector<FilterDataDecl>& getFilterDataDecls() { return filterDataDecl; }
|
||||
|
||||
void importIndex(FileFilterIndex* indexToImport);
|
||||
void resetIndex();
|
||||
|
@ -81,7 +81,7 @@ private:
|
|||
|
||||
void manageIndexEntry(std::map<std::string, int>* index, std::string key, bool remove);
|
||||
|
||||
void clearIndex(std::map<std::string, int>& indexMap);
|
||||
void clearIndex(std::map<std::string, int>& indexMap) { indexMap.clear(); }
|
||||
|
||||
std::string mTextFilter;
|
||||
bool mFilterByText;
|
||||
|
@ -117,7 +117,6 @@ private:
|
|||
std::vector<std::string> mHiddenIndexFilteredKeys;
|
||||
|
||||
FileData* mRootFolder;
|
||||
|
||||
};
|
||||
|
||||
#endif // ES_APP_FILE_FILTER_INDEX_H
|
||||
|
|
|
@ -48,8 +48,9 @@ namespace FileSorts
|
|||
FileData::SortType(&compareSystemDescending, "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]));
|
||||
|
||||
bool compareName(const FileData* file1, const FileData* file2)
|
||||
{
|
||||
|
@ -155,11 +156,13 @@ namespace FileSorts
|
|||
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
||||
// Any non-numeric value will end up as zero.
|
||||
if (!file1Players.empty() &&
|
||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit)) {
|
||||
file1Int = stoi(file1Players);
|
||||
}
|
||||
if (!file2Players.empty() &&
|
||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit)) {
|
||||
file2Int = stoi(file2Players);
|
||||
}
|
||||
return file1Int < file2Int;
|
||||
}
|
||||
|
||||
|
@ -177,11 +180,13 @@ namespace FileSorts
|
|||
if (dashPos != std::string::npos)
|
||||
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
||||
if (!file1Players.empty() &&
|
||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit)) {
|
||||
file1Int = stoi(file1Players);
|
||||
}
|
||||
if (!file2Players.empty() &&
|
||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit)) {
|
||||
file2Int = stoi(file2Players);
|
||||
}
|
||||
return file1Int > file2Int;
|
||||
}
|
||||
|
||||
|
@ -201,16 +206,18 @@ namespace FileSorts
|
|||
{
|
||||
// Only games have playcount metadata.
|
||||
if (file1->metadata.getType() == GAME_METADATA &&
|
||||
file2->metadata.getType() == GAME_METADATA)
|
||||
file2->metadata.getType() == GAME_METADATA) {
|
||||
return (file1)->metadata.getInt("playcount") < (file2)->metadata.getInt("playcount");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool compareTimesPlayedDescending(const FileData* file1, const FileData* file2)
|
||||
{
|
||||
if (file1->metadata.getType() == GAME_METADATA &&
|
||||
file2->metadata.getType() == GAME_METADATA)
|
||||
file2->metadata.getType() == GAME_METADATA) {
|
||||
return (file1)->metadata.getInt("playcount") > (file2)->metadata.getInt("playcount");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -227,4 +234,5 @@ namespace FileSorts
|
|||
std::string system2 = Utils::String::toUpper(file2->getSystemName());
|
||||
return system1.compare(system2) > 0;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace FileSorts
|
||||
|
|
|
@ -38,6 +38,6 @@ namespace FileSorts
|
|||
bool compareSystemDescending(const FileData* file1, const FileData* file2);
|
||||
|
||||
extern const std::vector<FileData::SortType> SortTypes;
|
||||
};
|
||||
}; // namespace FileSorts
|
||||
|
||||
#endif // ES_APP_FILE_SORTS_H
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
#include "Gamelist.h"
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
|
@ -25,8 +25,8 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
|||
std::string relative = Utils::FileSystem::removeCommonPath(path, root->getPath(), contains);
|
||||
|
||||
if (!contains) {
|
||||
LOG(LogError) << "Path \"" << path << "\" is outside system path \"" <<
|
||||
system->getStartPath() << "\"";
|
||||
LOG(LogError) << "Path \"" << path << "\" is outside system path \""
|
||||
<< system->getStartPath() << "\"";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,9 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
|||
}
|
||||
|
||||
// Create missing folder.
|
||||
FileData* folder = new FileData(FOLDER, Utils::FileSystem::getStem(treeNode->getPath())
|
||||
+ "/" + *path_it, system->getSystemEnvData(), system);
|
||||
FileData* folder = new FileData(
|
||||
FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it,
|
||||
system->getSystemEnvData(), system);
|
||||
treeNode->addChild(folder);
|
||||
treeNode = folder;
|
||||
}
|
||||
|
@ -89,24 +90,24 @@ void parseGamelist(SystemData* system)
|
|||
std::string xmlpath = system->getGamelistPath(false);
|
||||
|
||||
if (!Utils::FileSystem::exists(xmlpath)) {
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): System \"" << system->getName() <<
|
||||
"\" does not have a gamelist.xml file";
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): System \"" << system->getName()
|
||||
<< "\" does not have a gamelist.xml file";
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(LogInfo) << "Parsing gamelist file \"" << xmlpath << "\"...";
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result result =
|
||||
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!result) {
|
||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlpath <<
|
||||
"\": " << result.description();
|
||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlpath
|
||||
<< "\": " << result.description();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,24 +125,24 @@ void parseGamelist(SystemData* system)
|
|||
for (int i = 0; i < 2; i++) {
|
||||
std::string tag = tagList[i];
|
||||
FileType type = typeList[i];
|
||||
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode; fileNode =
|
||||
fileNode.next_sibling(tag.c_str())) {
|
||||
const std::string path =
|
||||
Utils::FileSystem::resolveRelativePath(fileNode.child("path").text().get(),
|
||||
relativeTo, false);
|
||||
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode;
|
||||
fileNode = fileNode.next_sibling(tag.c_str())) {
|
||||
const std::string path = Utils::FileSystem::resolveRelativePath(
|
||||
fileNode.child("path").text().get(), relativeTo, false);
|
||||
|
||||
if (!trustGamelist && !Utils::FileSystem::exists(path)) {
|
||||
LOG(LogWarning) << (type == GAME ? "File \"" : "Folder \"") << path <<
|
||||
"\" does not exist, ignoring entry";
|
||||
LOG(LogWarning) << (type == GAME ? "File \"" : "Folder \"") << path
|
||||
<< "\" does not exist, ignoring entry";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip hidden files, check both the file itself and the directory in which
|
||||
// it is located.
|
||||
if (!showHiddenFiles && (Utils::FileSystem::isHidden(path) ||
|
||||
if (!showHiddenFiles &&
|
||||
(Utils::FileSystem::isHidden(path) ||
|
||||
Utils::FileSystem::isHidden(Utils::FileSystem::getParent(path)))) {
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden file \"" <<
|
||||
path << "\"";
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden file \"" << path
|
||||
<< "\"";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -163,8 +164,8 @@ void parseGamelist(SystemData* system)
|
|||
else {
|
||||
// Skip arcade asset entries as these will not be used in any way inside
|
||||
// the application.
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping arcade asset \"" <<
|
||||
file->getName() << "\"";
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping arcade asset \""
|
||||
<< file->getName() << "\"";
|
||||
delete file;
|
||||
continue;
|
||||
}
|
||||
|
@ -174,9 +175,10 @@ void parseGamelist(SystemData* system)
|
|||
// application restart.
|
||||
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
||||
if (file->getHidden()) {
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden " <<
|
||||
(type == GAME ? "file" : "folder") << " entry \"" <<
|
||||
file->getName() << "\"" << " (\"" << file->getPath() << "\")";
|
||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden "
|
||||
<< (type == GAME ? "file" : "folder") << " entry \""
|
||||
<< file->getName() << "\""
|
||||
<< " (\"" << file->getPath() << "\")";
|
||||
delete file;
|
||||
}
|
||||
// Also delete any folders which are empty, i.e. all their entries are hidden.
|
||||
|
@ -188,8 +190,10 @@ void parseGamelist(SystemData* system)
|
|||
}
|
||||
}
|
||||
|
||||
void addFileDataNode(pugi::xml_node& parent, const FileData* file,
|
||||
const std::string& tag, SystemData* system)
|
||||
void addFileDataNode(pugi::xml_node& parent,
|
||||
const FileData* file,
|
||||
const std::string& tag,
|
||||
SystemData* system)
|
||||
{
|
||||
// Create game and add to parent node.
|
||||
pugi::xml_node newNode = parent.append_child(tag.c_str());
|
||||
|
@ -211,8 +215,9 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file,
|
|||
|
||||
// Try and make the path relative if we can so things still
|
||||
// work if we change the ROM folder location in the future.
|
||||
newNode.prepend_child("path").text().set(Utils::FileSystem::createRelativePath(file->
|
||||
getPath(), system->getStartPath(), false).c_str());
|
||||
newNode.prepend_child("path").text().set(
|
||||
Utils::FileSystem::createRelativePath(file->getPath(), system->getStartPath(), false)
|
||||
.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,23 +237,23 @@ void updateGamelist(SystemData* system)
|
|||
|
||||
if (Utils::FileSystem::exists(xmlReadPath)) {
|
||||
// Parse an existing file first.
|
||||
#if defined(_WIN64)
|
||||
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result result =
|
||||
doc.load_file(Utils::String::stringToWideString(xmlReadPath).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!result) {
|
||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlReadPath << "\": " <<
|
||||
result.description();
|
||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlReadPath
|
||||
<< "\": " << result.description();
|
||||
return;
|
||||
}
|
||||
|
||||
root = doc.child("gameList");
|
||||
if (!root) {
|
||||
LOG(LogError) << "Couldn't find <gameList> node in gamelist \"" <<
|
||||
xmlReadPath << "\"";
|
||||
LOG(LogError) << "Couldn't find <gameList> node in gamelist \"" << xmlReadPath << "\"";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +271,7 @@ void updateGamelist(SystemData* system)
|
|||
// Get only files, no folders.
|
||||
std::vector<FileData*> files = rootFolder->getFilesRecursive(GAME | FOLDER);
|
||||
// Iterate through all files, checking if they're already in the XML file.
|
||||
for (std::vector<FileData*>::const_iterator fit = files.cbegin();
|
||||
for (std::vector<FileData*>::const_iterator fit = files.cbegin(); // Line break.
|
||||
fit != files.cend(); fit++) {
|
||||
const std::string tag = ((*fit)->getType() == GAME) ? "game" : "folder";
|
||||
|
||||
|
@ -284,9 +289,9 @@ void updateGamelist(SystemData* system)
|
|||
continue;
|
||||
}
|
||||
|
||||
std::string nodePath = Utils::FileSystem::getCanonicalPath(
|
||||
Utils::FileSystem::resolveRelativePath(pathNode.text().get(),
|
||||
system->getStartPath(), true));
|
||||
std::string nodePath =
|
||||
Utils::FileSystem::getCanonicalPath(Utils::FileSystem::resolveRelativePath(
|
||||
pathNode.text().get(), system->getStartPath(), true));
|
||||
std::string gamePath = Utils::FileSystem::getCanonicalPath((*fit)->getPath());
|
||||
|
||||
if (nodePath == gamePath) {
|
||||
|
@ -312,16 +317,17 @@ void updateGamelist(SystemData* system)
|
|||
std::string xmlWritePath(system->getGamelistPath(true));
|
||||
Utils::FileSystem::createDirectory(Utils::FileSystem::getParent(xmlWritePath));
|
||||
|
||||
LOG(LogDebug) << "Gamelist::updateGamelist(): Added/updated " << numUpdated <<
|
||||
(numUpdated == 1 ? " entity in \"" : " entities in \"") << xmlReadPath << "\"";
|
||||
LOG(LogDebug) << "Gamelist::updateGamelist(): Added/updated " << numUpdated
|
||||
<< (numUpdated == 1 ? " entity in \"" : " entities in \"") << xmlReadPath
|
||||
<< "\"";
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
if (!doc.save_file(Utils::String::stringToWideString(xmlWritePath).c_str())) {
|
||||
#else
|
||||
#else
|
||||
if (!doc.save_file(xmlWritePath.c_str())) {
|
||||
#endif
|
||||
LOG(LogError) << "Error saving gamelist.xml to \"" <<
|
||||
xmlWritePath << "\" (for system " << system->getName() << ")";
|
||||
#endif
|
||||
LOG(LogError) << "Error saving gamelist.xml to \"" << xmlWritePath
|
||||
<< "\" (for system " << system->getName() << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@
|
|||
#if defined(BUILD_VLC_PLAYER)
|
||||
#include "components/VideoVlcComponent.h"
|
||||
#endif
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "Sound.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
MediaViewer::MediaViewer(Window* window) : mWindow(window), mVideo(nullptr), mImage(nullptr)
|
||||
MediaViewer::MediaViewer(Window* window)
|
||||
: mWindow(window)
|
||||
, mVideo(nullptr)
|
||||
, mImage(nullptr)
|
||||
{
|
||||
mWindow->setMediaViewer(this);
|
||||
}
|
||||
|
@ -90,7 +93,7 @@ void MediaViewer::render()
|
|||
if (mVideo && !mDisplayingImage) {
|
||||
mVideo->render(transform);
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
Renderer::shaderParameters videoParameters;
|
||||
unsigned int shaders = 0;
|
||||
if (Settings::getInstance()->getBool("MediaViewerVideoScanlines"))
|
||||
|
@ -98,6 +101,7 @@ void MediaViewer::render()
|
|||
if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
||||
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
||||
float heightModifier = Renderer::getScreenHeightModifier();
|
||||
// clang-format off
|
||||
if (heightModifier < 1)
|
||||
videoParameters.blurPasses = 2; // Below 1080
|
||||
else if (heightModifier >= 4)
|
||||
|
@ -112,18 +116,19 @@ void MediaViewer::render()
|
|||
videoParameters.blurPasses = 3; // 1440
|
||||
else if (heightModifier >= 1)
|
||||
videoParameters.blurPasses = 2; // 1080
|
||||
// clang-format on
|
||||
}
|
||||
Renderer::shaderPostprocessing(shaders, videoParameters);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else if (mImage && mImage->hasImage() && mImage->getSize() != 0) {
|
||||
mImage->render(transform);
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
if (mCurrentImageIndex == mScreenShotIndex &&
|
||||
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
|
||||
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This is necessary so that the video loops if viewing an image when
|
||||
// the video ends.
|
||||
|
@ -244,14 +249,14 @@ void MediaViewer::playVideo()
|
|||
mDisplayingImage = false;
|
||||
ViewController::get()->onStopVideo();
|
||||
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
if (Settings::getInstance()->getString("VideoPlayer") == "ffmpeg")
|
||||
mVideo = new VideoFFmpegComponent(mWindow);
|
||||
else
|
||||
mVideo = new VideoVlcComponent(mWindow);
|
||||
#else
|
||||
#else
|
||||
mVideo = new VideoFFmpegComponent(mWindow);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mVideo->topWindow(true);
|
||||
mVideo->setOrigin(0.5f, 0.5f);
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#ifndef ES_APP_MEDIA_VIEWER_H
|
||||
#define ES_APP_MEDIA_VIEWER_H
|
||||
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/VideoComponent.h"
|
||||
#include "FileData.h"
|
||||
#include "Window.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/VideoComponent.h"
|
||||
|
||||
class MediaViewer : public Window::MediaViewer
|
||||
{
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
|
||||
#include "MetaData.h"
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "Log.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
// clang-format off
|
||||
MetaDataDecl gameDecls[] = {
|
||||
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape
|
||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
||||
|
@ -39,9 +40,6 @@ MetaDataDecl gameDecls[] = {
|
|||
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date", false}
|
||||
};
|
||||
|
||||
const std::vector<MetaDataDecl> gameMDD(gameDecls, gameDecls +
|
||||
sizeof(gameDecls) / sizeof(gameDecls[0]));
|
||||
|
||||
MetaDataDecl folderDecls[] = {
|
||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
||||
{"desc", MD_MULTILINE_STRING, "", false, "description", "enter description", true},
|
||||
|
@ -59,13 +57,18 @@ MetaDataDecl folderDecls[] = {
|
|||
{"hidemetadata", MD_BOOL, "false", false, "hide metadata fields", "enter hide metadata off/on", false},
|
||||
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date", false}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::vector<MetaDataDecl> folderMDD(folderDecls, folderDecls +
|
||||
const std::vector<MetaDataDecl> gameMDD(gameDecls,
|
||||
gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0]));
|
||||
|
||||
const std::vector<MetaDataDecl> folderMDD(folderDecls,
|
||||
folderDecls +
|
||||
sizeof(folderDecls) / sizeof(folderDecls[0]));
|
||||
|
||||
const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
|
||||
{
|
||||
switch(type) {
|
||||
switch (type) {
|
||||
case GAME_METADATA:
|
||||
return gameMDD;
|
||||
case FOLDER_METADATA:
|
||||
|
@ -77,7 +80,8 @@ const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
|
|||
}
|
||||
|
||||
MetaDataList::MetaDataList(MetaDataListType type)
|
||||
: mType(type), mWasChanged(false)
|
||||
: mType(type)
|
||||
, mWasChanged(false)
|
||||
{
|
||||
const std::vector<MetaDataDecl>& mdd = getMDD();
|
||||
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++)
|
||||
|
@ -85,7 +89,8 @@ MetaDataList::MetaDataList(MetaDataListType type)
|
|||
}
|
||||
|
||||
MetaDataList MetaDataList::createFromXML(MetaDataListType type,
|
||||
pugi::xml_node& node, const std::string& relativeTo)
|
||||
pugi::xml_node& node,
|
||||
const std::string& relativeTo)
|
||||
{
|
||||
MetaDataList mdl(type);
|
||||
|
||||
|
@ -107,7 +112,8 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type,
|
|||
return mdl;
|
||||
}
|
||||
|
||||
void MetaDataList::appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
||||
void MetaDataList::appendToXML(pugi::xml_node& parent,
|
||||
bool ignoreDefaults,
|
||||
const std::string& relativeTo) const
|
||||
{
|
||||
const std::vector<MetaDataDecl>& mdd = getMDD();
|
||||
|
@ -138,30 +144,33 @@ void MetaDataList::set(const std::string& key, const std::string& value)
|
|||
|
||||
const std::string& MetaDataList::get(const std::string& key) const
|
||||
{
|
||||
// Check that the key actually exists, otherwise return empty string.
|
||||
// Check that the key actually exists, otherwise return an empty string.
|
||||
if (mMap.count(key) > 0)
|
||||
return mMap.at(key);
|
||||
else
|
||||
|
||||
return mNoResult;
|
||||
}
|
||||
|
||||
int MetaDataList::getInt(const std::string& key) const
|
||||
{
|
||||
// Return integer value.
|
||||
return atoi(get(key).c_str());
|
||||
}
|
||||
|
||||
float MetaDataList::getFloat(const std::string& key) const
|
||||
{
|
||||
// Return float value.
|
||||
return static_cast<float>(atof(get(key).c_str()));
|
||||
}
|
||||
|
||||
bool MetaDataList::wasChanged() const
|
||||
{
|
||||
// Return whether the metadata was changed.
|
||||
return mWasChanged;
|
||||
}
|
||||
|
||||
void MetaDataList::resetChangedFlag()
|
||||
{
|
||||
// Reset the change flag.
|
||||
mWasChanged = false;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pugi { class xml_node; }
|
||||
namespace pugi
|
||||
{
|
||||
class xml_node;
|
||||
}
|
||||
|
||||
enum MetaDataType {
|
||||
// Generic types.
|
||||
|
@ -51,7 +54,7 @@ struct MetaDataDecl {
|
|||
};
|
||||
|
||||
enum MetaDataListType {
|
||||
GAME_METADATA,
|
||||
GAME_METADATA, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
FOLDER_METADATA
|
||||
};
|
||||
|
||||
|
@ -61,8 +64,10 @@ class MetaDataList
|
|||
{
|
||||
public:
|
||||
static MetaDataList createFromXML(MetaDataListType type,
|
||||
pugi::xml_node& node, const std::string& relativeTo);
|
||||
void appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
||||
pugi::xml_node& node,
|
||||
const std::string& relativeTo);
|
||||
void appendToXML(pugi::xml_node& parent,
|
||||
bool ignoreDefaults,
|
||||
const std::string& relativeTo) const;
|
||||
|
||||
MetaDataList(MetaDataListType type);
|
||||
|
@ -76,10 +81,12 @@ public:
|
|||
bool wasChanged() const;
|
||||
void resetChangedFlag();
|
||||
|
||||
inline MetaDataListType getType() const { return mType; }
|
||||
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
||||
inline const std::vector<MetaDataDecl>& getMDD(MetaDataListType type) const
|
||||
{ return getMDDByType(type); }
|
||||
MetaDataListType getType() const { return mType; }
|
||||
const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
||||
const std::vector<MetaDataDecl>& getMDD(MetaDataListType type) const
|
||||
{
|
||||
return getMDDByType(type);
|
||||
}
|
||||
|
||||
private:
|
||||
MetaDataListType mType;
|
||||
|
|
|
@ -9,28 +9,26 @@
|
|||
|
||||
#include "MiximageGenerator.h"
|
||||
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
MiximageGenerator::MiximageGenerator(FileData* game, std::string& resultMessage)
|
||||
: mGame(game),
|
||||
mResultMessage(resultMessage),
|
||||
mWidth(1280),
|
||||
mHeight(960),
|
||||
mMarquee(false),
|
||||
mBox3D(false),
|
||||
mCover(false)
|
||||
: mGame(game)
|
||||
, mResultMessage(resultMessage)
|
||||
, mWidth(1280)
|
||||
, mHeight(960)
|
||||
, mMarquee(false)
|
||||
, mBox3D(false)
|
||||
, mCover(false)
|
||||
{
|
||||
}
|
||||
|
||||
MiximageGenerator::~MiximageGenerator()
|
||||
{
|
||||
}
|
||||
MiximageGenerator::~MiximageGenerator() {}
|
||||
|
||||
void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
||||
{
|
||||
|
@ -68,7 +66,7 @@ void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
|||
mBox3D = true;
|
||||
}
|
||||
else if (Settings::getInstance()->getBool("MiximageCoverFallback") &&
|
||||
(mCoverPath= mGame->getCoverPath()) != "") {
|
||||
(mCoverPath = mGame->getCoverPath()) != "") {
|
||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
||||
"No 3D box image found, using cover image as fallback";
|
||||
mCover = true;
|
||||
|
@ -93,9 +91,10 @@ void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
|||
else {
|
||||
const auto endTime = std::chrono::system_clock::now();
|
||||
|
||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): Processing completed in: " <<
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
(endTime - startTime).count() << " ms";
|
||||
LOG(LogDebug)
|
||||
<< "MiximageGenerator::MiximageGenerator(): Processing completed in: "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count()
|
||||
<< " ms";
|
||||
}
|
||||
|
||||
mResultMessage = mMessage;
|
||||
|
@ -113,19 +112,19 @@ bool MiximageGenerator::generateImage()
|
|||
unsigned int fileHeight = 0;
|
||||
unsigned int filePitch = 0;
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFileType(mScreenshotPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN)
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||
Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFIFFromFilename(mScreenshotPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN) {
|
||||
LOG(LogError) << "Screenshot image in unknown image format, aborting";
|
||||
|
@ -135,12 +134,12 @@ bool MiximageGenerator::generateImage()
|
|||
|
||||
// Make sure that we can actually read this format.
|
||||
if (FreeImage_FIFSupportsReading(fileFormat)) {
|
||||
#if defined(_WIN64)
|
||||
screenshotFile = FreeImage_LoadU(fileFormat,
|
||||
Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
screenshotFile =
|
||||
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||
#else
|
||||
screenshotFile = FreeImage_Load(fileFormat, mScreenshotPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "Screenshot file format not supported";
|
||||
|
@ -155,20 +154,20 @@ bool MiximageGenerator::generateImage()
|
|||
}
|
||||
|
||||
if (mMarquee) {
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFileTypeU(
|
||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
fileFormat =
|
||||
FreeImage_GetFileTypeU(Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||
#else
|
||||
fileFormat = FreeImage_GetFileType(mMarqueePath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN)
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFIFFromFilename(mMarqueePath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN) {
|
||||
LOG(LogDebug) << "Marquee in unknown format, skipping image";
|
||||
|
@ -180,12 +179,12 @@ bool MiximageGenerator::generateImage()
|
|||
mMarquee = false;
|
||||
}
|
||||
else {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
marqueeFile = FreeImage_LoadU(fileFormat,
|
||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||
#else
|
||||
#else
|
||||
marqueeFile = FreeImage_Load(fileFormat, mMarqueePath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
if (!marqueeFile) {
|
||||
LOG(LogError) << "Couldn't load marquee image, corrupt file?";
|
||||
mMessage = "Error loading marquee image, corrupt file?";
|
||||
|
@ -195,19 +194,19 @@ bool MiximageGenerator::generateImage()
|
|||
}
|
||||
|
||||
if (mBox3D) {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFileType(mBox3DPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN)
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||
Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFIFFromFilename(mBox3DPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN) {
|
||||
LOG(LogDebug) << "3D box in unknown format, skipping image";
|
||||
|
@ -219,12 +218,12 @@ bool MiximageGenerator::generateImage()
|
|||
mBox3D = false;
|
||||
}
|
||||
else {
|
||||
#if defined(_WIN64)
|
||||
boxFile = FreeImage_LoadU(fileFormat,
|
||||
Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
boxFile =
|
||||
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||
#else
|
||||
boxFile = FreeImage_Load(fileFormat, mBox3DPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
if (!boxFile) {
|
||||
LOG(LogError) << "Couldn't load 3D box image, corrupt file?";
|
||||
mMessage = "Error loading 3d box image, corrupt file?";
|
||||
|
@ -233,20 +232,19 @@ bool MiximageGenerator::generateImage()
|
|||
}
|
||||
}
|
||||
else if (mCover) {
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFileTypeU(
|
||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mCoverPath).c_str());
|
||||
#else
|
||||
fileFormat = FreeImage_GetFileType(mCoverPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN)
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
||||
#else
|
||||
#else
|
||||
fileFormat = FreeImage_GetFIFFromFilename(mCoverPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (fileFormat == FIF_UNKNOWN) {
|
||||
LOG(LogDebug) << "Box cover in unknown format, skipping image";
|
||||
|
@ -258,12 +256,12 @@ bool MiximageGenerator::generateImage()
|
|||
mCover = false;
|
||||
}
|
||||
else {
|
||||
#if defined(_WIN64)
|
||||
boxFile = FreeImage_LoadU(fileFormat,
|
||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
boxFile =
|
||||
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mCoverPath).c_str());
|
||||
#else
|
||||
boxFile = FreeImage_Load(fileFormat, mCoverPath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
if (!boxFile) {
|
||||
LOG(LogError) << "Couldn't load box cover image, corrupt file?";
|
||||
mMessage = "Error loading box cover image, corrupt file?";
|
||||
|
@ -409,7 +407,7 @@ bool MiximageGenerator::generateImage()
|
|||
yPosMarquee = 0;
|
||||
|
||||
// Only RGB channels for the image.
|
||||
marqueeImageRGB = CImg<unsigned char>(marqueeImage.get_shared_channels(0,2));
|
||||
marqueeImageRGB = CImg<unsigned char>(marqueeImage.get_shared_channels(0, 2));
|
||||
// Only alpha channel for the image.
|
||||
marqueeImageAlpha = CImg<unsigned char>(marqueeImage.get_shared_channel(3));
|
||||
}
|
||||
|
@ -427,17 +425,17 @@ bool MiximageGenerator::generateImage()
|
|||
|
||||
std::vector<unsigned char> boxVector(fileWidth * fileHeight * 4);
|
||||
|
||||
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&boxVector.at(0)), boxFile,
|
||||
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
||||
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&boxVector.at(0)), boxFile, filePitch,
|
||||
32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
||||
|
||||
boxImage = CImg<unsigned char>(FreeImage_GetWidth(boxFile),
|
||||
FreeImage_GetHeight(boxFile), 1, 4);
|
||||
boxImage =
|
||||
CImg<unsigned char>(FreeImage_GetWidth(boxFile), FreeImage_GetHeight(boxFile), 1, 4);
|
||||
|
||||
Utils::CImg::convertRGBAToCImg(boxVector, boxImage);
|
||||
Utils::CImg::removeTransparentPadding(boxImage);
|
||||
|
||||
float scaleFactor = static_cast<float>(boxTargetHeight) /
|
||||
static_cast<float>(boxImage.height());
|
||||
float scaleFactor =
|
||||
static_cast<float>(boxTargetHeight) / static_cast<float>(boxImage.height());
|
||||
unsigned int width = static_cast<int>(static_cast<float>(boxImage.width()) * scaleFactor);
|
||||
unsigned int targetWidth = 0;
|
||||
|
||||
|
@ -464,7 +462,7 @@ bool MiximageGenerator::generateImage()
|
|||
yPosBox = canvasImage.height() - boxImage.height();
|
||||
|
||||
// Only RGB channels for the image.
|
||||
boxImageRGB = CImg<unsigned char>(boxImage.get_shared_channels(0,2));
|
||||
boxImageRGB = CImg<unsigned char>(boxImage.get_shared_channels(0, 2));
|
||||
// Only alpha channel for the image.
|
||||
boxImageAlpha = CImg<unsigned char>(boxImage.get_shared_channel(3));
|
||||
}
|
||||
|
@ -478,20 +476,15 @@ bool MiximageGenerator::generateImage()
|
|||
sampleFrameColor(screenshotImage, frameColor);
|
||||
|
||||
// Upper / lower frame.
|
||||
frameImage.draw_rectangle(
|
||||
xPosScreenshot + 2,
|
||||
yPosScreenshot - screenshotFrameWidth,
|
||||
frameImage.draw_rectangle(xPosScreenshot + 2, yPosScreenshot - screenshotFrameWidth,
|
||||
xPosScreenshot + screenshotWidth - 2,
|
||||
yPosScreenshot + screenshotHeight + screenshotFrameWidth - 1,
|
||||
frameColor);
|
||||
|
||||
// Left / right frame.
|
||||
frameImage.draw_rectangle(
|
||||
xPosScreenshot - screenshotFrameWidth,
|
||||
yPosScreenshot + 2,
|
||||
frameImage.draw_rectangle(xPosScreenshot - screenshotFrameWidth, yPosScreenshot + 2,
|
||||
xPosScreenshot + screenshotWidth + screenshotFrameWidth - 1,
|
||||
yPosScreenshot + screenshotHeight - 2,
|
||||
frameColor);
|
||||
yPosScreenshot + screenshotHeight - 2, frameColor);
|
||||
|
||||
// We draw circles in order to get rounded corners for the frame.
|
||||
const unsigned int circleRadius = 8 * resolutionMultiplier;
|
||||
|
@ -505,10 +498,12 @@ bool MiximageGenerator::generateImage()
|
|||
yPosScreenshot + circleOffset, circleRadius, frameColor);
|
||||
// Lower right corner.
|
||||
frameImage.draw_circle(xPosScreenshot + screenshotWidth - circleOffset - 1,
|
||||
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius, frameColor);
|
||||
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius,
|
||||
frameColor);
|
||||
// Lower left corner.
|
||||
frameImage.draw_circle(xPosScreenshot + circleOffset,
|
||||
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius, frameColor);
|
||||
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius,
|
||||
frameColor);
|
||||
|
||||
CImg<unsigned char> frameImageRGB(frameImage.get_shared_channels(0, 2));
|
||||
|
||||
|
@ -516,8 +511,8 @@ bool MiximageGenerator::generateImage()
|
|||
canvasImage.draw_image(xPosScreenshot, yPosScreenshot, screenshotImage);
|
||||
|
||||
if (mMarquee)
|
||||
canvasImage.draw_image(xPosMarquee, yPosMarquee, marqueeImageRGB,
|
||||
marqueeImageAlpha, 1, 255);
|
||||
canvasImage.draw_image(xPosMarquee, yPosMarquee, marqueeImageRGB, marqueeImageAlpha, 1,
|
||||
255);
|
||||
if (mBox3D || mCover)
|
||||
canvasImage.draw_image(xPosBox, yPosBox, boxImageRGB, boxImageAlpha, 1, 255);
|
||||
|
||||
|
@ -531,12 +526,13 @@ bool MiximageGenerator::generateImage()
|
|||
canvasImage.height(), canvasImage.width() * 4, 32,
|
||||
FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE);
|
||||
|
||||
#if defined(_WIN64)
|
||||
bool savedImage = (FreeImage_SaveU(FIF_PNG, mixImage,
|
||||
#if defined(_WIN64)
|
||||
bool savedImage =
|
||||
(FreeImage_SaveU(FIF_PNG, mixImage,
|
||||
Utils::String::stringToWideString(getSavePath()).c_str()) != 0);
|
||||
#else
|
||||
#else
|
||||
bool savedImage = (FreeImage_Save(FIF_PNG, mixImage, getSavePath().c_str()) != 0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!savedImage) {
|
||||
LOG(LogError) << "Couldn't save miximage, permission problems or disk full?";
|
||||
|
@ -555,7 +551,9 @@ bool MiximageGenerator::generateImage()
|
|||
}
|
||||
|
||||
void MiximageGenerator::calculateMarqueeSize(const unsigned int& targetWidth,
|
||||
const unsigned int& targetHeight, unsigned int& width, unsigned int& height)
|
||||
const unsigned int& targetHeight,
|
||||
unsigned int& width,
|
||||
unsigned int& height)
|
||||
{
|
||||
unsigned int adjustedTargetWidth = 0;
|
||||
float widthModifier = 0.5f;
|
||||
|
@ -572,8 +570,8 @@ void MiximageGenerator::calculateMarqueeSize(const unsigned int& targetWidth,
|
|||
if (widthRatio >= 4)
|
||||
widthModifier += Math::clamp(widthRatio / 40.0f, 0.0f, 0.3f);
|
||||
|
||||
adjustedTargetWidth = static_cast<unsigned int>(
|
||||
static_cast<float>(targetWidth) * widthModifier);
|
||||
adjustedTargetWidth =
|
||||
static_cast<unsigned int>(static_cast<float>(targetWidth) * widthModifier);
|
||||
scaleFactor = static_cast<float>(adjustedTargetWidth) / static_cast<float>(width);
|
||||
|
||||
// For really tall and narrow images, we may have exceeded the target height.
|
||||
|
@ -627,7 +625,7 @@ void MiximageGenerator::sampleFrameColor(CImg<unsigned char>& screenshotImage,
|
|||
unsigned char blueC = Math::clamp(static_cast<int>(blueLine / 255), 0, 255);
|
||||
|
||||
// Convert to the HSL color space to be able to modify saturation and lightness.
|
||||
CImg<float> colorHSL = CImg<>(1,1,1,3).fill(redC, greenC, blueC).RGBtoHSL();
|
||||
CImg<float> colorHSL = CImg<>(1, 1, 1, 3).fill(redC, greenC, blueC).RGBtoHSL();
|
||||
|
||||
float hue = colorHSL(0, 0, 0, 0);
|
||||
float saturation = colorHSL(0, 0, 0, 1);
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#ifndef ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
||||
#define ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
||||
|
||||
#include "utils/CImgUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "utils/CImgUtil.h"
|
||||
|
||||
#include <FreeImage.h>
|
||||
#include <future>
|
||||
|
@ -29,8 +29,10 @@ public:
|
|||
|
||||
private:
|
||||
bool generateImage();
|
||||
void calculateMarqueeSize(const unsigned int& targetWidth, const unsigned int& targetHeight,
|
||||
unsigned int& width, unsigned int& height);
|
||||
void calculateMarqueeSize(const unsigned int& targetWidth,
|
||||
const unsigned int& targetHeight,
|
||||
unsigned int& width,
|
||||
unsigned int& height);
|
||||
void sampleFrameColor(CImg<unsigned char>& screenshotImage, unsigned char (&frameColor)[4]);
|
||||
|
||||
std::string getSavePath();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
namespace PlatformIds
|
||||
{
|
||||
// clang-format off
|
||||
std::vector<std::string> platformNames = {
|
||||
"unknown", // Nothing set.
|
||||
|
||||
|
@ -132,6 +133,7 @@ namespace PlatformIds
|
|||
"ignore", // Do not allow scraping for this system.
|
||||
"invalid"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
PlatformId getPlatformId(const std::string& str)
|
||||
{
|
||||
|
@ -148,6 +150,8 @@ namespace PlatformIds
|
|||
|
||||
const std::string getPlatformName(PlatformId id)
|
||||
{
|
||||
// Return the platform name.
|
||||
return platformNames[id];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PlatformIds
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace PlatformIds
|
|||
|
||||
PlatformId getPlatformId(const std::string& str);
|
||||
const std::string getPlatformName(PlatformId id);
|
||||
}
|
||||
|
||||
} // namespace PlatformIds
|
||||
|
||||
#endif // ES_APP_PLATFORM_ID_H
|
||||
|
|
|
@ -11,12 +11,6 @@
|
|||
|
||||
#include "SystemData.h"
|
||||
|
||||
#include "resources/ResourceManager.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "FileSorts.h"
|
||||
|
@ -25,6 +19,12 @@
|
|||
#include "Platform.h"
|
||||
#include "Settings.h"
|
||||
#include "ThemeData.h"
|
||||
#include "resources/ResourceManager.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <pugixml.hpp>
|
||||
|
@ -39,10 +39,6 @@ FindRules::FindRules()
|
|||
loadFindRules();
|
||||
}
|
||||
|
||||
FindRules::~FindRules()
|
||||
{
|
||||
}
|
||||
|
||||
void FindRules::loadFindRules()
|
||||
{
|
||||
std::string customSystemsDirectory =
|
||||
|
@ -54,16 +50,16 @@ void FindRules::loadFindRules()
|
|||
LOG(LogInfo) << "Found custom find rules configuration file";
|
||||
}
|
||||
else {
|
||||
#if defined(_WIN64)
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/windows/es_find_rules.xml", false);
|
||||
#elif defined(__APPLE__)
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/macos/es_find_rules.xml", false);
|
||||
#else
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/unix/es_find_rules.xml", false);
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
path = ResourceManager::getInstance()->getResourcePath(
|
||||
":/systems/windows/es_find_rules.xml", false);
|
||||
#elif defined(__APPLE__)
|
||||
path = ResourceManager::getInstance()->getResourcePath(":/systems/macos/es_find_rules.xml",
|
||||
false);
|
||||
#else
|
||||
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_find_rules.xml",
|
||||
false);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (path == "") {
|
||||
|
@ -74,11 +70,11 @@ void FindRules::loadFindRules()
|
|||
LOG(LogInfo) << "Parsing find rules configuration file \"" << path << "\"...";
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!res) {
|
||||
LOG(LogError) << "Couldn't parse es_find_rules.xml: " << res.description();
|
||||
|
@ -104,25 +100,25 @@ void FindRules::loadFindRules()
|
|||
continue;
|
||||
}
|
||||
if (mEmulators.find(emulatorName) != mEmulators.end()) {
|
||||
LOG(LogWarning) << "Found repeating emulator tag \"" << emulatorName <<
|
||||
"\", skipping entry";
|
||||
LOG(LogWarning) << "Found repeating emulator tag \"" << emulatorName
|
||||
<< "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
for (pugi::xml_node rule = emulator.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
||||
std::string ruleType = rule.attribute("type").as_string();
|
||||
if (ruleType.empty()) {
|
||||
LOG(LogWarning) << "Found rule tag without type attribute for emulator \"" <<
|
||||
emulatorName << "\", skipping entry";
|
||||
LOG(LogWarning) << "Found rule tag without type attribute for emulator \""
|
||||
<< emulatorName << "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
if (ruleType != "winregistrypath" && ruleType != "systempath" &&
|
||||
ruleType != "staticpath") {
|
||||
#else
|
||||
#else
|
||||
if (ruleType != "systempath" && ruleType != "staticpath") {
|
||||
#endif
|
||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType <<
|
||||
"\" for emulator \"" << emulatorName << "\", skipping entry";
|
||||
#endif
|
||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType << "\" for emulator \""
|
||||
<< emulatorName << "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
for (pugi::xml_node entry = rule.child("entry"); entry;
|
||||
|
@ -132,42 +128,40 @@ void FindRules::loadFindRules()
|
|||
emulatorRules.systemPaths.push_back(entryValue);
|
||||
else if (ruleType == "staticpath")
|
||||
emulatorRules.staticPaths.push_back(entryValue);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
else if (ruleType == "winregistrypath")
|
||||
emulatorRules.winRegistryPaths.push_back(entryValue);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
mEmulators[emulatorName] = emulatorRules;
|
||||
emulatorRules.systemPaths.clear();
|
||||
emulatorRules.staticPaths.clear();
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
emulatorRules.winRegistryPaths.clear();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
for (pugi::xml_node core = ruleList.child("core"); core;
|
||||
core = core.next_sibling("core")) {
|
||||
for (pugi::xml_node core = ruleList.child("core"); core; core = core.next_sibling("core")) {
|
||||
std::string coreName = core.attribute("name").as_string();
|
||||
if (coreName.empty()) {
|
||||
LOG(LogWarning) << "Found core tag without name attribute, skipping entry";
|
||||
continue;
|
||||
}
|
||||
if (mCores.find(coreName) != mCores.end()) {
|
||||
LOG(LogWarning) << "Found repeating core tag \"" << coreName <<
|
||||
"\", skipping entry";
|
||||
LOG(LogWarning) << "Found repeating core tag \"" << coreName << "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
for (pugi::xml_node rule = core.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
||||
std::string ruleType = rule.attribute("type").as_string();
|
||||
if (ruleType.empty()) {
|
||||
LOG(LogWarning) << "Found rule tag without type attribute for core \"" <<
|
||||
coreName << "\", skipping entry";
|
||||
LOG(LogWarning) << "Found rule tag without type attribute for core \"" << coreName
|
||||
<< "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
if (ruleType != "corepath") {
|
||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType <<
|
||||
"\" for core \"" << coreName << "\", skipping entry";
|
||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType << "\" for core \""
|
||||
<< coreName << "\", skipping entry";
|
||||
continue;
|
||||
}
|
||||
for (pugi::xml_node entry = rule.child("entry"); entry;
|
||||
|
@ -182,23 +176,22 @@ void FindRules::loadFindRules()
|
|||
}
|
||||
}
|
||||
|
||||
SystemData::SystemData(
|
||||
const std::string& name,
|
||||
SystemData::SystemData(const std::string& name,
|
||||
const std::string& fullName,
|
||||
SystemEnvironmentData* envData,
|
||||
const std::string& themeFolder,
|
||||
bool CollectionSystem,
|
||||
bool CustomCollectionSystem)
|
||||
: mName(name),
|
||||
mFullName(fullName),
|
||||
mEnvData(envData),
|
||||
mThemeFolder(themeFolder),
|
||||
mIsCollectionSystem(CollectionSystem),
|
||||
mIsCustomCollectionSystem(CustomCollectionSystem),
|
||||
mIsGroupedCustomCollectionSystem(false),
|
||||
mIsGameSystem(true),
|
||||
mScrapeFlag(false),
|
||||
mPlaceholder(nullptr)
|
||||
: mName(name)
|
||||
, mFullName(fullName)
|
||||
, mEnvData(envData)
|
||||
, mThemeFolder(themeFolder)
|
||||
, mIsCollectionSystem(CollectionSystem)
|
||||
, mIsCustomCollectionSystem(CustomCollectionSystem)
|
||||
, mIsGroupedCustomCollectionSystem(false)
|
||||
, mIsGameSystem(true)
|
||||
, mScrapeFlag(false)
|
||||
, mPlaceholder(nullptr)
|
||||
{
|
||||
mFilterIndex = new FileFilterIndex();
|
||||
|
||||
|
@ -289,9 +282,9 @@ bool SystemData::populateFolder(FileData* folder)
|
|||
|
||||
// Skip hidden files and folders.
|
||||
if (!showHiddenFiles && Utils::FileSystem::isHidden(filePath)) {
|
||||
LOG(LogDebug) << "SystemData::populateFolder(): Skipping hidden " <<
|
||||
(Utils::FileSystem::isDirectory(filePath) ? "directory \"" : "file \"") <<
|
||||
filePath << "\"";
|
||||
LOG(LogDebug) << "SystemData::populateFolder(): Skipping hidden "
|
||||
<< (Utils::FileSystem::isDirectory(filePath) ? "directory \"" : "file \"")
|
||||
<< filePath << "\"";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -327,7 +320,8 @@ bool SystemData::populateFolder(FileData* folder)
|
|||
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(filePath);
|
||||
const std::string canonicalStartPath =
|
||||
Utils::FileSystem::getCanonicalPath(mEnvData->mStartPath);
|
||||
const std::string combinedPath = mEnvData->mStartPath +
|
||||
const std::string combinedPath =
|
||||
mEnvData->mStartPath +
|
||||
canonicalPath.substr(canonicalStartPath.size(),
|
||||
canonicalStartPath.size() - canonicalPath.size());
|
||||
if (filePath.find(combinedPath) == 0) {
|
||||
|
@ -335,6 +329,7 @@ bool SystemData::populateFolder(FileData* folder)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this);
|
||||
populateFolder(newFolder);
|
||||
|
||||
|
@ -352,16 +347,14 @@ void SystemData::indexAllGameFilters(const FileData* folder)
|
|||
{
|
||||
const std::vector<FileData*>& children = folder->getChildren();
|
||||
|
||||
for (std::vector<FileData*>::const_iterator it = children.cbegin();
|
||||
for (std::vector<FileData*>::const_iterator it = children.cbegin(); // Line break.
|
||||
it != children.cend(); it++) {
|
||||
switch ((*it)->getType()) {
|
||||
case GAME: {
|
||||
case GAME:
|
||||
mFilterIndex->addToIndex(*it);
|
||||
}
|
||||
break;
|
||||
case FOLDER: {
|
||||
case FOLDER:
|
||||
indexAllGameFilters(*it);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -400,11 +393,11 @@ bool SystemData::loadConfig()
|
|||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!res) {
|
||||
LOG(LogError) << "Couldn't parse es_systems.xml: " << res.description();
|
||||
|
@ -436,21 +429,21 @@ bool SystemData::loadConfig()
|
|||
// the ROM path configured as ROMDirectory in es_settings.xml. If it's set to ""
|
||||
// in this configuration file, the default hardcoded path $HOME/ROMs/ will be used.
|
||||
path = Utils::String::replace(path, "%ROMPATH%", rompath);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
path = Utils::String::replace(path, "\\", "/");
|
||||
#endif
|
||||
#endif
|
||||
path = Utils::String::replace(path, "//", "/");
|
||||
|
||||
// Check that the ROM directory for the system is valid or otherwise abort the processing.
|
||||
if (!Utils::FileSystem::exists(path)) {
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
||||
name << "\" as the defined ROM directory \"" << path << "\" does not exist";
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||
<< "\" as the defined ROM directory \"" << path << "\" does not exist";
|
||||
continue;
|
||||
}
|
||||
if (!Utils::FileSystem::isDirectory(path)) {
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
||||
name << "\" as the defined ROM directory \"" << path <<
|
||||
"\" is not actually a directory";
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||
<< "\" as the defined ROM directory \"" << path
|
||||
<< "\" is not actually a directory";
|
||||
continue;
|
||||
}
|
||||
if (Utils::FileSystem::isSymlink(path)) {
|
||||
|
@ -458,9 +451,9 @@ bool SystemData::loadConfig()
|
|||
// as that would lead to an infite loop, meaning the application would never start.
|
||||
std::string resolvedRompath = Utils::FileSystem::getCanonicalPath(rompath);
|
||||
if (resolvedRompath.find(Utils::FileSystem::getCanonicalPath(path)) == 0) {
|
||||
LOG(LogWarning) << "Skipping system \"" << name <<
|
||||
"\" as the defined ROM directory \"" << path <<
|
||||
"\" is an infinitely recursive symlink";
|
||||
LOG(LogWarning) << "Skipping system \"" << name
|
||||
<< "\" as the defined ROM directory \"" << path
|
||||
<< "\" is an infinitely recursive symlink";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -489,8 +482,8 @@ bool SystemData::loadConfig()
|
|||
// If there's a platform entry defined but it does not match the list of supported
|
||||
// platforms, then generate a warning.
|
||||
if (str != "" && platformId == PlatformIds::PLATFORM_UNKNOWN)
|
||||
LOG(LogWarning) << "Unknown platform \"" << str << "\" defined for system \"" <<
|
||||
name << "\"";
|
||||
LOG(LogWarning) << "Unknown platform \"" << str << "\" defined for system \""
|
||||
<< name << "\"";
|
||||
else if (platformId != PlatformIds::PLATFORM_UNKNOWN)
|
||||
platformIds.push_back(platformId);
|
||||
}
|
||||
|
@ -501,12 +494,13 @@ bool SystemData::loadConfig()
|
|||
// Validate.
|
||||
|
||||
if (name.empty()) {
|
||||
LOG(LogError) <<
|
||||
"A system in the es_systems.xml file has no name defined, skipping entry";
|
||||
LOG(LogError)
|
||||
<< "A system in the es_systems.xml file has no name defined, skipping entry";
|
||||
continue;
|
||||
}
|
||||
else if (fullname.empty() || path.empty() || extensions.empty() || cmd.empty()) {
|
||||
LOG(LogError) << "System \"" << name << "\" is missing the fullname, path, "
|
||||
LOG(LogError) << "System \"" << name
|
||||
<< "\" is missing the fullname, path, "
|
||||
"extension, or command tag, skipping entry";
|
||||
continue;
|
||||
}
|
||||
|
@ -514,13 +508,13 @@ bool SystemData::loadConfig()
|
|||
// Convert path to generic directory seperators.
|
||||
path = Utils::FileSystem::getGenericPath(path);
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
if (!Settings::getInstance()->getBool("ShowHiddenFiles") &&
|
||||
Utils::FileSystem::isHidden(path)) {
|
||||
LOG(LogWarning) << "Skipping hidden ROM folder \"" << path << "\"";
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Create the system runtime environment data.
|
||||
SystemEnvironmentData* envData = new SystemEnvironmentData;
|
||||
|
@ -535,8 +529,7 @@ bool SystemData::loadConfig()
|
|||
// If the option to show hidden games has been disabled, then check whether all
|
||||
// games for the system are hidden. That will flag the system as empty.
|
||||
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
||||
std::vector<FileData*> recursiveGames =
|
||||
newSys->getRootFolder()->getChildrenRecursive();
|
||||
std::vector<FileData*> recursiveGames = newSys->getRootFolder()->getChildrenRecursive();
|
||||
onlyHidden = true;
|
||||
for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) {
|
||||
if ((*it)->getType() != FOLDER) {
|
||||
|
@ -548,8 +541,8 @@ bool SystemData::loadConfig()
|
|||
}
|
||||
|
||||
if (newSys->getRootFolder()->getChildrenByFilename().size() == 0 || onlyHidden) {
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
||||
name << "\" as no files matched any of the defined file extensions";
|
||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||
<< "\" as no files matched any of the defined file extensions";
|
||||
delete newSys;
|
||||
}
|
||||
else {
|
||||
|
@ -559,8 +552,7 @@ bool SystemData::loadConfig()
|
|||
|
||||
// Sort systems by their full names.
|
||||
std::sort(std::begin(sSystemVector), std::end(sSystemVector),
|
||||
[](SystemData* a, SystemData* b) {
|
||||
return a->getFullName() < b->getFullName(); });
|
||||
[](SystemData* a, SystemData* b) { return a->getFullName() < b->getFullName(); });
|
||||
|
||||
// Don't load any collections if there are no systems available.
|
||||
if (sSystemVector.size() > 0)
|
||||
|
@ -580,12 +572,12 @@ void SystemData::deleteSystems()
|
|||
std::string SystemData::getConfigPath(bool legacyWarning)
|
||||
{
|
||||
if (legacyWarning) {
|
||||
std::string legacyConfigFile = Utils::FileSystem::getHomePath() +
|
||||
"/.emulationstation/es_systems.cfg";
|
||||
std::string legacyConfigFile =
|
||||
Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
||||
|
||||
if (Utils::FileSystem::exists(legacyConfigFile)) {
|
||||
LOG(LogInfo) << "Found legacy systems configuration file \"" << legacyConfigFile <<
|
||||
"\", to retain your customizations move it to "
|
||||
LOG(LogInfo) << "Found legacy systems configuration file \"" << legacyConfigFile
|
||||
<< "\", to retain your customizations move it to "
|
||||
"\"custom_systems/es_systems.xml\" or otherwise delete the file";
|
||||
}
|
||||
}
|
||||
|
@ -608,16 +600,14 @@ std::string SystemData::getConfigPath(bool legacyWarning)
|
|||
return path;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/windows/es_systems.xml", true);
|
||||
#elif defined(__APPLE__)
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/macos/es_systems.xml", true);
|
||||
#else
|
||||
path = ResourceManager::getInstance()->
|
||||
getResourcePath(":/systems/unix/es_systems.xml", true);
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
path =
|
||||
ResourceManager::getInstance()->getResourcePath(":/systems/windows/es_systems.xml", true);
|
||||
#elif defined(__APPLE__)
|
||||
path = ResourceManager::getInstance()->getResourcePath(":/systems/macos/es_systems.xml", true);
|
||||
#else
|
||||
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_systems.xml", true);
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
@ -635,8 +625,8 @@ bool SystemData::createSystemDirectories()
|
|||
LOG(LogInfo) << "Generating ROM directory structure...";
|
||||
|
||||
if (Utils::FileSystem::exists(rompath) && Utils::FileSystem::isRegularFile(rompath)) {
|
||||
LOG(LogError) <<
|
||||
"Requested ROM directory \"" << rompath << "\" is actually a file, aborting";
|
||||
LOG(LogError) << "Requested ROM directory \"" << rompath
|
||||
<< "\" is actually a file, aborting";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -654,11 +644,11 @@ bool SystemData::createSystemDirectories()
|
|||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
||||
|
||||
pugi::xml_document doc;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!res) {
|
||||
LOG(LogError) << "Couldn't parse es_systems.xml";
|
||||
|
@ -701,7 +691,8 @@ bool SystemData::createSystemDirectories()
|
|||
// Check that the %ROMPATH% variable is actually used for the path element.
|
||||
// If not, skip the system.
|
||||
if (path.find("%ROMPATH%") != 0) {
|
||||
LOG(LogWarning) << "The path element for system \"" << name << "\" does not "
|
||||
LOG(LogWarning) << "The path element for system \"" << name
|
||||
<< "\" does not "
|
||||
"utilize the %ROMPATH% variable, skipping entry";
|
||||
continue;
|
||||
}
|
||||
|
@ -711,14 +702,13 @@ bool SystemData::createSystemDirectories()
|
|||
|
||||
// Trim any leading directory separator characters.
|
||||
systemDir.erase(systemDir.begin(),
|
||||
std::find_if(systemDir.begin(), systemDir.end(), [](char c) {
|
||||
return c != '/' && c != '\\';
|
||||
}));
|
||||
std::find_if(systemDir.begin(), systemDir.end(),
|
||||
[](char c) { return c != '/' && c != '\\'; }));
|
||||
|
||||
if (!Utils::FileSystem::exists(rompath + systemDir)) {
|
||||
if (!Utils::FileSystem::createDirectory(rompath + systemDir)) {
|
||||
LOG(LogError) << "Couldn't create system directory \"" << systemDir <<
|
||||
"\", permission problems or disk full?";
|
||||
LOG(LogError) << "Couldn't create system directory \"" << systemDir
|
||||
<< "\", permission problems or disk full?";
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -739,16 +729,17 @@ bool SystemData::createSystemDirectories()
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
systemInfoFile.open(Utils::String::stringToWideString(rompath +
|
||||
systemDir + systemInfoFileName).c_str());
|
||||
#else
|
||||
#if defined(_WIN64)
|
||||
systemInfoFile.open(
|
||||
Utils::String::stringToWideString(rompath + systemDir + systemInfoFileName).c_str());
|
||||
#else
|
||||
systemInfoFile.open(rompath + systemDir + systemInfoFileName);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (systemInfoFile.fail()) {
|
||||
LOG(LogError) << "Couldn't create system information file \"" << rompath +
|
||||
systemDir + systemInfoFileName << "\", permission problems or disk full?";
|
||||
LOG(LogError) << "Couldn't create system information file \""
|
||||
<< rompath + systemDir + systemInfoFileName
|
||||
<< "\", permission problems or disk full?";
|
||||
systemInfoFile.close();
|
||||
return true;
|
||||
}
|
||||
|
@ -770,12 +761,12 @@ bool SystemData::createSystemDirectories()
|
|||
systemsVector.push_back(systemDir + ": " + fullname);
|
||||
|
||||
if (replaceInfoFile) {
|
||||
LOG(LogInfo) << "Replaced existing system information file \"" <<
|
||||
rompath + systemDir + systemInfoFileName << "\"";
|
||||
LOG(LogInfo) << "Replaced existing system information file \""
|
||||
<< rompath + systemDir + systemInfoFileName << "\"";
|
||||
}
|
||||
else {
|
||||
LOG(LogInfo) << "Created system information file \"" <<
|
||||
rompath + systemDir + systemInfoFileName << "\"";
|
||||
LOG(LogInfo) << "Created system information file \""
|
||||
<< rompath + systemDir + systemInfoFileName << "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,11 +784,11 @@ bool SystemData::createSystemDirectories()
|
|||
|
||||
if (systemsFileSuccess) {
|
||||
std::ofstream systemsFile;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
systemsFile.open(Utils::String::stringToWideString(rompath + systemsFileName).c_str());
|
||||
#else
|
||||
#else
|
||||
systemsFile.open(rompath + systemsFileName);
|
||||
#endif
|
||||
#endif
|
||||
if (systemsFile.fail()) {
|
||||
systemsFileSuccess = false;
|
||||
}
|
||||
|
@ -867,8 +858,8 @@ std::string SystemData::getGamelistPath(bool forWrite) const
|
|||
if (Utils::FileSystem::exists(filePath))
|
||||
return filePath;
|
||||
|
||||
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" +
|
||||
mName + "/gamelist.xml";
|
||||
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" + mName +
|
||||
"/gamelist.xml";
|
||||
|
||||
// Make sure the directory exists if we're going to write to it,
|
||||
// or crashes will happen.
|
||||
|
@ -899,17 +890,12 @@ std::string SystemData::getThemePath() const
|
|||
return localThemePath;
|
||||
|
||||
// Not system theme, try default system theme in theme set.
|
||||
localThemePath = Utils::FileSystem::getParent(Utils::FileSystem::getParent(localThemePath)) +
|
||||
"/theme.xml";
|
||||
localThemePath =
|
||||
Utils::FileSystem::getParent(Utils::FileSystem::getParent(localThemePath)) + "/theme.xml";
|
||||
|
||||
return localThemePath;
|
||||
}
|
||||
|
||||
bool SystemData::hasGamelist() const
|
||||
{
|
||||
return (Utils::FileSystem::exists(getGamelistPath(false)));
|
||||
}
|
||||
|
||||
SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
||||
{
|
||||
unsigned int total = 0;
|
||||
|
@ -927,7 +913,7 @@ SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
|||
// Get a random number in range.
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::mt19937 engine { randDev() };
|
||||
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
||||
int target = uniform_dist(engine);
|
||||
|
||||
|
@ -942,8 +928,7 @@ SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (randomSystem == currentSystem);
|
||||
} while (randomSystem == currentSystem);
|
||||
|
||||
return randomSystem;
|
||||
}
|
||||
|
@ -956,13 +941,17 @@ FileData* SystemData::getRandomGame(const FileData* currentGame)
|
|||
|
||||
// If we're in the custom collection group list, then get the list of collections,
|
||||
// otherwise get a list of all the folder and file entries in the view.
|
||||
if (currentGame && currentGame->getType() == FOLDER && currentGame->
|
||||
getSystem()->isGroupedCustomCollection()) {
|
||||
if (currentGame && currentGame->getType() == FOLDER &&
|
||||
currentGame->getSystem()->isGroupedCustomCollection()) {
|
||||
gameList = mRootFolder->getParent()->getChildrenListToDisplay();
|
||||
}
|
||||
else {
|
||||
gameList = ViewController::get()->getGameListView(mRootFolder->
|
||||
getSystem()).get()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||
gameList = ViewController::get()
|
||||
->getGameListView(mRootFolder->getSystem())
|
||||
.get()
|
||||
->getCursor()
|
||||
->getParent()
|
||||
->getChildrenListToDisplay();
|
||||
}
|
||||
|
||||
if (gameList.size() > 0 && gameList.front()->getParent()->getOnlyFoldersFlag())
|
||||
|
@ -1003,11 +992,10 @@ FileData* SystemData::getRandomGame(const FileData* currentGame)
|
|||
// Get a random number in range.
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::mt19937 engine { randDev() };
|
||||
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
||||
target = uniform_dist(engine);
|
||||
}
|
||||
while (currentGame && gameList.at(target) == currentGame);
|
||||
} while (currentGame && gameList.at(target) == currentGame);
|
||||
|
||||
return gameList.at(target);
|
||||
}
|
||||
|
@ -1020,23 +1008,25 @@ void SystemData::sortSystem(bool reloadGamelist, bool jumpToFirstRow)
|
|||
bool favoritesSorting;
|
||||
|
||||
if (this->isCustomCollection() ||
|
||||
(this->isCollection() && this->getFullName() == "collections"))
|
||||
(this->isCollection() && this->getFullName() == "collections")) {
|
||||
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
||||
else
|
||||
}
|
||||
else {
|
||||
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||
}
|
||||
|
||||
FileData* rootFolder = getRootFolder();
|
||||
// Assign the sort type to all grouped custom collections.
|
||||
if (mIsCollectionSystem && mFullName == "collections") {
|
||||
for (auto it = rootFolder->getChildren().begin();
|
||||
for (auto it = rootFolder->getChildren().begin(); // Line break.
|
||||
it != rootFolder->getChildren().end(); it++) {
|
||||
setupSystemSortType((*it)->getSystem()->getRootFolder());
|
||||
}
|
||||
}
|
||||
setupSystemSortType(rootFolder);
|
||||
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(
|
||||
rootFolder->getSortTypeString()), favoritesSorting);
|
||||
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||
favoritesSorting);
|
||||
|
||||
if (reloadGamelist)
|
||||
ViewController::get()->reloadGameListView(this, false);
|
||||
|
@ -1079,7 +1069,8 @@ void SystemData::loadTheme()
|
|||
}
|
||||
}
|
||||
|
||||
void SystemData::writeMetaData() {
|
||||
void SystemData::writeMetaData()
|
||||
{
|
||||
if (Settings::getInstance()->getBool("IgnoreGamelist") || mIsCollectionSystem)
|
||||
return;
|
||||
|
||||
|
@ -1087,7 +1078,8 @@ void SystemData::writeMetaData() {
|
|||
updateGamelist(this);
|
||||
}
|
||||
|
||||
void SystemData::onMetaDataSavePoint() {
|
||||
void SystemData::onMetaDataSavePoint()
|
||||
{
|
||||
if (Settings::getInstance()->getString("SaveGamelistsMode") != "always")
|
||||
return;
|
||||
|
||||
|
@ -1101,14 +1093,14 @@ void SystemData::setupSystemSortType(FileData* mRootFolder)
|
|||
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||
if (FileSorts::SortTypes.at(i).description ==
|
||||
Settings::getInstance()->getString("DefaultSortOrder")) {
|
||||
mRootFolder->setSortTypeString(Settings::getInstance()->
|
||||
getString("DefaultSortOrder"));
|
||||
mRootFolder->setSortTypeString(
|
||||
Settings::getInstance()->getString("DefaultSortOrder"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no valid sort type was defined in the configuration file, set to default sorting.
|
||||
if (mRootFolder->getSortTypeString() == "")
|
||||
mRootFolder->setSortTypeString(Settings::getInstance()->
|
||||
getDefaultString("DefaultSortOrder"));
|
||||
mRootFolder->setSortTypeString(
|
||||
Settings::getInstance()->getDefaultString("DefaultSortOrder"));
|
||||
}
|
||||
|
|
|
@ -35,15 +35,14 @@ class FindRules
|
|||
{
|
||||
public:
|
||||
FindRules();
|
||||
~FindRules();
|
||||
|
||||
void loadFindRules();
|
||||
|
||||
private:
|
||||
struct EmulatorRules {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::vector<std::string> winRegistryPaths;
|
||||
#endif
|
||||
#endif
|
||||
std::vector<std::string> systemPaths;
|
||||
std::vector<std::string> staticPaths;
|
||||
};
|
||||
|
@ -61,8 +60,7 @@ private:
|
|||
class SystemData
|
||||
{
|
||||
public:
|
||||
SystemData(
|
||||
const std::string& name,
|
||||
SystemData(const std::string& name,
|
||||
const std::string& fullName,
|
||||
SystemEnvironmentData* envData,
|
||||
const std::string& themeFolder,
|
||||
|
@ -71,28 +69,32 @@ public:
|
|||
|
||||
~SystemData();
|
||||
|
||||
inline FileData* getRootFolder() const { return mRootFolder; };
|
||||
inline const std::string& getName() const { return mName; }
|
||||
inline const std::string& getFullName() const { return mFullName; }
|
||||
inline const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
||||
inline const std::vector<std::string>& getExtensions() const
|
||||
{ return mEnvData->mSearchExtensions; }
|
||||
inline const std::string& getThemeFolder() const { return mThemeFolder; }
|
||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||
inline const std::vector<PlatformIds::PlatformId>& getPlatformIds() const
|
||||
{ return mEnvData->mPlatformIds; }
|
||||
inline bool hasPlatformId(PlatformIds::PlatformId id) { if (!mEnvData) return false;
|
||||
return std::find(mEnvData->mPlatformIds.cbegin(), mEnvData->mPlatformIds.cend(), id)
|
||||
!= mEnvData->mPlatformIds.cend(); }
|
||||
FileData* getRootFolder() const { return mRootFolder; }
|
||||
const std::string& getName() const { return mName; }
|
||||
const std::string& getFullName() const { return mFullName; }
|
||||
const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
||||
const std::vector<std::string>& getExtensions() const { return mEnvData->mSearchExtensions; }
|
||||
const std::string& getThemeFolder() const { return mThemeFolder; }
|
||||
SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||
const std::vector<PlatformIds::PlatformId>& getPlatformIds() const
|
||||
{
|
||||
return mEnvData->mPlatformIds;
|
||||
}
|
||||
bool hasPlatformId(PlatformIds::PlatformId id)
|
||||
{
|
||||
if (!mEnvData)
|
||||
return false;
|
||||
return std::find(mEnvData->mPlatformIds.cbegin(), mEnvData->mPlatformIds.cend(), id) !=
|
||||
mEnvData->mPlatformIds.cend();
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
||||
const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
||||
|
||||
std::string getGamelistPath(bool forWrite) const;
|
||||
bool hasGamelist() const;
|
||||
std::string getThemePath() const;
|
||||
|
||||
std::pair<unsigned int, unsigned int> getDisplayedGameCount() const;
|
||||
bool getScrapeFlag() { return mScrapeFlag; };
|
||||
bool getScrapeFlag() { return mScrapeFlag; }
|
||||
void setScrapeFlag(bool scrapeflag) { mScrapeFlag = scrapeflag; }
|
||||
|
||||
static void deleteSystems();
|
||||
|
@ -106,16 +108,22 @@ public:
|
|||
static std::vector<SystemData*> sSystemVector;
|
||||
static std::unique_ptr<FindRules> sFindRules;
|
||||
|
||||
inline std::vector<SystemData*>::const_iterator getIterator() const
|
||||
{ return std::find(sSystemVector.cbegin(), sSystemVector.cend(), this); };
|
||||
inline std::vector<SystemData*>::const_reverse_iterator getRevIterator() const
|
||||
{ return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this); };
|
||||
inline bool isCollection() { return mIsCollectionSystem; };
|
||||
inline bool isCustomCollection() { return mIsCustomCollectionSystem; };
|
||||
inline bool isGroupedCustomCollection() { return mIsGroupedCustomCollectionSystem; };
|
||||
std::vector<SystemData*>::const_iterator getIterator() const
|
||||
{
|
||||
return std::find(sSystemVector.cbegin(), sSystemVector.cend(), this);
|
||||
}
|
||||
std::vector<SystemData*>::const_reverse_iterator getRevIterator() const
|
||||
{
|
||||
return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this);
|
||||
}
|
||||
bool isCollection() { return mIsCollectionSystem; }
|
||||
bool isCustomCollection() { return mIsCustomCollectionSystem; }
|
||||
bool isGroupedCustomCollection() { return mIsGroupedCustomCollectionSystem; }
|
||||
void setIsGroupedCustomCollection(bool isGroupedCustom)
|
||||
{ mIsGroupedCustomCollectionSystem = isGroupedCustom; };
|
||||
inline bool isGameSystem() { return mIsGameSystem; };
|
||||
{
|
||||
mIsGroupedCustomCollectionSystem = isGroupedCustom;
|
||||
};
|
||||
bool isGameSystem() { return mIsGameSystem; }
|
||||
|
||||
bool isVisible();
|
||||
|
||||
|
@ -123,14 +131,14 @@ public:
|
|||
SystemData* getPrev() const;
|
||||
static SystemData* getRandomSystem(const SystemData* currentSystem);
|
||||
FileData* getRandomGame(const FileData* currentGame = nullptr);
|
||||
FileData* getPlaceholder() { return mPlaceholder; };
|
||||
FileData* getPlaceholder() { return mPlaceholder; }
|
||||
|
||||
void sortSystem(bool reloadGamelist = true, bool jumpToFirstRow = false);
|
||||
|
||||
// Load or re-load theme.
|
||||
void loadTheme();
|
||||
|
||||
FileFilterIndex* getIndex() { return mFilterIndex; };
|
||||
FileFilterIndex* getIndex() { return mFilterIndex; }
|
||||
void onMetaDataSavePoint();
|
||||
void writeMetaData();
|
||||
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
#if defined(BUILD_VLC_PLAYER)
|
||||
#include "components/VideoVlcComponent.h"
|
||||
#endif
|
||||
#include "resources/Font.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "SystemData.h"
|
||||
#include "resources/Font.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include <random>
|
||||
#include <time.h>
|
||||
|
@ -36,24 +36,23 @@
|
|||
|
||||
#define FADE_TIME 300
|
||||
|
||||
SystemScreensaver::SystemScreensaver(
|
||||
Window* window)
|
||||
: mWindow(window),
|
||||
mState(STATE_INACTIVE),
|
||||
mImageScreensaver(nullptr),
|
||||
mVideoScreensaver(nullptr),
|
||||
mCurrentGame(nullptr),
|
||||
mPreviousGame(nullptr),
|
||||
mTimer(0),
|
||||
mMediaSwapTime(0),
|
||||
mTriggerNextGame(false),
|
||||
mHasMediaFiles(false),
|
||||
mFallbackScreensaver(false),
|
||||
mOpacity(0.0f),
|
||||
mDimValue(1.0),
|
||||
mRectangleFadeIn(50),
|
||||
mTextFadeIn(0),
|
||||
mSaturationAmount(1.0)
|
||||
SystemScreensaver::SystemScreensaver(Window* window)
|
||||
: mWindow(window)
|
||||
, mState(STATE_INACTIVE)
|
||||
, mImageScreensaver(nullptr)
|
||||
, mVideoScreensaver(nullptr)
|
||||
, mCurrentGame(nullptr)
|
||||
, mPreviousGame(nullptr)
|
||||
, mTimer(0)
|
||||
, mMediaSwapTime(0)
|
||||
, mTriggerNextGame(false)
|
||||
, mHasMediaFiles(false)
|
||||
, mFallbackScreensaver(false)
|
||||
, mOpacity(0.0f)
|
||||
, mDimValue(1.0)
|
||||
, mRectangleFadeIn(50)
|
||||
, mTextFadeIn(0)
|
||||
, mSaturationAmount(1.0)
|
||||
{
|
||||
mWindow->setScreensaver(this);
|
||||
}
|
||||
|
@ -65,21 +64,6 @@ SystemScreensaver::~SystemScreensaver()
|
|||
delete mImageScreensaver;
|
||||
}
|
||||
|
||||
bool SystemScreensaver::allowSleep()
|
||||
{
|
||||
return ((mVideoScreensaver == nullptr) && (mImageScreensaver == nullptr));
|
||||
}
|
||||
|
||||
bool SystemScreensaver::isScreensaverActive()
|
||||
{
|
||||
return (mState != STATE_INACTIVE);
|
||||
}
|
||||
|
||||
bool SystemScreensaver::isFallbackScreensaver()
|
||||
{
|
||||
return mFallbackScreensaver;
|
||||
}
|
||||
|
||||
void SystemScreensaver::startScreensaver(bool generateMediaList)
|
||||
{
|
||||
std::string path = "";
|
||||
|
@ -179,7 +163,7 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
|
|||
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo"))
|
||||
generateOverlayInfo();
|
||||
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// Create the correct type of video component.
|
||||
if (Settings::getInstance()->getBool("ScreensaverOmxPlayer"))
|
||||
mVideoScreensaver = new VideoOmxComponent(mWindow);
|
||||
|
@ -187,14 +171,14 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
|
|||
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
||||
else
|
||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||
#elif defined(BUILD_VLC_PLAYER)
|
||||
#elif defined(BUILD_VLC_PLAYER)
|
||||
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
||||
else
|
||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||
#else
|
||||
#else
|
||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mVideoScreensaver->topWindow(true);
|
||||
mVideoScreensaver->setOrigin(0.5f, 0.5f);
|
||||
|
@ -229,16 +213,17 @@ void SystemScreensaver::stopScreensaver()
|
|||
|
||||
mState = STATE_INACTIVE;
|
||||
|
||||
mDimValue = 1.0;
|
||||
mDimValue = 1.0f;
|
||||
mRectangleFadeIn = 50;
|
||||
mTextFadeIn = 0;
|
||||
mSaturationAmount = 1.0;
|
||||
mSaturationAmount = 1.0f;
|
||||
|
||||
if (mGameOverlay)
|
||||
mGameOverlay.reset();
|
||||
}
|
||||
|
||||
void SystemScreensaver::nextGame() {
|
||||
void SystemScreensaver::nextGame()
|
||||
{
|
||||
stopScreensaver();
|
||||
startScreensaver(false);
|
||||
}
|
||||
|
@ -249,8 +234,8 @@ void SystemScreensaver::launchGame()
|
|||
// Launching game
|
||||
ViewController::get()->triggerGameLaunch(mCurrentGame);
|
||||
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
||||
IGameListView* view = ViewController::get()->
|
||||
getGameListView(mCurrentGame->getSystem()).get();
|
||||
IGameListView* view =
|
||||
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
||||
view->setCursor(mCurrentGame);
|
||||
ViewController::get()->cancelViewTransitions();
|
||||
}
|
||||
|
@ -261,8 +246,8 @@ void SystemScreensaver::goToGame()
|
|||
if (mCurrentGame != nullptr) {
|
||||
// Go to the game in the gamelist view, but don't launch it.
|
||||
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
||||
IGameListView* view = ViewController::get()->
|
||||
getGameListView(mCurrentGame->getSystem()).get();
|
||||
IGameListView* view =
|
||||
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
||||
view->setCursor(mCurrentGame);
|
||||
ViewController::get()->cancelViewTransitions();
|
||||
}
|
||||
|
@ -305,20 +290,20 @@ void SystemScreensaver::renderScreensaver()
|
|||
Renderer::setMatrix(Transform4x4f::Identity());
|
||||
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
|
||||
if (mHasMediaFiles) {
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
|
||||
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
||||
#endif
|
||||
#endif
|
||||
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
|
||||
mGameOverlay) {
|
||||
if (mGameOverlayRectangleCoords.size() == 4) {
|
||||
Renderer::drawRect(mGameOverlayRectangleCoords[0],
|
||||
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
|
||||
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
|
||||
0x00000000 | mRectangleFadeIn );
|
||||
Renderer::drawRect(
|
||||
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
||||
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
||||
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
||||
}
|
||||
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 6 +
|
||||
mRectangleFadeIn / 20, 0, 170);
|
||||
mRectangleFadeIn =
|
||||
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
||||
|
||||
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
||||
if (mTextFadeIn > 50)
|
||||
|
@ -333,7 +318,7 @@ void SystemScreensaver::renderScreensaver()
|
|||
}
|
||||
else if (Settings::getInstance()->getString("ScreensaverType") == "video") {
|
||||
if (mHasMediaFiles) {
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
Renderer::shaderParameters videoParameters;
|
||||
unsigned int shaders = 0;
|
||||
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
|
||||
|
@ -341,6 +326,7 @@ void SystemScreensaver::renderScreensaver()
|
|||
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
||||
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
||||
float heightModifier = Renderer::getScreenHeightModifier();
|
||||
// clang-format off
|
||||
if (heightModifier < 1)
|
||||
videoParameters.blurPasses = 2; // Below 1080
|
||||
else if (heightModifier >= 4)
|
||||
|
@ -355,21 +341,22 @@ void SystemScreensaver::renderScreensaver()
|
|||
videoParameters.blurPasses = 3; // 1440
|
||||
else if (heightModifier >= 1)
|
||||
videoParameters.blurPasses = 2; // 1080
|
||||
// clang-format on
|
||||
}
|
||||
Renderer::shaderPostprocessing(shaders, videoParameters);
|
||||
#endif
|
||||
#endif
|
||||
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
|
||||
if (mGameOverlayRectangleCoords.size() == 4) {
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY);
|
||||
#endif
|
||||
Renderer::drawRect(mGameOverlayRectangleCoords[0],
|
||||
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
|
||||
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
|
||||
0x00000000 | mRectangleFadeIn );
|
||||
#endif
|
||||
Renderer::drawRect(
|
||||
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
||||
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
||||
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
||||
}
|
||||
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 6 +
|
||||
mRectangleFadeIn / 20, 0, 170);
|
||||
mRectangleFadeIn =
|
||||
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
||||
|
||||
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
||||
if (mTextFadeIn > 50)
|
||||
|
@ -384,7 +371,7 @@ void SystemScreensaver::renderScreensaver()
|
|||
}
|
||||
if (mFallbackScreensaver ||
|
||||
Settings::getInstance()->getString("ScreensaverType") == "dim") {
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
Renderer::shaderParameters dimParameters;
|
||||
dimParameters.fragmentDimValue = mDimValue;
|
||||
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters);
|
||||
|
@ -394,22 +381,22 @@ void SystemScreensaver::renderScreensaver()
|
|||
Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters);
|
||||
if (mSaturationAmount > 0.0)
|
||||
mSaturationAmount = Math::clamp(mSaturationAmount - 0.035f, 0.0f, 1.0f);
|
||||
#else
|
||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
|
||||
Renderer::getScreenHeight(), 0x000000A0, 0x000000A0);
|
||||
#endif
|
||||
#else
|
||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
||||
0x000000A0, 0x000000A0);
|
||||
#endif
|
||||
}
|
||||
else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
Renderer::shaderParameters blackParameters;
|
||||
blackParameters.fragmentDimValue = mDimValue;
|
||||
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
|
||||
if (mDimValue > 0.0)
|
||||
mDimValue = Math::clamp(mDimValue - 0.045f, 0.0f, 1.0f);
|
||||
#else
|
||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
|
||||
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
|
||||
#endif
|
||||
#else
|
||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
||||
0x000000FF, 0x000000FF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,7 +445,7 @@ void SystemScreensaver::update(int deltaTime)
|
|||
|
||||
void SystemScreensaver::generateImageList()
|
||||
{
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
// We only want nodes from game systems that are not collections.
|
||||
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
||||
|
@ -475,7 +462,7 @@ void SystemScreensaver::generateImageList()
|
|||
|
||||
void SystemScreensaver::generateVideoList()
|
||||
{
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
// We only want nodes from game systems that are not collections.
|
||||
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
||||
|
@ -513,8 +500,7 @@ void SystemScreensaver::generateCustomImageList()
|
|||
}
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << "Custom screensaver image directory '" <<
|
||||
imageDir << "' does not exist.";
|
||||
LOG(LogWarning) << "Custom screensaver image directory '" << imageDir << "' does not exist";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,12 +526,11 @@ void SystemScreensaver::pickRandomImage(std::string& path)
|
|||
// Get a random number in range.
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::uniform_int_distribution<int>
|
||||
uniform_dist(0, static_cast<int>(mImageFiles.size()) - 1);
|
||||
std::mt19937 engine { randDev() };
|
||||
std::uniform_int_distribution<int> uniform_dist(0,
|
||||
static_cast<int>(mImageFiles.size()) - 1);
|
||||
index = uniform_dist(engine);
|
||||
}
|
||||
while (mPreviousGame && mImageFiles.at(index) == mPreviousGame);
|
||||
} while (mPreviousGame && mImageFiles.at(index) == mPreviousGame);
|
||||
|
||||
path = mImageFiles.at(index)->getImagePath();
|
||||
mGameName = mImageFiles.at(index)->getName();
|
||||
|
@ -575,12 +560,11 @@ void SystemScreensaver::pickRandomVideo(std::string& path)
|
|||
// Get a random number in range.
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::uniform_int_distribution<int>
|
||||
uniform_dist(0, static_cast<int>(mVideoFiles.size()) - 1);
|
||||
std::mt19937 engine { randDev() };
|
||||
std::uniform_int_distribution<int> uniform_dist(0,
|
||||
static_cast<int>(mVideoFiles.size()) - 1);
|
||||
index = uniform_dist(engine);
|
||||
}
|
||||
while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame);
|
||||
} while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame);
|
||||
|
||||
path = mVideoFiles.at(index)->getVideoPath();
|
||||
mGameName = mVideoFiles.at(index)->getName();
|
||||
|
@ -604,12 +588,11 @@ void SystemScreensaver::pickRandomCustomImage(std::string& path)
|
|||
// Get a random number in range.
|
||||
std::random_device randDev;
|
||||
// Mersenne Twister pseudorandom number generator.
|
||||
std::mt19937 engine{randDev()};
|
||||
std::uniform_int_distribution<int>
|
||||
uniform_dist(0, static_cast<int>(mImageCustomFiles.size()) - 1);
|
||||
std::mt19937 engine { randDev() };
|
||||
std::uniform_int_distribution<int> uniform_dist(
|
||||
0, static_cast<int>(mImageCustomFiles.size()) - 1);
|
||||
index = uniform_dist(engine);
|
||||
}
|
||||
while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage);
|
||||
} while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage);
|
||||
|
||||
path = mImageCustomFiles.at(index);
|
||||
mPreviousCustomImage = path;
|
||||
|
@ -633,8 +616,8 @@ void SystemScreensaver::generateOverlayInfo()
|
|||
const std::string systemName = Utils::String::toUpper(mSystemName);
|
||||
const std::string overlayText = gameName + "\n" + systemName;
|
||||
|
||||
mGameOverlay = std::unique_ptr<TextCache>(mGameOverlayFont.at(0)->
|
||||
buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
|
||||
mGameOverlay = std::unique_ptr<TextCache>(
|
||||
mGameOverlayFont.at(0)->buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
|
||||
|
||||
float textSizeX;
|
||||
float textSizeY = mGameOverlayFont[0].get()->sizeText(overlayText).y();
|
||||
|
|
|
@ -22,9 +22,12 @@ public:
|
|||
SystemScreensaver(Window* window);
|
||||
virtual ~SystemScreensaver();
|
||||
|
||||
virtual bool allowSleep();
|
||||
virtual bool isScreensaverActive();
|
||||
virtual bool isFallbackScreensaver();
|
||||
virtual bool allowSleep()
|
||||
{
|
||||
return ((mVideoScreensaver == nullptr) && (mImageScreensaver == nullptr));
|
||||
}
|
||||
virtual bool isScreensaverActive() { return (mState != STATE_INACTIVE); }
|
||||
virtual bool isFallbackScreensaver() { return mFallbackScreensaver; }
|
||||
|
||||
virtual void startScreensaver(bool generateMediaList);
|
||||
virtual void stopScreensaver();
|
||||
|
@ -35,8 +38,8 @@ public:
|
|||
virtual void renderScreensaver();
|
||||
virtual void update(int deltaTime);
|
||||
|
||||
virtual FileData* getCurrentGame() { return mCurrentGame; };
|
||||
virtual void triggerNextGame() { mTriggerNextGame = true; };
|
||||
virtual FileData* getCurrentGame() { return mCurrentGame; }
|
||||
virtual void triggerNextGame() { mTriggerNextGame = true; }
|
||||
|
||||
private:
|
||||
void generateImageList();
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include "VolumeControl.h"
|
||||
|
||||
#include "math/Misc.h"
|
||||
#include "Log.h"
|
||||
#include "math/Misc.h"
|
||||
|
||||
#if defined(_RPI_)
|
||||
#include "Settings.h"
|
||||
|
@ -38,15 +38,15 @@ std::string VolumeControl::mixerCard = "default";
|
|||
VolumeControl* VolumeControl::sInstance = nullptr;
|
||||
|
||||
VolumeControl::VolumeControl()
|
||||
#if defined(__linux__)
|
||||
: mixerIndex(0),
|
||||
mixerHandle(nullptr),
|
||||
mixerElem(nullptr),
|
||||
mixerSelemId(nullptr)
|
||||
#elif defined(_WIN64)
|
||||
: mixerHandle(nullptr),
|
||||
endpointVolume(nullptr)
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
: mixerIndex(0)
|
||||
, mixerHandle(nullptr)
|
||||
, mixerElem(nullptr)
|
||||
, mixerSelemId(nullptr)
|
||||
#elif defined(_WIN64)
|
||||
: mixerHandle(nullptr)
|
||||
, endpointVolume(nullptr)
|
||||
#endif
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ VolumeControl::VolumeControl()
|
|||
VolumeControl::~VolumeControl()
|
||||
{
|
||||
deinit();
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__)
|
||||
snd_config_update_free_global();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
VolumeControl* VolumeControl::getInstance()
|
||||
|
@ -79,14 +79,15 @@ void VolumeControl::deleteInstance()
|
|||
void VolumeControl::init()
|
||||
{
|
||||
// Initialize audio mixer interface.
|
||||
#if defined(__linux__)
|
||||
|
||||
#if defined(__linux__)
|
||||
// Try to open mixer device.
|
||||
if (mixerHandle == nullptr) {
|
||||
#if defined(_RPI_)
|
||||
// Allow user to override the AudioCard and AudioDevice in es_settings.xml.
|
||||
#if defined(_RPI_)
|
||||
mixerCard = Settings::getInstance()->getString("AudioCard");
|
||||
mixerName = Settings::getInstance()->getString("AudioDevice");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
snd_mixer_selem_id_alloca(&mixerSelemId);
|
||||
// Sets simple-mixer index and name.
|
||||
|
@ -106,8 +107,8 @@ void VolumeControl::init()
|
|||
LOG(LogDebug) << "VolumeControl::init(): Mixer initialized";
|
||||
}
|
||||
else {
|
||||
LOG(LogError) <<
|
||||
"VolumeControl::init(): Failed to find mixer elements!";
|
||||
LOG(LogError)
|
||||
<< "VolumeControl::init(): Failed to find mixer elements!";
|
||||
snd_mixer_close(mixerHandle);
|
||||
mixerHandle = nullptr;
|
||||
}
|
||||
|
@ -119,8 +120,8 @@ void VolumeControl::init()
|
|||
}
|
||||
}
|
||||
else {
|
||||
LOG(LogError) <<
|
||||
"VolumeControl::init(): Failed to register simple element class!";
|
||||
LOG(LogError)
|
||||
<< "VolumeControl::init(): Failed to register simple element class!";
|
||||
snd_mixer_close(mixerHandle);
|
||||
mixerHandle = nullptr;
|
||||
}
|
||||
|
@ -135,22 +136,22 @@ void VolumeControl::init()
|
|||
LOG(LogError) << "VolumeControl::init(): Failed to open ALSA mixer!";
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN64)
|
||||
#elif defined(_WIN64)
|
||||
// Windows Vista or above.
|
||||
if (endpointVolume == nullptr) {
|
||||
CoInitialize(nullptr);
|
||||
IMMDeviceEnumerator* deviceEnumerator = nullptr;
|
||||
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IMMDeviceEnumerator), reinterpret_cast<LPVOID *>(&deviceEnumerator));
|
||||
__uuidof(IMMDeviceEnumerator),
|
||||
reinterpret_cast<LPVOID*>(&deviceEnumerator));
|
||||
if (deviceEnumerator != nullptr) {
|
||||
// Get default endpoint.
|
||||
IMMDevice * defaultDevice = nullptr;
|
||||
IMMDevice* defaultDevice = nullptr;
|
||||
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
|
||||
if (defaultDevice != nullptr) {
|
||||
// Retrieve endpoint volume.
|
||||
defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
|
||||
CLSCTX_INPROC_SERVER, nullptr,
|
||||
reinterpret_cast<LPVOID *>(&endpointVolume));
|
||||
defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER,
|
||||
nullptr, reinterpret_cast<LPVOID*>(&endpointVolume));
|
||||
if (endpointVolume == nullptr)
|
||||
LOG(LogError) << "VolumeControl::init(): "
|
||||
"Failed to get default audio endpoint volume!";
|
||||
|
@ -158,8 +159,7 @@ void VolumeControl::init()
|
|||
defaultDevice->Release();
|
||||
}
|
||||
else {
|
||||
LOG(LogError) <<
|
||||
"VolumeControl::init(): Failed to get default audio endpoint!";
|
||||
LOG(LogError) << "VolumeControl::init(): Failed to get default audio endpoint!";
|
||||
}
|
||||
// Release device enumerator. we don't need it anymore.
|
||||
deviceEnumerator->Release();
|
||||
|
@ -169,13 +169,14 @@ void VolumeControl::init()
|
|||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void VolumeControl::deinit()
|
||||
{
|
||||
// Deinitialize audio mixer interface.
|
||||
#if defined(__linux__)
|
||||
|
||||
#if defined(__linux__)
|
||||
if (mixerHandle != nullptr) {
|
||||
snd_mixer_detach(mixerHandle, mixerCard.c_str());
|
||||
snd_mixer_free(mixerHandle);
|
||||
|
@ -183,28 +184,28 @@ void VolumeControl::deinit()
|
|||
mixerHandle = nullptr;
|
||||
mixerElem = nullptr;
|
||||
}
|
||||
#elif defined(_WIN64)
|
||||
#elif defined(_WIN64)
|
||||
if (endpointVolume != nullptr) {
|
||||
endpointVolume->Release();
|
||||
endpointVolume = nullptr;
|
||||
CoUninitialize();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int VolumeControl::getVolume() const
|
||||
{
|
||||
int volume = 0;
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__)
|
||||
if (mixerElem != nullptr) {
|
||||
// Get volume range.
|
||||
long minVolume;
|
||||
long maxVolume;
|
||||
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
||||
long rawVolume;
|
||||
if (snd_mixer_selem_get_playback_volume(mixerElem,
|
||||
SND_MIXER_SCHN_MONO, &rawVolume) == 0) {
|
||||
if (snd_mixer_selem_get_playback_volume(mixerElem, SND_MIXER_SCHN_MONO, &rawVolume) ==
|
||||
0) {
|
||||
// Bring into range 0-100.
|
||||
rawVolume -= minVolume;
|
||||
if (rawVolume > 0)
|
||||
|
@ -218,7 +219,7 @@ int VolumeControl::getVolume() const
|
|||
LOG(LogError) << "VolumeControl::getVolume(): Failed to get volume range";
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN64)
|
||||
#elif defined(_WIN64)
|
||||
if (endpointVolume != nullptr) {
|
||||
// Windows Vista or above, uses EndpointVolume API.
|
||||
float floatVolume = 0.0f; // 0-1
|
||||
|
@ -230,7 +231,7 @@ int VolumeControl::getVolume() const
|
|||
LOG(LogError) << "VolumeControl::getVolume(): Failed to get master volume!";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
volume = Math::clamp(volume, 0, 100);
|
||||
return volume;
|
||||
|
@ -240,7 +241,7 @@ void VolumeControl::setVolume(int volume)
|
|||
{
|
||||
volume = Math::clamp(volume, 0, 100);
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__)
|
||||
if (mixerElem != nullptr) {
|
||||
// Get volume range.
|
||||
long minVolume;
|
||||
|
@ -248,10 +249,10 @@ void VolumeControl::setVolume(int volume)
|
|||
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
||||
// Bring into minVolume-maxVolume range and set.
|
||||
long rawVolume = (volume * (maxVolume - minVolume) / 100) + minVolume;
|
||||
if (snd_mixer_selem_set_playback_volume(mixerElem,
|
||||
SND_MIXER_SCHN_FRONT_LEFT, rawVolume) < 0 ||
|
||||
snd_mixer_selem_set_playback_volume(mixerElem,
|
||||
SND_MIXER_SCHN_FRONT_RIGHT, rawVolume) < 0) {
|
||||
if (snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_LEFT,
|
||||
rawVolume) < 0 ||
|
||||
snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_RIGHT,
|
||||
rawVolume) < 0) {
|
||||
LOG(LogError) << "VolumeControl::getVolume(): Failed to set mixer volume";
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +260,7 @@ void VolumeControl::setVolume(int volume)
|
|||
LOG(LogError) << "VolumeControl::getVolume(): Failed to get volume range";
|
||||
}
|
||||
}
|
||||
#elif defined(_WIN64)
|
||||
#elif defined(_WIN64)
|
||||
if (endpointVolume != nullptr) {
|
||||
// Windows Vista or above, uses EndpointVolume API.
|
||||
float floatVolume = 0.0f; // 0-1
|
||||
|
@ -268,5 +269,5 @@ void VolumeControl::setVolume(int volume)
|
|||
if (endpointVolume->SetMasterVolumeLevelScalar(floatVolume, nullptr) != S_OK)
|
||||
LOG(LogError) << "VolumeControl::setVolume(): Failed to set master volume";
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -38,18 +38,18 @@ public:
|
|||
|
||||
static VolumeControl* sInstance;
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__)
|
||||
static std::string mixerName;
|
||||
static std::string mixerCard;
|
||||
int mixerIndex;
|
||||
snd_mixer_t* mixerHandle;
|
||||
snd_mixer_elem_t* mixerElem;
|
||||
snd_mixer_selem_id_t* mixerSelemId;
|
||||
#elif defined(_WIN64)
|
||||
#elif defined(_WIN64)
|
||||
HMIXER mixerHandle;
|
||||
MIXERCONTROL mixerControl;
|
||||
IAudioEndpointVolume * endpointVolume;
|
||||
#endif
|
||||
IAudioEndpointVolume* endpointVolume;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ES_APP_VOLUME_CONTROL_H
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
class MoveCameraAnimation : public Animation
|
||||
{
|
||||
public:
|
||||
MoveCameraAnimation(
|
||||
Transform4x4f& camera,
|
||||
const Vector3f& target)
|
||||
: mCameraStart(camera),
|
||||
mTarget(target),
|
||||
cameraOut(camera) {}
|
||||
MoveCameraAnimation(Transform4x4f& camera, const Vector3f& target)
|
||||
: mCameraStart(camera)
|
||||
, mTarget(target)
|
||||
, cameraOut(camera)
|
||||
{
|
||||
}
|
||||
|
||||
int getDuration() const override { return 400; }
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "guis/GuiCollectionSystemsOptions.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
|
@ -16,21 +17,23 @@
|
|||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
|
||||
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||
Window* window,
|
||||
std::string title)
|
||||
: GuiSettings(window, title),
|
||||
mAddedCustomCollection(false),
|
||||
mDeletedCustomCollection(false)
|
||||
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::string title)
|
||||
: GuiSettings(window, title)
|
||||
, mAddedCustomCollection(false)
|
||||
, mDeletedCustomCollection(false)
|
||||
{
|
||||
// Finish editing custom collection.
|
||||
if (CollectionSystemsManager::get()->isEditing()) {
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" +
|
||||
Utils::String::toUpper(CollectionSystemsManager::get()->getEditingCollection()) +
|
||||
"' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(
|
||||
mWindow,
|
||||
"FINISH EDITING '" +
|
||||
Utils::String::toUpper(
|
||||
CollectionSystemsManager::get()->getEditingCollection()) +
|
||||
"' COLLECTION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.makeAcceptInputHandler([this] {
|
||||
CollectionSystemsManager::get()->exitEditMode();
|
||||
mWindow->invalidateCachedBackground();
|
||||
|
@ -40,13 +43,14 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
}
|
||||
|
||||
// Automatic collections.
|
||||
collection_systems_auto = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
collection_systems_auto = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
std::map<std::string, CollectionSystemData, stringComparator> autoSystems =
|
||||
CollectionSystemsManager::get()->getAutoCollectionSystems();
|
||||
// Add automatic systems.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = autoSystems.cbegin(); it != autoSystems.cend() ; it++)
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
autoSystems.cbegin();
|
||||
it != autoSystems.cend(); it++)
|
||||
collection_systems_auto->add(it->second.decl.longName, it->second.decl.name,
|
||||
it->second.isEnabled);
|
||||
addWithLabel("AUTOMATIC GAME COLLECTIONS", collection_systems_auto);
|
||||
|
@ -78,8 +82,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
}
|
||||
if (!addedAutoSystems.empty()) {
|
||||
for (std::string system : addedAutoSystems)
|
||||
CollectionSystemsManager::get()->
|
||||
repopulateCollection(autoSystems.find(system)->second.system);
|
||||
CollectionSystemsManager::get()->repopulateCollection(
|
||||
autoSystems.find(system)->second.system);
|
||||
}
|
||||
setNeedsSaving();
|
||||
setNeedsReloading();
|
||||
|
@ -88,22 +92,24 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
});
|
||||
|
||||
// Custom collections.
|
||||
collection_systems_custom = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
collection_systems_custom = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||
std::map<std::string, CollectionSystemData, stringComparator> customSystems =
|
||||
CollectionSystemsManager::get()->getCustomCollectionSystems();
|
||||
// Add custom systems.
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = customSystems.cbegin(); it != customSystems.cend() ; it++)
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
customSystems.cbegin();
|
||||
it != customSystems.cend(); it++)
|
||||
collection_systems_custom->add(it->second.decl.longName, it->second.decl.name,
|
||||
it->second.isEnabled);
|
||||
|
||||
addWithLabel("CUSTOM GAME COLLECTIONS", collection_systems_custom);
|
||||
addSaveFunc([this, customSystems] {
|
||||
if (!mDeletedCustomCollection) {
|
||||
std::string customSystemsSelected = Utils::String::vectorToDelimitedString(
|
||||
collection_systems_custom->getSelectedObjects(), ",", true);
|
||||
std::string customSystemsConfig = Settings::getInstance()->
|
||||
getString("CollectionSystemsCustom");
|
||||
std::string customSystemsConfig =
|
||||
Settings::getInstance()->getString("CollectionSystemsCustom");
|
||||
if (customSystemsSelected != customSystemsConfig) {
|
||||
if (CollectionSystemsManager::get()->isEditing())
|
||||
CollectionSystemsManager::get()->exitEditMode();
|
||||
|
@ -130,8 +136,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
}
|
||||
if (!mAddedCustomCollection && !addedCustomSystems.empty()) {
|
||||
for (std::string system : addedCustomSystems)
|
||||
CollectionSystemsManager::get()->
|
||||
repopulateCollection(customSystems.find(system)->second.system);
|
||||
CollectionSystemsManager::get()->repopulateCollection(
|
||||
customSystems.find(system)->second.system);
|
||||
}
|
||||
setNeedsSaving();
|
||||
setNeedsReloading();
|
||||
|
@ -146,29 +152,30 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
CollectionSystemsManager::get()->getUnusedSystemsFromTheme();
|
||||
if (unusedFolders.size() > 0) {
|
||||
ComponentListRow row;
|
||||
auto themeCollection = std::make_shared<TextComponent>(mWindow,
|
||||
"CREATE NEW CUSTOM COLLECTION FROM THEME", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto themeCollection =
|
||||
std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION FROM THEME",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto bracketThemeCollection = std::make_shared<ImageComponent>(mWindow);
|
||||
bracketThemeCollection->setImage(":/graphics/arrow.svg");
|
||||
bracketThemeCollection->setResize(Vector2f(0,
|
||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
bracketThemeCollection->setResize(
|
||||
Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
row.addElement(themeCollection, true);
|
||||
row.addElement(bracketThemeCollection, false);
|
||||
row.makeAcceptInputHandler([this, unusedFolders] {
|
||||
auto ss = new GuiSettings(mWindow, "SELECT THEME FOLDER");
|
||||
std::shared_ptr<OptionListComponent<std::string>> folderThemes =
|
||||
std::make_shared<OptionListComponent<std::string>>(mWindow,
|
||||
getHelpStyle(), "SELECT THEME FOLDER", true);
|
||||
std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
"SELECT THEME FOLDER", true);
|
||||
// Add custom systems.
|
||||
for (auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ ) {
|
||||
for (auto it = unusedFolders.cbegin(); it != unusedFolders.cend(); it++) {
|
||||
ComponentListRow row;
|
||||
std::string name = *it;
|
||||
std::function<void()> createCollectionCall = [this, name] {
|
||||
createCustomCollection(name);
|
||||
};
|
||||
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);
|
||||
// This transparent bracket is only added to generate the correct help prompts.
|
||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||
|
@ -184,12 +191,11 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
|
||||
// Create new custom collection.
|
||||
ComponentListRow row;
|
||||
auto newCollection = std::make_shared<TextComponent>(mWindow,
|
||||
"CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto newCollection = std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto bracketNewCollection = std::make_shared<ImageComponent>(mWindow);
|
||||
bracketNewCollection->setImage(":/graphics/arrow.svg");
|
||||
bracketNewCollection->setResize(Vector2f(0,
|
||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
bracketNewCollection->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
row.addElement(newCollection, true);
|
||||
row.addElement(bracketNewCollection, false);
|
||||
auto createCollectionCall = [this](const std::string& newVal) {
|
||||
|
@ -202,36 +208,38 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
createCustomCollection(name);
|
||||
};
|
||||
row.makeAcceptInputHandler([this, createCollectionCall] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(),
|
||||
"New Collection Name", "", createCollectionCall, false, "SAVE"));
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "New Collection Name", "",
|
||||
createCollectionCall, false, "SAVE"));
|
||||
});
|
||||
addRow(row);
|
||||
|
||||
// Delete custom collection.
|
||||
row.elements.clear();
|
||||
auto deleteCollection = std::make_shared<TextComponent>(mWindow,
|
||||
"DELETE CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto deleteCollection = std::make_shared<TextComponent>(
|
||||
mWindow, "DELETE CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
auto bracketDeleteCollection = std::make_shared<ImageComponent>(mWindow);
|
||||
bracketDeleteCollection->setImage(":/graphics/arrow.svg");
|
||||
bracketDeleteCollection->setResize(Vector2f(0,
|
||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
bracketDeleteCollection->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||
row.addElement(deleteCollection, true);
|
||||
row.addElement(bracketDeleteCollection, false);
|
||||
row.makeAcceptInputHandler([this, customSystems] {
|
||||
auto ss = new GuiSettings(mWindow, "SELECT COLLECTION TO DELETE");
|
||||
std::shared_ptr<OptionListComponent<std::string>> customCollections =
|
||||
std::make_shared<OptionListComponent<std::string>>(mWindow,
|
||||
getHelpStyle(), "", true);
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
||||
it = customSystems.cbegin(); it != customSystems.cend() ; it++) {
|
||||
std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(), "", true);
|
||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||
customSystems.cbegin();
|
||||
it != customSystems.cend(); it++) {
|
||||
ComponentListRow row;
|
||||
std::string name = (*it).first;
|
||||
std::function<void()> deleteCollectionCall = [this, name] {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, getHelpStyle(),
|
||||
"THIS WILL PERMANENTLY\nDELETE THE COLLECTION\n'" +
|
||||
Utils::String::toUpper(name) + "'\n"
|
||||
Utils::String::toUpper(name) +
|
||||
"'\n"
|
||||
"ARE YOU SURE?",
|
||||
"YES", [this, name] {
|
||||
"YES",
|
||||
[this, name] {
|
||||
if (CollectionSystemsManager::get()->isEditing())
|
||||
CollectionSystemsManager::get()->exitEditMode();
|
||||
mDeletedCustomCollection = true;
|
||||
|
@ -261,13 +269,11 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
CollectionSystemsManager::get()->deleteCustomCollection(name);
|
||||
return true;
|
||||
},
|
||||
"NO", [this] {
|
||||
return false;
|
||||
}));
|
||||
"NO", [this] { return false; }));
|
||||
};
|
||||
row.makeAcceptInputHandler(deleteCollectionCall);
|
||||
auto customCollection = std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
auto customCollection = std::make_shared<TextComponent>(
|
||||
mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
row.addElement(customCollection, true);
|
||||
// This transparent bracket is only added generate the correct help prompts.
|
||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||
|
@ -310,8 +316,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
|
||||
// Group unthemed custom collections.
|
||||
auto use_custom_collections_system = std::make_shared<SwitchComponent>(mWindow);
|
||||
use_custom_collections_system->setState(Settings::getInstance()->
|
||||
getBool("UseCustomCollectionsSystem"));
|
||||
use_custom_collections_system->setState(
|
||||
Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
|
||||
addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", use_custom_collections_system);
|
||||
addSaveFunc([this, use_custom_collections_system] {
|
||||
if (use_custom_collections_system->getState() !=
|
||||
|
@ -330,8 +336,8 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
|||
|
||||
// Show system names in collections.
|
||||
auto collection_show_system_info = std::make_shared<SwitchComponent>(mWindow);
|
||||
collection_show_system_info->setState(Settings::getInstance()->
|
||||
getBool("CollectionShowSystemInfo"));
|
||||
collection_show_system_info->setState(
|
||||
Settings::getInstance()->getBool("CollectionShowSystemInfo"));
|
||||
addWithLabel("SHOW SYSTEM NAMES IN COLLECTIONS", collection_show_system_info);
|
||||
addSaveFunc([this, collection_show_system_info] {
|
||||
if (collection_show_system_info->getState() !=
|
||||
|
@ -350,10 +356,9 @@ void GuiCollectionSystemsOptions::createCustomCollection(std::string inName)
|
|||
if (CollectionSystemsManager::get()->isEditing())
|
||||
CollectionSystemsManager::get()->exitEditMode();
|
||||
|
||||
std::string collectionName = CollectionSystemsManager::get()->
|
||||
getValidNewCollectionName(inName);
|
||||
SystemData* newCollection = CollectionSystemsManager::get()->
|
||||
addNewCustomCollection(collectionName);
|
||||
std::string collectionName = CollectionSystemsManager::get()->getValidNewCollectionName(inName);
|
||||
SystemData* newCollection =
|
||||
CollectionSystemsManager::get()->addNewCustomCollection(collectionName);
|
||||
|
||||
CollectionSystemsManager::get()->saveCustomCollection(newCollection);
|
||||
collection_systems_custom->add(collectionName, collectionName, true);
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
#include "GuiSettings.h"
|
||||
|
||||
template<typename T>
|
||||
class OptionListComponent;
|
||||
template <typename T> class OptionListComponent;
|
||||
|
||||
class GuiCollectionSystemsOptions : public GuiSettings
|
||||
{
|
||||
|
|
|
@ -10,23 +10,22 @@
|
|||
|
||||
#include "guis/GuiGameScraper.h"
|
||||
|
||||
#include "FileData.h"
|
||||
#include "MameNames.h"
|
||||
#include "SystemData.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "FileData.h"
|
||||
#include "MameNames.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GuiGameScraper::GuiGameScraper(
|
||||
Window* window,
|
||||
GuiGameScraper::GuiGameScraper(Window* window,
|
||||
ScraperSearchParams params,
|
||||
std::function<void(const ScraperSearchResult&)> doneFunc)
|
||||
: GuiComponent(window),
|
||||
mGrid(window, Vector2i(1, 7)),
|
||||
mBox(window, ":/graphics/frame.svg"),
|
||||
mSearchParams(params),
|
||||
mClose(false)
|
||||
: GuiComponent(window)
|
||||
, mGrid(window, Vector2i(1, 7))
|
||||
, mBox(window, ":/graphics/frame.svg")
|
||||
, mSearchParams(params)
|
||||
, mClose(false)
|
||||
{
|
||||
addChild(&mBox);
|
||||
addChild(&mGrid);
|
||||
|
@ -41,42 +40,42 @@ GuiGameScraper::GuiGameScraper(
|
|||
else {
|
||||
if (params.game->isArcadeGame() &&
|
||||
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
||||
scrapeName = Utils::FileSystem::getFileName(mSearchParams.game->getPath()) + " (" +
|
||||
MameNames::getInstance()->getCleanName(mSearchParams.game->getCleanName()) +
|
||||
")";
|
||||
scrapeName =
|
||||
Utils::FileSystem::getFileName(mSearchParams.game->getPath()) + " (" +
|
||||
MameNames::getInstance()->getCleanName(mSearchParams.game->getCleanName()) + ")";
|
||||
else
|
||||
scrapeName = Utils::FileSystem::getFileName(mSearchParams.game->getPath());
|
||||
}
|
||||
|
||||
mGameName = std::make_shared<TextComponent>(mWindow, scrapeName +
|
||||
mGameName = std::make_shared<TextComponent>(
|
||||
mWindow,
|
||||
scrapeName +
|
||||
((mSearchParams.game->getType() == FOLDER) ? " " + ViewController::FOLDER_CHAR : ""),
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mGameName, Vector2i(0, 1), false, true);
|
||||
|
||||
// Row 2 is a spacer.
|
||||
|
||||
mSystemName = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(
|
||||
mSearchParams.system->getFullName()), Font::get(FONT_SIZE_SMALL),
|
||||
0x888888FF, ALIGN_CENTER);
|
||||
mSystemName = std::make_shared<TextComponent>(
|
||||
mWindow, Utils::String::toUpper(mSearchParams.system->getFullName()),
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mSystemName, Vector2i(0, 3), false, true);
|
||||
|
||||
// Row 4 is a spacer.
|
||||
|
||||
// GuiScraperSearch.
|
||||
mSearch = std::make_shared<GuiScraperSearch>(window,
|
||||
GuiScraperSearch::NEVER_AUTO_ACCEPT, 1);
|
||||
mSearch = std::make_shared<GuiScraperSearch>(window, GuiScraperSearch::NEVER_AUTO_ACCEPT, 1);
|
||||
mGrid.setEntry(mSearch, Vector2i(0, 5), true);
|
||||
|
||||
// Buttons
|
||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH",
|
||||
"refine search", [&] {
|
||||
buttons.push_back(
|
||||
std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH", "refine search", [&] {
|
||||
mSearch->openInputScreen(mSearchParams);
|
||||
mGrid.resetCursor();
|
||||
}));
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(
|
||||
mWindow, "CANCEL", "cancel", [&] {
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel", [&] {
|
||||
if (mSearch->getSavedNewMedia()) {
|
||||
// If the user aborted the scraping but there was still some media downloaded,
|
||||
// then force an unload of the textures for the game image and marquee, and make
|
||||
|
@ -86,36 +85,16 @@ GuiGameScraper::GuiGameScraper(
|
|||
TextureResource::manualUnload(mSearchParams.game->getMarqueePath(), false);
|
||||
ViewController::get()->onFileChanged(mSearchParams.game, true);
|
||||
}
|
||||
delete this; }));
|
||||
delete this;
|
||||
}));
|
||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||
|
||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false);
|
||||
|
||||
// We call this->close() instead of just 'delete this' in the accept callback.
|
||||
// This is because of how GuiComponent::update works. If it was just 'delete this',
|
||||
// the following would happen when the metadata resolver is done:
|
||||
// GuiGameScraper::update()
|
||||
// GuiComponent::update()
|
||||
// it = mChildren.cbegin();
|
||||
// mBox::update()
|
||||
// it++;
|
||||
// mSearchComponent::update()
|
||||
// acceptCallback -> delete this
|
||||
// it++; // Error, mChildren has been deleted because it was part of 'this'.
|
||||
|
||||
// So instead we do this:
|
||||
// GuiGameScraper::update()
|
||||
// GuiComponent::update()
|
||||
// it = mChildren.cbegin();
|
||||
// mBox::update()
|
||||
// it++;
|
||||
// mSearchComponent::update()
|
||||
// acceptCallback -> close() -> mClose = true
|
||||
// it++; // OK.
|
||||
// if (mClose)
|
||||
// delete this;
|
||||
mSearch->setAcceptCallback([this, doneFunc](const ScraperSearchResult& result) {
|
||||
doneFunc(result); close(); });
|
||||
doneFunc(result);
|
||||
close();
|
||||
});
|
||||
mSearch->setCancelCallback([&] { delete this; });
|
||||
|
||||
// Limit the width of the GUI on ultrawide monitors. The 1.778 aspect ratio value is
|
||||
|
@ -124,8 +103,8 @@ GuiGameScraper::GuiGameScraper(
|
|||
float width = Math::clamp(0.95f * aspectValue, 0.70f, 0.95f) * Renderer::getScreenWidth();
|
||||
|
||||
setSize(width, Renderer::getScreenHeight() * 0.747f);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() -
|
||||
mSize.y()) / 2);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||
|
||||
mGrid.resetCursor();
|
||||
mSearch->search(params); // Start the search.
|
||||
|
@ -133,14 +112,14 @@ GuiGameScraper::GuiGameScraper(
|
|||
|
||||
void GuiGameScraper::onSizeChanged()
|
||||
{
|
||||
mBox.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
mBox.fitTo(mSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||
|
||||
mGrid.setRowHeightPerc(0, 0.04f, false);
|
||||
mGrid.setRowHeightPerc(1, mGameName->getFont()->getLetterHeight() /
|
||||
mSize.y(), false); // Game name.
|
||||
mGrid.setRowHeightPerc(1, mGameName->getFont()->getLetterHeight() / mSize.y(),
|
||||
false); // Game name.
|
||||
mGrid.setRowHeightPerc(2, 0.04f, false);
|
||||
mGrid.setRowHeightPerc(3, mSystemName->getFont()->getLetterHeight() /
|
||||
mSize.y(), false); // System name.
|
||||
mGrid.setRowHeightPerc(3, mSystemName->getFont()->getLetterHeight() / mSize.y(),
|
||||
false); // System name.
|
||||
mGrid.setRowHeightPerc(4, 0.04f, false);
|
||||
mGrid.setRowHeightPerc(6, mButtonGrid->getSize().y() / mSize.y(), false); // Buttons.
|
||||
mGrid.setSize(mSize);
|
||||
|
@ -190,5 +169,6 @@ HelpStyle GuiGameScraper::getHelpStyle()
|
|||
|
||||
void GuiGameScraper::close()
|
||||
{
|
||||
// This will cause update() to close the GUI.
|
||||
mClose = true;
|
||||
}
|
||||
|
|
|
@ -11,14 +11,15 @@
|
|||
#ifndef ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
||||
#define ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "guis/GuiScraperSearch.h"
|
||||
#include "GuiComponent.h"
|
||||
|
||||
class GuiGameScraper : public GuiComponent
|
||||
{
|
||||
public:
|
||||
GuiGameScraper(Window* window, ScraperSearchParams params,
|
||||
GuiGameScraper(Window* window,
|
||||
ScraperSearchParams params,
|
||||
std::function<void(const ScraperSearchResult&)> doneFunc);
|
||||
|
||||
void onSizeChanged() override;
|
||||
|
|
|
@ -10,21 +10,20 @@
|
|||
|
||||
#include "guis/GuiGamelistFilter.h"
|
||||
|
||||
#include "SystemData.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GuiGamelistFilter::GuiGamelistFilter(
|
||||
Window* window,
|
||||
GuiGamelistFilter::GuiGamelistFilter(Window* window,
|
||||
SystemData* system,
|
||||
std::function<void(bool)> filterChangedCallback)
|
||||
: GuiComponent(window),
|
||||
mMenu(window, "FILTER GAMELIST BY"),
|
||||
mSystem(system),
|
||||
mFiltersChangedCallback(filterChangedCallback),
|
||||
mFiltersChanged(false)
|
||||
: GuiComponent(window)
|
||||
, mMenu(window, "FILTER GAMELIST BY")
|
||||
, mSystem(system)
|
||||
, mFiltersChangedCallback(filterChangedCallback)
|
||||
, mFiltersChanged(false)
|
||||
{
|
||||
initializeMenu();
|
||||
}
|
||||
|
@ -41,7 +40,8 @@ void GuiGamelistFilter::initializeMenu()
|
|||
// Show filtered menu.
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "RESET ALL FILTERS",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistFilter::resetAllFilters, this));
|
||||
mMenu.addRow(row);
|
||||
row.elements.clear();
|
||||
|
@ -56,8 +56,10 @@ void GuiGamelistFilter::initializeMenu()
|
|||
// Save the initial filter values to be able to check later if any changes were made.
|
||||
mInitialTextFilter = mTextFilterField->getValue();
|
||||
|
||||
for (std::map<FilterIndexType, std::shared_ptr<OptionListComponent<std::string>>>::
|
||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
||||
for (std::map<FilterIndexType,
|
||||
std::shared_ptr<OptionListComponent<std::string>>>::const_iterator it =
|
||||
mFilterOptions.cbegin();
|
||||
it != mFilterOptions.cend(); it++) {
|
||||
std::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||
std::vector<std::string> filters = optionList->getSelectedObjects();
|
||||
mInitialFilters.push_back(filters);
|
||||
|
@ -67,8 +69,10 @@ void GuiGamelistFilter::initializeMenu()
|
|||
void GuiGamelistFilter::resetAllFilters()
|
||||
{
|
||||
mFilterIndex->resetFilters();
|
||||
for (std::map<FilterIndexType, std::shared_ptr< OptionListComponent<std::string>>>::
|
||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
||||
for (std::map<FilterIndexType,
|
||||
std::shared_ptr<OptionListComponent<std::string>>>::const_iterator it =
|
||||
mFilterOptions.cbegin();
|
||||
it != mFilterOptions.cend(); it++) {
|
||||
std::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||
optionList->selectNone();
|
||||
}
|
||||
|
@ -78,21 +82,18 @@ void GuiGamelistFilter::resetAllFilters()
|
|||
mFiltersChanged = true;
|
||||
}
|
||||
|
||||
GuiGamelistFilter::~GuiGamelistFilter()
|
||||
{
|
||||
mFilterOptions.clear();
|
||||
}
|
||||
GuiGamelistFilter::~GuiGamelistFilter() { mFilterOptions.clear(); }
|
||||
|
||||
void GuiGamelistFilter::addFiltersToMenu()
|
||||
{
|
||||
ComponentListRow row;
|
||||
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper("TEXT FILTER (GAME NAME)"),
|
||||
auto lbl =
|
||||
std::make_shared<TextComponent>(mWindow, Utils::String::toUpper("TEXT FILTER (GAME NAME)"),
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||
|
||||
mTextFilterField = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||
mTextFilterField = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF, ALIGN_RIGHT);
|
||||
|
||||
// Don't show the free text filter entry unless there are any games in the system.
|
||||
if (mSystem->getRootFolder()->getChildren().size() > 0) {
|
||||
|
@ -118,19 +119,19 @@ void GuiGamelistFilter::addFiltersToMenu()
|
|||
};
|
||||
|
||||
row.makeAcceptInputHandler([this, updateVal] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(),
|
||||
"TEXT FILTER (GAME NAME)", mTextFilterField->getValue(),
|
||||
updateVal, false, "OK", "APPLY CHANGES?"));
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "TEXT FILTER (GAME NAME)",
|
||||
mTextFilterField->getValue(), updateVal, false, "OK",
|
||||
"APPLY CHANGES?"));
|
||||
});
|
||||
|
||||
mMenu.addRow(row);
|
||||
|
||||
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
||||
|
||||
for (std::vector<FilterDataDecl>::const_iterator it =
|
||||
decls.cbegin(); it != decls.cend(); it++) {
|
||||
|
||||
for (std::vector<FilterDataDecl>::const_iterator it = decls.cbegin(); // Line break.
|
||||
it != decls.cend(); it++) {
|
||||
FilterIndexType type = (*it).type; // Type of filter.
|
||||
|
||||
// All possible filters for this type.
|
||||
std::map<std::string, int>* allKeys = (*it).allIndexKeys;
|
||||
std::string menuLabel = (*it).menuLabel; // Text to show in menu.
|
||||
|
@ -140,9 +141,9 @@ void GuiGamelistFilter::addFiltersToMenu()
|
|||
ComponentListRow row;
|
||||
|
||||
// Add genres.
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), menuLabel, true);
|
||||
for (auto it: *allKeys)
|
||||
optionList = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
menuLabel, true);
|
||||
for (auto it : *allKeys)
|
||||
optionList->add(it.first, it.first, mFilterIndex->isKeyBeingFilteredBy(it.first, type));
|
||||
if (allKeys->size() > 0)
|
||||
mMenu.addWithLabel(menuLabel, optionList);
|
||||
|
@ -157,8 +158,10 @@ void GuiGamelistFilter::applyFilters()
|
|||
mFiltersChanged = true;
|
||||
|
||||
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
||||
for (std::map<FilterIndexType, std::shared_ptr<OptionListComponent<std::string>>>::
|
||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
||||
for (std::map<FilterIndexType,
|
||||
std::shared_ptr<OptionListComponent<std::string>>>::const_iterator it =
|
||||
mFilterOptions.cbegin();
|
||||
it != mFilterOptions.cend(); it++) {
|
||||
std::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||
std::vector<std::string> filters = optionList->getSelectedObjects();
|
||||
auto iteratorDistance = std::distance(mFilterOptions.cbegin(), it);
|
||||
|
|
|
@ -11,19 +11,19 @@
|
|||
#ifndef ES_APP_GUIS_GUI_GAME_LIST_FILTER_H
|
||||
#define ES_APP_GUIS_GUI_GAME_LIST_FILTER_H
|
||||
|
||||
#include "components/MenuComponent.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
|
||||
template<typename T>
|
||||
class OptionListComponent;
|
||||
template <typename T> class OptionListComponent;
|
||||
class SystemData;
|
||||
|
||||
class GuiGamelistFilter : public GuiComponent
|
||||
{
|
||||
public:
|
||||
GuiGamelistFilter(Window* window,
|
||||
SystemData* system, std::function<void(bool)> filtersChangedCallback);
|
||||
SystemData* system,
|
||||
std::function<void(bool)> filtersChangedCallback);
|
||||
|
||||
~GuiGamelistFilter();
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
|
||||
#include "GuiGamelistOptions.h"
|
||||
|
||||
#include "guis/GuiGamelistFilter.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "FileSorts.h"
|
||||
|
@ -24,18 +19,21 @@
|
|||
#include "MameNames.h"
|
||||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "guis/GuiGamelistFilter.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
GuiGamelistOptions::GuiGamelistOptions(
|
||||
Window* window,
|
||||
SystemData* system)
|
||||
: GuiComponent(window),
|
||||
mSystem(system),
|
||||
mMenu(window, "OPTIONS"),
|
||||
mFiltersChanged(false),
|
||||
mCancelled(false),
|
||||
mIsCustomCollection(false),
|
||||
mIsCustomCollectionGroup(false),
|
||||
mCustomCollectionSystem(nullptr)
|
||||
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system)
|
||||
: GuiComponent(window)
|
||||
, mSystem(system)
|
||||
, mMenu(window, "OPTIONS")
|
||||
, mFiltersChanged(false)
|
||||
, mCancelled(false)
|
||||
, mIsCustomCollection(false)
|
||||
, mIsCustomCollectionGroup(false)
|
||||
, mCustomCollectionSystem(nullptr)
|
||||
{
|
||||
addChild(&mMenu);
|
||||
|
||||
|
@ -46,8 +44,7 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
ComponentListRow row;
|
||||
|
||||
// There is some special logic required for custom collections.
|
||||
if (file->getSystem()->isCustomCollection() &&
|
||||
file->getPath() != file->getSystem()->getName())
|
||||
if (file->getSystem()->isCustomCollection() && file->getPath() != file->getSystem()->getName())
|
||||
mIsCustomCollection = true;
|
||||
else if (file->getSystem()->isCustomCollection() &&
|
||||
file->getPath() == file->getSystem()->getName())
|
||||
|
@ -84,12 +81,12 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
else {
|
||||
// Check if the currently selected game is a favorite.
|
||||
bool isFavorite = false;
|
||||
if (mFirstLetterIndex.size() == 1 && mFirstLetterIndex.front() ==
|
||||
ViewController::FAVORITE_CHAR)
|
||||
if (mFirstLetterIndex.size() == 1 &&
|
||||
mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR)
|
||||
isFavorite = true;
|
||||
else if (mFirstLetterIndex.size() > 1 && (mFirstLetterIndex.front() ==
|
||||
ViewController::FAVORITE_CHAR || mFirstLetterIndex[1] ==
|
||||
ViewController::FAVORITE_CHAR))
|
||||
else if (mFirstLetterIndex.size() > 1 &&
|
||||
(mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR ||
|
||||
mFirstLetterIndex[1] == ViewController::FAVORITE_CHAR))
|
||||
isFavorite = true;
|
||||
|
||||
// Get the first character of the game name (which could be a Unicode character).
|
||||
|
@ -99,8 +96,8 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
mCurrentFirstCharacter = Utils::String::getFirstCharacter(file->getSortName());
|
||||
}
|
||||
|
||||
mJumpToLetterList = std::make_shared<LetterList>(mWindow, getHelpStyle(),
|
||||
"JUMP TO...", false);
|
||||
mJumpToLetterList =
|
||||
std::make_shared<LetterList>(mWindow, getHelpStyle(), "JUMP TO...", false);
|
||||
|
||||
// Populate the quick selector.
|
||||
for (unsigned int i = 0; i < mFirstLetterIndex.size(); i++) {
|
||||
|
@ -146,8 +143,9 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
if (!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() > 0) {
|
||||
if (system->getName() != "recent" && Settings::getInstance()->getBool("GamelistFilters")) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FILTER GAMELIST",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
|
||||
mMenu.addRow(row);
|
||||
|
@ -155,12 +153,12 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
}
|
||||
// Add a dummy entry when applicable as the menu looks quite ugly if it's just blank.
|
||||
else if (!CollectionSystemsManager::get()->isEditing() &&
|
||||
mSystem->getRootFolder()->getChildren().size() == 0 &&
|
||||
!mIsCustomCollectionGroup && !mIsCustomCollection) {
|
||||
mSystem->getRootFolder()->getChildren().size() == 0 && !mIsCustomCollectionGroup &&
|
||||
!mIsCustomCollection) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "THIS SYSTEM HAS NO GAMES",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "THIS SYSTEM HAS NO GAMES",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
||||
|
@ -174,9 +172,10 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
(mIsCustomCollection || mIsCustomCollectionGroup)) {
|
||||
if (CollectionSystemsManager::get()->getEditingCollection() != customSystem) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(
|
||||
mWindow, "ADD/REMOVE GAMES TO THIS COLLECTION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"ADD/REMOVE GAMES TO THIS COLLECTION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::startEditMode, this));
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
@ -186,9 +185,13 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
CollectionSystemsManager::get()->isEditing()) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(
|
||||
mWindow, "FINISH EDITING '" + Utils::String::toUpper(
|
||||
mWindow,
|
||||
"FINISH EDITING '" +
|
||||
Utils::String::toUpper(
|
||||
CollectionSystemsManager::get()->getEditingCollection()) +
|
||||
"' COLLECTION",Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
"' COLLECTION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
|
||||
mMenu.addRow(row);
|
||||
}
|
||||
|
@ -197,8 +200,9 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
||||
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"EDIT THIS FOLDER'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS FOLDER'S METADATA",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||
mMenu.addRow(row);
|
||||
|
@ -208,8 +212,9 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
||||
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
"EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||
mMenu.addRow(row);
|
||||
|
@ -219,18 +224,24 @@ GuiGamelistOptions::GuiGamelistOptions(
|
|||
// Buttons. The logic to apply or cancel settings are handled by the destructor.
|
||||
if ((!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() == 0) ||
|
||||
system->getName() == "recent") {
|
||||
mMenu.addButton("CLOSE", "close", [&] { mCancelled = true; delete this; });
|
||||
mMenu.addButton("CLOSE", "close", [&] {
|
||||
mCancelled = true;
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
else {
|
||||
mMenu.addButton("APPLY", "apply", [&] { delete this; });
|
||||
mMenu.addButton("CANCEL", "cancel", [&] { mCancelled = true; delete this; });
|
||||
mMenu.addButton("CANCEL", "cancel", [&] {
|
||||
mCancelled = true;
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
|
||||
// Center the menu.
|
||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||
static_cast<float>(Renderer::getScreenHeight()));
|
||||
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f, (mSize.y() -
|
||||
mMenu.getSize().y()) / 2.0f);
|
||||
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f,
|
||||
(mSize.y() - mMenu.getSize().y()) / 2.0f);
|
||||
}
|
||||
|
||||
GuiGamelistOptions::~GuiGamelistOptions()
|
||||
|
@ -248,11 +259,12 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
|||
if (!mFromPlaceholder) {
|
||||
ViewController::get()->reloadGameListView(mSystem);
|
||||
}
|
||||
else if (!mCustomCollectionSystem->getRootFolder()->
|
||||
getChildrenListToDisplay().empty()) {
|
||||
else if (!mCustomCollectionSystem->getRootFolder()
|
||||
->getChildrenListToDisplay()
|
||||
.empty()) {
|
||||
ViewController::get()->reloadGameListView(mSystem);
|
||||
getGamelist()->setCursor(mCustomCollectionSystem->
|
||||
getRootFolder()->getChildrenListToDisplay().front());
|
||||
getGamelist()->setCursor(
|
||||
mCustomCollectionSystem->getRootFolder()->getChildrenListToDisplay().front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +274,7 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
|||
|
||||
if (!mFromPlaceholder) {
|
||||
FileData* root;
|
||||
|
||||
if (mIsCustomCollection)
|
||||
root = getGamelist()->getCursor()->getSystem()->getRootFolder();
|
||||
else
|
||||
|
@ -329,8 +342,7 @@ void GuiGamelistOptions::startEditMode()
|
|||
// Display the indication icons which show what games are part of the custom collection
|
||||
// currently being edited. This is done cheaply using onFileChanged() which will trigger
|
||||
// populateList().
|
||||
for (auto it = SystemData::sSystemVector.begin();
|
||||
it != SystemData::sSystemVector.end(); it++) {
|
||||
for (auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++) {
|
||||
ViewController::get()->getGameListView((*it))->onFileChanged(
|
||||
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
||||
}
|
||||
|
@ -362,12 +374,12 @@ void GuiGamelistOptions::openMetaDataEd()
|
|||
|
||||
clearGameBtnFunc = [this, file] {
|
||||
if (file->getType() == FOLDER) {
|
||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder \"" <<
|
||||
file->getFullPath() << "\"";
|
||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder \""
|
||||
<< file->getFullPath() << "\"";
|
||||
}
|
||||
else {
|
||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the file \"" <<
|
||||
file->getFullPath() << "\"";
|
||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the file \""
|
||||
<< file->getFullPath() << "\"";
|
||||
}
|
||||
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
||||
|
||||
|
@ -377,8 +389,8 @@ void GuiGamelistOptions::openMetaDataEd()
|
|||
if (it->key == "name") {
|
||||
if (file->isArcadeGame()) {
|
||||
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
||||
file->metadata.set(it->key, MameNames::getInstance()->
|
||||
getCleanName(file->getCleanName()));
|
||||
file->metadata.set(
|
||||
it->key, MameNames::getInstance()->getCleanName(file->getCleanName()));
|
||||
}
|
||||
else {
|
||||
file->metadata.set(it->key, file->getDisplayName());
|
||||
|
@ -408,8 +420,8 @@ void GuiGamelistOptions::openMetaDataEd()
|
|||
};
|
||||
|
||||
deleteGameBtnFunc = [this, file] {
|
||||
LOG(LogInfo) << "Deleting the game file \"" << file->getFullPath() <<
|
||||
"\", all its media files and its gamelist.xml entry.";
|
||||
LOG(LogInfo) << "Deleting the game file \"" << file->getFullPath()
|
||||
<< "\", all its media files and its gamelist.xml entry.";
|
||||
CollectionSystemsManager::get()->deleteCollectionFiles(file);
|
||||
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
||||
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true);
|
||||
|
@ -420,19 +432,19 @@ void GuiGamelistOptions::openMetaDataEd()
|
|||
};
|
||||
|
||||
if (file->getType() == FOLDER) {
|
||||
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata,
|
||||
file->metadata.getMDD(FOLDER_METADATA), p,
|
||||
Utils::FileSystem::getFileName(file->getPath()), std::bind(
|
||||
&IGameListView::onFileChanged, ViewController::get()->getGameListView(
|
||||
file->getSystem()).get(), file, true),
|
||||
mWindow->pushGui(new GuiMetaDataEd(
|
||||
mWindow, &file->metadata, file->metadata.getMDD(FOLDER_METADATA), p,
|
||||
Utils::FileSystem::getFileName(file->getPath()),
|
||||
std::bind(&IGameListView::onFileChanged,
|
||||
ViewController::get()->getGameListView(file->getSystem()).get(), file, true),
|
||||
clearGameBtnFunc, deleteGameBtnFunc));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata,
|
||||
file->metadata.getMDD(GAME_METADATA), p,
|
||||
Utils::FileSystem::getFileName(file->getPath()), std::bind(
|
||||
&IGameListView::onFileChanged, ViewController::get()->getGameListView(
|
||||
file->getSystem()).get(), file, true),
|
||||
mWindow->pushGui(new GuiMetaDataEd(
|
||||
mWindow, &file->metadata, file->metadata.getMDD(GAME_METADATA), p,
|
||||
Utils::FileSystem::getFileName(file->getPath()),
|
||||
std::bind(&IGameListView::onFileChanged,
|
||||
ViewController::get()->getGameListView(file->getSystem()).get(), file, true),
|
||||
clearGameBtnFunc, deleteGameBtnFunc));
|
||||
}
|
||||
}
|
||||
|
@ -442,14 +454,14 @@ void GuiGamelistOptions::jumpToLetter()
|
|||
char letter = mJumpToLetterList->getSelected().front();
|
||||
|
||||
// Get the gamelist.
|
||||
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
||||
getParent()->getChildrenListToDisplay();
|
||||
const std::vector<FileData*>& files =
|
||||
getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||
|
||||
for (unsigned int i = 0; i < files.size(); i++) {
|
||||
if (mFavoritesSorting && (mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR ||
|
||||
mFirstLetterIndex.front() == ViewController::FOLDER_CHAR)) {
|
||||
if (static_cast<char>(toupper(files.at(i)->getSortName().front())) ==
|
||||
letter && !files.at(i)->getFavorite()) {
|
||||
if (static_cast<char>(toupper(files.at(i)->getSortName().front())) == letter &&
|
||||
!files.at(i)->getFavorite()) {
|
||||
if (!mOnlyHasFolders && mFoldersOnTop && files.at(i)->getType() == FOLDER) {
|
||||
continue;
|
||||
}
|
||||
|
@ -477,8 +489,8 @@ void GuiGamelistOptions::jumpToFirstRow()
|
|||
{
|
||||
if (mFoldersOnTop && mJumpToLetterList->getSelected() == ViewController::FAVORITE_CHAR) {
|
||||
// Get the gamelist.
|
||||
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
||||
getParent()->getChildrenListToDisplay();
|
||||
const std::vector<FileData*>& files =
|
||||
getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||
// Select the first game that is not a folder, unless it's a folder-only list in
|
||||
// which case the first line overall is selected.
|
||||
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
||||
|
@ -502,8 +514,7 @@ bool GuiGamelistOptions::input(InputConfig* config, Input input)
|
|||
if (input.value != 0 && config->isMappedTo("back", input))
|
||||
mCancelled = true;
|
||||
|
||||
if (input.value != 0 && (config->isMappedTo("b", input) ||
|
||||
config->isMappedTo("back", input))) {
|
||||
if (input.value != 0 && (config->isMappedTo("b", input) || config->isMappedTo("back", input))) {
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
@ -521,9 +532,8 @@ HelpStyle GuiGamelistOptions::getHelpStyle()
|
|||
std::vector<HelpPrompt> GuiGamelistOptions::getHelpPrompts()
|
||||
{
|
||||
auto prompts = mMenu.getHelpPrompts();
|
||||
if (mSystem->getRootFolder()->getChildren().size() > 0 ||
|
||||
mIsCustomCollectionGroup || mIsCustomCollection ||
|
||||
CollectionSystemsManager::get()->isEditing())
|
||||
if (mSystem->getRootFolder()->getChildren().size() > 0 || mIsCustomCollectionGroup ||
|
||||
mIsCustomCollection || CollectionSystemsManager::get()->isEditing())
|
||||
prompts.push_back(HelpPrompt("a", "select"));
|
||||
if (mSystem->getRootFolder()->getChildren().size() > 0 && mSystem->getName() != "recent") {
|
||||
prompts.push_back(HelpPrompt("b", "close (apply)"));
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#ifndef ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H
|
||||
#define ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H
|
||||
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
|
||||
class IGameListView;
|
||||
class SystemData;
|
||||
|
|
|
@ -14,21 +14,18 @@
|
|||
|
||||
#include <SDL2/SDL_timer.h>
|
||||
|
||||
GuiInfoPopup::GuiInfoPopup(
|
||||
Window* window,
|
||||
std::string message,
|
||||
int duration)
|
||||
: GuiComponent(window),
|
||||
mMessage(message),
|
||||
mDuration(duration),
|
||||
mRunning(true)
|
||||
GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration)
|
||||
: GuiComponent(window)
|
||||
, mMessage(message)
|
||||
, mDuration(duration)
|
||||
, mRunning(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 the actual expected popup size.
|
||||
s->setSize(0.0f, 0.0f);
|
||||
|
@ -51,13 +48,13 @@ GuiInfoPopup::GuiInfoPopup(
|
|||
mSize[0] = mSize.x() + paddingX;
|
||||
mSize[1] = mSize.y() + paddingY;
|
||||
|
||||
float posX = Renderer::getScreenWidth()* 0.5f - mSize.x() * 0.5f;
|
||||
float posX = Renderer::getScreenWidth() * 0.5f - mSize.x() * 0.5f;
|
||||
float posY = Renderer::getScreenHeight() * 0.02f;
|
||||
|
||||
setPosition(posX, posY, 0);
|
||||
|
||||
mFrame->setImagePath(":/graphics/frame.svg");
|
||||
mFrame->fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
mFrame->fitTo(mSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||
addChild(mFrame);
|
||||
|
||||
// We only initialize the actual time when we first start to render.
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
~GuiInfoPopup();
|
||||
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
inline void stop() override { mRunning = false; }
|
||||
void stop() override { mRunning = false; }
|
||||
|
||||
private:
|
||||
bool updateState();
|
||||
|
|
|
@ -8,20 +8,19 @@
|
|||
|
||||
#include "guis/GuiLaunchScreen.h"
|
||||
|
||||
#include "FileData.h"
|
||||
#include "SystemData.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GuiLaunchScreen::GuiLaunchScreen(
|
||||
Window* window)
|
||||
: GuiComponent(window),
|
||||
mBackground(window, ":/graphics/frame.svg"),
|
||||
mGrid(nullptr),
|
||||
mMarquee(nullptr),
|
||||
mWindow(window)
|
||||
GuiLaunchScreen::GuiLaunchScreen(Window* window)
|
||||
: GuiComponent(window)
|
||||
, mBackground(window, ":/graphics/frame.svg")
|
||||
, mGrid(nullptr)
|
||||
, mMarquee(nullptr)
|
||||
, mWindow(window)
|
||||
{
|
||||
addChild(&mBackground);
|
||||
mWindow->setLaunchScreen(this);
|
||||
|
@ -29,6 +28,7 @@ GuiLaunchScreen::GuiLaunchScreen(
|
|||
|
||||
GuiLaunchScreen::~GuiLaunchScreen()
|
||||
{
|
||||
// This only executes when exiting the application.
|
||||
closeLaunchScreen();
|
||||
}
|
||||
|
||||
|
@ -51,49 +51,53 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
const float gameNameFontSize = 0.073f;
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0),
|
||||
false, false, Vector2i(1, 1));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0), false, false,
|
||||
Vector2i(1, 1));
|
||||
|
||||
// Title.
|
||||
mTitle = std::make_shared<TextComponent>(mWindow, "LAUNCHING GAME",
|
||||
Font::get(static_cast<int>(titleFontSize * std::min(Renderer::getScreenHeight(),
|
||||
Renderer::getScreenWidth()))), 0x666666FF, ALIGN_CENTER);
|
||||
mTitle = std::make_shared<TextComponent>(
|
||||
mWindow, "LAUNCHING GAME",
|
||||
Font::get(static_cast<int>(
|
||||
titleFontSize * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth()))),
|
||||
0x666666FF, ALIGN_CENTER);
|
||||
mGrid->setEntry(mTitle, Vector2i(1, 1), false, true, Vector2i(1, 1));
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 2),
|
||||
false, false, Vector2i(1, 1));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 2), false, false,
|
||||
Vector2i(1, 1));
|
||||
|
||||
// Row for the marquee.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 3),
|
||||
false, false, Vector2i(1, 1));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 3), false, false,
|
||||
Vector2i(1, 1));
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 4),
|
||||
false, false, Vector2i(1, 1));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 4), false, false,
|
||||
Vector2i(1, 1));
|
||||
|
||||
// Game name.
|
||||
mGameName = std::make_shared<TextComponent>(mWindow, "GAME NAME",
|
||||
Font::get(static_cast<int>(gameNameFontSize * std::min(Renderer::getScreenHeight(),
|
||||
Renderer::getScreenWidth()))), 0x444444FF, ALIGN_CENTER);
|
||||
mGameName = std::make_shared<TextComponent>(
|
||||
mWindow, "GAME NAME",
|
||||
Font::get(static_cast<int>(
|
||||
gameNameFontSize * std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth()))),
|
||||
0x444444FF, ALIGN_CENTER);
|
||||
mGrid->setEntry(mGameName, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
||||
|
||||
// System name.
|
||||
mSystemName = std::make_shared<TextComponent>(mWindow, "SYSTEM NAME",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x666666FF, ALIGN_CENTER);
|
||||
mSystemName = std::make_shared<TextComponent>(
|
||||
mWindow, "SYSTEM NAME", Font::get(FONT_SIZE_MEDIUM), 0x666666FF, ALIGN_CENTER);
|
||||
mGrid->setEntry(mSystemName, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
||||
|
||||
// Spacer row.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 7),
|
||||
false, false, Vector2i(1, 1));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 7), false, false,
|
||||
Vector2i(1, 1));
|
||||
|
||||
// Left spacer.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0),
|
||||
false, false, Vector2i(1, 8));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false, false,
|
||||
Vector2i(1, 8));
|
||||
|
||||
// Right spacer.
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(2, 0),
|
||||
false, false, Vector2i(1, 8));
|
||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(2, 0), false, false,
|
||||
Vector2i(1, 8));
|
||||
|
||||
// Adjust the width depending on the aspect ratio of the screen, to make the screen look
|
||||
// somewhat coherent regardless of screen type. The 1.778 aspect ratio value is the 16:9
|
||||
|
@ -106,9 +110,11 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
float maxWidth = static_cast<float>(Renderer::getScreenWidth()) * maxWidthModifier;
|
||||
float minWidth = static_cast<float>(Renderer::getScreenWidth()) * minWidthModifier;
|
||||
|
||||
float fontWidth = Font::get(static_cast<int>(gameNameFontSize *
|
||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))->
|
||||
sizeText(Utils::String::toUpper(game->getName())).x();
|
||||
float fontWidth =
|
||||
Font::get(static_cast<int>(gameNameFontSize * std::min(Renderer::getScreenHeight(),
|
||||
Renderer::getScreenWidth())))
|
||||
->sizeText(Utils::String::toUpper(game->getName()))
|
||||
.x();
|
||||
|
||||
// Add a bit of width to compensate for the left and right spacers.
|
||||
fontWidth += static_cast<float>(Renderer::getScreenWidth()) * 0.05f;
|
||||
|
@ -159,7 +165,8 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
if (mImagePath != "") {
|
||||
mMarquee->setImage(game->getMarqueePath(), false);
|
||||
mMarquee->cropTransparentPadding(static_cast<float>(Renderer::getScreenWidth()) *
|
||||
(0.25f * (1.778f / Renderer::getScreenAspectRatio())), mGrid->getRowHeight(3));
|
||||
(0.25f * (1.778f / Renderer::getScreenAspectRatio())),
|
||||
mGrid->getRowHeight(3));
|
||||
|
||||
mMarquee->setOrigin(0.5f, 0.5f);
|
||||
Vector3f currentPos = mMarquee->getPosition();
|
||||
|
@ -167,18 +174,18 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
|||
|
||||
// Position the image in the middle of row four.
|
||||
currentPos.x() = mSize.x() / 2.0f;
|
||||
currentPos.y() = mGrid->getRowHeight(0) + mGrid->getRowHeight(1) +
|
||||
mGrid->getRowHeight(2) + mGrid->getRowHeight(3) / 2.0f;
|
||||
currentPos.y() = mGrid->getRowHeight(0) + mGrid->getRowHeight(1) + mGrid->getRowHeight(2) +
|
||||
mGrid->getRowHeight(3) / 2.0f;
|
||||
mMarquee->setPosition(currentPos);
|
||||
}
|
||||
|
||||
setOrigin({0.5f, 0.5f});
|
||||
setOrigin({ 0.5f, 0.5f });
|
||||
|
||||
// Center on the X axis and keep slightly off-center on the Y axis.
|
||||
setPosition(static_cast<float>(Renderer::getScreenWidth()) / 2.0f,
|
||||
static_cast<float>(Renderer::getScreenHeight()) / 2.25f);
|
||||
|
||||
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||
mBackground.setEdgeColor(0xEEEEEEFF);
|
||||
}
|
||||
|
||||
|
@ -203,6 +210,7 @@ void GuiLaunchScreen::closeLaunchScreen()
|
|||
|
||||
void GuiLaunchScreen::onSizeChanged()
|
||||
{
|
||||
// Update mGrid size.
|
||||
mGrid->setSize(mSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
#ifndef ES_APP_GUIS_GUI_LAUNCH_SCREEN_H
|
||||
#define ES_APP_GUIS_GUI_LAUNCH_SCREEN_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "Window.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "Window.h"
|
||||
|
||||
class FileData;
|
||||
|
||||
|
@ -35,7 +35,6 @@ public:
|
|||
private:
|
||||
Window* mWindow;
|
||||
ComponentGrid* mGrid;
|
||||
|
||||
NinePatchComponent mBackground;
|
||||
|
||||
std::shared_ptr<TextComponent> mTitle;
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#include "guis/GuiMediaViewerOptions.h"
|
||||
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "Settings.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
|
||||
GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string& title)
|
||||
: GuiSettings(window, title)
|
||||
|
@ -41,7 +41,7 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Render scanlines for videos using a shader.
|
||||
auto video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||
video_scanlines->setState(Settings::getInstance()->getBool("MediaViewerVideoScanlines"));
|
||||
|
@ -60,18 +60,16 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
|||
video_blur->setState(Settings::getInstance()->getBool("MediaViewerVideoBlur"));
|
||||
addWithLabel("RENDER BLUR FOR VIDEOS", video_blur);
|
||||
addSaveFunc([video_blur, this] {
|
||||
if (video_blur->getState() !=
|
||||
Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
||||
Settings::getInstance()->setBool("MediaViewerVideoBlur",
|
||||
video_blur->getState());
|
||||
if (video_blur->getState() != Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
||||
Settings::getInstance()->setBool("MediaViewerVideoBlur", video_blur->getState());
|
||||
setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Render scanlines for screenshots using a shader.
|
||||
auto screenshot_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||
screenshot_scanlines->setState(Settings::getInstance()->
|
||||
getBool("MediaViewerScreenshotScanlines"));
|
||||
screenshot_scanlines->setState(
|
||||
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"));
|
||||
addWithLabel("RENDER SCANLINES FOR SCREENSHOTS", screenshot_scanlines);
|
||||
addSaveFunc([screenshot_scanlines, this] {
|
||||
if (screenshot_scanlines->getState() !=
|
||||
|
@ -81,5 +79,5 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
|||
setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -9,6 +9,14 @@
|
|||
|
||||
#include "guis/GuiMenu.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "EmulationStation.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "FileSorts.h"
|
||||
#include "Platform.h"
|
||||
#include "Scripting.h"
|
||||
#include "SystemData.h"
|
||||
#include "VolumeControl.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "components/SliderComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
|
@ -19,23 +27,17 @@
|
|||
#include "guis/GuiMsgBox.h"
|
||||
#include "guis/GuiScraperMenu.h"
|
||||
#include "guis/GuiScreensaverOptions.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "EmulationStation.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "FileSorts.h"
|
||||
#include "Platform.h"
|
||||
#include "Scripting.h"
|
||||
#include "SystemData.h"
|
||||
#include "VolumeControl.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <algorithm>
|
||||
|
||||
GuiMenu::GuiMenu(Window* window) : GuiComponent(window),
|
||||
mMenu(window, "MAIN MENU"), mVersion(window)
|
||||
GuiMenu::GuiMenu(Window* window)
|
||||
: GuiComponent(window)
|
||||
, mMenu(window, "MAIN MENU")
|
||||
, mVersion(window)
|
||||
{
|
||||
bool isFullUI = UIModeController::getInstance()->isUIModeFull();
|
||||
|
||||
|
@ -48,27 +50,26 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window),
|
|||
addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundOptions(); });
|
||||
|
||||
if (isFullUI)
|
||||
addEntry("INPUT DEVICE SETTINGS", 0x777777FF, true, [this] {
|
||||
openInputDeviceOptions(); });
|
||||
addEntry("INPUT DEVICE SETTINGS", 0x777777FF, true, [this] { openInputDeviceOptions(); });
|
||||
|
||||
if (isFullUI)
|
||||
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true, [this] {
|
||||
openCollectionSystemOptions(); });
|
||||
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true,
|
||||
[this] { openCollectionSystemOptions(); });
|
||||
|
||||
if (isFullUI)
|
||||
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherOptions(); });
|
||||
|
||||
// TEMPORARY - disabled for now, will be used in the future.
|
||||
// if (isFullUI)
|
||||
// addEntry("UTILITIES", 0x777777FF, true, [this] {
|
||||
// openUtilitiesMenu(); });
|
||||
// if (isFullUI)
|
||||
// addEntry("UTILITIES", 0x777777FF, true, [this] {
|
||||
// openUtilitiesMenu(); });
|
||||
|
||||
if (!Settings::getInstance()->getBool("ForceKiosk") &&
|
||||
Settings::getInstance()->getString("UIMode") != "kiosk") {
|
||||
if (Settings::getInstance()->getBool("ShowQuitMenu"))
|
||||
addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); });
|
||||
addEntry("QUIT", 0x777777FF, true, [this] { openQuitMenu(); });
|
||||
else
|
||||
addEntry("QUIT EMULATIONSTATION", 0x777777FF, false, [this] {openQuitMenu(); });
|
||||
addEntry("QUIT EMULATIONSTATION", 0x777777FF, false, [this] { openQuitMenu(); });
|
||||
}
|
||||
|
||||
addChild(&mMenu);
|
||||
|
@ -86,26 +87,24 @@ GuiMenu::~GuiMenu()
|
|||
ViewController::get()->stopScrolling();
|
||||
}
|
||||
|
||||
void GuiMenu::openScraperOptions()
|
||||
{
|
||||
mWindow->pushGui(new GuiScraperMenu(mWindow, "SCRAPER"));
|
||||
}
|
||||
void GuiMenu::openScraperOptions() { mWindow->pushGui(new GuiScraperMenu(mWindow, "SCRAPER")); }
|
||||
|
||||
void GuiMenu::openUIOptions()
|
||||
{
|
||||
auto s = new GuiSettings(mWindow, "UI SETTINGS");
|
||||
|
||||
// Optionally start in selected system/gamelist.
|
||||
auto startup_system = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "GAMELIST ON STARTUP", false);
|
||||
auto startup_system = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "GAMELIST ON STARTUP", false);
|
||||
startup_system->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == "");
|
||||
float dotsSize = Font::get(FONT_SIZE_MEDIUM)->sizeText("...").x();
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||
it++) {
|
||||
if ((*it)->getName() != "retropie") {
|
||||
// If required, abbreviate the system name so it doesn't overlap the setting name.
|
||||
std::string abbreviatedString = Font::get(FONT_SIZE_MEDIUM)->
|
||||
getTextMaxWidth((*it)->getFullName(), mSize.x() * 0.47f);
|
||||
std::string abbreviatedString =
|
||||
Font::get(FONT_SIZE_MEDIUM)
|
||||
->getTextMaxWidth((*it)->getFullName(), mSize.x() * 0.47f);
|
||||
float sizeDifference = Font::get(FONT_SIZE_MEDIUM)->sizeText((*it)->getFullName()).x() -
|
||||
Font::get(FONT_SIZE_MEDIUM)->sizeText(abbreviatedString).x();
|
||||
if (sizeDifference > 0) {
|
||||
|
@ -122,7 +121,8 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
}
|
||||
startup_system->add(abbreviatedString, (*it)->getName(),
|
||||
Settings::getInstance()->getString("StartupSystem") == (*it)->getName());
|
||||
Settings::getInstance()->getString("StartupSystem") ==
|
||||
(*it)->getName());
|
||||
}
|
||||
}
|
||||
s->addWithLabel("GAMELIST ON STARTUP", startup_system);
|
||||
|
@ -134,8 +134,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// GameList view style.
|
||||
auto gamelist_view_style = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "GAMELIST VIEW STYLE", false);
|
||||
auto gamelist_view_style = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "GAMELIST VIEW STYLE", false);
|
||||
std::string selectedViewStyle = Settings::getInstance()->getString("GamelistViewStyle");
|
||||
gamelist_view_style->add("automatic", "automatic", selectedViewStyle == "automatic");
|
||||
gamelist_view_style->add("basic", "basic", selectedViewStyle == "basic");
|
||||
|
@ -159,15 +159,15 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Transition style.
|
||||
auto transition_style = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "TRANSITION STYLE", false);
|
||||
auto transition_style = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "TRANSITION STYLE", false);
|
||||
std::vector<std::string> transitions;
|
||||
transitions.push_back("slide");
|
||||
transitions.push_back("fade");
|
||||
transitions.push_back("instant");
|
||||
for (auto it = transitions.cbegin(); it != transitions.cend(); it++)
|
||||
transition_style->add(*it, *it, Settings::getInstance()->
|
||||
getString("TransitionStyle") == *it);
|
||||
transition_style->add(*it, *it,
|
||||
Settings::getInstance()->getString("TransitionStyle") == *it);
|
||||
s->addWithLabel("TRANSITION STYLE", transition_style);
|
||||
s->addSaveFunc([transition_style, s] {
|
||||
if (transition_style->getSelected() !=
|
||||
|
@ -184,8 +184,8 @@ void GuiMenu::openUIOptions()
|
|||
themeSets.find(Settings::getInstance()->getString("ThemeSet"));
|
||||
if (selectedSet == themeSets.cend())
|
||||
selectedSet = themeSets.cbegin();
|
||||
auto theme_set = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "THEME SET", false);
|
||||
auto theme_set = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
"THEME SET", false);
|
||||
for (auto it = themeSets.cbegin(); it != themeSets.cend(); it++)
|
||||
theme_set->add(it->first, it->first, it == selectedSet);
|
||||
s->addWithLabel("THEME SET", theme_set);
|
||||
|
@ -211,8 +211,8 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
|
||||
// UI mode.
|
||||
auto ui_mode = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "UI MODE", false);
|
||||
auto ui_mode = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
"UI MODE", false);
|
||||
std::vector<std::string> uiModes;
|
||||
uiModes.push_back("full");
|
||||
uiModes.push_back("kiosk");
|
||||
|
@ -250,8 +250,9 @@ void GuiMenu::openUIOptions()
|
|||
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?";
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, this->getHelpStyle(), msg,
|
||||
"YES", [this, selectedMode] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, this->getHelpStyle(), msg, "YES",
|
||||
[this, selectedMode] {
|
||||
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '"
|
||||
<< selectedMode << "'.";
|
||||
Settings::getInstance()->setString("UIMode", selectedMode);
|
||||
|
@ -273,11 +274,12 @@ void GuiMenu::openUIOptions()
|
|||
ViewController::get()->reloadAll();
|
||||
ViewController::get()->goToSystem(SystemData::sSystemVector.front(), false);
|
||||
mWindow->invalidateCachedBackground();
|
||||
}, "NO", nullptr));
|
||||
},
|
||||
"NO", nullptr));
|
||||
}
|
||||
else {
|
||||
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" <<
|
||||
selectedMode << "'.";
|
||||
LOG(LogDebug) << "GuiMenu::openUISettings(): Setting UI mode to '" << selectedMode
|
||||
<< "'.";
|
||||
Settings::getInstance()->setString("UIMode", ui_mode->getSelected());
|
||||
Settings::getInstance()->setBool("ForceFull", false);
|
||||
Settings::getInstance()->setBool("ForceKiosk", false);
|
||||
|
@ -296,8 +298,8 @@ void GuiMenu::openUIOptions()
|
|||
// Default gamelist sort order.
|
||||
typedef OptionListComponent<const FileData::SortType*> SortList;
|
||||
std::string sortOrder;
|
||||
auto default_sort_order = std::make_shared<SortList>
|
||||
(mWindow, getHelpStyle(), "DEFAULT SORT ORDER", false);
|
||||
auto default_sort_order =
|
||||
std::make_shared<SortList>(mWindow, getHelpStyle(), "DEFAULT SORT ORDER", false);
|
||||
// Exclude the System sort options.
|
||||
unsigned int numSortTypes = static_cast<unsigned int>(FileSorts::SortTypes.size() - 2);
|
||||
for (unsigned int i = 0; i < numSortTypes; i++) {
|
||||
|
@ -331,8 +333,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Open menu effect.
|
||||
auto menu_opening_effect = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "MENU OPENING EFFECT", false);
|
||||
auto menu_opening_effect = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "MENU OPENING EFFECT", false);
|
||||
std::string selectedMenuEffect = Settings::getInstance()->getString("MenuOpeningEffect");
|
||||
menu_opening_effect->add("SCALE-UP", "scale-up", selectedMenuEffect == "scale-up");
|
||||
menu_opening_effect->add("NONE", "none", selectedMenuEffect == "none");
|
||||
|
@ -351,8 +353,8 @@ void GuiMenu::openUIOptions()
|
|||
});
|
||||
|
||||
// Launch screen duration.
|
||||
auto launch_screen_duration = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "LAUNCH SCREEN DURATION", false);
|
||||
auto launch_screen_duration = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "LAUNCH SCREEN DURATION", false);
|
||||
std::string selectedDuration = Settings::getInstance()->getString("LaunchScreenDuration");
|
||||
launch_screen_duration->add("NORMAL", "normal", selectedDuration == "normal");
|
||||
launch_screen_duration->add("BRIEF", "brief", selectedDuration == "brief");
|
||||
|
@ -372,7 +374,7 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Blur background when the menu is open.
|
||||
auto menu_blur_background = std::make_shared<SwitchComponent>(mWindow);
|
||||
menu_blur_background->setState(Settings::getInstance()->getBool("MenuBlurBackground"));
|
||||
|
@ -386,7 +388,7 @@ void GuiMenu::openUIOptions()
|
|||
s->setInvalidateCachedBackground();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Display pillarboxes (and letterboxes) for videos in the gamelists.
|
||||
auto gamelist_video_pillarbox = std::make_shared<SwitchComponent>(mWindow);
|
||||
|
@ -401,7 +403,7 @@ void GuiMenu::openUIOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Render scanlines for videos in the gamelists.
|
||||
auto gamelist_video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||
gamelist_video_scanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines"));
|
||||
|
@ -414,15 +416,14 @@ void GuiMenu::openUIOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Sort folders on top of the gamelists.
|
||||
auto folders_on_top = std::make_shared<SwitchComponent>(mWindow);
|
||||
folders_on_top->setState(Settings::getInstance()->getBool("FoldersOnTop"));
|
||||
s->addWithLabel("SORT FOLDERS ON TOP OF GAMELISTS", folders_on_top);
|
||||
s->addSaveFunc([folders_on_top, s] {
|
||||
if (folders_on_top->getState() !=
|
||||
Settings::getInstance()->getBool("FoldersOnTop")) {
|
||||
if (folders_on_top->getState() != Settings::getInstance()->getBool("FoldersOnTop")) {
|
||||
Settings::getInstance()->setBool("FoldersOnTop", folders_on_top->getState());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsSorting();
|
||||
|
@ -434,9 +435,8 @@ void GuiMenu::openUIOptions()
|
|||
auto favorites_first = std::make_shared<SwitchComponent>(mWindow);
|
||||
favorites_first->setState(Settings::getInstance()->getBool("FavoritesFirst"));
|
||||
s->addWithLabel("SORT FAVORITE GAMES ABOVE NON-FAVORITES", favorites_first);
|
||||
s->addSaveFunc([favorites_first,s ] {
|
||||
if (favorites_first->getState() !=
|
||||
Settings::getInstance()->getBool("FavoritesFirst")) {
|
||||
s->addSaveFunc([favorites_first, s] {
|
||||
if (favorites_first->getState() != Settings::getInstance()->getBool("FavoritesFirst")) {
|
||||
Settings::getInstance()->setBool("FavoritesFirst", favorites_first->getState());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsSorting();
|
||||
|
@ -465,8 +465,7 @@ void GuiMenu::openUIOptions()
|
|||
s->addSaveFunc([special_chars_ascii, s] {
|
||||
if (special_chars_ascii->getState() !=
|
||||
Settings::getInstance()->getBool("SpecialCharsASCII")) {
|
||||
Settings::getInstance()->setBool("SpecialCharsASCII",
|
||||
special_chars_ascii->getState());
|
||||
Settings::getInstance()->setBool("SpecialCharsASCII", special_chars_ascii->getState());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
s->setInvalidateCachedBackground();
|
||||
|
@ -503,10 +502,8 @@ void GuiMenu::openUIOptions()
|
|||
random_add_button->setState(Settings::getInstance()->getBool("RandomAddButton"));
|
||||
s->addWithLabel("ENABLE RANDOM SYSTEM OR GAME BUTTON", random_add_button);
|
||||
s->addSaveFunc([random_add_button, s] {
|
||||
if (Settings::getInstance()->getBool("RandomAddButton") !=
|
||||
random_add_button->getState()) {
|
||||
Settings::getInstance()->setBool("RandomAddButton",
|
||||
random_add_button->getState());
|
||||
if (Settings::getInstance()->getBool("RandomAddButton") != random_add_button->getState()) {
|
||||
Settings::getInstance()->setBool("RandomAddButton", random_add_button->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -516,8 +513,7 @@ void GuiMenu::openUIOptions()
|
|||
gamelist_filters->setState(Settings::getInstance()->getBool("GamelistFilters"));
|
||||
s->addWithLabel("ENABLE GAMELIST FILTERS", gamelist_filters);
|
||||
s->addSaveFunc([gamelist_filters, s] {
|
||||
if (Settings::getInstance()->getBool("GamelistFilters") !=
|
||||
gamelist_filters->getState()) {
|
||||
if (Settings::getInstance()->getBool("GamelistFilters") != gamelist_filters->getState()) {
|
||||
Settings::getInstance()->setBool("GamelistFilters", gamelist_filters->getState());
|
||||
s->setNeedsSaving();
|
||||
s->setNeedsReloading();
|
||||
|
@ -563,8 +559,10 @@ void GuiMenu::openUIOptions()
|
|||
// Media viewer.
|
||||
ComponentListRow media_viewer_row;
|
||||
media_viewer_row.elements.clear();
|
||||
media_viewer_row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "MEDIA VIEWER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
media_viewer_row.addElement(std::make_shared<TextComponent>(mWindow, "MEDIA VIEWER SETTINGS",
|
||||
Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF),
|
||||
true);
|
||||
media_viewer_row.addElement(makeArrow(mWindow), false);
|
||||
media_viewer_row.makeAcceptInputHandler(std::bind(&GuiMenu::openMediaViewerOptions, this));
|
||||
s->addRow(media_viewer_row);
|
||||
|
@ -572,8 +570,10 @@ void GuiMenu::openUIOptions()
|
|||
// Screensaver.
|
||||
ComponentListRow screensaver_row;
|
||||
screensaver_row.elements.clear();
|
||||
screensaver_row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
screensaver_row.addElement(std::make_shared<TextComponent>(mWindow, "SCREENSAVER SETTINGS",
|
||||
Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF),
|
||||
true);
|
||||
screensaver_row.addElement(makeArrow(mWindow), false);
|
||||
screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
|
||||
s->addRow(screensaver_row);
|
||||
|
@ -585,28 +585,27 @@ void GuiMenu::openSoundOptions()
|
|||
{
|
||||
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
|
||||
|
||||
// TEMPORARY - Hide the volume slider on macOS and BSD Unix until the volume control logic
|
||||
// has been implemented for these operating systems.
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
// TEMPORARY - Hide the volume slider on macOS and BSD Unix until the volume control logic
|
||||
// has been implemented for these operating systems.
|
||||
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
||||
// System volume.
|
||||
auto system_volume = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||
system_volume->setValue(static_cast<float>(VolumeControl::getInstance()->getVolume()));
|
||||
s->addWithLabel("SYSTEM VOLUME", system_volume);
|
||||
s->addSaveFunc([system_volume] {
|
||||
VolumeControl::getInstance()->
|
||||
setVolume(static_cast<int>(std::round(system_volume->getValue())));
|
||||
VolumeControl::getInstance()->setVolume(
|
||||
static_cast<int>(std::round(system_volume->getValue())));
|
||||
// Explicitly delete the VolumeControl instance so that it will reinitialize the
|
||||
// next time the menu is entered. This is the easiest way to detect new default
|
||||
// audio devices or changes to the audio volume done by the operating system.
|
||||
VolumeControl::getInstance()->deleteInstance();
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Volume for navigation sounds.
|
||||
auto sound_volume_navigation =
|
||||
std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||
sound_volume_navigation->setValue(static_cast<float>(Settings::getInstance()->
|
||||
getInt("SoundVolumeNavigation")));
|
||||
auto sound_volume_navigation = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||
sound_volume_navigation->setValue(
|
||||
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeNavigation")));
|
||||
s->addWithLabel("NAVIGATION SOUNDS VOLUME", sound_volume_navigation);
|
||||
s->addSaveFunc([sound_volume_navigation, s] {
|
||||
if (sound_volume_navigation->getValue() !=
|
||||
|
@ -618,10 +617,9 @@ void GuiMenu::openSoundOptions()
|
|||
});
|
||||
|
||||
// Volume for videos.
|
||||
auto sound_volume_videos =
|
||||
std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||
sound_volume_videos->setValue(static_cast<float>(Settings::getInstance()->
|
||||
getInt("SoundVolumeVideos")));
|
||||
auto sound_volume_videos = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||
sound_volume_videos->setValue(
|
||||
static_cast<float>(Settings::getInstance()->getInt("SoundVolumeVideos")));
|
||||
s->addWithLabel("VIDEO PLAYER VOLUME", sound_volume_videos);
|
||||
s->addSaveFunc([sound_volume_videos, s] {
|
||||
if (sound_volume_videos->getValue() !=
|
||||
|
@ -641,17 +639,17 @@ void GuiMenu::openSoundOptions()
|
|||
// The code is still active for Raspberry Pi though as I'm not sure if this is
|
||||
// useful for that device.
|
||||
// #if defined(__linux__)
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// Audio card.
|
||||
auto audio_card = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "AUDIO CARD", false);
|
||||
auto audio_card = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "AUDIO CARD", false);
|
||||
std::vector<std::string> audio_cards;
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// RPi Specific Audio Cards.
|
||||
audio_cards.push_back("local");
|
||||
audio_cards.push_back("hdmi");
|
||||
audio_cards.push_back("both");
|
||||
#endif
|
||||
#endif
|
||||
audio_cards.push_back("default");
|
||||
audio_cards.push_back("sysdefault");
|
||||
audio_cards.push_back("dmix");
|
||||
|
@ -677,8 +675,8 @@ void GuiMenu::openSoundOptions()
|
|||
});
|
||||
|
||||
// Volume control device.
|
||||
auto vol_dev = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "AUDIO DEVICE", false);
|
||||
auto vol_dev = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
"AUDIO DEVICE", false);
|
||||
std::vector<std::string> transitions;
|
||||
transitions.push_back("PCM");
|
||||
transitions.push_back("Speaker");
|
||||
|
@ -702,12 +700,12 @@ void GuiMenu::openSoundOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// OMXPlayer audio device.
|
||||
auto omx_audio_dev = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "OMX PLAYER AUDIO DEVICE", false);
|
||||
auto omx_audio_dev = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "OMX PLAYER AUDIO DEVICE", false);
|
||||
std::vector<std::string> omx_cards;
|
||||
// RPi Specific Audio Cards
|
||||
omx_cards.push_back("local");
|
||||
|
@ -725,13 +723,12 @@ void GuiMenu::openSoundOptions()
|
|||
omx_audio_dev->add(*it, *it, Settings::getInstance()->getString("OMXAudioDev") == *it);
|
||||
s->addWithLabel("OMX PLAYER AUDIO DEVICE", omx_audio_dev);
|
||||
s->addSaveFunc([omx_audio_dev, s] {
|
||||
if (omx_audio_dev->getSelected() !=
|
||||
Settings::getInstance()->getString("OMXAudioDev")) {
|
||||
if (omx_audio_dev->getSelected() != Settings::getInstance()->getString("OMXAudioDev")) {
|
||||
Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Play audio for gamelist videos.
|
||||
auto gamelist_video_audio = std::make_shared<SwitchComponent>(mWindow);
|
||||
|
@ -748,8 +745,8 @@ void GuiMenu::openSoundOptions()
|
|||
|
||||
// Play audio for media viewer videos.
|
||||
auto media_viewer_video_audio = std::make_shared<SwitchComponent>(mWindow);
|
||||
media_viewer_video_audio->setState(Settings::getInstance()->
|
||||
getBool("MediaViewerVideoAudio"));
|
||||
media_viewer_video_audio->setState(
|
||||
Settings::getInstance()->getBool("MediaViewerVideoAudio"));
|
||||
s->addWithLabel("PLAY AUDIO FOR MEDIA VIEWER VIDEOS", media_viewer_video_audio);
|
||||
s->addSaveFunc([media_viewer_video_audio, s] {
|
||||
if (media_viewer_video_audio->getState() !=
|
||||
|
@ -762,8 +759,8 @@ void GuiMenu::openSoundOptions()
|
|||
|
||||
// Play audio for screensaver videos.
|
||||
auto screensaver_video_audio = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_video_audio->setState(Settings::getInstance()->
|
||||
getBool("ScreensaverVideoAudio"));
|
||||
screensaver_video_audio->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverVideoAudio"));
|
||||
s->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEOS", screensaver_video_audio);
|
||||
s->addSaveFunc([screensaver_video_audio, s] {
|
||||
if (screensaver_video_audio->getState() !=
|
||||
|
@ -776,14 +773,12 @@ void GuiMenu::openSoundOptions()
|
|||
|
||||
// Navigation sounds.
|
||||
auto navigation_sounds = std::make_shared<SwitchComponent>(mWindow);
|
||||
navigation_sounds->setState(Settings::getInstance()->
|
||||
getBool("NavigationSounds"));
|
||||
navigation_sounds->setState(Settings::getInstance()->getBool("NavigationSounds"));
|
||||
s->addWithLabel("ENABLE NAVIGATION SOUNDS", navigation_sounds);
|
||||
s->addSaveFunc([navigation_sounds, s] {
|
||||
if (navigation_sounds->getState() !=
|
||||
Settings::getInstance()->getBool("NavigationSounds")) {
|
||||
Settings::getInstance()->setBool("NavigationSounds",
|
||||
navigation_sounds->getState());
|
||||
Settings::getInstance()->setBool("NavigationSounds", navigation_sounds->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -797,8 +792,8 @@ void GuiMenu::openInputDeviceOptions()
|
|||
auto s = new GuiSettings(mWindow, "INPUT DEVICE SETTINGS");
|
||||
|
||||
// Controller type.
|
||||
auto input_controller_type = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "CONTROLLER TYPE", false);
|
||||
auto input_controller_type = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "CONTROLLER TYPE", false);
|
||||
std::string selectedPlayer = Settings::getInstance()->getString("InputControllerType");
|
||||
input_controller_type->add("XBOX", "xbox", selectedPlayer == "xbox");
|
||||
input_controller_type->add("XBOX 360", "xbox360", selectedPlayer == "xbox360");
|
||||
|
@ -822,8 +817,8 @@ void GuiMenu::openInputDeviceOptions()
|
|||
|
||||
// Whether to only accept input from the first controller.
|
||||
auto input_only_first_controller = std::make_shared<SwitchComponent>(mWindow);
|
||||
input_only_first_controller->setState(Settings::getInstance()->
|
||||
getBool("InputOnlyFirstController"));
|
||||
input_only_first_controller->setState(
|
||||
Settings::getInstance()->getBool("InputOnlyFirstController"));
|
||||
s->addWithLabel("ONLY ACCEPT INPUT FROM FIRST CONTROLLER", input_only_first_controller);
|
||||
s->addSaveFunc([input_only_first_controller, s] {
|
||||
if (Settings::getInstance()->getBool("InputOnlyFirstController") !=
|
||||
|
@ -837,9 +832,10 @@ void GuiMenu::openInputDeviceOptions()
|
|||
// Configure keyboard and controllers.
|
||||
ComponentListRow configure_input_row;
|
||||
configure_input_row.elements.clear();
|
||||
configure_input_row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "CONFIGURE KEYBOARD AND CONTROLLERS",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
configure_input_row.addElement(
|
||||
std::make_shared<TextComponent>(mWindow, "CONFIGURE KEYBOARD AND CONTROLLERS",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
configure_input_row.addElement(makeArrow(mWindow), false);
|
||||
configure_input_row.makeAcceptInputHandler(std::bind(&GuiMenu::openConfigInput, this, s));
|
||||
s->addRow(configure_input_row);
|
||||
|
@ -856,18 +852,17 @@ void GuiMenu::openConfigInput(GuiSettings* settings)
|
|||
// the input device settings menu later on.
|
||||
settings->setNeedsSaving(false);
|
||||
|
||||
std::string message =
|
||||
"THE KEYBOARD AND CONTROLLERS ARE AUTOMATICALLY\n"
|
||||
std::string message = "THE KEYBOARD AND CONTROLLERS ARE AUTOMATICALLY\n"
|
||||
"CONFIGURED, BUT USING THIS CONFIGURATION TOOL\n"
|
||||
"YOU CAN OVERRIDE THE DEFAULT BUTTON MAPPINGS\n"
|
||||
"(THIS WILL NOT AFFECT THE HELP PROMPTS)\n"
|
||||
"CONTINUE?";
|
||||
|
||||
Window* window = mWindow;
|
||||
window->pushGui(new GuiMsgBox(window, getHelpStyle(),
|
||||
message, "YES", [window] {
|
||||
window->pushGui(new GuiDetectDevice(window, false, false, nullptr));
|
||||
}, "NO", nullptr));
|
||||
window->pushGui(new GuiMsgBox(
|
||||
window, getHelpStyle(), message, "YES",
|
||||
[window] { window->pushGui(new GuiDetectDevice(window, false, false, nullptr)); }, "NO",
|
||||
nullptr));
|
||||
}
|
||||
|
||||
void GuiMenu::openOtherOptions()
|
||||
|
@ -887,8 +882,8 @@ void GuiMenu::openOtherOptions()
|
|||
});
|
||||
|
||||
// Display/monitor.
|
||||
auto display_index = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "DISPLAY/MONITOR INDEX", false);
|
||||
auto display_index = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "DISPLAY/MONITOR INDEX", false);
|
||||
std::vector<std::string> displayIndex;
|
||||
displayIndex.push_back("1");
|
||||
displayIndex.push_back("2");
|
||||
|
@ -907,10 +902,10 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(__unix__)
|
||||
#if defined(__unix__)
|
||||
// Fullscreen mode.
|
||||
auto fullscreen_mode = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "FULLSCREEN MODE", false);
|
||||
auto fullscreen_mode = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "FULLSCREEN MODE", false);
|
||||
std::vector<std::string> screenmode;
|
||||
screenmode.push_back("normal");
|
||||
screenmode.push_back("borderless");
|
||||
|
@ -924,12 +919,12 @@ void GuiMenu::openOtherOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
// Video player.
|
||||
auto video_player = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "FULLSCREEN MODE", false);
|
||||
auto video_player = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "FULLSCREEN MODE", false);
|
||||
std::string selectedPlayer = Settings::getInstance()->getString("VideoPlayer");
|
||||
video_player->add("FFmpeg", "ffmpeg", selectedPlayer == "ffmpeg");
|
||||
video_player->add("VLC", "vlc", selectedPlayer == "vlc");
|
||||
|
@ -945,18 +940,18 @@ void GuiMenu::openOtherOptions()
|
|||
s->setNeedsReloading();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// When to save game metadata.
|
||||
auto save_gamelist_mode = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "WHEN TO SAVE METADATA", false);
|
||||
auto save_gamelist_mode = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "WHEN TO SAVE METADATA", false);
|
||||
std::vector<std::string> saveModes;
|
||||
saveModes.push_back("on exit");
|
||||
saveModes.push_back("always");
|
||||
saveModes.push_back("never");
|
||||
for (auto it = saveModes.cbegin(); it != saveModes.cend(); it++) {
|
||||
save_gamelist_mode->add(*it, *it, Settings::getInstance()->
|
||||
getString("SaveGamelistsMode") == *it);
|
||||
save_gamelist_mode->add(*it, *it,
|
||||
Settings::getInstance()->getString("SaveGamelistsMode") == *it);
|
||||
}
|
||||
s->addWithLabel("WHEN TO SAVE GAME METADATA", save_gamelist_mode);
|
||||
s->addSaveFunc([save_gamelist_mode, s] {
|
||||
|
@ -964,7 +959,7 @@ void GuiMenu::openOtherOptions()
|
|||
Settings::getInstance()->getString("SaveGamelistsMode")) {
|
||||
Settings::getInstance()->setString("SaveGamelistsMode",
|
||||
save_gamelist_mode->getSelected());
|
||||
// Always save the gamelist.xml files if switching to 'always' as there may
|
||||
// Always save the gamelist.xml files if switching to "always" as there may
|
||||
// be changes that will otherwise be lost.
|
||||
if (Settings::getInstance()->getString("SaveGamelistsMode") == "always") {
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
|
@ -996,56 +991,55 @@ void GuiMenu::openOtherOptions()
|
|||
mWindow->invalidateCachedBackground();
|
||||
};
|
||||
rowMediaDir.makeAcceptInputHandler([this, titleMediaDir, mediaDirectoryStaticText,
|
||||
defaultDirectoryText, initValueMediaDir, updateValMediaDir, multiLineMediaDir] {
|
||||
mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, getHelpStyle(),
|
||||
titleMediaDir, mediaDirectoryStaticText, defaultDirectoryText,
|
||||
Settings::getInstance()->getString("MediaDirectory"),
|
||||
updateValMediaDir, multiLineMediaDir, "SAVE", "SAVE CHANGES?"));
|
||||
defaultDirectoryText, initValueMediaDir, updateValMediaDir,
|
||||
multiLineMediaDir] {
|
||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
||||
mWindow, getHelpStyle(), titleMediaDir, mediaDirectoryStaticText, defaultDirectoryText,
|
||||
Settings::getInstance()->getString("MediaDirectory"), updateValMediaDir,
|
||||
multiLineMediaDir, "SAVE", "SAVE CHANGES?"));
|
||||
});
|
||||
s->addRow(rowMediaDir);
|
||||
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// Video playing using OMXPlayer.
|
||||
auto video_omx_player = std::make_shared<SwitchComponent>(mWindow);
|
||||
video_omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer"));
|
||||
s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", video_omx_player);
|
||||
s->addSaveFunc([video_omx_player, s] {
|
||||
if (video_omx_player->getState() !=
|
||||
Settings::getInstance()->getBool("VideoOmxPlayer")) {
|
||||
if (video_omx_player->getState() != Settings::getInstance()->getBool("VideoOmxPlayer")) {
|
||||
Settings::getInstance()->setBool("VideoOmxPlayer", video_omx_player->getState());
|
||||
s->setNeedsSaving();
|
||||
// Need to reload all views to re-create the right video components.
|
||||
s->setNeedsReloading();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Hide taskbar during the ES program session.
|
||||
auto hide_taskbar = std::make_shared<SwitchComponent>(mWindow);
|
||||
hide_taskbar->setState(Settings::getInstance()->getBool("HideTaskbar"));
|
||||
s->addWithLabel("HIDE TASKBAR (REQUIRES RESTART)", hide_taskbar);
|
||||
s->addSaveFunc([hide_taskbar, s] {
|
||||
if (hide_taskbar->getState() !=
|
||||
Settings::getInstance()->getBool("HideTaskbar")) {
|
||||
Settings::getInstance()-> setBool("HideTaskbar", hide_taskbar->getState());
|
||||
if (hide_taskbar->getState() != Settings::getInstance()->getBool("HideTaskbar")) {
|
||||
Settings::getInstance()->setBool("HideTaskbar", hide_taskbar->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Run ES in the background when a game has been launched.
|
||||
auto run_in_background = std::make_shared<SwitchComponent>(mWindow);
|
||||
run_in_background->setState(Settings::getInstance()->getBool("RunInBackground"));
|
||||
s->addWithLabel("RUN IN BACKGROUND (WHILE GAME IS LAUNCHED)", run_in_background);
|
||||
s->addSaveFunc([run_in_background,s] {
|
||||
s->addSaveFunc([run_in_background, s] {
|
||||
if (run_in_background->getState() != Settings::getInstance()->getBool("RunInBackground")) {
|
||||
Settings::getInstance()->setBool("RunInBackground", run_in_background->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Workaround for launching games on AMD and Intel graphics drivers.
|
||||
auto launch_workaround = std::make_shared<SwitchComponent>(mWindow);
|
||||
launch_workaround->setState(Settings::getInstance()->getBool("LaunchWorkaround"));
|
||||
|
@ -1061,24 +1055,25 @@ void GuiMenu::openOtherOptions()
|
|||
if (Settings::getInstance()->getBool("RunInBackground")) {
|
||||
launch_workaround->setEnabled(false);
|
||||
launch_workaround->setOpacity(DISABLED_OPACITY);
|
||||
launch_workaround->getParent()->getChild(launch_workaround->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
launch_workaround->getParent()
|
||||
->getChild(launch_workaround->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Whether to upscale the video frame rate to 60 FPS.
|
||||
auto video_upscale_frame_rate = std::make_shared<SwitchComponent>(mWindow);
|
||||
video_upscale_frame_rate->setState(Settings::getInstance()->getBool("VideoUpscaleFrameRate"));
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
#if defined(BUILD_VLC_PLAYER)
|
||||
s->addWithLabel("UPSCALE VIDEO FRAME RATE TO 60 FPS (FFMPEG)", video_upscale_frame_rate);
|
||||
#else
|
||||
#else
|
||||
s->addWithLabel("UPSCALE VIDEO FRAME RATE TO 60 FPS", video_upscale_frame_rate);
|
||||
#endif
|
||||
#endif
|
||||
s->addSaveFunc([video_upscale_frame_rate, s] {
|
||||
if (video_upscale_frame_rate->getState() !=
|
||||
Settings::getInstance()->getBool("VideoUpscaleFrameRate")) {
|
||||
Settings::getInstance()->
|
||||
setBool("VideoUpscaleFrameRate", video_upscale_frame_rate->getState());
|
||||
Settings::getInstance()->setBool("VideoUpscaleFrameRate",
|
||||
video_upscale_frame_rate->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -1091,8 +1086,8 @@ void GuiMenu::openOtherOptions()
|
|||
s->addSaveFunc([launchcommand_override, s] {
|
||||
if (launchcommand_override->getState() !=
|
||||
Settings::getInstance()->getBool("LaunchCommandOverride")) {
|
||||
Settings::getInstance()->
|
||||
setBool("LaunchCommandOverride", launchcommand_override->getState());
|
||||
Settings::getInstance()->setBool("LaunchCommandOverride",
|
||||
launchcommand_override->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -1143,7 +1138,7 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(__unix__)
|
||||
#if defined(__unix__)
|
||||
// Whether to disable desktop composition.
|
||||
auto disable_composition = std::make_shared<SwitchComponent>(mWindow);
|
||||
disable_composition->setState(Settings::getInstance()->getBool("DisableComposition"));
|
||||
|
@ -1151,12 +1146,11 @@ void GuiMenu::openOtherOptions()
|
|||
s->addSaveFunc([disable_composition, s] {
|
||||
if (disable_composition->getState() !=
|
||||
Settings::getInstance()->getBool("DisableComposition")) {
|
||||
Settings::getInstance()->setBool("DisableComposition",
|
||||
disable_composition->getState());
|
||||
Settings::getInstance()->setBool("DisableComposition", disable_composition->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// GPU statistics overlay.
|
||||
auto display_gpu_statistics = std::make_shared<SwitchComponent>(mWindow);
|
||||
|
@ -1183,41 +1177,42 @@ void GuiMenu::openOtherOptions()
|
|||
}
|
||||
});
|
||||
|
||||
// macOS requires root privileges to reboot and power off so it doesn't make much
|
||||
// sense to enable this setting and menu entry for that operating system.
|
||||
#if !defined(__APPLE__)
|
||||
// macOS requires root privileges to reboot and power off so it doesn't make much
|
||||
// sense to enable this setting and menu entry for that operating system.
|
||||
#if !defined(__APPLE__)
|
||||
// Whether to show the quit menu with the options to reboot and shutdown the computer.
|
||||
auto show_quit_menu = std::make_shared<SwitchComponent>(mWindow);
|
||||
show_quit_menu->setState(Settings::getInstance()->getBool("ShowQuitMenu"));
|
||||
s->addWithLabel("SHOW QUIT MENU (REBOOT AND POWER OFF ENTRIES)", show_quit_menu);
|
||||
s->addSaveFunc([this, show_quit_menu, s] {
|
||||
if (show_quit_menu->getState() !=
|
||||
Settings::getInstance()->getBool("ShowQuitMenu")) {
|
||||
if (show_quit_menu->getState() != Settings::getInstance()->getBool("ShowQuitMenu")) {
|
||||
Settings::getInstance()->setBool("ShowQuitMenu", show_quit_menu->getState());
|
||||
s->setNeedsSaving();
|
||||
GuiMenu::close(false);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Switch callback.
|
||||
auto launchWorkaroundToggleFunc = [launch_workaround]() {
|
||||
if (launch_workaround->getEnabled()) {
|
||||
launch_workaround->setEnabled(false);
|
||||
launch_workaround->setOpacity(DISABLED_OPACITY);
|
||||
launch_workaround->getParent()->getChild(launch_workaround->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
launch_workaround->getParent()
|
||||
->getChild(launch_workaround->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
else {
|
||||
launch_workaround->setEnabled(true);
|
||||
launch_workaround->setOpacity(255);
|
||||
launch_workaround->getParent()->getChild(launch_workaround->
|
||||
getChildIndex() - 1)->setOpacity(255);
|
||||
launch_workaround->getParent()
|
||||
->getChild(launch_workaround->getChildIndex() - 1)
|
||||
->setOpacity(255);
|
||||
}
|
||||
};
|
||||
run_in_background->setCallback(launchWorkaroundToggleFunc);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mWindow->pushGui(s);
|
||||
}
|
||||
|
@ -1225,19 +1220,20 @@ void GuiMenu::openOtherOptions()
|
|||
void GuiMenu::openUtilitiesMenu()
|
||||
{
|
||||
auto s = new GuiSettings(mWindow, "UTILITIES");
|
||||
|
||||
mWindow->pushGui(s);
|
||||
}
|
||||
|
||||
void GuiMenu::openQuitMenu()
|
||||
{
|
||||
if (!Settings::getInstance()->getBool("ShowQuitMenu")) {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, this->getHelpStyle(),
|
||||
"REALLY QUIT?", "YES", [this] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, this->getHelpStyle(), "REALLY QUIT?", "YES",
|
||||
[this] {
|
||||
Scripting::fireEvent("quit");
|
||||
close(true);
|
||||
quitES();
|
||||
}, "NO", nullptr));
|
||||
},
|
||||
"NO", nullptr));
|
||||
}
|
||||
else {
|
||||
auto s = new GuiSettings(mWindow, "QUIT");
|
||||
|
@ -1253,47 +1249,56 @@ void GuiMenu::openQuitMenu()
|
|||
ComponentListRow row;
|
||||
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
window->pushGui(new GuiMsgBox(window, this->getHelpStyle(),
|
||||
"REALLY QUIT?", "YES", [this] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
window, this->getHelpStyle(), "REALLY QUIT?", "YES",
|
||||
[this] {
|
||||
Scripting::fireEvent("quit");
|
||||
close(true);
|
||||
quitES();
|
||||
}, "NO", nullptr));
|
||||
},
|
||||
"NO", nullptr));
|
||||
});
|
||||
row.addElement(std::make_shared<TextComponent>(window, "QUIT EMULATIONSTATION",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(bracket, false);
|
||||
s->addRow(row);
|
||||
|
||||
row.elements.clear();
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
window->pushGui(new GuiMsgBox(window, this->getHelpStyle(),
|
||||
"REALLY REBOOT?", "YES", [] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
window, this->getHelpStyle(), "REALLY REBOOT?", "YES",
|
||||
[] {
|
||||
Scripting::fireEvent("quit", "reboot");
|
||||
Scripting::fireEvent("reboot");
|
||||
if (quitES(QuitMode::REBOOT) != 0) {
|
||||
LOG(LogWarning) << "Reboot terminated with non-zero result!";
|
||||
}
|
||||
}, "NO", nullptr));
|
||||
},
|
||||
"NO", nullptr));
|
||||
});
|
||||
row.addElement(std::make_shared<TextComponent>(window, "REBOOT SYSTEM",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(bracket, false);
|
||||
s->addRow(row);
|
||||
|
||||
row.elements.clear();
|
||||
row.makeAcceptInputHandler([window, this] {
|
||||
window->pushGui(new GuiMsgBox(window, this->getHelpStyle(),
|
||||
"REALLY POWER OFF?", "YES", [] {
|
||||
window->pushGui(new GuiMsgBox(
|
||||
window, this->getHelpStyle(), "REALLY POWER OFF?", "YES",
|
||||
[] {
|
||||
Scripting::fireEvent("quit", "poweroff");
|
||||
Scripting::fireEvent("poweroff");
|
||||
if (quitES(QuitMode::POWEROFF) != 0) {
|
||||
LOG(LogWarning) << "Power off terminated with non-zero result!";
|
||||
}
|
||||
}, "NO", nullptr));
|
||||
},
|
||||
"NO", nullptr));
|
||||
});
|
||||
row.addElement(std::make_shared<TextComponent>(window, "POWER OFF SYSTEM",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||
true);
|
||||
row.addElement(bracket, false);
|
||||
s->addRow(row);
|
||||
|
||||
|
@ -1331,8 +1336,10 @@ void GuiMenu::onSizeChanged()
|
|||
mVersion.setPosition(0, mSize.y() - mVersion.getSize().y());
|
||||
}
|
||||
|
||||
void GuiMenu::addEntry(const std::string& name, unsigned int color,
|
||||
bool add_arrow, const std::function<void()>& func)
|
||||
void GuiMenu::addEntry(const std::string& name,
|
||||
unsigned int color,
|
||||
bool add_arrow,
|
||||
const std::function<void()>& func)
|
||||
{
|
||||
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#ifndef ES_APP_GUIS_GUI_MENU_H
|
||||
#define ES_APP_GUIS_GUI_MENU_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "guis/GuiSettings.h"
|
||||
#include "GuiComponent.h"
|
||||
|
||||
class GuiMenu : public GuiComponent
|
||||
{
|
||||
|
@ -27,8 +27,10 @@ public:
|
|||
|
||||
private:
|
||||
void close(bool closeAllWindows);
|
||||
void addEntry(const std::string& name, unsigned int color,
|
||||
bool add_arrow, const std::function<void()>& func);
|
||||
void addEntry(const std::string& name,
|
||||
unsigned int color,
|
||||
bool add_arrow,
|
||||
const std::function<void()>& func);
|
||||
void addVersionInfo();
|
||||
|
||||
void openScraperOptions();
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
|
||||
#include "guis/GuiMetaDataEd.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileData.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Gamelist.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentList.h"
|
||||
#include "components/DateTimeEditComponent.h"
|
||||
|
@ -18,22 +24,15 @@
|
|||
#include "components/RatingComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "guis/GuiComplexTextEditPopup.h"
|
||||
#include "guis/GuiGameScraper.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "guis/GuiComplexTextEditPopup.h"
|
||||
#include "resources/Font.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileData.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Gamelist.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
|
||||
GuiMetaDataEd::GuiMetaDataEd(
|
||||
Window* window,
|
||||
GuiMetaDataEd::GuiMetaDataEd(Window* window,
|
||||
MetaDataList* md,
|
||||
const std::vector<MetaDataDecl>& mdd,
|
||||
ScraperSearchParams scraperParams,
|
||||
|
@ -41,43 +40,44 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
std::function<void()> saveCallback,
|
||||
std::function<void()> clearGameFunc,
|
||||
std::function<void()> deleteGameFunc)
|
||||
: GuiComponent(window),
|
||||
mScraperParams(scraperParams),
|
||||
mBackground(window, ":/graphics/frame.svg"),
|
||||
mGrid(window, Vector2i(1, 3)),
|
||||
mMetaDataDecl(mdd),
|
||||
mMetaData(md),
|
||||
mSavedCallback(saveCallback),
|
||||
mClearGameFunc(clearGameFunc),
|
||||
mDeleteGameFunc(deleteGameFunc),
|
||||
mMediaFilesUpdated(false)
|
||||
: GuiComponent(window)
|
||||
, mScraperParams(scraperParams)
|
||||
, mBackground(window, ":/graphics/frame.svg")
|
||||
, mGrid(window, Vector2i(1, 3))
|
||||
, mMetaDataDecl(mdd)
|
||||
, mMetaData(md)
|
||||
, mSavedCallback(saveCallback)
|
||||
, mClearGameFunc(clearGameFunc)
|
||||
, mDeleteGameFunc(deleteGameFunc)
|
||||
, mMediaFilesUpdated(false)
|
||||
{
|
||||
addChild(&mBackground);
|
||||
addChild(&mGrid);
|
||||
|
||||
mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5));
|
||||
|
||||
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA",
|
||||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA", Font::get(FONT_SIZE_LARGE),
|
||||
0x555555FF, ALIGN_CENTER);
|
||||
|
||||
// Extract possible subfolders from the path.
|
||||
std::string folderPath = Utils::String::replace(
|
||||
Utils::FileSystem::getParent(scraperParams.game->getPath()),
|
||||
std::string folderPath =
|
||||
Utils::String::replace(Utils::FileSystem::getParent(scraperParams.game->getPath()),
|
||||
scraperParams.system->getSystemEnvData()->mStartPath, "");
|
||||
|
||||
if (folderPath.size() >= 2) {
|
||||
folderPath.erase(0, 1);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
folderPath.push_back('\\');
|
||||
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
||||
#else
|
||||
#else
|
||||
folderPath.push_back('/');
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
mSubtitle = std::make_shared<TextComponent>(mWindow, folderPath +
|
||||
Utils::FileSystem::getFileName(scraperParams.game->getPath()) +
|
||||
" [" + Utils::String::toUpper(scraperParams.system->getName()) + "]" +
|
||||
mSubtitle = std::make_shared<TextComponent>(
|
||||
mWindow,
|
||||
folderPath + Utils::FileSystem::getFileName(scraperParams.game->getPath()) + " [" +
|
||||
Utils::String::toUpper(scraperParams.system->getName()) + "]" +
|
||||
(scraperParams.game->getType() == FOLDER ? " " + ViewController::FOLDER_CHAR : ""),
|
||||
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER, Vector3f(0.0f, 0.0f, 0.0f),
|
||||
Vector2f(0.0f, 0.0f), 0x00000000, 0.05f);
|
||||
|
@ -103,22 +103,21 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
// Don't show the launch command override entry if this option has been disabled.
|
||||
if (!Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
||||
iter->type == MD_LAUNCHCOMMAND) {
|
||||
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
||||
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
ed = std::make_shared<TextComponent>(
|
||||
window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
assert(ed);
|
||||
ed->setValue(mMetaData->get(iter->key));
|
||||
mEditors.push_back(ed);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create ed and add it (and any related components) to mMenu.
|
||||
// ed's value will be set below.
|
||||
// It's very important to put the element with the help prompt as the last row
|
||||
// entry instead of for instance the spacer. That is so because ComponentList
|
||||
// always looks for the help prompt at the back of the element stack.
|
||||
ComponentListRow row;
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper(iter->displayName), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
auto lbl =
|
||||
std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(iter->displayName),
|
||||
Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
row.addElement(lbl, true); // Label.
|
||||
|
||||
switch (iter->type) {
|
||||
|
@ -135,7 +134,7 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
}
|
||||
case MD_RATING: {
|
||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0.0f);
|
||||
row.addElement(spacer, false);
|
||||
|
||||
ed = std::make_shared<RatingComponent>(window, true);
|
||||
|
@ -145,17 +144,17 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
row.addElement(ed, false, true);
|
||||
|
||||
auto ratingSpacer = std::make_shared<GuiComponent>(mWindow);
|
||||
ratingSpacer->setSize(Renderer::getScreenWidth() * 0.001f, 0);
|
||||
ratingSpacer->setSize(Renderer::getScreenWidth() * 0.001f, 0.0f);
|
||||
row.addElement(ratingSpacer, false);
|
||||
|
||||
// Pass input to the actual RatingComponent instead of the spacer.
|
||||
row.input_handler = std::bind(&GuiComponent::input,
|
||||
ed.get(), std::placeholders::_1, std::placeholders::_2);
|
||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
break;
|
||||
}
|
||||
case MD_DATE: {
|
||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0.0f);
|
||||
row.addElement(spacer, false);
|
||||
|
||||
ed = std::make_shared<DateTimeEditComponent>(window, true);
|
||||
|
@ -164,29 +163,22 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
row.addElement(ed, false);
|
||||
|
||||
auto dateSpacer = std::make_shared<GuiComponent>(mWindow);
|
||||
dateSpacer->setSize(Renderer::getScreenWidth() * 0.0035f, 0);
|
||||
dateSpacer->setSize(Renderer::getScreenWidth() * 0.0035f, 0.0f);
|
||||
row.addElement(dateSpacer, false);
|
||||
|
||||
// Pass input to the actual DateTimeEditComponent instead of the spacer.
|
||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(),
|
||||
std::placeholders::_1, std::placeholders::_2);
|
||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
break;
|
||||
}
|
||||
// Not in use as 'lastplayed' is flagged as statistics and these are skipped.
|
||||
// Let's still keep the code because it may be needed in the future.
|
||||
// case MD_TIME: {
|
||||
// ed = std::make_shared<DateTimeEditComponent>(window,
|
||||
// DateTimeEditComponent::DISP_RELATIVE_TO_NOW);
|
||||
// row.addElement(ed, false);
|
||||
// break;
|
||||
// }
|
||||
case MD_LAUNCHCOMMAND: {
|
||||
ed = std::make_shared<TextComponent>(window, "",
|
||||
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT),
|
||||
0x777777FF, ALIGN_RIGHT);
|
||||
row.addElement(ed, true);
|
||||
|
||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0.0f);
|
||||
row.addElement(spacer, false);
|
||||
|
||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||
|
@ -207,26 +199,27 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
};
|
||||
|
||||
std::string staticTextString = "Default value from es_systems.xml:";
|
||||
std::string defaultLaunchCommand = scraperParams.system->
|
||||
getSystemEnvData()->mLaunchCommand;
|
||||
std::string defaultLaunchCommand =
|
||||
scraperParams.system->getSystemEnvData()->mLaunchCommand;
|
||||
|
||||
row.makeAcceptInputHandler([this, title, staticTextString,
|
||||
defaultLaunchCommand, ed, updateVal, multiLine] {
|
||||
mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, getHelpStyle(),
|
||||
title, staticTextString, defaultLaunchCommand, ed->getValue(),
|
||||
updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
||||
row.makeAcceptInputHandler([this, title, staticTextString, defaultLaunchCommand, ed,
|
||||
updateVal, multiLine] {
|
||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
||||
mWindow, getHelpStyle(), title, staticTextString, defaultLaunchCommand,
|
||||
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
||||
});
|
||||
break;
|
||||
}
|
||||
case MD_MULTILINE_STRING:
|
||||
default: {
|
||||
// MD_STRING.
|
||||
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
||||
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
ed = std::make_shared<TextComponent>(window, "",
|
||||
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT),
|
||||
0x777777FF, ALIGN_RIGHT);
|
||||
row.addElement(ed, true);
|
||||
|
||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0);
|
||||
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0.0f);
|
||||
row.addElement(spacer, false);
|
||||
|
||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||
|
@ -240,8 +233,8 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
gamePath = Utils::FileSystem::getStem(mScraperParams.game->getPath());
|
||||
|
||||
// OK callback (apply new value to ed).
|
||||
auto updateVal = [ed, currentKey, originalValue, gamePath]
|
||||
(const std::string& newVal) {
|
||||
auto updateVal = [ed, currentKey, originalValue,
|
||||
gamePath](const std::string& newVal) {
|
||||
// If the user has entered a blank game name, then set the name to the ROM
|
||||
// filename (minus the extension).
|
||||
if (currentKey == "name" && newVal == "") {
|
||||
|
@ -251,9 +244,9 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
else
|
||||
ed->setColor(TEXTCOLOR_USERMARKED);
|
||||
}
|
||||
else if (newVal == "" && (currentKey == "developer" ||
|
||||
currentKey == "publisher" || currentKey == "genre" ||
|
||||
currentKey == "players")) {
|
||||
else if (newVal == "" &&
|
||||
(currentKey == "developer" || currentKey == "publisher" ||
|
||||
currentKey == "genre" || currentKey == "players")) {
|
||||
ed->setValue("unknown");
|
||||
if (originalValue == "unknown")
|
||||
ed->setColor(DEFAULT_TEXTCOLOR);
|
||||
|
@ -271,7 +264,8 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
|
||||
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
||||
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
||||
ed->getValue(), updateVal, multiLine,
|
||||
"APPLY", "APPLY CHANGES?"));
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -286,8 +280,8 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||
|
||||
if (!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SCRAPE", "scrape",
|
||||
std::bind(&GuiMetaDataEd::fetch, this)));
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(
|
||||
mWindow, "SCRAPE", "scrape", std::bind(&GuiMetaDataEd::fetch, this)));
|
||||
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save metadata", [&] {
|
||||
save();
|
||||
|
@ -296,10 +290,12 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
}));
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes",
|
||||
[&] { delete this; }));
|
||||
|
||||
if (scraperParams.game->getType() == FOLDER) {
|
||||
if (mClearGameFunc) {
|
||||
auto clearSelf = [&] { mClearGameFunc(); delete this; };
|
||||
auto clearSelf = [&] {
|
||||
mClearGameFunc();
|
||||
delete this;
|
||||
};
|
||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"THIS WILL DELETE ANY MEDIA FILES AND\n"
|
||||
|
@ -307,14 +303,18 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
"BUT NEITHER THE FOLDER ITSELF OR ANY\n"
|
||||
"CONTENT INSIDE IT WILL BE REMOVED\n"
|
||||
"ARE YOU SURE?",
|
||||
"YES", clearSelf, "NO", nullptr)); };
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR",
|
||||
"clear folder", clearSelfBtnFunc));
|
||||
"YES", clearSelf, "NO", nullptr));
|
||||
};
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear folder",
|
||||
clearSelfBtnFunc));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mClearGameFunc) {
|
||||
auto clearSelf = [&] { mClearGameFunc(); delete this; };
|
||||
auto clearSelf = [&] {
|
||||
mClearGameFunc();
|
||||
delete this;
|
||||
};
|
||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"THIS WILL DELETE ANY MEDIA FILES\n"
|
||||
|
@ -322,22 +322,27 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
"THIS GAME, BUT THE GAME FILE\n"
|
||||
"ITSELF WILL NOT BE REMOVED\n"
|
||||
"ARE YOU SURE?",
|
||||
"YES", clearSelf, "NO", nullptr)); };
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR",
|
||||
"clear file", clearSelfBtnFunc));
|
||||
"YES", clearSelf, "NO", nullptr));
|
||||
};
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear file",
|
||||
clearSelfBtnFunc));
|
||||
}
|
||||
|
||||
if (mDeleteGameFunc) {
|
||||
auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
|
||||
auto deleteFilesAndSelf = [&] {
|
||||
mDeleteGameFunc();
|
||||
delete this;
|
||||
};
|
||||
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"THIS WILL DELETE THE GAME\n"
|
||||
"FILE, ANY MEDIA FILES AND\n"
|
||||
"THE GAMELIST.XML ENTRY\n"
|
||||
"ARE YOU SURE?",
|
||||
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
|
||||
"delete game", deleteGameBtnFunc));
|
||||
"YES", deleteFilesAndSelf, "NO", nullptr));
|
||||
};
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE", "delete game",
|
||||
deleteGameBtnFunc));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,11 +350,12 @@ GuiMetaDataEd::GuiMetaDataEd(
|
|||
mGrid.setEntry(mButtons, Vector2i(0, 2), true, false);
|
||||
|
||||
// Resize + center.
|
||||
float width = static_cast<float>(std::min(static_cast<int>(Renderer::getScreenHeight() *
|
||||
1.05f), static_cast<int>(Renderer::getScreenWidth() * 0.90f)));
|
||||
float width =
|
||||
static_cast<float>(std::min(static_cast<int>(Renderer::getScreenHeight() * 1.05f),
|
||||
static_cast<int>(Renderer::getScreenWidth() * 0.90f)));
|
||||
setSize(width, Renderer::getScreenHeight() * 0.83f);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
||||
(Renderer::getScreenHeight() - mSize.y()) / 2);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||
}
|
||||
|
||||
void GuiMetaDataEd::onSizeChanged()
|
||||
|
@ -360,8 +366,8 @@ void GuiMetaDataEd::onSizeChanged()
|
|||
const float subtitleHeight = mSubtitle->getFont()->getLetterHeight();
|
||||
const float titleSubtitleSpacing = mSize.y() * 0.03f;
|
||||
|
||||
mGrid.setRowHeightPerc(0, (titleHeight + titleSubtitleSpacing + subtitleHeight +
|
||||
TITLE_VERT_PADDING) / mSize.y());
|
||||
mGrid.setRowHeightPerc(
|
||||
0, (titleHeight + titleSubtitleSpacing + subtitleHeight + TITLE_VERT_PADDING) / mSize.y());
|
||||
mGrid.setRowHeightPerc(2, mButtons->getSize().y() / mSize.y());
|
||||
|
||||
// Snap list size to the row height to prevent a fraction of a row from being displayed.
|
||||
|
@ -383,7 +389,7 @@ void GuiMetaDataEd::onSizeChanged()
|
|||
mList->setSize(mList->getSize().x(), listHeight);
|
||||
Vector2f newWindowSize = mSize;
|
||||
newWindowSize.y() -= heightAdjustment;
|
||||
mBackground.fitTo(newWindowSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
mBackground.fitTo(newWindowSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||
|
||||
// Move the buttons up as well to make the layout align correctly after the resize.
|
||||
Vector3f newButtonPos = mButtons->getPosition();
|
||||
|
@ -501,8 +507,8 @@ void GuiMetaDataEd::save()
|
|||
|
||||
void GuiMetaDataEd::fetch()
|
||||
{
|
||||
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams,
|
||||
std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
||||
GuiGameScraper* scr = new GuiGameScraper(
|
||||
mWindow, mScraperParams, std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
||||
mWindow->pushGui(scr);
|
||||
}
|
||||
|
||||
|
@ -514,10 +520,6 @@ void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
|
|||
|
||||
mMediaFilesUpdated = result.savedNewMedia;
|
||||
|
||||
// Curently disabled as I'm not sure if this is more annoying than helpful.
|
||||
// // Select the Save button.
|
||||
// mButtons->moveCursor(Vector2i(1, 0));
|
||||
|
||||
// Check if any values were manually changed before starting the scraping.
|
||||
// If so, it's these values we should compare against when scraping, not
|
||||
// the values previously saved for the game.
|
||||
|
@ -561,19 +563,6 @@ void GuiMetaDataEd::close()
|
|||
}
|
||||
}
|
||||
|
||||
// Keep code for potential future use.
|
||||
// std::function<void()> closeFunc;
|
||||
// if (!closeAllWindows) {
|
||||
// closeFunc = [this] { delete this; };
|
||||
// }
|
||||
// else {
|
||||
// Window* window = mWindow;
|
||||
// closeFunc = [window, this] {
|
||||
// while (window->peekGui() != ViewController::get())
|
||||
// delete window->peekGui();
|
||||
// };
|
||||
// }
|
||||
|
||||
std::function<void()> closeFunc;
|
||||
closeFunc = [this] {
|
||||
if (mMediaFilesUpdated) {
|
||||
|
@ -592,11 +581,13 @@ void GuiMetaDataEd::close()
|
|||
|
||||
if (metadataUpdated) {
|
||||
// Changes were made, ask if the user wants to save them.
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"SAVE CHANGES?",
|
||||
"YES", [this, closeFunc] { save(); closeFunc(); },
|
||||
"NO", closeFunc
|
||||
));
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, getHelpStyle(), "SAVE CHANGES?", "YES",
|
||||
[this, closeFunc] {
|
||||
save();
|
||||
closeFunc();
|
||||
},
|
||||
"NO", closeFunc));
|
||||
}
|
||||
else {
|
||||
// Always save if the media files have been changed (i.e. newly scraped images).
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#ifndef ES_APP_GUIS_GUI_META_DATA_ED_H
|
||||
#define ES_APP_GUIS_GUI_META_DATA_ED_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
|
||||
class ComponentList;
|
||||
class TextComponent;
|
||||
|
@ -24,9 +24,9 @@ class TextComponent;
|
|||
class GuiMetaDataEd : public GuiComponent
|
||||
{
|
||||
public:
|
||||
GuiMetaDataEd(
|
||||
Window* window,
|
||||
MetaDataList* md, const std::vector<MetaDataDecl>&mdd,
|
||||
GuiMetaDataEd(Window* window,
|
||||
MetaDataList* md,
|
||||
const std::vector<MetaDataDecl>& mdd,
|
||||
ScraperSearchParams params,
|
||||
const std::string& header,
|
||||
std::function<void()> savedCallback,
|
||||
|
|
|
@ -9,17 +9,15 @@
|
|||
|
||||
#include "guis/GuiOfflineGenerator.h"
|
||||
|
||||
#include "SystemData.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GuiOfflineGenerator::GuiOfflineGenerator(
|
||||
Window* window,
|
||||
const std::queue<FileData*>& gameQueue)
|
||||
: GuiComponent(window),
|
||||
mBackground(window, ":/graphics/frame.svg"),
|
||||
mGrid(window, Vector2i(6, 13)),
|
||||
mGameQueue(gameQueue)
|
||||
GuiOfflineGenerator::GuiOfflineGenerator(Window* window, const std::queue<FileData*>& gameQueue)
|
||||
: GuiComponent(window)
|
||||
, mBackground(window, ":/graphics/frame.svg")
|
||||
, mGrid(window, Vector2i(6, 13))
|
||||
, mGameQueue(gameQueue)
|
||||
{
|
||||
addChild(&mBackground);
|
||||
addChild(&mGrid);
|
||||
|
@ -42,105 +40,104 @@ GuiOfflineGenerator::GuiOfflineGenerator(
|
|||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true, Vector2i(6, 1));
|
||||
|
||||
mStatus = std::make_shared<TextComponent>(mWindow, "NOT STARTED",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
||||
mStatus = std::make_shared<TextComponent>(mWindow, "NOT STARTED", Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mStatus, Vector2i(0, 1), false, true, Vector2i(6, 1));
|
||||
|
||||
mGameCounter = std::make_shared<TextComponent>(mWindow,
|
||||
mGameCounter = std::make_shared<TextComponent>(
|
||||
mWindow,
|
||||
std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
||||
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mGameCounter, Vector2i(0, 2), false, true, Vector2i(6, 1));
|
||||
|
||||
// Spacer row with top border.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 3),
|
||||
false, false, Vector2i(6, 1), GridFlags::BORDER_TOP);
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 3), false, false,
|
||||
Vector2i(6, 1), GridFlags::BORDER_TOP);
|
||||
|
||||
// Left spacer.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 4),
|
||||
false, false, Vector2i(1, 7));
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 4), false, false,
|
||||
Vector2i(1, 7));
|
||||
|
||||
// Generated label.
|
||||
mGeneratedLbl = std::make_shared<TextComponent>(mWindow, "Generated:",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGeneratedLbl = std::make_shared<TextComponent>(
|
||||
mWindow, "Generated:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mGeneratedLbl, Vector2i(1, 4), false, true, Vector2i(1, 1));
|
||||
|
||||
// Generated value/counter.
|
||||
mGeneratedVal = std::make_shared<TextComponent>(mWindow,
|
||||
std::to_string(mGamesProcessed),
|
||||
mGeneratedVal =
|
||||
std::make_shared<TextComponent>(mWindow, std::to_string(mGamesProcessed),
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mGeneratedVal, Vector2i(2, 4), false, true, Vector2i(1, 1));
|
||||
|
||||
// Overwritten label.
|
||||
mOverwrittenLbl = std::make_shared<TextComponent>(mWindow, "Overwritten:",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mOverwrittenLbl = std::make_shared<TextComponent>(
|
||||
mWindow, "Overwritten:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mOverwrittenLbl, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
||||
|
||||
// Overwritten value/counter.
|
||||
mOverwrittenVal = std::make_shared<TextComponent>(mWindow,
|
||||
std::to_string(mImagesOverwritten),
|
||||
mOverwrittenVal =
|
||||
std::make_shared<TextComponent>(mWindow, std::to_string(mImagesOverwritten),
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mOverwrittenVal, Vector2i(2, 5), false, true, Vector2i(1, 1));
|
||||
|
||||
// Skipping label.
|
||||
mSkippedLbl = std::make_shared<TextComponent>(mWindow, "Skipped (existing):",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mSkippedLbl = std::make_shared<TextComponent>(
|
||||
mWindow, "Skipped (existing):", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mSkippedLbl, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
||||
|
||||
// Skipping value/counter.
|
||||
mSkippedVal= std::make_shared<TextComponent>(mWindow,
|
||||
std::to_string(mGamesSkipped),
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mSkippedVal = std::make_shared<TextComponent>(
|
||||
mWindow, std::to_string(mGamesSkipped), Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mSkippedVal, Vector2i(2, 6), false, true, Vector2i(1, 1));
|
||||
|
||||
// Failed label.
|
||||
mFailedLbl = std::make_shared<TextComponent>(mWindow, "Failed:",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mFailedLbl = std::make_shared<TextComponent>(mWindow, "Failed:", Font::get(FONT_SIZE_SMALL),
|
||||
0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mFailedLbl, Vector2i(1, 7), false, true, Vector2i(1, 1));
|
||||
|
||||
// Failed value/counter.
|
||||
mFailedVal = std::make_shared<TextComponent>(mWindow,
|
||||
std::to_string(mGamesFailed),
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mFailedVal = std::make_shared<TextComponent>(
|
||||
mWindow, std::to_string(mGamesFailed), Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mFailedVal, Vector2i(2, 7), false, true, Vector2i(1, 1));
|
||||
|
||||
// Processing label.
|
||||
mProcessingLbl = std::make_shared<TextComponent>(mWindow, "Processing: ",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mProcessingLbl = std::make_shared<TextComponent>(
|
||||
mWindow, "Processing: ", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mProcessingLbl, Vector2i(3, 4), false, true, Vector2i(1, 1));
|
||||
|
||||
// Processing value.
|
||||
mProcessingVal = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mProcessingVal = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL),
|
||||
0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mProcessingVal, Vector2i(4, 4), false, true, Vector2i(1, 1));
|
||||
|
||||
// Spacer row.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 8),
|
||||
false, false, Vector2i(4, 1));
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 8), false, false,
|
||||
Vector2i(4, 1));
|
||||
|
||||
// Last error message label.
|
||||
mLastErrorLbl = std::make_shared<TextComponent>(mWindow, "Last error message:",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mLastErrorLbl = std::make_shared<TextComponent>(
|
||||
mWindow, "Last error message:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mLastErrorLbl, Vector2i(1, 9), false, true, Vector2i(4, 1));
|
||||
|
||||
// Last error message value.
|
||||
mLastErrorVal = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||
mLastErrorVal = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL),
|
||||
0x888888FF, ALIGN_LEFT);
|
||||
mGrid.setEntry(mLastErrorVal, Vector2i(1, 10), false, true, Vector2i(4, 1));
|
||||
|
||||
// Right spacer.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(5, 4),
|
||||
false, false, Vector2i(1, 7));
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(5, 4), false, false,
|
||||
Vector2i(1, 7));
|
||||
|
||||
// Spacer row with bottom border.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 11),
|
||||
false, false, Vector2i(6, 1), GridFlags::BORDER_BOTTOM);
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 11), false, false,
|
||||
Vector2i(6, 1), GridFlags::BORDER_BOTTOM);
|
||||
|
||||
// Buttons.
|
||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||
|
||||
mStartPauseButton = std::make_shared<ButtonComponent>(mWindow, "START",
|
||||
"start processing", [this](){
|
||||
mStartPauseButton =
|
||||
std::make_shared<ButtonComponent>(mWindow, "START", "start processing", [this]() {
|
||||
if (!mProcessing) {
|
||||
mProcessing = true;
|
||||
mPaused = false;
|
||||
|
@ -165,14 +162,14 @@ GuiOfflineGenerator::GuiOfflineGenerator(
|
|||
|
||||
buttons.push_back(mStartPauseButton);
|
||||
|
||||
mCloseButton = std::make_shared<ButtonComponent>(mWindow, "CLOSE", "close", [this](){
|
||||
mCloseButton = std::make_shared<ButtonComponent>(mWindow, "CLOSE", "close", [this]() {
|
||||
if (mGamesProcessed != 0 && mGamesProcessed != mTotalGames) {
|
||||
LOG(LogInfo) << "GuiOfflineGenerator: Aborted after processing " <<
|
||||
mGamesProcessed << (mGamesProcessed == 1 ? " game (" : " games (") <<
|
||||
mImagesGenerated << (mImagesGenerated == 1 ? " image " : " images ") <<
|
||||
"generated, " << mGamesSkipped <<
|
||||
(mGamesSkipped == 1 ? " game " : " games ") << "skipped, " << mGamesFailed <<
|
||||
(mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||
LOG(LogInfo) << "GuiOfflineGenerator: Aborted after processing " << mGamesProcessed
|
||||
<< (mGamesProcessed == 1 ? " game (" : " games (") << mImagesGenerated
|
||||
<< (mImagesGenerated == 1 ? " image " : " images ") << "generated, "
|
||||
<< mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ")
|
||||
<< "skipped, " << mGamesFailed
|
||||
<< (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||
}
|
||||
delete this;
|
||||
});
|
||||
|
@ -184,8 +181,8 @@ GuiOfflineGenerator::GuiOfflineGenerator(
|
|||
|
||||
// For narrower displays (e.g. in 4:3 ratio), allow the window to fill 95% of the screen
|
||||
// width rather than the 85% allowed for wider displays.
|
||||
float width = Renderer::getScreenWidth() *
|
||||
((Renderer::getScreenAspectRatio() < 1.4f) ? 0.95f : 0.85f);
|
||||
float width =
|
||||
Renderer::getScreenWidth() * ((Renderer::getScreenAspectRatio() < 1.4f) ? 0.95f : 0.85f);
|
||||
|
||||
setSize(width, Renderer::getScreenHeight() * 0.75f);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||
|
@ -281,8 +278,8 @@ void GuiOfflineGenerator::update(int deltaTime)
|
|||
mGame = mGameQueue.front();
|
||||
mGameQueue.pop();
|
||||
|
||||
mGameName = mGame->getName() + " [" +
|
||||
Utils::String::toUpper(mGame->getSystem()->getName()) + "]";
|
||||
mGameName =
|
||||
mGame->getName() + " [" + Utils::String::toUpper(mGame->getSystem()->getName()) + "]";
|
||||
mProcessingVal->setText(mGameName);
|
||||
|
||||
if (!Settings::getInstance()->getBool("MiximageOverwrite") &&
|
||||
|
@ -319,13 +316,13 @@ void GuiOfflineGenerator::update(int deltaTime)
|
|||
if (mGamesProcessed == mTotalGames) {
|
||||
mStatus->setText("COMPLETED");
|
||||
mStartPauseButton->setText("DONE", "done (close)");
|
||||
mStartPauseButton->setPressedFunc([this](){ delete this; });
|
||||
mStartPauseButton->setPressedFunc([this]() { delete this; });
|
||||
mCloseButton->setText("CLOSE", "close");
|
||||
mProcessingVal->setText("");
|
||||
LOG(LogInfo) << "GuiOfflineGenerator: Completed processing (" << mImagesGenerated <<
|
||||
(mImagesGenerated == 1 ? " image " : " images ") << "generated, " <<
|
||||
mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ") << "skipped, " <<
|
||||
mGamesFailed << (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||
LOG(LogInfo) << "GuiOfflineGenerator: Completed processing (" << mImagesGenerated
|
||||
<< (mImagesGenerated == 1 ? " image " : " images ") << "generated, "
|
||||
<< mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ") << "skipped, "
|
||||
<< mGamesFailed << (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||
mProcessing = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#ifndef ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
||||
#define ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
||||
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "MiximageGenerator.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
|
||||
#include <queue>
|
||||
|
||||
|
|
|
@ -10,23 +10,23 @@
|
|||
|
||||
#include "guis/GuiScraperMenu.h"
|
||||
|
||||
#include "FileData.h"
|
||||
#include "FileSorts.h"
|
||||
#include "SystemData.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "guis/GuiOfflineGenerator.h"
|
||||
#include "guis/GuiScraperMulti.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "FileData.h"
|
||||
#include "FileSorts.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
|
||||
GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
||||
: GuiComponent(window), mMenu(window, title)
|
||||
: GuiComponent(window)
|
||||
, mMenu(window, title)
|
||||
{
|
||||
// Scraper service.
|
||||
mScraper = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SCRAPE FROM", false);
|
||||
mScraper = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||
"SCRAPE FROM", false);
|
||||
std::vector<std::string> scrapers = getScraperList();
|
||||
// Select either the first entry or the one read from the settings,
|
||||
// just in case the scraper from settings has vanished.
|
||||
|
@ -36,22 +36,50 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
|||
|
||||
// Search filters, getSearches() will generate a queue of games to scrape
|
||||
// based on the outcome of the checks below.
|
||||
mFilters = std::make_shared< OptionListComponent<GameFilterFunc>>
|
||||
(mWindow, getHelpStyle(), "SCRAPE THESE GAMES", false);
|
||||
mFilters->add("ALL GAMES", [](SystemData*, FileData*) -> bool { return true; }, false);
|
||||
mFilters->add("FAVORITE GAMES", [](SystemData*, FileData* g) -> bool {
|
||||
return g->getFavorite(); }, false);
|
||||
mFilters->add("NO METADATA", [](SystemData*, FileData* g) -> bool {
|
||||
return g->metadata.get("desc").empty(); }, false);
|
||||
mFilters->add("NO GAME IMAGE",
|
||||
mFilters = std::make_shared<OptionListComponent<GameFilterFunc>>(mWindow, getHelpStyle(),
|
||||
"SCRAPE THESE GAMES", false);
|
||||
mFilters->add(
|
||||
"ALL GAMES",
|
||||
[](SystemData*, FileData*) -> bool {
|
||||
// All games.
|
||||
return true;
|
||||
},
|
||||
false);
|
||||
mFilters->add(
|
||||
"FAVORITE GAMES",
|
||||
[](SystemData*, FileData* g) -> bool {
|
||||
return g->getImagePath().empty(); }, false);
|
||||
mFilters->add("NO GAME VIDEO",
|
||||
// Favorite games.
|
||||
return g->getFavorite();
|
||||
},
|
||||
false);
|
||||
mFilters->add(
|
||||
"NO METADATA",
|
||||
[](SystemData*, FileData* g) -> bool {
|
||||
return g->getVideoPath().empty(); }, false);
|
||||
mFilters->add("FOLDERS ONLY",
|
||||
// No metadata.
|
||||
return g->metadata.get("desc").empty();
|
||||
},
|
||||
false);
|
||||
mFilters->add(
|
||||
"NO GAME IMAGE",
|
||||
[](SystemData*, FileData* g) -> bool {
|
||||
return g->getType() == FOLDER; }, false);
|
||||
// No game image.
|
||||
return g->getImagePath().empty();
|
||||
},
|
||||
false);
|
||||
mFilters->add(
|
||||
"NO GAME VIDEO",
|
||||
[](SystemData*, FileData* g) -> bool {
|
||||
// No game video.
|
||||
return g->getVideoPath().empty();
|
||||
},
|
||||
false);
|
||||
mFilters->add(
|
||||
"FOLDERS ONLY",
|
||||
[](SystemData*, FileData* g) -> bool {
|
||||
// Folders only.
|
||||
return g->getType() == FOLDER;
|
||||
},
|
||||
false);
|
||||
|
||||
mFilters->selectEntry(Settings::getInstance()->getInt("ScraperFilter"));
|
||||
mMenu.addWithLabel("SCRAPE THESE GAMES", mFilters);
|
||||
|
@ -68,20 +96,20 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
|||
});
|
||||
|
||||
// Add systems (all systems with an existing platform ID are listed).
|
||||
mSystems = std::make_shared< OptionListComponent<SystemData*>>
|
||||
(mWindow, getHelpStyle(), "SCRAPE THESE SYSTEMS", true);
|
||||
mSystems = std::make_shared<OptionListComponent<SystemData*>>(mWindow, getHelpStyle(),
|
||||
"SCRAPE THESE SYSTEMS", true);
|
||||
for (unsigned int i = 0; i < SystemData::sSystemVector.size(); i++) {
|
||||
if (!SystemData::sSystemVector[i]->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) {
|
||||
mSystems->add(SystemData::sSystemVector[i]->getFullName(),
|
||||
SystemData::sSystemVector[i],
|
||||
mSystems->add(SystemData::sSystemVector[i]->getFullName(), SystemData::sSystemVector[i],
|
||||
!SystemData::sSystemVector[i]->getPlatformIds().empty());
|
||||
SystemData::sSystemVector[i]->getScrapeFlag() ?
|
||||
mSystems->selectEntry(i) : mSystems->unselectEntry(i);
|
||||
SystemData::sSystemVector[i]->getScrapeFlag() ? mSystems->selectEntry(i) :
|
||||
mSystems->unselectEntry(i);
|
||||
}
|
||||
}
|
||||
mMenu.addWithLabel("SCRAPE THESE SYSTEMS", mSystems);
|
||||
|
||||
addEntry("ACCOUNT SETTINGS", 0x777777FF, true, [this] {
|
||||
// Open the account options menu.
|
||||
openAccountOptions();
|
||||
});
|
||||
addEntry("CONTENT SETTINGS", 0x777777FF, true, [this] {
|
||||
|
@ -93,6 +121,7 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
|||
openContentOptions();
|
||||
});
|
||||
addEntry("MIXIMAGE SETTINGS", 0x777777FF, true, [this] {
|
||||
// Open the miximage options menu.
|
||||
openMiximageOptions();
|
||||
});
|
||||
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] {
|
||||
|
@ -111,7 +140,7 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
|||
|
||||
setSize(mMenu.getSize());
|
||||
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||
Renderer::getScreenHeight() * 0.13f);
|
||||
}
|
||||
|
||||
|
@ -120,7 +149,7 @@ GuiScraperMenu::~GuiScraperMenu()
|
|||
// Save the scrape flags to the system settings so that they are
|
||||
// remembered throughout the program session.
|
||||
std::vector<SystemData*> sys = mSystems->getSelectedObjects();
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
(*it)->setScrapeFlag(false);
|
||||
for (auto it_sys = sys.cbegin(); it_sys != sys.cend(); it_sys++) {
|
||||
|
@ -136,8 +165,8 @@ void GuiScraperMenu::openAccountOptions()
|
|||
|
||||
// Whether to use the ScreenScraper account when scraping.
|
||||
auto scraper_use_account_screenscraper = std::make_shared<SwitchComponent>(mWindow);
|
||||
scraper_use_account_screenscraper->setState(Settings::getInstance()->
|
||||
getBool("ScraperUseAccountScreenScraper"));
|
||||
scraper_use_account_screenscraper->setState(
|
||||
Settings::getInstance()->getBool("ScraperUseAccountScreenScraper"));
|
||||
s->addWithLabel("USE THIS ACCOUNT FOR SCREENSCRAPER", scraper_use_account_screenscraper);
|
||||
s->addSaveFunc([scraper_use_account_screenscraper, s] {
|
||||
if (scraper_use_account_screenscraper->getState() !=
|
||||
|
@ -149,8 +178,8 @@ void GuiScraperMenu::openAccountOptions()
|
|||
});
|
||||
|
||||
// ScreenScraper username.
|
||||
auto scraper_username_screenscraper = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||
auto scraper_username_screenscraper = std::make_shared<TextComponent>(
|
||||
mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||
s->addEditableTextComponent("SCREENSCRAPER USERNAME", scraper_username_screenscraper,
|
||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper"));
|
||||
s->addSaveFunc([scraper_username_screenscraper, s] {
|
||||
|
@ -163,16 +192,16 @@ void GuiScraperMenu::openAccountOptions()
|
|||
});
|
||||
|
||||
// ScreenScraper password.
|
||||
auto scraper_password_screenscraper = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||
auto scraper_password_screenscraper = std::make_shared<TextComponent>(
|
||||
mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||
std::string passwordMasked;
|
||||
if (Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
||||
passwordMasked = "********";
|
||||
scraper_password_screenscraper->setHiddenValue(
|
||||
Settings::getInstance()->getString("ScraperPasswordScreenScraper"));
|
||||
}
|
||||
s->addEditableTextComponent("SCREENSCRAPER PASSWORD",
|
||||
scraper_password_screenscraper, passwordMasked, "", true);
|
||||
s->addEditableTextComponent("SCREENSCRAPER PASSWORD", scraper_password_screenscraper,
|
||||
passwordMasked, "", true);
|
||||
s->addSaveFunc([scraper_password_screenscraper, s] {
|
||||
if (scraper_password_screenscraper->getHiddenValue() !=
|
||||
Settings::getInstance()->getString("ScraperPasswordScreenScraper")) {
|
||||
|
@ -215,8 +244,9 @@ void GuiScraperMenu::openContentOptions()
|
|||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||
scrape_ratings->setEnabled(false);
|
||||
scrape_ratings->setOpacity(DISABLED_OPACITY);
|
||||
scrape_ratings->getParent()->getChild(scrape_ratings->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
scrape_ratings->getParent()
|
||||
->getChild(scrape_ratings->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
|
||||
// Scrape other metadata.
|
||||
|
@ -245,8 +275,9 @@ void GuiScraperMenu::openContentOptions()
|
|||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||
scrape_videos->setEnabled(false);
|
||||
scrape_videos->setOpacity(DISABLED_OPACITY);
|
||||
scrape_videos->getParent()->getChild(scrape_videos->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
scrape_videos->getParent()
|
||||
->getChild(scrape_videos->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
|
||||
// Scrape screenshots images.
|
||||
|
@ -299,8 +330,9 @@ void GuiScraperMenu::openContentOptions()
|
|||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||
scrape_3dboxes->setEnabled(false);
|
||||
scrape_3dboxes->setOpacity(DISABLED_OPACITY);
|
||||
scrape_3dboxes->getParent()->getChild(scrape_3dboxes->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
scrape_3dboxes->getParent()
|
||||
->getChild(scrape_3dboxes->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
|
||||
mWindow->pushGui(s);
|
||||
|
@ -311,8 +343,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
auto s = new GuiSettings(mWindow, "MIXIMAGE SETTINGS");
|
||||
|
||||
// Miximage resolution.
|
||||
auto miximage_resolution = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "MIXIMAGE RESOLUTION", false);
|
||||
auto miximage_resolution = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "MIXIMAGE RESOLUTION", false);
|
||||
std::string selectedResolution = Settings::getInstance()->getString("MiximageResolution");
|
||||
miximage_resolution->add("1280x960", "1280x960", selectedResolution == "1280x960");
|
||||
miximage_resolution->add("1920x1440", "1920x1440", selectedResolution == "1920x1440");
|
||||
|
@ -325,15 +357,15 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
s->addSaveFunc([miximage_resolution, s] {
|
||||
if (miximage_resolution->getSelected() !=
|
||||
Settings::getInstance()->getString("MiximageResolution")) {
|
||||
Settings::getInstance()->
|
||||
setString("MiximageResolution", miximage_resolution->getSelected());
|
||||
Settings::getInstance()->setString("MiximageResolution",
|
||||
miximage_resolution->getSelected());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Screenshot scaling method.
|
||||
auto miximage_scaling = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SCREENSHOT SCALING", false);
|
||||
auto miximage_scaling = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "SCREENSHOT SCALING", false);
|
||||
std::string selectedScaling = Settings::getInstance()->getString("MiximageScreenshotScaling");
|
||||
miximage_scaling->add("sharp", "sharp", selectedScaling == "sharp");
|
||||
miximage_scaling->add("smooth", "smooth", selectedScaling == "smooth");
|
||||
|
@ -345,8 +377,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
s->addSaveFunc([miximage_scaling, s] {
|
||||
if (miximage_scaling->getSelected() !=
|
||||
Settings::getInstance()->getString("MiximageScreenshotScaling")) {
|
||||
Settings::getInstance()->
|
||||
setString("MiximageScreenshotScaling", miximage_scaling->getSelected());
|
||||
Settings::getInstance()->setString("MiximageScreenshotScaling",
|
||||
miximage_scaling->getSelected());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -356,8 +388,7 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
miximage_generate->setState(Settings::getInstance()->getBool("MiximageGenerate"));
|
||||
s->addWithLabel("GENERATE MIXIMAGES WHEN SCRAPING", miximage_generate);
|
||||
s->addSaveFunc([miximage_generate, s] {
|
||||
if (miximage_generate->getState() !=
|
||||
Settings::getInstance()->getBool("MiximageGenerate")) {
|
||||
if (miximage_generate->getState() != Settings::getInstance()->getBool("MiximageGenerate")) {
|
||||
Settings::getInstance()->setBool("MiximageGenerate", miximage_generate->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
|
@ -408,8 +439,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
s->addSaveFunc([miximage_marquee, s] {
|
||||
if (miximage_marquee->getState() !=
|
||||
Settings::getInstance()->getBool("MiximageIncludeMarquee")) {
|
||||
Settings::getInstance()->
|
||||
setBool("MiximageIncludeMarquee", miximage_marquee->getState());
|
||||
Settings::getInstance()->setBool("MiximageIncludeMarquee",
|
||||
miximage_marquee->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -419,10 +450,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
miximage_box->setState(Settings::getInstance()->getBool("MiximageIncludeBox"));
|
||||
s->addWithLabel("INCLUDE BOX IMAGE", miximage_box);
|
||||
s->addSaveFunc([miximage_box, s] {
|
||||
if (miximage_box->getState() !=
|
||||
Settings::getInstance()->getBool("MiximageIncludeBox")) {
|
||||
Settings::getInstance()->
|
||||
setBool("MiximageIncludeBox", miximage_box->getState());
|
||||
if (miximage_box->getState() != Settings::getInstance()->getBool("MiximageIncludeBox")) {
|
||||
Settings::getInstance()->setBool("MiximageIncludeBox", miximage_box->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -434,8 +463,8 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
s->addSaveFunc([miximage_cover_fallback, s] {
|
||||
if (miximage_cover_fallback->getState() !=
|
||||
Settings::getInstance()->getBool("MiximageCoverFallback")) {
|
||||
Settings::getInstance()->
|
||||
setBool("MiximageCoverFallback", miximage_cover_fallback->getState());
|
||||
Settings::getInstance()->setBool("MiximageCoverFallback",
|
||||
miximage_cover_fallback->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -443,8 +472,10 @@ void GuiScraperMenu::openMiximageOptions()
|
|||
// Miximage offline generator.
|
||||
ComponentListRow offline_generator_row;
|
||||
offline_generator_row.elements.clear();
|
||||
offline_generator_row.addElement(std::make_shared<TextComponent>
|
||||
(mWindow, "OFFLINE GENERATOR", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
offline_generator_row.addElement(std::make_shared<TextComponent>(mWindow, "OFFLINE GENERATOR",
|
||||
Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF),
|
||||
true);
|
||||
offline_generator_row.addElement(makeArrow(mWindow), false);
|
||||
offline_generator_row.makeAcceptInputHandler(
|
||||
std::bind(&GuiScraperMenu::openOfflineGenerator, this, s));
|
||||
|
@ -492,13 +523,15 @@ void GuiScraperMenu::openOtherOptions()
|
|||
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
||||
|
||||
// Scraper region.
|
||||
auto scraper_region = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "REGION", false);
|
||||
auto scraper_region = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "REGION", false);
|
||||
std::string selectedScraperRegion = Settings::getInstance()->getString("ScraperRegion");
|
||||
// clang-format off
|
||||
scraper_region->add("Europe", "eu", selectedScraperRegion == "eu");
|
||||
scraper_region->add("Japan", "jp", selectedScraperRegion == "jp");
|
||||
scraper_region->add("USA", "us", selectedScraperRegion == "us");
|
||||
scraper_region->add("World", "wor", selectedScraperRegion == "wor");
|
||||
// clang-format on
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
// configuration file. Simply set the region to "Europe" in this case.
|
||||
if (scraper_region->getSelectedObjects().size() == 0)
|
||||
|
@ -515,14 +548,16 @@ void GuiScraperMenu::openOtherOptions()
|
|||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||
scraper_region->setEnabled(false);
|
||||
scraper_region->setOpacity(DISABLED_OPACITY);
|
||||
scraper_region->getParent()->getChild(scraper_region->
|
||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
||||
scraper_region->getParent()
|
||||
->getChild(scraper_region->getChildIndex() - 1)
|
||||
->setOpacity(DISABLED_OPACITY);
|
||||
}
|
||||
|
||||
// Scraper language.
|
||||
auto scraper_language = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "PREFERRED LANGUAGE", false);
|
||||
auto scraper_language = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "PREFERRED LANGUAGE", false);
|
||||
std::string selectedScraperLanguage = Settings::getInstance()->getString("ScraperLanguage");
|
||||
// clang-format off
|
||||
scraper_language->add("English", "en", selectedScraperLanguage == "en");
|
||||
scraper_language->add("Español", "es", selectedScraperLanguage == "es");
|
||||
scraper_language->add("Português", "pt", selectedScraperLanguage == "pt");
|
||||
|
@ -543,6 +578,7 @@ void GuiScraperMenu::openOtherOptions()
|
|||
scraper_language->add("Čeština", "cz", selectedScraperLanguage == "cz");
|
||||
scraper_language->add("Slovenčina", "sk", selectedScraperLanguage == "sk");
|
||||
scraper_language->add("Türkçe", "tr", selectedScraperLanguage == "tr");
|
||||
//clang-format on
|
||||
// If there are no objects returned, then there must be a manually modified entry in the
|
||||
// configuration file. Simply set the language to "English" in this case.
|
||||
if (scraper_language->getSelectedObjects().size() == 0)
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
#include "scrapers/Scraper.h"
|
||||
|
||||
class FileData;
|
||||
template<typename T>
|
||||
class OptionListComponent;
|
||||
class SwitchComponent;
|
||||
class SystemData;
|
||||
|
||||
template <typename T> class OptionListComponent;
|
||||
typedef std::function<bool(SystemData*, FileData*)> GameFilterFunc;
|
||||
|
||||
class GuiScraperMenu : public GuiComponent
|
||||
|
@ -38,16 +37,18 @@ private:
|
|||
void pressedStart();
|
||||
void start();
|
||||
|
||||
void addEntry(const std::string&, unsigned int color,
|
||||
bool add_arrow, const std::function<void()>& func);
|
||||
void addEntry(const std::string&,
|
||||
unsigned int color,
|
||||
bool add_arrow,
|
||||
const std::function<void()>& func);
|
||||
void openAccountOptions();
|
||||
void openContentOptions();
|
||||
void openMiximageOptions();
|
||||
void openOfflineGenerator(GuiSettings* settings);
|
||||
void openOtherOptions();
|
||||
|
||||
std::queue<ScraperSearchParams> getSearches(
|
||||
std::vector<SystemData*> systems, GameFilterFunc selector);
|
||||
std::queue<ScraperSearchParams> getSearches(std::vector<SystemData*> systems,
|
||||
GameFilterFunc selector);
|
||||
|
||||
std::shared_ptr<OptionListComponent<std::string>> mScraper;
|
||||
std::shared_ptr<OptionListComponent<GameFilterFunc>> mFilters;
|
||||
|
|
|
@ -11,27 +11,26 @@
|
|||
|
||||
#include "guis/GuiScraperMulti.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "Gamelist.h"
|
||||
#include "MameNames.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "guis/GuiScraperSearch.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "Gamelist.h"
|
||||
#include "MameNames.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
|
||||
GuiScraperMulti::GuiScraperMulti(
|
||||
Window* window,
|
||||
GuiScraperMulti::GuiScraperMulti(Window* window,
|
||||
const std::queue<ScraperSearchParams>& searches,
|
||||
bool approveResults)
|
||||
: GuiComponent(window),
|
||||
mBackground(window, ":/graphics/frame.svg"),
|
||||
mGrid(window, Vector2i(1, 5)),
|
||||
mSearchQueue(searches),
|
||||
mApproveResults(approveResults)
|
||||
: GuiComponent(window)
|
||||
, mBackground(window, ":/graphics/frame.svg")
|
||||
, mGrid(window, Vector2i(1, 5))
|
||||
, mSearchQueue(searches)
|
||||
, mApproveResults(approveResults)
|
||||
{
|
||||
assert(mSearchQueue.size());
|
||||
|
||||
|
@ -50,35 +49,36 @@ GuiScraperMulti::GuiScraperMulti(
|
|||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
|
||||
|
||||
mSystem = std::make_shared<TextComponent>(mWindow, "SYSTEM",
|
||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
||||
mSystem = std::make_shared<TextComponent>(mWindow, "SYSTEM", Font::get(FONT_SIZE_MEDIUM),
|
||||
0x777777FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mSystem, Vector2i(0, 1), false, true);
|
||||
|
||||
mSubtitle = std::make_shared<TextComponent>(mWindow, "subtitle text",
|
||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||
mSubtitle = std::make_shared<TextComponent>(
|
||||
mWindow, "subtitle text", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||
mGrid.setEntry(mSubtitle, Vector2i(0, 2), false, true);
|
||||
|
||||
if (mApproveResults && !Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
||||
GuiScraperSearch::NEVER_AUTO_ACCEPT, mTotalGames);
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||
mWindow, GuiScraperSearch::NEVER_AUTO_ACCEPT, mTotalGames);
|
||||
else if (mApproveResults && Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
||||
GuiScraperSearch::ACCEPT_SINGLE_MATCHES, mTotalGames);
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||
mWindow, GuiScraperSearch::ACCEPT_SINGLE_MATCHES, mTotalGames);
|
||||
else if (!mApproveResults)
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
||||
GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, mTotalGames);
|
||||
mSearchComp->setAcceptCallback(std::bind(&GuiScraperMulti::acceptResult,
|
||||
this, std::placeholders::_1));
|
||||
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||
mWindow, GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, mTotalGames);
|
||||
mSearchComp->setAcceptCallback(
|
||||
std::bind(&GuiScraperMulti::acceptResult, this, std::placeholders::_1));
|
||||
mSearchComp->setSkipCallback(std::bind(&GuiScraperMulti::skip, this));
|
||||
mSearchComp->setCancelCallback(std::bind(&GuiScraperMulti::finish, this));
|
||||
mGrid.setEntry(mSearchComp, Vector2i(0, 3), mSearchComp->getSearchType() !=
|
||||
GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, true);
|
||||
mGrid.setEntry(mSearchComp, Vector2i(0, 3),
|
||||
mSearchComp->getSearchType() != GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT,
|
||||
true);
|
||||
|
||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||
|
||||
if (mApproveResults) {
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH",
|
||||
"refine search", [&] {
|
||||
buttons.push_back(
|
||||
std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH", "refine search", [&] {
|
||||
mSearchComp->openInputScreen(mSearchQueue.front());
|
||||
mGrid.resetCursor();
|
||||
}));
|
||||
|
@ -89,8 +89,8 @@ GuiScraperMulti::GuiScraperMulti(
|
|||
}));
|
||||
}
|
||||
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "STOP",
|
||||
"stop", std::bind(&GuiScraperMulti::finish, this)));
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "STOP", "stop",
|
||||
std::bind(&GuiScraperMulti::finish, this)));
|
||||
|
||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false);
|
||||
|
@ -101,8 +101,8 @@ GuiScraperMulti::GuiScraperMulti(
|
|||
float width = Math::clamp(0.95f * aspectValue, 0.70f, 0.95f) * Renderer::getScreenWidth();
|
||||
|
||||
setSize(width, Renderer::getScreenHeight() * 0.849f);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() -
|
||||
mSize.y()) / 2);
|
||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||
|
||||
doNextSearch();
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ GuiScraperMulti::~GuiScraperMulti()
|
|||
{
|
||||
if (mTotalSuccessful > 0) {
|
||||
// Sort all systems to possibly update their view style from Basic to Detailed or Video.
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
it !=SystemData::sSystemVector.cend(); it++) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
(*it)->sortSystem();
|
||||
}
|
||||
}
|
||||
|
@ -121,10 +121,10 @@ GuiScraperMulti::~GuiScraperMulti()
|
|||
|
||||
void GuiScraperMulti::onSizeChanged()
|
||||
{
|
||||
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
||||
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||
|
||||
mGrid.setRowHeightPerc(0, mTitle->getFont()->getLetterHeight() * 1.9725f / mSize.y(), false);
|
||||
mGrid.setRowHeightPerc(1, (mSystem->getFont()->getLetterHeight() + 2) / mSize.y(), false);
|
||||
mGrid.setRowHeightPerc(1, (mSystem->getFont()->getLetterHeight() + 2.0f) / mSize.y(), false);
|
||||
mGrid.setRowHeightPerc(2, mSubtitle->getFont()->getHeight() * 1.75f / mSize.y(), false);
|
||||
mGrid.setRowHeightPerc(4, mButtonGrid->getSize().y() / mSize.y(), false);
|
||||
mGrid.setSize(mSize);
|
||||
|
@ -149,33 +149,35 @@ void GuiScraperMulti::doNextSearch()
|
|||
else {
|
||||
if (mSearchQueue.front().game->isArcadeGame() &&
|
||||
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
||||
scrapeName = Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath()) +
|
||||
" (" + MameNames::getInstance()->getCleanName(mSearchQueue.front().game->
|
||||
getCleanName()) + ")";
|
||||
scrapeName =
|
||||
Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath()) + " (" +
|
||||
MameNames::getInstance()->getCleanName(mSearchQueue.front().game->getCleanName()) +
|
||||
")";
|
||||
else
|
||||
scrapeName = Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath());
|
||||
}
|
||||
|
||||
// Extract possible subfolders from the path.
|
||||
std::string folderPath = Utils::String::replace(
|
||||
Utils::FileSystem::getParent(mSearchQueue.front().game->getPath()),
|
||||
std::string folderPath =
|
||||
Utils::String::replace(Utils::FileSystem::getParent(mSearchQueue.front().game->getPath()),
|
||||
mSearchQueue.front().system->getSystemEnvData()->mStartPath, "");
|
||||
|
||||
if (folderPath.size() >= 2) {
|
||||
folderPath.erase(0, 1);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
folderPath.push_back('\\');
|
||||
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
||||
#else
|
||||
#else
|
||||
folderPath.push_back('/');
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// Update subtitle.
|
||||
ss.str("");
|
||||
ss << "GAME " << (mCurrentGame + 1) << " OF " << mTotalGames << " - " << folderPath <<
|
||||
scrapeName << ((mSearchQueue.front().game->getType() == FOLDER) ? " " +
|
||||
ViewController::FOLDER_CHAR : "");
|
||||
ss << "GAME " << (mCurrentGame + 1) << " OF " << mTotalGames << " - " << folderPath
|
||||
<< scrapeName
|
||||
<< ((mSearchQueue.front().game->getType() == FOLDER) ? " " + ViewController::FOLDER_CHAR :
|
||||
"");
|
||||
mSubtitle->setText(ss.str());
|
||||
|
||||
mSearchComp->search(mSearchQueue.front());
|
||||
|
@ -212,12 +214,12 @@ void GuiScraperMulti::finish()
|
|||
ss << "NO GAMES WERE SCRAPED";
|
||||
}
|
||||
else {
|
||||
ss << mTotalSuccessful << " GAME" <<
|
||||
((mTotalSuccessful > 1) ? "S" : "") << " SUCCESSFULLY SCRAPED";
|
||||
ss << mTotalSuccessful << " GAME" << ((mTotalSuccessful > 1) ? "S" : "")
|
||||
<< " SUCCESSFULLY SCRAPED";
|
||||
|
||||
if (mTotalSkipped > 0)
|
||||
ss << "\n" << mTotalSkipped << " GAME"
|
||||
<< ((mTotalSkipped > 1) ? "S" : "") << " SKIPPED";
|
||||
ss << "\n"
|
||||
<< mTotalSkipped << " GAME" << ((mTotalSkipped > 1) ? "S" : "") << " SKIPPED";
|
||||
}
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), ss.str(), "OK", [&] {
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#ifndef ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
||||
#define ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "components/NinePatchComponent.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "MetaData.h"
|
||||
|
||||
class GuiScraperSearch;
|
||||
class TextComponent;
|
||||
|
@ -24,8 +24,7 @@ class TextComponent;
|
|||
class GuiScraperMulti : public GuiComponent
|
||||
{
|
||||
public:
|
||||
GuiScraperMulti(
|
||||
Window* window,
|
||||
GuiScraperMulti(Window* window,
|
||||
const std::queue<ScraperSearchParams>& searches,
|
||||
bool approveResults);
|
||||
|
||||
|
@ -40,15 +39,7 @@ private:
|
|||
void acceptResult(const ScraperSearchResult& result);
|
||||
void skip();
|
||||
void doNextSearch();
|
||||
|
||||
void finish();
|
||||
unsigned int mTotalGames;
|
||||
unsigned int mCurrentGame;
|
||||
unsigned int mTotalSuccessful;
|
||||
unsigned int mTotalSkipped;
|
||||
std::queue<ScraperSearchParams> mSearchQueue;
|
||||
std::vector<MetaDataDecl> mMetaDataDecl;
|
||||
bool mApproveResults;
|
||||
|
||||
NinePatchComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
@ -58,6 +49,14 @@ private:
|
|||
std::shared_ptr<TextComponent> mSubtitle;
|
||||
std::shared_ptr<GuiScraperSearch> mSearchComp;
|
||||
std::shared_ptr<ComponentGrid> mButtonGrid;
|
||||
|
||||
std::queue<ScraperSearchParams> mSearchQueue;
|
||||
std::vector<MetaDataDecl> mMetaDataDecl;
|
||||
unsigned int mTotalGames;
|
||||
unsigned int mCurrentGame;
|
||||
unsigned int mTotalSuccessful;
|
||||
unsigned int mTotalSkipped;
|
||||
bool mApproveResults;
|
||||
};
|
||||
|
||||
#endif // ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
|
||||
#include "guis/GuiScraperSearch.h"
|
||||
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "MameNames.h"
|
||||
#include "PlatformId.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "components/ComponentList.h"
|
||||
#include "components/DateTimeEditComponent.h"
|
||||
#include "components/ImageComponent.h"
|
||||
|
@ -26,28 +33,18 @@
|
|||
#include "resources/Font.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "MameNames.h"
|
||||
#include "PlatformId.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
|
||||
#define FAILED_VERIFICATION_RETRIES 8
|
||||
|
||||
GuiScraperSearch::GuiScraperSearch(
|
||||
Window* window,
|
||||
SearchType type,
|
||||
unsigned int scrapeCount)
|
||||
: GuiComponent(window),
|
||||
mGrid(window, Vector2i(4, 3)),
|
||||
mBusyAnim(window),
|
||||
mSearchType(type),
|
||||
mScrapeCount(scrapeCount),
|
||||
mScrapeRatings(false),
|
||||
mRefinedSearch(false),
|
||||
mFoundGame(false)
|
||||
GuiScraperSearch::GuiScraperSearch(Window* window, SearchType type, unsigned int scrapeCount)
|
||||
: GuiComponent(window)
|
||||
, mGrid(window, Vector2i(4, 3))
|
||||
, mBusyAnim(window)
|
||||
, mSearchType(type)
|
||||
, mScrapeCount(scrapeCount)
|
||||
, mScrapeRatings(false)
|
||||
, mRefinedSearch(false)
|
||||
, mFoundGame(false)
|
||||
{
|
||||
addChild(&mGrid);
|
||||
|
||||
|
@ -56,8 +53,8 @@ GuiScraperSearch::GuiScraperSearch(
|
|||
mRetryCount = 0;
|
||||
|
||||
// Left spacer (empty component, needed for borders).
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0),
|
||||
false, false, Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false, false,
|
||||
Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||
|
||||
// Selected result name.
|
||||
mResultName = std::make_shared<TextComponent>(mWindow, "Result name",
|
||||
|
@ -89,40 +86,47 @@ GuiScraperSearch::GuiScraperSearch(
|
|||
mMD_ReleaseDate = std::make_shared<DateTimeEditComponent>(mWindow);
|
||||
mMD_ReleaseDate->setColor(mdColor);
|
||||
mMD_ReleaseDate->setUppercase(true);
|
||||
mMD_Developer = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Publisher = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Genre = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Players = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Developer =
|
||||
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Publisher =
|
||||
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Genre =
|
||||
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Players =
|
||||
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||
mMD_Filler = std::make_shared<TextComponent>(mWindow, "", font, mdColor);
|
||||
|
||||
if (Settings::getInstance()->getString("Scraper") != "thegamesdb")
|
||||
mScrapeRatings = true;
|
||||
|
||||
if (mScrapeRatings)
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "RATING:", font, mdLblColor), mMD_Rating, false));
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "RELEASED:", font, mdLblColor), mMD_ReleaseDate));
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "DEVELOPER:", font, mdLblColor), mMD_Developer));
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "PUBLISHER:", font, mdLblColor), mMD_Publisher));
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "GENRE:", font, mdLblColor), mMD_Genre));
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "PLAYERS:", font, mdLblColor), mMD_Players));
|
||||
mMD_Pairs.push_back(
|
||||
MetaDataPair(std::make_shared<TextComponent>(mWindow, "RATING:", font, mdLblColor),
|
||||
mMD_Rating, false));
|
||||
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "RELEASED:", font, mdLblColor), mMD_ReleaseDate));
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "DEVELOPER:", font, mdLblColor), mMD_Developer));
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "PUBLISHER:", font, mdLblColor), mMD_Publisher));
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "GENRE:", font, mdLblColor), mMD_Genre));
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "PLAYERS:", font, mdLblColor), mMD_Players));
|
||||
|
||||
// If no rating is being scraped, add a filler to make sure that the fonts keep the same
|
||||
// size so the GUI looks consistent.
|
||||
if (!mScrapeRatings)
|
||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
||||
(mWindow, "", font, mdLblColor), mMD_Filler));
|
||||
mMD_Pairs.push_back(MetaDataPair(
|
||||
std::make_shared<TextComponent>(mWindow, "", font, mdLblColor), mMD_Filler));
|
||||
|
||||
mMD_Grid = std::make_shared<ComponentGrid>(mWindow,
|
||||
Vector2i(2, static_cast<int>(mMD_Pairs.size()*2 - 1)));
|
||||
mMD_Grid = std::make_shared<ComponentGrid>(
|
||||
mWindow, Vector2i(2, static_cast<int>(mMD_Pairs.size() * 2 - 1)));
|
||||
unsigned int i = 0;
|
||||
for (auto it = mMD_Pairs.cbegin(); it != mMD_Pairs.cend(); it++) {
|
||||
mMD_Grid->setEntry(it->first, Vector2i(0, i), false, true);
|
||||
|
@ -135,7 +139,9 @@ GuiScraperSearch::GuiScraperSearch(
|
|||
// Result list.
|
||||
mResultList = std::make_shared<ComponentList>(mWindow);
|
||||
mResultList->setCursorChangedCallback([this](CursorState state) {
|
||||
if (state == CURSOR_STOPPED) updateInfoPane(); });
|
||||
if (state == CURSOR_STOPPED)
|
||||
updateInfoPane();
|
||||
});
|
||||
|
||||
updateViewStyle();
|
||||
}
|
||||
|
@ -216,11 +222,11 @@ void GuiScraperSearch::onSizeChanged()
|
|||
resizeMetadata();
|
||||
|
||||
if (mSearchType != ALWAYS_ACCEPT_FIRST_RESULT)
|
||||
mDescContainer->setSize(mGrid.getColWidth(1) * boxartCellScale +
|
||||
mGrid.getColWidth(2), mResultDesc->getFont()->getHeight() * 3);
|
||||
mDescContainer->setSize(mGrid.getColWidth(1) * boxartCellScale + mGrid.getColWidth(2),
|
||||
mResultDesc->getFont()->getHeight() * 3.0f);
|
||||
else
|
||||
mDescContainer->setSize(mGrid.getColWidth(3) * boxartCellScale,
|
||||
mResultDesc->getFont()->getHeight() * 6);
|
||||
mResultDesc->getFont()->getHeight() * 6.0f);
|
||||
|
||||
// Make description text wrap at edge of container.
|
||||
mResultDesc->setSize(mDescContainer->getSize().x(), 0);
|
||||
|
@ -247,13 +253,14 @@ void GuiScraperSearch::resizeMetadata()
|
|||
it->first->setFont(fontLbl);
|
||||
it->first->setSize(0, 0);
|
||||
if (it->first->getSize().x() > maxLblWidth)
|
||||
maxLblWidth = it->first->getSize().x() +
|
||||
(16.0f * Renderer::getScreenWidthModifier());
|
||||
maxLblWidth =
|
||||
it->first->getSize().x() + (16.0f * Renderer::getScreenWidthModifier());
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < mMD_Pairs.size(); i++)
|
||||
mMD_Grid->setRowHeightPerc(i * 2, (fontLbl->getLetterHeight() +
|
||||
(2.0f * Renderer::getScreenHeightModifier())) / mMD_Grid->getSize().y());
|
||||
mMD_Grid->setRowHeightPerc(
|
||||
i * 2, (fontLbl->getLetterHeight() + (2.0f * Renderer::getScreenHeightModifier())) /
|
||||
mMD_Grid->getSize().y());
|
||||
|
||||
// Update component fonts.
|
||||
mMD_ReleaseDate->setFont(fontComp);
|
||||
|
@ -289,8 +296,8 @@ void GuiScraperSearch::updateViewStyle()
|
|||
GridFlags::BORDER_TOP);
|
||||
|
||||
// Need a border on the bottom left.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 2),
|
||||
false, false, Vector2i(3, 1), GridFlags::BORDER_BOTTOM);
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 2), false, false,
|
||||
Vector2i(3, 1), GridFlags::BORDER_BOTTOM);
|
||||
|
||||
// Show description on the right.
|
||||
mGrid.setEntry(mDescContainer, Vector2i(3, 0), false, false, Vector2i(1, 3),
|
||||
|
@ -300,8 +307,8 @@ void GuiScraperSearch::updateViewStyle()
|
|||
}
|
||||
else {
|
||||
// Fake row where name would be.
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0),
|
||||
false, true, Vector2i(2, 1), GridFlags::BORDER_TOP);
|
||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0), false, true,
|
||||
Vector2i(2, 1), GridFlags::BORDER_TOP);
|
||||
|
||||
// Show result list on the right.
|
||||
mGrid.setEntry(mResultList, Vector2i(3, 0), true, true, Vector2i(1, 3),
|
||||
|
@ -355,7 +362,8 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
|||
if (results.empty()) {
|
||||
// Check if the scraper used is still valid.
|
||||
if (!isValidConfiguredScraper()) {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, getHelpStyle(),
|
||||
Utils::String::toUpper("Configured scraper is no longer available.\n"
|
||||
"Please change the scraping source in the settings."),
|
||||
"FINISH", mSkipCallback));
|
||||
|
@ -363,8 +371,8 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
|||
else {
|
||||
mFoundGame = false;
|
||||
ComponentListRow row;
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "NO GAMES FOUND",
|
||||
font, color), true);
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "NO GAMES FOUND", font, color),
|
||||
true);
|
||||
|
||||
if (mSkipCallback)
|
||||
row.makeAcceptInputHandler(mSkipCallback);
|
||||
|
@ -379,8 +387,10 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
|||
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||
Utils::String::toUpper(results.at(i).mdl.get("name")), font, color), true);
|
||||
row.addElement(
|
||||
std::make_shared<TextComponent>(
|
||||
mWindow, Utils::String::toUpper(results.at(i).mdl.get("name")), font, color),
|
||||
true);
|
||||
row.makeAcceptInputHandler([this, i] { returnResult(mScraperResults.at(i)); });
|
||||
mResultList->addRow(row);
|
||||
}
|
||||
|
@ -399,8 +409,8 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
|||
// For automatic mode, if there's no thumbnail to download or no matching games found,
|
||||
// proceed directly or we'll get stuck forever.
|
||||
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) {
|
||||
if (mScraperResults.size() == 0 || (mScraperResults.size() > 0 &&
|
||||
mScraperResults.front().thumbnailImageUrl == "")) {
|
||||
if (mScraperResults.size() == 0 ||
|
||||
(mScraperResults.size() > 0 && mScraperResults.front().thumbnailImageUrl == "")) {
|
||||
if (mScraperResults.size() == 0)
|
||||
mSkipCallback();
|
||||
else
|
||||
|
@ -424,8 +434,8 @@ void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status s
|
|||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mRetrySearch = true;
|
||||
mRetryCount++;
|
||||
LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount <<
|
||||
" of " << FAILED_VERIFICATION_RETRIES;
|
||||
LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount << " of "
|
||||
<< FAILED_VERIFICATION_RETRIES;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
@ -435,14 +445,15 @@ void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status s
|
|||
if (mScrapeCount > 1) {
|
||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
||||
"RETRY", std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
"SKIP", mSkipCallback,
|
||||
"CANCEL", mCancelCallback, true));
|
||||
"RETRY",
|
||||
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
"SKIP", mSkipCallback, "CANCEL", mCancelCallback, true));
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
||||
"RETRY", std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
"RETRY",
|
||||
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||
"CANCEL", mCancelCallback, "", nullptr, true));
|
||||
}
|
||||
}
|
||||
|
@ -489,8 +500,8 @@ void GuiScraperSearch::updateInfoPane()
|
|||
// Add an entry into the thumbnail map, this way we can track and download
|
||||
// each thumbnail separately even as they're downloading while scrolling
|
||||
// through the result list.
|
||||
mThumbnailReqMap.insert(std::pair<std::string,
|
||||
std::unique_ptr<HttpReq>>(mScraperResults[i].thumbnailImageUrl,
|
||||
mThumbnailReqMap.insert(std::pair<std::string, std::unique_ptr<HttpReq>>(
|
||||
mScraperResults[i].thumbnailImageUrl,
|
||||
std::unique_ptr<HttpReq>(new HttpReq(thumb))));
|
||||
}
|
||||
}
|
||||
|
@ -593,8 +604,8 @@ void GuiScraperSearch::update(int deltaTime)
|
|||
|
||||
// Check if the thumbnail for the currently selected game has finished downloading.
|
||||
if (mScraperResults.size() > 0) {
|
||||
auto it = mThumbnailReqMap.find(mScraperResults[mResultList->
|
||||
getCursorId()].thumbnailImageUrl);
|
||||
auto it =
|
||||
mThumbnailReqMap.find(mScraperResults[mResultList->getCursorId()].thumbnailImageUrl);
|
||||
if (it != mThumbnailReqMap.end() && it->second->status() != HttpReq::REQ_IN_PROGRESS)
|
||||
updateThumbnail();
|
||||
}
|
||||
|
@ -683,11 +694,12 @@ void GuiScraperSearch::update(int deltaTime)
|
|||
if (mScrapeResult.mediaFilesDownloadStatus == COMPLETED &&
|
||||
Settings::getInstance()->getBool("MiximageGenerate")) {
|
||||
std::string currentMiximage = mLastSearch.game->getMiximagePath();
|
||||
if (currentMiximage == "" || (currentMiximage != "" &&
|
||||
if (currentMiximage == "" ||
|
||||
(currentMiximage != "" &&
|
||||
Settings::getInstance()->getBool("MiximageOverwrite"))) {
|
||||
|
||||
mMiximageGenerator = std::make_unique<MiximageGenerator>(mLastSearch.game,
|
||||
mResultMessage);
|
||||
mMiximageGenerator =
|
||||
std::make_unique<MiximageGenerator>(mLastSearch.game, mResultMessage);
|
||||
|
||||
// The promise/future mechanism is used as signaling for the thread to
|
||||
// indicate that processing has been completed. The reason to run a separate
|
||||
|
@ -697,8 +709,9 @@ void GuiScraperSearch::update(int deltaTime)
|
|||
std::promise<bool>().swap(mGeneratorPromise);
|
||||
mGeneratorFuture = mGeneratorPromise.get_future();
|
||||
|
||||
mMiximageGeneratorThread = std::thread(&MiximageGenerator::startThread,
|
||||
mMiximageGenerator.get(), &mGeneratorPromise);
|
||||
mMiximageGeneratorThread =
|
||||
std::thread(&MiximageGenerator::startThread, mMiximageGenerator.get(),
|
||||
&mGeneratorPromise);
|
||||
}
|
||||
else {
|
||||
returnResult(mScrapeResult);
|
||||
|
@ -791,12 +804,13 @@ void GuiScraperSearch::openInputScreen(ScraperSearchParams& params)
|
|||
searchString = params.nameOverride;
|
||||
}
|
||||
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH",
|
||||
searchString, searchForFunc, false, "SEARCH", "APPLY CHANGES?"));
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH", searchString,
|
||||
searchForFunc, false, "SEARCH", "APPLY CHANGES?"));
|
||||
}
|
||||
|
||||
bool GuiScraperSearch::saveMetadata(
|
||||
const ScraperSearchResult& result, MetaDataList& metadata, FileData* scrapedGame)
|
||||
bool GuiScraperSearch::saveMetadata(const ScraperSearchResult& result,
|
||||
MetaDataList& metadata,
|
||||
FileData* scrapedGame)
|
||||
{
|
||||
bool metadataUpdated = false;
|
||||
bool hasDefaultName = false;
|
||||
|
@ -897,13 +911,3 @@ HelpStyle GuiScraperSearch::getHelpStyle()
|
|||
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
|
||||
return style;
|
||||
}
|
||||
|
||||
void GuiScraperSearch::onFocusGained()
|
||||
{
|
||||
mGrid.onFocusGained();
|
||||
}
|
||||
|
||||
void GuiScraperSearch::onFocusLost()
|
||||
{
|
||||
mGrid.onFocusLost();
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
#ifndef ES_APP_GUIS_GUI_SCRAPER_SEARCH_H
|
||||
#define ES_APP_GUIS_GUI_SCRAPER_SEARCH_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "MiximageGenerator.h"
|
||||
#include "components/BusyComponent.h"
|
||||
#include "components/ComponentGrid.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "MiximageGenerator.h"
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
@ -36,9 +36,9 @@ class GuiScraperSearch : public GuiComponent
|
|||
{
|
||||
public:
|
||||
enum SearchType {
|
||||
ALWAYS_ACCEPT_FIRST_RESULT,
|
||||
ACCEPT_SINGLE_MATCHES,
|
||||
NEVER_AUTO_ACCEPT
|
||||
ALWAYS_ACCEPT_FIRST_RESULT, // Automatic mode.
|
||||
ACCEPT_SINGLE_MATCHES, // Semi-automatic mode.
|
||||
NEVER_AUTO_ACCEPT // Manual mode.
|
||||
};
|
||||
|
||||
GuiScraperSearch(Window* window, SearchType searchType, unsigned int scrapeCount = 1);
|
||||
|
@ -47,20 +47,29 @@ public:
|
|||
void search(const ScraperSearchParams& params);
|
||||
void openInputScreen(ScraperSearchParams& from);
|
||||
void stop();
|
||||
inline SearchType getSearchType() const { return mSearchType; }
|
||||
SearchType getSearchType() const { return mSearchType; }
|
||||
bool getSavedNewMedia()
|
||||
{ return (mMDResolveHandle ? mMDResolveHandle->getSavedNewMedia() : false); };
|
||||
{
|
||||
return (mMDResolveHandle ? mMDResolveHandle->getSavedNewMedia() : false);
|
||||
}
|
||||
static bool saveMetadata(const ScraperSearchResult& result,
|
||||
MetaDataList& metadata, FileData* scrapedGame);
|
||||
MetaDataList& metadata,
|
||||
FileData* scrapedGame);
|
||||
|
||||
// Metadata assets will be resolved before calling the accept callback
|
||||
// (e.g. result.mdl's "image" is automatically downloaded and properly set).
|
||||
inline void setAcceptCallback(const std::function<void(const ScraperSearchResult&)>&
|
||||
acceptCallback) { mAcceptCallback = acceptCallback; }
|
||||
inline void setSkipCallback(const std::function<void()>&
|
||||
skipCallback) { mSkipCallback = skipCallback; };
|
||||
inline void setCancelCallback(const std::function<void()>&
|
||||
cancelCallback) { mScrapeCount -= 1; mCancelCallback = cancelCallback; }
|
||||
// Metadata assets will be resolved before calling the accept callback.
|
||||
void setAcceptCallback(const std::function<void(const ScraperSearchResult&)>& acceptCallback)
|
||||
{
|
||||
mAcceptCallback = acceptCallback;
|
||||
}
|
||||
void setSkipCallback(const std::function<void()>& skipCallback)
|
||||
{
|
||||
mSkipCallback = skipCallback;
|
||||
}
|
||||
void setCancelCallback(const std::function<void()>& cancelCallback)
|
||||
{
|
||||
mScrapeCount -= 1;
|
||||
mCancelCallback = cancelCallback;
|
||||
}
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
|
@ -68,20 +77,19 @@ public:
|
|||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
HelpStyle getHelpStyle() override;
|
||||
void onSizeChanged() override;
|
||||
void onFocusGained() override;
|
||||
void onFocusLost() override;
|
||||
|
||||
void unsetRefinedSearch() { mRefinedSearch = false; }
|
||||
void onFocusGained() override { mGrid.onFocusGained(); }
|
||||
void onFocusLost() override { mGrid.onFocusLost(); }
|
||||
|
||||
private:
|
||||
void updateViewStyle();
|
||||
void updateThumbnail();
|
||||
void updateInfoPane();
|
||||
|
||||
void resizeMetadata();
|
||||
|
||||
void onSearchError(const std::string& error, HttpReq::Status status =
|
||||
HttpReq::REQ_UNDEFINED_ERROR);
|
||||
void onSearchError(const std::string& error,
|
||||
HttpReq::Status status = HttpReq::REQ_UNDEFINED_ERROR);
|
||||
void onSearchDone(const std::vector<ScraperSearchResult>& results);
|
||||
|
||||
int getSelectedIndex();
|
||||
|
@ -117,8 +125,13 @@ private:
|
|||
bool resize;
|
||||
|
||||
MetaDataPair(const std::shared_ptr<TextComponent>& f,
|
||||
const std::shared_ptr<GuiComponent>& s, bool r = true)
|
||||
: first(f), second(s), resize(r) {};
|
||||
const std::shared_ptr<GuiComponent>& s,
|
||||
bool r = true)
|
||||
: first(f)
|
||||
, second(s)
|
||||
, resize(r)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<MetaDataPair> mMD_Pairs;
|
||||
|
|
|
@ -9,54 +9,55 @@
|
|||
|
||||
#include "guis/GuiScreensaverOptions.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "components/OptionListComponent.h"
|
||||
#include "components/SliderComponent.h"
|
||||
#include "components/SwitchComponent.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "Settings.h"
|
||||
|
||||
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string& title)
|
||||
: GuiSettings(window, title)
|
||||
{
|
||||
// Screensaver timer.
|
||||
auto screensaver_timer = std::make_shared<SliderComponent>(mWindow, 0.f, 30.f, 1.f, "m");
|
||||
screensaver_timer->setValue(static_cast<float>(Settings::getInstance()->
|
||||
getInt("ScreensaverTimer") / (1000 * 60)));
|
||||
auto screensaver_timer = std::make_shared<SliderComponent>(mWindow, 0.0f, 30.0f, 1.0f, "m");
|
||||
screensaver_timer->setValue(
|
||||
static_cast<float>(Settings::getInstance()->getInt("ScreensaverTimer") / (1000 * 60)));
|
||||
addWithLabel("START SCREENSAVER AFTER (MINUTES)", screensaver_timer);
|
||||
addSaveFunc([screensaver_timer, this] {
|
||||
if (static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)) !=
|
||||
Settings::getInstance()->getInt("ScreensaverTimer")) {
|
||||
Settings::getInstance()->setInt("ScreensaverTimer",
|
||||
Settings::getInstance()->setInt(
|
||||
"ScreensaverTimer",
|
||||
static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)));
|
||||
setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Screensaver type.
|
||||
auto screensaver_type = std::make_shared<OptionListComponent<std::string>>
|
||||
(mWindow, getHelpStyle(), "SCREENSAVER TYPE", false);
|
||||
auto screensaver_type = std::make_shared<OptionListComponent<std::string>>(
|
||||
mWindow, getHelpStyle(), "SCREENSAVER TYPE", false);
|
||||
std::vector<std::string> screensavers;
|
||||
screensavers.push_back("dim");
|
||||
screensavers.push_back("black");
|
||||
screensavers.push_back("slideshow");
|
||||
screensavers.push_back("video");
|
||||
for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++)
|
||||
screensaver_type->add(*it, *it, Settings::getInstance()->
|
||||
getString("ScreensaverType") == *it);
|
||||
screensaver_type->add(*it, *it,
|
||||
Settings::getInstance()->getString("ScreensaverType") == *it);
|
||||
addWithLabel("SCREENSAVER TYPE", screensaver_type);
|
||||
addSaveFunc([screensaver_type, this] {
|
||||
if (screensaver_type->getSelected() !=
|
||||
Settings::getInstance()->getString("ScreensaverType")) {
|
||||
if (screensaver_type->getSelected() == "video") {
|
||||
// If before it wasn't risky but now there's a risk of problems, show warning.
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, getHelpStyle(),
|
||||
"THE 'VIDEO' SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS\n\n"
|
||||
"IF YOU DO NOT HAVE ANY VIDEOS, THE\n"
|
||||
"SCREENSAVER WILL DEFAULT TO 'DIM'",
|
||||
"OK", [] { return; }, "", nullptr, "", nullptr));
|
||||
}
|
||||
Settings::getInstance()->setString("ScreensaverType",
|
||||
screensaver_type->getSelected());
|
||||
Settings::getInstance()->setString("ScreensaverType", screensaver_type->getSelected());
|
||||
setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
@ -77,19 +78,21 @@ GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string&
|
|||
// Show filtered menu.
|
||||
ComponentListRow 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(
|
||||
&GuiScreensaverOptions::openSlideshowScreensaverOptions, this));
|
||||
row.makeAcceptInputHandler(
|
||||
std::bind(&GuiScreensaverOptions::openSlideshowScreensaverOptions, this));
|
||||
addRow(row);
|
||||
|
||||
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(
|
||||
&GuiScreensaverOptions::openVideoScreensaverOptions, this));
|
||||
row.makeAcceptInputHandler(
|
||||
std::bind(&GuiScreensaverOptions::openVideoScreensaverOptions, this));
|
||||
addRow(row);
|
||||
}
|
||||
|
||||
|
@ -99,25 +102,25 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
|
||||
// Timer for swapping images (in seconds).
|
||||
auto screensaver_swap_image_timeout =
|
||||
std::make_shared<SliderComponent>(mWindow, 2.f, 120.f, 2.f, "s");
|
||||
screensaver_swap_image_timeout->setValue(static_cast<float>(Settings::getInstance()->
|
||||
getInt("ScreensaverSwapImageTimeout") / (1000)));
|
||||
std::make_shared<SliderComponent>(mWindow, 2.0f, 120.0f, 2.0f, "s");
|
||||
screensaver_swap_image_timeout->setValue(static_cast<float>(
|
||||
Settings::getInstance()->getInt("ScreensaverSwapImageTimeout") / (1000)));
|
||||
s->addWithLabel("SWAP IMAGES AFTER (SECONDS)", screensaver_swap_image_timeout);
|
||||
s->addSaveFunc([screensaver_swap_image_timeout, s] {
|
||||
if (screensaver_swap_image_timeout->getValue() !=
|
||||
static_cast<float>(Settings::getInstance()->
|
||||
getInt("ScreensaverSwapImageTimeout") / (1000))) {
|
||||
Settings::getInstance()->setInt("ScreensaverSwapImageTimeout",
|
||||
static_cast<int>(std::round(screensaver_swap_image_timeout->getValue()) *
|
||||
(1000)));
|
||||
static_cast<float>(Settings::getInstance()->getInt("ScreensaverSwapImageTimeout") /
|
||||
(1000))) {
|
||||
Settings::getInstance()->setInt(
|
||||
"ScreensaverSwapImageTimeout",
|
||||
static_cast<int>(std::round(screensaver_swap_image_timeout->getValue()) * (1000)));
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Stretch images to screen resolution.
|
||||
auto screensaver_stretch_images = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_stretch_images->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverStretchImages"));
|
||||
screensaver_stretch_images->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverStretchImages"));
|
||||
s->addWithLabel("STRETCH IMAGES TO SCREEN RESOLUTION", screensaver_stretch_images);
|
||||
s->addSaveFunc([screensaver_stretch_images, s] {
|
||||
if (screensaver_stretch_images->getState() !=
|
||||
|
@ -130,8 +133,8 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
|
||||
// Show game info overlay for slideshow screensaver.
|
||||
auto screensaver_slideshow_game_info = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_slideshow_game_info->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"));
|
||||
screensaver_slideshow_game_info->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"));
|
||||
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_slideshow_game_info);
|
||||
s->addSaveFunc([screensaver_slideshow_game_info, s] {
|
||||
if (screensaver_slideshow_game_info->getState() !=
|
||||
|
@ -142,11 +145,11 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Render scanlines using a shader.
|
||||
auto screensaver_slideshow_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_slideshow_scanlines->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"));
|
||||
screensaver_slideshow_scanlines->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"));
|
||||
s->addWithLabel("RENDER SCANLINES", screensaver_slideshow_scanlines);
|
||||
s->addSaveFunc([screensaver_slideshow_scanlines, s] {
|
||||
if (screensaver_slideshow_scanlines->getState() !=
|
||||
|
@ -156,12 +159,12 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Whether to use custom images.
|
||||
auto screensaver_slideshow_custom_images = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_slideshow_custom_images->setState(Settings::getInstance()->
|
||||
getBool("ScreensaverSlideshowCustomImages"));
|
||||
screensaver_slideshow_custom_images->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages"));
|
||||
s->addWithLabel("USE CUSTOM IMAGES", screensaver_slideshow_custom_images);
|
||||
s->addSaveFunc([screensaver_slideshow_custom_images, s] {
|
||||
if (screensaver_slideshow_custom_images->getState() !=
|
||||
|
@ -174,8 +177,8 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
|
||||
// Whether to recurse the custom image directory.
|
||||
auto screensaver_slideshow_recurse = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_slideshow_recurse->setState(Settings::getInstance()->
|
||||
getBool("ScreensaverSlideshowRecurse"));
|
||||
screensaver_slideshow_recurse->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverSlideshowRecurse"));
|
||||
s->addWithLabel("CUSTOM IMAGE DIRECTORY RECURSIVE SEARCH", screensaver_slideshow_recurse);
|
||||
s->addSaveFunc([screensaver_slideshow_recurse, s] {
|
||||
if (screensaver_slideshow_recurse->getState() !=
|
||||
|
@ -187,9 +190,10 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
|||
});
|
||||
|
||||
// Custom image directory.
|
||||
auto screensaver_slideshow_image_dir = std::make_shared<TextComponent>(mWindow, "",
|
||||
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT);
|
||||
s->addEditableTextComponent("CUSTOM IMAGE DIRECTORY", screensaver_slideshow_image_dir,
|
||||
auto screensaver_slideshow_image_dir = std::make_shared<TextComponent>(
|
||||
mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT);
|
||||
s->addEditableTextComponent(
|
||||
"CUSTOM IMAGE DIRECTORY", screensaver_slideshow_image_dir,
|
||||
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"),
|
||||
Settings::getInstance()->getDefaultString("ScreensaverSlideshowImageDir"));
|
||||
s->addSaveFunc([screensaver_slideshow_image_dir, s] {
|
||||
|
@ -210,25 +214,25 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
|||
|
||||
// Timer for swapping videos (in seconds).
|
||||
auto screensaver_swap_video_timeout =
|
||||
std::make_shared<SliderComponent>(mWindow, 0.f, 120.f, 2.f, "s");
|
||||
screensaver_swap_video_timeout->setValue(static_cast<float>(Settings::getInstance()->
|
||||
getInt("ScreensaverSwapVideoTimeout") / (1000)));
|
||||
std::make_shared<SliderComponent>(mWindow, 0.0f, 120.0f, 2.0f, "s");
|
||||
screensaver_swap_video_timeout->setValue(static_cast<float>(
|
||||
Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") / (1000)));
|
||||
s->addWithLabel("SWAP VIDEOS AFTER (SECONDS)", screensaver_swap_video_timeout);
|
||||
s->addSaveFunc([screensaver_swap_video_timeout, s] {
|
||||
if (screensaver_swap_video_timeout->getValue() !=
|
||||
static_cast<float>(Settings::getInstance()->
|
||||
getInt("ScreensaverSwapVideoTimeout") / (1000))) {
|
||||
Settings::getInstance()->setInt("ScreensaverSwapVideoTimeout",
|
||||
static_cast<int>(std::round(screensaver_swap_video_timeout->getValue()) *
|
||||
(1000)));
|
||||
static_cast<float>(Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") /
|
||||
(1000))) {
|
||||
Settings::getInstance()->setInt(
|
||||
"ScreensaverSwapVideoTimeout",
|
||||
static_cast<int>(std::round(screensaver_swap_video_timeout->getValue()) * (1000)));
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
|
||||
// Stretch videos to screen resolution.
|
||||
auto screensaver_stretch_videos = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_stretch_videos->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverStretchVideos"));
|
||||
screensaver_stretch_videos->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverStretchVideos"));
|
||||
s->addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", screensaver_stretch_videos);
|
||||
s->addSaveFunc([screensaver_stretch_videos, s] {
|
||||
if (screensaver_stretch_videos->getState() !=
|
||||
|
@ -241,8 +245,8 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
|||
|
||||
// Show game info overlay for video screensaver.
|
||||
auto screensaver_video_game_info = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_video_game_info->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverVideoGameInfo"));
|
||||
screensaver_video_game_info->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverVideoGameInfo"));
|
||||
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_video_game_info);
|
||||
s->addSaveFunc([screensaver_video_game_info, s] {
|
||||
if (screensaver_video_game_info->getState() !=
|
||||
|
@ -253,7 +257,7 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
|||
}
|
||||
});
|
||||
|
||||
#if defined(_RPI_)
|
||||
#if defined(_RPI_)
|
||||
// Use OMX player for screensaver.
|
||||
auto screensaver_omx_player = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_omx_player->setState(Settings::getInstance()->getBool("ScreensaverOmxPlayer"));
|
||||
|
@ -261,18 +265,18 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
|||
s->addSaveFunc([screensaver_omx_player, s] {
|
||||
if (screensaver_omx_player->getState() !=
|
||||
Settings::getInstance()->getBool("ScreensaverOmxPlayer")) {
|
||||
Settings::getInstance()->
|
||||
setBool("ScreensaverOmxPlayer", screensaver_omx_player->getState());
|
||||
Settings::getInstance()->setBool("ScreensaverOmxPlayer",
|
||||
screensaver_omx_player->getState());
|
||||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_OPENGL_21)
|
||||
#if defined(USE_OPENGL_21)
|
||||
// Render scanlines using a shader.
|
||||
auto screensaver_video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||
screensaver_video_scanlines->
|
||||
setState(Settings::getInstance()->getBool("ScreensaverVideoScanlines"));
|
||||
screensaver_video_scanlines->setState(
|
||||
Settings::getInstance()->getBool("ScreensaverVideoScanlines"));
|
||||
s->addWithLabel("RENDER SCANLINES", screensaver_video_scanlines);
|
||||
s->addSaveFunc([screensaver_video_scanlines, s] {
|
||||
if (screensaver_video_scanlines->getState() !=
|
||||
|
@ -295,7 +299,7 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
|||
s->setNeedsSaving();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mWindow->pushGui(s);
|
||||
}
|
||||
|
|
|
@ -10,33 +10,31 @@
|
|||
|
||||
#include "guis/GuiSettings.h"
|
||||
|
||||
#include "components/HelpComponent.h"
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "components/HelpComponent.h"
|
||||
#include "guis/GuiTextEditPopup.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
GuiSettings::GuiSettings(
|
||||
Window* window,
|
||||
std::string title)
|
||||
: GuiComponent(window),
|
||||
mMenu(window, title),
|
||||
mNeedsSaving(false),
|
||||
mNeedsReloadHelpPrompts(false),
|
||||
mNeedsCollectionsUpdate(false),
|
||||
mNeedsSorting(false),
|
||||
mNeedsSortingCollections(false),
|
||||
mNeedsResetFilters(false),
|
||||
mNeedsReloading(false),
|
||||
mNeedsGoToStart(false),
|
||||
mNeedsGoToSystem(false),
|
||||
mNeedsGoToGroupedCollections(false),
|
||||
mInvalidateCachedBackground(false),
|
||||
mGoToSystem(nullptr)
|
||||
GuiSettings::GuiSettings(Window* window, std::string title)
|
||||
: GuiComponent(window)
|
||||
, mMenu(window, title)
|
||||
, mNeedsSaving(false)
|
||||
, mNeedsReloadHelpPrompts(false)
|
||||
, mNeedsCollectionsUpdate(false)
|
||||
, mNeedsSorting(false)
|
||||
, mNeedsSortingCollections(false)
|
||||
, mNeedsResetFilters(false)
|
||||
, mNeedsReloading(false)
|
||||
, mNeedsGoToStart(false)
|
||||
, mNeedsGoToSystem(false)
|
||||
, mNeedsGoToGroupedCollections(false)
|
||||
, mInvalidateCachedBackground(false)
|
||||
, mGoToSystem(nullptr)
|
||||
{
|
||||
addChild(&mMenu);
|
||||
mMenu.addButton("BACK", "back", [this] { delete this; });
|
||||
|
@ -49,6 +47,7 @@ GuiSettings::GuiSettings(
|
|||
|
||||
GuiSettings::~GuiSettings()
|
||||
{
|
||||
// Save on exit.
|
||||
save();
|
||||
}
|
||||
|
||||
|
@ -72,11 +71,11 @@ void GuiSettings::save()
|
|||
}
|
||||
|
||||
if (mNeedsSorting) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
||||
SystemData::sSystemVector.cend(); it++) {
|
||||
if (!(!mNeedsSortingCollections && (*it)->isCollection())) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||
it++) {
|
||||
if (!(!mNeedsSortingCollections && (*it)->isCollection()))
|
||||
(*it)->sortSystem(true);
|
||||
}
|
||||
|
||||
// Jump to the first row of the gamelist.
|
||||
IGameListView* gameList = ViewController::get()->getGameListView((*it)).get();
|
||||
gameList->setCursor(gameList->getFirstEntry());
|
||||
|
@ -84,11 +83,10 @@ void GuiSettings::save()
|
|||
}
|
||||
|
||||
if (mNeedsResetFilters) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
if ((*it)->getThemeFolder() == "custom-collections") {
|
||||
for (FileData* customSystem :
|
||||
(*it)->getRootFolder()->getChildrenListToDisplay())
|
||||
for (FileData* customSystem : (*it)->getRootFolder()->getChildrenListToDisplay())
|
||||
customSystem->getSystem()->getIndex()->resetFilters();
|
||||
}
|
||||
(*it)->getIndex()->resetFilters();
|
||||
|
@ -152,8 +150,7 @@ void GuiSettings::save()
|
|||
}
|
||||
}
|
||||
|
||||
void GuiSettings::addEditableTextComponent(
|
||||
const std::string label,
|
||||
void GuiSettings::addEditableTextComponent(const std::string label,
|
||||
std::shared_ptr<GuiComponent> ed,
|
||||
std::string value,
|
||||
std::string defaultValue,
|
||||
|
@ -200,11 +197,11 @@ void GuiSettings::addEditableTextComponent(
|
|||
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||
// Never display the value if it's a password, instead set it to blank.
|
||||
if (isPassword)
|
||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label,
|
||||
"", updateVal, false));
|
||||
mWindow->pushGui(
|
||||
new GuiTextEditPopup(mWindow, getHelpStyle(), label, "", updateVal, false));
|
||||
else
|
||||
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);
|
||||
|
@ -219,15 +216,6 @@ bool GuiSettings::input(InputConfig* config, Input input)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Keep code for potential future use.
|
||||
// if (config->isMappedTo("start", input) && input.value != 0) {
|
||||
// // Close everything.
|
||||
// Window* window = mWindow;
|
||||
// while (window->peekGui() && window->peekGui() != ViewController::get())
|
||||
// delete window->peekGui();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#ifndef ES_APP_GUIS_GUI_SETTINGS_H
|
||||
#define ES_APP_GUIS_GUI_SETTINGS_H
|
||||
|
||||
#include "components/MenuComponent.h"
|
||||
#include "SystemData.h"
|
||||
#include "components/MenuComponent.h"
|
||||
|
||||
// This is just a really simple template for a GUI that calls some save functions when closed.
|
||||
class GuiSettings : public GuiComponent
|
||||
|
@ -22,29 +22,33 @@ public:
|
|||
virtual ~GuiSettings();
|
||||
|
||||
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); };
|
||||
void addEditableTextComponent(
|
||||
const std::string label,
|
||||
void addRow(const ComponentListRow& row) { mMenu.addRow(row); }
|
||||
void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp)
|
||||
{
|
||||
mMenu.addWithLabel(label, comp);
|
||||
}
|
||||
void addEditableTextComponent(const std::string label,
|
||||
std::shared_ptr<GuiComponent> ed,
|
||||
std::string value,
|
||||
std::string defaultValue = "",
|
||||
bool isPassword = false);
|
||||
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
||||
void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); }
|
||||
|
||||
void setNeedsSaving(bool state = true) { mNeedsSaving = state; };
|
||||
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; };
|
||||
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; };
|
||||
void setNeedsSorting() { mNeedsSorting = true; };
|
||||
void setNeedsSortingCollections() { mNeedsSortingCollections = true; };
|
||||
void setNeedsSaving(bool state = true) { mNeedsSaving = state; }
|
||||
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; }
|
||||
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; }
|
||||
void setNeedsSorting() { mNeedsSorting = true; }
|
||||
void setNeedsSortingCollections() { mNeedsSortingCollections = true; }
|
||||
void setNeedsResetFilters() { mNeedsResetFilters = true; }
|
||||
void setNeedsReloading() { mNeedsReloading = true; };
|
||||
void setNeedsGoToStart() { mNeedsGoToStart = true; };
|
||||
void setNeedsReloading() { mNeedsReloading = true; }
|
||||
void setNeedsGoToStart() { mNeedsGoToStart = true; }
|
||||
void setNeedsGoToSystem(SystemData* goToSystem)
|
||||
{ mNeedsGoToSystem = true; mGoToSystem = goToSystem; };
|
||||
void setNeedsGoToGroupedCollections() { mNeedsGoToGroupedCollections = true; };
|
||||
void setInvalidateCachedBackground() { mInvalidateCachedBackground = true; };
|
||||
{
|
||||
mNeedsGoToSystem = true;
|
||||
mGoToSystem = goToSystem;
|
||||
};
|
||||
void setNeedsGoToGroupedCollections() { mNeedsGoToGroupedCollections = true; }
|
||||
void setInvalidateCachedBackground() { mInvalidateCachedBackground = true; }
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
|
@ -53,6 +57,8 @@ public:
|
|||
private:
|
||||
MenuComponent mMenu;
|
||||
std::vector<std::function<void()>> mSaveFuncs;
|
||||
SystemData* mGoToSystem;
|
||||
|
||||
bool mNeedsSaving;
|
||||
bool mNeedsReloadHelpPrompts;
|
||||
bool mNeedsCollectionsUpdate;
|
||||
|
@ -64,8 +70,6 @@ private:
|
|||
bool mNeedsGoToSystem;
|
||||
bool mNeedsGoToGroupedCollections;
|
||||
bool mInvalidateCachedBackground;
|
||||
|
||||
SystemData* mGoToSystem;
|
||||
};
|
||||
|
||||
#endif // ES_APP_GUIS_GUI_SETTINGS_H
|
||||
|
|
|
@ -18,13 +18,6 @@
|
|||
// environment and starts listening to SDL events.
|
||||
//
|
||||
|
||||
#include "guis/GuiDetectDevice.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "guis/GuiComplexTextEditPopup.h"
|
||||
#include "guis/GuiLaunchScreen.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "EmulationStation.h"
|
||||
|
@ -37,6 +30,13 @@
|
|||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "SystemScreensaver.h"
|
||||
#include "guis/GuiComplexTextEditPopup.h"
|
||||
#include "guis/GuiDetectDevice.h"
|
||||
#include "guis/GuiLaunchScreen.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_main.h>
|
||||
|
@ -56,14 +56,14 @@ bool forceInputConfig = false;
|
|||
bool settingsNeedSaving = false;
|
||||
|
||||
enum loadSystemsReturnCode {
|
||||
LOADING_OK,
|
||||
LOADING_OK, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
INVALID_FILE,
|
||||
NO_ROMS
|
||||
};
|
||||
|
||||
#if defined(_WIN64)
|
||||
enum win64ConsoleType {
|
||||
NO_CONSOLE,
|
||||
NO_CONSOLE, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
PARENT_CONSOLE,
|
||||
ALLOCATED_CONSOLE
|
||||
};
|
||||
|
@ -131,11 +131,11 @@ bool parseArgs(int argc, char* argv[])
|
|||
{
|
||||
Utils::FileSystem::setExePath(argv[0]);
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Print any command line output to the console.
|
||||
if (argc > 1)
|
||||
win64ConsoleType consoleType = outputToConsole(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string portableFilePath = Utils::FileSystem::getExePath() + "/portable.txt";
|
||||
|
||||
|
@ -145,11 +145,11 @@ bool parseArgs(int argc, char* argv[])
|
|||
std::cout << "Found portable.txt in the ES-DE executable directory\n";
|
||||
std::ifstream portableFile;
|
||||
std::string homePath;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
portableFile.open(Utils::String::stringToWideString(portableFilePath).c_str());
|
||||
#else
|
||||
#else
|
||||
portableFile.open(portableFilePath.c_str());
|
||||
#endif
|
||||
#endif
|
||||
if (!portableFile.fail()) {
|
||||
std::string relativePath;
|
||||
getline(portableFile, relativePath);
|
||||
|
@ -159,9 +159,9 @@ bool parseArgs(int argc, char* argv[])
|
|||
else
|
||||
homePath = Utils::FileSystem::getExePath() + "/" + relativePath;
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
homePath = Utils::String::replace(homePath, "/", "\\");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!Utils::FileSystem::exists(homePath)) {
|
||||
std::cerr << "Error: Defined home path \"" << homePath << "\" does not exist\n";
|
||||
|
@ -185,18 +185,18 @@ bool parseArgs(int argc, char* argv[])
|
|||
std::cerr << "Error: No home path supplied with \'--home'\n";
|
||||
return false;
|
||||
}
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
if (!Utils::FileSystem::exists(argv[i + 1]) &&
|
||||
(!Utils::FileSystem::driveExists(argv[i + 1]))) {
|
||||
#else
|
||||
#else
|
||||
if (!Utils::FileSystem::exists(argv[i + 1])) {
|
||||
#endif
|
||||
#endif
|
||||
std::cerr << "Error: Home path \'" << argv[i + 1] << "\' does not exist\n";
|
||||
return false;
|
||||
}
|
||||
if (Utils::FileSystem::isRegularFile(argv[i + 1])) {
|
||||
std::cerr << "Error: Home path \'" << argv[i + 1] <<
|
||||
"\' is a file and not a directory\n";
|
||||
std::cerr << "Error: Home path \'" << argv[i + 1]
|
||||
<< "\' is a file and not a directory\n";
|
||||
return false;
|
||||
}
|
||||
Utils::FileSystem::setHomePath(argv[i + 1]);
|
||||
|
@ -236,8 +236,8 @@ bool parseArgs(int argc, char* argv[])
|
|||
int height = atoi(argv[i + 2]);
|
||||
if (width < 640 || height < 480 || width > 7680 || height > 4320 ||
|
||||
height < width / 4 || width < height / 2) {
|
||||
std::cerr << "Error: Unsupported resolution "
|
||||
<< width << "x" << height << " supplied.\n";
|
||||
std::cerr << "Error: Unsupported resolution " << width << "x" << height
|
||||
<< " supplied.\n";
|
||||
return false;
|
||||
}
|
||||
Settings::getInstance()->setInt("WindowWidth", width);
|
||||
|
@ -277,7 +277,8 @@ bool parseArgs(int argc, char* argv[])
|
|||
}
|
||||
// On Unix, enable settings for the fullscreen mode.
|
||||
// On macOS and Windows only windowed mode is supported.
|
||||
#if defined(__unix__)
|
||||
|
||||
#if defined(__unix__)
|
||||
else if (strcmp(argv[i], "--windowed") == 0) {
|
||||
Settings::getInstance()->setBool("Windowed", true);
|
||||
}
|
||||
|
@ -289,7 +290,7 @@ bool parseArgs(int argc, char* argv[])
|
|||
Settings::getInstance()->setString("FullscreenMode", "borderless");
|
||||
settingsNeedSaving = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
else if (strcmp(argv[i], "--vsync") == 0) {
|
||||
if (i >= argc - 1) {
|
||||
std::cerr << "Error: No VSync value supplied.\n";
|
||||
|
@ -350,12 +351,12 @@ bool parseArgs(int argc, char* argv[])
|
|||
Log::setReportingLevel(LogDebug);
|
||||
}
|
||||
else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
||||
std::cout <<
|
||||
"EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << "\n";
|
||||
std::cout << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << "\n";
|
||||
return false;
|
||||
}
|
||||
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
std::cout <<
|
||||
// clang-format off
|
||||
"Usage: emulationstation [options]\n"
|
||||
"EmulationStation Desktop Edition, Emulator Front-end\n\n"
|
||||
"Options:\n"
|
||||
|
@ -381,6 +382,7 @@ bool parseArgs(int argc, char* argv[])
|
|||
" --debug Print debug information\n"
|
||||
" --version, -v Display version information\n"
|
||||
" --help, -h Summon a sentient, angry tuba\n";
|
||||
// clang-format on
|
||||
return false; // Exit after printing help.
|
||||
}
|
||||
else {
|
||||
|
@ -400,13 +402,13 @@ bool checkApplicationHomeDirectory()
|
|||
std::string home = Utils::FileSystem::getHomePath();
|
||||
std::string applicationHome = home + "/.emulationstation";
|
||||
if (!Utils::FileSystem::exists(applicationHome)) {
|
||||
#if defined(_WIN64)
|
||||
std::cout << "First startup, creating application home directory \"" <<
|
||||
Utils::String::replace(applicationHome, "/", "\\") << "\"\n";
|
||||
#else
|
||||
std::cout << "First startup, creating application home directory \"" <<
|
||||
applicationHome << "\"\n";
|
||||
#endif
|
||||
#if defined(_WIN64)
|
||||
std::cout << "First startup, creating application home directory \""
|
||||
<< Utils::String::replace(applicationHome, "/", "\\") << "\"\n";
|
||||
#else
|
||||
std::cout << "First startup, creating application home directory \"" << applicationHome
|
||||
<< "\"\n";
|
||||
#endif
|
||||
Utils::FileSystem::createDirectory(applicationHome);
|
||||
if (!Utils::FileSystem::exists(applicationHome)) {
|
||||
std::cerr << "Fatal error: Couldn't create directory, permission problems?\n";
|
||||
|
@ -431,9 +433,9 @@ loadSystemsReturnCode loadSystemConfigFile()
|
|||
return LOADING_OK;
|
||||
}
|
||||
|
||||
// Called on exit, assuming we get far enough to have the log initialized.
|
||||
void onExit()
|
||||
{
|
||||
// Called on exit, assuming we get far enough to have the log initialized.
|
||||
Log::close();
|
||||
}
|
||||
|
||||
|
@ -443,7 +445,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
std::locale::global(std::locale("C"));
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
// This is a workaround to disable the incredibly annoying save state functionality in
|
||||
// macOS which forces a restore of the previous window state. The problem is that this
|
||||
// removes the splash screen on startup and it may have other adverse effects as well.
|
||||
|
@ -465,22 +467,22 @@ int main(int argc, char* argv[])
|
|||
// the functionality.
|
||||
std::string chmodCommand = "chmod 500 \"" + saveStateDir + "\"";
|
||||
system(chmodCommand.c_str());
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!parseArgs(argc, argv)) {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
FreeConsole();
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Send debug output to the console..
|
||||
if (Settings::getInstance()->getBool("Debug"))
|
||||
outputToConsole(true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Hide taskbar if the setting for this is enabled.
|
||||
bool taskbarStateChanged = false;
|
||||
unsigned int taskbarState;
|
||||
|
@ -490,12 +492,12 @@ int main(int argc, char* argv[])
|
|||
taskbarState = getTaskbarState();
|
||||
hideTaskbar();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(FREEIMAGE_LIB)
|
||||
// Call this ONLY when linking with FreeImage as a static library.
|
||||
#if defined(FREEIMAGE_LIB)
|
||||
FreeImage_Initialise();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If ~/.emulationstation doesn't exist and cannot be created, bail.
|
||||
if (!checkApplicationHomeDirectory())
|
||||
|
@ -504,8 +506,8 @@ int main(int argc, char* argv[])
|
|||
// Start the logger.
|
||||
Log::init();
|
||||
Log::open();
|
||||
LOG(LogInfo) << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING <<
|
||||
", built " << PROGRAM_BUILT_STRING;
|
||||
LOG(LogInfo) << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << ", built "
|
||||
<< PROGRAM_BUILT_STRING;
|
||||
|
||||
// Always close the log on exit.
|
||||
atexit(&onExit);
|
||||
|
@ -525,15 +527,15 @@ int main(int argc, char* argv[])
|
|||
// Check if the application version has changed, which would normally mean that the
|
||||
// user has upgraded to a newer release.
|
||||
std::string applicationVersion;
|
||||
if ((applicationVersion = Settings::getInstance()->
|
||||
getString("ApplicationVersion")) != PROGRAM_VERSION_STRING) {
|
||||
if ((applicationVersion = Settings::getInstance()->getString("ApplicationVersion")) !=
|
||||
PROGRAM_VERSION_STRING) {
|
||||
if (applicationVersion != "") {
|
||||
LOG(LogInfo) << "Application version changed from previous startup, from \"" <<
|
||||
applicationVersion << "\" to \"" << PROGRAM_VERSION_STRING << "\"";
|
||||
LOG(LogInfo) << "Application version changed from previous startup, from \""
|
||||
<< applicationVersion << "\" to \"" << PROGRAM_VERSION_STRING << "\"";
|
||||
}
|
||||
else {
|
||||
LOG(LogInfo) << "Application version setting is blank, changing it to \"" <<
|
||||
PROGRAM_VERSION_STRING << "\"";
|
||||
LOG(LogInfo) << "Application version setting is blank, changing it to \""
|
||||
<< PROGRAM_VERSION_STRING << "\"";
|
||||
}
|
||||
Settings::getInstance()->setString("ApplicationVersion", PROGRAM_VERSION_STRING);
|
||||
Settings::getInstance()->saveFile();
|
||||
|
@ -582,11 +584,11 @@ int main(int argc, char* argv[])
|
|||
if (event.type == SDL_QUIT)
|
||||
return 1;
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
// This hides the mouse cursor during startup, i.e. before we have begun to capture SDL events.
|
||||
// On macOS this causes the mouse cursor to jump back to the Dock so don't do it on this OS.
|
||||
#if !defined(__APPLE__)
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (splashScreen) {
|
||||
std::string progressText = "Loading...";
|
||||
|
@ -625,8 +627,8 @@ int main(int argc, char* argv[])
|
|||
// Open the input configuration GUI if the flag to force this was passed from the command line.
|
||||
if (!loadSystemsStatus) {
|
||||
if (forceInputConfig) {
|
||||
window.pushGui(new GuiDetectDevice(&window, false, true, [] {
|
||||
ViewController::get()->goToStart(); }));
|
||||
window.pushGui(new GuiDetectDevice(&window, false, true,
|
||||
[] { ViewController::get()->goToStart(); }));
|
||||
}
|
||||
else {
|
||||
ViewController::get()->goToStart();
|
||||
|
@ -639,16 +641,19 @@ int main(int argc, char* argv[])
|
|||
int lastTime = SDL_GetTicks();
|
||||
const auto applicationEndTime = std::chrono::system_clock::now();
|
||||
|
||||
LOG(LogInfo) << "Application startup time: " <<
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
(applicationEndTime - applicationStartTime).count() << " ms";
|
||||
LOG(LogInfo) << "Application startup time: "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(applicationEndTime -
|
||||
applicationStartTime)
|
||||
.count()
|
||||
<< " ms";
|
||||
|
||||
bool running = true;
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
// Now that we've finished loading, disable the relative mouse mode or otherwise mouse
|
||||
// input wouldn't work in any games that are launched.
|
||||
#if !defined(__APPLE__)
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (running) {
|
||||
if (SDL_PollEvent(&event)) {
|
||||
|
@ -657,8 +662,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (event.type == SDL_QUIT)
|
||||
running = false;
|
||||
}
|
||||
while (SDL_PollEvent(&event));
|
||||
|
||||
} while (SDL_PollEvent(&event));
|
||||
}
|
||||
|
||||
if (window.isSleeping()) {
|
||||
|
@ -694,24 +699,24 @@ int main(int argc, char* argv[])
|
|||
NavigationSounds::getInstance()->deinit();
|
||||
Settings::deinit();
|
||||
|
||||
#if defined(FREEIMAGE_LIB)
|
||||
// Call this ONLY when linking with FreeImage as a static library.
|
||||
#if defined(FREEIMAGE_LIB)
|
||||
FreeImage_DeInitialise();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// If the taskbar state was changed (taskbar was hidden), then revert it.
|
||||
if (taskbarStateChanged)
|
||||
revertTaskbarState(taskbarState);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
processQuitMode();
|
||||
|
||||
LOG(LogInfo) << "EmulationStation cleanly shutting down";
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
FreeConsole();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,20 +10,20 @@
|
|||
#include "scrapers/GamesDBJSONScraper.h"
|
||||
#include "scrapers/GamesDBJSONScraperResources.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "MameNames.h"
|
||||
#include "PlatformId.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <pugixml.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
|
||||
using namespace PlatformIds;
|
||||
using namespace rapidjson;
|
||||
|
@ -103,10 +103,10 @@ const std::map<PlatformId, std::string> gamesdb_new_platformid_map {
|
|||
{ SONY_PLAYSTATION_PORTABLE, "13" },
|
||||
{ SUPER_NINTENDO, "6" },
|
||||
{ SHARP_X1, "4977" },
|
||||
{ SHARP_X68000, "4931"},
|
||||
{ SHARP_X68000, "4931" },
|
||||
{ NEC_SUPERGRAFX, "34" },
|
||||
{ NEC_PC_8800, "4933"},
|
||||
{ NEC_PC_9800, "4934"},
|
||||
{ NEC_PC_8800, "4933" },
|
||||
{ NEC_PC_9800, "4934" },
|
||||
{ NEC_PC_ENGINE, "34" },
|
||||
{ NEC_PC_ENGINE_CD, "4955" },
|
||||
{ BANDAI_WONDERSWAN, "4925" },
|
||||
|
@ -118,7 +118,8 @@ const std::map<PlatformId, std::string> gamesdb_new_platformid_map {
|
|||
{ TANDY_TRS80, "4941" },
|
||||
};
|
||||
|
||||
void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params,
|
||||
void thegamesdb_generate_json_scraper_requests(
|
||||
const ScraperSearchParams& params,
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||
std::vector<ScraperSearchResult>& results)
|
||||
{
|
||||
|
@ -168,7 +169,7 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
|||
if (!platforms.empty()) {
|
||||
bool first = true;
|
||||
platformQueryParam += "&filter%5Bplatform%5D=";
|
||||
for (auto platformIt = platforms.cbegin();
|
||||
for (auto platformIt = platforms.cbegin(); // Line break.
|
||||
platformIt != platforms.cend(); platformIt++) {
|
||||
auto mapIt = gamesdb_new_platformid_map.find(*platformIt);
|
||||
if (mapIt != gamesdb_new_platformid_map.cend()) {
|
||||
|
@ -178,8 +179,9 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
|||
first = false;
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << "TheGamesDB scraper: No support for platform \"" <<
|
||||
getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||
LOG(LogWarning)
|
||||
<< "TheGamesDB scraper: No support for platform \""
|
||||
<< getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||
}
|
||||
}
|
||||
path += platformQueryParam;
|
||||
|
@ -188,8 +190,8 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
|||
LOG(LogWarning) << "TheGamesDB scraper: No platform defined, search will be inaccurate";
|
||||
}
|
||||
|
||||
requests.push(std::unique_ptr<ScraperRequest>
|
||||
(new TheGamesDBJSONRequest(requests, results, path)));
|
||||
requests.push(
|
||||
std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,41 +206,40 @@ void thegamesdb_generate_json_scraper_requests(
|
|||
|
||||
path += "/Games/Images/GamesImages?" + apiKey + "&games_id=" + gameIDs;
|
||||
|
||||
requests.push(std::unique_ptr<ScraperRequest>
|
||||
(new TheGamesDBJSONRequest(requests, results, path)));
|
||||
requests.push(
|
||||
std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path)));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string getStringOrThrow(const Value& v, const std::string& key)
|
||||
{
|
||||
std::string getStringOrThrow(const Value& v, const std::string& key)
|
||||
{
|
||||
if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsString()) {
|
||||
throw std::runtime_error(
|
||||
"rapidjson internal assertion failure: missing or non string key:" + key);
|
||||
}
|
||||
return v[key.c_str()].GetString();
|
||||
}
|
||||
}
|
||||
|
||||
int getIntOrThrow(const Value& v, const std::string& key)
|
||||
{
|
||||
int getIntOrThrow(const Value& v, const std::string& key)
|
||||
{
|
||||
if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsInt()) {
|
||||
throw std::runtime_error(
|
||||
"rapidjson internal assertion failure: missing or non int key:" + key);
|
||||
}
|
||||
return v[key.c_str()].GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
int getIntOrThrow(const Value& v)
|
||||
{
|
||||
int getIntOrThrow(const Value& v)
|
||||
{
|
||||
if (!v.IsInt()) {
|
||||
throw std::runtime_error("rapidjson internal assertion failure: not an int");
|
||||
}
|
||||
return v.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
std::string getDeveloperString(const Value& v)
|
||||
{
|
||||
std::string getDeveloperString(const Value& v)
|
||||
{
|
||||
if (!v.IsArray())
|
||||
return "";
|
||||
|
||||
|
@ -257,10 +258,10 @@ std::string getDeveloperString(const Value& v)
|
|||
first = false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getPublisherString(const Value& v)
|
||||
{
|
||||
std::string getPublisherString(const Value& v)
|
||||
{
|
||||
if (!v.IsArray())
|
||||
return "";
|
||||
|
||||
|
@ -279,10 +280,10 @@ std::string getPublisherString(const Value& v)
|
|||
first = false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getGenreString(const Value& v)
|
||||
{
|
||||
std::string getGenreString(const Value& v)
|
||||
{
|
||||
if (!v.IsArray())
|
||||
return "";
|
||||
|
||||
|
@ -301,10 +302,10 @@ std::string getGenreString(const Value& v)
|
|||
first = false;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
void processGame(const Value& game, std::vector<ScraperSearchResult>& results)
|
||||
{
|
||||
void processGame(const Value& game, std::vector<ScraperSearchResult>& results)
|
||||
{
|
||||
ScraperSearchResult result;
|
||||
|
||||
if (game.HasMember("id") && game["id"].IsInt())
|
||||
|
@ -319,42 +320,43 @@ void processGame(const Value& game, std::vector<ScraperSearchResult>& results)
|
|||
if (game.HasMember("release_date") && game["release_date"].IsString()) {
|
||||
result.mdl.set("releasedate", Utils::Time::DateTime(Utils::Time::stringToTime(
|
||||
game["release_date"].GetString(), "%Y-%m-%d")));
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (unparsed): " <<
|
||||
game["release_date"].GetString();
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (parsed): " <<
|
||||
result.mdl.get("releasedate");
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (unparsed): "
|
||||
<< game["release_date"].GetString();
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Release Date (parsed): "
|
||||
<< result.mdl.get("releasedate");
|
||||
}
|
||||
|
||||
if (game.HasMember("developers") && game["developers"].IsArray()) {
|
||||
result.mdl.set("developer", getDeveloperString(game["developers"]));
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Developer: " <<
|
||||
result.mdl.get("developer");
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Developer: "
|
||||
<< result.mdl.get("developer");
|
||||
}
|
||||
|
||||
if (game.HasMember("publishers") && game["publishers"].IsArray()) {
|
||||
result.mdl.set("publisher", getPublisherString(game["publishers"]));
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Publisher: " <<
|
||||
result.mdl.get("publisher");
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Publisher: "
|
||||
<< result.mdl.get("publisher");
|
||||
}
|
||||
|
||||
if (game.HasMember("genres") && game["genres"].IsArray()) {
|
||||
result.mdl.set("genre", getGenreString(game["genres"]));
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Genre: " <<
|
||||
result.mdl.get("genre");
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Genre: "
|
||||
<< result.mdl.get("genre");
|
||||
}
|
||||
|
||||
if (game.HasMember("players") && game["players"].IsInt()) {
|
||||
result.mdl.set("players", std::to_string(game["players"].GetInt()));
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Players: " <<
|
||||
result.mdl.get("players");
|
||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Players: "
|
||||
<< result.mdl.get("players");
|
||||
}
|
||||
|
||||
result.mediaURLFetch = NOT_STARTED;
|
||||
results.push_back(result);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void processMediaURLs(const Value& images, const std::string& base_url,
|
||||
void processMediaURLs(const Value& images,
|
||||
const std::string& base_url,
|
||||
std::vector<ScraperSearchResult>& results)
|
||||
{
|
||||
ScraperSearchResult result;
|
||||
|
@ -367,9 +369,8 @@ void processMediaURLs(const Value& images, const std::string& base_url,
|
|||
result.marqueeUrl = "";
|
||||
result.screenshotUrl = "";
|
||||
|
||||
// Quite excessive testing for valid values, but you never know
|
||||
// what the server has returned and we don't want to crash the
|
||||
// program due to malformed data.
|
||||
// Quite excessive testing for valid values, but you never know what the server has
|
||||
// returned and we don't want to crash the program due to malformed data.
|
||||
if (gameMedia.IsArray()) {
|
||||
for (SizeType i = 0; i < gameMedia.Size(); i++) {
|
||||
std::string mediatype;
|
||||
|
@ -404,8 +405,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
|||
doc.Parse(req->getContent().c_str());
|
||||
|
||||
if (doc.HasParseError()) {
|
||||
std::string err =
|
||||
std::string("TheGamesDBJSONRequest - Error parsing JSON \n\t") +
|
||||
std::string err = std::string("TheGamesDBJSONRequest - Error parsing JSON \n\t") +
|
||||
GetParseError_En(doc.GetParseError());
|
||||
setError(err);
|
||||
LOG(LogError) << err;
|
||||
|
@ -440,12 +440,11 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
|||
if (doc.HasMember("remaining_monthly_allowance") && doc.HasMember("extra_allowance")) {
|
||||
for (auto i = 0; i < results.size(); i++) {
|
||||
results[i].scraperRequestAllowance =
|
||||
doc["remaining_monthly_allowance"].GetInt() +
|
||||
doc["extra_allowance"].GetInt();
|
||||
doc["remaining_monthly_allowance"].GetInt() + doc["extra_allowance"].GetInt();
|
||||
}
|
||||
LOG(LogDebug) << "TheGamesDBJSONRequest::process(): "
|
||||
"Remaining monthly scraping allowance: " <<
|
||||
results.back().scraperRequestAllowance;
|
||||
"Remaining monthly scraping allowance: "
|
||||
<< results.back().scraperRequestAllowance;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,37 +12,40 @@
|
|||
|
||||
#include "scrapers/Scraper.h"
|
||||
|
||||
namespace pugi {
|
||||
namespace pugi
|
||||
{
|
||||
class xml_document;
|
||||
}
|
||||
|
||||
void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params,
|
||||
void thegamesdb_generate_json_scraper_requests(
|
||||
const ScraperSearchParams& params,
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||
std::vector<ScraperSearchResult>& results);
|
||||
|
||||
void thegamesdb_generate_json_scraper_requests(const std::string& gameIDs,
|
||||
void thegamesdb_generate_json_scraper_requests(
|
||||
const std::string& gameIDs,
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||
std::vector<ScraperSearchResult>& results);
|
||||
|
||||
class TheGamesDBJSONRequest : public ScraperHttpRequest
|
||||
{
|
||||
public:
|
||||
public:
|
||||
// Constructor for a GetGameList request.
|
||||
TheGamesDBJSONRequest(
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
||||
TheGamesDBJSONRequest(std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
||||
std::vector<ScraperSearchResult>& resultsWrite,
|
||||
const std::string& url)
|
||||
: ScraperHttpRequest(resultsWrite, url),
|
||||
mRequestQueue(&requestsWrite)
|
||||
: ScraperHttpRequest(resultsWrite, url)
|
||||
, mRequestQueue(&requestsWrite)
|
||||
{
|
||||
}
|
||||
// Constructior for a GetGame request
|
||||
TheGamesDBJSONRequest(std::vector<ScraperSearchResult>& resultsWrite, const std::string& url)
|
||||
: ScraperHttpRequest(resultsWrite, url), mRequestQueue(nullptr)
|
||||
: ScraperHttpRequest(resultsWrite, url)
|
||||
, mRequestQueue(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void process(const std::unique_ptr<HttpReq>& req,
|
||||
std::vector<ScraperSearchResult>& results) override;
|
||||
bool isGameRequest() { return !mRequestQueue; }
|
||||
|
|
|
@ -14,52 +14,53 @@
|
|||
|
||||
#include "scrapers/GamesDBJSONScraperResources.h"
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "Log.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <thread>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace {
|
||||
constexpr char GamesDBAPIKey[] =
|
||||
namespace
|
||||
{
|
||||
constexpr char GamesDBAPIKey[] =
|
||||
"445fcbc3f32bb2474bc27016b99eb963d318ee3a608212c543b9a79de1041600";
|
||||
|
||||
constexpr int MAX_WAIT_MS = 90000;
|
||||
constexpr int POLL_TIME_MS = 500;
|
||||
constexpr int MAX_WAIT_ITER = MAX_WAIT_MS / POLL_TIME_MS;
|
||||
constexpr int MAX_WAIT_MS = 90000;
|
||||
constexpr int POLL_TIME_MS = 500;
|
||||
constexpr int MAX_WAIT_ITER = MAX_WAIT_MS / POLL_TIME_MS;
|
||||
|
||||
constexpr char SCRAPER_RESOURCES_DIR[] = "scrapers";
|
||||
constexpr char DEVELOPERS_JSON_FILE[] = "gamesdb_developers.json";
|
||||
constexpr char PUBLISHERS_JSON_FILE[] = "gamesdb_publishers.json";
|
||||
constexpr char GENRES_JSON_FILE[] = "gamesdb_genres.json";
|
||||
constexpr char DEVELOPERS_ENDPOINT[] = "/Developers";
|
||||
constexpr char PUBLISHERS_ENDPOINT[] = "/Publishers";
|
||||
constexpr char GENRES_ENDPOINT[] = "/Genres";
|
||||
constexpr char SCRAPER_RESOURCES_DIR[] = "scrapers";
|
||||
constexpr char DEVELOPERS_JSON_FILE[] = "gamesdb_developers.json";
|
||||
constexpr char PUBLISHERS_JSON_FILE[] = "gamesdb_publishers.json";
|
||||
constexpr char GENRES_JSON_FILE[] = "gamesdb_genres.json";
|
||||
constexpr char DEVELOPERS_ENDPOINT[] = "/Developers";
|
||||
constexpr char PUBLISHERS_ENDPOINT[] = "/Publishers";
|
||||
constexpr char GENRES_ENDPOINT[] = "/Genres";
|
||||
|
||||
std::string genFilePath(const std::string& file_name)
|
||||
{
|
||||
std::string genFilePath(const std::string& file_name)
|
||||
{
|
||||
return Utils::FileSystem::getGenericPath(getScrapersResouceDir() + "/" + file_name);
|
||||
}
|
||||
}
|
||||
|
||||
void ensureScrapersResourcesDir()
|
||||
{
|
||||
void ensureScrapersResourcesDir()
|
||||
{
|
||||
std::string path = getScrapersResouceDir();
|
||||
if (!Utils::FileSystem::exists(path))
|
||||
Utils::FileSystem::createDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string getScrapersResouceDir()
|
||||
{
|
||||
return Utils::FileSystem::getGenericPath(
|
||||
Utils::FileSystem::getHomePath() + "/.emulationstation/" + SCRAPER_RESOURCES_DIR);
|
||||
return Utils::FileSystem::getGenericPath(Utils::FileSystem::getHomePath() +
|
||||
"/.emulationstation/" + SCRAPER_RESOURCES_DIR);
|
||||
}
|
||||
|
||||
std::string TheGamesDBJSONRequestResources::getApiKey() const { return GamesDBAPIKey; }
|
||||
|
@ -69,16 +70,16 @@ void TheGamesDBJSONRequestResources::prepare()
|
|||
if (checkLoaded())
|
||||
return;
|
||||
|
||||
if (loadResource(gamesdb_new_developers_map, "developers",
|
||||
genFilePath(DEVELOPERS_JSON_FILE)) && !gamesdb_developers_resource_request)
|
||||
if (loadResource(gamesdb_new_developers_map, "developers", genFilePath(DEVELOPERS_JSON_FILE)) &&
|
||||
!gamesdb_developers_resource_request)
|
||||
gamesdb_developers_resource_request = fetchResource(DEVELOPERS_ENDPOINT);
|
||||
|
||||
if (loadResource(gamesdb_new_publishers_map, "publishers",
|
||||
genFilePath(PUBLISHERS_JSON_FILE)) && !gamesdb_publishers_resource_request)
|
||||
if (loadResource(gamesdb_new_publishers_map, "publishers", genFilePath(PUBLISHERS_JSON_FILE)) &&
|
||||
!gamesdb_publishers_resource_request)
|
||||
gamesdb_publishers_resource_request = fetchResource(PUBLISHERS_ENDPOINT);
|
||||
|
||||
if (loadResource(gamesdb_new_genres_map, "genres",
|
||||
genFilePath(GENRES_JSON_FILE)) && !gamesdb_genres_resource_request)
|
||||
if (loadResource(gamesdb_new_genres_map, "genres", genFilePath(GENRES_JSON_FILE)) &&
|
||||
!gamesdb_genres_resource_request)
|
||||
gamesdb_genres_resource_request = fetchResource(GENRES_ENDPOINT);
|
||||
}
|
||||
|
||||
|
@ -90,17 +91,18 @@ void TheGamesDBJSONRequestResources::ensureResources()
|
|||
for (int i = 0; i < MAX_WAIT_ITER; i++) {
|
||||
|
||||
if (gamesdb_developers_resource_request &&
|
||||
saveResource(gamesdb_developers_resource_request.get(),
|
||||
gamesdb_new_developers_map, "developers", genFilePath(DEVELOPERS_JSON_FILE)))
|
||||
saveResource(gamesdb_developers_resource_request.get(), gamesdb_new_developers_map,
|
||||
"developers", genFilePath(DEVELOPERS_JSON_FILE)))
|
||||
gamesdb_developers_resource_request.reset(nullptr);
|
||||
|
||||
if (gamesdb_publishers_resource_request &&
|
||||
saveResource(gamesdb_publishers_resource_request.get(),
|
||||
gamesdb_new_publishers_map, "publishers", genFilePath(PUBLISHERS_JSON_FILE)))
|
||||
saveResource(gamesdb_publishers_resource_request.get(), gamesdb_new_publishers_map,
|
||||
"publishers", genFilePath(PUBLISHERS_JSON_FILE)))
|
||||
gamesdb_publishers_resource_request.reset(nullptr);
|
||||
|
||||
if (gamesdb_genres_resource_request && saveResource(gamesdb_genres_resource_request.get(),
|
||||
gamesdb_new_genres_map, "genres", genFilePath(GENRES_JSON_FILE)))
|
||||
if (gamesdb_genres_resource_request &&
|
||||
saveResource(gamesdb_genres_resource_request.get(), gamesdb_new_genres_map, "genres",
|
||||
genFilePath(GENRES_JSON_FILE)))
|
||||
gamesdb_genres_resource_request.reset(nullptr);
|
||||
|
||||
if (!gamesdb_developers_resource_request && !gamesdb_publishers_resource_request &&
|
||||
|
@ -118,8 +120,7 @@ bool TheGamesDBJSONRequestResources::checkLoaded()
|
|||
!gamesdb_new_publishers_map.empty();
|
||||
}
|
||||
|
||||
bool TheGamesDBJSONRequestResources::saveResource(
|
||||
HttpReq* req,
|
||||
bool TheGamesDBJSONRequestResources::saveResource(HttpReq* req,
|
||||
std::unordered_map<int, std::string>& resource,
|
||||
const std::string& resource_name,
|
||||
const std::string& file_name)
|
||||
|
@ -133,8 +134,8 @@ bool TheGamesDBJSONRequestResources::saveResource(
|
|||
return false; // Not ready: wait some more.
|
||||
}
|
||||
if (req->status() != HttpReq::REQ_SUCCESS) {
|
||||
LOG(LogError) << "Resource request for " << file_name <<
|
||||
" failed:\n\t" << req->getErrorMsg();
|
||||
LOG(LogError) << "Resource request for " << file_name << " failed:\n\t"
|
||||
<< req->getErrorMsg();
|
||||
return true; // Request failed, resetting request..
|
||||
}
|
||||
|
||||
|
@ -156,8 +157,7 @@ std::unique_ptr<HttpReq> TheGamesDBJSONRequestResources::fetchResource(const std
|
|||
return std::unique_ptr<HttpReq>(new HttpReq(path));
|
||||
}
|
||||
|
||||
int TheGamesDBJSONRequestResources::loadResource(
|
||||
std::unordered_map<int, std::string>& resource,
|
||||
int TheGamesDBJSONRequestResources::loadResource(std::unordered_map<int, std::string>& resource,
|
||||
const std::string& resource_name,
|
||||
const std::string& file_name)
|
||||
{
|
||||
|
@ -172,8 +172,8 @@ int TheGamesDBJSONRequestResources::loadResource(
|
|||
|
||||
if (doc.HasParseError()) {
|
||||
std::string err = std::string("TheGamesDBJSONRequest - "
|
||||
"Error parsing JSON for resource file ") + file_name +
|
||||
":\n\t" + GetParseError_En(doc.GetParseError());
|
||||
"Error parsing JSON for resource file ") +
|
||||
file_name + ":\n\t" + GetParseError_En(doc.GetParseError());
|
||||
LOG(LogError) << err;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -33,18 +33,16 @@ struct TheGamesDBJSONRequestResources {
|
|||
std::unordered_map<int, std::string> gamesdb_new_publishers_map;
|
||||
std::unordered_map<int, std::string> gamesdb_new_genres_map;
|
||||
|
||||
private:
|
||||
private:
|
||||
bool checkLoaded();
|
||||
|
||||
bool saveResource(
|
||||
HttpReq* req,
|
||||
bool saveResource(HttpReq* req,
|
||||
std::unordered_map<int, std::string>& resource,
|
||||
const std::string& resource_name,
|
||||
const std::string& file_name);
|
||||
std::unique_ptr<HttpReq> fetchResource(const std::string& endpoint);
|
||||
|
||||
int loadResource(
|
||||
std::unordered_map<int, std::string>& resource,
|
||||
int loadResource(std::unordered_map<int, std::string>& resource,
|
||||
const std::string& resource_name,
|
||||
const std::string& file_name);
|
||||
|
||||
|
|
|
@ -10,20 +10,20 @@
|
|||
|
||||
#include "scrapers/Scraper.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "GamesDBJSONScraper.h"
|
||||
#include "Log.h"
|
||||
#include "ScreenScraper.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#if defined(_WIN64)
|
||||
#include "views/ViewController.h"
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <FreeImage.h>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
|
||||
const std::map<std::string, generate_scraper_requests_func> scraper_request_funcs {
|
||||
|
@ -41,9 +41,9 @@ std::unique_ptr<ScraperSearchHandle> startScraperSearch(const ScraperSearchParam
|
|||
LOG(LogError) << "Configured scraper (" << name << ") unavailable, scraping aborted";
|
||||
}
|
||||
else {
|
||||
LOG(LogDebug) << "Scraper::startScraperSearch(): Scraping system \"" <<
|
||||
params.system->getName() << "\", game file \"" <<
|
||||
params.game->getFileName() << "\"";
|
||||
LOG(LogDebug) << "Scraper::startScraperSearch(): Scraping system \""
|
||||
<< params.system->getName() << "\", game file \""
|
||||
<< params.game->getFileName() << "\"";
|
||||
scraper_request_funcs.at(name)(params, handle->mRequestQueue, handle->mResults);
|
||||
}
|
||||
|
||||
|
@ -84,12 +84,6 @@ bool isValidConfiguredScraper()
|
|||
return scraper_request_funcs.find(name) != scraper_request_funcs.end();
|
||||
}
|
||||
|
||||
// ScraperSearchHandle.
|
||||
ScraperSearchHandle::ScraperSearchHandle()
|
||||
{
|
||||
setStatus(ASYNC_IN_PROGRESS);
|
||||
}
|
||||
|
||||
void ScraperSearchHandle::update()
|
||||
{
|
||||
if (mStatus == ASYNC_DONE)
|
||||
|
@ -134,7 +128,8 @@ ScraperRequest::ScraperRequest(std::vector<ScraperSearchResult>& resultsWrite)
|
|||
|
||||
// ScraperHttpRequest.
|
||||
ScraperHttpRequest::ScraperHttpRequest(std::vector<ScraperSearchResult>& resultsWrite,
|
||||
const std::string& url) : ScraperRequest(resultsWrite)
|
||||
const std::string& url)
|
||||
: ScraperRequest(resultsWrite)
|
||||
{
|
||||
setStatus(ASYNC_IN_PROGRESS);
|
||||
mReq = std::unique_ptr<HttpReq>(new HttpReq(url));
|
||||
|
@ -155,7 +150,7 @@ void ScraperHttpRequest::update()
|
|||
return;
|
||||
|
||||
// Everything else is some sort of error.
|
||||
LOG(LogError) << "ScraperHttpRequest network error (status: " << status<< ") - "
|
||||
LOG(LogError) << "ScraperHttpRequest network error (status: " << status << ") - "
|
||||
<< mReq->getErrorMsg();
|
||||
setError("Network error: " + mReq->getErrorMsg());
|
||||
}
|
||||
|
@ -168,7 +163,8 @@ std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult
|
|||
}
|
||||
|
||||
MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||
const ScraperSearchParams& search) : mResult(result)
|
||||
const ScraperSearchParams& search)
|
||||
: mResult(result)
|
||||
{
|
||||
struct mediaFileInfoStruct {
|
||||
std::string fileURL;
|
||||
|
@ -221,10 +217,10 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
mediaFileInfo.existingMediaFile = search.game->getVideoPath();
|
||||
mediaFileInfo.resizeFile = false;
|
||||
scrapeFiles.push_back(mediaFileInfo);
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
// Required due to the idiotic file locking that exists on this operating system.
|
||||
ViewController::get()->onStopVideo();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
for (auto it = scrapeFiles.cbegin(); it != scrapeFiles.cend(); it++) {
|
||||
|
@ -253,8 +249,7 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
|
||||
// If the image is cached already as the thumbnail, then we don't need
|
||||
// to download it again, in this case just save it to disk and resize it.
|
||||
if (mResult.thumbnailImageUrl == it->fileURL &&
|
||||
mResult.thumbnailImageData.size() > 0) {
|
||||
if (mResult.thumbnailImageUrl == it->fileURL && mResult.thumbnailImageData.size() > 0) {
|
||||
|
||||
// This is just a temporary workaround to avoid saving media files to disk that
|
||||
// are actually just containing error messages from the scraper service. The
|
||||
|
@ -267,8 +262,8 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
if (Settings::getInstance()->getBool("ScraperHaltOnInvalidMedia") &&
|
||||
mResult.thumbnailImageData.size() < 350) {
|
||||
|
||||
FIMEMORY* memoryStream = FreeImage_OpenMemory(
|
||||
reinterpret_cast<BYTE*>(&mResult.thumbnailImageData.at(0)),
|
||||
FIMEMORY* memoryStream =
|
||||
FreeImage_OpenMemory(reinterpret_cast<BYTE*>(&mResult.thumbnailImageData.at(0)),
|
||||
static_cast<DWORD>(mResult.thumbnailImageData.size()));
|
||||
|
||||
FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
||||
|
@ -294,17 +289,17 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(filePath))) {
|
||||
setError("Media directory does not exist and can't be created. "
|
||||
"Permission problems?");
|
||||
LOG(LogError) << "Couldn't create media directory: \"" <<
|
||||
Utils::FileSystem::getParent(filePath) << "\"";
|
||||
LOG(LogError) << "Couldn't create media directory: \""
|
||||
<< Utils::FileSystem::getParent(filePath) << "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::ofstream stream(Utils::String::stringToWideString(filePath).c_str(),
|
||||
std::ios_base::out | std::ios_base::binary);
|
||||
#else
|
||||
#else
|
||||
std::ofstream stream(filePath, std::ios_base::out | std::ios_base::binary);
|
||||
#endif
|
||||
#endif
|
||||
if (!stream || stream.bad()) {
|
||||
setError("Failed to open path for writing media file.\nPermission error?");
|
||||
return;
|
||||
|
@ -331,7 +326,8 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
|||
// If it's not cached, then initiate the download.
|
||||
else {
|
||||
mFuncs.push_back(ResolvePair(downloadMediaAsync(it->fileURL, filePath,
|
||||
it->existingMediaFile, it->subDirectory, it->resizeFile, mResult.savedNewMedia),
|
||||
it->existingMediaFile, it->subDirectory,
|
||||
it->resizeFile, mResult.savedNewMedia),
|
||||
[this, filePath] {}));
|
||||
}
|
||||
}
|
||||
|
@ -361,8 +357,7 @@ void MDResolveHandle::update()
|
|||
setStatus(ASYNC_DONE);
|
||||
}
|
||||
|
||||
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
|
||||
const std::string& url,
|
||||
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(const std::string& url,
|
||||
const std::string& saveAs,
|
||||
const std::string& existingMediaPath,
|
||||
const std::string& mediaType,
|
||||
|
@ -370,26 +365,20 @@ std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
|
|||
bool& savedNewMedia)
|
||||
{
|
||||
return std::unique_ptr<MediaDownloadHandle>(new MediaDownloadHandle(
|
||||
url,
|
||||
saveAs,
|
||||
existingMediaPath,
|
||||
mediaType,
|
||||
resizeFile,
|
||||
savedNewMedia));
|
||||
url, saveAs, existingMediaPath, mediaType, resizeFile, savedNewMedia));
|
||||
}
|
||||
|
||||
MediaDownloadHandle::MediaDownloadHandle(
|
||||
const std::string& url,
|
||||
MediaDownloadHandle::MediaDownloadHandle(const std::string& url,
|
||||
const std::string& path,
|
||||
const std::string& existingMediaPath,
|
||||
const std::string& mediaType,
|
||||
const bool resizeFile,
|
||||
bool& savedNewMedia)
|
||||
: mSavePath(path),
|
||||
mExistingMediaFile(existingMediaPath),
|
||||
mMediaType(mediaType),
|
||||
mResizeFile(resizeFile),
|
||||
mReq(new HttpReq(url))
|
||||
: mSavePath(path)
|
||||
, mExistingMediaFile(existingMediaPath)
|
||||
, mMediaType(mediaType)
|
||||
, mResizeFile(resizeFile)
|
||||
, mReq(new HttpReq(url))
|
||||
{
|
||||
mSavedNewMediaPtr = &savedNewMedia;
|
||||
}
|
||||
|
@ -427,11 +416,8 @@ void MediaDownloadHandle::update()
|
|||
|
||||
if (mMediaType != "videos") {
|
||||
std::string imageData = mReq->getContent();
|
||||
|
||||
FIMEMORY* memoryStream = FreeImage_OpenMemory(
|
||||
reinterpret_cast<BYTE*>(&imageData.at(0)),
|
||||
FIMEMORY* memoryStream = FreeImage_OpenMemory(reinterpret_cast<BYTE*>(&imageData.at(0)),
|
||||
static_cast<DWORD>(imageData.size()));
|
||||
|
||||
imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
||||
FreeImage_CloseMemory(memoryStream);
|
||||
}
|
||||
|
@ -455,17 +441,17 @@ void MediaDownloadHandle::update()
|
|||
// problems or the MediaDirectory setting points to a file instead of a directory.
|
||||
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(mSavePath))) {
|
||||
setError("Media directory does not exist and can't be created. Permission problems?");
|
||||
LOG(LogError) << "Couldn't create media directory: \"" <<
|
||||
Utils::FileSystem::getParent(mSavePath) << "\"";
|
||||
LOG(LogError) << "Couldn't create media directory: \""
|
||||
<< Utils::FileSystem::getParent(mSavePath) << "\"";
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
std::ofstream stream(Utils::String::stringToWideString(mSavePath).c_str(),
|
||||
std::ios_base::out | std::ios_base::binary);
|
||||
#else
|
||||
#else
|
||||
std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary);
|
||||
#endif
|
||||
#endif
|
||||
if (!stream || stream.bad()) {
|
||||
setError("Failed to open path for writing media file.\nPermission error?");
|
||||
return;
|
||||
|
@ -512,15 +498,16 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
|||
FIBITMAP* image = nullptr;
|
||||
|
||||
// Detect the file format.
|
||||
#if defined(_WIN64)
|
||||
|
||||
#if defined(_WIN64)
|
||||
format = FreeImage_GetFileTypeU(Utils::String::stringToWideString(path).c_str(), 0);
|
||||
if (format == FIF_UNKNOWN)
|
||||
format = FreeImage_GetFIFFromFilenameU(Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
format = FreeImage_GetFileType(path.c_str(), 0);
|
||||
if (format == FIF_UNKNOWN)
|
||||
format = FreeImage_GetFIFFromFilename(path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
if (format == FIF_UNKNOWN) {
|
||||
LOG(LogError) << "Could not detect filetype for image \"" << path << "\"!";
|
||||
return false;
|
||||
|
@ -528,11 +515,11 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
|||
|
||||
// Make sure we can read this format, and if so, then load it.
|
||||
if (FreeImage_FIFSupportsReading(format)) {
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
image = FreeImage_LoadU(format, Utils::String::stringToWideString(path).c_str());
|
||||
#else
|
||||
#else
|
||||
image = FreeImage_Load(format, path.c_str());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LOG(LogError) << "File format not supported for image \"" << path << "\"";
|
||||
|
@ -545,8 +532,8 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
|||
// If the image is smaller than (or the same size as) maxWidth and maxHeight, then don't
|
||||
// do any scaling. It doesn't make sense to upscale the image and waste disk space.
|
||||
if (maxWidth >= width && maxHeight >= height) {
|
||||
LOG(LogDebug) << "Scraper::resizeImage(): Saving image \"" << path <<
|
||||
"\" at its original resolution " << width << "x" << height;
|
||||
LOG(LogDebug) << "Scraper::resizeImage(): Saving image \"" << path
|
||||
<< "\" at its original resolution " << width << "x" << height;
|
||||
FreeImage_Unload(image);
|
||||
return true;
|
||||
}
|
||||
|
@ -576,12 +563,12 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
bool saved = (FreeImage_SaveU(format, imageRescaled,
|
||||
Utils::String::stringToWideString(path).c_str()) != 0);
|
||||
#else
|
||||
#else
|
||||
bool saved = (FreeImage_Save(format, imageRescaled, path.c_str()) != 0);
|
||||
#endif
|
||||
#endif
|
||||
FreeImage_Unload(imageRescaled);
|
||||
|
||||
if (!saved) {
|
||||
|
@ -596,7 +583,8 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
|||
}
|
||||
|
||||
std::string getSaveAsPath(const ScraperSearchParams& params,
|
||||
const std::string& filetypeSubdirectory, const std::string& extension)
|
||||
const std::string& filetypeSubdirectory,
|
||||
const std::string& extension)
|
||||
{
|
||||
const std::string systemsubdirectory = params.system->getName();
|
||||
const std::string name = Utils::FileSystem::getStem(params.game->getPath());
|
||||
|
|
|
@ -27,7 +27,7 @@ class FileData;
|
|||
class SystemData;
|
||||
|
||||
enum downloadStatus {
|
||||
NOT_STARTED,
|
||||
NOT_STARTED, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
IN_PROGRESS,
|
||||
COMPLETED
|
||||
};
|
||||
|
@ -40,7 +40,10 @@ struct ScraperSearchParams {
|
|||
};
|
||||
|
||||
struct ScraperSearchResult {
|
||||
ScraperSearchResult() : mdl(GAME_METADATA) {};
|
||||
ScraperSearchResult()
|
||||
: mdl(GAME_METADATA)
|
||||
{
|
||||
}
|
||||
|
||||
MetaDataList mdl;
|
||||
std::string gameID;
|
||||
|
@ -73,34 +76,6 @@ struct ScraperSearchResult {
|
|||
bool savedNewMedia;
|
||||
};
|
||||
|
||||
// So let me explain why I've abstracted this so heavily.
|
||||
// There are two ways I can think of that you'd want to write a scraper.
|
||||
|
||||
// 1. Do some HTTP request(s) -> process it -> return the results.
|
||||
// 2. Do some local filesystem queries (an offline scraper) -> return the results.
|
||||
|
||||
// The first way needs to be asynchronous while it's waiting for the HTTP request to return.
|
||||
// The second doesn't.
|
||||
|
||||
// It would be nice if we could write it like this:
|
||||
// search = generate_http_request(searchparams);
|
||||
// wait_until_done(search);
|
||||
// ... process search ...
|
||||
// return results;
|
||||
|
||||
// We could do this if we used threads. Right now ES doesn't because I'm pretty sure I'll
|
||||
// fuck it up, and I'm not sure of the performance of threads on the Pi (single-core ARM).
|
||||
// We could also do this if we used coroutines.
|
||||
// I can't find a really good cross-platform coroutine library (x86/64/ARM Linux + Windows),
|
||||
// and I don't want to spend more time chasing libraries than just writing it the long way once.
|
||||
|
||||
// So, I did it the "long" way.
|
||||
// ScraperSearchHandle - one logical search, e.g. "search for mario".
|
||||
// ScraperRequest - encapsulates some sort of asynchronous request that will ultimately
|
||||
// return some results.
|
||||
// ScraperHttpRequest - implementation of ScraperRequest that waits on an HttpReq, then
|
||||
// processes it with some processing function.
|
||||
|
||||
// A scraper search gathers results from (potentially multiple) ScraperRequests.
|
||||
class ScraperRequest : public AsyncHandle
|
||||
{
|
||||
|
@ -133,21 +108,20 @@ private:
|
|||
class ScraperSearchHandle : public AsyncHandle
|
||||
{
|
||||
public:
|
||||
ScraperSearchHandle();
|
||||
ScraperSearchHandle() { setStatus(ASYNC_IN_PROGRESS); }
|
||||
|
||||
void update();
|
||||
inline const std::vector<ScraperSearchResult>& getResults() const
|
||||
const std::vector<ScraperSearchResult>& getResults() const
|
||||
{
|
||||
assert(mStatus != ASYNC_IN_PROGRESS);
|
||||
return mResults;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend std::unique_ptr<ScraperSearchHandle>
|
||||
startScraperSearch(const ScraperSearchParams& params);
|
||||
friend std::unique_ptr<ScraperSearchHandle> startScraperSearch(
|
||||
const ScraperSearchParams& params);
|
||||
|
||||
friend std::unique_ptr<ScraperSearchHandle>
|
||||
startMediaURLsFetch(const std::string& gameIDs);
|
||||
friend std::unique_ptr<ScraperSearchHandle> startMediaURLsFetch(const std::string& gameIDs);
|
||||
|
||||
std::queue<std::unique_ptr<ScraperRequest>> mRequestQueue;
|
||||
std::vector<ScraperSearchResult> mResults;
|
||||
|
@ -164,7 +138,8 @@ std::vector<std::string> getScraperList();
|
|||
// Returns true if the scraper configured in the settings is still valid.
|
||||
bool isValidConfiguredScraper();
|
||||
|
||||
typedef void (*generate_scraper_requests_func)(const ScraperSearchParams& params,
|
||||
typedef void (*generate_scraper_requests_func)(
|
||||
const ScraperSearchParams& params,
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||
std::vector<ScraperSearchResult>& results);
|
||||
|
||||
|
@ -177,8 +152,11 @@ public:
|
|||
MDResolveHandle(const ScraperSearchResult& result, const ScraperSearchParams& search);
|
||||
|
||||
void update() override;
|
||||
inline const ScraperSearchResult& getResult() const
|
||||
{ assert(mStatus == ASYNC_DONE); return mResult; }
|
||||
const ScraperSearchResult& getResult() const
|
||||
{
|
||||
assert(mStatus == ASYNC_DONE);
|
||||
return mResult;
|
||||
}
|
||||
bool getSavedNewMedia() { return mResult.savedNewMedia; }
|
||||
|
||||
private:
|
||||
|
@ -191,8 +169,7 @@ private:
|
|||
class MediaDownloadHandle : public AsyncHandle
|
||||
{
|
||||
public:
|
||||
MediaDownloadHandle(
|
||||
const std::string& url,
|
||||
MediaDownloadHandle(const std::string& url,
|
||||
const std::string& path,
|
||||
const std::string& existingMediaPath,
|
||||
const std::string& mediaType,
|
||||
|
@ -207,17 +184,17 @@ private:
|
|||
std::string mExistingMediaFile;
|
||||
std::string mMediaType;
|
||||
bool mResizeFile;
|
||||
bool *mSavedNewMediaPtr;
|
||||
bool* mSavedNewMediaPtr;
|
||||
};
|
||||
|
||||
// Downloads to the home directory, using this subdirectory structure:
|
||||
// ".emulationstation/downloaded_media/[system_name]/[media_type]/[game_name].[file_extension]".
|
||||
// The subdirectories are automatically created if they do not exist.
|
||||
std::string getSaveAsPath(const ScraperSearchParams& params,
|
||||
const std::string& filetypeSubdirectory, const std::string& url);
|
||||
const std::string& filetypeSubdirectory,
|
||||
const std::string& url);
|
||||
|
||||
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
|
||||
const std::string& url,
|
||||
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(const std::string& url,
|
||||
const std::string& saveAs,
|
||||
const std::string& existingMediaPath,
|
||||
const std::string& mediaType,
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
|
||||
#include "scrapers/ScreenScraper.h"
|
||||
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "FileData.h"
|
||||
#include "Log.h"
|
||||
#include "PlatformId.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "math/Misc.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
@ -42,7 +42,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
{ ATARI_JAGUAR, 27 },
|
||||
{ ATARI_JAGUAR_CD, 171 },
|
||||
{ ATARI_LYNX, 28 },
|
||||
{ ATARI_ST, 42},
|
||||
{ ATARI_ST, 42 },
|
||||
{ ATARI_XE, 43 },
|
||||
{ ATOMISWAVE, 53 },
|
||||
{ BBC_MICRO, 37 },
|
||||
|
@ -62,7 +62,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
{ MSX_TURBO_R, 118 },
|
||||
{ SNK_NEO_GEO, 142 },
|
||||
{ SNK_NEO_GEO_CD, 142 },
|
||||
{ SNK_NEO_GEO_POCKET, 25},
|
||||
{ SNK_NEO_GEO_POCKET, 25 },
|
||||
{ SNK_NEO_GEO_POCKET_COLOR, 82 },
|
||||
{ NINTENDO_3DS, 17 },
|
||||
{ NINTENDO_64, 14 },
|
||||
|
@ -88,7 +88,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
{ NEC_PCFX, 72 },
|
||||
{ GAMEENGINE_OPENBOR, 214 },
|
||||
{ TANGERINE_ORIC, 131 },
|
||||
{ GAMEENGINE_SCUMMVM, 123},
|
||||
{ GAMEENGINE_SCUMMVM, 123 },
|
||||
{ SEGA_32X, 19 },
|
||||
{ SEGA_CD, 20 },
|
||||
{ SEGA_DREAMCAST, 23 },
|
||||
|
@ -98,8 +98,8 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
{ SEGA_MEGA_DRIVE, 1 },
|
||||
{ SEGA_SATURN, 22 },
|
||||
{ SEGA_SG1000, 109 },
|
||||
{ SHARP_X1, 220},
|
||||
{ SHARP_X68000, 79},
|
||||
{ SHARP_X1, 220 },
|
||||
{ SHARP_X68000, 79 },
|
||||
{ GAMEENGINE_SOLARUS, 223 },
|
||||
{ SONY_PLAYSTATION, 57 },
|
||||
{ SONY_PLAYSTATION_2, 58 },
|
||||
|
@ -110,8 +110,8 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
{ SUPER_NINTENDO, 4 },
|
||||
{ NEC_SUPERGRAFX, 105 },
|
||||
{ GAMEENGINE_TIC80, 222 },
|
||||
{ NEC_PC_8800, 221},
|
||||
{ NEC_PC_9800, 208},
|
||||
{ NEC_PC_8800, 221 },
|
||||
{ NEC_PC_9800, 208 },
|
||||
{ NEC_PC_ENGINE, 31 },
|
||||
{ NEC_PC_ENGINE_CD, 114 },
|
||||
{ BANDAI_WONDERSWAN, 45 },
|
||||
|
@ -131,7 +131,8 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
|||
|
||||
// Helper XML parsing method, finding a node-by-name recursively.
|
||||
pugi::xml_node find_node_by_name_re(const pugi::xml_node& node,
|
||||
const std::vector<std::string> node_names) {
|
||||
const std::vector<std::string> node_names)
|
||||
{
|
||||
|
||||
for (const std::string& _val : node_names) {
|
||||
pugi::xpath_query query_node_name((static_cast<std::string>("//") + _val).c_str());
|
||||
|
@ -147,7 +148,8 @@ pugi::xml_node find_node_by_name_re(const pugi::xml_node& node,
|
|||
// Help XML parsing method, finding an direct child XML node starting from the parent and
|
||||
// filtering by an attribute value list.
|
||||
pugi::xml_node find_child_by_attribute_list(const pugi::xml_node& node_parent,
|
||||
const std::string& node_name, const std::string& attribute_name,
|
||||
const std::string& node_name,
|
||||
const std::string& attribute_name,
|
||||
const std::vector<std::string> attribute_values)
|
||||
{
|
||||
for (auto _val : attribute_values) {
|
||||
|
@ -195,19 +197,19 @@ void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
|||
p_ids.push_back(mapIt->second);
|
||||
}
|
||||
else {
|
||||
LOG(LogWarning) << "ScreenScraper: No support for platform \"" <<
|
||||
getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||
LOG(LogWarning) << "ScreenScraper: No support for platform \""
|
||||
<< getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||
// Add the scrape request without a platform/system ID.
|
||||
requests.push(std::unique_ptr<ScraperRequest>
|
||||
(new ScreenScraperRequest(requests, results, path)));
|
||||
requests.push(
|
||||
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||
}
|
||||
}
|
||||
|
||||
if (p_ids.size() == 0) {
|
||||
LOG(LogWarning) << "ScreenScraper: No platform defined, search will be inaccurate";
|
||||
// Add the scrape request without a platform/system ID.
|
||||
requests.push(std::unique_ptr<ScraperRequest>
|
||||
(new ScreenScraperRequest(requests, results, path)));
|
||||
requests.push(
|
||||
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||
}
|
||||
|
||||
// Sort the platform IDs and remove duplicates.
|
||||
|
@ -218,8 +220,8 @@ void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
|||
for (auto platform = p_ids.cbegin(); platform != p_ids.cend(); platform++) {
|
||||
path += "&systemeid=";
|
||||
path += HttpReq::urlEncode(std::to_string(*platform));
|
||||
requests.push(std::unique_ptr<ScraperRequest>
|
||||
(new ScreenScraperRequest(requests, results, path)));
|
||||
requests.push(
|
||||
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,13 +286,14 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
||||
std::string userID = data.child("ssuser").child("id").text().get();
|
||||
if (userID != "") {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Scraping using account \"" <<
|
||||
userID << "\"";
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Scraping using account \""
|
||||
<< userID << "\"";
|
||||
}
|
||||
else {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): The configured account '" <<
|
||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper") <<
|
||||
"' was not included in the scraper response, wrong username or password?";
|
||||
LOG(LogDebug)
|
||||
<< "ScreenScraperRequest::processGame(): The configured account '"
|
||||
<< Settings::getInstance()->getString("ScraperUsernameScreenScraper")
|
||||
<< "' was not included in the scraper response, wrong username or password?";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,9 +307,9 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
|
||||
// Scraping allowance.
|
||||
if (maxRequestsPerDay > 0) {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: " <<
|
||||
requestsToday << "/" << maxRequestsPerDay << " (" <<
|
||||
scraperRequestAllowance << " remaining)";
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: "
|
||||
<< requestsToday << "/" << maxRequestsPerDay << " ("
|
||||
<< scraperRequestAllowance << " remaining)";
|
||||
}
|
||||
else {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: "
|
||||
|
@ -329,8 +332,11 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
Utils::String::toLower(Settings::getInstance()->getString("ScraperLanguage"));
|
||||
|
||||
// Name fallback: US, WOR(LD). (Xpath: Data/jeu[0]/noms/nom[*]).
|
||||
result.mdl.set("name", find_child_by_attribute_list(game.child("noms"),
|
||||
"nom", "region", { region, "wor", "us" , "ss", "eu", "jp" }).text().get());
|
||||
result.mdl.set("name",
|
||||
find_child_by_attribute_list(game.child("noms"), "nom", "region",
|
||||
{ region, "wor", "us", "ss", "eu", "jp" })
|
||||
.text()
|
||||
.get());
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Name: " << result.mdl.get("name");
|
||||
|
||||
// Validate rating.
|
||||
|
@ -346,14 +352,16 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
ss << ratingVal;
|
||||
if (ratingVal > 0) {
|
||||
result.mdl.set("rating", ss.str());
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Rating: " <<
|
||||
result.mdl.get("rating");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Rating: "
|
||||
<< result.mdl.get("rating");
|
||||
}
|
||||
}
|
||||
|
||||
// Description fallback language: EN, WOR(LD).
|
||||
std::string description = find_child_by_attribute_list(game.child("synopsis"),
|
||||
"synopsis", "langue", { language, "en", "wor" }).text().get();
|
||||
std::string description = find_child_by_attribute_list(game.child("synopsis"), "synopsis",
|
||||
"langue", { language, "en", "wor" })
|
||||
.text()
|
||||
.get();
|
||||
|
||||
// Translate some HTML character codes to UTF-8 characters.
|
||||
if (!description.empty()) {
|
||||
|
@ -362,80 +370,83 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
}
|
||||
|
||||
// Get the date proper. The API returns multiple 'date' children nodes to the 'dates'
|
||||
// main child of 'jeu'.
|
||||
// Date fallback: WOR(LD), US, SS, JP, EU.
|
||||
// main child of 'jeu'. Date fallback: WOR(LD), US, SS, JP, EU.
|
||||
std::string _date = find_child_by_attribute_list(game.child("dates"), "date", "region",
|
||||
{ region, "wor", "us", "ss", "jp", "eu" }).text().get();
|
||||
{ region, "wor", "us", "ss", "jp", "eu" })
|
||||
.text()
|
||||
.get();
|
||||
|
||||
// Date can be YYYY-MM-DD or just YYYY.
|
||||
if (_date.length() > 4) {
|
||||
result.mdl.set("releasedate", Utils::Time::DateTime(
|
||||
Utils::Time::stringToTime(_date, "%Y-%m-%d")));
|
||||
result.mdl.set("releasedate",
|
||||
Utils::Time::DateTime(Utils::Time::stringToTime(_date, "%Y-%m-%d")));
|
||||
}
|
||||
else if (_date.length() > 0) {
|
||||
result.mdl.set("releasedate", Utils::Time::DateTime(
|
||||
Utils::Time::stringToTime(_date, "%Y")));
|
||||
result.mdl.set("releasedate",
|
||||
Utils::Time::DateTime(Utils::Time::stringToTime(_date, "%Y")));
|
||||
}
|
||||
|
||||
if (_date.length() > 0) {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (unparsed): " <<
|
||||
_date;
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (parsed): " <<
|
||||
result.mdl.get("releasedate");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (unparsed): "
|
||||
<< _date;
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (parsed): "
|
||||
<< result.mdl.get("releasedate");
|
||||
}
|
||||
|
||||
// Developer for the game (Xpath: Data/jeu[0]/developpeur).
|
||||
std::string developer = game.child("developpeur").text().get();
|
||||
if (!developer.empty()) {
|
||||
result.mdl.set("developer", Utils::String::replace(developer, " ", " "));
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Developer: " <<
|
||||
result.mdl.get("developer");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Developer: "
|
||||
<< result.mdl.get("developer");
|
||||
}
|
||||
|
||||
// Publisher for the game (Xpath: Data/jeu[0]/editeur).
|
||||
std::string publisher = game.child("editeur").text().get();
|
||||
if (!publisher.empty()) {
|
||||
result.mdl.set("publisher", Utils::String::replace(publisher, " ", " "));
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Publisher: " <<
|
||||
result.mdl.get("publisher");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Publisher: "
|
||||
<< result.mdl.get("publisher");
|
||||
}
|
||||
|
||||
// Genre fallback language: EN. (Xpath: Data/jeu[0]/genres/genre[*]).
|
||||
std::string genre = find_child_by_attribute_list(game.child("genres"),
|
||||
"genre", "langue", { language, "en" }).text().get();
|
||||
std::string genre = find_child_by_attribute_list(game.child("genres"), "genre", "langue",
|
||||
{ language, "en" })
|
||||
.text()
|
||||
.get();
|
||||
if (!genre.empty()) {
|
||||
result.mdl.set("genre", genre);
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Genre: " <<
|
||||
result.mdl.get("genre");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Genre: "
|
||||
<< result.mdl.get("genre");
|
||||
}
|
||||
|
||||
// Players.
|
||||
std::string players = game.child("joueurs").text().get();
|
||||
if (!players.empty()) {
|
||||
result.mdl.set("players", players);
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Players: " <<
|
||||
result.mdl.get("players");
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Players: "
|
||||
<< result.mdl.get("players");
|
||||
}
|
||||
|
||||
// Media super-node.
|
||||
pugi::xml_node media_list = game.child("medias");
|
||||
|
||||
if (media_list) {
|
||||
// 3D box
|
||||
processMedia(result, media_list, ssConfig.media_3dbox,
|
||||
result.box3DUrl, result.box3DFormat, region);
|
||||
// Cover
|
||||
processMedia(result, media_list, ssConfig.media_cover,
|
||||
result.coverUrl, result.coverFormat, region);
|
||||
// Marquee (wheel)
|
||||
processMedia(result, media_list, ssConfig.media_marquee,
|
||||
result.marqueeUrl, result.marqueeFormat, region);
|
||||
// Screenshot
|
||||
processMedia(result, media_list, ssConfig.media_screenshot,
|
||||
result.screenshotUrl, result.screenshotFormat, region);
|
||||
// Video
|
||||
processMedia(result, media_list, ssConfig.media_video,
|
||||
result.videoUrl, result.videoFormat, region);
|
||||
// 3D box.
|
||||
processMedia(result, media_list, ssConfig.media_3dbox, result.box3DUrl,
|
||||
result.box3DFormat, region);
|
||||
// Cover.
|
||||
processMedia(result, media_list, ssConfig.media_cover, result.coverUrl,
|
||||
result.coverFormat, region);
|
||||
// Marquee (wheel).
|
||||
processMedia(result, media_list, ssConfig.media_marquee, result.marqueeUrl,
|
||||
result.marqueeFormat, region);
|
||||
// Screenshot.
|
||||
processMedia(result, media_list, ssConfig.media_screenshot, result.screenshotUrl,
|
||||
result.screenshotFormat, region);
|
||||
// Video.
|
||||
processMedia(result, media_list, ssConfig.media_video, result.videoUrl,
|
||||
result.videoFormat, region);
|
||||
}
|
||||
result.mediaURLFetch = COMPLETED;
|
||||
out_results.push_back(result);
|
||||
|
@ -446,8 +457,7 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
|||
}
|
||||
}
|
||||
|
||||
void ScreenScraperRequest::processMedia(
|
||||
ScraperSearchResult& result,
|
||||
void ScreenScraperRequest::processMedia(ScraperSearchResult& result,
|
||||
const pugi::xml_node& media_list,
|
||||
std::string mediaType,
|
||||
std::string& fileURL,
|
||||
|
@ -460,8 +470,8 @@ void ScreenScraperRequest::processMedia(
|
|||
// We need to do this because any child of 'medias' has the form
|
||||
// <media type="..." region="..." format="...">
|
||||
// and we need to find the right media for the region.
|
||||
pugi::xpath_node_set results = media_list.select_nodes((static_cast<std::string>
|
||||
("media[@type='") + mediaType + "']").c_str());
|
||||
pugi::xpath_node_set results = media_list.select_nodes(
|
||||
(static_cast<std::string>("media[@type='") + mediaType + "']").c_str());
|
||||
|
||||
if (results.size()) {
|
||||
// Videos don't have any region attributes, so just take the first entry
|
||||
|
@ -471,8 +481,8 @@ void ScreenScraperRequest::processMedia(
|
|||
}
|
||||
else {
|
||||
// Region fallback: WOR(LD), US, CUS(TOM?), JP, EU.
|
||||
for (auto _region : std::vector<std::string>{
|
||||
region, "wor", "us", "cus", "jp", "eu" }) {
|
||||
for (auto _region :
|
||||
std::vector<std::string> { region, "wor", "us", "cus", "jp", "eu" }) {
|
||||
if (art)
|
||||
break;
|
||||
|
||||
|
@ -498,7 +508,8 @@ void ScreenScraperRequest::processMedia(
|
|||
}
|
||||
else {
|
||||
LOG(LogDebug) << "ScreenScraperRequest::processMedia(): "
|
||||
"Failed to find media XML node with name '" << mediaType << "'";
|
||||
"Failed to find media XML node with name '"
|
||||
<< mediaType << "'";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,11 +538,11 @@ void ScreenScraperRequest::processList(const pugi::xml_document& xmldoc,
|
|||
std::string id = game.child("id").text().get();
|
||||
std::string name = game.child("nom").text().get();
|
||||
std::string platformId = game.child("systemeid").text().get();
|
||||
std::string path = ssConfig.getGameSearchUrl(name) + "&systemeid=" +
|
||||
platformId + "&gameid=" + id;
|
||||
std::string path =
|
||||
ssConfig.getGameSearchUrl(name) + "&systemeid=" + platformId + "&gameid=" + id;
|
||||
|
||||
mRequestQueue->push(std::unique_ptr<ScraperRequest>
|
||||
(new ScreenScraperRequest(results, path)));
|
||||
mRequestQueue->push(
|
||||
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(results, path)));
|
||||
|
||||
game = game.next_sibling("jeu");
|
||||
}
|
||||
|
@ -549,9 +560,11 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
|||
std::find_if(searchName.begin(), searchName.end(), [](char c) {
|
||||
return !std::isspace(static_cast<unsigned char>(c));
|
||||
}));
|
||||
searchName.erase(std::find_if(searchName.rbegin(), searchName.rend(), [](char c) {
|
||||
return !std::isspace(static_cast<unsigned char>(c));
|
||||
}).base(), searchName.end());
|
||||
searchName.erase(
|
||||
std::find_if(searchName.rbegin(), searchName.rend(),
|
||||
[](char c) { return !std::isspace(static_cast<unsigned char>(c)); })
|
||||
.base(),
|
||||
searchName.end());
|
||||
|
||||
// If only whitespaces were entered as the search string, then search using a random string
|
||||
// that will not return any results. This is a quick and dirty way to avoid french error
|
||||
|
@ -578,9 +591,10 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
|||
// than four characters which would break the wide search.
|
||||
std::string trimTrailingPluses = searchName;
|
||||
trimTrailingPluses.erase(std::find_if(trimTrailingPluses.rbegin(),
|
||||
trimTrailingPluses.rend(), [](char c) {
|
||||
return c != '+';
|
||||
}).base(), trimTrailingPluses.end());
|
||||
trimTrailingPluses.rend(),
|
||||
[](char c) { return c != '+'; })
|
||||
.base(),
|
||||
trimTrailingPluses.end());
|
||||
|
||||
if (trimTrailingPluses.size() < 4)
|
||||
singleSearch = true;
|
||||
|
@ -605,20 +619,18 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
|||
}
|
||||
|
||||
if (singleSearch) {
|
||||
screenScraperURL = API_URL_BASE
|
||||
+ "/jeuInfos.php?devid=" + Utils::String::scramble(API_DEV_U, API_DEV_KEY)
|
||||
+ "&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY)
|
||||
+ "&softname=" + HttpReq::urlEncode(API_SOFT_NAME)
|
||||
+ "&output=xml"
|
||||
+ "&romnom=" + HttpReq::urlEncode(searchName);
|
||||
screenScraperURL = API_URL_BASE + "/jeuInfos.php?devid=" +
|
||||
Utils::String::scramble(API_DEV_U, API_DEV_KEY) +
|
||||
"&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY) +
|
||||
"&softname=" + HttpReq::urlEncode(API_SOFT_NAME) + "&output=xml" +
|
||||
"&romnom=" + HttpReq::urlEncode(searchName);
|
||||
}
|
||||
else {
|
||||
screenScraperURL = API_URL_BASE
|
||||
+ "/jeuRecherche.php?devid=" + Utils::String::scramble(API_DEV_U, API_DEV_KEY)
|
||||
+ "&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY)
|
||||
+ "&softname=" + HttpReq::urlEncode(API_SOFT_NAME)
|
||||
+ "&output=xml"
|
||||
+ "&recherche=" + HttpReq::urlEncode(searchName);
|
||||
screenScraperURL = API_URL_BASE + "/jeuRecherche.php?devid=" +
|
||||
Utils::String::scramble(API_DEV_U, API_DEV_KEY) +
|
||||
"&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY) +
|
||||
"&softname=" + HttpReq::urlEncode(API_SOFT_NAME) + "&output=xml" +
|
||||
"&recherche=" + HttpReq::urlEncode(searchName);
|
||||
}
|
||||
|
||||
// Username / password, if this has been setup and activated.
|
||||
|
@ -626,8 +638,8 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
|||
std::string username = Settings::getInstance()->getString("ScraperUsernameScreenScraper");
|
||||
std::string password = Settings::getInstance()->getString("ScraperPasswordScreenScraper");
|
||||
if (!username.empty() && !password.empty())
|
||||
screenScraperURL += "&ssid=" + HttpReq::urlEncode(username) + "&sspassword=" +
|
||||
HttpReq::urlEncode(password);
|
||||
screenScraperURL += "&ssid=" + HttpReq::urlEncode(username) +
|
||||
"&sspassword=" + HttpReq::urlEncode(password);
|
||||
}
|
||||
|
||||
return screenScraperURL;
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
#ifndef ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
||||
#define ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
||||
|
||||
#include "scrapers/Scraper.h"
|
||||
#include "EmulationStation.h"
|
||||
#include "scrapers/Scraper.h"
|
||||
|
||||
namespace pugi { class xml_document; }
|
||||
namespace pugi
|
||||
{
|
||||
class xml_document;
|
||||
}
|
||||
|
||||
void screenscraper_generate_scraper_requests(
|
||||
const ScraperSearchParams& params,
|
||||
void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||
std::vector<ScraperSearchResult>& results);
|
||||
|
||||
|
@ -26,33 +28,36 @@ public:
|
|||
// ctor for a GetGameList request.
|
||||
ScreenScraperRequest(std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
||||
std::vector<ScraperSearchResult>& resultsWrite,
|
||||
const std::string& url) : ScraperHttpRequest(resultsWrite, url),
|
||||
mRequestQueue(&requestsWrite) {}
|
||||
const std::string& url)
|
||||
: ScraperHttpRequest(resultsWrite, url)
|
||||
, mRequestQueue(&requestsWrite)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor for a GetGame request.
|
||||
ScreenScraperRequest(std::vector<ScraperSearchResult>& resultsWrite,
|
||||
const std::string& url) : ScraperHttpRequest(resultsWrite, url),
|
||||
mRequestQueue(nullptr) {}
|
||||
ScreenScraperRequest(std::vector<ScraperSearchResult>& resultsWrite, const std::string& url)
|
||||
: ScraperHttpRequest(resultsWrite, url)
|
||||
, mRequestQueue(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// Settings for the scraper.
|
||||
static const struct ScreenScraperConfig {
|
||||
std::string getGameSearchUrl(const std::string gameName) const;
|
||||
|
||||
// Access to the API.
|
||||
const std::string API_DEV_U =
|
||||
{ 15, 21, 39, 22, 42, 40 };
|
||||
const std::string API_DEV_P =
|
||||
{ 32, 70, 46, 54, 12, 5, 13, 120, 50, 66, 25 };
|
||||
const std::string API_DEV_KEY =
|
||||
{ 67, 112, 72, 120, 121, 77, 119, 74, 84, 56, 75, 122, 78, 98, 69, 86, 56, 120, 120, 49 };
|
||||
const std::string API_DEV_U = { 15, 21, 39, 22, 42, 40 };
|
||||
const std::string API_DEV_P = { 32, 70, 46, 54, 12, 5, 13, 120, 50, 66, 25 };
|
||||
const std::string API_DEV_KEY = { 67, 112, 72, 120, 121, 77, 119, 74, 84, 56,
|
||||
75, 122, 78, 98, 69, 86, 56, 120, 120, 49 };
|
||||
const std::string API_URL_BASE = "https://www.screenscraper.fr/api2";
|
||||
const std::string API_SOFT_NAME = "EmulationStation-DE " +
|
||||
static_cast<std::string>(PROGRAM_VERSION_STRING);
|
||||
const std::string API_SOFT_NAME =
|
||||
"EmulationStation-DE " + static_cast<std::string>(PROGRAM_VERSION_STRING);
|
||||
|
||||
// Which type of image artwork we need. Possible values (not a comprehensive list):
|
||||
// - ss: in-game screenshot
|
||||
// - box-3D: 3D boxart
|
||||
// - box-2D: 2D boxart (default)
|
||||
// - box-2D: 2D boxart
|
||||
// - screenmarque : marquee
|
||||
// - sstitle: in-game start screenshot
|
||||
// - steamgrid: Steam artwork
|
||||
|
@ -75,13 +80,13 @@ public:
|
|||
|
||||
// Which Region to use when selecting the artwork.
|
||||
// Applies to: artwork, name of the game, date of release.
|
||||
// This is read from es_settings.xml, setting 'ScraperRegion'.
|
||||
// This is read from es_settings.xml, setting "ScraperRegion".
|
||||
|
||||
// Which Language to use when selecting the textual information.
|
||||
// Applies to: description, genre.
|
||||
// This is read from es_settings.xml, setting 'ScraperLanguage'.
|
||||
// This is read from es_settings.xml, setting "ScraperLanguage".
|
||||
|
||||
ScreenScraperConfig() {};
|
||||
ScreenScraperConfig() {}
|
||||
} configuration;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
|
||||
#include "views/SystemView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#if defined(_WIN64)
|
||||
#include <cmath>
|
||||
|
@ -26,14 +26,12 @@
|
|||
const int logoBuffersLeft[] = { -5, -2, -1 };
|
||||
const int logoBuffersRight[] = { 1, 2, 5 };
|
||||
|
||||
SystemView::SystemView(
|
||||
Window* window)
|
||||
: IList<SystemViewData, SystemData*>
|
||||
(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP),
|
||||
mPreviousScrollVelocity(0),
|
||||
mUpdatedGameCount(false),
|
||||
mViewNeedsReload(true),
|
||||
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
||||
SystemView::SystemView(Window* window)
|
||||
: IList<SystemViewData, SystemData*>(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP)
|
||||
, mPreviousScrollVelocity(0)
|
||||
, mUpdatedGameCount(false)
|
||||
, mViewNeedsReload(true)
|
||||
, mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
||||
{
|
||||
mCamOffset = 0;
|
||||
mExtrasCamOffset = 0;
|
||||
|
@ -58,7 +56,7 @@ void SystemView::populate()
|
|||
{
|
||||
mEntries.clear();
|
||||
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
|
||||
|
||||
|
@ -74,8 +72,8 @@ void SystemView::populate()
|
|||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||
if (logoElem) {
|
||||
std::string path = logoElem->get<std::string>("path");
|
||||
std::string defaultPath = logoElem->has("default") ?
|
||||
logoElem->get<std::string>("default") : "";
|
||||
std::string defaultPath =
|
||||
logoElem->has("default") ? logoElem->get<std::string>("default") : "";
|
||||
if ((!path.empty() && ResourceManager::getInstance()->fileExists(path)) ||
|
||||
(!defaultPath.empty() &&
|
||||
ResourceManager::getInstance()->fileExists(defaultPath))) {
|
||||
|
@ -88,16 +86,14 @@ void SystemView::populate()
|
|||
}
|
||||
if (!e.data.logo) {
|
||||
// No logo in theme; use text.
|
||||
TextComponent* text = new TextComponent(
|
||||
mWindow,
|
||||
(*it)->getName(),
|
||||
Font::get(FONT_SIZE_LARGE),
|
||||
0x000000FF,
|
||||
ALIGN_CENTER);
|
||||
TextComponent* text =
|
||||
new TextComponent(mWindow, (*it)->getName(), Font::get(FONT_SIZE_LARGE),
|
||||
0x000000FF, ALIGN_CENTER);
|
||||
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||
text->applyTheme((*it)->getTheme(), "system", "logoText",
|
||||
ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR |
|
||||
ThemeFlags::FORCE_UPPERCASE | ThemeFlags::LINE_SPACING | ThemeFlags::TEXT);
|
||||
ThemeFlags::FORCE_UPPERCASE | ThemeFlags::LINE_SPACING |
|
||||
ThemeFlags::TEXT);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
|
||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) {
|
||||
|
@ -134,10 +130,9 @@ void SystemView::populate()
|
|||
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
||||
|
||||
// Sort the extras by z-index.
|
||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(),
|
||||
[](GuiComponent* a, GuiComponent* b) {
|
||||
return b->getZIndex() > a->getZIndex();
|
||||
});
|
||||
std::stable_sort(
|
||||
e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(),
|
||||
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
|
||||
|
||||
this->add(e);
|
||||
}
|
||||
|
@ -146,9 +141,10 @@ void SystemView::populate()
|
|||
// Something is wrong, there is not a single system to show, check if UI mode is not full.
|
||||
if (!UIModeController::getInstance()->isUIModeFull()) {
|
||||
Settings::getInstance()->setString("UIMode", "full");
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||
"The selected UI mode has nothing to show,\n returning to UI mode \"Full\"",
|
||||
"OK", nullptr));
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, getHelpStyle(),
|
||||
"The selected UI mode has nothing to show,\n returning to UI mode \"Full\"", "OK",
|
||||
nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,14 +158,14 @@ void SystemView::updateGameCount()
|
|||
ss << "CONFIGURATION";
|
||||
else if (getSelected()->isCollection() && (getSelected()->getName() == "favorites"))
|
||||
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S");
|
||||
// The 'recent' gamelist has probably been trimmed after sorting, so we'll cap it at
|
||||
// The "recent" gamelist has probably been trimmed after sorting, so we'll cap it at
|
||||
// its maximum limit of 50 games.
|
||||
else if (getSelected()->isCollection() && (getSelected()->getName() == "recent"))
|
||||
ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME" <<
|
||||
(gameCount.first == 1 ? " " : "S");
|
||||
ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME"
|
||||
<< (gameCount.first == 1 ? " " : "S");
|
||||
else
|
||||
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "(" <<
|
||||
gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)");
|
||||
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "("
|
||||
<< gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)");
|
||||
|
||||
mSystemInfo.setText(ss.str());
|
||||
}
|
||||
|
@ -241,8 +237,7 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||
config->isMappedTo("back", input) &&
|
||||
if (!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("back", input) &&
|
||||
Settings::getInstance()->getBool("ScreensaverControls")) {
|
||||
if (!mWindow->isScreensaverActive()) {
|
||||
ViewController::get()->stopScrolling();
|
||||
|
@ -254,10 +249,8 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (config->isMappedLike("left", input) ||
|
||||
config->isMappedLike("right", input) ||
|
||||
config->isMappedLike("up", input) ||
|
||||
config->isMappedLike("down", input))
|
||||
if (config->isMappedLike("left", input) || config->isMappedLike("right", input) ||
|
||||
config->isMappedLike("up", input) || config->isMappedLike("down", input))
|
||||
listInput(0);
|
||||
}
|
||||
|
||||
|
@ -302,8 +295,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||
|
||||
// To prevent ugly jumps with two systems when quickly repeating the same direction.
|
||||
if (mPreviousScrollVelocity != 0 && posMax == 2 &&
|
||||
mScrollVelocity == mPreviousScrollVelocity ) {
|
||||
if (mPreviousScrollVelocity != 0 && posMax == 2 && mScrollVelocity == mPreviousScrollVelocity) {
|
||||
if (fabs(endPos - startPos) < 0.5 || fabs(endPos - startPos) > 1.5) {
|
||||
(mScrollVelocity < 0) ? endPos -= 1 : endPos += 1;
|
||||
(mCursor == 0) ? mCursor = 1 : mCursor = 0;
|
||||
|
@ -323,7 +315,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
anim = new LambdaAnimation(
|
||||
[this, startExtrasFade, startPos, endPos, posMax](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
float f = Math::lerp(startPos, endPos, t * t * t + 1);
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if (f >= posMax)
|
||||
|
@ -343,16 +335,17 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
this->mExtrasCamOffset = endPos;
|
||||
|
||||
// Update the game count when the entire animation has been completed.
|
||||
if (mExtrasFadeOpacity == 1.0)
|
||||
if (mExtrasFadeOpacity == 1.0f)
|
||||
updateGameCount();
|
||||
}, 500);
|
||||
},
|
||||
500);
|
||||
}
|
||||
else if (transition_style == "slide") {
|
||||
mUpdatedGameCount = false;
|
||||
anim = new LambdaAnimation(
|
||||
[this, startPos, endPos, posMax](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
float f = Math::lerp(startPos, endPos, t * t * t + 1);
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if (f >= posMax)
|
||||
|
@ -363,19 +356,24 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
|
||||
// Hack to make the game count being updated in the middle of the animation.
|
||||
bool update = false;
|
||||
if (endPos == -1 && fabs(fabs(posMax) - fabs(mCamOffset)) > 0.5 && !mUpdatedGameCount)
|
||||
if (endPos == -1.0f && fabs(fabs(posMax) - fabs(mCamOffset)) > 0.5f &&
|
||||
!mUpdatedGameCount) {
|
||||
update = true;
|
||||
else if (endPos > posMax && fabs(endPos - posMax - fabs(mCamOffset)) <
|
||||
0.5 && !mUpdatedGameCount)
|
||||
}
|
||||
else if (endPos > posMax && fabs(endPos - posMax - fabs(mCamOffset)) < 0.5f &&
|
||||
!mUpdatedGameCount) {
|
||||
update = true;
|
||||
else if (fabs(fabs(endPos) - fabs(mCamOffset)) < 0.5 && !mUpdatedGameCount)
|
||||
}
|
||||
else if (fabs(fabs(endPos) - fabs(mCamOffset)) < 0.5f && !mUpdatedGameCount) {
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
mUpdatedGameCount = true;
|
||||
updateGameCount();
|
||||
}
|
||||
}, 500);
|
||||
},
|
||||
500);
|
||||
}
|
||||
else {
|
||||
// Instant.
|
||||
|
@ -383,7 +381,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
anim = new LambdaAnimation(
|
||||
[this, startPos, endPos, posMax](float t) {
|
||||
t -= 1;
|
||||
float f = Math::lerp(startPos, endPos, t*t*t + 1);
|
||||
float f = Math::lerp(startPos, endPos, t * t * t + 1);
|
||||
if (f < 0)
|
||||
f += posMax;
|
||||
if (f >= posMax)
|
||||
|
@ -391,7 +389,8 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
|||
|
||||
this->mCamOffset = f;
|
||||
this->mExtrasCamOffset = endPos;
|
||||
}, 500);
|
||||
},
|
||||
500);
|
||||
}
|
||||
|
||||
setAnimation(anim, 0, nullptr, false, 0);
|
||||
|
@ -460,13 +459,14 @@ void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
|||
if (!theme->hasView("system"))
|
||||
return;
|
||||
|
||||
const ThemeData::ThemeElement* carouselElem = theme->
|
||||
getElement("system", "systemcarousel", "carousel");
|
||||
const ThemeData::ThemeElement* carouselElem =
|
||||
theme->getElement("system", "systemcarousel", "carousel");
|
||||
|
||||
if (carouselElem)
|
||||
getCarouselFromTheme(carouselElem);
|
||||
|
||||
const ThemeData::ThemeElement* sysInfoElem = theme->
|
||||
getElement("system", "systemInfo", "text");
|
||||
const ThemeData::ThemeElement* sysInfoElem = theme->getElement("system", "systemInfo", "text");
|
||||
|
||||
if (sysInfoElem)
|
||||
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
|
||||
|
||||
|
@ -479,72 +479,80 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
// Background box behind logos.
|
||||
Transform4x4f carouselTrans = trans;
|
||||
carouselTrans.translate(Vector3f(mCarousel.pos.x(), mCarousel.pos.y(), 0.0));
|
||||
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1,
|
||||
mCarousel.origin.y() * mCarousel.size.y() * -1, 0.0f));
|
||||
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1.0f,
|
||||
mCarousel.origin.y() * mCarousel.size.y() * -1.0f, 0.0f));
|
||||
|
||||
Vector2f clipPos(carouselTrans.translation().x(), carouselTrans.translation().y());
|
||||
Renderer::pushClipRect(Vector2i(static_cast<int>(clipPos.x()), static_cast<int>(clipPos.y())),
|
||||
Renderer::pushClipRect(
|
||||
Vector2i(static_cast<int>(clipPos.x()), static_cast<int>(clipPos.y())),
|
||||
Vector2i(static_cast<int>(mCarousel.size.x()), static_cast<int>(mCarousel.size.y())));
|
||||
|
||||
Renderer::setMatrix(carouselTrans);
|
||||
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(),
|
||||
mCarousel.color, mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
||||
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(), mCarousel.color,
|
||||
mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
||||
|
||||
// Draw logos.
|
||||
// Note: logoSpacing will also include the size of the logo itself.
|
||||
Vector2f logoSpacing(0.0, 0.0);
|
||||
float xOff = 0.0;
|
||||
float yOff = 0.0;
|
||||
Vector2f logoSpacing(0.0f, 0.0f);
|
||||
float xOff = 0.0f;
|
||||
float yOff = 0.0f;
|
||||
|
||||
switch (mCarousel.type) {
|
||||
case VERTICAL_WHEEL:
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
||||
case VERTICAL_WHEEL: {
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
xOff = mCarousel.logoSize.x() / 10.f;
|
||||
xOff = mCarousel.logoSize.x() / 10.0f;
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
||||
else
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f;
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f;
|
||||
break;
|
||||
case VERTICAL:
|
||||
logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() *
|
||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y();
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
||||
}
|
||||
case VERTICAL: {
|
||||
logoSpacing[1] =
|
||||
((mCarousel.size.y() - (mCarousel.logoSize.y() * mCarousel.maxLogoCount)) /
|
||||
(mCarousel.maxLogoCount)) +
|
||||
mCarousel.logoSize.y();
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
|
||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||
xOff = mCarousel.logoSize.x() / 10.f;
|
||||
xOff = mCarousel.logoSize.x() / 10.0f;
|
||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
||||
else
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2;
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f;
|
||||
break;
|
||||
case HORIZONTAL_WHEEL:
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 -
|
||||
}
|
||||
case HORIZONTAL_WHEEL: {
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f -
|
||||
(mCamOffset * logoSpacing[1]);
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
yOff = mCarousel.logoSize.y() / 10;
|
||||
yOff = mCarousel.logoSize.y() / 10.0f;
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
||||
else
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2;
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f;
|
||||
break;
|
||||
case HORIZONTAL:
|
||||
default:
|
||||
logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() *
|
||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x();
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f -
|
||||
}
|
||||
case HORIZONTAL: {
|
||||
}
|
||||
default: {
|
||||
logoSpacing[0] =
|
||||
((mCarousel.size.x() - (mCarousel.logoSize.x() * mCarousel.maxLogoCount)) /
|
||||
(mCarousel.maxLogoCount)) +
|
||||
mCarousel.logoSize.x();
|
||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f -
|
||||
(mCamOffset * logoSpacing[0]);
|
||||
|
||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||
yOff = mCarousel.logoSize.y() / 10.f;
|
||||
yOff = mCarousel.logoSize.y() / 10.0f;
|
||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
||||
else
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f;
|
||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int center = static_cast<int>(mCamOffset);
|
||||
int logoCount = std::min(mCarousel.maxLogoCount, static_cast<int>(mEntries.size()));
|
||||
|
@ -558,9 +566,10 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
bufferRight = 0;
|
||||
}
|
||||
|
||||
for (int i = center - logoCount / 2 + bufferLeft;
|
||||
for (int i = center - logoCount / 2 + bufferLeft; // Line break.
|
||||
i <= center + logoCount / 2 + bufferRight; i++) {
|
||||
int index = i;
|
||||
|
||||
while (index < 0)
|
||||
index += static_cast<int>(mEntries.size());
|
||||
while (index >= static_cast<int>(mEntries.size()))
|
||||
|
@ -575,11 +584,11 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
|||
scale = std::min(mCarousel.logoScale, std::max(1.0f, scale));
|
||||
scale /= mCarousel.logoScale;
|
||||
|
||||
int opacity = static_cast<int>(std::round(0x80 + ((0xFF - 0x80) *
|
||||
(1.0f - fabs(distance)))));
|
||||
int opacity =
|
||||
static_cast<int>(std::round(0x80 + ((0xFF - 0x80) * (1.0f - fabs(distance)))));
|
||||
opacity = std::max(static_cast<int>(0x80), opacity);
|
||||
|
||||
const std::shared_ptr<GuiComponent> &comp = mEntries.at(index).data.logo;
|
||||
const std::shared_ptr<GuiComponent>& comp = mEntries.at(index).data.logo;
|
||||
if (mCarousel.type == VERTICAL_WHEEL || mCarousel.type == HORIZONTAL_WHEEL) {
|
||||
comp->setRotationDegrees(mCarousel.logoRotation * distance);
|
||||
comp->setRotationOrigin(mCarousel.logoRotationOrigin);
|
||||
|
@ -599,11 +608,11 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
|||
// Adding texture loading buffers depending on scrolling speed and status.
|
||||
int bufferIndex = getScrollingVelocity() + 1;
|
||||
|
||||
Renderer::pushClipRect(Vector2i::Zero(), Vector2i(static_cast<int>(mSize.x()),
|
||||
static_cast<int>(mSize.y())));
|
||||
Renderer::pushClipRect(Vector2i::Zero(),
|
||||
Vector2i(static_cast<int>(mSize.x()), static_cast<int>(mSize.y())));
|
||||
|
||||
for (int i = extrasCenter + logoBuffersLeft[bufferIndex]; i <= extrasCenter +
|
||||
logoBuffersRight[bufferIndex]; i++) {
|
||||
for (int i = extrasCenter + logoBuffersLeft[bufferIndex];
|
||||
i <= extrasCenter + logoBuffersRight[bufferIndex]; i++) {
|
||||
int index = i;
|
||||
while (index < 0)
|
||||
index += static_cast<int>(mEntries.size());
|
||||
|
@ -611,20 +620,20 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
|||
index -= static_cast<int>(mEntries.size());
|
||||
|
||||
// Only render selected system when not showing.
|
||||
if (mShowing || index == mCursor)
|
||||
{
|
||||
if (mShowing || index == mCursor) {
|
||||
Transform4x4f extrasTrans = trans;
|
||||
if (mCarousel.type == HORIZONTAL || mCarousel.type == HORIZONTAL_WHEEL)
|
||||
extrasTrans.translate(Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0));
|
||||
else
|
||||
extrasTrans.translate(Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0));
|
||||
|
||||
Renderer::pushClipRect(Vector2i(static_cast<int>(extrasTrans.translation()[0]),
|
||||
Renderer::pushClipRect(
|
||||
Vector2i(static_cast<int>(extrasTrans.translation()[0]),
|
||||
static_cast<int>(extrasTrans.translation()[1])),
|
||||
Vector2i(static_cast<int>(mSize.x()), static_cast<int>(mSize.y())));
|
||||
SystemViewData data = mEntries.at(index).data;
|
||||
for (unsigned int j = 0; j < data.backgroundExtras.size(); j++) {
|
||||
GuiComponent *extra = data.backgroundExtras[j];
|
||||
GuiComponent* extra = data.backgroundExtras[j];
|
||||
if (extra->getZIndex() >= lower && extra->getZIndex() < upper)
|
||||
extra->render(extrasTrans);
|
||||
}
|
||||
|
@ -637,7 +646,7 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
|||
|
||||
void SystemView::renderFade(const Transform4x4f& trans)
|
||||
{
|
||||
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mExtrasFadeOpacity * 255);
|
||||
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mExtrasFadeOpacity * 255.0f);
|
||||
Renderer::setMatrix(trans);
|
||||
Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor);
|
||||
}
|
||||
|
@ -658,13 +667,13 @@ void SystemView::getDefaultElements(void)
|
|||
mCarousel.colorEnd = 0xFFFFFFD8;
|
||||
mCarousel.colorGradientHorizontal = true;
|
||||
mCarousel.logoScale = 1.2f;
|
||||
mCarousel.logoRotation = 7.5;
|
||||
mCarousel.logoRotationOrigin.x() = -5;
|
||||
mCarousel.logoRotationOrigin.y() = 0.5;
|
||||
mCarousel.logoRotation = 7.5f;
|
||||
mCarousel.logoRotationOrigin.x() = -5.0f;
|
||||
mCarousel.logoRotationOrigin.y() = 0.5f;
|
||||
mCarousel.logoSize.x() = 0.25f * mSize.x();
|
||||
mCarousel.logoSize.y() = 0.155f * mSize.y();
|
||||
mCarousel.maxLogoCount = 3;
|
||||
mCarousel.zIndex = 40;
|
||||
mCarousel.zIndex = 40.0f;
|
||||
|
||||
// System info bar.
|
||||
mSystemInfo.setSize(mSize.x(), mSystemInfo.getFont()->getLetterHeight() * 2.2f);
|
||||
|
@ -702,7 +711,8 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
|||
if (elem->has("colorEnd"))
|
||||
mCarousel.colorEnd = elem->get<unsigned int>("colorEnd");
|
||||
if (elem->has("gradientType"))
|
||||
mCarousel.colorGradientHorizontal = !(elem->get<std::string>("gradientType").compare("horizontal"));
|
||||
mCarousel.colorGradientHorizontal =
|
||||
!(elem->get<std::string>("gradientType").compare("horizontal"));
|
||||
if (elem->has("logoScale"))
|
||||
mCarousel.logoScale = elem->get<float>("logoScale");
|
||||
if (elem->has("logoSize"))
|
||||
|
@ -728,13 +738,3 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
|||
mCarousel.logoAlignment = ALIGN_CENTER;
|
||||
}
|
||||
}
|
||||
|
||||
void SystemView::onShow()
|
||||
{
|
||||
mShowing = true;
|
||||
}
|
||||
|
||||
void SystemView::onHide()
|
||||
{
|
||||
mShowing = false;
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#ifndef ES_APP_VIEWS_SYSTEM_VIEW_H
|
||||
#define ES_APP_VIEWS_SYSTEM_VIEW_H
|
||||
|
||||
#include "GuiComponent.h"
|
||||
#include "Sound.h"
|
||||
#include "components/IList.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "resources/Font.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "Sound.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -55,8 +55,8 @@ public:
|
|||
SystemView(Window* window);
|
||||
~SystemView();
|
||||
|
||||
virtual void onShow() override;
|
||||
virtual void onHide() override;
|
||||
virtual void onShow() override { mShowing = true; }
|
||||
virtual void onHide() override { mShowing = false; }
|
||||
|
||||
void goToSystem(SystemData* system, bool animate);
|
||||
|
||||
|
@ -69,12 +69,14 @@ public:
|
|||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
virtual HelpStyle getHelpStyle() override;
|
||||
|
||||
CarouselType getCarouselType() { return mCarousel.type; };
|
||||
CarouselType getCarouselType() { return mCarousel.type; }
|
||||
|
||||
protected:
|
||||
void onCursorChanged(const CursorState& state) override;
|
||||
virtual void onScroll() override {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND); }
|
||||
virtual void onScroll() override
|
||||
{
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||
}
|
||||
|
||||
private:
|
||||
void populate();
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
#include "UIModeController.h"
|
||||
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Log.h"
|
||||
#include "SystemData.h"
|
||||
#include "Window.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
UIModeController* UIModeController::sInstance = nullptr;
|
||||
|
||||
|
@ -34,7 +34,8 @@ void UIModeController::deinit()
|
|||
}
|
||||
}
|
||||
|
||||
UIModeController::UIModeController() : mPassKeyCounter(0)
|
||||
UIModeController::UIModeController()
|
||||
: mPassKeyCounter(0)
|
||||
{
|
||||
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
|
||||
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
|
||||
|
@ -47,13 +48,12 @@ void UIModeController::monitorUIMode()
|
|||
if (uimode != mCurrentUIMode && !ViewController::get()->isCameraMoving()) {
|
||||
mCurrentUIMode = uimode;
|
||||
// Reset filters and sort gamelists (which will update the game counter).
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
||||
SystemData::sSystemVector.cend(); it++) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
(*it)->sortSystem(true);
|
||||
(*it)->getIndex()->resetFilters();
|
||||
if ((*it)->getThemeFolder() == "custom-collections") {
|
||||
for (FileData* customSystem :
|
||||
(*it)->getRootFolder()->getChildrenListToDisplay())
|
||||
for (FileData* customSystem : (*it)->getRootFolder()->getChildrenListToDisplay())
|
||||
customSystem->getSystem()->getIndex()->resetFilters();
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ bool UIModeController::listen(InputConfig* config, Input input)
|
|||
unlockUIMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -101,9 +102,9 @@ void UIModeController::unlockUIMode()
|
|||
|
||||
bool UIModeController::isUIModeFull()
|
||||
{
|
||||
return ((mCurrentUIMode == "full" || (isUIModeKid() &&
|
||||
Settings::getInstance()->getBool("EnableMenuKidMode")))
|
||||
&& !Settings::getInstance()->getBool("ForceKiosk"));
|
||||
return ((mCurrentUIMode == "full" ||
|
||||
(isUIModeKid() && Settings::getInstance()->getBool("EnableMenuKidMode"))) &&
|
||||
!Settings::getInstance()->getBool("ForceKiosk"));
|
||||
}
|
||||
|
||||
bool UIModeController::isUIModeKid()
|
||||
|
@ -139,19 +140,19 @@ std::string UIModeController::getFormattedPassKeyStr()
|
|||
symbolY = "X";
|
||||
}
|
||||
else if (controllerType == "ps4" || controllerType == "ps5") {
|
||||
#if defined(_MSC_VER) // MSVC compiler.
|
||||
// These symbols are far from perfect but you can at least understand what
|
||||
// they are supposed to depict.
|
||||
#if defined(_MSC_VER) // MSVC compiler.
|
||||
symbolA = Utils::String::wideStringToString(L"\uF00D"); // Cross.
|
||||
symbolB = Utils::String::wideStringToString(L"\uF111"); // Circle
|
||||
symbolX = Utils::String::wideStringToString(L"\uF04D"); // Square.
|
||||
symbolY = Utils::String::wideStringToString(L"\uF0D8"); // Triangle.
|
||||
#else
|
||||
#else
|
||||
symbolA = "\uF00D"; // Cross.
|
||||
symbolB = "\uF111"; // Circle
|
||||
symbolX = "\uF04D"; // Square.
|
||||
symbolY = "\uF0D8"; // Triangle.
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// Xbox controller.
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
bool isUIModeKid();
|
||||
bool isUIModeKiosk();
|
||||
|
||||
void setCurrentUIMode(const std::string& mode) { mCurrentUIMode = mode; };
|
||||
void setCurrentUIMode(const std::string& mode) { mCurrentUIMode = mode; }
|
||||
|
||||
private:
|
||||
UIModeController();
|
||||
|
@ -58,8 +58,9 @@ private:
|
|||
int mPassKeyCounter;
|
||||
|
||||
// These are Xbox button names, so they may be different in pracise on non-Xbox controllers.
|
||||
const std::vector<std::string> mInputVals =
|
||||
{ "up", "down", "left", "right", "a", "b", "x", "y" };
|
||||
const std::vector<std::string> mInputVals = {
|
||||
"up", "down", "left", "right", "a", "b", "x", "y"
|
||||
};
|
||||
};
|
||||
|
||||
#endif // ES_APP_VIEWS_UI_MODE_CONTROLLER_H
|
||||
|
|
|
@ -12,17 +12,6 @@
|
|||
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include "animations/Animation.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "animations/MoveCameraAnimation.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "guis/GuiMenu.h"
|
||||
#include "views/gamelist/DetailedGameListView.h"
|
||||
#include "views/gamelist/GridGameListView.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/gamelist/VideoGameListView.h"
|
||||
#include "views/SystemView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "InputManager.h"
|
||||
|
@ -32,8 +21,20 @@
|
|||
#include "SystemData.h"
|
||||
#include "SystemView.h"
|
||||
#include "Window.h"
|
||||
#include "animations/Animation.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "animations/MoveCameraAnimation.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "guis/GuiMenu.h"
|
||||
#include "views/SystemView.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/gamelist/DetailedGameListView.h"
|
||||
#include "views/gamelist/GridGameListView.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "views/gamelist/VideoGameListView.h"
|
||||
|
||||
ViewController* ViewController::sInstance = nullptr;
|
||||
|
||||
#if defined(_MSC_VER) // MSVC compiler.
|
||||
const std::string ViewController::FAVORITE_CHAR = Utils::String::wideStringToString(L"\uF005");
|
||||
const std::string ViewController::FOLDER_CHAR = Utils::String::wideStringToString(L"\uF07C");
|
||||
|
@ -60,21 +61,20 @@ void ViewController::init(Window* window)
|
|||
sInstance = new ViewController(window);
|
||||
}
|
||||
|
||||
ViewController::ViewController(
|
||||
Window* window)
|
||||
: GuiComponent(window),
|
||||
mCurrentView(nullptr),
|
||||
mPreviousView(nullptr),
|
||||
mSkipView(nullptr),
|
||||
mCamera(Transform4x4f::Identity()),
|
||||
mSystemViewTransition(false),
|
||||
mWrappedViews(false),
|
||||
mFadeOpacity(0),
|
||||
mCancelledTransition(false),
|
||||
mLockInput(false),
|
||||
mNextSystem(false),
|
||||
mGameToLaunch(nullptr),
|
||||
mNoGamesMessageBox(nullptr)
|
||||
ViewController::ViewController(Window* window)
|
||||
: GuiComponent(window)
|
||||
, mCurrentView(nullptr)
|
||||
, mPreviousView(nullptr)
|
||||
, mSkipView(nullptr)
|
||||
, mCamera(Transform4x4f::Identity())
|
||||
, mSystemViewTransition(false)
|
||||
, mWrappedViews(false)
|
||||
, mFadeOpacity(0)
|
||||
, mCancelledTransition(false)
|
||||
, mLockInput(false)
|
||||
, mNextSystem(false)
|
||||
, mGameToLaunch(nullptr)
|
||||
, mNoGamesMessageBox(nullptr)
|
||||
{
|
||||
mState.viewing = NOTHING;
|
||||
mState.viewstyle = AUTOMATIC;
|
||||
|
@ -89,27 +89,26 @@ ViewController::~ViewController()
|
|||
|
||||
void ViewController::invalidSystemsFileDialog()
|
||||
{
|
||||
std::string errorMessage =
|
||||
"COULDN'T PARSE THE SYSTEMS CONFIGURATION FILE.\n"
|
||||
std::string errorMessage = "COULDN'T PARSE THE SYSTEMS CONFIGURATION FILE.\n"
|
||||
"IF YOU HAVE A CUSTOMIZED es_systems.xml FILE, THEN\n"
|
||||
"SOMETHING IS LIKELY WRONG WITH YOUR XML SYNTAX.\n"
|
||||
"IF YOU DON'T HAVE A CUSTOM SYSTEMS FILE, THEN THE\n"
|
||||
"EMULATIONSTATION INSTALLATION IS BROKEN. SEE THE\n"
|
||||
"APPLICATION LOG FILE es_log.txt FOR ADDITIONAL INFO.";
|
||||
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||
errorMessage.c_str(),
|
||||
"QUIT", [] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, HelpStyle(), errorMessage.c_str(), "QUIT",
|
||||
[] {
|
||||
SDL_Event quit;
|
||||
quit.type = SDL_QUIT;
|
||||
SDL_PushEvent(&quit);
|
||||
}, "", nullptr, "", nullptr, true));
|
||||
},
|
||||
"", nullptr, "", nullptr, true));
|
||||
}
|
||||
|
||||
void ViewController::noGamesDialog()
|
||||
{
|
||||
mNoGamesErrorMessage =
|
||||
"NO GAME FILES WERE FOUND. EITHER PLACE YOUR GAMES IN\n"
|
||||
mNoGamesErrorMessage = "NO GAME FILES WERE FOUND. EITHER PLACE YOUR GAMES IN\n"
|
||||
"THE CURRENTLY CONFIGURED ROM DIRECTORY OR CHANGE\n"
|
||||
"ITS PATH USING THE BUTTON BELOW. OPTIONALLY THE ROM\n"
|
||||
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL\n"
|
||||
|
@ -117,80 +116,79 @@ void ViewController::noGamesDialog()
|
|||
"INFORMATION SUCH AS THE SUPPORTED FILE EXTENSIONS.\n"
|
||||
"THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n";
|
||||
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||
#else
|
||||
#else
|
||||
mRomDirectory = FileData::getROMDirectory();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mNoGamesMessageBox = new GuiMsgBox(mWindow, HelpStyle(), mNoGamesErrorMessage + mRomDirectory,
|
||||
"CHANGE ROM DIRECTORY", [this] {
|
||||
mNoGamesMessageBox = new GuiMsgBox(
|
||||
mWindow, HelpStyle(), mNoGamesErrorMessage + mRomDirectory, "CHANGE ROM DIRECTORY",
|
||||
[this] {
|
||||
std::string currentROMDirectory;
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
currentROMDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||
#else
|
||||
#else
|
||||
currentROMDirectory = FileData::getROMDirectory();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
||||
mWindow,
|
||||
HelpStyle(),
|
||||
"ENTER ROM DIRECTORY PATH",
|
||||
"Currently configured path:",
|
||||
currentROMDirectory,
|
||||
currentROMDirectory,
|
||||
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH",
|
||||
"Currently configured path:", currentROMDirectory, currentROMDirectory,
|
||||
[this](const std::string& newROMDirectory) {
|
||||
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
||||
Settings::getInstance()->saveFile();
|
||||
#if defined(_WIN64)
|
||||
#if defined(_WIN64)
|
||||
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||
#else
|
||||
#else
|
||||
mRomDirectory = FileData::getROMDirectory();
|
||||
#endif
|
||||
#endif
|
||||
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
||||
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
||||
"OK", nullptr, "", nullptr, "", nullptr, true));
|
||||
},
|
||||
false,
|
||||
"SAVE",
|
||||
"SAVE CHANGES?",
|
||||
"LOAD CURRENT",
|
||||
"LOAD CURRENTLY CONFIGURED VALUE",
|
||||
"CLEAR",
|
||||
"CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)",
|
||||
false));
|
||||
false, "SAVE", "SAVE CHANGES?", "LOAD CURRENT", "LOAD CURRENTLY CONFIGURED VALUE",
|
||||
"CLEAR", "CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)", false));
|
||||
},
|
||||
"CREATE DIRECTORIES", [this] {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||
"CREATE DIRECTORIES",
|
||||
[this] {
|
||||
mWindow->pushGui(new GuiMsgBox(
|
||||
mWindow, HelpStyle(),
|
||||
"THIS WILL CREATE DIRECTORIES FOR ALL THE\n"
|
||||
"GAME SYSTEMS DEFINED IN es_systems.xml\n\n"
|
||||
"THIS MAY CREATE A LOT OF FOLDERS SO IT'S\n"
|
||||
"ADVICED TO REMOVE THE ONES YOU DON'T NEED\n\n"
|
||||
"PROCEED?",
|
||||
"YES", [this] {
|
||||
"YES",
|
||||
[this] {
|
||||
if (!SystemData::createSystemDirectories()) {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||
"THE SYSTEM DIRECTORIES WERE SUCCESSFULLY\n"
|
||||
"GENERATED, EXIT THE APPLICATION AND PLACE\n"
|
||||
"YOUR GAMES IN THE NEWLY CREATED FOLDERS", "OK", nullptr,
|
||||
"", nullptr, "", nullptr, true));
|
||||
"YOUR GAMES IN THE NEWLY CREATED FOLDERS",
|
||||
"OK", nullptr, "", nullptr, "", nullptr,
|
||||
true));
|
||||
}
|
||||
else {
|
||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||
"ERROR CREATING THE SYSTEM DIRECTORIES,\n"
|
||||
"PERMISSION PROBLEMS OR DISK FULL?\n\n"
|
||||
"SEE THE LOG FILE FOR MORE DETAILS", "OK", nullptr,
|
||||
"", nullptr, "", nullptr, true));
|
||||
"SEE THE LOG FILE FOR MORE DETAILS",
|
||||
"OK", nullptr, "", nullptr, "", nullptr,
|
||||
true));
|
||||
}
|
||||
}, "NO", nullptr, "", nullptr, true));
|
||||
},
|
||||
"QUIT", [] {
|
||||
"NO", nullptr, "", nullptr, true));
|
||||
},
|
||||
"QUIT",
|
||||
[] {
|
||||
SDL_Event quit;
|
||||
quit.type = SDL_QUIT;
|
||||
SDL_PushEvent(&quit);
|
||||
}, true, false);
|
||||
},
|
||||
true, false);
|
||||
|
||||
mWindow->pushGui(mNoGamesMessageBox);
|
||||
}
|
||||
|
@ -205,7 +203,7 @@ void ViewController::goToStart()
|
|||
// If a specific system is requested, go directly to its game list.
|
||||
auto requestedSystem = Settings::getInstance()->getString("StartupSystem");
|
||||
if ("" != requestedSystem && "retropie" != requestedSystem) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); it++) {
|
||||
if ((*it)->getName() == requestedSystem) {
|
||||
goToGameList(*it);
|
||||
|
@ -396,8 +394,9 @@ void ViewController::goToGameList(SystemData* system)
|
|||
restoreViewPosition();
|
||||
|
||||
if (mPreviousView && Settings::getInstance()->getString("TransitionStyle") == "fade" &&
|
||||
isAnimationPlaying(0))
|
||||
isAnimationPlaying(0)) {
|
||||
mPreviousView->onHide();
|
||||
}
|
||||
|
||||
if (mPreviousView) {
|
||||
mSkipView = mPreviousView;
|
||||
|
@ -541,11 +540,13 @@ void ViewController::playViewTransition(bool instant)
|
|||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||
|
||||
if (instant || transition_style == "instant") {
|
||||
setAnimation(new LambdaAnimation([this, target](float /*t*/) {
|
||||
setAnimation(new LambdaAnimation(
|
||||
[this, target](float /*t*/) {
|
||||
this->mCamera.translation() = -target;
|
||||
if (mPreviousView)
|
||||
mPreviousView->onHide();
|
||||
}, 1));
|
||||
},
|
||||
1));
|
||||
updateHelpPrompts();
|
||||
}
|
||||
else if (transition_style == "fade") {
|
||||
|
@ -558,7 +559,7 @@ void ViewController::playViewTransition(bool instant)
|
|||
// Without this, a (much shorter) fade transition would still play as
|
||||
// finishedCallback is calling this function.
|
||||
if (!mCancelledTransition)
|
||||
mFadeOpacity = Math::lerp(0, 1, t);
|
||||
mFadeOpacity = Math::lerp(0.0f, 1.0f, t);
|
||||
};
|
||||
|
||||
auto fadeCallback = [this]() {
|
||||
|
@ -572,8 +573,8 @@ void ViewController::playViewTransition(bool instant)
|
|||
[this, fadeFunc, fadeCallback, target] {
|
||||
this->mCamera.translation() = -target;
|
||||
updateHelpPrompts();
|
||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION),
|
||||
FADE_WAIT, fadeCallback, true);
|
||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT,
|
||||
fadeCallback, true);
|
||||
});
|
||||
|
||||
// Fast-forward animation if we're partway faded.
|
||||
|
@ -646,8 +647,9 @@ void ViewController::launch(FileData* game)
|
|||
if (durationString == "disabled") {
|
||||
// If the game launch screen has been set as disabled, show a simple info popup
|
||||
// notification instead.
|
||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow, "LAUNCHING GAME '" +
|
||||
Utils::String::toUpper(game->metadata.get("name") + "'"), 10000);
|
||||
GuiInfoPopup* s = new GuiInfoPopup(
|
||||
mWindow, "LAUNCHING GAME '" + Utils::String::toUpper(game->metadata.get("name") + "'"),
|
||||
10000);
|
||||
mWindow->setInfoPopup(s);
|
||||
duration = 1700;
|
||||
}
|
||||
|
@ -670,16 +672,14 @@ void ViewController::launch(FileData* game)
|
|||
// This is just a dummy animation in order for the launch screen or notification popup
|
||||
// to be displayed briefly, and for the navigation sound playing to be able to complete.
|
||||
// During this time period, all user input is blocked.
|
||||
setAnimation(new LambdaAnimation([](float t){}, duration), 0, [this, game] {
|
||||
setAnimation(new LambdaAnimation([](float t) {}, duration), 0, [this, game] {
|
||||
game->launchGame(mWindow);
|
||||
// If the launch screen is disabled then this will do nothing.
|
||||
mWindow->closeLaunchScreen();
|
||||
onFileChanged(game, true);
|
||||
// This is a workaround so that any keys or button presses used for exiting the emulator
|
||||
// are not captured upon returning.
|
||||
setAnimation(new LambdaAnimation([](float t){}, 1), 0, [this] {
|
||||
mLockInput = false;
|
||||
});
|
||||
setAnimation(new LambdaAnimation([](float t) {}, 1), 0, [this] { mLockInput = false; });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -733,36 +733,39 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
|||
}
|
||||
|
||||
// Create the view.
|
||||
switch (selectedViewStyle)
|
||||
{
|
||||
case VIDEO:
|
||||
switch (selectedViewStyle) {
|
||||
case VIDEO: {
|
||||
view = std::shared_ptr<IGameListView>(
|
||||
new VideoGameListView(mWindow, system->getRootFolder()));
|
||||
mState.viewstyle = VIDEO;
|
||||
break;
|
||||
case DETAILED:
|
||||
}
|
||||
case DETAILED: {
|
||||
view = std::shared_ptr<IGameListView>(
|
||||
new DetailedGameListView(mWindow, system->getRootFolder()));
|
||||
mState.viewstyle = DETAILED;
|
||||
break;
|
||||
case GRID:
|
||||
}
|
||||
case GRID: {
|
||||
view = std::shared_ptr<IGameListView>(
|
||||
new GridGameListView(mWindow, system->getRootFolder()));
|
||||
mState.viewstyle = GRID;
|
||||
break;
|
||||
case BASIC:
|
||||
default:
|
||||
}
|
||||
case BASIC: {
|
||||
}
|
||||
default: {
|
||||
view = std::shared_ptr<IGameListView>(
|
||||
new BasicGameListView(mWindow, system->getRootFolder()));
|
||||
mState.viewstyle = BASIC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
view->setTheme(system->getTheme());
|
||||
|
||||
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
||||
int id = static_cast<int>(
|
||||
std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
||||
int id = static_cast<int>(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
||||
view->setPosition(id * static_cast<float>(Renderer::getScreenWidth()),
|
||||
static_cast<float>(Renderer::getScreenHeight() * 2));
|
||||
|
||||
|
@ -870,8 +873,8 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
|||
if (it->second == mCurrentView || (it->second == mPreviousView && isCameraMoving())) {
|
||||
// Clipping.
|
||||
Vector3f guiStart = it->second->getPosition();
|
||||
Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(),
|
||||
it->second->getSize().y(), 0);
|
||||
Vector3f guiEnd = it->second->getPosition() +
|
||||
Vector3f(it->second->getSize().x(), it->second->getSize().y(), 0);
|
||||
|
||||
if (guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() &&
|
||||
guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y())
|
||||
|
@ -895,13 +898,14 @@ void ViewController::preload()
|
|||
{
|
||||
unsigned int systemCount = static_cast<int>(SystemData::sSystemVector.size());
|
||||
|
||||
for (auto it = SystemData::sSystemVector.cbegin();
|
||||
it != SystemData::sSystemVector.cend(); it ++) {
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||
it++) {
|
||||
if (Settings::getInstance()->getBool("SplashScreen") &&
|
||||
Settings::getInstance()->getBool("SplashScreenProgress")) {
|
||||
mWindow->renderLoadingScreen("Loading '" + (*it)->getFullName() + "' (" +
|
||||
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it)+1) +
|
||||
"/" + std::to_string(systemCount) + ")");
|
||||
mWindow->renderLoadingScreen(
|
||||
"Loading '" + (*it)->getFullName() + "' (" +
|
||||
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it) + 1) + "/" +
|
||||
std::to_string(systemCount) + ")");
|
||||
}
|
||||
(*it)->getIndex()->resetFilters();
|
||||
getGameListView(*it);
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
#ifndef ES_APP_VIEWS_VIEW_CONTROLLER_H
|
||||
#define ES_APP_VIEWS_VIEW_CONTROLLER_H
|
||||
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "guis/GuiComplexTextEditPopup.h"
|
||||
#include "guis/GuiMsgBox.h"
|
||||
#include "renderers/Renderer.h"
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -46,8 +46,10 @@ public:
|
|||
// If a basic view detected a metadata change, it can request to recreate
|
||||
// the current gamelist view (as it may change to be detailed).
|
||||
void reloadGameListView(IGameListView* gamelist, bool reloadTheme = false);
|
||||
inline void reloadGameListView(SystemData* system, bool reloadTheme = false)
|
||||
{ reloadGameListView(getGameListView(system).get(), reloadTheme); }
|
||||
void reloadGameListView(SystemData* system, bool reloadTheme = false)
|
||||
{
|
||||
reloadGameListView(getGameListView(system).get(), reloadTheme);
|
||||
}
|
||||
// Reload everything with a theme.
|
||||
// Used when the "ThemeSet" setting changes.
|
||||
void reloadAll();
|
||||
|
@ -67,22 +69,26 @@ public:
|
|||
void stopScrolling();
|
||||
|
||||
void onFileChanged(FileData* file, bool reloadGameList);
|
||||
void triggerGameLaunch(FileData* game) { mGameToLaunch = game; mLockInput = true; };
|
||||
bool getGameLaunchTriggered() { return (mGameToLaunch != nullptr); };
|
||||
void triggerGameLaunch(FileData* game)
|
||||
{
|
||||
mGameToLaunch = game;
|
||||
mLockInput = true;
|
||||
};
|
||||
bool getGameLaunchTriggered() { return (mGameToLaunch != nullptr); }
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
|
||||
enum ViewMode {
|
||||
NOTHING,
|
||||
NOTHING, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
START_SCREEN,
|
||||
SYSTEM_SELECT,
|
||||
GAME_LIST
|
||||
};
|
||||
|
||||
enum GameListViewStyle {
|
||||
AUTOMATIC,
|
||||
AUTOMATIC, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||
BASIC,
|
||||
DETAILED,
|
||||
GRID,
|
||||
|
@ -93,7 +99,7 @@ public:
|
|||
ViewMode viewing;
|
||||
GameListViewStyle viewstyle;
|
||||
|
||||
inline SystemData* getSystem() const
|
||||
SystemData* getSystem() const
|
||||
{
|
||||
assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT);
|
||||
return system;
|
||||
|
@ -104,7 +110,7 @@ public:
|
|||
SystemData* system;
|
||||
};
|
||||
|
||||
inline const State& getState() const { return mState; }
|
||||
const State& getState() const { return mState; }
|
||||
|
||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
virtual HelpStyle getHelpStyle() override;
|
||||
|
@ -143,6 +149,9 @@ private:
|
|||
std::map<SystemData*, std::shared_ptr<IGameListView>> mGameListViews;
|
||||
std::shared_ptr<SystemView> mSystemListView;
|
||||
|
||||
FileData* mGameToLaunch;
|
||||
State mState;
|
||||
|
||||
Transform4x4f mCamera;
|
||||
bool mSystemViewTransition;
|
||||
bool mWrappedViews;
|
||||
|
@ -151,9 +160,6 @@ private:
|
|||
bool mCancelledTransition; // Needed only for the Fade transition style.
|
||||
bool mLockInput;
|
||||
bool mNextSystem;
|
||||
FileData* mGameToLaunch;
|
||||
|
||||
State mState;
|
||||
};
|
||||
|
||||
#endif // ES_APP_VIEWS_VIEW_CONTROLLER_H
|
||||
|
|
|
@ -8,15 +8,16 @@
|
|||
|
||||
#include "views/gamelist/BasicGameListView.h"
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
BasicGameListView::BasicGameListView(Window* window, FileData* root)
|
||||
: ISimpleGameListView(window, root), mList(window)
|
||||
: ISimpleGameListView(window, root)
|
||||
, mList(window)
|
||||
{
|
||||
mList.setSize(mSize.x(), mSize.y() * 0.8f);
|
||||
mList.setPosition(0, mSize.y() * 0.2f);
|
||||
|
@ -91,14 +92,14 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files, FileDa
|
|||
if ((*it)->getFavorite() && favoriteStar &&
|
||||
mRoot->getSystem()->getName() != "favorites") {
|
||||
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
||||
mList.add(inCollectionPrefix + "* " +
|
||||
(*it)->getName(), *it, ((*it)->getType() == FOLDER));
|
||||
mList.add(inCollectionPrefix + "* " + (*it)->getName(), *it,
|
||||
((*it)->getType() == FOLDER));
|
||||
else
|
||||
mList.add(inCollectionPrefix + ViewController::FAVORITE_CHAR + " " +
|
||||
(*it)->getName(), *it, ((*it)->getType() == FOLDER));
|
||||
(*it)->getName(),
|
||||
*it, ((*it)->getType() == FOLDER));
|
||||
}
|
||||
else if ((*it)->getType() == FOLDER &&
|
||||
mRoot->getSystem()->getName() != "collections") {
|
||||
else if ((*it)->getType() == FOLDER && mRoot->getSystem()->getName() != "collections") {
|
||||
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
||||
mList.add("# " + (*it)->getName(), *it, true);
|
||||
else
|
||||
|
@ -117,11 +118,6 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files, FileDa
|
|||
generateFirstLetterIndex(files);
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getCursor()
|
||||
{
|
||||
return mList.getSelected();
|
||||
}
|
||||
|
||||
void BasicGameListView::setCursor(FileData* cursor)
|
||||
{
|
||||
if (!mList.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
||||
|
@ -133,6 +129,7 @@ void BasicGameListView::setCursor(FileData* cursor)
|
|||
if (mCursorStack.empty() || mCursorStack.top() != cursor->getParent()) {
|
||||
std::stack<FileData*> tmp;
|
||||
FileData* ptr = cursor->getParent();
|
||||
|
||||
while (ptr && ptr != mRoot) {
|
||||
tmp.push(ptr);
|
||||
ptr = ptr->getParent();
|
||||
|
@ -148,31 +145,6 @@ void BasicGameListView::setCursor(FileData* cursor)
|
|||
}
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getNextEntry()
|
||||
{
|
||||
return mList.getNext();
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getPreviousEntry()
|
||||
{
|
||||
return mList.getPrevious();
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getFirstEntry()
|
||||
{
|
||||
return mList.getFirst();
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getLastEntry()
|
||||
{
|
||||
return mList.getLast();
|
||||
}
|
||||
|
||||
FileData* BasicGameListView::getFirstGameEntry()
|
||||
{
|
||||
return mFirstGameEntry;
|
||||
}
|
||||
|
||||
void BasicGameListView::addPlaceholder(FileData* firstEntry)
|
||||
{
|
||||
// Empty list, add a placeholder.
|
||||
|
@ -186,18 +158,9 @@ void BasicGameListView::addPlaceholder(FileData* firstEntry)
|
|||
mList.add(placeholder->getName(), placeholder, (placeholder->getType() == PLACEHOLDER));
|
||||
}
|
||||
|
||||
std::string BasicGameListView::getQuickSystemSelectRightButton()
|
||||
{
|
||||
return "right";
|
||||
}
|
||||
|
||||
std::string BasicGameListView::getQuickSystemSelectLeftButton()
|
||||
{
|
||||
return "left";
|
||||
}
|
||||
|
||||
void BasicGameListView::launch(FileData* game)
|
||||
{
|
||||
// This triggers ViewController to launch the game.
|
||||
ViewController::get()->triggerGameLaunch(game);
|
||||
}
|
||||
|
||||
|
@ -251,8 +214,8 @@ void BasicGameListView::removeMedia(FileData* game)
|
|||
|
||||
// If there are no media files left in the directory after the deletion, then remove
|
||||
// the directory too. Remove any empty parent directories as well.
|
||||
auto removeEmptyDirFunc = []
|
||||
(std::string systemMediaDir, std::string mediaType, std::string path) {
|
||||
auto removeEmptyDirFunc = [](std::string systemMediaDir, std::string mediaType,
|
||||
std::string path) {
|
||||
std::string parentPath = Utils::FileSystem::getParent(path);
|
||||
while (parentPath != systemMediaDir + "/" + mediaType) {
|
||||
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
||||
|
|
|
@ -21,30 +21,33 @@ public:
|
|||
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
||||
|
||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||
|
||||
virtual FileData* getCursor() override;
|
||||
virtual void setCursor(FileData* cursor) override;
|
||||
virtual FileData* getNextEntry() override;
|
||||
virtual FileData* getPreviousEntry() override;
|
||||
virtual FileData* getFirstEntry() override;
|
||||
virtual FileData* getLastEntry() override;
|
||||
virtual FileData* getFirstGameEntry() override;
|
||||
|
||||
virtual FileData* getCursor() override { return mList.getSelected(); }
|
||||
virtual FileData* getNextEntry() override { return mList.getNext(); }
|
||||
virtual FileData* getPreviousEntry() override { return mList.getPrevious(); }
|
||||
virtual FileData* getFirstEntry() override { return mList.getFirst(); }
|
||||
virtual FileData* getLastEntry() override { return mList.getLast(); }
|
||||
virtual FileData* getFirstGameEntry() override { return mFirstGameEntry; }
|
||||
|
||||
virtual std::string getName() const override { return "basic"; }
|
||||
|
||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
virtual void launch(FileData* game) override;
|
||||
|
||||
virtual bool isListScrolling() override { return mList.isScrolling(); };
|
||||
virtual void stopListScrolling() override { mList.stopScrolling(); };
|
||||
virtual bool isListScrolling() override { return mList.isScrolling(); }
|
||||
virtual void stopListScrolling() override { mList.stopScrolling(); }
|
||||
|
||||
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
||||
{ return mFirstLetterIndex; };
|
||||
{
|
||||
return mFirstLetterIndex;
|
||||
}
|
||||
|
||||
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
||||
virtual void launch(FileData* game) override;
|
||||
|
||||
protected:
|
||||
virtual std::string getQuickSystemSelectRightButton() override;
|
||||
virtual std::string getQuickSystemSelectLeftButton() override;
|
||||
virtual std::string getQuickSystemSelectRightButton() override { return "right"; }
|
||||
virtual std::string getQuickSystemSelectLeftButton() override { return "left"; }
|
||||
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
||||
virtual void remove(FileData* game, bool deleteFile) override;
|
||||
virtual void removeMedia(FileData* game) override;
|
||||
|
|
|
@ -8,45 +8,40 @@
|
|||
|
||||
#include "views/gamelist/DetailedGameListView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "SystemData.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#define FADE_IN_START_OPACITY 0.5f
|
||||
#define FADE_IN_TIME 650
|
||||
|
||||
DetailedGameListView::DetailedGameListView(
|
||||
Window* window,
|
||||
FileData* root)
|
||||
: BasicGameListView(window, root),
|
||||
mDescContainer(window),
|
||||
mDescription(window),
|
||||
mGamelistInfo(window),
|
||||
|
||||
mThumbnail(window),
|
||||
mMarquee(window),
|
||||
mImage(window),
|
||||
|
||||
mLblRating(window),
|
||||
mLblReleaseDate(window),
|
||||
mLblDeveloper(window),
|
||||
mLblPublisher(window),
|
||||
mLblGenre(window),
|
||||
mLblPlayers(window),
|
||||
mLblLastPlayed(window),
|
||||
mLblPlayCount(window),
|
||||
|
||||
mRating(window),
|
||||
mReleaseDate(window),
|
||||
mDeveloper(window),
|
||||
mPublisher(window),
|
||||
mGenre(window),
|
||||
mPlayers(window),
|
||||
mLastPlayed(window),
|
||||
mPlayCount(window),
|
||||
mName(window),
|
||||
mLastUpdated(nullptr)
|
||||
DetailedGameListView::DetailedGameListView(Window* window, FileData* root)
|
||||
: BasicGameListView(window, root)
|
||||
, mDescContainer(window)
|
||||
, mDescription(window)
|
||||
, mGamelistInfo(window)
|
||||
, mThumbnail(window)
|
||||
, mMarquee(window)
|
||||
, mImage(window)
|
||||
, mLblRating(window)
|
||||
, mLblReleaseDate(window)
|
||||
, mLblDeveloper(window)
|
||||
, mLblPublisher(window)
|
||||
, mLblGenre(window)
|
||||
, mLblPlayers(window)
|
||||
, mLblLastPlayed(window)
|
||||
, mLblPlayCount(window)
|
||||
, mRating(window)
|
||||
, mReleaseDate(window)
|
||||
, mDeveloper(window)
|
||||
, mPublisher(window)
|
||||
, mGenre(window)
|
||||
, mPlayers(window)
|
||||
, mLastPlayed(window)
|
||||
, mPlayCount(window)
|
||||
, mName(window)
|
||||
, mLastUpdated(nullptr)
|
||||
{
|
||||
const float padding = 0.01f;
|
||||
|
||||
|
@ -114,8 +109,8 @@ DetailedGameListView::DetailedGameListView(
|
|||
addChild(&mName);
|
||||
|
||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
mDescContainer.setAutoScroll(true);
|
||||
mDescContainer.setDefaultZIndex(40);
|
||||
addChild(&mDescContainer);
|
||||
|
@ -150,10 +145,10 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
|||
initMDLabels();
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
assert(labels.size() == 8);
|
||||
std::vector<std::string> lblElements = {
|
||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
||||
};
|
||||
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||
"md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players",
|
||||
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < labels.size(); i++)
|
||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||
|
@ -161,10 +156,9 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
|||
initMDValues();
|
||||
std::vector<GuiComponent*> values = getMDValues();
|
||||
assert(values.size() == 8);
|
||||
std::vector<std::string> valElements = {
|
||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
||||
};
|
||||
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||
"md_publisher", "md_genre", "md_players",
|
||||
"md_lastplayed", "md_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < values.size(); i++)
|
||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||
|
@ -172,7 +166,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
|||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||
mDescription.applyTheme(theme, getName(), "md_description",
|
||||
mDescription.applyTheme(
|
||||
theme, getName(), "md_description",
|
||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||
|
||||
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
||||
|
@ -205,7 +200,7 @@ void DetailedGameListView::initMDLabels()
|
|||
}
|
||||
else {
|
||||
// Work from the last component.
|
||||
GuiComponent* lc = components[i-1];
|
||||
GuiComponent* lc = components[i - 1];
|
||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||
}
|
||||
|
||||
|
@ -232,13 +227,13 @@ void DetailedGameListView::initMDValues()
|
|||
|
||||
float bottom = 0.0f;
|
||||
|
||||
const float colSize = (mSize.x() * 0.48f) / 2;
|
||||
const float colSize = (mSize.x() * 0.48f) / 2.0f;
|
||||
for (unsigned int i = 0; i < labels.size(); i++) {
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2;
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2.0f;
|
||||
values[i]->setPosition(labels[i]->getPosition() +
|
||||
Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||
values[i]->setDefaultZIndex(40);
|
||||
values[i]->setDefaultZIndex(40.0f);
|
||||
|
||||
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
||||
|
||||
|
@ -247,8 +242,8 @@ void DetailedGameListView::initMDValues()
|
|||
}
|
||||
|
||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
}
|
||||
|
||||
void DetailedGameListView::updateInfoPanel()
|
||||
|
@ -334,8 +329,8 @@ void DetailedGameListView::updateInfoPanel()
|
|||
// the first of these so that we can display its game media.
|
||||
if (file->getSystem()->isCustomCollection() &&
|
||||
file->getPath() == file->getSystem()->getName()) {
|
||||
mRandomGame = CollectionSystemsManager::get()->
|
||||
updateCollectionFolderMetadata(file->getSystem());
|
||||
mRandomGame =
|
||||
CollectionSystemsManager::get()->updateCollectionFolderMetadata(file->getSystem());
|
||||
if (mRandomGame) {
|
||||
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
||||
mMarquee.setImage(mRandomGame->getMarqueePath());
|
||||
|
@ -371,16 +366,16 @@ void DetailedGameListView::updateInfoPanel()
|
|||
else
|
||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||
std::to_string(mFilteredGameCount) + " + " +
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||
" / " + std::to_string(mGameCount);
|
||||
}
|
||||
else {
|
||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
||||
std::to_string(mGameCount);
|
||||
gamelistInfoString +=
|
||||
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||
if (!(file->getSystem()->isCollection() &&
|
||||
file->getSystem()->getFullName() == "favorites"))
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " "
|
||||
+ std::to_string(mFavoritesGameCount);
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||
std::to_string(mFavoritesGameCount);
|
||||
}
|
||||
|
||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||
|
@ -390,8 +385,8 @@ void DetailedGameListView::updateInfoPanel()
|
|||
|
||||
// Fade in the game image.
|
||||
auto func = [this](float t) {
|
||||
mImage.setOpacity(static_cast<unsigned char>(Math::lerp(
|
||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
mImage.setOpacity(static_cast<unsigned char>(
|
||||
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
};
|
||||
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||
|
||||
|
|
|
@ -8,48 +8,42 @@
|
|||
|
||||
#include "views/gamelist/GridGameListView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "Settings.h"
|
||||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#define FADE_IN_START_OPACITY 0.5f
|
||||
#define FADE_IN_TIME 650
|
||||
|
||||
GridGameListView::GridGameListView(
|
||||
Window* window,
|
||||
FileData* root)
|
||||
: ISimpleGameListView(window, root),
|
||||
|
||||
mGrid(window),
|
||||
mMarquee(window),
|
||||
mImage(window),
|
||||
|
||||
mDescContainer(window),
|
||||
mDescription(window),
|
||||
mGamelistInfo(window),
|
||||
|
||||
mLblRating(window),
|
||||
mLblReleaseDate(window),
|
||||
mLblDeveloper(window),
|
||||
mLblPublisher(window),
|
||||
mLblGenre(window),
|
||||
mLblPlayers(window),
|
||||
mLblLastPlayed(window),
|
||||
mLblPlayCount(window),
|
||||
|
||||
mRating(window),
|
||||
mReleaseDate(window),
|
||||
mDeveloper(window),
|
||||
mPublisher(window),
|
||||
mGenre(window),
|
||||
mPlayers(window),
|
||||
mLastPlayed(window),
|
||||
mPlayCount(window),
|
||||
mName(window)
|
||||
GridGameListView::GridGameListView(Window* window, FileData* root)
|
||||
: ISimpleGameListView(window, root)
|
||||
, mGrid(window)
|
||||
, mMarquee(window)
|
||||
, mImage(window)
|
||||
, mDescContainer(window)
|
||||
, mDescription(window)
|
||||
, mGamelistInfo(window)
|
||||
, mLblRating(window)
|
||||
, mLblReleaseDate(window)
|
||||
, mLblDeveloper(window)
|
||||
, mLblPublisher(window)
|
||||
, mLblGenre(window)
|
||||
, mLblPlayers(window)
|
||||
, mLblLastPlayed(window)
|
||||
, mLblPlayCount(window)
|
||||
, mRating(window)
|
||||
, mReleaseDate(window)
|
||||
, mDeveloper(window)
|
||||
, mPublisher(window)
|
||||
, mGenre(window)
|
||||
, mPlayers(window)
|
||||
, mLastPlayed(window)
|
||||
, mPlayCount(window)
|
||||
, mName(window)
|
||||
{
|
||||
const float padding = 0.01f;
|
||||
|
||||
|
@ -95,8 +89,8 @@ GridGameListView::GridGameListView(
|
|||
addChild(&mName);
|
||||
|
||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
mDescContainer.setAutoScroll(true);
|
||||
mDescContainer.setDefaultZIndex(40);
|
||||
addChild(&mDescContainer);
|
||||
|
@ -107,7 +101,7 @@ GridGameListView::GridGameListView(
|
|||
|
||||
mMarquee.setOrigin(0.5f, 0.5f);
|
||||
mMarquee.setPosition(mSize.x() * 0.25f, mSize.y() * 0.10f);
|
||||
mMarquee.setMaxSize(mSize.x() * (0.5f - 2 * padding), mSize.y() * 0.18f);
|
||||
mMarquee.setMaxSize(mSize.x() * (0.5f - 2.0f * padding), mSize.y() * 0.18f);
|
||||
mMarquee.setDefaultZIndex(35);
|
||||
mMarquee.setVisible(false);
|
||||
addChild(&mMarquee);
|
||||
|
@ -130,10 +124,6 @@ GridGameListView::GridGameListView(
|
|||
updateInfoPanel();
|
||||
}
|
||||
|
||||
GridGameListView::~GridGameListView()
|
||||
{
|
||||
}
|
||||
|
||||
void GridGameListView::onFileChanged(FileData* file, bool reloadGameList)
|
||||
{
|
||||
if (reloadGameList) {
|
||||
|
@ -145,11 +135,6 @@ void GridGameListView::onFileChanged(FileData* file, bool reloadGameList)
|
|||
ISimpleGameListView::onFileChanged(file, reloadGameList);
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getCursor()
|
||||
{
|
||||
return mGrid.getSelected();
|
||||
}
|
||||
|
||||
void GridGameListView::setCursor(FileData* cursor)
|
||||
{
|
||||
if (!mGrid.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
||||
|
@ -176,47 +161,11 @@ void GridGameListView::setCursor(FileData* cursor)
|
|||
}
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getNextEntry()
|
||||
{
|
||||
return mGrid.getNext();;
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getPreviousEntry()
|
||||
{
|
||||
return mGrid.getPrevious();
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getFirstEntry()
|
||||
{
|
||||
return mGrid.getFirst();;
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getLastEntry()
|
||||
{
|
||||
return mGrid.getLast();
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getFirstGameEntry()
|
||||
{
|
||||
return firstGameEntry;
|
||||
}
|
||||
|
||||
std::string GridGameListView::getQuickSystemSelectRightButton()
|
||||
{
|
||||
return "rightshoulder";
|
||||
}
|
||||
|
||||
std::string GridGameListView::getQuickSystemSelectLeftButton()
|
||||
{
|
||||
return "leftshoulder";
|
||||
}
|
||||
|
||||
bool GridGameListView::input(InputConfig* config, Input input)
|
||||
{
|
||||
if (input.value == 0 && (config->isMappedLike("left", input) ||
|
||||
config->isMappedLike("right", input) ||
|
||||
(config->isMappedLike("up", input)) ||
|
||||
(config->isMappedLike("down", input)) ))
|
||||
if (input.value == 0 &&
|
||||
(config->isMappedLike("left", input) || config->isMappedLike("right", input) ||
|
||||
(config->isMappedLike("up", input)) || (config->isMappedLike("down", input))))
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
||||
|
||||
if (input.value != 0 && config->isMappedLike("righttrigger", input)) {
|
||||
|
@ -295,10 +244,10 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
initMDLabels();
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
assert(labels.size() == 8);
|
||||
std::vector<std::string> lblElements = {
|
||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
||||
};
|
||||
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||
"md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players",
|
||||
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < labels.size(); i++)
|
||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||
|
@ -306,10 +255,9 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
initMDValues();
|
||||
std::vector<GuiComponent*> values = getMDValues();
|
||||
assert(values.size() == 8);
|
||||
std::vector<std::string> valElements = {
|
||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
||||
};
|
||||
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||
"md_publisher", "md_genre", "md_players",
|
||||
"md_lastplayed", "md_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < values.size(); i++)
|
||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||
|
@ -317,7 +265,8 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||
mDescription.applyTheme(theme, getName(), "md_description",
|
||||
mDescription.applyTheme(
|
||||
theme, getName(), "md_description",
|
||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||
|
||||
// Repopulate list in case a new theme is displaying a different image.
|
||||
|
@ -336,6 +285,12 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
sortChildren();
|
||||
}
|
||||
|
||||
void GridGameListView::onShow()
|
||||
{
|
||||
GuiComponent::onShow();
|
||||
updateInfoPanel();
|
||||
}
|
||||
|
||||
void GridGameListView::initMDLabels()
|
||||
{
|
||||
std::vector<TextComponent*> components = getMDLabels();
|
||||
|
@ -356,7 +311,7 @@ void GridGameListView::initMDLabels()
|
|||
}
|
||||
else {
|
||||
// Work from the last component.
|
||||
GuiComponent* lc = components[i-1];
|
||||
GuiComponent* lc = components[i - 1];
|
||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||
}
|
||||
|
||||
|
@ -383,9 +338,9 @@ void GridGameListView::initMDValues()
|
|||
|
||||
float bottom = 0.0f;
|
||||
|
||||
const float colSize = (mSize.x() * 0.48f) / 2;
|
||||
const float colSize = (mSize.x() * 0.48f) / 2.0f;
|
||||
for (unsigned int i = 0; i < labels.size(); i++) {
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2;
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2.0f;
|
||||
values[i]->setPosition(labels[i]->getPosition() +
|
||||
Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||
|
@ -397,8 +352,8 @@ void GridGameListView::initMDValues()
|
|||
}
|
||||
|
||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
}
|
||||
|
||||
void GridGameListView::updateInfoPanel()
|
||||
|
@ -465,17 +420,18 @@ void GridGameListView::updateInfoPanel()
|
|||
|
||||
if (mIsFiltered) {
|
||||
if (mFilteredGameCountAll == mFilteredGameCount)
|
||||
gamelistInfoString += ViewController::FILTER_CHAR + " "
|
||||
+ std::to_string(mFilteredGameCount) + " / " + std::to_string(mGameCount);
|
||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||
std::to_string(mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
else
|
||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||
std::to_string(mFilteredGameCount) + " + " +
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||
" / " + std::to_string(mGameCount);
|
||||
}
|
||||
else {
|
||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
||||
std::to_string(mGameCount);
|
||||
gamelistInfoString +=
|
||||
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||
if (!(file->getSystem()->isCollection() &&
|
||||
file->getSystem()->getFullName() == "favorites"))
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||
|
@ -489,8 +445,8 @@ void GridGameListView::updateInfoPanel()
|
|||
|
||||
// Fade in the game image.
|
||||
auto func = [this](float t) {
|
||||
mImage.setOpacity(static_cast<unsigned char>(Math::lerp(
|
||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
mImage.setOpacity(static_cast<unsigned char>(
|
||||
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
};
|
||||
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||
|
||||
|
@ -560,6 +516,7 @@ void GridGameListView::addPlaceholder(FileData* firstEntry)
|
|||
|
||||
void GridGameListView::launch(FileData* game)
|
||||
{
|
||||
// This triggers ViewController to launch the game.
|
||||
ViewController::get()->triggerGameLaunch(game);
|
||||
}
|
||||
|
||||
|
@ -605,8 +562,8 @@ void GridGameListView::removeMedia(FileData* game)
|
|||
|
||||
// If there are no media files left in the directory after the deletion, then remove
|
||||
// the directory too. Remove any empty parent directories as well.
|
||||
auto removeEmptyDirFunc = []
|
||||
(std::string systemMediaDir, std::string mediaType, std::string path) {
|
||||
auto removeEmptyDirFunc = [](std::string systemMediaDir, std::string mediaType,
|
||||
std::string path) {
|
||||
std::string parentPath = Utils::FileSystem::getParent(path);
|
||||
while (parentPath != systemMediaDir + "/" + mediaType) {
|
||||
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
||||
|
@ -724,13 +681,11 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
|||
|
||||
if (!UIModeController::getInstance()->isUIModeKid())
|
||||
prompts.push_back(HelpPrompt("back", "options"));
|
||||
if (mRoot->getSystem()->isGameSystem() &&
|
||||
Settings::getInstance()->getBool("RandomAddButton"))
|
||||
if (mRoot->getSystem()->isGameSystem() && Settings::getInstance()->getBool("RandomAddButton"))
|
||||
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
||||
|
||||
if (mRoot->getSystem()->isGameSystem() &&
|
||||
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
|
||||
!mCursorStack.empty()) &&
|
||||
(mRoot->getSystem()->getThemeFolder() != "custom-collections" || !mCursorStack.empty()) &&
|
||||
!UIModeController::getInstance()->isUIModeKid() &&
|
||||
!UIModeController::getInstance()->isUIModeKiosk() &&
|
||||
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
||||
|
@ -749,11 +704,6 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
|||
|
||||
void GridGameListView::update(int deltaTime)
|
||||
{
|
||||
// Update.
|
||||
ISimpleGameListView::update(deltaTime);
|
||||
}
|
||||
|
||||
void GridGameListView::onShow()
|
||||
{
|
||||
GuiComponent::onShow();
|
||||
updateInfoPanel();
|
||||
}
|
||||
|
|
|
@ -20,48 +20,50 @@ class GridGameListView : public ISimpleGameListView
|
|||
{
|
||||
public:
|
||||
GridGameListView(Window* window, FileData* root);
|
||||
virtual ~GridGameListView();
|
||||
virtual ~GridGameListView() {}
|
||||
|
||||
// Called when a FileData* is added, has its metadata changed, or is removed.
|
||||
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
||||
|
||||
virtual void onShow() override;
|
||||
|
||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||
|
||||
virtual FileData* getCursor() override;
|
||||
virtual void setCursor(FileData* cursor) override;
|
||||
virtual FileData* getNextEntry() override;
|
||||
virtual FileData* getPreviousEntry() override;
|
||||
virtual FileData* getFirstEntry() override;
|
||||
virtual FileData* getLastEntry() override;
|
||||
virtual FileData* getFirstGameEntry() override;
|
||||
|
||||
virtual bool input(InputConfig* config, Input input) override;
|
||||
virtual FileData* getCursor() override { return mGrid.getSelected(); }
|
||||
virtual FileData* getNextEntry() override { return mGrid.getNext(); }
|
||||
virtual FileData* getPreviousEntry() override { return mGrid.getPrevious(); }
|
||||
virtual FileData* getFirstEntry() override { return mGrid.getFirst(); }
|
||||
virtual FileData* getLastEntry() override { return mGrid.getLast(); }
|
||||
virtual FileData* getFirstGameEntry() override { return firstGameEntry; }
|
||||
|
||||
virtual std::string getName() const override { return "grid"; }
|
||||
|
||||
virtual bool input(InputConfig* config, Input input) override;
|
||||
|
||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
virtual void launch(FileData* game) override;
|
||||
|
||||
virtual bool isListScrolling() override { return mGrid.isScrolling(); };
|
||||
virtual bool isListScrolling() override { return mGrid.isScrolling(); }
|
||||
virtual void stopListScrolling() override
|
||||
{
|
||||
mGrid.stopAllAnimations();
|
||||
mGrid.stopScrolling();
|
||||
};
|
||||
}
|
||||
|
||||
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
||||
{ return mFirstLetterIndex; };
|
||||
{
|
||||
return mFirstLetterIndex;
|
||||
}
|
||||
|
||||
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
||||
|
||||
protected:
|
||||
virtual void update(int deltaTime) override;
|
||||
virtual std::string getQuickSystemSelectRightButton() override;
|
||||
virtual std::string getQuickSystemSelectLeftButton() override;
|
||||
virtual std::string getQuickSystemSelectRightButton() override { return "rightshoulder"; }
|
||||
virtual std::string getQuickSystemSelectLeftButton() override { return "leftshoulder"; }
|
||||
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
||||
virtual void remove(FileData* game, bool deleteFile) override;
|
||||
virtual void removeMedia(FileData* game) override;
|
||||
virtual void update(int deltaTime) override;
|
||||
|
||||
ImageGridComponent<FileData*> mGrid;
|
||||
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
|
||||
|
|
|
@ -8,17 +8,31 @@
|
|||
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include "guis/GuiGamelistOptions.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "Sound.h"
|
||||
#include "Window.h"
|
||||
#include "guis/GuiGamelistOptions.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
IGameListView::IGameListView(Window* window, FileData* root)
|
||||
: GuiComponent(window)
|
||||
, mRoot(root)
|
||||
{
|
||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||
static_cast<float>(Renderer::getScreenHeight()));
|
||||
}
|
||||
|
||||
void IGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
mTheme = theme;
|
||||
onThemeChanged(theme);
|
||||
}
|
||||
|
||||
bool IGameListView::input(InputConfig* config, Input input)
|
||||
{
|
||||
// Select button opens GuiGamelistOptions.
|
||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||
if (!UIModeController::getInstance()->isUIModeKid() && // Line break.
|
||||
config->isMappedTo("back", input) && input.value) {
|
||||
ViewController::get()->cancelViewTransitions();
|
||||
stopListScrolling();
|
||||
|
@ -29,8 +43,8 @@ bool IGameListView::input(InputConfig* config, Input input)
|
|||
// Ctrl-R reloads the view when debugging.
|
||||
else if (Settings::getInstance()->getBool("Debug") &&
|
||||
config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) &&
|
||||
input.id == SDLK_r && input.value != 0) {
|
||||
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) && input.id == SDLK_r &&
|
||||
input.value != 0) {
|
||||
LOG(LogDebug) << "IGameListView::input(): Reloading view";
|
||||
ViewController::get()->reloadGameListView(this, true);
|
||||
return true;
|
||||
|
@ -39,12 +53,6 @@ bool IGameListView::input(InputConfig* config, Input input)
|
|||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
void IGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
mTheme = theme;
|
||||
onThemeChanged(theme);
|
||||
}
|
||||
|
||||
HelpStyle IGameListView::getHelpStyle()
|
||||
{
|
||||
HelpStyle style;
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#ifndef ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H
|
||||
#define ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H
|
||||
|
||||
#include "renderers/Renderer.h"
|
||||
#include "FileData.h"
|
||||
#include "GuiComponent.h"
|
||||
#include "renderers/Renderer.h"
|
||||
|
||||
class ThemeData;
|
||||
class Window;
|
||||
|
@ -20,12 +20,7 @@ class Window;
|
|||
class IGameListView : public GuiComponent
|
||||
{
|
||||
public:
|
||||
IGameListView(Window* window, FileData* root) : GuiComponent(window), mRoot(root)
|
||||
{
|
||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||
static_cast<float>(Renderer::getScreenHeight()));
|
||||
}
|
||||
|
||||
IGameListView(Window* window, FileData* root);
|
||||
virtual ~IGameListView() {}
|
||||
|
||||
// Called when a FileData* is added, has its metadata changed, or is removed.
|
||||
|
@ -35,7 +30,7 @@ public:
|
|||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) = 0;
|
||||
|
||||
void setTheme(const std::shared_ptr<ThemeData>& theme);
|
||||
inline const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
||||
const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
||||
|
||||
virtual FileData* getCursor() = 0;
|
||||
virtual void setCursor(FileData*) = 0;
|
||||
|
|
|
@ -8,26 +8,24 @@
|
|||
|
||||
#include "views/gamelist/ISimpleGameListView.h"
|
||||
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "FileFilterIndex.h"
|
||||
#include "Settings.h"
|
||||
#include "Sound.h"
|
||||
#include "SystemData.h"
|
||||
#include "guis/GuiInfoPopup.h"
|
||||
#include "utils/StringUtil.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
ISimpleGameListView::ISimpleGameListView(
|
||||
Window* window,
|
||||
FileData* root)
|
||||
: IGameListView(window, root),
|
||||
mHeaderText(window),
|
||||
mHeaderImage(window),
|
||||
mBackground(window),
|
||||
mRandomGame(nullptr)
|
||||
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root)
|
||||
: IGameListView(window, root)
|
||||
, mHeaderText(window)
|
||||
, mHeaderImage(window)
|
||||
, mBackground(window)
|
||||
, mRandomGame(nullptr)
|
||||
{
|
||||
mHeaderText.setText("Logo Text");
|
||||
mHeaderText.setSize(mSize.x(), 0);
|
||||
|
@ -124,7 +122,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
std::vector<FileData*> listEntries = cursor->getChildrenListToDisplay();
|
||||
// Check if there is an entry in the cursor stack history matching any entry
|
||||
// in the currect folder. If so, select that entry.
|
||||
for (auto it = mCursorStackHistory.begin();
|
||||
for (auto it = mCursorStackHistory.begin(); // Line break.
|
||||
it != mCursorStackHistory.end(); it++) {
|
||||
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
||||
listEntries.end()) {
|
||||
|
@ -185,8 +183,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
}
|
||||
else if (config->isMappedTo("x", input) &&
|
||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||
mCursorStack.empty() && ViewController::get()->getState().viewing ==
|
||||
ViewController::GAME_LIST) {
|
||||
mCursorStack.empty() &&
|
||||
ViewController::get()->getState().viewing == ViewController::GAME_LIST) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
||||
// Jump to the randomly selected game.
|
||||
if (mRandomGame) {
|
||||
|
@ -239,9 +237,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
}
|
||||
else if (config->isMappedTo("y", input) &&
|
||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||
!CollectionSystemsManager::get()->isEditing() &&
|
||||
mCursorStack.empty() && ViewController::get()->getState().viewing ==
|
||||
ViewController::GAME_LIST) {
|
||||
!CollectionSystemsManager::get()->isEditing() && mCursorStack.empty() &&
|
||||
ViewController::get()->getState().viewing == ViewController::GAME_LIST) {
|
||||
// Jump to the randomly selected game.
|
||||
if (mRandomGame) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(SELECTSOUND);
|
||||
|
@ -249,8 +246,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
// remove it so we don't get multiple entries.
|
||||
std::vector<FileData*> listEntries =
|
||||
mRandomGame->getSystem()->getRootFolder()->getChildrenListToDisplay();
|
||||
for (auto it = mCursorStackHistory.begin();
|
||||
it != mCursorStackHistory.end(); it++) {
|
||||
for (auto it = mCursorStackHistory.begin(); it != mCursorStackHistory.end(); it++) {
|
||||
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
||||
listEntries.end()) {
|
||||
mCursorStackHistory.erase(it);
|
||||
|
@ -278,8 +274,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
getCursor()->getParent()->getPath() == "collections") {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||
GuiInfoPopup* s;
|
||||
s = new GuiInfoPopup(mWindow,
|
||||
"CAN'T ADD CUSTOM COLLECTIONS TO CUSTOM COLLECTIONS", 4000);
|
||||
s = new GuiInfoPopup(mWindow, "CAN'T ADD CUSTOM COLLECTIONS TO CUSTOM COLLECTIONS",
|
||||
4000);
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
// Notify the user if attempting to add a placeholder to a custom collection.
|
||||
|
@ -287,8 +283,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
mRoot->getSystem()->isGameSystem() && getCursor()->getType() == PLACEHOLDER) {
|
||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||
GuiInfoPopup* s;
|
||||
s = new GuiInfoPopup(mWindow,
|
||||
"CAN'T ADD PLACEHOLDERS TO CUSTOM COLLECTIONS", 4000);
|
||||
s = new GuiInfoPopup(mWindow, "CAN'T ADD PLACEHOLDERS TO CUSTOM COLLECTIONS", 4000);
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
else if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER &&
|
||||
|
@ -317,8 +312,9 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
else
|
||||
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||
|
||||
if (favoritesSorting && static_cast<std::string>(
|
||||
mRoot->getSystem()->getName()) != "recent" && !isEditing) {
|
||||
if (favoritesSorting &&
|
||||
static_cast<std::string>(mRoot->getSystem()->getName()) != "recent" &&
|
||||
!isEditing) {
|
||||
FileData* entryToSelect;
|
||||
// Add favorite flag.
|
||||
if (!getCursor()->getFavorite()) {
|
||||
|
@ -348,8 +344,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
// For all other scenarios try to select the next entry, and if it doesn't
|
||||
// exist, select the previous entry.
|
||||
else {
|
||||
entryToSelect = getCursor() != getNextEntry() ?
|
||||
getNextEntry() : getPreviousEntry();
|
||||
entryToSelect =
|
||||
getCursor() != getNextEntry() ? getNextEntry() : getPreviousEntry();
|
||||
}
|
||||
}
|
||||
// Remove favorite flag.
|
||||
|
@ -367,7 +363,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
else if (foldersOnTop &&
|
||||
getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
||||
entryToSelect = getPreviousEntry()->getType() == FOLDER ?
|
||||
getCursor() : getPreviousEntry();
|
||||
getCursor() :
|
||||
getPreviousEntry();
|
||||
}
|
||||
// If we are on the favorite marking boundary, select the previous entry.
|
||||
else if (getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
||||
|
@ -376,8 +373,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
// For all other scenarios try to select the next entry, and if it doesn't
|
||||
// exist, select the previous entry.
|
||||
else {
|
||||
entryToSelect = getCursor() != getNextEntry() ?
|
||||
getNextEntry() : getPreviousEntry();
|
||||
entryToSelect =
|
||||
getCursor() != getNextEntry() ? getNextEntry() : getPreviousEntry();
|
||||
}
|
||||
|
||||
// If we removed the last favorite marking, set the flag to jump to the
|
||||
|
@ -399,22 +396,30 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
if (entryToUpdate->getType() == FOLDER) {
|
||||
GuiInfoPopup* s;
|
||||
if (isEditing) {
|
||||
s = new GuiInfoPopup(mWindow,
|
||||
"CAN'T ADD FOLDERS TO CUSTOM COLLECTIONS", 4000);
|
||||
s = new GuiInfoPopup(mWindow, "CAN'T ADD FOLDERS TO CUSTOM COLLECTIONS",
|
||||
4000);
|
||||
}
|
||||
else {
|
||||
MetaDataList* md = &entryToUpdate->getSourceFileData()->metadata;
|
||||
if (md->get("favorite") == "false") {
|
||||
md->set("favorite", "true");
|
||||
s = new GuiInfoPopup(mWindow, "MARKED FOLDER '" +
|
||||
s = new GuiInfoPopup(
|
||||
mWindow,
|
||||
"MARKED FOLDER '" +
|
||||
Utils::String::toUpper(Utils::String::removeParenthesis(
|
||||
entryToUpdate->getName())) + "' AS FAVORITE", 4000);
|
||||
entryToUpdate->getName())) +
|
||||
"' AS FAVORITE",
|
||||
4000);
|
||||
}
|
||||
else {
|
||||
md->set("favorite", "false");
|
||||
s = new GuiInfoPopup(mWindow, "REMOVED FAVORITE MARKING FOR FOLDER '" +
|
||||
s = new GuiInfoPopup(
|
||||
mWindow,
|
||||
"REMOVED FAVORITE MARKING FOR FOLDER '" +
|
||||
Utils::String::toUpper(Utils::String::removeParenthesis(
|
||||
entryToUpdate->getName())) + "'", 4000);
|
||||
entryToUpdate->getName())) +
|
||||
"'",
|
||||
4000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,16 +436,19 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
// was unmarked. We couldn't do this earlier as we didn't have the list
|
||||
// sorted yet.
|
||||
if (removedLastFavorite) {
|
||||
ViewController::get()->getGameListView(entryToUpdate->
|
||||
getSystem())->setCursor(ViewController::get()->
|
||||
getGameListView(entryToUpdate->getSystem())->getFirstEntry());
|
||||
ViewController::get()
|
||||
->getGameListView(entryToUpdate->getSystem())
|
||||
->setCursor(ViewController::get()
|
||||
->getGameListView(entryToUpdate->getSystem())
|
||||
->getFirstEntry());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (isEditing && entryToUpdate->metadata.get("nogamecount") == "true") {
|
||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow,
|
||||
"CAN'T ADD ENTRIES THAT ARE NOT COUNTED "
|
||||
"AS GAMES TO CUSTOM COLLECTIONS", 4000);
|
||||
"AS GAMES TO CUSTOM COLLECTIONS",
|
||||
4000);
|
||||
mWindow->setInfoPopup(s);
|
||||
}
|
||||
else if (CollectionSystemsManager::get()->toggleGameInCollection(entryToUpdate)) {
|
||||
|
@ -451,9 +459,11 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
// Jump to the first entry in the gamelist if the last favorite was unmarked.
|
||||
if (foldersOnTop && removedLastFavorite &&
|
||||
!entryToUpdate->getSystem()->isCustomCollection()) {
|
||||
ViewController::get()->getGameListView(entryToUpdate->getSystem())->
|
||||
setCursor(ViewController::get()->getGameListView(entryToUpdate->
|
||||
getSystem())->getFirstGameEntry());
|
||||
ViewController::get()
|
||||
->getGameListView(entryToUpdate->getSystem())
|
||||
->setCursor(ViewController::get()
|
||||
->getGameListView(entryToUpdate->getSystem())
|
||||
->getFirstGameEntry());
|
||||
}
|
||||
else if (removedLastFavorite &&
|
||||
!entryToUpdate->getSystem()->isCustomCollection()) {
|
||||
|
@ -469,8 +479,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
|||
for (auto it = SystemData::sSystemVector.begin();
|
||||
it != SystemData::sSystemVector.end(); it++) {
|
||||
ViewController::get()->getGameListView((*it))->onFileChanged(
|
||||
ViewController::get()->getGameListView((*it))->
|
||||
getCursor(), false);
|
||||
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -511,13 +520,13 @@ void ISimpleGameListView::generateGamelistInfo(FileData* cursor, FileData* first
|
|||
|
||||
if (idx->isFiltered()) {
|
||||
mIsFiltered = true;
|
||||
mFilteredGameCount = static_cast<unsigned int>(rootFolder->
|
||||
getFilesRecursive(GAME, true, false).size());
|
||||
mFilteredGameCount =
|
||||
static_cast<unsigned int>(rootFolder->getFilesRecursive(GAME, true, false).size());
|
||||
// Also count the games that are set to not be counted as games, as the filter may
|
||||
// apply to such entries as well and this will be indicated with a separate '+ XX'
|
||||
// in the GamelistInfo field.
|
||||
mFilteredGameCountAll = static_cast<unsigned int>(rootFolder->
|
||||
getFilesRecursive(GAME, true, true).size());
|
||||
mFilteredGameCountAll =
|
||||
static_cast<unsigned int>(rootFolder->getFilesRecursive(GAME, true, true).size());
|
||||
}
|
||||
|
||||
if (firstEntry->getParent() && firstEntry->getParent()->getType() == FOLDER)
|
||||
|
@ -553,17 +562,21 @@ void ISimpleGameListView::generateFirstLetterIndex(const std::vector<FileData*>&
|
|||
|
||||
// Build the index.
|
||||
for (auto it = files.begin(); it != files.end(); it++) {
|
||||
if ((*it)->getType() == FOLDER && (*it)->getFavorite() &&
|
||||
favoritesSorting && !onlyFavorites)
|
||||
if ((*it)->getType() == FOLDER && (*it)->getFavorite() && favoritesSorting &&
|
||||
!onlyFavorites) {
|
||||
hasFavorites = true;
|
||||
else if ((*it)->getType() == FOLDER && foldersOnTop && !onlyFolders)
|
||||
}
|
||||
else if ((*it)->getType() == FOLDER && foldersOnTop && !onlyFolders) {
|
||||
hasFolders = true;
|
||||
else if ((*it)->getType() == GAME && (*it)->getFavorite() &&
|
||||
favoritesSorting && !onlyFavorites)
|
||||
}
|
||||
else if ((*it)->getType() == GAME && (*it)->getFavorite() && favoritesSorting &&
|
||||
!onlyFavorites) {
|
||||
hasFavorites = true;
|
||||
else
|
||||
}
|
||||
else {
|
||||
mFirstLetterIndex.push_back(Utils::String::getFirstCharacter((*it)->getSortName()));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort and make each entry unique.
|
||||
std::sort(mFirstLetterIndex.begin(), mFirstLetterIndex.end());
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#ifndef ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H
|
||||
#define ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H
|
||||
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
#include "components/ImageComponent.h"
|
||||
#include "components/TextComponent.h"
|
||||
#include "views/gamelist/IGameListView.h"
|
||||
|
||||
#include <stack>
|
||||
|
||||
|
@ -39,9 +39,13 @@ public:
|
|||
// These functions are used to retain the folder cursor history, for instance
|
||||
// during a view reload. The calling function stores the history temporarily.
|
||||
void copyCursorHistory(std::vector<FileData*>& cursorHistory) override
|
||||
{ cursorHistory = mCursorStackHistory; };
|
||||
{
|
||||
cursorHistory = mCursorStackHistory;
|
||||
};
|
||||
void populateCursorHistory(std::vector<FileData*>& cursorHistory) override
|
||||
{ mCursorStackHistory = cursorHistory; };
|
||||
{
|
||||
mCursorStackHistory = cursorHistory;
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual std::string getQuickSystemSelectRightButton() = 0;
|
||||
|
|
|
@ -16,67 +16,62 @@
|
|||
#if defined(BUILD_VLC_PLAYER)
|
||||
#include "components/VideoVlcComponent.h"
|
||||
#endif
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "AudioManager.h"
|
||||
#include "CollectionSystemsManager.h"
|
||||
#include "SystemData.h"
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "views/ViewController.h"
|
||||
|
||||
#define FADE_IN_START_OPACITY 0.5f
|
||||
#define FADE_IN_TIME 650
|
||||
|
||||
VideoGameListView::VideoGameListView(
|
||||
Window* window,
|
||||
FileData* root)
|
||||
: BasicGameListView(window, root),
|
||||
mDescContainer(window),
|
||||
mDescription(window),
|
||||
mGamelistInfo(window),
|
||||
|
||||
mThumbnail(window),
|
||||
mMarquee(window),
|
||||
mImage(window),
|
||||
mVideo(nullptr),
|
||||
mVideoPlaying(false),
|
||||
|
||||
mLblRating(window),
|
||||
mLblReleaseDate(window),
|
||||
mLblDeveloper(window),
|
||||
mLblPublisher(window),
|
||||
mLblGenre(window),
|
||||
mLblPlayers(window),
|
||||
mLblLastPlayed(window),
|
||||
mLblPlayCount(window),
|
||||
|
||||
mRating(window),
|
||||
mReleaseDate(window),
|
||||
mDeveloper(window),
|
||||
mPublisher(window),
|
||||
mGenre(window),
|
||||
mPlayers(window),
|
||||
mLastPlayed(window),
|
||||
mPlayCount(window),
|
||||
mName(window),
|
||||
mLastUpdated(nullptr)
|
||||
VideoGameListView::VideoGameListView(Window* window, FileData* root)
|
||||
: BasicGameListView(window, root)
|
||||
, mDescContainer(window)
|
||||
, mDescription(window)
|
||||
, mGamelistInfo(window)
|
||||
, mThumbnail(window)
|
||||
, mMarquee(window)
|
||||
, mImage(window)
|
||||
, mVideo(nullptr)
|
||||
, mVideoPlaying(false)
|
||||
, mLblRating(window)
|
||||
, mLblReleaseDate(window)
|
||||
, mLblDeveloper(window)
|
||||
, mLblPublisher(window)
|
||||
, mLblGenre(window)
|
||||
, mLblPlayers(window)
|
||||
, mLblLastPlayed(window)
|
||||
, mLblPlayCount(window)
|
||||
, mRating(window)
|
||||
, mReleaseDate(window)
|
||||
, mDeveloper(window)
|
||||
, mPublisher(window)
|
||||
, mGenre(window)
|
||||
, mPlayers(window)
|
||||
, mLastPlayed(window)
|
||||
, mPlayCount(window)
|
||||
, mName(window)
|
||||
, mLastUpdated(nullptr)
|
||||
{
|
||||
const float padding = 0.01f;
|
||||
|
||||
// Create the correct type of video window.
|
||||
#if defined(_RPI_)
|
||||
// Create the correct type of video window.
|
||||
#if defined(_RPI_)
|
||||
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
||||
mVideo = new VideoOmxComponent(window);
|
||||
else if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||
mVideo = new VideoVlcComponent(window);
|
||||
else
|
||||
mVideo = new VideoFFmpegComponent(window);
|
||||
#elif defined(BUILD_VLC_PLAYER)
|
||||
#elif defined(BUILD_VLC_PLAYER)
|
||||
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||
mVideo = new VideoVlcComponent(window);
|
||||
else
|
||||
mVideo = new VideoFFmpegComponent(window);
|
||||
#else
|
||||
#else
|
||||
mVideo = new VideoFFmpegComponent(window);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
||||
mList.setSize(mSize.x() * (0.50f - padding), mList.getSize().y());
|
||||
|
@ -87,21 +82,21 @@ VideoGameListView::VideoGameListView(
|
|||
mThumbnail.setOrigin(0.5f, 0.5f);
|
||||
mThumbnail.setPosition(2.0f, 2.0f);
|
||||
mThumbnail.setVisible(false);
|
||||
mThumbnail.setMaxSize(mSize.x() * (0.25f - 2 * padding), mSize.y() * 0.10f);
|
||||
mThumbnail.setMaxSize(mSize.x() * (0.25f - 2.0f * padding), mSize.y() * 0.10f);
|
||||
mThumbnail.setDefaultZIndex(35);
|
||||
addChild(&mThumbnail);
|
||||
|
||||
// Marquee.
|
||||
mMarquee.setOrigin(0.5f, 0.5f);
|
||||
mMarquee.setPosition(mSize.x() * 0.25f, mSize.y() * 0.10f);
|
||||
mMarquee.setMaxSize(mSize.x() * (0.5f - 2 * padding), mSize.y() * 0.18f);
|
||||
mMarquee.setMaxSize(mSize.x() * (0.5f - 2.0f * padding), mSize.y() * 0.18f);
|
||||
mMarquee.setDefaultZIndex(35);
|
||||
addChild(&mMarquee);
|
||||
|
||||
// Video.
|
||||
mVideo->setOrigin(0.5f, 0.5f);
|
||||
mVideo->setPosition(mSize.x() * 0.25f, mSize.y() * 0.4f);
|
||||
mVideo->setSize(mSize.x() * (0.5f - 2 * padding), mSize.y() * 0.4f);
|
||||
mVideo->setSize(mSize.x() * (0.5f - 2.0f * padding), mSize.y() * 0.4f);
|
||||
mVideo->setDefaultZIndex(30);
|
||||
addChild(mVideo);
|
||||
|
||||
|
@ -140,8 +135,8 @@ VideoGameListView::VideoGameListView(
|
|||
addChild(&mName);
|
||||
|
||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
mDescContainer.setAutoScroll(true);
|
||||
mDescContainer.setDefaultZIndex(40);
|
||||
addChild(&mDescContainer);
|
||||
|
@ -160,10 +155,7 @@ VideoGameListView::VideoGameListView(
|
|||
initMDValues();
|
||||
}
|
||||
|
||||
VideoGameListView::~VideoGameListView()
|
||||
{
|
||||
delete mVideo;
|
||||
}
|
||||
VideoGameListView::~VideoGameListView() { delete mVideo; }
|
||||
|
||||
void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
|
@ -177,16 +169,17 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
mImage.applyTheme(theme, getName(), "md_image",
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||
mVideo->applyTheme(theme, getName(), "md_video",
|
||||
POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
|
||||
POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION |
|
||||
VISIBLE);
|
||||
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||
|
||||
initMDLabels();
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
assert(labels.size() == 8);
|
||||
std::vector<std::string> lblElements = {
|
||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
||||
};
|
||||
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||
"md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players",
|
||||
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < labels.size(); i++)
|
||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||
|
@ -194,10 +187,9 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
initMDValues();
|
||||
std::vector<GuiComponent*> values = getMDValues();
|
||||
assert(values.size() == 8);
|
||||
std::vector<std::string> valElements = {
|
||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
||||
};
|
||||
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||
"md_publisher", "md_genre", "md_players",
|
||||
"md_lastplayed", "md_playcount" };
|
||||
|
||||
for (unsigned int i = 0; i < values.size(); i++)
|
||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||
|
@ -205,7 +197,8 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||
mDescription.applyTheme(theme, getName(), "md_description",
|
||||
mDescription.applyTheme(
|
||||
theme, getName(), "md_description",
|
||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||
|
||||
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
||||
|
@ -238,7 +231,7 @@ void VideoGameListView::initMDLabels()
|
|||
}
|
||||
else {
|
||||
// Work from the last component.
|
||||
GuiComponent* lc = components[i-1];
|
||||
GuiComponent* lc = components[i - 1];
|
||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||
}
|
||||
|
||||
|
@ -265,11 +258,11 @@ void VideoGameListView::initMDValues()
|
|||
|
||||
float bottom = 0.0f;
|
||||
|
||||
const float colSize = (mSize.x() * 0.48f) / 2;
|
||||
const float colSize = (mSize.x() * 0.48f) / 2.0f;
|
||||
for (unsigned int i = 0; i < labels.size(); i++) {
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2;
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2.0f;
|
||||
values[i]->setPosition(labels[i]->getPosition() +
|
||||
Vector3f(labels[i]->getSize().x(),heightDiff, 0));
|
||||
Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||
values[i]->setDefaultZIndex(40);
|
||||
|
||||
|
@ -280,8 +273,8 @@ void VideoGameListView::initMDValues()
|
|||
}
|
||||
|
||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||
mDescContainer.getPosition().y());
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||
mSize.y() - mDescContainer.getPosition().y());
|
||||
}
|
||||
|
||||
void VideoGameListView::updateInfoPanel()
|
||||
|
@ -368,8 +361,8 @@ void VideoGameListView::updateInfoPanel()
|
|||
// the first of these so that we can display its game media.
|
||||
if (file->getSystem()->isCustomCollection() &&
|
||||
file->getPath() == file->getSystem()->getName()) {
|
||||
mRandomGame = CollectionSystemsManager::get()->
|
||||
updateCollectionFolderMetadata(file->getSystem());
|
||||
mRandomGame =
|
||||
CollectionSystemsManager::get()->updateCollectionFolderMetadata(file->getSystem());
|
||||
if (mRandomGame) {
|
||||
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
||||
mMarquee.setImage(mRandomGame->getMarqueePath());
|
||||
|
@ -398,7 +391,6 @@ void VideoGameListView::updateInfoPanel()
|
|||
mVideo->setImage(file->getImagePath());
|
||||
mVideo->onHide();
|
||||
|
||||
|
||||
if (!mVideo->setVideo(file->getVideoPath()))
|
||||
mVideo->setDefaultVideo();
|
||||
}
|
||||
|
@ -423,16 +415,16 @@ void VideoGameListView::updateInfoPanel()
|
|||
else
|
||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||
std::to_string(mFilteredGameCount) + " + " +
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
||||
std::to_string(mGameCount);
|
||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||
" / " + std::to_string(mGameCount);
|
||||
}
|
||||
else {
|
||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
||||
std::to_string(mGameCount);
|
||||
gamelistInfoString +=
|
||||
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||
if (!(file->getSystem()->isCollection() &&
|
||||
file->getSystem()->getFullName() == "favorites"))
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " "
|
||||
+ std::to_string(mFavoritesGameCount);
|
||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||
std::to_string(mFavoritesGameCount);
|
||||
}
|
||||
|
||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||
|
@ -442,8 +434,8 @@ void VideoGameListView::updateInfoPanel()
|
|||
|
||||
// Fade in the game image.
|
||||
auto func = [this](float t) {
|
||||
mVideo->setOpacity(static_cast<unsigned char>(Math::lerp(
|
||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
mVideo->setOpacity(static_cast<unsigned char>(
|
||||
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||
};
|
||||
mVideo->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||
|
||||
|
@ -498,10 +490,7 @@ void VideoGameListView::updateInfoPanel()
|
|||
}
|
||||
}
|
||||
|
||||
void VideoGameListView::launch(FileData* game)
|
||||
{
|
||||
ViewController::get()->triggerGameLaunch(game);
|
||||
}
|
||||
void VideoGameListView::launch(FileData* game) { ViewController::get()->triggerGameLaunch(game); }
|
||||
|
||||
std::vector<TextComponent*> VideoGameListView::getMDLabels()
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue