mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-02-18 04:45:39 +00:00
Formatted the es-app source tree using clang-format.
This commit is contained in:
parent
745cf6ff92
commit
af5e32e121
File diff suppressed because it is too large
Load diff
|
@ -34,7 +34,7 @@ class Window;
|
||||||
struct SystemEnvironmentData;
|
struct SystemEnvironmentData;
|
||||||
|
|
||||||
enum CollectionSystemType {
|
enum CollectionSystemType {
|
||||||
AUTO_ALL_GAMES,
|
AUTO_ALL_GAMES, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
AUTO_LAST_PLAYED,
|
AUTO_LAST_PLAYED,
|
||||||
AUTO_FAVORITES,
|
AUTO_FAVORITES,
|
||||||
CUSTOM_COLLECTION
|
CUSTOM_COLLECTION
|
||||||
|
@ -115,13 +115,17 @@ public:
|
||||||
// Repopulate the collection, which is basically a forced update of its complete content.
|
// Repopulate the collection, which is basically a forced update of its complete content.
|
||||||
void repopulateCollection(SystemData* sysData);
|
void repopulateCollection(SystemData* sysData);
|
||||||
|
|
||||||
inline std::map<std::string, CollectionSystemData, stringComparator>
|
std::map<std::string, CollectionSystemData, stringComparator> getAutoCollectionSystems()
|
||||||
getAutoCollectionSystems() { return mAutoCollectionSystemsData; };
|
{
|
||||||
inline std::map<std::string, CollectionSystemData, stringComparator>
|
return mAutoCollectionSystemsData;
|
||||||
getCustomCollectionSystems() { return mCustomCollectionSystemsData; };
|
}
|
||||||
inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; };
|
std::map<std::string, CollectionSystemData, stringComparator> getCustomCollectionSystems()
|
||||||
inline bool isEditing() { return mIsEditingCustom; };
|
{
|
||||||
inline std::string getEditingCollection() { return mEditingCollection; };
|
return mCustomCollectionSystemsData;
|
||||||
|
}
|
||||||
|
SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; }
|
||||||
|
bool isEditing() { return mIsEditingCustom; }
|
||||||
|
std::string getEditingCollection() { return mEditingCollection; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CollectionSystemsManager* sInstance;
|
static CollectionSystemsManager* sInstance;
|
||||||
|
@ -143,7 +147,9 @@ private:
|
||||||
SystemData* getAllGamesCollection();
|
SystemData* getAllGamesCollection();
|
||||||
// Create a new empty collection system based on the name and declaration.
|
// Create a new empty collection system based on the name and declaration.
|
||||||
SystemData* createNewCollectionEntry(std::string name,
|
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.
|
// Populate an automatic collection system.
|
||||||
void populateAutoCollection(CollectionSystemData* sysData);
|
void populateAutoCollection(CollectionSystemData* sysData);
|
||||||
// Populate a custom collection system.
|
// Populate a custom collection system.
|
||||||
|
@ -151,8 +157,8 @@ private:
|
||||||
|
|
||||||
// Functions to handle System View removal and insertion of collections:
|
// Functions to handle System View removal and insertion of collections:
|
||||||
void removeCollectionsFromDisplayedSystems();
|
void removeCollectionsFromDisplayedSystems();
|
||||||
void addEnabledCollectionsToDisplayedSystems(std::map<std::string,
|
void addEnabledCollectionsToDisplayedSystems(
|
||||||
CollectionSystemData, stringComparator>* colSystemData);
|
std::map<std::string, CollectionSystemData, stringComparator>* colSystemData);
|
||||||
|
|
||||||
// Auxiliary functions:
|
// Auxiliary functions:
|
||||||
std::vector<std::string> getSystemsFromConfig();
|
std::vector<std::string> getSystemsFromConfig();
|
||||||
|
|
|
@ -10,14 +10,16 @@
|
||||||
|
|
||||||
// These numbers and strings need to be manually updated for a new version.
|
// 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.
|
// 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_MAJOR 1
|
||||||
#define PROGRAM_VERSION_MINOR 0
|
#define PROGRAM_VERSION_MINOR 1
|
||||||
#define PROGRAM_VERSION_MAINTENANCE 0
|
#define PROGRAM_VERSION_MAINTENANCE 0
|
||||||
|
// clang-format on
|
||||||
#define PROGRAM_VERSION_STRING "1.1.0-rc-dev"
|
#define PROGRAM_VERSION_STRING "1.1.0-rc-dev"
|
||||||
|
|
||||||
#define PROGRAM_BUILT_STRING __DATE__ " - " __TIME__
|
#define PROGRAM_BUILT_STRING __DATE__ " - " __TIME__
|
||||||
|
|
||||||
#define RESOURCE_VERSION_STRING "1,1,0\0"
|
#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
|
#endif // ES_APP_EMULATION_STATION_H
|
||||||
|
|
|
@ -10,12 +10,6 @@
|
||||||
|
|
||||||
#include "FileData.h"
|
#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 "AudioManager.h"
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
|
@ -26,33 +20,37 @@
|
||||||
#include "Scripting.h"
|
#include "Scripting.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Window.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>
|
#include <assert.h>
|
||||||
|
|
||||||
FileData::FileData(
|
FileData::FileData(FileType type,
|
||||||
FileType type,
|
const std::string& path,
|
||||||
const std::string& path,
|
SystemEnvironmentData* envData,
|
||||||
SystemEnvironmentData* envData,
|
SystemData* system)
|
||||||
SystemData* system)
|
: mType(type)
|
||||||
: mType(type),
|
, mPath(path)
|
||||||
mPath(path),
|
, mSystem(system)
|
||||||
mSystem(system),
|
, mEnvData(envData)
|
||||||
mEnvData(envData),
|
, mSourceFileData(nullptr)
|
||||||
mSourceFileData(nullptr),
|
, mParent(nullptr)
|
||||||
mParent(nullptr),
|
, mOnlyFolders(false)
|
||||||
mOnlyFolders(false),
|
, mDeletionFlag(false)
|
||||||
mDeletionFlag(false),
|
// Metadata is set in the constructor.
|
||||||
// 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).
|
// Metadata needs at least a name field (since that's what getName() will return).
|
||||||
if (metadata.get("name").empty()) {
|
if (metadata.get("name").empty()) {
|
||||||
if ((system->hasPlatformId(PlatformIds::ARCADE) ||
|
if ((system->hasPlatformId(PlatformIds::ARCADE) ||
|
||||||
system->hasPlatformId(PlatformIds::SNK_NEO_GEO)) &&
|
system->hasPlatformId(PlatformIds::SNK_NEO_GEO)) &&
|
||||||
metadata.getType() != FOLDER_METADATA) {
|
metadata.getType() != FOLDER_METADATA) {
|
||||||
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
||||||
metadata.set("name",
|
metadata.set("name", MameNames::getInstance()->getCleanName(getCleanName()));
|
||||||
MameNames::getInstance()->getCleanName(getCleanName()));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (metadata.getType() == FOLDER_METADATA && Utils::FileSystem::isHidden(mPath)) {
|
if (metadata.getType() == FOLDER_METADATA && Utils::FileSystem::isHidden(mPath)) {
|
||||||
|
@ -89,6 +87,7 @@ std::string FileData::getCleanName() const
|
||||||
|
|
||||||
const std::string& FileData::getName()
|
const std::string& FileData::getName()
|
||||||
{
|
{
|
||||||
|
// Return metadata name.
|
||||||
return metadata.get("name");
|
return metadata.get("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,14 +143,13 @@ const std::vector<FileData*> FileData::getChildrenRecursive() const
|
||||||
{
|
{
|
||||||
std::vector<FileData*> childrenRecursive;
|
std::vector<FileData*> childrenRecursive;
|
||||||
|
|
||||||
for (auto it = mChildrenByFilename.cbegin();
|
for (auto it = mChildrenByFilename.cbegin(); it != mChildrenByFilename.cend(); it++) {
|
||||||
it != mChildrenByFilename.cend(); it++) {
|
|
||||||
childrenRecursive.push_back((*it).second);
|
childrenRecursive.push_back((*it).second);
|
||||||
// Recurse through any subdirectories.
|
// Recurse through any subdirectories.
|
||||||
if ((*it).second->getType() == FOLDER) {
|
if ((*it).second->getType() == FOLDER) {
|
||||||
std::vector<FileData*> childrenSubdirectory = (*it).second->getChildrenRecursive();
|
std::vector<FileData*> childrenSubdirectory = (*it).second->getChildrenRecursive();
|
||||||
childrenRecursive.insert(childrenRecursive.end(),
|
childrenRecursive.insert(childrenRecursive.end(), childrenSubdirectory.begin(),
|
||||||
childrenSubdirectory.begin(), childrenSubdirectory.end());
|
childrenSubdirectory.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,13 +169,13 @@ const std::string FileData::getROMDirectory()
|
||||||
// Expand home path if ~ is used.
|
// Expand home path if ~ is used.
|
||||||
romDirPath = Utils::FileSystem::expandHomePath(romDirPath);
|
romDirPath = Utils::FileSystem::expandHomePath(romDirPath);
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
if (romDirPath.back() != '\\')
|
if (romDirPath.back() != '\\')
|
||||||
romDirPath = romDirPath + "\\";
|
romDirPath = romDirPath + "\\";
|
||||||
#else
|
#else
|
||||||
if (romDirPath.back() != '/')
|
if (romDirPath.back() != '/')
|
||||||
romDirPath = romDirPath + "/";
|
romDirPath = romDirPath + "/";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// If %ESPATH% is used for the ROM path configuration, then expand it to the binary
|
// If %ESPATH% is used for the ROM path configuration, then expand it to the binary
|
||||||
|
@ -202,10 +200,10 @@ const std::string FileData::getMediaDirectory()
|
||||||
|
|
||||||
// If %ESPATH% is used for the media directory configuration, then expand it to the
|
// If %ESPATH% is used for the media directory configuration, then expand it to the
|
||||||
// binary directory of ES-DE.
|
// binary directory of ES-DE.
|
||||||
mediaDirPath = Utils::String::replace(
|
mediaDirPath =
|
||||||
mediaDirPath, "%ESPATH%", Utils::FileSystem::getExePath());
|
Utils::String::replace(mediaDirPath, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||||
|
|
||||||
if (mediaDirPath.back() != '/')
|
if (mediaDirPath.back() != '/')
|
||||||
mediaDirPath = mediaDirPath + "/";
|
mediaDirPath = mediaDirPath + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,11 +217,11 @@ const std::string FileData::getMediafilePath(std::string subdirectory, std::stri
|
||||||
|
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
if (mEnvData->mStartPath != "")
|
if (mEnvData->mStartPath != "")
|
||||||
subFolders = Utils::String::replace(
|
subFolders =
|
||||||
Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
Utils::String::replace(Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||||
|
|
||||||
const std::string tempPath = getMediaDirectory() + mSystemName + "/" + subdirectory +
|
const std::string tempPath = getMediaDirectory() + mSystemName + "/" + subdirectory +
|
||||||
subFolders + "/" + getDisplayName();
|
subFolders + "/" + getDisplayName();
|
||||||
|
|
||||||
// Look for an image file in the media directory.
|
// Look for an image file in the media directory.
|
||||||
for (int i = 0; i < extList.size(); i++) {
|
for (int i = 0; i < extList.size(); i++) {
|
||||||
|
@ -253,31 +251,37 @@ const std::string FileData::getImagePath() const
|
||||||
|
|
||||||
const std::string FileData::get3DBoxPath() const
|
const std::string FileData::get3DBoxPath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the 3D box image.
|
||||||
return getMediafilePath("3dboxes", "3dbox");
|
return getMediafilePath("3dboxes", "3dbox");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string FileData::getCoverPath() const
|
const std::string FileData::getCoverPath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the cover image.
|
||||||
return getMediafilePath("covers", "cover");
|
return getMediafilePath("covers", "cover");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string FileData::getMarqueePath() const
|
const std::string FileData::getMarqueePath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the marquee image.
|
||||||
return getMediafilePath("marquees", "marquee");
|
return getMediafilePath("marquees", "marquee");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string FileData::getMiximagePath() const
|
const std::string FileData::getMiximagePath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the miximage.
|
||||||
return getMediafilePath("miximages", "miximage");
|
return getMediafilePath("miximages", "miximage");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string FileData::getScreenshotPath() const
|
const std::string FileData::getScreenshotPath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the screenshot image.
|
||||||
return getMediafilePath("screenshots", "screenshot");
|
return getMediafilePath("screenshots", "screenshot");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string FileData::getThumbnailPath() const
|
const std::string FileData::getThumbnailPath() const
|
||||||
{
|
{
|
||||||
|
// Return path to the thumbnail image.
|
||||||
return getMediafilePath("thumbnails", "thumbnail");
|
return getMediafilePath("thumbnails", "thumbnail");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,11 +292,11 @@ const std::string FileData::getVideoPath() const
|
||||||
|
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
if (mEnvData->mStartPath != "")
|
if (mEnvData->mStartPath != "")
|
||||||
subFolders = Utils::String::replace(
|
subFolders =
|
||||||
Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
Utils::String::replace(Utils::FileSystem::getParent(mPath), mEnvData->mStartPath, "");
|
||||||
|
|
||||||
const std::string tempPath =
|
const std::string tempPath =
|
||||||
getMediaDirectory() + mSystemName + "/videos" + subFolders + "/" + getDisplayName();
|
getMediaDirectory() + mSystemName + "/videos" + subFolders + "/" + getDisplayName();
|
||||||
|
|
||||||
// Look for media in the media directory.
|
// Look for media in the media directory.
|
||||||
for (int i = 0; i < extList.size(); i++) {
|
for (int i = 0; i < extList.size(); i++) {
|
||||||
|
@ -322,7 +326,8 @@ const std::vector<FileData*>& FileData::getChildrenListToDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask,
|
std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask,
|
||||||
bool displayedOnly, bool countAllGames) const
|
bool displayedOnly,
|
||||||
|
bool countAllGames) const
|
||||||
{
|
{
|
||||||
std::vector<FileData*> out;
|
std::vector<FileData*> out;
|
||||||
FileFilterIndex* idx = mSystem->getIndex();
|
FileFilterIndex* idx = mSystem->getIndex();
|
||||||
|
@ -354,7 +359,8 @@ std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
||||||
bool excludeRecursively, bool respectExclusions) const
|
bool excludeRecursively,
|
||||||
|
bool respectExclusions) const
|
||||||
{
|
{
|
||||||
std::vector<FileData*> out;
|
std::vector<FileData*> out;
|
||||||
|
|
||||||
|
@ -375,7 +381,7 @@ std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
||||||
|
|
||||||
if ((*it)->getChildren().size() > 0) {
|
if ((*it)->getChildren().size() > 0) {
|
||||||
std::vector<FileData*> subChildren = (*it)->getScrapeFilesRecursive(
|
std::vector<FileData*> subChildren = (*it)->getScrapeFilesRecursive(
|
||||||
includeFolders, excludeRecursively, respectExclusions);
|
includeFolders, excludeRecursively, respectExclusions);
|
||||||
out.insert(out.cend(), subChildren.cbegin(), subChildren.cend());
|
out.insert(out.cend(), subChildren.cbegin(), subChildren.cend());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,32 +389,25 @@ std::vector<FileData*> FileData::getScrapeFilesRecursive(bool includeFolders,
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FileData::getKey() {
|
std::string FileData::getKey() { return getFileName(); }
|
||||||
return getFileName();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool FileData::isArcadeAsset()
|
const bool FileData::isArcadeAsset()
|
||||||
{
|
{
|
||||||
const std::string stem = Utils::FileSystem::getStem(mPath);
|
const std::string stem = Utils::FileSystem::getStem(mPath);
|
||||||
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
||||||
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
||||||
(MameNames::getInstance()->isBios(stem) ||
|
(MameNames::getInstance()->isBios(stem) || MameNames::getInstance()->isDevice(stem)));
|
||||||
MameNames::getInstance()->isDevice(stem)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool FileData::isArcadeGame()
|
const bool FileData::isArcadeGame()
|
||||||
{
|
{
|
||||||
const std::string stem = Utils::FileSystem::getStem(mPath);
|
const std::string stem = Utils::FileSystem::getStem(mPath);
|
||||||
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
||||||
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
mSystem->hasPlatformId(PlatformIds::SNK_NEO_GEO))) &&
|
||||||
(!MameNames::getInstance()->isBios(stem) &&
|
(!MameNames::getInstance()->isBios(stem) && !MameNames::getInstance()->isDevice(stem)));
|
||||||
!MameNames::getInstance()->isDevice(stem)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* FileData::getSourceFileData()
|
FileData* FileData::getSourceFileData() { return this; }
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileData::addChild(FileData* file)
|
void FileData::addChild(FileData* file)
|
||||||
{
|
{
|
||||||
|
@ -441,7 +440,7 @@ void FileData::removeChild(FileData* file)
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileData::sort(ComparisonFunction& comparator,
|
void FileData::sort(ComparisonFunction& comparator,
|
||||||
std::pair<unsigned int, unsigned int>& gameCount)
|
std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
{
|
{
|
||||||
mOnlyFolders = true;
|
mOnlyFolders = true;
|
||||||
mHasFolders = false;
|
mHasFolders = false;
|
||||||
|
@ -456,17 +455,17 @@ void FileData::sort(ComparisonFunction& comparator,
|
||||||
|
|
||||||
if (!showHiddenGames) {
|
if (!showHiddenGames) {
|
||||||
for (auto it = mChildren.begin(); it != mChildren.end();) {
|
for (auto it = mChildren.begin(); it != mChildren.end();) {
|
||||||
// If the option to hide hidden games has been set and the game is hidden,
|
// If the option to hide hidden games has been set and the game is hidden,
|
||||||
// then skip it. Normally games are hidden during loading of the gamelists in
|
// then skip it. Normally games are hidden during loading of the gamelists in
|
||||||
// Gamelist::parseGamelist() and this code should only run when a user has marked
|
// Gamelist::parseGamelist() and this code should only run when a user has marked
|
||||||
// an entry manually as hidden. So upon the next application startup, this game
|
// an entry manually as hidden. So upon the next application startup, this game
|
||||||
// should be filtered already at that earlier point.
|
// should be filtered already at that earlier point.
|
||||||
if ((*it)->getHidden())
|
if ((*it)->getHidden())
|
||||||
it = mChildren.erase(it);
|
it = mChildren.erase(it);
|
||||||
// Also hide folders where all its entries have been hidden, unless it's a
|
// Also hide folders where all its entries have been hidden, unless it's a
|
||||||
// grouped custom collection.
|
// grouped custom collection.
|
||||||
else if ((*it)->getType() == FOLDER && (*it)->getChildren().size() == 0 &&
|
else if ((*it)->getType() == FOLDER && (*it)->getChildren().size() == 0 &&
|
||||||
!(*it)->getSystem()->isGroupedCustomCollection())
|
!(*it)->getSystem()->isGroupedCustomCollection())
|
||||||
it = mChildren.erase(it);
|
it = mChildren.erase(it);
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
|
@ -502,11 +501,11 @@ void FileData::sort(ComparisonFunction& comparator,
|
||||||
// If the requested sorting is not by filename, then sort in ascending filename order
|
// If the requested sorting is not by filename, then sort in ascending filename order
|
||||||
// as a first step, in order to get a correct secondary sorting.
|
// as a first step, in order to get a correct secondary sorting.
|
||||||
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
||||||
getSortTypeFromString("filename, descending").comparisonFunction != comparator) {
|
getSortTypeFromString("filename, descending").comparisonFunction != comparator) {
|
||||||
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
|
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foldersOnTop && mOnlyFolders)
|
if (foldersOnTop && mOnlyFolders)
|
||||||
|
@ -523,9 +522,9 @@ void FileData::sort(ComparisonFunction& comparator,
|
||||||
// If the requested sorting is not by filename, then sort in ascending filename order
|
// If the requested sorting is not by filename, then sort in ascending filename order
|
||||||
// as a first step, in order to get a correct secondary sorting.
|
// as a first step, in order to get a correct secondary sorting.
|
||||||
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
||||||
getSortTypeFromString("filename, descending").comparisonFunction != comparator)
|
getSortTypeFromString("filename, descending").comparisonFunction != comparator)
|
||||||
std::stable_sort(mChildren.begin(), mChildren.end(),
|
std::stable_sort(mChildren.begin(), mChildren.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
|
|
||||||
std::stable_sort(mChildren.begin(), mChildren.end(), comparator);
|
std::stable_sort(mChildren.begin(), mChildren.end(), comparator);
|
||||||
}
|
}
|
||||||
|
@ -555,7 +554,7 @@ void FileData::sort(ComparisonFunction& comparator,
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileData::sortFavoritesOnTop(ComparisonFunction& comparator,
|
void FileData::sortFavoritesOnTop(ComparisonFunction& comparator,
|
||||||
std::pair<unsigned int, unsigned int>& gameCount)
|
std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
{
|
{
|
||||||
mOnlyFolders = true;
|
mOnlyFolders = true;
|
||||||
mHasFolders = false;
|
mHasFolders = false;
|
||||||
|
@ -634,39 +633,39 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator,
|
||||||
// some folders as favorites is probably a rare situation.
|
// some folders as favorites is probably a rare situation.
|
||||||
if (!mOnlyFolders && mChildrenFavoritesFolders.size() > 0) {
|
if (!mOnlyFolders && mChildrenFavoritesFolders.size() > 0) {
|
||||||
mChildrenFolders.insert(mChildrenFolders.end(), mChildrenFavoritesFolders.begin(),
|
mChildrenFolders.insert(mChildrenFolders.end(), mChildrenFavoritesFolders.begin(),
|
||||||
mChildrenFavoritesFolders.end());
|
mChildrenFavoritesFolders.end());
|
||||||
mChildrenFavoritesFolders.erase(mChildrenFavoritesFolders.begin(),
|
mChildrenFavoritesFolders.erase(mChildrenFavoritesFolders.begin(),
|
||||||
mChildrenFavoritesFolders.end());
|
mChildrenFavoritesFolders.end());
|
||||||
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the requested sorting is not by filename, then sort in ascending filename order
|
// If the requested sorting is not by filename, then sort in ascending filename order
|
||||||
// as a first step, in order to get a correct secondary sorting.
|
// as a first step, in order to get a correct secondary sorting.
|
||||||
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
if (getSortTypeFromString("filename, ascending").comparisonFunction != comparator &&
|
||||||
getSortTypeFromString("filename, descending").comparisonFunction != comparator) {
|
getSortTypeFromString("filename, descending").comparisonFunction != comparator) {
|
||||||
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
std::stable_sort(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end(),
|
std::stable_sort(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(),
|
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
|
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
|
||||||
getSortTypeFromString("filename, ascending").comparisonFunction);
|
getSortTypeFromString("filename, ascending").comparisonFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort favorite games and the other games separately.
|
// Sort favorite games and the other games separately.
|
||||||
if (foldersOnTop && mOnlyFolders) {
|
if (foldersOnTop && mOnlyFolders) {
|
||||||
std::stable_sort(mChildrenFavoritesFolders.begin(),
|
std::stable_sort(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end(),
|
||||||
mChildrenFavoritesFolders.end(), comparator);
|
comparator);
|
||||||
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator);
|
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator);
|
||||||
}
|
}
|
||||||
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(), comparator);
|
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(), comparator);
|
||||||
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
|
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
|
||||||
|
|
||||||
// Iterate through any child favorite folders.
|
// Iterate through any child favorite folders.
|
||||||
for (auto it = mChildrenFavoritesFolders.cbegin(); it !=
|
for (auto it = mChildrenFavoritesFolders.cbegin(); // Line break.
|
||||||
mChildrenFavoritesFolders.cend(); it++) {
|
it != mChildrenFavoritesFolders.cend(); it++) {
|
||||||
if ((*it)->getChildren().size() > 0)
|
if ((*it)->getChildren().size() > 0)
|
||||||
(*it)->sortFavoritesOnTop(comparator, gameCount);
|
(*it)->sortFavoritesOnTop(comparator, gameCount);
|
||||||
}
|
}
|
||||||
|
@ -690,9 +689,9 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator,
|
||||||
// Combine the individually sorted favorite games and other games vectors.
|
// Combine the individually sorted favorite games and other games vectors.
|
||||||
mChildren.erase(mChildren.begin(), mChildren.end());
|
mChildren.erase(mChildren.begin(), mChildren.end());
|
||||||
mChildren.reserve(mChildrenFavoritesFolders.size() + mChildrenFolders.size() +
|
mChildren.reserve(mChildrenFavoritesFolders.size() + mChildrenFolders.size() +
|
||||||
mChildrenFavorites.size() + mChildrenOthers.size());
|
mChildrenFavorites.size() + mChildrenOthers.size());
|
||||||
mChildren.insert(mChildren.end(), mChildrenFavoritesFolders.begin(),
|
mChildren.insert(mChildren.end(), mChildrenFavoritesFolders.begin(),
|
||||||
mChildrenFavoritesFolders.end());
|
mChildrenFavoritesFolders.end());
|
||||||
mChildren.insert(mChildren.end(), mChildrenFolders.begin(), mChildrenFolders.end());
|
mChildren.insert(mChildren.end(), mChildrenFolders.begin(), mChildrenFolders.end());
|
||||||
mChildren.insert(mChildren.end(), mChildrenFavorites.begin(), mChildrenFavorites.end());
|
mChildren.insert(mChildren.end(), mChildrenFavorites.begin(), mChildrenFavorites.end());
|
||||||
mChildren.insert(mChildren.end(), mChildrenOthers.begin(), mChildrenOthers.end());
|
mChildren.insert(mChildren.end(), mChildrenOthers.begin(), mChildrenOthers.end());
|
||||||
|
@ -711,10 +710,10 @@ void FileData::sort(const SortType& type, bool mFavoritesOnTop)
|
||||||
void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
{
|
{
|
||||||
bool isKidMode = (Settings::getInstance()->getString("UIMode") == "kid" ||
|
bool isKidMode = (Settings::getInstance()->getString("UIMode") == "kid" ||
|
||||||
Settings::getInstance()->getBool("ForceKid"));
|
Settings::getInstance()->getBool("ForceKid"));
|
||||||
|
|
||||||
(Settings::getInstance()->getString("UIMode") == "kid" ||
|
(Settings::getInstance()->getString("UIMode") == "kid" ||
|
||||||
Settings::getInstance()->getBool("ForceKid"));
|
Settings::getInstance()->getBool("ForceKid"));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mChildren.size(); i++) {
|
for (unsigned int i = 0; i < mChildren.size(); i++) {
|
||||||
if (mChildren[i]->getType() == GAME && mChildren[i]->getCountAsGame()) {
|
if (mChildren[i]->getType() == GAME && mChildren[i]->getCountAsGame()) {
|
||||||
|
@ -731,7 +730,8 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
|
||||||
mGameCount = gameCount;
|
mGameCount = gameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData::SortType FileData::getSortTypeFromString(std::string desc) {
|
FileData::SortType FileData::getSortTypeFromString(std::string desc)
|
||||||
|
{
|
||||||
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
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
|
// Check if there is a launch command override for the game
|
||||||
// and the corresponding option to use it has been set.
|
// and the corresponding option to use it has been set.
|
||||||
if (Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
if (Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
||||||
!metadata.get("launchcommand").empty())
|
!metadata.get("launchcommand").empty()) {
|
||||||
command = metadata.get("launchcommand");
|
command = metadata.get("launchcommand");
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
command = mEnvData->mLaunchCommand;
|
command = mEnvData->mLaunchCommand;
|
||||||
|
}
|
||||||
|
|
||||||
std::string commandRaw = command;
|
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.
|
// 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: ") {
|
if (binaryPath.substr(0, 18) == "NO EMULATOR RULE: ") {
|
||||||
std::string emulatorEntry = binaryPath.substr(18, binaryPath.size() - 18);
|
std::string emulatorEntry = binaryPath.substr(18, binaryPath.size() - 18);
|
||||||
LOG(LogError) << "Couldn't launch game, either there is no emulator entry for \"" <<
|
LOG(LogError)
|
||||||
emulatorEntry << "\" in es_find_rules.xml or there are no systempath or staticpath "
|
<< "Couldn't launch game, either there is no emulator entry for \"" << emulatorEntry
|
||||||
"rules defined";
|
<< "\" in es_find_rules.xml or there are no systempath or staticpath rules defined";
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: MISSING EMULATOR CONFIGURATION FOR '" +
|
GuiInfoPopup* s = new GuiInfoPopup(
|
||||||
emulatorEntry + "'", 6000);
|
window, "ERROR: MISSING EMULATOR CONFIGURATION FOR '" + emulatorEntry + "'", 6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -810,20 +812,23 @@ void FileData::launchGame(Window* window)
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: COULDN'T FIND EMULATOR, HAS IT " \
|
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||||
"BEEN PROPERLY INSTALLED?", 6000);
|
"ERROR: COULDN'T FIND EMULATOR, HAS IT "
|
||||||
|
"BEEN PROPERLY INSTALLED?",
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \"" <<
|
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \""
|
||||||
Utils::String::replace(Utils::String::replace(
|
<< Utils::String::replace(
|
||||||
binaryPath, "%ESPATH%", esPath), "/", "\\") << "\"";
|
Utils::String::replace(binaryPath, "%ESPATH%", esPath), "/", "\\")
|
||||||
#else
|
<< "\"";
|
||||||
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \"" <<
|
#else
|
||||||
Utils::String::replace(binaryPath, "%ESPATH%", esPath) << "\"";
|
LOG(LogDebug) << "FileData::launchGame(): Found emulator binary \""
|
||||||
#endif
|
<< Utils::String::replace(binaryPath, "%ESPATH%", esPath) << "\"";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// If %EMUPATH% is used in es_systems.xml for this system, then check that the core
|
// 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;
|
unsigned int quotationMarkPos = 0;
|
||||||
if (command.find("\"%EMUPATH%", emuPathPos - 1) != std::string::npos) {
|
if (command.find("\"%EMUPATH%", emuPathPos - 1) != std::string::npos) {
|
||||||
hasQuotationMark = true;
|
hasQuotationMark = true;
|
||||||
quotationMarkPos = static_cast<unsigned int>(
|
quotationMarkPos =
|
||||||
command.find("\"", emuPathPos + 9) - emuPathPos);
|
static_cast<unsigned int>(command.find("\"", emuPathPos + 9) - emuPathPos);
|
||||||
}
|
}
|
||||||
size_t spacePos = command.find(" ", emuPathPos + quotationMarkPos);
|
size_t spacePos = command.find(" ", emuPathPos + quotationMarkPos);
|
||||||
std::string coreRaw;
|
std::string coreRaw;
|
||||||
|
@ -843,22 +848,23 @@ void FileData::launchGame(Window* window)
|
||||||
if (spacePos != std::string::npos) {
|
if (spacePos != std::string::npos) {
|
||||||
coreRaw = command.substr(emuPathPos, spacePos - emuPathPos);
|
coreRaw = command.substr(emuPathPos, spacePos - emuPathPos);
|
||||||
coreFile = Utils::FileSystem::getParent(binaryPath) +
|
coreFile = Utils::FileSystem::getParent(binaryPath) +
|
||||||
command.substr(emuPathPos + 9, spacePos - emuPathPos - 9);
|
command.substr(emuPathPos + 9, spacePos - emuPathPos - 9);
|
||||||
if (hasQuotationMark) {
|
if (hasQuotationMark) {
|
||||||
coreRaw.pop_back();
|
coreRaw.pop_back();
|
||||||
coreFile.pop_back();
|
coreFile.pop_back();
|
||||||
}
|
}
|
||||||
if (!Utils::FileSystem::isRegularFile(coreFile) &&
|
if (!Utils::FileSystem::isRegularFile(coreFile) &&
|
||||||
!Utils::FileSystem::isSymlink(coreFile)) {
|
!Utils::FileSystem::isSymlink(coreFile)) {
|
||||||
LOG(LogError) << "Couldn't launch game, emulator core file \"" <<
|
LOG(LogError) << "Couldn't launch game, emulator core file \""
|
||||||
Utils::FileSystem::getFileName(coreFile) << "\" not found";
|
<< Utils::FileSystem::getFileName(coreFile) << "\" not found";
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window,
|
GuiInfoPopup* s = new GuiInfoPopup(
|
||||||
"ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
window,
|
||||||
Utils::String::toUpper(Utils::FileSystem::getFileName(coreFile)) +
|
"ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
||||||
"'", 6000);
|
Utils::String::toUpper(Utils::FileSystem::getFileName(coreFile)) + "'",
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -877,8 +883,10 @@ void FileData::launchGame(Window* window)
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: INVALID ENTRY IN SYSTEMS " \
|
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||||
"CONFIGURATION FILE", 6000);
|
"ERROR: INVALID ENTRY IN SYSTEMS "
|
||||||
|
"CONFIGURATION FILE",
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -886,13 +894,13 @@ void FileData::launchGame(Window* window)
|
||||||
|
|
||||||
// Error handling in case of no core find rule.
|
// Error handling in case of no core find rule.
|
||||||
if (coreEntry != "" && emulatorCorePaths.empty()) {
|
if (coreEntry != "" && emulatorCorePaths.empty()) {
|
||||||
LOG(LogError) << "Couldn't launch game, either there is no core entry for \"" <<
|
LOG(LogError) << "Couldn't launch game, either there is no core entry for \"" << coreEntry
|
||||||
coreEntry << "\" in es_find_rules.xml or there are no corepath rules defined";
|
<< "\" in es_find_rules.xml or there are no corepath rules defined";
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: MISSING CORE CONFIGURATION FOR '" +
|
GuiInfoPopup* s = new GuiInfoPopup(
|
||||||
coreEntry + "'", 6000);
|
window, "ERROR: MISSING CORE CONFIGURATION FOR '" + coreEntry + "'", 6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -913,46 +921,47 @@ void FileData::launchGame(Window* window)
|
||||||
separatorPos = quotePos;
|
separatorPos = quotePos;
|
||||||
|
|
||||||
if (separatorPos != std::string::npos) {
|
if (separatorPos != std::string::npos) {
|
||||||
coreName = command.substr(coreFilePos + 2, separatorPos - (coreFilePos + 2));
|
coreName = command.substr(coreFilePos + 2, separatorPos - (coreFilePos + 2));
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::string coreFile = Utils::FileSystem::expandHomePath(path + "\\" + coreName);
|
std::string coreFile = Utils::FileSystem::expandHomePath(path + "\\" + coreName);
|
||||||
#else
|
#else
|
||||||
std::string coreFile = Utils::FileSystem::expandHomePath(path + "/" + coreName);
|
std::string coreFile = Utils::FileSystem::expandHomePath(path + "/" + coreName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Expand %EMUPATH% if it has been used in the %CORE_ variable.
|
// Expand %EMUPATH% if it has been used in the %CORE_ variable.
|
||||||
size_t stringPos = coreFile.find("%EMUPATH%");
|
size_t stringPos = coreFile.find("%EMUPATH%");
|
||||||
if (stringPos != std::string::npos) {
|
if (stringPos != std::string::npos) {
|
||||||
#if defined (_WIN64)
|
#if defined(_WIN64)
|
||||||
coreFile = Utils::String::replace(coreFile.replace(stringPos, 9,
|
coreFile = Utils::String::replace(
|
||||||
Utils::FileSystem::getParent(binaryPath)), "/", "\\");
|
coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath)), "/",
|
||||||
#else
|
"\\");
|
||||||
|
#else
|
||||||
coreFile = coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath));
|
coreFile = coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand %ESPATH% if it has been used in the %CORE_ variable.
|
// Expand %ESPATH% if it has been used in the %CORE_ variable.
|
||||||
stringPos = coreFile.find("%ESPATH%");
|
stringPos = coreFile.find("%ESPATH%");
|
||||||
if (stringPos != std::string::npos) {
|
if (stringPos != std::string::npos) {
|
||||||
coreFile = coreFile.replace(stringPos, 8, esPath);
|
coreFile = coreFile.replace(stringPos, 8, esPath);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
coreFile = Utils::String::replace(coreFile, "/", "\\");
|
coreFile = Utils::String::replace(coreFile, "/", "\\");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils::FileSystem::isRegularFile(coreFile) ||
|
if (Utils::FileSystem::isRegularFile(coreFile) ||
|
||||||
Utils::FileSystem::isSymlink(coreFile)) {
|
Utils::FileSystem::isSymlink(coreFile)) {
|
||||||
foundCoreFile = true;
|
foundCoreFile = true;
|
||||||
// Escape any blankspaces.
|
// Escape any blankspaces.
|
||||||
if (coreFile.find(" ") != std::string::npos)
|
if (coreFile.find(" ") != std::string::npos)
|
||||||
coreFile = Utils::FileSystem::getEscapedPath(coreFile);
|
coreFile = Utils::FileSystem::getEscapedPath(coreFile);
|
||||||
command.replace(coreEntryPos, separatorPos - coreEntryPos, 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.
|
// Remove any quotation marks as it would make the launch function fail.
|
||||||
if (command.find("\"") != std::string::npos)
|
if (command.find("\"") != std::string::npos)
|
||||||
command = Utils::String::replace(command, "\"", "");
|
command = Utils::String::replace(command, "\"", "");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -961,23 +970,28 @@ void FileData::launchGame(Window* window)
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: INVALID ENTRY IN SYSTEMS " \
|
GuiInfoPopup* s = new GuiInfoPopup(window,
|
||||||
"CONFIGURATION FILE", 6000);
|
"ERROR: INVALID ENTRY IN SYSTEMS "
|
||||||
|
"CONFIGURATION FILE",
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!foundCoreFile && coreName.size() > 0) {
|
if (!foundCoreFile && coreName.size() > 0) {
|
||||||
LOG(LogError) << "Couldn't launch game, emulator core file \"" <<
|
LOG(LogError) << "Couldn't launch game, emulator core file \""
|
||||||
coreName.substr(0, coreName.size()) << "\" not found";
|
<< coreName.substr(0, coreName.size()) << "\" not found";
|
||||||
LOG(LogError) << "Raw emulator launch command:";
|
LOG(LogError) << "Raw emulator launch command:";
|
||||||
LOG(LogError) << commandRaw;
|
LOG(LogError) << commandRaw;
|
||||||
LOG(LogError) <<
|
LOG(LogError)
|
||||||
"Tried to find the core file using these paths as defined by es_find_rules.xml:";
|
<< "Tried to find the core file using these paths as defined by es_find_rules.xml:";
|
||||||
LOG(LogError) << Utils::String::vectorToDelimitedString(emulatorCorePaths, ", ");
|
LOG(LogError) << Utils::String::vectorToDelimitedString(emulatorCorePaths, ", ");
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
GuiInfoPopup* s =
|
||||||
Utils::String::toUpper(coreName.substr(0, coreName.size()) + "'"), 6000);
|
new GuiInfoPopup(window,
|
||||||
|
"ERROR: COULDN'T FIND EMULATOR CORE FILE '" +
|
||||||
|
Utils::String::toUpper(coreName.substr(0, coreName.size()) + "'"),
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -990,12 +1004,13 @@ void FileData::launchGame(Window* window)
|
||||||
// swapBuffers() is called here to turn the screen black to eliminate some potential
|
// 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
|
// flickering and to avoid showing the game launch message briefly when returning
|
||||||
// from the game.
|
// from the game.
|
||||||
#if defined(_WIN64)
|
|
||||||
|
#if defined(_WIN64)
|
||||||
if (!(Settings::getInstance()->getBool("LaunchWorkaround") ||
|
if (!(Settings::getInstance()->getBool("LaunchWorkaround") ||
|
||||||
ViewController::get()->runInBackground(mSystem)))
|
ViewController::get()->runInBackground(mSystem)))
|
||||||
#else
|
#else
|
||||||
if (!ViewController::get()->runInBackground(mSystem))
|
if (!ViewController::get()->runInBackground(mSystem))
|
||||||
#endif
|
#endif
|
||||||
Renderer::swapBuffers();
|
Renderer::swapBuffers();
|
||||||
|
|
||||||
Scripting::fireEvent("game-start", romPath, getSourceFileData()->metadata.get("name"));
|
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) << "Raw emulator launch command:";
|
||||||
LOG(LogDebug) << commandRaw;
|
LOG(LogDebug) << commandRaw;
|
||||||
LOG(LogInfo) << "Expanded emulator launch command:";
|
LOG(LogInfo) << "Expanded emulator launch command:";
|
||||||
|
|
||||||
LOG(LogInfo) << command;
|
LOG(LogInfo) << command;
|
||||||
|
|
||||||
// Possibly keep ES-DE running in the background while the game is launched.
|
// 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),
|
returnValue = launchGameWindows(Utils::String::stringToWideString(command),
|
||||||
ViewController::get()->runInBackground(mSystem));
|
ViewController::get()->runInBackground(mSystem));
|
||||||
#else
|
#else
|
||||||
returnValue = launchGameUnix(command, ViewController::get()->runInBackground(mSystem));
|
returnValue = launchGameUnix(command, ViewController::get()->runInBackground(mSystem));
|
||||||
#endif
|
#endif
|
||||||
// Notify the user in case of a failed game launch using a popup window.
|
// Notify the user in case of a failed game launch using a popup window.
|
||||||
if (returnValue != 0) {
|
if (returnValue != 0) {
|
||||||
LOG(LogWarning) << "...launch terminated with nonzero return value " << returnValue;
|
LOG(LogWarning) << "...launch terminated with nonzero return value " << returnValue;
|
||||||
|
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(window, "ERROR LAUNCHING GAME '" +
|
GuiInfoPopup* s = new GuiInfoPopup(
|
||||||
Utils::String::toUpper(metadata.get("name")) + "' (ERROR CODE " +
|
window,
|
||||||
Utils::String::toUpper(std::to_string(returnValue) + ")"), 6000);
|
"ERROR LAUNCHING GAME '" + Utils::String::toUpper(metadata.get("name")) +
|
||||||
|
"' (ERROR CODE " + Utils::String::toUpper(std::to_string(returnValue) + ")"),
|
||||||
|
6000);
|
||||||
window->setInfoPopup(s);
|
window->setInfoPopup(s);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Stop showing the game launch notification.
|
// Stop showing the game launch notification.
|
||||||
window->stopInfoPopup();
|
window->stopInfoPopup();
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// For some game systems or if the "RunInBackground" setting has been enabled, keep
|
// 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
|
// ES-DE running while the game is launched. This pauses any video and keeps the
|
||||||
// screensaver from getting activated.
|
// screensaver from getting activated.
|
||||||
|
@ -1035,7 +1053,7 @@ void FileData::launchGame(Window* window)
|
||||||
// Normalize deltaTime so that the screensaver does not start immediately
|
// Normalize deltaTime so that the screensaver does not start immediately
|
||||||
// when returning from the game.
|
// when returning from the game.
|
||||||
window->normalizeNextUpdate();
|
window->normalizeNextUpdate();
|
||||||
#else
|
#else
|
||||||
// For some game systems we need to keep ES-DE running while the game is launched.
|
// 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.
|
// This pauses any video and keeps the screensaver from getting activated.
|
||||||
if (ViewController::get()->runInBackground(mSystem))
|
if (ViewController::get()->runInBackground(mSystem))
|
||||||
|
@ -1043,7 +1061,7 @@ void FileData::launchGame(Window* window)
|
||||||
// Normalize deltaTime so that the screensaver does not start immediately
|
// Normalize deltaTime so that the screensaver does not start immediately
|
||||||
// when returning from the game.
|
// when returning from the game.
|
||||||
window->normalizeNextUpdate();
|
window->normalizeNextUpdate();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Scripting::fireEvent("game-end", romPath, getSourceFileData()->metadata.get("name"));
|
Scripting::fireEvent("game-end", romPath, getSourceFileData()->metadata.get("name"));
|
||||||
|
@ -1062,10 +1080,10 @@ void FileData::launchGame(Window* window)
|
||||||
|
|
||||||
// If the parent is a folder and it's not the root of the system, then update its lastplayed
|
// If the parent is a folder and it's not the root of the system, then update its lastplayed
|
||||||
// timestamp to the same time as the game that was just launched.
|
// timestamp to the same time as the game that was just launched.
|
||||||
if (gameToUpdate->getParent()->getType() == FOLDER && gameToUpdate->getParent()->getName() !=
|
if (gameToUpdate->getParent()->getType() == FOLDER &&
|
||||||
gameToUpdate->getSystem()->getFullName()) {
|
gameToUpdate->getParent()->getName() != gameToUpdate->getSystem()->getFullName()) {
|
||||||
gameToUpdate->getParent()->metadata.set("lastplayed",
|
gameToUpdate->getParent()->metadata.set("lastplayed",
|
||||||
gameToUpdate->metadata.get("lastplayed"));
|
gameToUpdate->metadata.get("lastplayed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionSystemsManager::get()->refreshCollectionSystems(gameToUpdate);
|
CollectionSystemsManager::get()->refreshCollectionSystems(gameToUpdate);
|
||||||
|
@ -1086,9 +1104,9 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
|
|
||||||
// Method 1, emulator binary is defined using find rules:
|
// Method 1, emulator binary is defined using find rules:
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::vector<std::string> emulatorWinRegistryPaths;
|
std::vector<std::string> emulatorWinRegistryPaths;
|
||||||
#endif
|
#endif
|
||||||
std::vector<std::string> emulatorSystemPaths;
|
std::vector<std::string> emulatorSystemPaths;
|
||||||
std::vector<std::string> emulatorStaticPaths;
|
std::vector<std::string> emulatorStaticPaths;
|
||||||
std::string emulatorEntry;
|
std::string emulatorEntry;
|
||||||
|
@ -1101,10 +1119,10 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emulatorEntry != "") {
|
if (emulatorEntry != "") {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
emulatorWinRegistryPaths =
|
emulatorWinRegistryPaths =
|
||||||
SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryPaths;
|
SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryPaths;
|
||||||
#endif
|
#endif
|
||||||
emulatorSystemPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].systemPaths;
|
emulatorSystemPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].systemPaths;
|
||||||
emulatorStaticPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].staticPaths;
|
emulatorStaticPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].staticPaths;
|
||||||
}
|
}
|
||||||
|
@ -1113,11 +1131,11 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
if (emulatorEntry != "" && emulatorSystemPaths.empty() && emulatorStaticPaths.empty())
|
if (emulatorEntry != "" && emulatorSystemPaths.empty() && emulatorStaticPaths.empty())
|
||||||
return "NO EMULATOR RULE: " + emulatorEntry;
|
return "NO EMULATOR RULE: " + emulatorEntry;
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
for (std::string path : emulatorWinRegistryPaths) {
|
for (std::string path : emulatorWinRegistryPaths) {
|
||||||
// Search for the emulator using the App Paths keys in the Windows Registry.
|
// Search for the emulator using the App Paths keys in the Windows Registry.
|
||||||
std::string registryKeyPath =
|
std::string registryKeyPath =
|
||||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + path;
|
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" + path;
|
||||||
|
|
||||||
HKEY registryKey;
|
HKEY registryKey;
|
||||||
LSTATUS keyStatus = -1;
|
LSTATUS keyStatus = -1;
|
||||||
|
@ -1126,33 +1144,19 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
DWORD pathSize = 1024;
|
DWORD pathSize = 1024;
|
||||||
|
|
||||||
// First look in HKEY_CURRENT_USER.
|
// First look in HKEY_CURRENT_USER.
|
||||||
keyStatus = RegOpenKeyEx(
|
keyStatus = RegOpenKeyEx(HKEY_CURRENT_USER, registryKeyPath.c_str(), 0, KEY_QUERY_VALUE,
|
||||||
HKEY_CURRENT_USER,
|
®istryKey);
|
||||||
registryKeyPath.c_str(),
|
|
||||||
0,
|
|
||||||
KEY_QUERY_VALUE,
|
|
||||||
®istryKey);
|
|
||||||
|
|
||||||
// If not found, then try in HKEY_LOCAL_MACHINE.
|
// If not found, then try in HKEY_LOCAL_MACHINE.
|
||||||
if (keyStatus != ERROR_SUCCESS) {
|
if (keyStatus != ERROR_SUCCESS) {
|
||||||
keyStatus = RegOpenKeyEx(
|
keyStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, registryKeyPath.c_str(), 0,
|
||||||
HKEY_LOCAL_MACHINE,
|
KEY_QUERY_VALUE, ®istryKey);
|
||||||
registryKeyPath.c_str(),
|
|
||||||
0,
|
|
||||||
KEY_QUERY_VALUE,
|
|
||||||
®istryKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the key exists, then try to retrieve the value.
|
// If the key exists, then try to retrieve the value.
|
||||||
if (keyStatus == ERROR_SUCCESS) {
|
if (keyStatus == ERROR_SUCCESS) {
|
||||||
pathStatus = RegGetValue(
|
pathStatus = RegGetValue(registryKey, nullptr, nullptr, RRF_RT_REG_SZ, nullptr,
|
||||||
registryKey,
|
®istryPath, &pathSize);
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
RRF_RT_REG_SZ,
|
|
||||||
nullptr,
|
|
||||||
®istryPath,
|
|
||||||
&pathSize);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
RegCloseKey(registryKey);
|
RegCloseKey(registryKey);
|
||||||
|
@ -1163,7 +1167,7 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
// so check for that as well.
|
// so check for that as well.
|
||||||
if (pathStatus == ERROR_SUCCESS) {
|
if (pathStatus == ERROR_SUCCESS) {
|
||||||
if (Utils::FileSystem::isRegularFile(registryPath) ||
|
if (Utils::FileSystem::isRegularFile(registryPath) ||
|
||||||
Utils::FileSystem::isSymlink(registryPath)) {
|
Utils::FileSystem::isSymlink(registryPath)) {
|
||||||
command.replace(0, endPos + 1, registryPath);
|
command.replace(0, endPos + 1, registryPath);
|
||||||
RegCloseKey(registryKey);
|
RegCloseKey(registryKey);
|
||||||
return registryPath;
|
return registryPath;
|
||||||
|
@ -1171,25 +1175,24 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
}
|
}
|
||||||
RegCloseKey(registryKey);
|
RegCloseKey(registryKey);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (std::string path : emulatorSystemPaths) {
|
for (std::string path : emulatorSystemPaths) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::wstring pathWide = Utils::String::stringToWideString(path);
|
std::wstring pathWide = Utils::String::stringToWideString(path);
|
||||||
// Search for the emulator using the PATH environmental variable.
|
// Search for the emulator using the PATH environmental variable.
|
||||||
DWORD size = SearchPathW(nullptr, pathWide.c_str(), L".exe", 0, nullptr, nullptr);
|
DWORD size = SearchPathW(nullptr, pathWide.c_str(), L".exe", 0, nullptr, nullptr);
|
||||||
|
|
||||||
if (size) {
|
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;
|
wchar_t* fileName = nullptr;
|
||||||
|
|
||||||
SearchPathW(nullptr, pathWide.c_str(), L".exe", size + 1 ,
|
SearchPathW(nullptr, pathWide.c_str(), L".exe", size + 1, pathBuffer.data(), &fileName);
|
||||||
pathBuffer.data(), &fileName);
|
|
||||||
std::wstring pathString = pathBuffer.data();
|
std::wstring pathString = pathBuffer.data();
|
||||||
|
|
||||||
if (pathString.length()) {
|
if (pathString.length()) {
|
||||||
exePath = Utils::String::wideStringToString(pathString.substr(0,
|
exePath = Utils::String::wideStringToString(
|
||||||
pathString.size() - std::wstring(fileName).size()));
|
pathString.substr(0, pathString.size() - std::wstring(fileName).size()));
|
||||||
exePath.pop_back();
|
exePath.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1198,14 +1201,14 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
command.replace(0, endPos + 1, exePath);
|
command.replace(0, endPos + 1, exePath);
|
||||||
return exePath;
|
return exePath;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
exePath = Utils::FileSystem::getPathToBinary(path);
|
exePath = Utils::FileSystem::getPathToBinary(path);
|
||||||
if (exePath != "") {
|
if (exePath != "") {
|
||||||
exePath += "/" + path;
|
exePath += "/" + path;
|
||||||
command.replace(0, endPos + 1, exePath);
|
command.replace(0, endPos + 1, exePath);
|
||||||
return exePath;
|
return exePath;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::string path : emulatorStaticPaths) {
|
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());
|
path = Utils::String::replace(path, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||||
// Likewise for the %ROMPATH% variable which expands to the configured ROM directory.
|
// Likewise for the %ROMPATH% variable which expands to the configured ROM directory.
|
||||||
path = Utils::String::replace(path, "%ROMPATH%", getROMDirectory());
|
path = Utils::String::replace(path, "%ROMPATH%", getROMDirectory());
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
path = Utils::String::replace(path, "/", "\\");
|
path = Utils::String::replace(path, "/", "\\");
|
||||||
#endif
|
#endif
|
||||||
if (Utils::FileSystem::isRegularFile(path) ||
|
if (Utils::FileSystem::isRegularFile(path) || Utils::FileSystem::isSymlink(path)) {
|
||||||
Utils::FileSystem::isSymlink(path)) {
|
|
||||||
command.replace(0, endPos + 1, path);
|
command.replace(0, endPos + 1, path);
|
||||||
return 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.
|
// If %ESPATH% is used, then expand it to the binary directory of ES-DE.
|
||||||
command = Utils::String::replace(command, "%ESPATH%", Utils::FileSystem::getExePath());
|
command = Utils::String::replace(command, "%ESPATH%", Utils::FileSystem::getExePath());
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
command = Utils::String::replace(command, "/", "\\");
|
command = Utils::String::replace(command, "/", "\\");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If the first character is a quotation mark, then we need to extract up to the
|
// 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.
|
// next quotation mark, otherwise we'll only extract up to the first space character.
|
||||||
|
@ -1242,23 +1244,23 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
emuExecutable = command.substr(0, command.find(' '));
|
emuExecutable = command.substr(0, command.find(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::wstring emuExecutableWide = Utils::String::stringToWideString(emuExecutable);
|
std::wstring emuExecutableWide = Utils::String::stringToWideString(emuExecutable);
|
||||||
// Search for the emulator using the PATH environmental variable.
|
// Search for the emulator using the PATH environmental variable.
|
||||||
DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr);
|
DWORD size = SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", 0, nullptr, nullptr);
|
||||||
|
|
||||||
if (size) {
|
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;
|
wchar_t* fileName = nullptr;
|
||||||
|
|
||||||
SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", size + 1 ,
|
SearchPathW(nullptr, emuExecutableWide.c_str(), L".exe", size + 1, pathBuffer.data(),
|
||||||
pathBuffer.data(), &fileName);
|
&fileName);
|
||||||
|
|
||||||
exePath = Utils::String::wideStringToString(pathBuffer.data());
|
exePath = Utils::String::wideStringToString(pathBuffer.data());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (Utils::FileSystem::isRegularFile(emuExecutable) ||
|
if (Utils::FileSystem::isRegularFile(emuExecutable) ||
|
||||||
Utils::FileSystem::isSymlink(emuExecutable)) {
|
Utils::FileSystem::isSymlink(emuExecutable)) {
|
||||||
exePath = emuExecutable;
|
exePath = emuExecutable;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1266,14 +1268,16 @@ std::string FileData::findEmulatorPath(std::string& command)
|
||||||
if (exePath != "")
|
if (exePath != "")
|
||||||
exePath += "/" + emuExecutable;
|
exePath += "/" + emuExecutable;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return exePath;
|
return exePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
||||||
: FileData(file->getSourceFileData()->getType(), file->getSourceFileData()->getPath(),
|
: FileData(file->getSourceFileData()->getType(),
|
||||||
file->getSourceFileData()->getSystemEnvData(), system)
|
file->getSourceFileData()->getPath(),
|
||||||
|
file->getSourceFileData()->getSystemEnvData(),
|
||||||
|
system)
|
||||||
{
|
{
|
||||||
// We use this constructor to create a clone of the filedata, and change its system.
|
// We use this constructor to create a clone of the filedata, and change its system.
|
||||||
mSourceFileData = file->getSourceFileData();
|
mSourceFileData = file->getSourceFileData();
|
||||||
|
@ -1291,15 +1295,6 @@ CollectionFileData::~CollectionFileData()
|
||||||
mParent = nullptr;
|
mParent = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CollectionFileData::getKey() {
|
|
||||||
return getFullPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileData* CollectionFileData::getSourceFileData()
|
|
||||||
{
|
|
||||||
return mSourceFileData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CollectionFileData::refreshMetadata()
|
void CollectionFileData::refreshMetadata()
|
||||||
{
|
{
|
||||||
metadata = mSourceFileData->metadata;
|
metadata = mSourceFileData->metadata;
|
||||||
|
@ -1310,9 +1305,9 @@ const std::string& CollectionFileData::getName()
|
||||||
{
|
{
|
||||||
if (mDirty) {
|
if (mDirty) {
|
||||||
mCollectionFileName =
|
mCollectionFileName =
|
||||||
Utils::String::removeParenthesis(mSourceFileData->metadata.get("name"));
|
Utils::String::removeParenthesis(mSourceFileData->metadata.get("name"));
|
||||||
mCollectionFileName +=
|
mCollectionFileName +=
|
||||||
" [" + Utils::String::toUpper(mSourceFileData->getSystem()->getName()) + "]";
|
" [" + Utils::String::toUpper(mSourceFileData->getSystem()->getName()) + "]";
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#ifndef ES_APP_FILE_DATA_H
|
#ifndef ES_APP_FILE_DATA_H
|
||||||
#define ES_APP_FILE_DATA_H
|
#define ES_APP_FILE_DATA_H
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "MetaData.h"
|
#include "MetaData.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
@ -30,8 +30,10 @@ enum FileType {
|
||||||
class FileData
|
class FileData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileData(FileType type, const std::string& path,
|
FileData(FileType type,
|
||||||
SystemEnvironmentData* envData, SystemData* system);
|
const std::string& path,
|
||||||
|
SystemEnvironmentData* envData,
|
||||||
|
SystemData* system);
|
||||||
|
|
||||||
virtual ~FileData();
|
virtual ~FileData();
|
||||||
|
|
||||||
|
@ -41,17 +43,19 @@ public:
|
||||||
const bool getKidgame();
|
const bool getKidgame();
|
||||||
const bool getHidden();
|
const bool getHidden();
|
||||||
const bool getCountAsGame();
|
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 bool getExcludeFromScraper();
|
||||||
const std::vector<FileData*> getChildrenRecursive() const;
|
const std::vector<FileData*> getChildrenRecursive() const;
|
||||||
inline FileType getType() const { return mType; }
|
FileType getType() const { return mType; }
|
||||||
inline const std::string& getPath() const { return mPath; }
|
const std::string& getPath() const { return mPath; }
|
||||||
inline FileData* getParent() const { return mParent; }
|
FileData* getParent() const { return mParent; }
|
||||||
inline const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const
|
const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const
|
||||||
{ return mChildrenByFilename; }
|
{
|
||||||
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
|
return mChildrenByFilename;
|
||||||
inline SystemData* getSystem() const { return mSystem; }
|
}
|
||||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
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 getOnlyFoldersFlag() { return mOnlyFolders; }
|
||||||
const bool getHasFoldersFlag() { return mHasFolders; }
|
const bool getHasFoldersFlag() { return mHasFolders; }
|
||||||
static const std::string getROMDirectory();
|
static const std::string getROMDirectory();
|
||||||
|
@ -66,29 +70,31 @@ public:
|
||||||
const std::string getThumbnailPath() const;
|
const std::string getThumbnailPath() const;
|
||||||
const std::string getVideoPath() const;
|
const std::string getVideoPath() const;
|
||||||
|
|
||||||
bool getDeletionFlag() { return mDeletionFlag; };
|
bool getDeletionFlag() { return mDeletionFlag; }
|
||||||
void setDeletionFlag(bool setting) { mDeletionFlag = setting; };
|
void setDeletionFlag(bool setting) { mDeletionFlag = setting; }
|
||||||
|
|
||||||
const std::vector<FileData*>& getChildrenListToDisplay();
|
const std::vector<FileData*>& getChildrenListToDisplay();
|
||||||
std::vector<FileData*> getFilesRecursive(unsigned int typeMask,
|
std::vector<FileData*> getFilesRecursive(unsigned int typeMask,
|
||||||
bool displayedOnly = false, bool countAllGames = true) const;
|
bool displayedOnly = false,
|
||||||
std::vector<FileData*> getScrapeFilesRecursive(bool includeFolders, bool excludeRecursively,
|
bool countAllGames = true) const;
|
||||||
bool respectExclusions) const;
|
std::vector<FileData*> getScrapeFilesRecursive(bool includeFolders,
|
||||||
|
bool excludeRecursively,
|
||||||
|
bool respectExclusions) const;
|
||||||
|
|
||||||
void addChild(FileData* file); // Error if mType != FOLDER
|
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();
|
virtual std::string getKey();
|
||||||
const bool isArcadeAsset();
|
const bool isArcadeAsset();
|
||||||
const bool isArcadeGame();
|
const bool isArcadeGame();
|
||||||
inline std::string getFullPath() { return getPath(); };
|
std::string getFullPath() { return getPath(); }
|
||||||
inline std::string getFileName() { return Utils::FileSystem::getFileName(getPath()); };
|
std::string getFileName() { return Utils::FileSystem::getFileName(getPath()); }
|
||||||
virtual FileData* getSourceFileData();
|
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.
|
// Returns our best guess at the "real" name for this file.
|
||||||
std::string getDisplayName() const;
|
std::string getDisplayName() const;
|
||||||
|
@ -104,19 +110,22 @@ public:
|
||||||
ComparisonFunction* comparisonFunction;
|
ComparisonFunction* comparisonFunction;
|
||||||
std::string description;
|
std::string description;
|
||||||
SortType(ComparisonFunction* sortFunction, const std::string& sortDescription)
|
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);
|
void sort(ComparisonFunction& comparator, std::pair<unsigned int, unsigned int>& gameCount);
|
||||||
void sortFavoritesOnTop(ComparisonFunction& comparator,
|
void sortFavoritesOnTop(ComparisonFunction& comparator,
|
||||||
std::pair<unsigned int, unsigned int>& gameCount);
|
std::pair<unsigned int, unsigned int>& gameCount);
|
||||||
void sort(const SortType& type, bool mFavoritesOnTop = false);
|
void sort(const SortType& type, bool mFavoritesOnTop = false);
|
||||||
MetaDataList metadata;
|
MetaDataList metadata;
|
||||||
// Only count the games, a cheaper alternative to a full sort when that is not required.
|
// 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);
|
void countGames(std::pair<unsigned int, unsigned int>& gameCount);
|
||||||
|
|
||||||
inline void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||||
inline std::string getSortTypeString() { return mSortTypeString; }
|
std::string getSortTypeString() { return mSortTypeString; }
|
||||||
FileData::SortType getSortTypeFromString(std::string desc);
|
FileData::SortType getSortTypeFromString(std::string desc);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -130,7 +139,7 @@ private:
|
||||||
std::string mPath;
|
std::string mPath;
|
||||||
SystemEnvironmentData* mEnvData;
|
SystemEnvironmentData* mEnvData;
|
||||||
SystemData* mSystem;
|
SystemData* mSystem;
|
||||||
std::unordered_map<std::string,FileData*> mChildrenByFilename;
|
std::unordered_map<std::string, FileData*> mChildrenByFilename;
|
||||||
std::vector<FileData*> mChildren;
|
std::vector<FileData*> mChildren;
|
||||||
std::vector<FileData*> mFilteredChildren;
|
std::vector<FileData*> mFilteredChildren;
|
||||||
// The pair includes all games, and favorite games.
|
// The pair includes all games, and favorite games.
|
||||||
|
@ -148,8 +157,8 @@ public:
|
||||||
~CollectionFileData();
|
~CollectionFileData();
|
||||||
const std::string& getName();
|
const std::string& getName();
|
||||||
void refreshMetadata();
|
void refreshMetadata();
|
||||||
FileData* getSourceFileData();
|
FileData* getSourceFileData() { return mSourceFileData; }
|
||||||
std::string getKey();
|
std::string getKey() { return getFullPath(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Needs to be updated when metadata changes.
|
// Needs to be updated when metadata changes.
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
|
|
||||||
#include "math/Misc.h"
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "views/UIModeController.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "math/Misc.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "views/UIModeController.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
@ -21,19 +21,20 @@
|
||||||
#define INCLUDE_UNKNOWN false;
|
#define INCLUDE_UNKNOWN false;
|
||||||
|
|
||||||
FileFilterIndex::FileFilterIndex()
|
FileFilterIndex::FileFilterIndex()
|
||||||
: mFilterByText(false),
|
: mFilterByText(false)
|
||||||
mFilterByFavorites(false),
|
, mFilterByFavorites(false)
|
||||||
mFilterByGenre(false),
|
, mFilterByGenre(false)
|
||||||
mFilterByPlayers(false),
|
, mFilterByPlayers(false)
|
||||||
mFilterByPubDev(false),
|
, mFilterByPubDev(false)
|
||||||
mFilterByRatings(false),
|
, mFilterByRatings(false)
|
||||||
mFilterByKidGame(false),
|
, mFilterByKidGame(false)
|
||||||
mFilterByCompleted(false),
|
, mFilterByCompleted(false)
|
||||||
mFilterByBroken(false),
|
, mFilterByBroken(false)
|
||||||
mFilterByHidden(false)
|
, mFilterByHidden(false)
|
||||||
{
|
{
|
||||||
clearAllFilters();
|
clearAllFilters();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
FilterDataDecl filterDecls[] = {
|
FilterDataDecl filterDecls[] = {
|
||||||
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
||||||
{ FAVORITES_FILTER, &mFavoritesIndexAllKeys, &mFilterByFavorites, &mFavoritesIndexFilteredKeys, "favorite", false, "", "FAVORITES" },
|
{ FAVORITES_FILTER, &mFavoritesIndexAllKeys, &mFilterByFavorites, &mFavoritesIndexFilteredKeys, "favorite", false, "", "FAVORITES" },
|
||||||
|
@ -46,21 +47,18 @@ FileFilterIndex::FileFilterIndex()
|
||||||
{ BROKEN_FILTER, &mBrokenIndexAllKeys, &mFilterByBroken, &mBrokenIndexFilteredKeys, "broken", false, "", "BROKEN" },
|
{ BROKEN_FILTER, &mBrokenIndexAllKeys, &mFilterByBroken, &mBrokenIndexFilteredKeys, "broken", false, "", "BROKEN" },
|
||||||
{ HIDDEN_FILTER, &mHiddenIndexAllKeys, &mFilterByHidden, &mHiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN" }
|
{ HIDDEN_FILTER, &mHiddenIndexAllKeys, &mFilterByHidden, &mHiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN" }
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
filterDataDecl = std::vector<FilterDataDecl>(filterDecls, filterDecls +
|
filterDataDecl = std::vector<FilterDataDecl>(
|
||||||
sizeof(filterDecls) / sizeof(filterDecls[0]));
|
filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileFilterIndex::~FileFilterIndex()
|
FileFilterIndex::~FileFilterIndex()
|
||||||
{
|
{
|
||||||
|
// Reset the index when destroyed.
|
||||||
resetIndex();
|
resetIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FilterDataDecl>& FileFilterIndex::getFilterDataDecls()
|
|
||||||
{
|
|
||||||
return filterDataDecl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
||||||
{
|
{
|
||||||
struct IndexImportStructure {
|
struct IndexImportStructure {
|
||||||
|
@ -80,22 +78,23 @@ void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
||||||
{ &mHiddenIndexAllKeys, &(indexToImport->mHiddenIndexAllKeys) },
|
{ &mHiddenIndexAllKeys, &(indexToImport->mHiddenIndexAllKeys) },
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<IndexImportStructure> indexImportDecl =
|
std::vector<IndexImportStructure> indexImportDecl = std::vector<IndexImportStructure>(
|
||||||
std::vector<IndexImportStructure>(indexStructDecls, indexStructDecls +
|
indexStructDecls,
|
||||||
sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
indexStructDecls + sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
||||||
|
|
||||||
for (std::vector<IndexImportStructure>::const_iterator indexesIt =
|
for (std::vector<IndexImportStructure>::const_iterator indexesIt = indexImportDecl.cbegin();
|
||||||
indexImportDecl.cbegin(); indexesIt != indexImportDecl.cend(); indexesIt++)
|
indexesIt != indexImportDecl.cend(); indexesIt++) {
|
||||||
{
|
|
||||||
for (std::map<std::string, int>::const_iterator sourceIt =
|
for (std::map<std::string, int>::const_iterator sourceIt =
|
||||||
(*indexesIt).sourceIndex->cbegin(); sourceIt !=
|
(*indexesIt).sourceIndex->cbegin();
|
||||||
(*indexesIt).sourceIndex->cend(); sourceIt++) {
|
sourceIt != (*indexesIt).sourceIndex->cend(); sourceIt++) {
|
||||||
if ((*indexesIt).destinationIndex->find((*sourceIt).first) ==
|
if ((*indexesIt).destinationIndex->find((*sourceIt).first) ==
|
||||||
(*indexesIt).destinationIndex->cend())
|
(*indexesIt).destinationIndex->cend()) {
|
||||||
// Entry doesn't exist.
|
// Entry doesn't exist.
|
||||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
|
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
|
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +114,8 @@ void FileFilterIndex::resetIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FileFilterIndex::getIndexableKey(FileData* game,
|
std::string FileFilterIndex::getIndexableKey(FileData* game,
|
||||||
FilterIndexType type, bool getSecondary)
|
FilterIndexType type,
|
||||||
|
bool getSecondary)
|
||||||
{
|
{
|
||||||
std::string key = "";
|
std::string key = "";
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -166,8 +166,8 @@ std::string FileFilterIndex::getIndexableKey(FileData* game,
|
||||||
// These values should only exist if a third party application has
|
// These values should only exist if a third party application has
|
||||||
// been used for scraping the ratings, or if the gamelist.xml file
|
// been used for scraping the ratings, or if the gamelist.xml file
|
||||||
// has been manually edited.
|
// has been manually edited.
|
||||||
ratingNumber = static_cast<int>(
|
ratingNumber =
|
||||||
(ceilf(stof(ratingString) / 0.1f) / 10) * 5);
|
static_cast<int>((ceilf(stof(ratingString) / 0.1f) / 10.0f) * 5.0f);
|
||||||
|
|
||||||
if (ratingNumber < 0)
|
if (ratingNumber < 0)
|
||||||
ratingNumber = 0;
|
ratingNumber = 0;
|
||||||
|
@ -176,11 +176,11 @@ std::string FileFilterIndex::getIndexableKey(FileData* game,
|
||||||
key = "5 STARS";
|
key = "5 STARS";
|
||||||
else
|
else
|
||||||
key = std::to_string(ratingNumber) + " - " +
|
key = std::to_string(ratingNumber) + " - " +
|
||||||
std::to_string(ratingNumber) + ".5 STARS";
|
std::to_string(ratingNumber) + ".5 STARS";
|
||||||
}
|
}
|
||||||
catch (int e) {
|
catch (int e) {
|
||||||
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): " <<
|
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): "
|
||||||
ratingString << ", " << e;
|
<< ratingString << ", " << e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,13 +254,13 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>*
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||||
it != filterDataDecl.cend(); it++) {
|
it != filterDataDecl.cend(); it++) {
|
||||||
if ((*it).type == type) {
|
if ((*it).type == type) {
|
||||||
FilterDataDecl filterData = (*it);
|
FilterDataDecl filterData = (*it);
|
||||||
*(filterData.filteredByRef) = values->size() > 0;
|
*(filterData.filteredByRef) = values->size() > 0;
|
||||||
filterData.currentFilteredKeys->clear();
|
filterData.currentFilteredKeys->clear();
|
||||||
for (std::vector<std::string>::const_iterator vit =
|
for (std::vector<std::string>::const_iterator vit = values->cbegin();
|
||||||
values->cbegin(); vit != values->cend(); vit++) {
|
vit != values->cend(); vit++) {
|
||||||
// Check if it exists.
|
// Check if it exists.
|
||||||
if (filterData.allIndexKeys->find(*vit) != filterData.allIndexKeys->cend()) {
|
if (filterData.allIndexKeys->find(*vit) != filterData.allIndexKeys->cend()) {
|
||||||
filterData.currentFilteredKeys->push_back(std::string(*vit));
|
filterData.currentFilteredKeys->push_back(std::string(*vit));
|
||||||
|
@ -272,20 +272,20 @@ void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>*
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileFilterIndex::setTextFilter(std::string textFilter)
|
void FileFilterIndex::setTextFilter(std::string textFilter)
|
||||||
{
|
{
|
||||||
mTextFilter = textFilter;
|
mTextFilter = textFilter;
|
||||||
|
|
||||||
if (textFilter == "")
|
if (textFilter == "")
|
||||||
mFilterByText = false;
|
mFilterByText = false;
|
||||||
else
|
else
|
||||||
mFilterByText = true;
|
mFilterByText = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void FileFilterIndex::clearAllFilters()
|
void FileFilterIndex::clearAllFilters()
|
||||||
{
|
{
|
||||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||||
it != filterDataDecl.cend(); it++) {
|
it != filterDataDecl.cend(); it++) {
|
||||||
FilterDataDecl filterData = (*it);
|
FilterDataDecl filterData = (*it);
|
||||||
*(filterData.filteredByRef) = false;
|
*(filterData.filteredByRef) = false;
|
||||||
filterData.currentFilteredKeys->clear();
|
filterData.currentFilteredKeys->clear();
|
||||||
|
@ -312,19 +312,19 @@ void FileFilterIndex::setKidModeFilters()
|
||||||
void FileFilterIndex::debugPrintIndexes()
|
void FileFilterIndex::debugPrintIndexes()
|
||||||
{
|
{
|
||||||
LOG(LogInfo) << "Printing Indexes...";
|
LOG(LogInfo) << "Printing Indexes...";
|
||||||
for (auto x: mFavoritesIndexAllKeys) {
|
for (auto x : mFavoritesIndexAllKeys) {
|
||||||
LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
|
LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
|
||||||
}
|
}
|
||||||
for (auto x: mGenreIndexAllKeys) {
|
for (auto x : mGenreIndexAllKeys) {
|
||||||
LOG(LogInfo) << "Genre Index: " << x.first << ": " << x.second;
|
LOG(LogInfo) << "Genre Index: " << x.first << ": " << x.second;
|
||||||
}
|
}
|
||||||
for (auto x: mPlayersIndexAllKeys) {
|
for (auto x : mPlayersIndexAllKeys) {
|
||||||
LOG(LogInfo) << "Multiplayer Index: " << x.first << ": " << x.second;
|
LOG(LogInfo) << "Multiplayer Index: " << x.first << ": " << x.second;
|
||||||
}
|
}
|
||||||
for (auto x: mPubDevIndexAllKeys) {
|
for (auto x : mPubDevIndexAllKeys) {
|
||||||
LOG(LogInfo) << "PubDev Index: " << x.first << ": " << x.second;
|
LOG(LogInfo) << "PubDev Index: " << x.first << ": " << x.second;
|
||||||
}
|
}
|
||||||
for (auto x: mRatingsIndexAllKeys) {
|
for (auto x : mRatingsIndexAllKeys) {
|
||||||
LOG(LogInfo) << "Ratings Index: " << x.first << ": " << x.second;
|
LOG(LogInfo) << "Ratings Index: " << x.first << ": " << x.second;
|
||||||
}
|
}
|
||||||
for (auto x : mKidGameIndexAllKeys) {
|
for (auto x : mKidGameIndexAllKeys) {
|
||||||
|
@ -348,8 +348,8 @@ bool FileFilterIndex::showFile(FileData* game)
|
||||||
if (game->getType() == FOLDER) {
|
if (game->getType() == FOLDER) {
|
||||||
std::vector<FileData*> children = game->getChildren();
|
std::vector<FileData*> children = game->getChildren();
|
||||||
// Iterate through all of the children, until there's a match.
|
// Iterate through all of the children, until there's a match.
|
||||||
for (std::vector<FileData*>::const_iterator it = children.cbegin();
|
for (std::vector<FileData*>::const_iterator it = children.cbegin(); it != children.cend();
|
||||||
it != children.cend(); it++) {
|
it++) {
|
||||||
if (showFile(*it))
|
if (showFile(*it))
|
||||||
return true;
|
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
|
// Name filters take precedence over all other filters, so if there is no match for
|
||||||
// the game name, then always return false.
|
// the game name, then always return false.
|
||||||
if (mTextFilter != "" && !(Utils::String::toUpper(game->
|
if (mTextFilter != "" &&
|
||||||
getName()).find(mTextFilter) != std::string::npos)) {
|
!(Utils::String::toUpper(game->getName()).find(mTextFilter) != std::string::npos)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (mTextFilter != "") {
|
else if (mTextFilter != "") {
|
||||||
|
@ -370,7 +370,7 @@ bool FileFilterIndex::showFile(FileData* game)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
||||||
it != filterDataDecl.cend(); it++) {
|
it != filterDataDecl.cend(); it++) {
|
||||||
FilterDataDecl filterData = (*it);
|
FilterDataDecl filterData = (*it);
|
||||||
if (filterData.primaryKey == "kidgame" && UIModeController::getInstance()->isUIModeKid()) {
|
if (filterData.primaryKey == "kidgame" && UIModeController::getInstance()->isUIModeKid()) {
|
||||||
return (getIndexableKey(game, filterData.type, false) != "FALSE");
|
return (getIndexableKey(game, filterData.type, false) != "FALSE");
|
||||||
|
@ -419,18 +419,19 @@ bool FileFilterIndex::isFiltered()
|
||||||
|
|
||||||
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
||||||
{
|
{
|
||||||
const FilterIndexType filterTypes[9] = { FAVORITES_FILTER, GENRE_FILTER,
|
const FilterIndexType filterTypes[9] = { FAVORITES_FILTER, GENRE_FILTER, PLAYER_FILTER,
|
||||||
PLAYER_FILTER, PUBDEV_FILTER, RATINGS_FILTER, KIDGAME_FILTER,
|
PUBDEV_FILTER, RATINGS_FILTER, KIDGAME_FILTER,
|
||||||
COMPLETED_FILTER, BROKEN_FILTER, HIDDEN_FILTER };
|
COMPLETED_FILTER, BROKEN_FILTER, HIDDEN_FILTER };
|
||||||
std::vector<std::string> filterKeysList[9] = { mFavoritesIndexFilteredKeys,
|
std::vector<std::string> filterKeysList[9] = {
|
||||||
mGenreIndexFilteredKeys, mPlayersIndexFilteredKeys, mPubDevIndexFilteredKeys,
|
mFavoritesIndexFilteredKeys, mGenreIndexFilteredKeys, mPlayersIndexFilteredKeys,
|
||||||
mRatingsIndexFilteredKeys, mKidGameIndexFilteredKeys, mCompletedIndexFilteredKeys,
|
mPubDevIndexFilteredKeys, mRatingsIndexFilteredKeys, mKidGameIndexFilteredKeys,
|
||||||
mBrokenIndexFilteredKeys, mHiddenIndexFilteredKeys };
|
mCompletedIndexFilteredKeys, mBrokenIndexFilteredKeys, mHiddenIndexFilteredKeys
|
||||||
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
if (filterTypes[i] == type) {
|
if (filterTypes[i] == type) {
|
||||||
for (std::vector<std::string>::const_iterator it = filterKeysList[i].cbegin();
|
for (std::vector<std::string>::const_iterator it = filterKeysList[i].cbegin();
|
||||||
it != filterKeysList[i].cend(); it++) {
|
it != filterKeysList[i].cend(); it++) {
|
||||||
if (key == (*it))
|
if (key == (*it))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -589,7 +590,8 @@ void FileFilterIndex::manageHiddenEntryInIndex(FileData* game, bool remove)
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
||||||
std::string key, bool remove)
|
std::string key,
|
||||||
|
bool remove)
|
||||||
{
|
{
|
||||||
bool includeUnknown = INCLUDE_UNKNOWN;
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
||||||
if (!includeUnknown && key == UNKNOWN_LABEL)
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
||||||
|
@ -600,7 +602,7 @@ void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
||||||
if (index->find(key) == index->cend()) {
|
if (index->find(key) == index->cend()) {
|
||||||
// Disabled for now as this could happen because default values are assigned as
|
// 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.
|
// 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 {
|
else {
|
||||||
(index->at(key))--;
|
(index->at(key))--;
|
||||||
|
@ -617,8 +619,3 @@ void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
||||||
(index->at(key))++;
|
(index->at(key))++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileFilterIndex::clearIndex(std::map<std::string, int>& indexMap)
|
|
||||||
{
|
|
||||||
indexMap.clear();
|
|
||||||
}
|
|
||||||
|
|
|
@ -52,13 +52,13 @@ public:
|
||||||
void removeFromIndex(FileData* game);
|
void removeFromIndex(FileData* game);
|
||||||
void setFilter(FilterIndexType type, std::vector<std::string>* values);
|
void setFilter(FilterIndexType type, std::vector<std::string>* values);
|
||||||
void setTextFilter(std::string textFilter);
|
void setTextFilter(std::string textFilter);
|
||||||
std::string getTextFilter() { return mTextFilter; };
|
std::string getTextFilter() { return mTextFilter; }
|
||||||
void clearAllFilters();
|
void clearAllFilters();
|
||||||
void debugPrintIndexes();
|
void debugPrintIndexes();
|
||||||
bool showFile(FileData* game);
|
bool showFile(FileData* game);
|
||||||
bool isFiltered();
|
bool isFiltered();
|
||||||
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
|
bool isKeyBeingFilteredBy(std::string key, FilterIndexType type);
|
||||||
std::vector<FilterDataDecl>& getFilterDataDecls();
|
std::vector<FilterDataDecl>& getFilterDataDecls() { return filterDataDecl; }
|
||||||
|
|
||||||
void importIndex(FileFilterIndex* indexToImport);
|
void importIndex(FileFilterIndex* indexToImport);
|
||||||
void resetIndex();
|
void resetIndex();
|
||||||
|
@ -81,7 +81,7 @@ private:
|
||||||
|
|
||||||
void manageIndexEntry(std::map<std::string, int>* index, std::string key, bool remove);
|
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;
|
std::string mTextFilter;
|
||||||
bool mFilterByText;
|
bool mFilterByText;
|
||||||
|
@ -117,7 +117,6 @@ private:
|
||||||
std::vector<std::string> mHiddenIndexFilteredKeys;
|
std::vector<std::string> mHiddenIndexFilteredKeys;
|
||||||
|
|
||||||
FileData* mRootFolder;
|
FileData* mRootFolder;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_FILE_FILTER_INDEX_H
|
#endif // ES_APP_FILE_FILTER_INDEX_H
|
||||||
|
|
|
@ -48,8 +48,9 @@ namespace FileSorts
|
||||||
FileData::SortType(&compareSystemDescending, "system, descending")
|
FileData::SortType(&compareSystemDescending, "system, descending")
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<FileData::SortType> SortTypes(typesArr, typesArr +
|
const std::vector<FileData::SortType> SortTypes(typesArr,
|
||||||
sizeof(typesArr)/sizeof(typesArr[0]));
|
typesArr +
|
||||||
|
sizeof(typesArr) / sizeof(typesArr[0]));
|
||||||
|
|
||||||
bool compareName(const FileData* file1, const FileData* file2)
|
bool compareName(const FileData* file1, const FileData* file2)
|
||||||
{
|
{
|
||||||
|
@ -155,11 +156,13 @@ namespace FileSorts
|
||||||
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
||||||
// Any non-numeric value will end up as zero.
|
// Any non-numeric value will end up as zero.
|
||||||
if (!file1Players.empty() &&
|
if (!file1Players.empty() &&
|
||||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit)) {
|
||||||
file1Int = stoi(file1Players);
|
file1Int = stoi(file1Players);
|
||||||
|
}
|
||||||
if (!file2Players.empty() &&
|
if (!file2Players.empty() &&
|
||||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit)) {
|
||||||
file2Int = stoi(file2Players);
|
file2Int = stoi(file2Players);
|
||||||
|
}
|
||||||
return file1Int < file2Int;
|
return file1Int < file2Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +180,13 @@ namespace FileSorts
|
||||||
if (dashPos != std::string::npos)
|
if (dashPos != std::string::npos)
|
||||||
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
||||||
if (!file1Players.empty() &&
|
if (!file1Players.empty() &&
|
||||||
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit)) {
|
||||||
file1Int = stoi(file1Players);
|
file1Int = stoi(file1Players);
|
||||||
|
}
|
||||||
if (!file2Players.empty() &&
|
if (!file2Players.empty() &&
|
||||||
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit)) {
|
||||||
file2Int = stoi(file2Players);
|
file2Int = stoi(file2Players);
|
||||||
|
}
|
||||||
return file1Int > file2Int;
|
return file1Int > file2Int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,16 +206,18 @@ namespace FileSorts
|
||||||
{
|
{
|
||||||
// Only games have playcount metadata.
|
// Only games have playcount metadata.
|
||||||
if (file1->metadata.getType() == GAME_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 (file1)->metadata.getInt("playcount") < (file2)->metadata.getInt("playcount");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool compareTimesPlayedDescending(const FileData* file1, const FileData* file2)
|
bool compareTimesPlayedDescending(const FileData* file1, const FileData* file2)
|
||||||
{
|
{
|
||||||
if (file1->metadata.getType() == GAME_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 (file1)->metadata.getInt("playcount") > (file2)->metadata.getInt("playcount");
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,4 +234,5 @@ namespace FileSorts
|
||||||
std::string system2 = Utils::String::toUpper(file2->getSystemName());
|
std::string system2 = Utils::String::toUpper(file2->getSystemName());
|
||||||
return system1.compare(system2) > 0;
|
return system1.compare(system2) > 0;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
}; // namespace FileSorts
|
||||||
|
|
|
@ -38,6 +38,6 @@ namespace FileSorts
|
||||||
bool compareSystemDescending(const FileData* file1, const FileData* file2);
|
bool compareSystemDescending(const FileData* file1, const FileData* file2);
|
||||||
|
|
||||||
extern const std::vector<FileData::SortType> SortTypes;
|
extern const std::vector<FileData::SortType> SortTypes;
|
||||||
};
|
}; // namespace FileSorts
|
||||||
|
|
||||||
#endif // ES_APP_FILE_SORTS_H
|
#endif // ES_APP_FILE_SORTS_H
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include "Gamelist.h"
|
#include "Gamelist.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
#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);
|
std::string relative = Utils::FileSystem::removeCommonPath(path, root->getPath(), contains);
|
||||||
|
|
||||||
if (!contains) {
|
if (!contains) {
|
||||||
LOG(LogError) << "Path \"" << path << "\" is outside system path \"" <<
|
LOG(LogError) << "Path \"" << path << "\" is outside system path \""
|
||||||
system->getStartPath() << "\"";
|
<< system->getStartPath() << "\"";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
||||||
bool found = false;
|
bool found = false;
|
||||||
while (path_it != pathList.end()) {
|
while (path_it != pathList.end()) {
|
||||||
const std::unordered_map<std::string, FileData*>& children =
|
const std::unordered_map<std::string, FileData*>& children =
|
||||||
treeNode->getChildrenByFilename();
|
treeNode->getChildrenByFilename();
|
||||||
|
|
||||||
std::string key = *path_it;
|
std::string key = *path_it;
|
||||||
found = children.find(key) != children.cend();
|
found = children.find(key) != children.cend();
|
||||||
|
@ -71,8 +71,9 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create missing folder.
|
// Create missing folder.
|
||||||
FileData* folder = new FileData(FOLDER, Utils::FileSystem::getStem(treeNode->getPath())
|
FileData* folder = new FileData(
|
||||||
+ "/" + *path_it, system->getSystemEnvData(), system);
|
FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it,
|
||||||
|
system->getSystemEnvData(), system);
|
||||||
treeNode->addChild(folder);
|
treeNode->addChild(folder);
|
||||||
treeNode = folder;
|
treeNode = folder;
|
||||||
}
|
}
|
||||||
|
@ -89,24 +90,24 @@ void parseGamelist(SystemData* system)
|
||||||
std::string xmlpath = system->getGamelistPath(false);
|
std::string xmlpath = system->getGamelistPath(false);
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(xmlpath)) {
|
if (!Utils::FileSystem::exists(xmlpath)) {
|
||||||
LOG(LogDebug) << "Gamelist::parseGamelist(): System \"" << system->getName() <<
|
LOG(LogDebug) << "Gamelist::parseGamelist(): System \"" << system->getName()
|
||||||
"\" does not have a gamelist.xml file";
|
<< "\" does not have a gamelist.xml file";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LogInfo) << "Parsing gamelist file \"" << xmlpath << "\"...";
|
LOG(LogInfo) << "Parsing gamelist file \"" << xmlpath << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result result =
|
pugi::xml_parse_result result =
|
||||||
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
||||||
#else
|
#else
|
||||||
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlpath <<
|
LOG(LogError) << "Error parsing gamelist file \"" << xmlpath
|
||||||
"\": " << result.description();
|
<< "\": " << result.description();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,24 +125,24 @@ void parseGamelist(SystemData* system)
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
std::string tag = tagList[i];
|
std::string tag = tagList[i];
|
||||||
FileType type = typeList[i];
|
FileType type = typeList[i];
|
||||||
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode; fileNode =
|
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode;
|
||||||
fileNode.next_sibling(tag.c_str())) {
|
fileNode = fileNode.next_sibling(tag.c_str())) {
|
||||||
const std::string path =
|
const std::string path = Utils::FileSystem::resolveRelativePath(
|
||||||
Utils::FileSystem::resolveRelativePath(fileNode.child("path").text().get(),
|
fileNode.child("path").text().get(), relativeTo, false);
|
||||||
relativeTo, false);
|
|
||||||
|
|
||||||
if (!trustGamelist && !Utils::FileSystem::exists(path)) {
|
if (!trustGamelist && !Utils::FileSystem::exists(path)) {
|
||||||
LOG(LogWarning) << (type == GAME ? "File \"" : "Folder \"") << path <<
|
LOG(LogWarning) << (type == GAME ? "File \"" : "Folder \"") << path
|
||||||
"\" does not exist, ignoring entry";
|
<< "\" does not exist, ignoring entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip hidden files, check both the file itself and the directory in which
|
// Skip hidden files, check both the file itself and the directory in which
|
||||||
// it is located.
|
// it is located.
|
||||||
if (!showHiddenFiles && (Utils::FileSystem::isHidden(path) ||
|
if (!showHiddenFiles &&
|
||||||
Utils::FileSystem::isHidden(Utils::FileSystem::getParent(path)))) {
|
(Utils::FileSystem::isHidden(path) ||
|
||||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden file \"" <<
|
Utils::FileSystem::isHidden(Utils::FileSystem::getParent(path)))) {
|
||||||
path << "\"";
|
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden file \"" << path
|
||||||
|
<< "\"";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +164,8 @@ void parseGamelist(SystemData* system)
|
||||||
else {
|
else {
|
||||||
// Skip arcade asset entries as these will not be used in any way inside
|
// Skip arcade asset entries as these will not be used in any way inside
|
||||||
// the application.
|
// the application.
|
||||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping arcade asset \"" <<
|
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping arcade asset \""
|
||||||
file->getName() << "\"";
|
<< file->getName() << "\"";
|
||||||
delete file;
|
delete file;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -174,9 +175,10 @@ void parseGamelist(SystemData* system)
|
||||||
// application restart.
|
// application restart.
|
||||||
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
||||||
if (file->getHidden()) {
|
if (file->getHidden()) {
|
||||||
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden " <<
|
LOG(LogDebug) << "Gamelist::parseGamelist(): Skipping hidden "
|
||||||
(type == GAME ? "file" : "folder") << " entry \"" <<
|
<< (type == GAME ? "file" : "folder") << " entry \""
|
||||||
file->getName() << "\"" << " (\"" << file->getPath() << "\")";
|
<< file->getName() << "\""
|
||||||
|
<< " (\"" << file->getPath() << "\")";
|
||||||
delete file;
|
delete file;
|
||||||
}
|
}
|
||||||
// Also delete any folders which are empty, i.e. all their entries are hidden.
|
// 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,
|
void addFileDataNode(pugi::xml_node& parent,
|
||||||
const std::string& tag, SystemData* system)
|
const FileData* file,
|
||||||
|
const std::string& tag,
|
||||||
|
SystemData* system)
|
||||||
{
|
{
|
||||||
// Create game and add to parent node.
|
// Create game and add to parent node.
|
||||||
pugi::xml_node newNode = parent.append_child(tag.c_str());
|
pugi::xml_node newNode = parent.append_child(tag.c_str());
|
||||||
|
@ -199,8 +203,8 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file,
|
||||||
|
|
||||||
// First element is "name", there's only one element and the name is the default.
|
// First element is "name", there's only one element and the name is the default.
|
||||||
if (newNode.children().begin() == newNode.child("name") &&
|
if (newNode.children().begin() == newNode.child("name") &&
|
||||||
++newNode.children().begin() == newNode.children().end() &&
|
++newNode.children().begin() == newNode.children().end() &&
|
||||||
newNode.child("name").text().get() == file->getDisplayName()) {
|
newNode.child("name").text().get() == file->getDisplayName()) {
|
||||||
|
|
||||||
// If the only info is the default name, don't bother
|
// If the only info is the default name, don't bother
|
||||||
// with this node, delete it and ultimately do nothing.
|
// with this node, delete it and ultimately do nothing.
|
||||||
|
@ -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
|
// Try and make the path relative if we can so things still
|
||||||
// work if we change the ROM folder location in the future.
|
// work if we change the ROM folder location in the future.
|
||||||
newNode.prepend_child("path").text().set(Utils::FileSystem::createRelativePath(file->
|
newNode.prepend_child("path").text().set(
|
||||||
getPath(), system->getStartPath(), false).c_str());
|
Utils::FileSystem::createRelativePath(file->getPath(), system->getStartPath(), false)
|
||||||
|
.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,23 +237,23 @@ void updateGamelist(SystemData* system)
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(xmlReadPath)) {
|
if (Utils::FileSystem::exists(xmlReadPath)) {
|
||||||
// Parse an existing file first.
|
// Parse an existing file first.
|
||||||
#if defined(_WIN64)
|
|
||||||
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result result =
|
pugi::xml_parse_result result =
|
||||||
doc.load_file(Utils::String::stringToWideString(xmlReadPath).c_str());
|
doc.load_file(Utils::String::stringToWideString(xmlReadPath).c_str());
|
||||||
#else
|
#else
|
||||||
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
|
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG(LogError) << "Error parsing gamelist file \"" << xmlReadPath << "\": " <<
|
LOG(LogError) << "Error parsing gamelist file \"" << xmlReadPath
|
||||||
result.description();
|
<< "\": " << result.description();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
root = doc.child("gameList");
|
root = doc.child("gameList");
|
||||||
if (!root) {
|
if (!root) {
|
||||||
LOG(LogError) << "Couldn't find <gameList> node in gamelist \"" <<
|
LOG(LogError) << "Couldn't find <gameList> node in gamelist \"" << xmlReadPath << "\"";
|
||||||
xmlReadPath << "\"";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,8 +271,8 @@ void updateGamelist(SystemData* system)
|
||||||
// Get only files, no folders.
|
// Get only files, no folders.
|
||||||
std::vector<FileData*> files = rootFolder->getFilesRecursive(GAME | FOLDER);
|
std::vector<FileData*> files = rootFolder->getFilesRecursive(GAME | FOLDER);
|
||||||
// Iterate through all files, checking if they're already in the XML file.
|
// 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++) {
|
fit != files.cend(); fit++) {
|
||||||
const std::string tag = ((*fit)->getType() == GAME) ? "game" : "folder";
|
const std::string tag = ((*fit)->getType() == GAME) ? "game" : "folder";
|
||||||
|
|
||||||
// Do not touch if it wasn't changed and is not flagged for deletion.
|
// Do not touch if it wasn't changed and is not flagged for deletion.
|
||||||
|
@ -277,16 +282,16 @@ void updateGamelist(SystemData* system)
|
||||||
// Check if the file already exists in the XML file.
|
// Check if the file already exists in the XML file.
|
||||||
// If it does, remove the entry before adding it back.
|
// If it does, remove the entry before adding it back.
|
||||||
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode;
|
for (pugi::xml_node fileNode = root.child(tag.c_str()); fileNode;
|
||||||
fileNode = fileNode.next_sibling(tag.c_str())) {
|
fileNode = fileNode.next_sibling(tag.c_str())) {
|
||||||
pugi::xml_node pathNode = fileNode.child("path");
|
pugi::xml_node pathNode = fileNode.child("path");
|
||||||
if (!pathNode) {
|
if (!pathNode) {
|
||||||
LOG(LogError) << "<" << tag << "> node contains no <path> child";
|
LOG(LogError) << "<" << tag << "> node contains no <path> child";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string nodePath = Utils::FileSystem::getCanonicalPath(
|
std::string nodePath =
|
||||||
Utils::FileSystem::resolveRelativePath(pathNode.text().get(),
|
Utils::FileSystem::getCanonicalPath(Utils::FileSystem::resolveRelativePath(
|
||||||
system->getStartPath(), true));
|
pathNode.text().get(), system->getStartPath(), true));
|
||||||
std::string gamePath = Utils::FileSystem::getCanonicalPath((*fit)->getPath());
|
std::string gamePath = Utils::FileSystem::getCanonicalPath((*fit)->getPath());
|
||||||
|
|
||||||
if (nodePath == gamePath) {
|
if (nodePath == gamePath) {
|
||||||
|
@ -312,16 +317,17 @@ void updateGamelist(SystemData* system)
|
||||||
std::string xmlWritePath(system->getGamelistPath(true));
|
std::string xmlWritePath(system->getGamelistPath(true));
|
||||||
Utils::FileSystem::createDirectory(Utils::FileSystem::getParent(xmlWritePath));
|
Utils::FileSystem::createDirectory(Utils::FileSystem::getParent(xmlWritePath));
|
||||||
|
|
||||||
LOG(LogDebug) << "Gamelist::updateGamelist(): Added/updated " << numUpdated <<
|
LOG(LogDebug) << "Gamelist::updateGamelist(): Added/updated " << numUpdated
|
||||||
(numUpdated == 1 ? " entity in \"" : " entities in \"") << xmlReadPath << "\"";
|
<< (numUpdated == 1 ? " entity in \"" : " entities in \"") << xmlReadPath
|
||||||
|
<< "\"";
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
if (!doc.save_file(Utils::String::stringToWideString(xmlWritePath).c_str())) {
|
if (!doc.save_file(Utils::String::stringToWideString(xmlWritePath).c_str())) {
|
||||||
#else
|
#else
|
||||||
if (!doc.save_file(xmlWritePath.c_str())) {
|
if (!doc.save_file(xmlWritePath.c_str())) {
|
||||||
#endif
|
#endif
|
||||||
LOG(LogError) << "Error saving gamelist.xml to \"" <<
|
LOG(LogError) << "Error saving gamelist.xml to \"" << xmlWritePath
|
||||||
xmlWritePath << "\" (for system " << system->getName() << ")";
|
<< "\" (for system " << system->getName() << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,14 @@
|
||||||
#if defined(BUILD_VLC_PLAYER)
|
#if defined(BUILD_VLC_PLAYER)
|
||||||
#include "components/VideoVlcComponent.h"
|
#include "components/VideoVlcComponent.h"
|
||||||
#endif
|
#endif
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "AudioManager.h"
|
#include "AudioManager.h"
|
||||||
#include "Sound.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);
|
mWindow->setMediaViewer(this);
|
||||||
}
|
}
|
||||||
|
@ -85,12 +88,12 @@ void MediaViewer::render()
|
||||||
|
|
||||||
// Render a black background below the game media.
|
// Render a black background below the game media.
|
||||||
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
||||||
|
|
||||||
if (mVideo && !mDisplayingImage) {
|
if (mVideo && !mDisplayingImage) {
|
||||||
mVideo->render(transform);
|
mVideo->render(transform);
|
||||||
|
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
Renderer::shaderParameters videoParameters;
|
Renderer::shaderParameters videoParameters;
|
||||||
unsigned int shaders = 0;
|
unsigned int shaders = 0;
|
||||||
if (Settings::getInstance()->getBool("MediaViewerVideoScanlines"))
|
if (Settings::getInstance()->getBool("MediaViewerVideoScanlines"))
|
||||||
|
@ -98,6 +101,7 @@ void MediaViewer::render()
|
||||||
if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
||||||
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
||||||
float heightModifier = Renderer::getScreenHeightModifier();
|
float heightModifier = Renderer::getScreenHeightModifier();
|
||||||
|
// clang-format off
|
||||||
if (heightModifier < 1)
|
if (heightModifier < 1)
|
||||||
videoParameters.blurPasses = 2; // Below 1080
|
videoParameters.blurPasses = 2; // Below 1080
|
||||||
else if (heightModifier >= 4)
|
else if (heightModifier >= 4)
|
||||||
|
@ -112,18 +116,19 @@ void MediaViewer::render()
|
||||||
videoParameters.blurPasses = 3; // 1440
|
videoParameters.blurPasses = 3; // 1440
|
||||||
else if (heightModifier >= 1)
|
else if (heightModifier >= 1)
|
||||||
videoParameters.blurPasses = 2; // 1080
|
videoParameters.blurPasses = 2; // 1080
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
Renderer::shaderPostprocessing(shaders, videoParameters);
|
Renderer::shaderPostprocessing(shaders, videoParameters);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (mImage && mImage->hasImage() && mImage->getSize() != 0) {
|
else if (mImage && mImage->hasImage() && mImage->getSize() != 0) {
|
||||||
mImage->render(transform);
|
mImage->render(transform);
|
||||||
|
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
if (mCurrentImageIndex == mScreenShotIndex &&
|
if (mCurrentImageIndex == mScreenShotIndex &&
|
||||||
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
|
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"))
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is necessary so that the video loops if viewing an image when
|
// This is necessary so that the video loops if viewing an image when
|
||||||
// the video ends.
|
// the video ends.
|
||||||
|
@ -244,14 +249,14 @@ void MediaViewer::playVideo()
|
||||||
mDisplayingImage = false;
|
mDisplayingImage = false;
|
||||||
ViewController::get()->onStopVideo();
|
ViewController::get()->onStopVideo();
|
||||||
|
|
||||||
#if defined(BUILD_VLC_PLAYER)
|
#if defined(BUILD_VLC_PLAYER)
|
||||||
if (Settings::getInstance()->getString("VideoPlayer") == "ffmpeg")
|
if (Settings::getInstance()->getString("VideoPlayer") == "ffmpeg")
|
||||||
mVideo = new VideoFFmpegComponent(mWindow);
|
mVideo = new VideoFFmpegComponent(mWindow);
|
||||||
else
|
else
|
||||||
mVideo = new VideoVlcComponent(mWindow);
|
mVideo = new VideoVlcComponent(mWindow);
|
||||||
#else
|
#else
|
||||||
mVideo = new VideoFFmpegComponent(mWindow);
|
mVideo = new VideoFFmpegComponent(mWindow);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mVideo->topWindow(true);
|
mVideo->topWindow(true);
|
||||||
mVideo->setOrigin(0.5f, 0.5f);
|
mVideo->setOrigin(0.5f, 0.5f);
|
||||||
|
@ -259,10 +264,10 @@ void MediaViewer::playVideo()
|
||||||
|
|
||||||
if (Settings::getInstance()->getBool("MediaViewerStretchVideos"))
|
if (Settings::getInstance()->getBool("MediaViewerStretchVideos"))
|
||||||
mVideo->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
mVideo->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
else
|
else
|
||||||
mVideo->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
mVideo->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
|
|
||||||
mVideo->setVideo(mVideoFile);
|
mVideo->setVideo(mVideoFile);
|
||||||
mVideo->setMediaViewerMode(true);
|
mVideo->setMediaViewerMode(true);
|
||||||
|
@ -282,6 +287,6 @@ void MediaViewer::showImage(int index)
|
||||||
mImage->setOrigin(0.5f, 0.5f);
|
mImage->setOrigin(0.5f, 0.5f);
|
||||||
mImage->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
|
mImage->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
|
||||||
mImage->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
mImage->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
#ifndef ES_APP_MEDIA_VIEWER_H
|
#ifndef ES_APP_MEDIA_VIEWER_H
|
||||||
#define ES_APP_MEDIA_VIEWER_H
|
#define ES_APP_MEDIA_VIEWER_H
|
||||||
|
|
||||||
#include "components/ImageComponent.h"
|
|
||||||
#include "components/VideoComponent.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
#include "components/ImageComponent.h"
|
||||||
|
#include "components/VideoComponent.h"
|
||||||
|
|
||||||
class MediaViewer : public Window::MediaViewer
|
class MediaViewer : public Window::MediaViewer
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,11 +9,12 @@
|
||||||
|
|
||||||
#include "MetaData.h"
|
#include "MetaData.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
MetaDataDecl gameDecls[] = {
|
MetaDataDecl gameDecls[] = {
|
||||||
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape
|
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd, shouldScrape
|
||||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
{"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}
|
{"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[] = {
|
MetaDataDecl folderDecls[] = {
|
||||||
{"name", MD_STRING, "", false, "name", "enter name", true},
|
{"name", MD_STRING, "", false, "name", "enter name", true},
|
||||||
{"desc", MD_MULTILINE_STRING, "", false, "description", "enter description", 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},
|
{"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}
|
{"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,
|
||||||
sizeof(folderDecls) / sizeof(folderDecls[0]));
|
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)
|
const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case GAME_METADATA:
|
case GAME_METADATA:
|
||||||
return gameMDD;
|
return gameMDD;
|
||||||
case FOLDER_METADATA:
|
case FOLDER_METADATA:
|
||||||
|
@ -77,7 +80,8 @@ const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataList::MetaDataList(MetaDataListType type)
|
MetaDataList::MetaDataList(MetaDataListType type)
|
||||||
: mType(type), mWasChanged(false)
|
: mType(type)
|
||||||
|
, mWasChanged(false)
|
||||||
{
|
{
|
||||||
const std::vector<MetaDataDecl>& mdd = getMDD();
|
const std::vector<MetaDataDecl>& mdd = getMDD();
|
||||||
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++)
|
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++)
|
||||||
|
@ -85,7 +89,8 @@ MetaDataList::MetaDataList(MetaDataListType type)
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDataList MetaDataList::createFromXML(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);
|
MetaDataList mdl(type);
|
||||||
|
|
||||||
|
@ -107,8 +112,9 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type,
|
||||||
return mdl;
|
return mdl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaDataList::appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
void MetaDataList::appendToXML(pugi::xml_node& parent,
|
||||||
const std::string& relativeTo) const
|
bool ignoreDefaults,
|
||||||
|
const std::string& relativeTo) const
|
||||||
{
|
{
|
||||||
const std::vector<MetaDataDecl>& mdd = getMDD();
|
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
|
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)
|
if (mMap.count(key) > 0)
|
||||||
return mMap.at(key);
|
return mMap.at(key);
|
||||||
else
|
else
|
||||||
|
return mNoResult;
|
||||||
return mNoResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MetaDataList::getInt(const std::string& key) const
|
int MetaDataList::getInt(const std::string& key) const
|
||||||
{
|
{
|
||||||
|
// Return integer value.
|
||||||
return atoi(get(key).c_str());
|
return atoi(get(key).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
float MetaDataList::getFloat(const std::string& key) const
|
float MetaDataList::getFloat(const std::string& key) const
|
||||||
{
|
{
|
||||||
|
// Return float value.
|
||||||
return static_cast<float>(atof(get(key).c_str()));
|
return static_cast<float>(atof(get(key).c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetaDataList::wasChanged() const
|
bool MetaDataList::wasChanged() const
|
||||||
{
|
{
|
||||||
|
// Return whether the metadata was changed.
|
||||||
return mWasChanged;
|
return mWasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaDataList::resetChangedFlag()
|
void MetaDataList::resetChangedFlag()
|
||||||
{
|
{
|
||||||
|
// Reset the change flag.
|
||||||
mWasChanged = false;
|
mWasChanged = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,10 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace pugi { class xml_node; }
|
namespace pugi
|
||||||
|
{
|
||||||
|
class xml_node;
|
||||||
|
}
|
||||||
|
|
||||||
enum MetaDataType {
|
enum MetaDataType {
|
||||||
// Generic types.
|
// Generic types.
|
||||||
|
@ -40,7 +43,7 @@ struct MetaDataDecl {
|
||||||
std::string key;
|
std::string key;
|
||||||
MetaDataType type;
|
MetaDataType type;
|
||||||
std::string defaultValue;
|
std::string defaultValue;
|
||||||
// If true, ignore values for this metadata.
|
// If true, ignore values for this metadata.
|
||||||
bool isStatistic;
|
bool isStatistic;
|
||||||
// Displayed as this in editors.
|
// Displayed as this in editors.
|
||||||
std::string displayName;
|
std::string displayName;
|
||||||
|
@ -51,7 +54,7 @@ struct MetaDataDecl {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MetaDataListType {
|
enum MetaDataListType {
|
||||||
GAME_METADATA,
|
GAME_METADATA, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
FOLDER_METADATA
|
FOLDER_METADATA
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,9 +64,11 @@ class MetaDataList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static MetaDataList createFromXML(MetaDataListType type,
|
static MetaDataList createFromXML(MetaDataListType type,
|
||||||
pugi::xml_node& node, const std::string& relativeTo);
|
pugi::xml_node& node,
|
||||||
void appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
const std::string& relativeTo);
|
||||||
const std::string& relativeTo) const;
|
void appendToXML(pugi::xml_node& parent,
|
||||||
|
bool ignoreDefaults,
|
||||||
|
const std::string& relativeTo) const;
|
||||||
|
|
||||||
MetaDataList(MetaDataListType type);
|
MetaDataList(MetaDataListType type);
|
||||||
|
|
||||||
|
@ -76,10 +81,12 @@ public:
|
||||||
bool wasChanged() const;
|
bool wasChanged() const;
|
||||||
void resetChangedFlag();
|
void resetChangedFlag();
|
||||||
|
|
||||||
inline MetaDataListType getType() const { return mType; }
|
MetaDataListType getType() const { return mType; }
|
||||||
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
|
||||||
inline const std::vector<MetaDataDecl>& getMDD(MetaDataListType type) const
|
const std::vector<MetaDataDecl>& getMDD(MetaDataListType type) const
|
||||||
{ return getMDDByType(type); }
|
{
|
||||||
|
return getMDDByType(type);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MetaDataListType mType;
|
MetaDataListType mType;
|
||||||
|
|
|
@ -9,47 +9,45 @@
|
||||||
|
|
||||||
#include "MiximageGenerator.h"
|
#include "MiximageGenerator.h"
|
||||||
|
|
||||||
#include "math/Misc.h"
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "math/Misc.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
MiximageGenerator::MiximageGenerator(FileData* game, std::string& resultMessage)
|
MiximageGenerator::MiximageGenerator(FileData* game, std::string& resultMessage)
|
||||||
: mGame(game),
|
: mGame(game)
|
||||||
mResultMessage(resultMessage),
|
, mResultMessage(resultMessage)
|
||||||
mWidth(1280),
|
, mWidth(1280)
|
||||||
mHeight(960),
|
, mHeight(960)
|
||||||
mMarquee(false),
|
, mMarquee(false)
|
||||||
mBox3D(false),
|
, mBox3D(false)
|
||||||
mCover(false)
|
, mCover(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MiximageGenerator::~MiximageGenerator()
|
MiximageGenerator::~MiximageGenerator() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
||||||
{
|
{
|
||||||
mMiximagePromise = miximagePromise;
|
mMiximagePromise = miximagePromise;
|
||||||
|
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): Creating miximage for \""
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): Creating miximage for \""
|
||||||
<< mGame->getFileName() << "\"";
|
<< mGame->getFileName() << "\"";
|
||||||
|
|
||||||
if (mGame->getMiximagePath() != "" && !Settings::getInstance()->getBool("MiximageOverwrite")) {
|
if (mGame->getMiximagePath() != "" && !Settings::getInstance()->getBool("MiximageOverwrite")) {
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): File already exists and miximage "
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): File already exists and miximage "
|
||||||
"overwriting has not been enabled, aborting";
|
"overwriting has not been enabled, aborting";
|
||||||
mMiximagePromise->set_value(true);
|
mMiximagePromise->set_value(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mScreenshotPath = mGame->getScreenshotPath()) == "") {
|
if ((mScreenshotPath = mGame->getScreenshotPath()) == "") {
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
||||||
"No screenshot image found, aborting";
|
"No screenshot image found, aborting";
|
||||||
mResultMessage = "No screenshot image found, couldn't generate miximage";
|
mResultMessage = "No screenshot image found, couldn't generate miximage";
|
||||||
mMiximagePromise->set_value(true);
|
mMiximagePromise->set_value(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -68,14 +66,14 @@ void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
||||||
mBox3D = true;
|
mBox3D = true;
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getBool("MiximageCoverFallback") &&
|
else if (Settings::getInstance()->getBool("MiximageCoverFallback") &&
|
||||||
(mCoverPath= mGame->getCoverPath()) != "") {
|
(mCoverPath = mGame->getCoverPath()) != "") {
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
||||||
"No 3D box image found, using cover image as fallback";
|
"No 3D box image found, using cover image as fallback";
|
||||||
mCover = true;
|
mCover = true;
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getBool("MiximageCoverFallback")) {
|
else if (Settings::getInstance()->getBool("MiximageCoverFallback")) {
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): "
|
||||||
"No 3D box or cover images found";
|
"No 3D box or cover images found";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): No 3D box image found";
|
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): No 3D box image found";
|
||||||
|
@ -93,9 +91,10 @@ void MiximageGenerator::startThread(std::promise<bool>* miximagePromise)
|
||||||
else {
|
else {
|
||||||
const auto endTime = std::chrono::system_clock::now();
|
const auto endTime = std::chrono::system_clock::now();
|
||||||
|
|
||||||
LOG(LogDebug) << "MiximageGenerator::MiximageGenerator(): Processing completed in: " <<
|
LOG(LogDebug)
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>
|
<< "MiximageGenerator::MiximageGenerator(): Processing completed in: "
|
||||||
(endTime - startTime).count() << " ms";
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count()
|
||||||
|
<< " ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
mResultMessage = mMessage;
|
mResultMessage = mMessage;
|
||||||
|
@ -113,19 +112,19 @@ bool MiximageGenerator::generateImage()
|
||||||
unsigned int fileHeight = 0;
|
unsigned int fileHeight = 0;
|
||||||
unsigned int filePitch = 0;
|
unsigned int filePitch = 0;
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mScreenshotPath).c_str());
|
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFileType(mScreenshotPath.c_str());
|
fileFormat = FreeImage_GetFileType(mScreenshotPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN)
|
if (fileFormat == FIF_UNKNOWN)
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||||
Utils::String::stringToWideString(mScreenshotPath).c_str());
|
Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFIFFromFilename(mScreenshotPath.c_str());
|
fileFormat = FreeImage_GetFIFFromFilename(mScreenshotPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN) {
|
if (fileFormat == FIF_UNKNOWN) {
|
||||||
LOG(LogError) << "Screenshot image in unknown image format, aborting";
|
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.
|
// Make sure that we can actually read this format.
|
||||||
if (FreeImage_FIFSupportsReading(fileFormat)) {
|
if (FreeImage_FIFSupportsReading(fileFormat)) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
screenshotFile = FreeImage_LoadU(fileFormat,
|
screenshotFile =
|
||||||
Utils::String::stringToWideString(mScreenshotPath).c_str());
|
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mScreenshotPath).c_str());
|
||||||
#else
|
#else
|
||||||
screenshotFile = FreeImage_Load(fileFormat, mScreenshotPath.c_str());
|
screenshotFile = FreeImage_Load(fileFormat, mScreenshotPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) << "Screenshot file format not supported";
|
LOG(LogError) << "Screenshot file format not supported";
|
||||||
|
@ -155,20 +154,20 @@ bool MiximageGenerator::generateImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMarquee) {
|
if (mMarquee) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFileTypeU(
|
fileFormat =
|
||||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
FreeImage_GetFileTypeU(Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFileType(mMarqueePath.c_str());
|
fileFormat = FreeImage_GetFileType(mMarqueePath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN)
|
if (fileFormat == FIF_UNKNOWN)
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFIFFromFilename(mMarqueePath.c_str());
|
fileFormat = FreeImage_GetFIFFromFilename(mMarqueePath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN) {
|
if (fileFormat == FIF_UNKNOWN) {
|
||||||
LOG(LogDebug) << "Marquee in unknown format, skipping image";
|
LOG(LogDebug) << "Marquee in unknown format, skipping image";
|
||||||
|
@ -180,12 +179,12 @@ bool MiximageGenerator::generateImage()
|
||||||
mMarquee = false;
|
mMarquee = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
marqueeFile = FreeImage_LoadU(fileFormat,
|
marqueeFile = FreeImage_LoadU(fileFormat,
|
||||||
Utils::String::stringToWideString(mMarqueePath).c_str());
|
Utils::String::stringToWideString(mMarqueePath).c_str());
|
||||||
#else
|
#else
|
||||||
marqueeFile = FreeImage_Load(fileFormat, mMarqueePath.c_str());
|
marqueeFile = FreeImage_Load(fileFormat, mMarqueePath.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (!marqueeFile) {
|
if (!marqueeFile) {
|
||||||
LOG(LogError) << "Couldn't load marquee image, corrupt file?";
|
LOG(LogError) << "Couldn't load marquee image, corrupt file?";
|
||||||
mMessage = "Error loading marquee image, corrupt file?";
|
mMessage = "Error loading marquee image, corrupt file?";
|
||||||
|
@ -195,19 +194,19 @@ bool MiximageGenerator::generateImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mBox3D) {
|
if (mBox3D) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mBox3DPath).c_str());
|
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFileType(mBox3DPath.c_str());
|
fileFormat = FreeImage_GetFileType(mBox3DPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN)
|
if (fileFormat == FIF_UNKNOWN)
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||||
Utils::String::stringToWideString(mBox3DPath).c_str());
|
Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFIFFromFilename(mBox3DPath.c_str());
|
fileFormat = FreeImage_GetFIFFromFilename(mBox3DPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN) {
|
if (fileFormat == FIF_UNKNOWN) {
|
||||||
LOG(LogDebug) << "3D box in unknown format, skipping image";
|
LOG(LogDebug) << "3D box in unknown format, skipping image";
|
||||||
|
@ -219,12 +218,12 @@ bool MiximageGenerator::generateImage()
|
||||||
mBox3D = false;
|
mBox3D = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
boxFile = FreeImage_LoadU(fileFormat,
|
boxFile =
|
||||||
Utils::String::stringToWideString(mBox3DPath).c_str());
|
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mBox3DPath).c_str());
|
||||||
#else
|
#else
|
||||||
boxFile = FreeImage_Load(fileFormat, mBox3DPath.c_str());
|
boxFile = FreeImage_Load(fileFormat, mBox3DPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (!boxFile) {
|
if (!boxFile) {
|
||||||
LOG(LogError) << "Couldn't load 3D box image, corrupt file?";
|
LOG(LogError) << "Couldn't load 3D box image, corrupt file?";
|
||||||
mMessage = "Error loading 3d box image, corrupt file?";
|
mMessage = "Error loading 3d box image, corrupt file?";
|
||||||
|
@ -233,20 +232,19 @@ bool MiximageGenerator::generateImage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mCover) {
|
else if (mCover) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFileTypeU(
|
fileFormat = FreeImage_GetFileTypeU(Utils::String::stringToWideString(mCoverPath).c_str());
|
||||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
#else
|
||||||
#else
|
|
||||||
fileFormat = FreeImage_GetFileType(mCoverPath.c_str());
|
fileFormat = FreeImage_GetFileType(mCoverPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN)
|
if (fileFormat == FIF_UNKNOWN)
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
fileFormat = FreeImage_GetFIFFromFilenameU(
|
fileFormat = FreeImage_GetFIFFromFilenameU(
|
||||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
Utils::String::stringToWideString(mCoverPath).c_str());
|
||||||
#else
|
#else
|
||||||
fileFormat = FreeImage_GetFIFFromFilename(mCoverPath.c_str());
|
fileFormat = FreeImage_GetFIFFromFilename(mCoverPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fileFormat == FIF_UNKNOWN) {
|
if (fileFormat == FIF_UNKNOWN) {
|
||||||
LOG(LogDebug) << "Box cover in unknown format, skipping image";
|
LOG(LogDebug) << "Box cover in unknown format, skipping image";
|
||||||
|
@ -258,12 +256,12 @@ bool MiximageGenerator::generateImage()
|
||||||
mCover = false;
|
mCover = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
boxFile = FreeImage_LoadU(fileFormat,
|
boxFile =
|
||||||
Utils::String::stringToWideString(mCoverPath).c_str());
|
FreeImage_LoadU(fileFormat, Utils::String::stringToWideString(mCoverPath).c_str());
|
||||||
#else
|
#else
|
||||||
boxFile = FreeImage_Load(fileFormat, mCoverPath.c_str());
|
boxFile = FreeImage_Load(fileFormat, mCoverPath.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (!boxFile) {
|
if (!boxFile) {
|
||||||
LOG(LogError) << "Couldn't load box cover image, corrupt file?";
|
LOG(LogError) << "Couldn't load box cover image, corrupt file?";
|
||||||
mMessage = "Error loading box cover image, corrupt file?";
|
mMessage = "Error loading box cover image, corrupt file?";
|
||||||
|
@ -318,7 +316,7 @@ bool MiximageGenerator::generateImage()
|
||||||
std::vector<unsigned char> screenshotVector(fileWidth * fileHeight * 4);
|
std::vector<unsigned char> screenshotVector(fileWidth * fileHeight * 4);
|
||||||
|
|
||||||
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&screenshotVector.at(0)), screenshotFile,
|
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&screenshotVector.at(0)), screenshotFile,
|
||||||
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
||||||
|
|
||||||
CImg<unsigned char> screenshotImage(fileWidth, fileHeight, 1, 4, 0);
|
CImg<unsigned char> screenshotImage(fileWidth, fileHeight, 1, 4, 0);
|
||||||
|
|
||||||
|
@ -386,10 +384,10 @@ bool MiximageGenerator::generateImage()
|
||||||
std::vector<unsigned char> marqueeVector(fileWidth * fileHeight * 4);
|
std::vector<unsigned char> marqueeVector(fileWidth * fileHeight * 4);
|
||||||
|
|
||||||
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&marqueeVector.at(0)), marqueeFile,
|
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&marqueeVector.at(0)), marqueeFile,
|
||||||
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
||||||
|
|
||||||
marqueeImage = CImg<unsigned char>(FreeImage_GetWidth(marqueeFile),
|
marqueeImage = CImg<unsigned char>(FreeImage_GetWidth(marqueeFile),
|
||||||
FreeImage_GetHeight(marqueeFile), 1, 4, 0);
|
FreeImage_GetHeight(marqueeFile), 1, 4, 0);
|
||||||
|
|
||||||
Utils::CImg::convertRGBAToCImg(marqueeVector, marqueeImage);
|
Utils::CImg::convertRGBAToCImg(marqueeVector, marqueeImage);
|
||||||
Utils::CImg::removeTransparentPadding(marqueeImage);
|
Utils::CImg::removeTransparentPadding(marqueeImage);
|
||||||
|
@ -409,7 +407,7 @@ bool MiximageGenerator::generateImage()
|
||||||
yPosMarquee = 0;
|
yPosMarquee = 0;
|
||||||
|
|
||||||
// Only RGB channels for the image.
|
// 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.
|
// Only alpha channel for the image.
|
||||||
marqueeImageAlpha = CImg<unsigned char>(marqueeImage.get_shared_channel(3));
|
marqueeImageAlpha = CImg<unsigned char>(marqueeImage.get_shared_channel(3));
|
||||||
}
|
}
|
||||||
|
@ -427,17 +425,17 @@ bool MiximageGenerator::generateImage()
|
||||||
|
|
||||||
std::vector<unsigned char> boxVector(fileWidth * fileHeight * 4);
|
std::vector<unsigned char> boxVector(fileWidth * fileHeight * 4);
|
||||||
|
|
||||||
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&boxVector.at(0)), boxFile,
|
FreeImage_ConvertToRawBits(reinterpret_cast<BYTE*>(&boxVector.at(0)), boxFile, filePitch,
|
||||||
filePitch, 32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
32, FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE, 1);
|
||||||
|
|
||||||
boxImage = CImg<unsigned char>(FreeImage_GetWidth(boxFile),
|
boxImage =
|
||||||
FreeImage_GetHeight(boxFile), 1, 4);
|
CImg<unsigned char>(FreeImage_GetWidth(boxFile), FreeImage_GetHeight(boxFile), 1, 4);
|
||||||
|
|
||||||
Utils::CImg::convertRGBAToCImg(boxVector, boxImage);
|
Utils::CImg::convertRGBAToCImg(boxVector, boxImage);
|
||||||
Utils::CImg::removeTransparentPadding(boxImage);
|
Utils::CImg::removeTransparentPadding(boxImage);
|
||||||
|
|
||||||
float scaleFactor = static_cast<float>(boxTargetHeight) /
|
float scaleFactor =
|
||||||
static_cast<float>(boxImage.height());
|
static_cast<float>(boxTargetHeight) / static_cast<float>(boxImage.height());
|
||||||
unsigned int width = static_cast<int>(static_cast<float>(boxImage.width()) * scaleFactor);
|
unsigned int width = static_cast<int>(static_cast<float>(boxImage.width()) * scaleFactor);
|
||||||
unsigned int targetWidth = 0;
|
unsigned int targetWidth = 0;
|
||||||
|
|
||||||
|
@ -464,7 +462,7 @@ bool MiximageGenerator::generateImage()
|
||||||
yPosBox = canvasImage.height() - boxImage.height();
|
yPosBox = canvasImage.height() - boxImage.height();
|
||||||
|
|
||||||
// Only RGB channels for the image.
|
// 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.
|
// Only alpha channel for the image.
|
||||||
boxImageAlpha = CImg<unsigned char>(boxImage.get_shared_channel(3));
|
boxImageAlpha = CImg<unsigned char>(boxImage.get_shared_channel(3));
|
||||||
}
|
}
|
||||||
|
@ -478,20 +476,15 @@ bool MiximageGenerator::generateImage()
|
||||||
sampleFrameColor(screenshotImage, frameColor);
|
sampleFrameColor(screenshotImage, frameColor);
|
||||||
|
|
||||||
// Upper / lower frame.
|
// Upper / lower frame.
|
||||||
frameImage.draw_rectangle(
|
frameImage.draw_rectangle(xPosScreenshot + 2, yPosScreenshot - screenshotFrameWidth,
|
||||||
xPosScreenshot + 2,
|
xPosScreenshot + screenshotWidth - 2,
|
||||||
yPosScreenshot - screenshotFrameWidth,
|
yPosScreenshot + screenshotHeight + screenshotFrameWidth - 1,
|
||||||
xPosScreenshot + screenshotWidth - 2,
|
frameColor);
|
||||||
yPosScreenshot + screenshotHeight + screenshotFrameWidth - 1,
|
|
||||||
frameColor);
|
|
||||||
|
|
||||||
// Left / right frame.
|
// Left / right frame.
|
||||||
frameImage.draw_rectangle(
|
frameImage.draw_rectangle(xPosScreenshot - screenshotFrameWidth, yPosScreenshot + 2,
|
||||||
xPosScreenshot - screenshotFrameWidth,
|
xPosScreenshot + screenshotWidth + screenshotFrameWidth - 1,
|
||||||
yPosScreenshot + 2,
|
yPosScreenshot + screenshotHeight - 2, frameColor);
|
||||||
xPosScreenshot + screenshotWidth + screenshotFrameWidth - 1,
|
|
||||||
yPosScreenshot + screenshotHeight - 2,
|
|
||||||
frameColor);
|
|
||||||
|
|
||||||
// We draw circles in order to get rounded corners for the frame.
|
// We draw circles in order to get rounded corners for the frame.
|
||||||
const unsigned int circleRadius = 8 * resolutionMultiplier;
|
const unsigned int circleRadius = 8 * resolutionMultiplier;
|
||||||
|
@ -499,16 +492,18 @@ bool MiximageGenerator::generateImage()
|
||||||
|
|
||||||
// Upper left corner.
|
// Upper left corner.
|
||||||
frameImage.draw_circle(xPosScreenshot + circleOffset, yPosScreenshot + circleOffset,
|
frameImage.draw_circle(xPosScreenshot + circleOffset, yPosScreenshot + circleOffset,
|
||||||
circleRadius, frameColor);
|
circleRadius, frameColor);
|
||||||
// Upper right corner.
|
// Upper right corner.
|
||||||
frameImage.draw_circle(xPosScreenshot + screenshotWidth - circleOffset - 1,
|
frameImage.draw_circle(xPosScreenshot + screenshotWidth - circleOffset - 1,
|
||||||
yPosScreenshot + circleOffset, circleRadius, frameColor);
|
yPosScreenshot + circleOffset, circleRadius, frameColor);
|
||||||
// Lower right corner.
|
// Lower right corner.
|
||||||
frameImage.draw_circle(xPosScreenshot + screenshotWidth - circleOffset - 1,
|
frameImage.draw_circle(xPosScreenshot + screenshotWidth - circleOffset - 1,
|
||||||
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius, frameColor);
|
yPosScreenshot + screenshotHeight - circleOffset - 1, circleRadius,
|
||||||
|
frameColor);
|
||||||
// Lower left corner.
|
// Lower left corner.
|
||||||
frameImage.draw_circle(xPosScreenshot + circleOffset,
|
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));
|
CImg<unsigned char> frameImageRGB(frameImage.get_shared_channels(0, 2));
|
||||||
|
|
||||||
|
@ -516,8 +511,8 @@ bool MiximageGenerator::generateImage()
|
||||||
canvasImage.draw_image(xPosScreenshot, yPosScreenshot, screenshotImage);
|
canvasImage.draw_image(xPosScreenshot, yPosScreenshot, screenshotImage);
|
||||||
|
|
||||||
if (mMarquee)
|
if (mMarquee)
|
||||||
canvasImage.draw_image(xPosMarquee, yPosMarquee, marqueeImageRGB,
|
canvasImage.draw_image(xPosMarquee, yPosMarquee, marqueeImageRGB, marqueeImageAlpha, 1,
|
||||||
marqueeImageAlpha, 1, 255);
|
255);
|
||||||
if (mBox3D || mCover)
|
if (mBox3D || mCover)
|
||||||
canvasImage.draw_image(xPosBox, yPosBox, boxImageRGB, boxImageAlpha, 1, 255);
|
canvasImage.draw_image(xPosBox, yPosBox, boxImageRGB, boxImageAlpha, 1, 255);
|
||||||
|
|
||||||
|
@ -528,15 +523,16 @@ bool MiximageGenerator::generateImage()
|
||||||
|
|
||||||
FIBITMAP* mixImage = nullptr;
|
FIBITMAP* mixImage = nullptr;
|
||||||
mixImage = FreeImage_ConvertFromRawBits(&canvasVector.at(0), canvasImage.width(),
|
mixImage = FreeImage_ConvertFromRawBits(&canvasVector.at(0), canvasImage.width(),
|
||||||
canvasImage.height(), canvasImage.width() * 4, 32,
|
canvasImage.height(), canvasImage.width() * 4, 32,
|
||||||
FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE);
|
FI_RGBA_RED, FI_RGBA_GREEN, FI_RGBA_BLUE);
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
bool savedImage = (FreeImage_SaveU(FIF_PNG, mixImage,
|
bool savedImage =
|
||||||
Utils::String::stringToWideString(getSavePath()).c_str()) != 0);
|
(FreeImage_SaveU(FIF_PNG, mixImage,
|
||||||
#else
|
Utils::String::stringToWideString(getSavePath()).c_str()) != 0);
|
||||||
|
#else
|
||||||
bool savedImage = (FreeImage_Save(FIF_PNG, mixImage, getSavePath().c_str()) != 0);
|
bool savedImage = (FreeImage_Save(FIF_PNG, mixImage, getSavePath().c_str()) != 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!savedImage) {
|
if (!savedImage) {
|
||||||
LOG(LogError) << "Couldn't save miximage, permission problems or disk full?";
|
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,
|
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;
|
unsigned int adjustedTargetWidth = 0;
|
||||||
float widthModifier = 0.5f;
|
float widthModifier = 0.5f;
|
||||||
|
@ -572,13 +570,13 @@ void MiximageGenerator::calculateMarqueeSize(const unsigned int& targetWidth,
|
||||||
if (widthRatio >= 4)
|
if (widthRatio >= 4)
|
||||||
widthModifier += Math::clamp(widthRatio / 40.0f, 0.0f, 0.3f);
|
widthModifier += Math::clamp(widthRatio / 40.0f, 0.0f, 0.3f);
|
||||||
|
|
||||||
adjustedTargetWidth = static_cast<unsigned int>(
|
adjustedTargetWidth =
|
||||||
static_cast<float>(targetWidth) * widthModifier);
|
static_cast<unsigned int>(static_cast<float>(targetWidth) * widthModifier);
|
||||||
scaleFactor = static_cast<float>(adjustedTargetWidth) / static_cast<float>(width);
|
scaleFactor = static_cast<float>(adjustedTargetWidth) / static_cast<float>(width);
|
||||||
|
|
||||||
// For really tall and narrow images, we may have exceeded the target height.
|
// For really tall and narrow images, we may have exceeded the target height.
|
||||||
if (static_cast<int>(scaleFactor * static_cast<float>(height)) >
|
if (static_cast<int>(scaleFactor * static_cast<float>(height)) >
|
||||||
static_cast<float>(targetHeight))
|
static_cast<float>(targetHeight))
|
||||||
scaleFactor = static_cast<float>(targetHeight) / static_cast<float>(height);
|
scaleFactor = static_cast<float>(targetHeight) / static_cast<float>(height);
|
||||||
|
|
||||||
width = static_cast<int>(static_cast<float>(width) * scaleFactor);
|
width = static_cast<int>(static_cast<float>(width) * scaleFactor);
|
||||||
|
@ -586,7 +584,7 @@ void MiximageGenerator::calculateMarqueeSize(const unsigned int& targetWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiximageGenerator::sampleFrameColor(CImg<unsigned char>& screenshotImage,
|
void MiximageGenerator::sampleFrameColor(CImg<unsigned char>& screenshotImage,
|
||||||
unsigned char (&frameColor)[4])
|
unsigned char (&frameColor)[4])
|
||||||
{
|
{
|
||||||
// Calculate the number of samples relative to the configured resolution so we get
|
// Calculate the number of samples relative to the configured resolution so we get
|
||||||
// the same result regardless of miximage target size seting.
|
// the same result regardless of miximage target size seting.
|
||||||
|
@ -627,7 +625,7 @@ void MiximageGenerator::sampleFrameColor(CImg<unsigned char>& screenshotImage,
|
||||||
unsigned char blueC = Math::clamp(static_cast<int>(blueLine / 255), 0, 255);
|
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.
|
// 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 hue = colorHSL(0, 0, 0, 0);
|
||||||
float saturation = colorHSL(0, 0, 0, 1);
|
float saturation = colorHSL(0, 0, 0, 1);
|
||||||
|
@ -656,7 +654,7 @@ std::string MiximageGenerator::getSavePath()
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
if (mGame->getSystemEnvData()->mStartPath != "")
|
if (mGame->getSystemEnvData()->mStartPath != "")
|
||||||
subFolders = Utils::String::replace(Utils::FileSystem::getParent(mGame->getPath()),
|
subFolders = Utils::String::replace(Utils::FileSystem::getParent(mGame->getPath()),
|
||||||
mGame->getSystemEnvData()->mStartPath, "");
|
mGame->getSystemEnvData()->mStartPath, "");
|
||||||
|
|
||||||
std::string path = FileData::getMediaDirectory();
|
std::string path = FileData::getMediaDirectory();
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#ifndef ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
#ifndef ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
||||||
#define ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
#define ES_APP_SCRAPERS_MIXIMAGE_GENERATOR_H
|
||||||
|
|
||||||
#include "utils/CImgUtil.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
|
#include "utils/CImgUtil.h"
|
||||||
|
|
||||||
#include <FreeImage.h>
|
#include <FreeImage.h>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
@ -29,8 +29,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool generateImage();
|
bool generateImage();
|
||||||
void calculateMarqueeSize(const unsigned int& targetWidth, const unsigned int& targetHeight,
|
void calculateMarqueeSize(const unsigned int& targetWidth,
|
||||||
unsigned int& width, unsigned int& height);
|
const unsigned int& targetHeight,
|
||||||
|
unsigned int& width,
|
||||||
|
unsigned int& height);
|
||||||
void sampleFrameColor(CImg<unsigned char>& screenshotImage, unsigned char (&frameColor)[4]);
|
void sampleFrameColor(CImg<unsigned char>& screenshotImage, unsigned char (&frameColor)[4]);
|
||||||
|
|
||||||
std::string getSavePath();
|
std::string getSavePath();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
namespace PlatformIds
|
namespace PlatformIds
|
||||||
{
|
{
|
||||||
|
// clang-format off
|
||||||
std::vector<std::string> platformNames = {
|
std::vector<std::string> platformNames = {
|
||||||
"unknown", // Nothing set.
|
"unknown", // Nothing set.
|
||||||
|
|
||||||
|
@ -132,6 +133,7 @@ namespace PlatformIds
|
||||||
"ignore", // Do not allow scraping for this system.
|
"ignore", // Do not allow scraping for this system.
|
||||||
"invalid"
|
"invalid"
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
PlatformId getPlatformId(const std::string& str)
|
PlatformId getPlatformId(const std::string& str)
|
||||||
{
|
{
|
||||||
|
@ -148,6 +150,8 @@ namespace PlatformIds
|
||||||
|
|
||||||
const std::string getPlatformName(PlatformId id)
|
const std::string getPlatformName(PlatformId id)
|
||||||
{
|
{
|
||||||
|
// Return the platform name.
|
||||||
return platformNames[id];
|
return platformNames[id];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // namespace PlatformIds
|
||||||
|
|
|
@ -135,6 +135,7 @@ namespace PlatformIds
|
||||||
|
|
||||||
PlatformId getPlatformId(const std::string& str);
|
PlatformId getPlatformId(const std::string& str);
|
||||||
const std::string getPlatformName(PlatformId id);
|
const std::string getPlatformName(PlatformId id);
|
||||||
}
|
|
||||||
|
} // namespace PlatformIds
|
||||||
|
|
||||||
#endif // ES_APP_PLATFORM_ID_H
|
#endif // ES_APP_PLATFORM_ID_H
|
||||||
|
|
|
@ -11,12 +11,6 @@
|
||||||
|
|
||||||
#include "SystemData.h"
|
#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 "CollectionSystemsManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "FileSorts.h"
|
#include "FileSorts.h"
|
||||||
|
@ -25,6 +19,12 @@
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "ThemeData.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 <fstream>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
@ -39,14 +39,10 @@ FindRules::FindRules()
|
||||||
loadFindRules();
|
loadFindRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
FindRules::~FindRules()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindRules::loadFindRules()
|
void FindRules::loadFindRules()
|
||||||
{
|
{
|
||||||
std::string customSystemsDirectory =
|
std::string customSystemsDirectory =
|
||||||
Utils::FileSystem::getHomePath() + "/.emulationstation/custom_systems";
|
Utils::FileSystem::getHomePath() + "/.emulationstation/custom_systems";
|
||||||
|
|
||||||
std::string path = customSystemsDirectory + "/es_find_rules.xml";
|
std::string path = customSystemsDirectory + "/es_find_rules.xml";
|
||||||
|
|
||||||
|
@ -54,16 +50,16 @@ void FindRules::loadFindRules()
|
||||||
LOG(LogInfo) << "Found custom find rules configuration file";
|
LOG(LogInfo) << "Found custom find rules configuration file";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
path = ResourceManager::getInstance()->
|
path = ResourceManager::getInstance()->getResourcePath(
|
||||||
getResourcePath(":/systems/windows/es_find_rules.xml", false);
|
":/systems/windows/es_find_rules.xml", false);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
path = ResourceManager::getInstance()->
|
path = ResourceManager::getInstance()->getResourcePath(":/systems/macos/es_find_rules.xml",
|
||||||
getResourcePath(":/systems/macos/es_find_rules.xml", false);
|
false);
|
||||||
#else
|
#else
|
||||||
path = ResourceManager::getInstance()->
|
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_find_rules.xml",
|
||||||
getResourcePath(":/systems/unix/es_find_rules.xml", false);
|
false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path == "") {
|
if (path == "") {
|
||||||
|
@ -74,11 +70,11 @@ void FindRules::loadFindRules()
|
||||||
LOG(LogInfo) << "Parsing find rules configuration file \"" << path << "\"...";
|
LOG(LogInfo) << "Parsing find rules configuration file \"" << path << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
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());
|
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
LOG(LogError) << "Couldn't parse es_find_rules.xml: " << res.description();
|
LOG(LogError) << "Couldn't parse es_find_rules.xml: " << res.description();
|
||||||
|
@ -97,81 +93,79 @@ void FindRules::loadFindRules()
|
||||||
CoreRules coreRules;
|
CoreRules coreRules;
|
||||||
|
|
||||||
for (pugi::xml_node emulator = ruleList.child("emulator"); emulator;
|
for (pugi::xml_node emulator = ruleList.child("emulator"); emulator;
|
||||||
emulator = emulator.next_sibling("emulator")) {
|
emulator = emulator.next_sibling("emulator")) {
|
||||||
std::string emulatorName = emulator.attribute("name").as_string();
|
std::string emulatorName = emulator.attribute("name").as_string();
|
||||||
if (emulatorName.empty()) {
|
if (emulatorName.empty()) {
|
||||||
LOG(LogWarning) << "Found emulator tag without name attribute, skipping entry";
|
LOG(LogWarning) << "Found emulator tag without name attribute, skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mEmulators.find(emulatorName) != mEmulators.end()) {
|
if (mEmulators.find(emulatorName) != mEmulators.end()) {
|
||||||
LOG(LogWarning) << "Found repeating emulator tag \"" << emulatorName <<
|
LOG(LogWarning) << "Found repeating emulator tag \"" << emulatorName
|
||||||
"\", skipping entry";
|
<< "\", skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (pugi::xml_node rule = emulator.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
for (pugi::xml_node rule = emulator.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
||||||
std::string ruleType = rule.attribute("type").as_string();
|
std::string ruleType = rule.attribute("type").as_string();
|
||||||
if (ruleType.empty()) {
|
if (ruleType.empty()) {
|
||||||
LOG(LogWarning) << "Found rule tag without type attribute for emulator \"" <<
|
LOG(LogWarning) << "Found rule tag without type attribute for emulator \""
|
||||||
emulatorName << "\", skipping entry";
|
<< emulatorName << "\", skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
if (ruleType != "winregistrypath" && ruleType != "systempath" &&
|
if (ruleType != "winregistrypath" && ruleType != "systempath" &&
|
||||||
ruleType != "staticpath") {
|
ruleType != "staticpath") {
|
||||||
#else
|
#else
|
||||||
if (ruleType != "systempath" && ruleType != "staticpath") {
|
if (ruleType != "systempath" && ruleType != "staticpath") {
|
||||||
#endif
|
#endif
|
||||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType <<
|
LOG(LogWarning) << "Found invalid rule type \"" << ruleType << "\" for emulator \""
|
||||||
"\" for emulator \"" << emulatorName << "\", skipping entry";
|
<< emulatorName << "\", skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (pugi::xml_node entry = rule.child("entry"); entry;
|
for (pugi::xml_node entry = rule.child("entry"); entry;
|
||||||
entry = entry.next_sibling("entry")) {
|
entry = entry.next_sibling("entry")) {
|
||||||
std::string entryValue = entry.text().get();
|
std::string entryValue = entry.text().get();
|
||||||
if (ruleType == "systempath")
|
if (ruleType == "systempath")
|
||||||
emulatorRules.systemPaths.push_back(entryValue);
|
emulatorRules.systemPaths.push_back(entryValue);
|
||||||
else if (ruleType == "staticpath")
|
else if (ruleType == "staticpath")
|
||||||
emulatorRules.staticPaths.push_back(entryValue);
|
emulatorRules.staticPaths.push_back(entryValue);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
else if (ruleType == "winregistrypath")
|
else if (ruleType == "winregistrypath")
|
||||||
emulatorRules.winRegistryPaths.push_back(entryValue);
|
emulatorRules.winRegistryPaths.push_back(entryValue);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mEmulators[emulatorName] = emulatorRules;
|
mEmulators[emulatorName] = emulatorRules;
|
||||||
emulatorRules.systemPaths.clear();
|
emulatorRules.systemPaths.clear();
|
||||||
emulatorRules.staticPaths.clear();
|
emulatorRules.staticPaths.clear();
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
emulatorRules.winRegistryPaths.clear();
|
emulatorRules.winRegistryPaths.clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pugi::xml_node core = ruleList.child("core"); core;
|
for (pugi::xml_node core = ruleList.child("core"); core; core = core.next_sibling("core")) {
|
||||||
core = core.next_sibling("core")) {
|
|
||||||
std::string coreName = core.attribute("name").as_string();
|
std::string coreName = core.attribute("name").as_string();
|
||||||
if (coreName.empty()) {
|
if (coreName.empty()) {
|
||||||
LOG(LogWarning) << "Found core tag without name attribute, skipping entry";
|
LOG(LogWarning) << "Found core tag without name attribute, skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mCores.find(coreName) != mCores.end()) {
|
if (mCores.find(coreName) != mCores.end()) {
|
||||||
LOG(LogWarning) << "Found repeating core tag \"" << coreName <<
|
LOG(LogWarning) << "Found repeating core tag \"" << coreName << "\", skipping entry";
|
||||||
"\", skipping entry";
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (pugi::xml_node rule = core.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
for (pugi::xml_node rule = core.child("rule"); rule; rule = rule.next_sibling("rule")) {
|
||||||
std::string ruleType = rule.attribute("type").as_string();
|
std::string ruleType = rule.attribute("type").as_string();
|
||||||
if (ruleType.empty()) {
|
if (ruleType.empty()) {
|
||||||
LOG(LogWarning) << "Found rule tag without type attribute for core \"" <<
|
LOG(LogWarning) << "Found rule tag without type attribute for core \"" << coreName
|
||||||
coreName << "\", skipping entry";
|
<< "\", skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ruleType != "corepath") {
|
if (ruleType != "corepath") {
|
||||||
LOG(LogWarning) << "Found invalid rule type \"" << ruleType <<
|
LOG(LogWarning) << "Found invalid rule type \"" << ruleType << "\" for core \""
|
||||||
"\" for core \"" << coreName << "\", skipping entry";
|
<< coreName << "\", skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (pugi::xml_node entry = rule.child("entry"); entry;
|
for (pugi::xml_node entry = rule.child("entry"); entry;
|
||||||
entry = entry.next_sibling("entry")) {
|
entry = entry.next_sibling("entry")) {
|
||||||
std::string entryValue = entry.text().get();
|
std::string entryValue = entry.text().get();
|
||||||
if (ruleType == "corepath")
|
if (ruleType == "corepath")
|
||||||
coreRules.corePaths.push_back(entryValue);
|
coreRules.corePaths.push_back(entryValue);
|
||||||
|
@ -182,23 +176,22 @@ void FindRules::loadFindRules()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemData::SystemData(
|
SystemData::SystemData(const std::string& name,
|
||||||
const std::string& name,
|
const std::string& fullName,
|
||||||
const std::string& fullName,
|
SystemEnvironmentData* envData,
|
||||||
SystemEnvironmentData* envData,
|
const std::string& themeFolder,
|
||||||
const std::string& themeFolder,
|
bool CollectionSystem,
|
||||||
bool CollectionSystem,
|
bool CustomCollectionSystem)
|
||||||
bool CustomCollectionSystem)
|
: mName(name)
|
||||||
: mName(name),
|
, mFullName(fullName)
|
||||||
mFullName(fullName),
|
, mEnvData(envData)
|
||||||
mEnvData(envData),
|
, mThemeFolder(themeFolder)
|
||||||
mThemeFolder(themeFolder),
|
, mIsCollectionSystem(CollectionSystem)
|
||||||
mIsCollectionSystem(CollectionSystem),
|
, mIsCustomCollectionSystem(CustomCollectionSystem)
|
||||||
mIsCustomCollectionSystem(CustomCollectionSystem),
|
, mIsGroupedCustomCollectionSystem(false)
|
||||||
mIsGroupedCustomCollectionSystem(false),
|
, mIsGameSystem(true)
|
||||||
mIsGameSystem(true),
|
, mScrapeFlag(false)
|
||||||
mScrapeFlag(false),
|
, mPlaceholder(nullptr)
|
||||||
mPlaceholder(nullptr)
|
|
||||||
{
|
{
|
||||||
mFilterIndex = new FileFilterIndex();
|
mFilterIndex = new FileFilterIndex();
|
||||||
|
|
||||||
|
@ -220,7 +213,7 @@ SystemData::SystemData(
|
||||||
setupSystemSortType(mRootFolder);
|
setupSystemSortType(mRootFolder);
|
||||||
|
|
||||||
mRootFolder->sort(mRootFolder->getSortTypeFromString(mRootFolder->getSortTypeString()),
|
mRootFolder->sort(mRootFolder->getSortTypeFromString(mRootFolder->getSortTypeString()),
|
||||||
Settings::getInstance()->getBool("FavoritesFirst"));
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
|
|
||||||
indexAllGameFilters(mRootFolder);
|
indexAllGameFilters(mRootFolder);
|
||||||
}
|
}
|
||||||
|
@ -275,13 +268,13 @@ bool SystemData::populateFolder(FileData* folder)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
|
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
|
||||||
it != dirContent.cend(); it++) {
|
it != dirContent.cend(); it++) {
|
||||||
filePath = *it;
|
filePath = *it;
|
||||||
|
|
||||||
// Skip any recursive symlinks as those would hang the application at various places.
|
// Skip any recursive symlinks as those would hang the application at various places.
|
||||||
if (Utils::FileSystem::isSymlink(filePath)) {
|
if (Utils::FileSystem::isSymlink(filePath)) {
|
||||||
if (Utils::FileSystem::resolveSymlink(filePath) ==
|
if (Utils::FileSystem::resolveSymlink(filePath) ==
|
||||||
Utils::FileSystem::getFileName(filePath)) {
|
Utils::FileSystem::getFileName(filePath)) {
|
||||||
LOG(LogWarning) << "Skipped \"" << filePath << "\" as it's a recursive symlink";
|
LOG(LogWarning) << "Skipped \"" << filePath << "\" as it's a recursive symlink";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -289,9 +282,9 @@ bool SystemData::populateFolder(FileData* folder)
|
||||||
|
|
||||||
// Skip hidden files and folders.
|
// Skip hidden files and folders.
|
||||||
if (!showHiddenFiles && Utils::FileSystem::isHidden(filePath)) {
|
if (!showHiddenFiles && Utils::FileSystem::isHidden(filePath)) {
|
||||||
LOG(LogDebug) << "SystemData::populateFolder(): Skipping hidden " <<
|
LOG(LogDebug) << "SystemData::populateFolder(): Skipping hidden "
|
||||||
(Utils::FileSystem::isDirectory(filePath) ? "directory \"" : "file \"") <<
|
<< (Utils::FileSystem::isDirectory(filePath) ? "directory \"" : "file \"")
|
||||||
filePath << "\"";
|
<< filePath << "\"";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +299,7 @@ bool SystemData::populateFolder(FileData* folder)
|
||||||
|
|
||||||
isGame = false;
|
isGame = false;
|
||||||
if (std::find(mEnvData->mSearchExtensions.cbegin(), mEnvData->mSearchExtensions.cend(),
|
if (std::find(mEnvData->mSearchExtensions.cbegin(), mEnvData->mSearchExtensions.cend(),
|
||||||
extension) != mEnvData->mSearchExtensions.cend()) {
|
extension) != mEnvData->mSearchExtensions.cend()) {
|
||||||
FileData* newGame = new FileData(GAME, filePath, mEnvData, this);
|
FileData* newGame = new FileData(GAME, filePath, mEnvData, this);
|
||||||
|
|
||||||
// Prevent new arcade assets from being added.
|
// Prevent new arcade assets from being added.
|
||||||
|
@ -326,15 +319,17 @@ bool SystemData::populateFolder(FileData* folder)
|
||||||
if (Utils::FileSystem::isSymlink(filePath)) {
|
if (Utils::FileSystem::isSymlink(filePath)) {
|
||||||
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(filePath);
|
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(filePath);
|
||||||
const std::string canonicalStartPath =
|
const std::string canonicalStartPath =
|
||||||
Utils::FileSystem::getCanonicalPath(mEnvData->mStartPath);
|
Utils::FileSystem::getCanonicalPath(mEnvData->mStartPath);
|
||||||
const std::string combinedPath = mEnvData->mStartPath +
|
const std::string combinedPath =
|
||||||
canonicalPath.substr(canonicalStartPath.size(),
|
mEnvData->mStartPath +
|
||||||
canonicalStartPath.size() - canonicalPath.size());
|
canonicalPath.substr(canonicalStartPath.size(),
|
||||||
|
canonicalStartPath.size() - canonicalPath.size());
|
||||||
if (filePath.find(combinedPath) == 0) {
|
if (filePath.find(combinedPath) == 0) {
|
||||||
LOG(LogWarning) << "Skipped \"" << filePath << "\" as it's a recursive symlink";
|
LOG(LogWarning) << "Skipped \"" << filePath << "\" as it's a recursive symlink";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this);
|
FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this);
|
||||||
populateFolder(newFolder);
|
populateFolder(newFolder);
|
||||||
|
|
||||||
|
@ -352,17 +347,15 @@ void SystemData::indexAllGameFilters(const FileData* folder)
|
||||||
{
|
{
|
||||||
const std::vector<FileData*>& children = folder->getChildren();
|
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++) {
|
it != children.cend(); it++) {
|
||||||
switch ((*it)->getType()) {
|
switch ((*it)->getType()) {
|
||||||
case GAME: {
|
case GAME:
|
||||||
mFilterIndex->addToIndex(*it);
|
mFilterIndex->addToIndex(*it);
|
||||||
}
|
break;
|
||||||
break;
|
case FOLDER:
|
||||||
case FOLDER: {
|
|
||||||
indexAllGameFilters(*it);
|
indexAllGameFilters(*it);
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -400,11 +393,11 @@ bool SystemData::loadConfig()
|
||||||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
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());
|
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
LOG(LogError) << "Couldn't parse es_systems.xml: " << res.description();
|
LOG(LogError) << "Couldn't parse es_systems.xml: " << res.description();
|
||||||
|
@ -420,7 +413,7 @@ bool SystemData::loadConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pugi::xml_node system = systemList.child("system"); system;
|
for (pugi::xml_node system = systemList.child("system"); system;
|
||||||
system = system.next_sibling("system")) {
|
system = system.next_sibling("system")) {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string fullname;
|
std::string fullname;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -436,21 +429,21 @@ bool SystemData::loadConfig()
|
||||||
// the ROM path configured as ROMDirectory in es_settings.xml. If it's set to ""
|
// 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.
|
// in this configuration file, the default hardcoded path $HOME/ROMs/ will be used.
|
||||||
path = Utils::String::replace(path, "%ROMPATH%", rompath);
|
path = Utils::String::replace(path, "%ROMPATH%", rompath);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
path = Utils::String::replace(path, "\\", "/");
|
path = Utils::String::replace(path, "\\", "/");
|
||||||
#endif
|
#endif
|
||||||
path = Utils::String::replace(path, "//", "/");
|
path = Utils::String::replace(path, "//", "/");
|
||||||
|
|
||||||
// Check that the ROM directory for the system is valid or otherwise abort the processing.
|
// Check that the ROM directory for the system is valid or otherwise abort the processing.
|
||||||
if (!Utils::FileSystem::exists(path)) {
|
if (!Utils::FileSystem::exists(path)) {
|
||||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||||
name << "\" as the defined ROM directory \"" << path << "\" does not exist";
|
<< "\" as the defined ROM directory \"" << path << "\" does not exist";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!Utils::FileSystem::isDirectory(path)) {
|
if (!Utils::FileSystem::isDirectory(path)) {
|
||||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||||
name << "\" as the defined ROM directory \"" << path <<
|
<< "\" as the defined ROM directory \"" << path
|
||||||
"\" is not actually a directory";
|
<< "\" is not actually a directory";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Utils::FileSystem::isSymlink(path)) {
|
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.
|
// as that would lead to an infite loop, meaning the application would never start.
|
||||||
std::string resolvedRompath = Utils::FileSystem::getCanonicalPath(rompath);
|
std::string resolvedRompath = Utils::FileSystem::getCanonicalPath(rompath);
|
||||||
if (resolvedRompath.find(Utils::FileSystem::getCanonicalPath(path)) == 0) {
|
if (resolvedRompath.find(Utils::FileSystem::getCanonicalPath(path)) == 0) {
|
||||||
LOG(LogWarning) << "Skipping system \"" << name <<
|
LOG(LogWarning) << "Skipping system \"" << name
|
||||||
"\" as the defined ROM directory \"" << path <<
|
<< "\" as the defined ROM directory \"" << path
|
||||||
"\" is an infinitely recursive symlink";
|
<< "\" is an infinitely recursive symlink";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -472,7 +465,7 @@ bool SystemData::loadConfig()
|
||||||
|
|
||||||
// Platform ID list
|
// Platform ID list
|
||||||
const std::string platformList =
|
const std::string platformList =
|
||||||
Utils::String::toLower(system.child("platform").text().get());
|
Utils::String::toLower(system.child("platform").text().get());
|
||||||
std::vector<std::string> platformStrs = readList(platformList);
|
std::vector<std::string> platformStrs = readList(platformList);
|
||||||
std::vector<PlatformIds::PlatformId> platformIds;
|
std::vector<PlatformIds::PlatformId> platformIds;
|
||||||
for (auto it = platformStrs.cbegin(); it != platformStrs.cend(); it++) {
|
for (auto it = platformStrs.cbegin(); it != platformStrs.cend(); it++) {
|
||||||
|
@ -489,8 +482,8 @@ bool SystemData::loadConfig()
|
||||||
// If there's a platform entry defined but it does not match the list of supported
|
// If there's a platform entry defined but it does not match the list of supported
|
||||||
// platforms, then generate a warning.
|
// platforms, then generate a warning.
|
||||||
if (str != "" && platformId == PlatformIds::PLATFORM_UNKNOWN)
|
if (str != "" && platformId == PlatformIds::PLATFORM_UNKNOWN)
|
||||||
LOG(LogWarning) << "Unknown platform \"" << str << "\" defined for system \"" <<
|
LOG(LogWarning) << "Unknown platform \"" << str << "\" defined for system \""
|
||||||
name << "\"";
|
<< name << "\"";
|
||||||
else if (platformId != PlatformIds::PLATFORM_UNKNOWN)
|
else if (platformId != PlatformIds::PLATFORM_UNKNOWN)
|
||||||
platformIds.push_back(platformId);
|
platformIds.push_back(platformId);
|
||||||
}
|
}
|
||||||
|
@ -501,26 +494,27 @@ bool SystemData::loadConfig()
|
||||||
// Validate.
|
// Validate.
|
||||||
|
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
LOG(LogError) <<
|
LOG(LogError)
|
||||||
"A system in the es_systems.xml file has no name defined, skipping entry";
|
<< "A system in the es_systems.xml file has no name defined, skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (fullname.empty() || path.empty() || extensions.empty() || cmd.empty()) {
|
else if (fullname.empty() || path.empty() || extensions.empty() || cmd.empty()) {
|
||||||
LOG(LogError) << "System \"" << name << "\" is missing the fullname, path, "
|
LOG(LogError) << "System \"" << name
|
||||||
"extension, or command tag, skipping entry";
|
<< "\" is missing the fullname, path, "
|
||||||
|
"extension, or command tag, skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert path to generic directory seperators.
|
// Convert path to generic directory seperators.
|
||||||
path = Utils::FileSystem::getGenericPath(path);
|
path = Utils::FileSystem::getGenericPath(path);
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
if (!Settings::getInstance()->getBool("ShowHiddenFiles") &&
|
if (!Settings::getInstance()->getBool("ShowHiddenFiles") &&
|
||||||
Utils::FileSystem::isHidden(path)) {
|
Utils::FileSystem::isHidden(path)) {
|
||||||
LOG(LogWarning) << "Skipping hidden ROM folder \"" << path << "\"";
|
LOG(LogWarning) << "Skipping hidden ROM folder \"" << path << "\"";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create the system runtime environment data.
|
// Create the system runtime environment data.
|
||||||
SystemEnvironmentData* envData = new SystemEnvironmentData;
|
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
|
// 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.
|
// games for the system are hidden. That will flag the system as empty.
|
||||||
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
if (!Settings::getInstance()->getBool("ShowHiddenGames")) {
|
||||||
std::vector<FileData*> recursiveGames =
|
std::vector<FileData*> recursiveGames = newSys->getRootFolder()->getChildrenRecursive();
|
||||||
newSys->getRootFolder()->getChildrenRecursive();
|
|
||||||
onlyHidden = true;
|
onlyHidden = true;
|
||||||
for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) {
|
for (auto it = recursiveGames.cbegin(); it != recursiveGames.cend(); it++) {
|
||||||
if ((*it)->getType() != FOLDER) {
|
if ((*it)->getType() != FOLDER) {
|
||||||
|
@ -548,8 +541,8 @@ bool SystemData::loadConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newSys->getRootFolder()->getChildrenByFilename().size() == 0 || onlyHidden) {
|
if (newSys->getRootFolder()->getChildrenByFilename().size() == 0 || onlyHidden) {
|
||||||
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" <<
|
LOG(LogDebug) << "SystemData::loadConfig(): Skipping system \"" << name
|
||||||
name << "\" as no files matched any of the defined file extensions";
|
<< "\" as no files matched any of the defined file extensions";
|
||||||
delete newSys;
|
delete newSys;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -559,8 +552,7 @@ bool SystemData::loadConfig()
|
||||||
|
|
||||||
// Sort systems by their full names.
|
// Sort systems by their full names.
|
||||||
std::sort(std::begin(sSystemVector), std::end(sSystemVector),
|
std::sort(std::begin(sSystemVector), std::end(sSystemVector),
|
||||||
[](SystemData* a, SystemData* b) {
|
[](SystemData* a, SystemData* b) { return a->getFullName() < b->getFullName(); });
|
||||||
return a->getFullName() < b->getFullName(); });
|
|
||||||
|
|
||||||
// Don't load any collections if there are no systems available.
|
// Don't load any collections if there are no systems available.
|
||||||
if (sSystemVector.size() > 0)
|
if (sSystemVector.size() > 0)
|
||||||
|
@ -580,18 +572,18 @@ void SystemData::deleteSystems()
|
||||||
std::string SystemData::getConfigPath(bool legacyWarning)
|
std::string SystemData::getConfigPath(bool legacyWarning)
|
||||||
{
|
{
|
||||||
if (legacyWarning) {
|
if (legacyWarning) {
|
||||||
std::string legacyConfigFile = Utils::FileSystem::getHomePath() +
|
std::string legacyConfigFile =
|
||||||
"/.emulationstation/es_systems.cfg";
|
Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(legacyConfigFile)) {
|
if (Utils::FileSystem::exists(legacyConfigFile)) {
|
||||||
LOG(LogInfo) << "Found legacy systems configuration file \"" << legacyConfigFile <<
|
LOG(LogInfo) << "Found legacy systems configuration file \"" << legacyConfigFile
|
||||||
"\", to retain your customizations move it to "
|
<< "\", to retain your customizations move it to "
|
||||||
"\"custom_systems/es_systems.xml\" or otherwise delete the file";
|
"\"custom_systems/es_systems.xml\" or otherwise delete the file";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string customSystemsDirectory =
|
std::string customSystemsDirectory =
|
||||||
Utils::FileSystem::getHomePath() + "/.emulationstation/custom_systems";
|
Utils::FileSystem::getHomePath() + "/.emulationstation/custom_systems";
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(customSystemsDirectory)) {
|
if (!Utils::FileSystem::exists(customSystemsDirectory)) {
|
||||||
LOG(LogInfo) << "Creating custom systems directory \"" << customSystemsDirectory << "\"...";
|
LOG(LogInfo) << "Creating custom systems directory \"" << customSystemsDirectory << "\"...";
|
||||||
|
@ -608,16 +600,14 @@ std::string SystemData::getConfigPath(bool legacyWarning)
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
path = ResourceManager::getInstance()->
|
path =
|
||||||
getResourcePath(":/systems/windows/es_systems.xml", true);
|
ResourceManager::getInstance()->getResourcePath(":/systems/windows/es_systems.xml", true);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
path = ResourceManager::getInstance()->
|
path = ResourceManager::getInstance()->getResourcePath(":/systems/macos/es_systems.xml", true);
|
||||||
getResourcePath(":/systems/macos/es_systems.xml", true);
|
#else
|
||||||
#else
|
path = ResourceManager::getInstance()->getResourcePath(":/systems/unix/es_systems.xml", true);
|
||||||
path = ResourceManager::getInstance()->
|
#endif
|
||||||
getResourcePath(":/systems/unix/es_systems.xml", true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
@ -627,16 +617,16 @@ bool SystemData::createSystemDirectories()
|
||||||
std::string path = getConfigPath(false);
|
std::string path = getConfigPath(false);
|
||||||
const std::string rompath = FileData::getROMDirectory();
|
const std::string rompath = FileData::getROMDirectory();
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(path)) {
|
if (!Utils::FileSystem::exists(path)) {
|
||||||
LOG(LogInfo) << "Systems configuration file does not exist, aborting";
|
LOG(LogInfo) << "Systems configuration file does not exist, aborting";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(LogInfo) << "Generating ROM directory structure...";
|
LOG(LogInfo) << "Generating ROM directory structure...";
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(rompath) && Utils::FileSystem::isRegularFile(rompath)) {
|
if (Utils::FileSystem::exists(rompath) && Utils::FileSystem::isRegularFile(rompath)) {
|
||||||
LOG(LogError) <<
|
LOG(LogError) << "Requested ROM directory \"" << rompath
|
||||||
"Requested ROM directory \"" << rompath << "\" is actually a file, aborting";
|
<< "\" is actually a file, aborting";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,11 +644,11 @@ bool SystemData::createSystemDirectories()
|
||||||
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
LOG(LogInfo) << "Parsing systems configuration file \"" << path << "\"...";
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
pugi::xml_parse_result res = doc.load_file(Utils::String::stringToWideString(path).c_str());
|
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());
|
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
LOG(LogError) << "Couldn't parse es_systems.xml";
|
LOG(LogError) << "Couldn't parse es_systems.xml";
|
||||||
|
@ -677,7 +667,7 @@ bool SystemData::createSystemDirectories()
|
||||||
std::vector<std::string> systemsVector;
|
std::vector<std::string> systemsVector;
|
||||||
|
|
||||||
for (pugi::xml_node system = systemList.child("system"); system;
|
for (pugi::xml_node system = systemList.child("system"); system;
|
||||||
system = system.next_sibling("system")) {
|
system = system.next_sibling("system")) {
|
||||||
std::string systemDir;
|
std::string systemDir;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string fullname;
|
std::string fullname;
|
||||||
|
@ -701,8 +691,9 @@ bool SystemData::createSystemDirectories()
|
||||||
// Check that the %ROMPATH% variable is actually used for the path element.
|
// Check that the %ROMPATH% variable is actually used for the path element.
|
||||||
// If not, skip the system.
|
// If not, skip the system.
|
||||||
if (path.find("%ROMPATH%") != 0) {
|
if (path.find("%ROMPATH%") != 0) {
|
||||||
LOG(LogWarning) << "The path element for system \"" << name << "\" does not "
|
LOG(LogWarning) << "The path element for system \"" << name
|
||||||
"utilize the %ROMPATH% variable, skipping entry";
|
<< "\" does not "
|
||||||
|
"utilize the %ROMPATH% variable, skipping entry";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -711,14 +702,13 @@ bool SystemData::createSystemDirectories()
|
||||||
|
|
||||||
// Trim any leading directory separator characters.
|
// Trim any leading directory separator characters.
|
||||||
systemDir.erase(systemDir.begin(),
|
systemDir.erase(systemDir.begin(),
|
||||||
std::find_if(systemDir.begin(), systemDir.end(), [](char c) {
|
std::find_if(systemDir.begin(), systemDir.end(),
|
||||||
return c != '/' && c != '\\';
|
[](char c) { return c != '/' && c != '\\'; }));
|
||||||
}));
|
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(rompath + systemDir)) {
|
if (!Utils::FileSystem::exists(rompath + systemDir)) {
|
||||||
if (!Utils::FileSystem::createDirectory(rompath + systemDir)) {
|
if (!Utils::FileSystem::createDirectory(rompath + systemDir)) {
|
||||||
LOG(LogError) << "Couldn't create system directory \"" << systemDir <<
|
LOG(LogError) << "Couldn't create system directory \"" << systemDir
|
||||||
"\", permission problems or disk full?";
|
<< "\", permission problems or disk full?";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -739,16 +729,17 @@ bool SystemData::createSystemDirectories()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
systemInfoFile.open(Utils::String::stringToWideString(rompath +
|
systemInfoFile.open(
|
||||||
systemDir + systemInfoFileName).c_str());
|
Utils::String::stringToWideString(rompath + systemDir + systemInfoFileName).c_str());
|
||||||
#else
|
#else
|
||||||
systemInfoFile.open(rompath + systemDir + systemInfoFileName);
|
systemInfoFile.open(rompath + systemDir + systemInfoFileName);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (systemInfoFile.fail()) {
|
if (systemInfoFile.fail()) {
|
||||||
LOG(LogError) << "Couldn't create system information file \"" << rompath +
|
LOG(LogError) << "Couldn't create system information file \""
|
||||||
systemDir + systemInfoFileName << "\", permission problems or disk full?";
|
<< rompath + systemDir + systemInfoFileName
|
||||||
|
<< "\", permission problems or disk full?";
|
||||||
systemInfoFile.close();
|
systemInfoFile.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -770,12 +761,12 @@ bool SystemData::createSystemDirectories()
|
||||||
systemsVector.push_back(systemDir + ": " + fullname);
|
systemsVector.push_back(systemDir + ": " + fullname);
|
||||||
|
|
||||||
if (replaceInfoFile) {
|
if (replaceInfoFile) {
|
||||||
LOG(LogInfo) << "Replaced existing system information file \"" <<
|
LOG(LogInfo) << "Replaced existing system information file \""
|
||||||
rompath + systemDir + systemInfoFileName << "\"";
|
<< rompath + systemDir + systemInfoFileName << "\"";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogInfo) << "Created system information file \"" <<
|
LOG(LogInfo) << "Created system information file \""
|
||||||
rompath + systemDir + systemInfoFileName << "\"";
|
<< rompath + systemDir + systemInfoFileName << "\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,11 +784,11 @@ bool SystemData::createSystemDirectories()
|
||||||
|
|
||||||
if (systemsFileSuccess) {
|
if (systemsFileSuccess) {
|
||||||
std::ofstream systemsFile;
|
std::ofstream systemsFile;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
systemsFile.open(Utils::String::stringToWideString(rompath + systemsFileName).c_str());
|
systemsFile.open(Utils::String::stringToWideString(rompath + systemsFileName).c_str());
|
||||||
#else
|
#else
|
||||||
systemsFile.open(rompath + systemsFileName);
|
systemsFile.open(rompath + systemsFileName);
|
||||||
#endif
|
#endif
|
||||||
if (systemsFile.fail()) {
|
if (systemsFile.fail()) {
|
||||||
systemsFileSuccess = false;
|
systemsFileSuccess = false;
|
||||||
}
|
}
|
||||||
|
@ -811,7 +802,7 @@ bool SystemData::createSystemDirectories()
|
||||||
|
|
||||||
if (!systemsFileSuccess) {
|
if (!systemsFileSuccess) {
|
||||||
LOG(LogWarning) << "System directories successfully created but couldn't create "
|
LOG(LogWarning) << "System directories successfully created but couldn't create "
|
||||||
"the systems.txt file in the ROM directory root";
|
"the systems.txt file in the ROM directory root";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -867,8 +858,8 @@ std::string SystemData::getGamelistPath(bool forWrite) const
|
||||||
if (Utils::FileSystem::exists(filePath))
|
if (Utils::FileSystem::exists(filePath))
|
||||||
return filePath;
|
return filePath;
|
||||||
|
|
||||||
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" +
|
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" + mName +
|
||||||
mName + "/gamelist.xml";
|
"/gamelist.xml";
|
||||||
|
|
||||||
// Make sure the directory exists if we're going to write to it,
|
// Make sure the directory exists if we're going to write to it,
|
||||||
// or crashes will happen.
|
// or crashes will happen.
|
||||||
|
@ -899,17 +890,12 @@ std::string SystemData::getThemePath() const
|
||||||
return localThemePath;
|
return localThemePath;
|
||||||
|
|
||||||
// Not system theme, try default system theme in theme set.
|
// Not system theme, try default system theme in theme set.
|
||||||
localThemePath = Utils::FileSystem::getParent(Utils::FileSystem::getParent(localThemePath)) +
|
localThemePath =
|
||||||
"/theme.xml";
|
Utils::FileSystem::getParent(Utils::FileSystem::getParent(localThemePath)) + "/theme.xml";
|
||||||
|
|
||||||
return localThemePath;
|
return localThemePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemData::hasGamelist() const
|
|
||||||
{
|
|
||||||
return (Utils::FileSystem::exists(getGamelistPath(false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
||||||
{
|
{
|
||||||
unsigned int total = 0;
|
unsigned int total = 0;
|
||||||
|
@ -927,7 +913,7 @@ SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
||||||
// Get a random number in range.
|
// Get a random number in range.
|
||||||
std::random_device randDev;
|
std::random_device randDev;
|
||||||
// Mersenne Twister pseudorandom number generator.
|
// Mersenne Twister pseudorandom number generator.
|
||||||
std::mt19937 engine{randDev()};
|
std::mt19937 engine { randDev() };
|
||||||
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
||||||
int target = uniform_dist(engine);
|
int target = uniform_dist(engine);
|
||||||
|
|
||||||
|
@ -942,8 +928,7 @@ SystemData* SystemData::getRandomSystem(const SystemData* currentSystem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (randomSystem == currentSystem);
|
||||||
while (randomSystem == currentSystem);
|
|
||||||
|
|
||||||
return randomSystem;
|
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,
|
// 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.
|
// otherwise get a list of all the folder and file entries in the view.
|
||||||
if (currentGame && currentGame->getType() == FOLDER && currentGame->
|
if (currentGame && currentGame->getType() == FOLDER &&
|
||||||
getSystem()->isGroupedCustomCollection()) {
|
currentGame->getSystem()->isGroupedCustomCollection()) {
|
||||||
gameList = mRootFolder->getParent()->getChildrenListToDisplay();
|
gameList = mRootFolder->getParent()->getChildrenListToDisplay();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gameList = ViewController::get()->getGameListView(mRootFolder->
|
gameList = ViewController::get()
|
||||||
getSystem()).get()->getCursor()->getParent()->getChildrenListToDisplay();
|
->getGameListView(mRootFolder->getSystem())
|
||||||
|
.get()
|
||||||
|
->getCursor()
|
||||||
|
->getParent()
|
||||||
|
->getChildrenListToDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameList.size() > 0 && gameList.front()->getParent()->getOnlyFoldersFlag())
|
if (gameList.size() > 0 && gameList.front()->getParent()->getOnlyFoldersFlag())
|
||||||
|
@ -1003,11 +992,10 @@ FileData* SystemData::getRandomGame(const FileData* currentGame)
|
||||||
// Get a random number in range.
|
// Get a random number in range.
|
||||||
std::random_device randDev;
|
std::random_device randDev;
|
||||||
// Mersenne Twister pseudorandom number generator.
|
// Mersenne Twister pseudorandom number generator.
|
||||||
std::mt19937 engine{randDev()};
|
std::mt19937 engine { randDev() };
|
||||||
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
std::uniform_int_distribution<int> uniform_dist(0, total - 1);
|
||||||
target = uniform_dist(engine);
|
target = uniform_dist(engine);
|
||||||
}
|
} while (currentGame && gameList.at(target) == currentGame);
|
||||||
while (currentGame && gameList.at(target) == currentGame);
|
|
||||||
|
|
||||||
return gameList.at(target);
|
return gameList.at(target);
|
||||||
}
|
}
|
||||||
|
@ -1020,23 +1008,25 @@ void SystemData::sortSystem(bool reloadGamelist, bool jumpToFirstRow)
|
||||||
bool favoritesSorting;
|
bool favoritesSorting;
|
||||||
|
|
||||||
if (this->isCustomCollection() ||
|
if (this->isCustomCollection() ||
|
||||||
(this->isCollection() && this->getFullName() == "collections"))
|
(this->isCollection() && this->getFullName() == "collections")) {
|
||||||
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||||
|
}
|
||||||
|
|
||||||
FileData* rootFolder = getRootFolder();
|
FileData* rootFolder = getRootFolder();
|
||||||
// Assign the sort type to all grouped custom collections.
|
// Assign the sort type to all grouped custom collections.
|
||||||
if (mIsCollectionSystem && mFullName == "collections") {
|
if (mIsCollectionSystem && mFullName == "collections") {
|
||||||
for (auto it = rootFolder->getChildren().begin();
|
for (auto it = rootFolder->getChildren().begin(); // Line break.
|
||||||
it != rootFolder->getChildren().end(); it++) {
|
it != rootFolder->getChildren().end(); it++) {
|
||||||
setupSystemSortType((*it)->getSystem()->getRootFolder());
|
setupSystemSortType((*it)->getSystem()->getRootFolder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setupSystemSortType(rootFolder);
|
setupSystemSortType(rootFolder);
|
||||||
|
|
||||||
rootFolder->sort(rootFolder->getSortTypeFromString(
|
rootFolder->sort(rootFolder->getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||||
rootFolder->getSortTypeString()), favoritesSorting);
|
favoritesSorting);
|
||||||
|
|
||||||
if (reloadGamelist)
|
if (reloadGamelist)
|
||||||
ViewController::get()->reloadGameListView(this, false);
|
ViewController::get()->reloadGameListView(this, false);
|
||||||
|
@ -1079,7 +1069,8 @@ void SystemData::loadTheme()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::writeMetaData() {
|
void SystemData::writeMetaData()
|
||||||
|
{
|
||||||
if (Settings::getInstance()->getBool("IgnoreGamelist") || mIsCollectionSystem)
|
if (Settings::getInstance()->getBool("IgnoreGamelist") || mIsCollectionSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1087,7 +1078,8 @@ void SystemData::writeMetaData() {
|
||||||
updateGamelist(this);
|
updateGamelist(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::onMetaDataSavePoint() {
|
void SystemData::onMetaDataSavePoint()
|
||||||
|
{
|
||||||
if (Settings::getInstance()->getString("SaveGamelistsMode") != "always")
|
if (Settings::getInstance()->getString("SaveGamelistsMode") != "always")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1100,15 +1092,15 @@ void SystemData::setupSystemSortType(FileData* mRootFolder)
|
||||||
if (Settings::getInstance()->getString("DefaultSortOrder") != "") {
|
if (Settings::getInstance()->getString("DefaultSortOrder") != "") {
|
||||||
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||||
if (FileSorts::SortTypes.at(i).description ==
|
if (FileSorts::SortTypes.at(i).description ==
|
||||||
Settings::getInstance()->getString("DefaultSortOrder")) {
|
Settings::getInstance()->getString("DefaultSortOrder")) {
|
||||||
mRootFolder->setSortTypeString(Settings::getInstance()->
|
mRootFolder->setSortTypeString(
|
||||||
getString("DefaultSortOrder"));
|
Settings::getInstance()->getString("DefaultSortOrder"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If no valid sort type was defined in the configuration file, set to default sorting.
|
// If no valid sort type was defined in the configuration file, set to default sorting.
|
||||||
if (mRootFolder->getSortTypeString() == "")
|
if (mRootFolder->getSortTypeString() == "")
|
||||||
mRootFolder->setSortTypeString(Settings::getInstance()->
|
mRootFolder->setSortTypeString(
|
||||||
getDefaultString("DefaultSortOrder"));
|
Settings::getInstance()->getDefaultString("DefaultSortOrder"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,15 +35,14 @@ class FindRules
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FindRules();
|
FindRules();
|
||||||
~FindRules();
|
|
||||||
|
|
||||||
void loadFindRules();
|
void loadFindRules();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct EmulatorRules {
|
struct EmulatorRules {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::vector<std::string> winRegistryPaths;
|
std::vector<std::string> winRegistryPaths;
|
||||||
#endif
|
#endif
|
||||||
std::vector<std::string> systemPaths;
|
std::vector<std::string> systemPaths;
|
||||||
std::vector<std::string> staticPaths;
|
std::vector<std::string> staticPaths;
|
||||||
};
|
};
|
||||||
|
@ -61,38 +60,41 @@ private:
|
||||||
class SystemData
|
class SystemData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SystemData(
|
SystemData(const std::string& name,
|
||||||
const std::string& name,
|
const std::string& fullName,
|
||||||
const std::string& fullName,
|
SystemEnvironmentData* envData,
|
||||||
SystemEnvironmentData* envData,
|
const std::string& themeFolder,
|
||||||
const std::string& themeFolder,
|
bool CollectionSystem = false,
|
||||||
bool CollectionSystem = false,
|
bool CustomCollectionSystem = false);
|
||||||
bool CustomCollectionSystem = false);
|
|
||||||
|
|
||||||
~SystemData();
|
~SystemData();
|
||||||
|
|
||||||
inline FileData* getRootFolder() const { return mRootFolder; };
|
FileData* getRootFolder() const { return mRootFolder; }
|
||||||
inline const std::string& getName() const { return mName; }
|
const std::string& getName() const { return mName; }
|
||||||
inline const std::string& getFullName() const { return mFullName; }
|
const std::string& getFullName() const { return mFullName; }
|
||||||
inline const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
||||||
inline const std::vector<std::string>& getExtensions() const
|
const std::vector<std::string>& getExtensions() const { return mEnvData->mSearchExtensions; }
|
||||||
{ return mEnvData->mSearchExtensions; }
|
const std::string& getThemeFolder() const { return mThemeFolder; }
|
||||||
inline const std::string& getThemeFolder() const { return mThemeFolder; }
|
SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
const std::vector<PlatformIds::PlatformId>& getPlatformIds() const
|
||||||
inline const std::vector<PlatformIds::PlatformId>& getPlatformIds() const
|
{
|
||||||
{ return mEnvData->mPlatformIds; }
|
return mEnvData->mPlatformIds;
|
||||||
inline bool hasPlatformId(PlatformIds::PlatformId id) { if (!mEnvData) return false;
|
}
|
||||||
return std::find(mEnvData->mPlatformIds.cbegin(), mEnvData->mPlatformIds.cend(), id)
|
bool hasPlatformId(PlatformIds::PlatformId id)
|
||||||
!= mEnvData->mPlatformIds.cend(); }
|
{
|
||||||
|
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;
|
std::string getGamelistPath(bool forWrite) const;
|
||||||
bool hasGamelist() const;
|
|
||||||
std::string getThemePath() const;
|
std::string getThemePath() const;
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> getDisplayedGameCount() const;
|
std::pair<unsigned int, unsigned int> getDisplayedGameCount() const;
|
||||||
bool getScrapeFlag() { return mScrapeFlag; };
|
bool getScrapeFlag() { return mScrapeFlag; }
|
||||||
void setScrapeFlag(bool scrapeflag) { mScrapeFlag = scrapeflag; }
|
void setScrapeFlag(bool scrapeflag) { mScrapeFlag = scrapeflag; }
|
||||||
|
|
||||||
static void deleteSystems();
|
static void deleteSystems();
|
||||||
|
@ -106,16 +108,22 @@ public:
|
||||||
static std::vector<SystemData*> sSystemVector;
|
static std::vector<SystemData*> sSystemVector;
|
||||||
static std::unique_ptr<FindRules> sFindRules;
|
static std::unique_ptr<FindRules> sFindRules;
|
||||||
|
|
||||||
inline std::vector<SystemData*>::const_iterator getIterator() const
|
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.cbegin(), sSystemVector.cend(), this);
|
||||||
{ return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this); };
|
}
|
||||||
inline bool isCollection() { return mIsCollectionSystem; };
|
std::vector<SystemData*>::const_reverse_iterator getRevIterator() const
|
||||||
inline bool isCustomCollection() { return mIsCustomCollectionSystem; };
|
{
|
||||||
inline bool isGroupedCustomCollection() { return mIsGroupedCustomCollectionSystem; };
|
return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this);
|
||||||
|
}
|
||||||
|
bool isCollection() { return mIsCollectionSystem; }
|
||||||
|
bool isCustomCollection() { return mIsCustomCollectionSystem; }
|
||||||
|
bool isGroupedCustomCollection() { return mIsGroupedCustomCollectionSystem; }
|
||||||
void setIsGroupedCustomCollection(bool isGroupedCustom)
|
void setIsGroupedCustomCollection(bool isGroupedCustom)
|
||||||
{ mIsGroupedCustomCollectionSystem = isGroupedCustom; };
|
{
|
||||||
inline bool isGameSystem() { return mIsGameSystem; };
|
mIsGroupedCustomCollectionSystem = isGroupedCustom;
|
||||||
|
};
|
||||||
|
bool isGameSystem() { return mIsGameSystem; }
|
||||||
|
|
||||||
bool isVisible();
|
bool isVisible();
|
||||||
|
|
||||||
|
@ -123,14 +131,14 @@ public:
|
||||||
SystemData* getPrev() const;
|
SystemData* getPrev() const;
|
||||||
static SystemData* getRandomSystem(const SystemData* currentSystem);
|
static SystemData* getRandomSystem(const SystemData* currentSystem);
|
||||||
FileData* getRandomGame(const FileData* currentGame = nullptr);
|
FileData* getRandomGame(const FileData* currentGame = nullptr);
|
||||||
FileData* getPlaceholder() { return mPlaceholder; };
|
FileData* getPlaceholder() { return mPlaceholder; }
|
||||||
|
|
||||||
void sortSystem(bool reloadGamelist = true, bool jumpToFirstRow = false);
|
void sortSystem(bool reloadGamelist = true, bool jumpToFirstRow = false);
|
||||||
|
|
||||||
// Load or re-load theme.
|
// Load or re-load theme.
|
||||||
void loadTheme();
|
void loadTheme();
|
||||||
|
|
||||||
FileFilterIndex* getIndex() { return mFilterIndex; };
|
FileFilterIndex* getIndex() { return mFilterIndex; }
|
||||||
void onMetaDataSavePoint();
|
void onMetaDataSavePoint();
|
||||||
void writeMetaData();
|
void writeMetaData();
|
||||||
|
|
||||||
|
@ -141,7 +149,7 @@ private:
|
||||||
bool mIsCustomCollectionSystem;
|
bool mIsCustomCollectionSystem;
|
||||||
bool mIsGroupedCustomCollectionSystem;
|
bool mIsGroupedCustomCollectionSystem;
|
||||||
bool mIsGameSystem;
|
bool mIsGameSystem;
|
||||||
bool mScrapeFlag; // Only used by scraper GUI to remember which systems to scrape.
|
bool mScrapeFlag; // Only used by scraper GUI to remember which systems to scrape.
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mFullName;
|
std::string mFullName;
|
||||||
SystemEnvironmentData* mEnvData;
|
SystemEnvironmentData* mEnvData;
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
#if defined(BUILD_VLC_PLAYER)
|
#if defined(BUILD_VLC_PLAYER)
|
||||||
#include "components/VideoVlcComponent.h"
|
#include "components/VideoVlcComponent.h"
|
||||||
#endif
|
#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 "AudioManager.h"
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "SystemData.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 <random>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -36,24 +36,23 @@
|
||||||
|
|
||||||
#define FADE_TIME 300
|
#define FADE_TIME 300
|
||||||
|
|
||||||
SystemScreensaver::SystemScreensaver(
|
SystemScreensaver::SystemScreensaver(Window* window)
|
||||||
Window* window)
|
: mWindow(window)
|
||||||
: mWindow(window),
|
, mState(STATE_INACTIVE)
|
||||||
mState(STATE_INACTIVE),
|
, mImageScreensaver(nullptr)
|
||||||
mImageScreensaver(nullptr),
|
, mVideoScreensaver(nullptr)
|
||||||
mVideoScreensaver(nullptr),
|
, mCurrentGame(nullptr)
|
||||||
mCurrentGame(nullptr),
|
, mPreviousGame(nullptr)
|
||||||
mPreviousGame(nullptr),
|
, mTimer(0)
|
||||||
mTimer(0),
|
, mMediaSwapTime(0)
|
||||||
mMediaSwapTime(0),
|
, mTriggerNextGame(false)
|
||||||
mTriggerNextGame(false),
|
, mHasMediaFiles(false)
|
||||||
mHasMediaFiles(false),
|
, mFallbackScreensaver(false)
|
||||||
mFallbackScreensaver(false),
|
, mOpacity(0.0f)
|
||||||
mOpacity(0.0f),
|
, mDimValue(1.0)
|
||||||
mDimValue(1.0),
|
, mRectangleFadeIn(50)
|
||||||
mRectangleFadeIn(50),
|
, mTextFadeIn(0)
|
||||||
mTextFadeIn(0),
|
, mSaturationAmount(1.0)
|
||||||
mSaturationAmount(1.0)
|
|
||||||
{
|
{
|
||||||
mWindow->setScreensaver(this);
|
mWindow->setScreensaver(this);
|
||||||
}
|
}
|
||||||
|
@ -65,21 +64,6 @@ SystemScreensaver::~SystemScreensaver()
|
||||||
delete mImageScreensaver;
|
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)
|
void SystemScreensaver::startScreensaver(bool generateMediaList)
|
||||||
{
|
{
|
||||||
std::string path = "";
|
std::string path = "";
|
||||||
|
@ -146,14 +130,14 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
|
||||||
mImageScreensaver->setImage(path);
|
mImageScreensaver->setImage(path);
|
||||||
mImageScreensaver->setOrigin(0.5f, 0.5f);
|
mImageScreensaver->setOrigin(0.5f, 0.5f);
|
||||||
mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
||||||
Renderer::getScreenHeight() / 2.0f);
|
Renderer::getScreenHeight() / 2.0f);
|
||||||
|
|
||||||
if (Settings::getInstance()->getBool("ScreensaverStretchImages"))
|
if (Settings::getInstance()->getBool("ScreensaverStretchImages"))
|
||||||
mImageScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
mImageScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
else
|
else
|
||||||
mImageScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
mImageScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
}
|
}
|
||||||
mTimer = 0;
|
mTimer = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -179,7 +163,7 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
|
||||||
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo"))
|
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo"))
|
||||||
generateOverlayInfo();
|
generateOverlayInfo();
|
||||||
|
|
||||||
#if defined(_RPI_)
|
#if defined(_RPI_)
|
||||||
// Create the correct type of video component.
|
// Create the correct type of video component.
|
||||||
if (Settings::getInstance()->getBool("ScreensaverOmxPlayer"))
|
if (Settings::getInstance()->getBool("ScreensaverOmxPlayer"))
|
||||||
mVideoScreensaver = new VideoOmxComponent(mWindow);
|
mVideoScreensaver = new VideoOmxComponent(mWindow);
|
||||||
|
@ -187,26 +171,26 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
|
||||||
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
||||||
else
|
else
|
||||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||||
#elif defined(BUILD_VLC_PLAYER)
|
#elif defined(BUILD_VLC_PLAYER)
|
||||||
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||||
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
||||||
else
|
else
|
||||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||||
#else
|
#else
|
||||||
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mVideoScreensaver->topWindow(true);
|
mVideoScreensaver->topWindow(true);
|
||||||
mVideoScreensaver->setOrigin(0.5f, 0.5f);
|
mVideoScreensaver->setOrigin(0.5f, 0.5f);
|
||||||
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
||||||
Renderer::getScreenHeight() / 2.0f);
|
Renderer::getScreenHeight() / 2.0f);
|
||||||
|
|
||||||
if (Settings::getInstance()->getBool("ScreensaverStretchVideos"))
|
if (Settings::getInstance()->getBool("ScreensaverStretchVideos"))
|
||||||
mVideoScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
mVideoScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
else
|
else
|
||||||
mVideoScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
mVideoScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
|
|
||||||
mVideoScreensaver->setVideo(path);
|
mVideoScreensaver->setVideo(path);
|
||||||
mVideoScreensaver->setScreensaverMode(true);
|
mVideoScreensaver->setScreensaverMode(true);
|
||||||
|
@ -229,16 +213,17 @@ void SystemScreensaver::stopScreensaver()
|
||||||
|
|
||||||
mState = STATE_INACTIVE;
|
mState = STATE_INACTIVE;
|
||||||
|
|
||||||
mDimValue = 1.0;
|
mDimValue = 1.0f;
|
||||||
mRectangleFadeIn = 50;
|
mRectangleFadeIn = 50;
|
||||||
mTextFadeIn = 0;
|
mTextFadeIn = 0;
|
||||||
mSaturationAmount = 1.0;
|
mSaturationAmount = 1.0f;
|
||||||
|
|
||||||
if (mGameOverlay)
|
if (mGameOverlay)
|
||||||
mGameOverlay.reset();
|
mGameOverlay.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemScreensaver::nextGame() {
|
void SystemScreensaver::nextGame()
|
||||||
|
{
|
||||||
stopScreensaver();
|
stopScreensaver();
|
||||||
startScreensaver(false);
|
startScreensaver(false);
|
||||||
}
|
}
|
||||||
|
@ -249,8 +234,8 @@ void SystemScreensaver::launchGame()
|
||||||
// Launching game
|
// Launching game
|
||||||
ViewController::get()->triggerGameLaunch(mCurrentGame);
|
ViewController::get()->triggerGameLaunch(mCurrentGame);
|
||||||
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
||||||
IGameListView* view = ViewController::get()->
|
IGameListView* view =
|
||||||
getGameListView(mCurrentGame->getSystem()).get();
|
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
||||||
view->setCursor(mCurrentGame);
|
view->setCursor(mCurrentGame);
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
}
|
}
|
||||||
|
@ -261,8 +246,8 @@ void SystemScreensaver::goToGame()
|
||||||
if (mCurrentGame != nullptr) {
|
if (mCurrentGame != nullptr) {
|
||||||
// Go to the game in the gamelist view, but don't launch it.
|
// Go to the game in the gamelist view, but don't launch it.
|
||||||
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
||||||
IGameListView* view = ViewController::get()->
|
IGameListView* view =
|
||||||
getGameListView(mCurrentGame->getSystem()).get();
|
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
||||||
view->setCursor(mCurrentGame);
|
view->setCursor(mCurrentGame);
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
}
|
}
|
||||||
|
@ -276,7 +261,7 @@ void SystemScreensaver::renderScreensaver()
|
||||||
// Render a black background below the video.
|
// Render a black background below the video.
|
||||||
Renderer::setMatrix(Transform4x4f::Identity());
|
Renderer::setMatrix(Transform4x4f::Identity());
|
||||||
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
||||||
|
|
||||||
// Only render the video if the state requires it.
|
// Only render the video if the state requires it.
|
||||||
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
||||||
|
@ -288,7 +273,7 @@ void SystemScreensaver::renderScreensaver()
|
||||||
// Render a black background below the image.
|
// Render a black background below the image.
|
||||||
Renderer::setMatrix(Transform4x4f::Identity());
|
Renderer::setMatrix(Transform4x4f::Identity());
|
||||||
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
||||||
|
|
||||||
// Only render the image if the state requires it.
|
// Only render the image if the state requires it.
|
||||||
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
||||||
|
@ -305,20 +290,20 @@ void SystemScreensaver::renderScreensaver()
|
||||||
Renderer::setMatrix(Transform4x4f::Identity());
|
Renderer::setMatrix(Transform4x4f::Identity());
|
||||||
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
|
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
|
||||||
if (mHasMediaFiles) {
|
if (mHasMediaFiles) {
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
||||||
#endif
|
#endif
|
||||||
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
|
||||||
mGameOverlay) {
|
mGameOverlay) {
|
||||||
if (mGameOverlayRectangleCoords.size() == 4) {
|
if (mGameOverlayRectangleCoords.size() == 4) {
|
||||||
Renderer::drawRect(mGameOverlayRectangleCoords[0],
|
Renderer::drawRect(
|
||||||
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
|
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
||||||
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
|
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
||||||
0x00000000 | mRectangleFadeIn );
|
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
||||||
}
|
}
|
||||||
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 6 +
|
mRectangleFadeIn =
|
||||||
mRectangleFadeIn / 20, 0, 170);
|
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
||||||
|
|
||||||
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
||||||
if (mTextFadeIn > 50)
|
if (mTextFadeIn > 50)
|
||||||
|
@ -333,7 +318,7 @@ void SystemScreensaver::renderScreensaver()
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getString("ScreensaverType") == "video") {
|
else if (Settings::getInstance()->getString("ScreensaverType") == "video") {
|
||||||
if (mHasMediaFiles) {
|
if (mHasMediaFiles) {
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
Renderer::shaderParameters videoParameters;
|
Renderer::shaderParameters videoParameters;
|
||||||
unsigned int shaders = 0;
|
unsigned int shaders = 0;
|
||||||
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
|
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
|
||||||
|
@ -341,6 +326,7 @@ void SystemScreensaver::renderScreensaver()
|
||||||
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
||||||
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
||||||
float heightModifier = Renderer::getScreenHeightModifier();
|
float heightModifier = Renderer::getScreenHeightModifier();
|
||||||
|
// clang-format off
|
||||||
if (heightModifier < 1)
|
if (heightModifier < 1)
|
||||||
videoParameters.blurPasses = 2; // Below 1080
|
videoParameters.blurPasses = 2; // Below 1080
|
||||||
else if (heightModifier >= 4)
|
else if (heightModifier >= 4)
|
||||||
|
@ -355,21 +341,22 @@ void SystemScreensaver::renderScreensaver()
|
||||||
videoParameters.blurPasses = 3; // 1440
|
videoParameters.blurPasses = 3; // 1440
|
||||||
else if (heightModifier >= 1)
|
else if (heightModifier >= 1)
|
||||||
videoParameters.blurPasses = 2; // 1080
|
videoParameters.blurPasses = 2; // 1080
|
||||||
|
// clang-format on
|
||||||
}
|
}
|
||||||
Renderer::shaderPostprocessing(shaders, videoParameters);
|
Renderer::shaderPostprocessing(shaders, videoParameters);
|
||||||
#endif
|
#endif
|
||||||
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
|
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
|
||||||
if (mGameOverlayRectangleCoords.size() == 4) {
|
if (mGameOverlayRectangleCoords.size() == 4) {
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY);
|
Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY);
|
||||||
#endif
|
#endif
|
||||||
Renderer::drawRect(mGameOverlayRectangleCoords[0],
|
Renderer::drawRect(
|
||||||
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
|
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
||||||
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
|
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
||||||
0x00000000 | mRectangleFadeIn );
|
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
||||||
}
|
}
|
||||||
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 6 +
|
mRectangleFadeIn =
|
||||||
mRectangleFadeIn / 20, 0, 170);
|
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
||||||
|
|
||||||
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
||||||
if (mTextFadeIn > 50)
|
if (mTextFadeIn > 50)
|
||||||
|
@ -383,8 +370,8 @@ void SystemScreensaver::renderScreensaver()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mFallbackScreensaver ||
|
if (mFallbackScreensaver ||
|
||||||
Settings::getInstance()->getString("ScreensaverType") == "dim") {
|
Settings::getInstance()->getString("ScreensaverType") == "dim") {
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
Renderer::shaderParameters dimParameters;
|
Renderer::shaderParameters dimParameters;
|
||||||
dimParameters.fragmentDimValue = mDimValue;
|
dimParameters.fragmentDimValue = mDimValue;
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters);
|
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters);
|
||||||
|
@ -394,22 +381,22 @@ void SystemScreensaver::renderScreensaver()
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters);
|
Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters);
|
||||||
if (mSaturationAmount > 0.0)
|
if (mSaturationAmount > 0.0)
|
||||||
mSaturationAmount = Math::clamp(mSaturationAmount - 0.035f, 0.0f, 1.0f);
|
mSaturationAmount = Math::clamp(mSaturationAmount - 0.035f, 0.0f, 1.0f);
|
||||||
#else
|
#else
|
||||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
|
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
||||||
Renderer::getScreenHeight(), 0x000000A0, 0x000000A0);
|
0x000000A0, 0x000000A0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
|
else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
Renderer::shaderParameters blackParameters;
|
Renderer::shaderParameters blackParameters;
|
||||||
blackParameters.fragmentDimValue = mDimValue;
|
blackParameters.fragmentDimValue = mDimValue;
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
|
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
|
||||||
if (mDimValue > 0.0)
|
if (mDimValue > 0.0)
|
||||||
mDimValue = Math::clamp(mDimValue - 0.045f, 0.0f, 1.0f);
|
mDimValue = Math::clamp(mDimValue - 0.045f, 0.0f, 1.0f);
|
||||||
#else
|
#else
|
||||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
|
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
||||||
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
|
0x000000FF, 0x000000FF);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,8 +445,8 @@ void SystemScreensaver::update(int deltaTime)
|
||||||
|
|
||||||
void SystemScreensaver::generateImageList()
|
void SystemScreensaver::generateImageList()
|
||||||
{
|
{
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it != SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
// We only want nodes from game systems that are not collections.
|
// We only want nodes from game systems that are not collections.
|
||||||
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
||||||
continue;
|
continue;
|
||||||
|
@ -475,8 +462,8 @@ void SystemScreensaver::generateImageList()
|
||||||
|
|
||||||
void SystemScreensaver::generateVideoList()
|
void SystemScreensaver::generateVideoList()
|
||||||
{
|
{
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it != SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
// We only want nodes from game systems that are not collections.
|
// We only want nodes from game systems that are not collections.
|
||||||
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
||||||
continue;
|
continue;
|
||||||
|
@ -493,7 +480,7 @@ void SystemScreensaver::generateVideoList()
|
||||||
void SystemScreensaver::generateCustomImageList()
|
void SystemScreensaver::generateCustomImageList()
|
||||||
{
|
{
|
||||||
std::string imageDir = Utils::FileSystem::expandHomePath(
|
std::string imageDir = Utils::FileSystem::expandHomePath(
|
||||||
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"));
|
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"));
|
||||||
|
|
||||||
// This makes it possible to set the custom image directory relative to the ES-DE binary
|
// This makes it possible to set the custom image directory relative to the ES-DE binary
|
||||||
// directory or the ROM directory.
|
// directory or the ROM directory.
|
||||||
|
@ -503,7 +490,7 @@ void SystemScreensaver::generateCustomImageList()
|
||||||
if (imageDir != "" && Utils::FileSystem::isDirectory(imageDir)) {
|
if (imageDir != "" && Utils::FileSystem::isDirectory(imageDir)) {
|
||||||
std::string imageFilter = ".jpg, .JPG, .png, .PNG";
|
std::string imageFilter = ".jpg, .JPG, .png, .PNG";
|
||||||
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(
|
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(
|
||||||
imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse"));
|
imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse"));
|
||||||
|
|
||||||
for (auto it = dirContent.begin(); it != dirContent.end(); it++) {
|
for (auto it = dirContent.begin(); it != dirContent.end(); it++) {
|
||||||
if (Utils::FileSystem::isRegularFile(*it)) {
|
if (Utils::FileSystem::isRegularFile(*it)) {
|
||||||
|
@ -513,8 +500,7 @@ void SystemScreensaver::generateCustomImageList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogWarning) << "Custom screensaver image directory '" <<
|
LOG(LogWarning) << "Custom screensaver image directory '" << imageDir << "' does not exist";
|
||||||
imageDir << "' does not exist.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,12 +526,11 @@ void SystemScreensaver::pickRandomImage(std::string& path)
|
||||||
// Get a random number in range.
|
// Get a random number in range.
|
||||||
std::random_device randDev;
|
std::random_device randDev;
|
||||||
// Mersenne Twister pseudorandom number generator.
|
// Mersenne Twister pseudorandom number generator.
|
||||||
std::mt19937 engine{randDev()};
|
std::mt19937 engine { randDev() };
|
||||||
std::uniform_int_distribution<int>
|
std::uniform_int_distribution<int> uniform_dist(0,
|
||||||
uniform_dist(0, static_cast<int>(mImageFiles.size()) - 1);
|
static_cast<int>(mImageFiles.size()) - 1);
|
||||||
index = uniform_dist(engine);
|
index = uniform_dist(engine);
|
||||||
}
|
} while (mPreviousGame && mImageFiles.at(index) == mPreviousGame);
|
||||||
while (mPreviousGame && mImageFiles.at(index) == mPreviousGame);
|
|
||||||
|
|
||||||
path = mImageFiles.at(index)->getImagePath();
|
path = mImageFiles.at(index)->getImagePath();
|
||||||
mGameName = mImageFiles.at(index)->getName();
|
mGameName = mImageFiles.at(index)->getName();
|
||||||
|
@ -575,12 +560,11 @@ void SystemScreensaver::pickRandomVideo(std::string& path)
|
||||||
// Get a random number in range.
|
// Get a random number in range.
|
||||||
std::random_device randDev;
|
std::random_device randDev;
|
||||||
// Mersenne Twister pseudorandom number generator.
|
// Mersenne Twister pseudorandom number generator.
|
||||||
std::mt19937 engine{randDev()};
|
std::mt19937 engine { randDev() };
|
||||||
std::uniform_int_distribution<int>
|
std::uniform_int_distribution<int> uniform_dist(0,
|
||||||
uniform_dist(0, static_cast<int>(mVideoFiles.size()) - 1);
|
static_cast<int>(mVideoFiles.size()) - 1);
|
||||||
index = uniform_dist(engine);
|
index = uniform_dist(engine);
|
||||||
}
|
} while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame);
|
||||||
while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame);
|
|
||||||
|
|
||||||
path = mVideoFiles.at(index)->getVideoPath();
|
path = mVideoFiles.at(index)->getVideoPath();
|
||||||
mGameName = mVideoFiles.at(index)->getName();
|
mGameName = mVideoFiles.at(index)->getName();
|
||||||
|
@ -604,12 +588,11 @@ void SystemScreensaver::pickRandomCustomImage(std::string& path)
|
||||||
// Get a random number in range.
|
// Get a random number in range.
|
||||||
std::random_device randDev;
|
std::random_device randDev;
|
||||||
// Mersenne Twister pseudorandom number generator.
|
// Mersenne Twister pseudorandom number generator.
|
||||||
std::mt19937 engine{randDev()};
|
std::mt19937 engine { randDev() };
|
||||||
std::uniform_int_distribution<int>
|
std::uniform_int_distribution<int> uniform_dist(
|
||||||
uniform_dist(0, static_cast<int>(mImageCustomFiles.size()) - 1);
|
0, static_cast<int>(mImageCustomFiles.size()) - 1);
|
||||||
index = uniform_dist(engine);
|
index = uniform_dist(engine);
|
||||||
}
|
} while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage);
|
||||||
while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage);
|
|
||||||
|
|
||||||
path = mImageCustomFiles.at(index);
|
path = mImageCustomFiles.at(index);
|
||||||
mPreviousCustomImage = path;
|
mPreviousCustomImage = path;
|
||||||
|
@ -633,8 +616,8 @@ void SystemScreensaver::generateOverlayInfo()
|
||||||
const std::string systemName = Utils::String::toUpper(mSystemName);
|
const std::string systemName = Utils::String::toUpper(mSystemName);
|
||||||
const std::string overlayText = gameName + "\n" + systemName;
|
const std::string overlayText = gameName + "\n" + systemName;
|
||||||
|
|
||||||
mGameOverlay = std::unique_ptr<TextCache>(mGameOverlayFont.at(0)->
|
mGameOverlay = std::unique_ptr<TextCache>(
|
||||||
buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
|
mGameOverlayFont.at(0)->buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
|
||||||
|
|
||||||
float textSizeX;
|
float textSizeX;
|
||||||
float textSizeY = mGameOverlayFont[0].get()->sizeText(overlayText).y();
|
float textSizeY = mGameOverlayFont[0].get()->sizeText(overlayText).y();
|
||||||
|
@ -645,7 +628,7 @@ void SystemScreensaver::generateOverlayInfo()
|
||||||
// injected in the size calculation. Regardless, this workaround is working
|
// injected in the size calculation. Regardless, this workaround is working
|
||||||
// fine for the time being.
|
// fine for the time being.
|
||||||
if (mGameOverlayFont[0].get()->sizeText(gameName).x() >
|
if (mGameOverlayFont[0].get()->sizeText(gameName).x() >
|
||||||
mGameOverlayFont[0].get()->sizeText(systemName).x())
|
mGameOverlayFont[0].get()->sizeText(systemName).x())
|
||||||
textSizeX = mGameOverlayFont[0].get()->sizeText(gameName).x();
|
textSizeX = mGameOverlayFont[0].get()->sizeText(gameName).x();
|
||||||
else
|
else
|
||||||
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x();
|
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x();
|
||||||
|
|
|
@ -22,9 +22,12 @@ public:
|
||||||
SystemScreensaver(Window* window);
|
SystemScreensaver(Window* window);
|
||||||
virtual ~SystemScreensaver();
|
virtual ~SystemScreensaver();
|
||||||
|
|
||||||
virtual bool allowSleep();
|
virtual bool allowSleep()
|
||||||
virtual bool isScreensaverActive();
|
{
|
||||||
virtual bool isFallbackScreensaver();
|
return ((mVideoScreensaver == nullptr) && (mImageScreensaver == nullptr));
|
||||||
|
}
|
||||||
|
virtual bool isScreensaverActive() { return (mState != STATE_INACTIVE); }
|
||||||
|
virtual bool isFallbackScreensaver() { return mFallbackScreensaver; }
|
||||||
|
|
||||||
virtual void startScreensaver(bool generateMediaList);
|
virtual void startScreensaver(bool generateMediaList);
|
||||||
virtual void stopScreensaver();
|
virtual void stopScreensaver();
|
||||||
|
@ -35,8 +38,8 @@ public:
|
||||||
virtual void renderScreensaver();
|
virtual void renderScreensaver();
|
||||||
virtual void update(int deltaTime);
|
virtual void update(int deltaTime);
|
||||||
|
|
||||||
virtual FileData* getCurrentGame() { return mCurrentGame; };
|
virtual FileData* getCurrentGame() { return mCurrentGame; }
|
||||||
virtual void triggerNextGame() { mTriggerNextGame = true; };
|
virtual void triggerNextGame() { mTriggerNextGame = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void generateImageList();
|
void generateImageList();
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
|
|
||||||
#include "VolumeControl.h"
|
#include "VolumeControl.h"
|
||||||
|
|
||||||
#include "math/Misc.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "math/Misc.h"
|
||||||
|
|
||||||
#if defined(_RPI_)
|
#if defined(_RPI_)
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
@ -38,15 +38,15 @@ std::string VolumeControl::mixerCard = "default";
|
||||||
VolumeControl* VolumeControl::sInstance = nullptr;
|
VolumeControl* VolumeControl::sInstance = nullptr;
|
||||||
|
|
||||||
VolumeControl::VolumeControl()
|
VolumeControl::VolumeControl()
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
: mixerIndex(0),
|
: mixerIndex(0)
|
||||||
mixerHandle(nullptr),
|
, mixerHandle(nullptr)
|
||||||
mixerElem(nullptr),
|
, mixerElem(nullptr)
|
||||||
mixerSelemId(nullptr)
|
, mixerSelemId(nullptr)
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
: mixerHandle(nullptr),
|
: mixerHandle(nullptr)
|
||||||
endpointVolume(nullptr)
|
, endpointVolume(nullptr)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ VolumeControl::VolumeControl()
|
||||||
VolumeControl::~VolumeControl()
|
VolumeControl::~VolumeControl()
|
||||||
{
|
{
|
||||||
deinit();
|
deinit();
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeControl* VolumeControl::getInstance()
|
VolumeControl* VolumeControl::getInstance()
|
||||||
|
@ -79,14 +79,15 @@ void VolumeControl::deleteInstance()
|
||||||
void VolumeControl::init()
|
void VolumeControl::init()
|
||||||
{
|
{
|
||||||
// Initialize audio mixer interface.
|
// Initialize audio mixer interface.
|
||||||
#if defined(__linux__)
|
|
||||||
|
#if defined(__linux__)
|
||||||
// Try to open mixer device.
|
// Try to open mixer device.
|
||||||
if (mixerHandle == nullptr) {
|
if (mixerHandle == nullptr) {
|
||||||
|
#if defined(_RPI_)
|
||||||
// Allow user to override the AudioCard and AudioDevice in es_settings.xml.
|
// Allow user to override the AudioCard and AudioDevice in es_settings.xml.
|
||||||
#if defined(_RPI_)
|
|
||||||
mixerCard = Settings::getInstance()->getString("AudioCard");
|
mixerCard = Settings::getInstance()->getString("AudioCard");
|
||||||
mixerName = Settings::getInstance()->getString("AudioDevice");
|
mixerName = Settings::getInstance()->getString("AudioDevice");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
snd_mixer_selem_id_alloca(&mixerSelemId);
|
snd_mixer_selem_id_alloca(&mixerSelemId);
|
||||||
// Sets simple-mixer index and name.
|
// Sets simple-mixer index and name.
|
||||||
|
@ -106,8 +107,8 @@ void VolumeControl::init()
|
||||||
LOG(LogDebug) << "VolumeControl::init(): Mixer initialized";
|
LOG(LogDebug) << "VolumeControl::init(): Mixer initialized";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) <<
|
LOG(LogError)
|
||||||
"VolumeControl::init(): Failed to find mixer elements!";
|
<< "VolumeControl::init(): Failed to find mixer elements!";
|
||||||
snd_mixer_close(mixerHandle);
|
snd_mixer_close(mixerHandle);
|
||||||
mixerHandle = nullptr;
|
mixerHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -119,8 +120,8 @@ void VolumeControl::init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) <<
|
LOG(LogError)
|
||||||
"VolumeControl::init(): Failed to register simple element class!";
|
<< "VolumeControl::init(): Failed to register simple element class!";
|
||||||
snd_mixer_close(mixerHandle);
|
snd_mixer_close(mixerHandle);
|
||||||
mixerHandle = nullptr;
|
mixerHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -135,31 +136,30 @@ void VolumeControl::init()
|
||||||
LOG(LogError) << "VolumeControl::init(): Failed to open ALSA mixer!";
|
LOG(LogError) << "VolumeControl::init(): Failed to open ALSA mixer!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
// Windows Vista or above.
|
// Windows Vista or above.
|
||||||
if (endpointVolume == nullptr) {
|
if (endpointVolume == nullptr) {
|
||||||
CoInitialize(nullptr);
|
CoInitialize(nullptr);
|
||||||
IMMDeviceEnumerator* deviceEnumerator = nullptr;
|
IMMDeviceEnumerator* deviceEnumerator = nullptr;
|
||||||
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
|
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
|
||||||
__uuidof(IMMDeviceEnumerator), reinterpret_cast<LPVOID *>(&deviceEnumerator));
|
__uuidof(IMMDeviceEnumerator),
|
||||||
|
reinterpret_cast<LPVOID*>(&deviceEnumerator));
|
||||||
if (deviceEnumerator != nullptr) {
|
if (deviceEnumerator != nullptr) {
|
||||||
// Get default endpoint.
|
// Get default endpoint.
|
||||||
IMMDevice * defaultDevice = nullptr;
|
IMMDevice* defaultDevice = nullptr;
|
||||||
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
|
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
|
||||||
if (defaultDevice != nullptr) {
|
if (defaultDevice != nullptr) {
|
||||||
// Retrieve endpoint volume.
|
// Retrieve endpoint volume.
|
||||||
defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
|
defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER,
|
||||||
CLSCTX_INPROC_SERVER, nullptr,
|
nullptr, reinterpret_cast<LPVOID*>(&endpointVolume));
|
||||||
reinterpret_cast<LPVOID *>(&endpointVolume));
|
|
||||||
if (endpointVolume == nullptr)
|
if (endpointVolume == nullptr)
|
||||||
LOG(LogError) << "VolumeControl::init(): "
|
LOG(LogError) << "VolumeControl::init(): "
|
||||||
"Failed to get default audio endpoint volume!";
|
"Failed to get default audio endpoint volume!";
|
||||||
// Release default device. we don't need it anymore.
|
// Release default device. we don't need it anymore.
|
||||||
defaultDevice->Release();
|
defaultDevice->Release();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) <<
|
LOG(LogError) << "VolumeControl::init(): Failed to get default audio endpoint!";
|
||||||
"VolumeControl::init(): Failed to get default audio endpoint!";
|
|
||||||
}
|
}
|
||||||
// Release device enumerator. we don't need it anymore.
|
// Release device enumerator. we don't need it anymore.
|
||||||
deviceEnumerator->Release();
|
deviceEnumerator->Release();
|
||||||
|
@ -169,13 +169,14 @@ void VolumeControl::init()
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeControl::deinit()
|
void VolumeControl::deinit()
|
||||||
{
|
{
|
||||||
// Deinitialize audio mixer interface.
|
// Deinitialize audio mixer interface.
|
||||||
#if defined(__linux__)
|
|
||||||
|
#if defined(__linux__)
|
||||||
if (mixerHandle != nullptr) {
|
if (mixerHandle != nullptr) {
|
||||||
snd_mixer_detach(mixerHandle, mixerCard.c_str());
|
snd_mixer_detach(mixerHandle, mixerCard.c_str());
|
||||||
snd_mixer_free(mixerHandle);
|
snd_mixer_free(mixerHandle);
|
||||||
|
@ -183,28 +184,28 @@ void VolumeControl::deinit()
|
||||||
mixerHandle = nullptr;
|
mixerHandle = nullptr;
|
||||||
mixerElem = nullptr;
|
mixerElem = nullptr;
|
||||||
}
|
}
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
if (endpointVolume != nullptr) {
|
if (endpointVolume != nullptr) {
|
||||||
endpointVolume->Release();
|
endpointVolume->Release();
|
||||||
endpointVolume = nullptr;
|
endpointVolume = nullptr;
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int VolumeControl::getVolume() const
|
int VolumeControl::getVolume() const
|
||||||
{
|
{
|
||||||
int volume = 0;
|
int volume = 0;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (mixerElem != nullptr) {
|
if (mixerElem != nullptr) {
|
||||||
// Get volume range.
|
// Get volume range.
|
||||||
long minVolume;
|
long minVolume;
|
||||||
long maxVolume;
|
long maxVolume;
|
||||||
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
||||||
long rawVolume;
|
long rawVolume;
|
||||||
if (snd_mixer_selem_get_playback_volume(mixerElem,
|
if (snd_mixer_selem_get_playback_volume(mixerElem, SND_MIXER_SCHN_MONO, &rawVolume) ==
|
||||||
SND_MIXER_SCHN_MONO, &rawVolume) == 0) {
|
0) {
|
||||||
// Bring into range 0-100.
|
// Bring into range 0-100.
|
||||||
rawVolume -= minVolume;
|
rawVolume -= minVolume;
|
||||||
if (rawVolume > 0)
|
if (rawVolume > 0)
|
||||||
|
@ -218,7 +219,7 @@ int VolumeControl::getVolume() const
|
||||||
LOG(LogError) << "VolumeControl::getVolume(): Failed to get volume range";
|
LOG(LogError) << "VolumeControl::getVolume(): Failed to get volume range";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
if (endpointVolume != nullptr) {
|
if (endpointVolume != nullptr) {
|
||||||
// Windows Vista or above, uses EndpointVolume API.
|
// Windows Vista or above, uses EndpointVolume API.
|
||||||
float floatVolume = 0.0f; // 0-1
|
float floatVolume = 0.0f; // 0-1
|
||||||
|
@ -230,7 +231,7 @@ int VolumeControl::getVolume() const
|
||||||
LOG(LogError) << "VolumeControl::getVolume(): Failed to get master volume!";
|
LOG(LogError) << "VolumeControl::getVolume(): Failed to get master volume!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
volume = Math::clamp(volume, 0, 100);
|
volume = Math::clamp(volume, 0, 100);
|
||||||
return volume;
|
return volume;
|
||||||
|
@ -240,7 +241,7 @@ void VolumeControl::setVolume(int volume)
|
||||||
{
|
{
|
||||||
volume = Math::clamp(volume, 0, 100);
|
volume = Math::clamp(volume, 0, 100);
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
if (mixerElem != nullptr) {
|
if (mixerElem != nullptr) {
|
||||||
// Get volume range.
|
// Get volume range.
|
||||||
long minVolume;
|
long minVolume;
|
||||||
|
@ -248,10 +249,10 @@ void VolumeControl::setVolume(int volume)
|
||||||
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
if (snd_mixer_selem_get_playback_volume_range(mixerElem, &minVolume, &maxVolume) == 0) {
|
||||||
// Bring into minVolume-maxVolume range and set.
|
// Bring into minVolume-maxVolume range and set.
|
||||||
long rawVolume = (volume * (maxVolume - minVolume) / 100) + minVolume;
|
long rawVolume = (volume * (maxVolume - minVolume) / 100) + minVolume;
|
||||||
if (snd_mixer_selem_set_playback_volume(mixerElem,
|
if (snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_LEFT,
|
||||||
SND_MIXER_SCHN_FRONT_LEFT, rawVolume) < 0 ||
|
rawVolume) < 0 ||
|
||||||
snd_mixer_selem_set_playback_volume(mixerElem,
|
snd_mixer_selem_set_playback_volume(mixerElem, SND_MIXER_SCHN_FRONT_RIGHT,
|
||||||
SND_MIXER_SCHN_FRONT_RIGHT, rawVolume) < 0) {
|
rawVolume) < 0) {
|
||||||
LOG(LogError) << "VolumeControl::getVolume(): Failed to set mixer volume";
|
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";
|
LOG(LogError) << "VolumeControl::getVolume(): Failed to get volume range";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
if (endpointVolume != nullptr) {
|
if (endpointVolume != nullptr) {
|
||||||
// Windows Vista or above, uses EndpointVolume API.
|
// Windows Vista or above, uses EndpointVolume API.
|
||||||
float floatVolume = 0.0f; // 0-1
|
float floatVolume = 0.0f; // 0-1
|
||||||
|
@ -268,5 +269,5 @@ void VolumeControl::setVolume(int volume)
|
||||||
if (endpointVolume->SetMasterVolumeLevelScalar(floatVolume, nullptr) != S_OK)
|
if (endpointVolume->SetMasterVolumeLevelScalar(floatVolume, nullptr) != S_OK)
|
||||||
LOG(LogError) << "VolumeControl::setVolume(): Failed to set master volume";
|
LOG(LogError) << "VolumeControl::setVolume(): Failed to set master volume";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,18 @@ public:
|
||||||
|
|
||||||
static VolumeControl* sInstance;
|
static VolumeControl* sInstance;
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
static std::string mixerName;
|
static std::string mixerName;
|
||||||
static std::string mixerCard;
|
static std::string mixerCard;
|
||||||
int mixerIndex;
|
int mixerIndex;
|
||||||
snd_mixer_t* mixerHandle;
|
snd_mixer_t* mixerHandle;
|
||||||
snd_mixer_elem_t* mixerElem;
|
snd_mixer_elem_t* mixerElem;
|
||||||
snd_mixer_selem_id_t* mixerSelemId;
|
snd_mixer_selem_id_t* mixerSelemId;
|
||||||
#elif defined(_WIN64)
|
#elif defined(_WIN64)
|
||||||
HMIXER mixerHandle;
|
HMIXER mixerHandle;
|
||||||
MIXERCONTROL mixerControl;
|
MIXERCONTROL mixerControl;
|
||||||
IAudioEndpointVolume * endpointVolume;
|
IAudioEndpointVolume* endpointVolume;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_VOLUME_CONTROL_H
|
#endif // ES_APP_VOLUME_CONTROL_H
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
class MoveCameraAnimation : public Animation
|
class MoveCameraAnimation : public Animation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MoveCameraAnimation(
|
MoveCameraAnimation(Transform4x4f& camera, const Vector3f& target)
|
||||||
Transform4x4f& camera,
|
: mCameraStart(camera)
|
||||||
const Vector3f& target)
|
, mTarget(target)
|
||||||
: mCameraStart(camera),
|
, cameraOut(camera)
|
||||||
mTarget(target),
|
{
|
||||||
cameraOut(camera) {}
|
}
|
||||||
|
|
||||||
int getDuration() const override { return 400; }
|
int getDuration() const override { return 400; }
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public:
|
||||||
// Cubic ease out.
|
// Cubic ease out.
|
||||||
t -= 1;
|
t -= 1;
|
||||||
cameraOut.translation() =
|
cameraOut.translation() =
|
||||||
-Vector3f().lerp(-mCameraStart.translation(), mTarget, t * t * t + 1);
|
-Vector3f().lerp(-mCameraStart.translation(), mTarget, t * t * t + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "guis/GuiCollectionSystemsOptions.h"
|
#include "guis/GuiCollectionSystemsOptions.h"
|
||||||
|
|
||||||
|
#include "CollectionSystemsManager.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
|
@ -16,21 +17,23 @@
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "CollectionSystemsManager.h"
|
|
||||||
|
|
||||||
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(Window* window, std::string title)
|
||||||
Window* window,
|
: GuiSettings(window, title)
|
||||||
std::string title)
|
, mAddedCustomCollection(false)
|
||||||
: GuiSettings(window, title),
|
, mDeletedCustomCollection(false)
|
||||||
mAddedCustomCollection(false),
|
|
||||||
mDeletedCustomCollection(false)
|
|
||||||
{
|
{
|
||||||
// Finish editing custom collection.
|
// Finish editing custom collection.
|
||||||
if (CollectionSystemsManager::get()->isEditing()) {
|
if (CollectionSystemsManager::get()->isEditing()) {
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" +
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
Utils::String::toUpper(CollectionSystemsManager::get()->getEditingCollection()) +
|
mWindow,
|
||||||
"' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
"FINISH EDITING '" +
|
||||||
|
Utils::String::toUpper(
|
||||||
|
CollectionSystemsManager::get()->getEditingCollection()) +
|
||||||
|
"' COLLECTION",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.makeAcceptInputHandler([this] {
|
row.makeAcceptInputHandler([this] {
|
||||||
CollectionSystemsManager::get()->exitEditMode();
|
CollectionSystemsManager::get()->exitEditMode();
|
||||||
mWindow->invalidateCachedBackground();
|
mWindow->invalidateCachedBackground();
|
||||||
|
@ -40,19 +43,20 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatic collections.
|
// Automatic collections.
|
||||||
collection_systems_auto = std::make_shared<OptionListComponent<std::string>>
|
collection_systems_auto = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||||
std::map<std::string, CollectionSystemData, stringComparator> autoSystems =
|
std::map<std::string, CollectionSystemData, stringComparator> autoSystems =
|
||||||
CollectionSystemsManager::get()->getAutoCollectionSystems();
|
CollectionSystemsManager::get()->getAutoCollectionSystems();
|
||||||
// Add automatic systems.
|
// Add automatic systems.
|
||||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||||
it = autoSystems.cbegin(); it != autoSystems.cend() ; it++)
|
autoSystems.cbegin();
|
||||||
|
it != autoSystems.cend(); it++)
|
||||||
collection_systems_auto->add(it->second.decl.longName, it->second.decl.name,
|
collection_systems_auto->add(it->second.decl.longName, it->second.decl.name,
|
||||||
it->second.isEnabled);
|
it->second.isEnabled);
|
||||||
addWithLabel("AUTOMATIC GAME COLLECTIONS", collection_systems_auto);
|
addWithLabel("AUTOMATIC GAME COLLECTIONS", collection_systems_auto);
|
||||||
addSaveFunc([this, autoSystems] {
|
addSaveFunc([this, autoSystems] {
|
||||||
std::string autoSystemsSelected = Utils::String::vectorToDelimitedString(
|
std::string autoSystemsSelected = Utils::String::vectorToDelimitedString(
|
||||||
collection_systems_auto->getSelectedObjects(), ",", true);
|
collection_systems_auto->getSelectedObjects(), ",", true);
|
||||||
std::string autoSystemsConfig = Settings::getInstance()->getString("CollectionSystemsAuto");
|
std::string autoSystemsConfig = Settings::getInstance()->getString("CollectionSystemsAuto");
|
||||||
if (autoSystemsSelected != autoSystemsConfig) {
|
if (autoSystemsSelected != autoSystemsConfig) {
|
||||||
if (CollectionSystemsManager::get()->isEditing())
|
if (CollectionSystemsManager::get()->isEditing())
|
||||||
|
@ -67,19 +71,19 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
}
|
}
|
||||||
else if (autoSystemsSelected != "") {
|
else if (autoSystemsSelected != "") {
|
||||||
std::vector<std::string> selectedVector =
|
std::vector<std::string> selectedVector =
|
||||||
Utils::String::delimitedStringToVector(autoSystemsSelected, ",");
|
Utils::String::delimitedStringToVector(autoSystemsSelected, ",");
|
||||||
std::vector<std::string> configuredVector =
|
std::vector<std::string> configuredVector =
|
||||||
Utils::String::delimitedStringToVector(autoSystemsConfig, ",");
|
Utils::String::delimitedStringToVector(autoSystemsConfig, ",");
|
||||||
for (std::string system : selectedVector) {
|
for (std::string system : selectedVector) {
|
||||||
if (std::find(configuredVector.begin(), configuredVector.end(), system) ==
|
if (std::find(configuredVector.begin(), configuredVector.end(), system) ==
|
||||||
configuredVector.end())
|
configuredVector.end())
|
||||||
addedAutoSystems.push_back(system);
|
addedAutoSystems.push_back(system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!addedAutoSystems.empty()) {
|
if (!addedAutoSystems.empty()) {
|
||||||
for (std::string system : addedAutoSystems)
|
for (std::string system : addedAutoSystems)
|
||||||
CollectionSystemsManager::get()->
|
CollectionSystemsManager::get()->repopulateCollection(
|
||||||
repopulateCollection(autoSystems.find(system)->second.system);
|
autoSystems.find(system)->second.system);
|
||||||
}
|
}
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
setNeedsReloading();
|
setNeedsReloading();
|
||||||
|
@ -88,50 +92,52 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Custom collections.
|
// Custom collections.
|
||||||
collection_systems_custom = std::make_shared<OptionListComponent<std::string>>
|
collection_systems_custom = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
mWindow, getHelpStyle(), "SELECT COLLECTIONS", true);
|
||||||
std::map<std::string, CollectionSystemData, stringComparator> customSystems =
|
std::map<std::string, CollectionSystemData, stringComparator> customSystems =
|
||||||
CollectionSystemsManager::get()->getCustomCollectionSystems();
|
CollectionSystemsManager::get()->getCustomCollectionSystems();
|
||||||
// Add custom systems.
|
// Add custom systems.
|
||||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||||
it = customSystems.cbegin(); it != customSystems.cend() ; it++)
|
customSystems.cbegin();
|
||||||
|
it != customSystems.cend(); it++)
|
||||||
collection_systems_custom->add(it->second.decl.longName, it->second.decl.name,
|
collection_systems_custom->add(it->second.decl.longName, it->second.decl.name,
|
||||||
it->second.isEnabled);
|
it->second.isEnabled);
|
||||||
|
|
||||||
addWithLabel("CUSTOM GAME COLLECTIONS", collection_systems_custom);
|
addWithLabel("CUSTOM GAME COLLECTIONS", collection_systems_custom);
|
||||||
addSaveFunc([this, customSystems] {
|
addSaveFunc([this, customSystems] {
|
||||||
if (!mDeletedCustomCollection) {
|
if (!mDeletedCustomCollection) {
|
||||||
std::string customSystemsSelected = Utils::String::vectorToDelimitedString(
|
std::string customSystemsSelected = Utils::String::vectorToDelimitedString(
|
||||||
collection_systems_custom->getSelectedObjects(), ",", true);
|
collection_systems_custom->getSelectedObjects(), ",", true);
|
||||||
std::string customSystemsConfig = Settings::getInstance()->
|
std::string customSystemsConfig =
|
||||||
getString("CollectionSystemsCustom");
|
Settings::getInstance()->getString("CollectionSystemsCustom");
|
||||||
if (customSystemsSelected != customSystemsConfig) {
|
if (customSystemsSelected != customSystemsConfig) {
|
||||||
if (CollectionSystemsManager::get()->isEditing())
|
if (CollectionSystemsManager::get()->isEditing())
|
||||||
CollectionSystemsManager::get()->exitEditMode();
|
CollectionSystemsManager::get()->exitEditMode();
|
||||||
Settings::getInstance()->setString("CollectionSystemsCustom",
|
Settings::getInstance()->setString("CollectionSystemsCustom",
|
||||||
customSystemsSelected);
|
customSystemsSelected);
|
||||||
// Check if any systems have been enabled, and if so repopulate them, which
|
// Check if any systems have been enabled, and if so repopulate them, which
|
||||||
// results in a complete initialization of their content. This is necessary as
|
// results in a complete initialization of their content. This is necessary as
|
||||||
// collections aren't updated while they are disabled.
|
// collections aren't updated while they are disabled.
|
||||||
std::vector<std::string> addedCustomSystems;
|
std::vector<std::string> addedCustomSystems;
|
||||||
if (customSystemsConfig == "") {
|
if (customSystemsConfig == "") {
|
||||||
addedCustomSystems =
|
addedCustomSystems =
|
||||||
Utils::String::delimitedStringToVector(customSystemsSelected, ",");
|
Utils::String::delimitedStringToVector(customSystemsSelected, ",");
|
||||||
}
|
}
|
||||||
else if (customSystemsSelected != "") {
|
else if (customSystemsSelected != "") {
|
||||||
std::vector<std::string> selectedVector =
|
std::vector<std::string> selectedVector =
|
||||||
Utils::String::delimitedStringToVector(customSystemsSelected, ",");
|
Utils::String::delimitedStringToVector(customSystemsSelected, ",");
|
||||||
std::vector<std::string> configuredVector =
|
std::vector<std::string> configuredVector =
|
||||||
Utils::String::delimitedStringToVector(customSystemsConfig, ",");
|
Utils::String::delimitedStringToVector(customSystemsConfig, ",");
|
||||||
for (std::string system : selectedVector) {
|
for (std::string system : selectedVector) {
|
||||||
if (std::find(configuredVector.begin(), configuredVector.end(), system) ==
|
if (std::find(configuredVector.begin(), configuredVector.end(), system) ==
|
||||||
configuredVector.end())
|
configuredVector.end())
|
||||||
addedCustomSystems.push_back(system);
|
addedCustomSystems.push_back(system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mAddedCustomCollection && !addedCustomSystems.empty()) {
|
if (!mAddedCustomCollection && !addedCustomSystems.empty()) {
|
||||||
for (std::string system : addedCustomSystems)
|
for (std::string system : addedCustomSystems)
|
||||||
CollectionSystemsManager::get()->
|
CollectionSystemsManager::get()->repopulateCollection(
|
||||||
repopulateCollection(customSystems.find(system)->second.system);
|
customSystems.find(system)->second.system);
|
||||||
}
|
}
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
setNeedsReloading();
|
setNeedsReloading();
|
||||||
|
@ -143,32 +149,33 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
|
|
||||||
// Create custom collection from theme.
|
// Create custom collection from theme.
|
||||||
std::vector<std::string> unusedFolders =
|
std::vector<std::string> unusedFolders =
|
||||||
CollectionSystemsManager::get()->getUnusedSystemsFromTheme();
|
CollectionSystemsManager::get()->getUnusedSystemsFromTheme();
|
||||||
if (unusedFolders.size() > 0) {
|
if (unusedFolders.size() > 0) {
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
auto themeCollection = std::make_shared<TextComponent>(mWindow,
|
auto themeCollection =
|
||||||
"CREATE NEW CUSTOM COLLECTION FROM THEME", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION FROM THEME",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
auto bracketThemeCollection = std::make_shared<ImageComponent>(mWindow);
|
auto bracketThemeCollection = std::make_shared<ImageComponent>(mWindow);
|
||||||
bracketThemeCollection->setImage(":/graphics/arrow.svg");
|
bracketThemeCollection->setImage(":/graphics/arrow.svg");
|
||||||
bracketThemeCollection->setResize(Vector2f(0,
|
bracketThemeCollection->setResize(
|
||||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||||
row.addElement(themeCollection, true);
|
row.addElement(themeCollection, true);
|
||||||
row.addElement(bracketThemeCollection, false);
|
row.addElement(bracketThemeCollection, false);
|
||||||
row.makeAcceptInputHandler([this, unusedFolders] {
|
row.makeAcceptInputHandler([this, unusedFolders] {
|
||||||
auto ss = new GuiSettings(mWindow, "SELECT THEME FOLDER");
|
auto ss = new GuiSettings(mWindow, "SELECT THEME FOLDER");
|
||||||
std::shared_ptr<OptionListComponent<std::string>> folderThemes =
|
std::shared_ptr<OptionListComponent<std::string>> folderThemes =
|
||||||
std::make_shared<OptionListComponent<std::string>>(mWindow,
|
std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||||
getHelpStyle(), "SELECT THEME FOLDER", true);
|
"SELECT THEME FOLDER", true);
|
||||||
// Add custom systems.
|
// Add custom systems.
|
||||||
for (auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ ) {
|
for (auto it = unusedFolders.cbegin(); it != unusedFolders.cend(); it++) {
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
std::string name = *it;
|
std::string name = *it;
|
||||||
std::function<void()> createCollectionCall = [this, name] {
|
std::function<void()> createCollectionCall = [this, name] {
|
||||||
createCustomCollection(name);
|
createCustomCollection(name);
|
||||||
};
|
};
|
||||||
row.makeAcceptInputHandler(createCollectionCall);
|
row.makeAcceptInputHandler(createCollectionCall);
|
||||||
auto themeFolder = std::make_shared<TextComponent>(mWindow,
|
auto themeFolder = std::make_shared<TextComponent>(
|
||||||
Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||||
row.addElement(themeFolder, true);
|
row.addElement(themeFolder, true);
|
||||||
// This transparent bracket is only added to generate the correct help prompts.
|
// This transparent bracket is only added to generate the correct help prompts.
|
||||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
@ -184,12 +191,11 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
|
|
||||||
// Create new custom collection.
|
// Create new custom collection.
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
auto newCollection = std::make_shared<TextComponent>(mWindow,
|
auto newCollection = std::make_shared<TextComponent>(mWindow, "CREATE NEW CUSTOM COLLECTION",
|
||||||
"CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
auto bracketNewCollection = std::make_shared<ImageComponent>(mWindow);
|
auto bracketNewCollection = std::make_shared<ImageComponent>(mWindow);
|
||||||
bracketNewCollection->setImage(":/graphics/arrow.svg");
|
bracketNewCollection->setImage(":/graphics/arrow.svg");
|
||||||
bracketNewCollection->setResize(Vector2f(0,
|
bracketNewCollection->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
|
||||||
row.addElement(newCollection, true);
|
row.addElement(newCollection, true);
|
||||||
row.addElement(bracketNewCollection, false);
|
row.addElement(bracketNewCollection, false);
|
||||||
auto createCollectionCall = [this](const std::string& newVal) {
|
auto createCollectionCall = [this](const std::string& newVal) {
|
||||||
|
@ -202,72 +208,72 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
createCustomCollection(name);
|
createCustomCollection(name);
|
||||||
};
|
};
|
||||||
row.makeAcceptInputHandler([this, createCollectionCall] {
|
row.makeAcceptInputHandler([this, createCollectionCall] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "New Collection Name", "",
|
||||||
"New Collection Name", "", createCollectionCall, false, "SAVE"));
|
createCollectionCall, false, "SAVE"));
|
||||||
});
|
});
|
||||||
addRow(row);
|
addRow(row);
|
||||||
|
|
||||||
// Delete custom collection.
|
// Delete custom collection.
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
auto deleteCollection = std::make_shared<TextComponent>(mWindow,
|
auto deleteCollection = std::make_shared<TextComponent>(
|
||||||
"DELETE CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
mWindow, "DELETE CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
auto bracketDeleteCollection = std::make_shared<ImageComponent>(mWindow);
|
auto bracketDeleteCollection = std::make_shared<ImageComponent>(mWindow);
|
||||||
bracketDeleteCollection->setImage(":/graphics/arrow.svg");
|
bracketDeleteCollection->setImage(":/graphics/arrow.svg");
|
||||||
bracketDeleteCollection->setResize(Vector2f(0,
|
bracketDeleteCollection->setResize(Vector2f(0, Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
||||||
Font::get(FONT_SIZE_MEDIUM)->getLetterHeight()));
|
|
||||||
row.addElement(deleteCollection, true);
|
row.addElement(deleteCollection, true);
|
||||||
row.addElement(bracketDeleteCollection, false);
|
row.addElement(bracketDeleteCollection, false);
|
||||||
row.makeAcceptInputHandler([this, customSystems] {
|
row.makeAcceptInputHandler([this, customSystems] {
|
||||||
auto ss = new GuiSettings(mWindow, "SELECT COLLECTION TO DELETE");
|
auto ss = new GuiSettings(mWindow, "SELECT COLLECTION TO DELETE");
|
||||||
std::shared_ptr<OptionListComponent<std::string>> customCollections =
|
std::shared_ptr<OptionListComponent<std::string>> customCollections =
|
||||||
std::make_shared<OptionListComponent<std::string>>(mWindow,
|
std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(), "", true);
|
||||||
getHelpStyle(), "", true);
|
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator it =
|
||||||
for (std::map<std::string, CollectionSystemData, stringComparator>::const_iterator
|
customSystems.cbegin();
|
||||||
it = customSystems.cbegin(); it != customSystems.cend() ; it++) {
|
it != customSystems.cend(); it++) {
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
std::string name = (*it).first;
|
std::string name = (*it).first;
|
||||||
std::function<void()> deleteCollectionCall = [this, name] {
|
std::function<void()> deleteCollectionCall = [this, name] {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
"THIS WILL PERMANENTLY\nDELETE THE COLLECTION\n'" +
|
mWindow, getHelpStyle(),
|
||||||
Utils::String::toUpper(name) + "'\n"
|
"THIS WILL PERMANENTLY\nDELETE THE COLLECTION\n'" +
|
||||||
|
Utils::String::toUpper(name) +
|
||||||
|
"'\n"
|
||||||
"ARE YOU SURE?",
|
"ARE YOU SURE?",
|
||||||
"YES", [this, name] {
|
"YES",
|
||||||
if (CollectionSystemsManager::get()->isEditing())
|
[this, name] {
|
||||||
CollectionSystemsManager::get()->exitEditMode();
|
if (CollectionSystemsManager::get()->isEditing())
|
||||||
mDeletedCustomCollection = true;
|
CollectionSystemsManager::get()->exitEditMode();
|
||||||
std::vector<std::string> selectedCustomCollections =
|
mDeletedCustomCollection = true;
|
||||||
collection_systems_custom->getSelectedObjects();
|
std::vector<std::string> selectedCustomCollections =
|
||||||
std::string collectionsConfigEntry;
|
collection_systems_custom->getSelectedObjects();
|
||||||
// Create the configuration file entry. If the collection to be
|
std::string collectionsConfigEntry;
|
||||||
// deleted was activated, then exclude it.
|
// Create the configuration file entry. If the collection to be
|
||||||
for (auto it = selectedCustomCollections.begin();
|
// deleted was activated, then exclude it.
|
||||||
it != selectedCustomCollections.end(); it++) {
|
for (auto it = selectedCustomCollections.begin();
|
||||||
if ((*it) != name) {
|
it != selectedCustomCollections.end(); it++) {
|
||||||
if ((*it) != selectedCustomCollections.front() &&
|
if ((*it) != name) {
|
||||||
collectionsConfigEntry != "")
|
if ((*it) != selectedCustomCollections.front() &&
|
||||||
collectionsConfigEntry += ",";
|
collectionsConfigEntry != "")
|
||||||
collectionsConfigEntry += (*it);
|
collectionsConfigEntry += ",";
|
||||||
}
|
collectionsConfigEntry += (*it);
|
||||||
}
|
}
|
||||||
// If the system to be deleted was present in es_settings.xml, we
|
}
|
||||||
// need to re-write it.
|
// If the system to be deleted was present in es_settings.xml, we
|
||||||
if (collectionsConfigEntry !=
|
// need to re-write it.
|
||||||
Settings::getInstance()->getString("CollectionSystemsCustom")) {
|
if (collectionsConfigEntry !=
|
||||||
Settings::getInstance()->setString("CollectionSystemsCustom",
|
Settings::getInstance()->getString("CollectionSystemsCustom")) {
|
||||||
collectionsConfigEntry);
|
Settings::getInstance()->setString("CollectionSystemsCustom",
|
||||||
setNeedsSaving();
|
collectionsConfigEntry);
|
||||||
setNeedsGoToStart();
|
setNeedsSaving();
|
||||||
}
|
setNeedsGoToStart();
|
||||||
CollectionSystemsManager::get()->deleteCustomCollection(name);
|
}
|
||||||
return true;
|
CollectionSystemsManager::get()->deleteCustomCollection(name);
|
||||||
},
|
return true;
|
||||||
"NO", [this] {
|
},
|
||||||
return false;
|
"NO", [this] { return false; }));
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
row.makeAcceptInputHandler(deleteCollectionCall);
|
row.makeAcceptInputHandler(deleteCollectionCall);
|
||||||
auto customCollection = std::make_shared<TextComponent>(mWindow,
|
auto customCollection = std::make_shared<TextComponent>(
|
||||||
Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||||
row.addElement(customCollection, true);
|
row.addElement(customCollection, true);
|
||||||
// This transparent bracket is only added generate the correct help prompts.
|
// This transparent bracket is only added generate the correct help prompts.
|
||||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
@ -310,14 +316,14 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
|
|
||||||
// Group unthemed custom collections.
|
// Group unthemed custom collections.
|
||||||
auto use_custom_collections_system = std::make_shared<SwitchComponent>(mWindow);
|
auto use_custom_collections_system = std::make_shared<SwitchComponent>(mWindow);
|
||||||
use_custom_collections_system->setState(Settings::getInstance()->
|
use_custom_collections_system->setState(
|
||||||
getBool("UseCustomCollectionsSystem"));
|
Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
|
||||||
addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", use_custom_collections_system);
|
addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", use_custom_collections_system);
|
||||||
addSaveFunc([this, use_custom_collections_system] {
|
addSaveFunc([this, use_custom_collections_system] {
|
||||||
if (use_custom_collections_system->getState() !=
|
if (use_custom_collections_system->getState() !=
|
||||||
Settings::getInstance()->getBool("UseCustomCollectionsSystem")) {
|
Settings::getInstance()->getBool("UseCustomCollectionsSystem")) {
|
||||||
Settings::getInstance()->setBool("UseCustomCollectionsSystem",
|
Settings::getInstance()->setBool("UseCustomCollectionsSystem",
|
||||||
use_custom_collections_system->getState());
|
use_custom_collections_system->getState());
|
||||||
if (CollectionSystemsManager::get()->isEditing())
|
if (CollectionSystemsManager::get()->isEditing())
|
||||||
CollectionSystemsManager::get()->exitEditMode();
|
CollectionSystemsManager::get()->exitEditMode();
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
|
@ -330,14 +336,14 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions(
|
||||||
|
|
||||||
// Show system names in collections.
|
// Show system names in collections.
|
||||||
auto collection_show_system_info = std::make_shared<SwitchComponent>(mWindow);
|
auto collection_show_system_info = std::make_shared<SwitchComponent>(mWindow);
|
||||||
collection_show_system_info->setState(Settings::getInstance()->
|
collection_show_system_info->setState(
|
||||||
getBool("CollectionShowSystemInfo"));
|
Settings::getInstance()->getBool("CollectionShowSystemInfo"));
|
||||||
addWithLabel("SHOW SYSTEM NAMES IN COLLECTIONS", collection_show_system_info);
|
addWithLabel("SHOW SYSTEM NAMES IN COLLECTIONS", collection_show_system_info);
|
||||||
addSaveFunc([this, collection_show_system_info] {
|
addSaveFunc([this, collection_show_system_info] {
|
||||||
if (collection_show_system_info->getState() !=
|
if (collection_show_system_info->getState() !=
|
||||||
Settings::getInstance()->getBool("CollectionShowSystemInfo")) {
|
Settings::getInstance()->getBool("CollectionShowSystemInfo")) {
|
||||||
Settings::getInstance()->setBool("CollectionShowSystemInfo",
|
Settings::getInstance()->setBool("CollectionShowSystemInfo",
|
||||||
collection_show_system_info->getState());
|
collection_show_system_info->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
setNeedsReloading();
|
setNeedsReloading();
|
||||||
setInvalidateCachedBackground();
|
setInvalidateCachedBackground();
|
||||||
|
@ -350,10 +356,9 @@ void GuiCollectionSystemsOptions::createCustomCollection(std::string inName)
|
||||||
if (CollectionSystemsManager::get()->isEditing())
|
if (CollectionSystemsManager::get()->isEditing())
|
||||||
CollectionSystemsManager::get()->exitEditMode();
|
CollectionSystemsManager::get()->exitEditMode();
|
||||||
|
|
||||||
std::string collectionName = CollectionSystemsManager::get()->
|
std::string collectionName = CollectionSystemsManager::get()->getValidNewCollectionName(inName);
|
||||||
getValidNewCollectionName(inName);
|
SystemData* newCollection =
|
||||||
SystemData* newCollection = CollectionSystemsManager::get()->
|
CollectionSystemsManager::get()->addNewCustomCollection(collectionName);
|
||||||
addNewCustomCollection(collectionName);
|
|
||||||
|
|
||||||
CollectionSystemsManager::get()->saveCustomCollection(newCollection);
|
CollectionSystemsManager::get()->saveCustomCollection(newCollection);
|
||||||
collection_systems_custom->add(collectionName, collectionName, true);
|
collection_systems_custom->add(collectionName, collectionName, true);
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
|
|
||||||
#include "GuiSettings.h"
|
#include "GuiSettings.h"
|
||||||
|
|
||||||
template<typename T>
|
template <typename T> class OptionListComponent;
|
||||||
class OptionListComponent;
|
|
||||||
|
|
||||||
class GuiCollectionSystemsOptions : public GuiSettings
|
class GuiCollectionSystemsOptions : public GuiSettings
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,23 +10,22 @@
|
||||||
|
|
||||||
#include "guis/GuiGameScraper.h"
|
#include "guis/GuiGameScraper.h"
|
||||||
|
|
||||||
|
#include "FileData.h"
|
||||||
|
#include "MameNames.h"
|
||||||
|
#include "SystemData.h"
|
||||||
#include "components/ButtonComponent.h"
|
#include "components/ButtonComponent.h"
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "FileData.h"
|
|
||||||
#include "MameNames.h"
|
|
||||||
#include "SystemData.h"
|
|
||||||
|
|
||||||
GuiGameScraper::GuiGameScraper(
|
GuiGameScraper::GuiGameScraper(Window* window,
|
||||||
Window* window,
|
ScraperSearchParams params,
|
||||||
ScraperSearchParams params,
|
std::function<void(const ScraperSearchResult&)> doneFunc)
|
||||||
std::function<void(const ScraperSearchResult&)> doneFunc)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mGrid(window, Vector2i(1, 7))
|
||||||
mGrid(window, Vector2i(1, 7)),
|
, mBox(window, ":/graphics/frame.svg")
|
||||||
mBox(window, ":/graphics/frame.svg"),
|
, mSearchParams(params)
|
||||||
mSearchParams(params),
|
, mClose(false)
|
||||||
mClose(false)
|
|
||||||
{
|
{
|
||||||
addChild(&mBox);
|
addChild(&mBox);
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
@ -40,82 +39,62 @@ GuiGameScraper::GuiGameScraper(
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (params.game->isArcadeGame() &&
|
if (params.game->isArcadeGame() &&
|
||||||
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
||||||
scrapeName = Utils::FileSystem::getFileName(mSearchParams.game->getPath()) + " (" +
|
scrapeName =
|
||||||
MameNames::getInstance()->getCleanName(mSearchParams.game->getCleanName()) +
|
Utils::FileSystem::getFileName(mSearchParams.game->getPath()) + " (" +
|
||||||
")";
|
MameNames::getInstance()->getCleanName(mSearchParams.game->getCleanName()) + ")";
|
||||||
else
|
else
|
||||||
scrapeName = Utils::FileSystem::getFileName(mSearchParams.game->getPath());
|
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 : ""),
|
((mSearchParams.game->getType() == FOLDER) ? " " + ViewController::FOLDER_CHAR : ""),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mGameName, Vector2i(0, 1), false, true);
|
mGrid.setEntry(mGameName, Vector2i(0, 1), false, true);
|
||||||
|
|
||||||
// Row 2 is a spacer.
|
// Row 2 is a spacer.
|
||||||
|
|
||||||
mSystemName = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(
|
mSystemName = std::make_shared<TextComponent>(
|
||||||
mSearchParams.system->getFullName()), Font::get(FONT_SIZE_SMALL),
|
mWindow, Utils::String::toUpper(mSearchParams.system->getFullName()),
|
||||||
0x888888FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mSystemName, Vector2i(0, 3), false, true);
|
mGrid.setEntry(mSystemName, Vector2i(0, 3), false, true);
|
||||||
|
|
||||||
// Row 4 is a spacer.
|
// Row 4 is a spacer.
|
||||||
|
|
||||||
// GuiScraperSearch.
|
// GuiScraperSearch.
|
||||||
mSearch = std::make_shared<GuiScraperSearch>(window,
|
mSearch = std::make_shared<GuiScraperSearch>(window, GuiScraperSearch::NEVER_AUTO_ACCEPT, 1);
|
||||||
GuiScraperSearch::NEVER_AUTO_ACCEPT, 1);
|
|
||||||
mGrid.setEntry(mSearch, Vector2i(0, 5), true);
|
mGrid.setEntry(mSearch, Vector2i(0, 5), true);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH",
|
buttons.push_back(
|
||||||
"refine search", [&] {
|
std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH", "refine search", [&] {
|
||||||
mSearch->openInputScreen(mSearchParams);
|
mSearch->openInputScreen(mSearchParams);
|
||||||
mGrid.resetCursor();
|
mGrid.resetCursor();
|
||||||
|
}));
|
||||||
|
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
|
||||||
|
// an update of the game entry. Otherwise the images would not get updated until
|
||||||
|
// the user scrolls up and down the gamelist.
|
||||||
|
TextureResource::manualUnload(mSearchParams.game->getImagePath(), false);
|
||||||
|
TextureResource::manualUnload(mSearchParams.game->getMarqueePath(), false);
|
||||||
|
ViewController::get()->onFileChanged(mSearchParams.game, true);
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
}));
|
}));
|
||||||
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
|
|
||||||
// an update of the game entry. Otherwise the images would not get updated until
|
|
||||||
// the user scrolls up and down the gamelist.
|
|
||||||
TextureResource::manualUnload(mSearchParams.game->getImagePath(), false);
|
|
||||||
TextureResource::manualUnload(mSearchParams.game->getMarqueePath(), false);
|
|
||||||
ViewController::get()->onFileChanged(mSearchParams.game, true);
|
|
||||||
}
|
|
||||||
delete this; }));
|
|
||||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||||
|
|
||||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false);
|
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) {
|
mSearch->setAcceptCallback([this, doneFunc](const ScraperSearchResult& result) {
|
||||||
doneFunc(result); close(); });
|
doneFunc(result);
|
||||||
|
close();
|
||||||
|
});
|
||||||
mSearch->setCancelCallback([&] { delete this; });
|
mSearch->setCancelCallback([&] { delete this; });
|
||||||
|
|
||||||
// Limit the width of the GUI on ultrawide monitors. The 1.778 aspect ratio value is
|
// 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();
|
float width = Math::clamp(0.95f * aspectValue, 0.70f, 0.95f) * Renderer::getScreenWidth();
|
||||||
|
|
||||||
setSize(width, Renderer::getScreenHeight() * 0.747f);
|
setSize(width, Renderer::getScreenHeight() * 0.747f);
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() -
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
mSize.y()) / 2);
|
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||||
|
|
||||||
mGrid.resetCursor();
|
mGrid.resetCursor();
|
||||||
mSearch->search(params); // Start the search.
|
mSearch->search(params); // Start the search.
|
||||||
|
@ -133,14 +112,14 @@ GuiGameScraper::GuiGameScraper(
|
||||||
|
|
||||||
void GuiGameScraper::onSizeChanged()
|
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(0, 0.04f, false);
|
||||||
mGrid.setRowHeightPerc(1, mGameName->getFont()->getLetterHeight() /
|
mGrid.setRowHeightPerc(1, mGameName->getFont()->getLetterHeight() / mSize.y(),
|
||||||
mSize.y(), false); // Game name.
|
false); // Game name.
|
||||||
mGrid.setRowHeightPerc(2, 0.04f, false);
|
mGrid.setRowHeightPerc(2, 0.04f, false);
|
||||||
mGrid.setRowHeightPerc(3, mSystemName->getFont()->getLetterHeight() /
|
mGrid.setRowHeightPerc(3, mSystemName->getFont()->getLetterHeight() / mSize.y(),
|
||||||
mSize.y(), false); // System name.
|
false); // System name.
|
||||||
mGrid.setRowHeightPerc(4, 0.04f, false);
|
mGrid.setRowHeightPerc(4, 0.04f, false);
|
||||||
mGrid.setRowHeightPerc(6, mButtonGrid->getSize().y() / mSize.y(), false); // Buttons.
|
mGrid.setRowHeightPerc(6, mButtonGrid->getSize().y() / mSize.y(), false); // Buttons.
|
||||||
mGrid.setSize(mSize);
|
mGrid.setSize(mSize);
|
||||||
|
@ -190,5 +169,6 @@ HelpStyle GuiGameScraper::getHelpStyle()
|
||||||
|
|
||||||
void GuiGameScraper::close()
|
void GuiGameScraper::close()
|
||||||
{
|
{
|
||||||
|
// This will cause update() to close the GUI.
|
||||||
mClose = true;
|
mClose = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,16 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
#ifndef ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
||||||
#define ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
#define ES_APP_GUIS_GUI_GAME_SCRAPER_H
|
||||||
|
|
||||||
|
#include "GuiComponent.h"
|
||||||
#include "components/NinePatchComponent.h"
|
#include "components/NinePatchComponent.h"
|
||||||
#include "guis/GuiScraperSearch.h"
|
#include "guis/GuiScraperSearch.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
|
|
||||||
class GuiGameScraper : public GuiComponent
|
class GuiGameScraper : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GuiGameScraper(Window* window, ScraperSearchParams params,
|
GuiGameScraper(Window* window,
|
||||||
std::function<void(const ScraperSearchResult&)> doneFunc);
|
ScraperSearchParams params,
|
||||||
|
std::function<void(const ScraperSearchResult&)> doneFunc);
|
||||||
|
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,20 @@
|
||||||
|
|
||||||
#include "guis/GuiGamelistFilter.h"
|
#include "guis/GuiGamelistFilter.h"
|
||||||
|
|
||||||
|
#include "SystemData.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "SystemData.h"
|
|
||||||
|
|
||||||
GuiGamelistFilter::GuiGamelistFilter(
|
GuiGamelistFilter::GuiGamelistFilter(Window* window,
|
||||||
Window* window,
|
SystemData* system,
|
||||||
SystemData* system,
|
std::function<void(bool)> filterChangedCallback)
|
||||||
std::function<void(bool)> filterChangedCallback)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mMenu(window, "FILTER GAMELIST BY")
|
||||||
mMenu(window, "FILTER GAMELIST BY"),
|
, mSystem(system)
|
||||||
mSystem(system),
|
, mFiltersChangedCallback(filterChangedCallback)
|
||||||
mFiltersChangedCallback(filterChangedCallback),
|
, mFiltersChanged(false)
|
||||||
mFiltersChanged(false)
|
|
||||||
{
|
{
|
||||||
initializeMenu();
|
initializeMenu();
|
||||||
}
|
}
|
||||||
|
@ -41,7 +40,8 @@ void GuiGamelistFilter::initializeMenu()
|
||||||
// Show filtered menu.
|
// Show filtered menu.
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "RESET ALL FILTERS",
|
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));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistFilter::resetAllFilters, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
|
@ -51,13 +51,15 @@ void GuiGamelistFilter::initializeMenu()
|
||||||
mMenu.addButton("BACK", "back", std::bind(&GuiGamelistFilter::applyFilters, this));
|
mMenu.addButton("BACK", "back", std::bind(&GuiGamelistFilter::applyFilters, this));
|
||||||
|
|
||||||
mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2.0f,
|
mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2.0f,
|
||||||
Renderer::getScreenHeight() * 0.13f);
|
Renderer::getScreenHeight() * 0.13f);
|
||||||
|
|
||||||
// Save the initial filter values to be able to check later if any changes were made.
|
// Save the initial filter values to be able to check later if any changes were made.
|
||||||
mInitialTextFilter = mTextFilterField->getValue();
|
mInitialTextFilter = mTextFilterField->getValue();
|
||||||
|
|
||||||
for (std::map<FilterIndexType, std::shared_ptr<OptionListComponent<std::string>>>::
|
for (std::map<FilterIndexType,
|
||||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
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::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||||
std::vector<std::string> filters = optionList->getSelectedObjects();
|
std::vector<std::string> filters = optionList->getSelectedObjects();
|
||||||
mInitialFilters.push_back(filters);
|
mInitialFilters.push_back(filters);
|
||||||
|
@ -67,8 +69,10 @@ void GuiGamelistFilter::initializeMenu()
|
||||||
void GuiGamelistFilter::resetAllFilters()
|
void GuiGamelistFilter::resetAllFilters()
|
||||||
{
|
{
|
||||||
mFilterIndex->resetFilters();
|
mFilterIndex->resetFilters();
|
||||||
for (std::map<FilterIndexType, std::shared_ptr< OptionListComponent<std::string>>>::
|
for (std::map<FilterIndexType,
|
||||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
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::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||||
optionList->selectNone();
|
optionList->selectNone();
|
||||||
}
|
}
|
||||||
|
@ -78,21 +82,18 @@ void GuiGamelistFilter::resetAllFilters()
|
||||||
mFiltersChanged = true;
|
mFiltersChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiGamelistFilter::~GuiGamelistFilter()
|
GuiGamelistFilter::~GuiGamelistFilter() { mFilterOptions.clear(); }
|
||||||
{
|
|
||||||
mFilterOptions.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiGamelistFilter::addFiltersToMenu()
|
void GuiGamelistFilter::addFiltersToMenu()
|
||||||
{
|
{
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
|
|
||||||
auto lbl = std::make_shared<TextComponent>(mWindow,
|
auto lbl =
|
||||||
Utils::String::toUpper("TEXT FILTER (GAME NAME)"),
|
std::make_shared<TextComponent>(mWindow, Utils::String::toUpper("TEXT FILTER (GAME NAME)"),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
|
|
||||||
mTextFilterField = std::make_shared<TextComponent>(mWindow, "",
|
mTextFilterField = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_MEDIUM),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
0x777777FF, ALIGN_RIGHT);
|
||||||
|
|
||||||
// Don't show the free text filter entry unless there are any games in the system.
|
// Don't show the free text filter entry unless there are any games in the system.
|
||||||
if (mSystem->getRootFolder()->getChildren().size() > 0) {
|
if (mSystem->getRootFolder()->getChildren().size() > 0) {
|
||||||
|
@ -113,25 +114,25 @@ void GuiGamelistFilter::addFiltersToMenu()
|
||||||
|
|
||||||
// Callback function.
|
// Callback function.
|
||||||
auto updateVal = [this](const std::string& newVal) {
|
auto updateVal = [this](const std::string& newVal) {
|
||||||
mTextFilterField->setValue(Utils::String::toUpper(newVal));
|
mTextFilterField->setValue(Utils::String::toUpper(newVal));
|
||||||
mFilterIndex->setTextFilter(Utils::String::toUpper(newVal));
|
mFilterIndex->setTextFilter(Utils::String::toUpper(newVal));
|
||||||
};
|
};
|
||||||
|
|
||||||
row.makeAcceptInputHandler([this, updateVal] {
|
row.makeAcceptInputHandler([this, updateVal] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "TEXT FILTER (GAME NAME)",
|
||||||
"TEXT FILTER (GAME NAME)", mTextFilterField->getValue(),
|
mTextFilterField->getValue(), updateVal, false, "OK",
|
||||||
updateVal, false, "OK", "APPLY CHANGES?"));
|
"APPLY CHANGES?"));
|
||||||
});
|
});
|
||||||
|
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
|
||||||
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
||||||
|
|
||||||
for (std::vector<FilterDataDecl>::const_iterator it =
|
for (std::vector<FilterDataDecl>::const_iterator it = decls.cbegin(); // Line break.
|
||||||
decls.cbegin(); it != decls.cend(); it++) {
|
it != decls.cend(); it++) {
|
||||||
|
|
||||||
FilterIndexType type = (*it).type; // Type of filter.
|
FilterIndexType type = (*it).type; // Type of filter.
|
||||||
// All possible filters for this type.
|
|
||||||
|
// All possible filters for this type.
|
||||||
std::map<std::string, int>* allKeys = (*it).allIndexKeys;
|
std::map<std::string, int>* allKeys = (*it).allIndexKeys;
|
||||||
std::string menuLabel = (*it).menuLabel; // Text to show in menu.
|
std::string menuLabel = (*it).menuLabel; // Text to show in menu.
|
||||||
std::shared_ptr<OptionListComponent<std::string>> optionList;
|
std::shared_ptr<OptionListComponent<std::string>> optionList;
|
||||||
|
@ -140,9 +141,9 @@ void GuiGamelistFilter::addFiltersToMenu()
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
|
|
||||||
// Add genres.
|
// Add genres.
|
||||||
optionList = std::make_shared<OptionListComponent<std::string>>
|
optionList = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||||
(mWindow, getHelpStyle(), menuLabel, true);
|
menuLabel, true);
|
||||||
for (auto it: *allKeys)
|
for (auto it : *allKeys)
|
||||||
optionList->add(it.first, it.first, mFilterIndex->isKeyBeingFilteredBy(it.first, type));
|
optionList->add(it.first, it.first, mFilterIndex->isKeyBeingFilteredBy(it.first, type));
|
||||||
if (allKeys->size() > 0)
|
if (allKeys->size() > 0)
|
||||||
mMenu.addWithLabel(menuLabel, optionList);
|
mMenu.addWithLabel(menuLabel, optionList);
|
||||||
|
@ -157,8 +158,10 @@ void GuiGamelistFilter::applyFilters()
|
||||||
mFiltersChanged = true;
|
mFiltersChanged = true;
|
||||||
|
|
||||||
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
|
||||||
for (std::map<FilterIndexType, std::shared_ptr<OptionListComponent<std::string>>>::
|
for (std::map<FilterIndexType,
|
||||||
const_iterator it = mFilterOptions.cbegin(); it != mFilterOptions.cend(); it++) {
|
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::shared_ptr<OptionListComponent<std::string>> optionList = it->second;
|
||||||
std::vector<std::string> filters = optionList->getSelectedObjects();
|
std::vector<std::string> filters = optionList->getSelectedObjects();
|
||||||
auto iteratorDistance = std::distance(mFilterOptions.cbegin(), it);
|
auto iteratorDistance = std::distance(mFilterOptions.cbegin(), it);
|
||||||
|
|
|
@ -11,19 +11,19 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_GAME_LIST_FILTER_H
|
#ifndef ES_APP_GUIS_GUI_GAME_LIST_FILTER_H
|
||||||
#define 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 "FileFilterIndex.h"
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
|
#include "components/MenuComponent.h"
|
||||||
|
|
||||||
template<typename T>
|
template <typename T> class OptionListComponent;
|
||||||
class OptionListComponent;
|
|
||||||
class SystemData;
|
class SystemData;
|
||||||
|
|
||||||
class GuiGamelistFilter : public GuiComponent
|
class GuiGamelistFilter : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GuiGamelistFilter(Window* window,
|
GuiGamelistFilter(Window* window,
|
||||||
SystemData* system, std::function<void(bool)> filtersChangedCallback);
|
SystemData* system,
|
||||||
|
std::function<void(bool)> filtersChangedCallback);
|
||||||
|
|
||||||
~GuiGamelistFilter();
|
~GuiGamelistFilter();
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
|
|
|
@ -12,11 +12,6 @@
|
||||||
|
|
||||||
#include "GuiGamelistOptions.h"
|
#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 "CollectionSystemsManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "FileSorts.h"
|
#include "FileSorts.h"
|
||||||
|
@ -24,18 +19,21 @@
|
||||||
#include "MameNames.h"
|
#include "MameNames.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.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(
|
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system)
|
||||||
Window* window,
|
: GuiComponent(window)
|
||||||
SystemData* system)
|
, mSystem(system)
|
||||||
: GuiComponent(window),
|
, mMenu(window, "OPTIONS")
|
||||||
mSystem(system),
|
, mFiltersChanged(false)
|
||||||
mMenu(window, "OPTIONS"),
|
, mCancelled(false)
|
||||||
mFiltersChanged(false),
|
, mIsCustomCollection(false)
|
||||||
mCancelled(false),
|
, mIsCustomCollectionGroup(false)
|
||||||
mIsCustomCollection(false),
|
, mCustomCollectionSystem(nullptr)
|
||||||
mIsCustomCollectionGroup(false),
|
|
||||||
mCustomCollectionSystem(nullptr)
|
|
||||||
{
|
{
|
||||||
addChild(&mMenu);
|
addChild(&mMenu);
|
||||||
|
|
||||||
|
@ -46,11 +44,10 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
|
|
||||||
// There is some special logic required for custom collections.
|
// There is some special logic required for custom collections.
|
||||||
if (file->getSystem()->isCustomCollection() &&
|
if (file->getSystem()->isCustomCollection() && file->getPath() != file->getSystem()->getName())
|
||||||
file->getPath() != file->getSystem()->getName())
|
|
||||||
mIsCustomCollection = true;
|
mIsCustomCollection = true;
|
||||||
else if (file->getSystem()->isCustomCollection() &&
|
else if (file->getSystem()->isCustomCollection() &&
|
||||||
file->getPath() == file->getSystem()->getName())
|
file->getPath() == file->getSystem()->getName())
|
||||||
mIsCustomCollectionGroup = true;
|
mIsCustomCollectionGroup = true;
|
||||||
|
|
||||||
if (mFromPlaceholder && file->getSystem()->isGroupedCustomCollection())
|
if (mFromPlaceholder && file->getSystem()->isGroupedCustomCollection())
|
||||||
|
@ -84,12 +81,12 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
else {
|
else {
|
||||||
// Check if the currently selected game is a favorite.
|
// Check if the currently selected game is a favorite.
|
||||||
bool isFavorite = false;
|
bool isFavorite = false;
|
||||||
if (mFirstLetterIndex.size() == 1 && mFirstLetterIndex.front() ==
|
if (mFirstLetterIndex.size() == 1 &&
|
||||||
ViewController::FAVORITE_CHAR)
|
mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR)
|
||||||
isFavorite = true;
|
isFavorite = true;
|
||||||
else if (mFirstLetterIndex.size() > 1 && (mFirstLetterIndex.front() ==
|
else if (mFirstLetterIndex.size() > 1 &&
|
||||||
ViewController::FAVORITE_CHAR || mFirstLetterIndex[1] ==
|
(mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR ||
|
||||||
ViewController::FAVORITE_CHAR))
|
mFirstLetterIndex[1] == ViewController::FAVORITE_CHAR))
|
||||||
isFavorite = true;
|
isFavorite = true;
|
||||||
|
|
||||||
// Get the first character of the game name (which could be a Unicode character).
|
// 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());
|
mCurrentFirstCharacter = Utils::String::getFirstCharacter(file->getSortName());
|
||||||
}
|
}
|
||||||
|
|
||||||
mJumpToLetterList = std::make_shared<LetterList>(mWindow, getHelpStyle(),
|
mJumpToLetterList =
|
||||||
"JUMP TO...", false);
|
std::make_shared<LetterList>(mWindow, getHelpStyle(), "JUMP TO...", false);
|
||||||
|
|
||||||
// Populate the quick selector.
|
// Populate the quick selector.
|
||||||
for (unsigned int i = 0; i < mFirstLetterIndex.size(); i++) {
|
for (unsigned int i = 0; i < mFirstLetterIndex.size(); i++) {
|
||||||
|
@ -146,8 +143,9 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
if (!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() > 0) {
|
if (!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() > 0) {
|
||||||
if (system->getName() != "recent" && Settings::getInstance()->getBool("GamelistFilters")) {
|
if (system->getName() != "recent" && Settings::getInstance()->getBool("GamelistFilters")) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>
|
row.addElement(std::make_shared<TextComponent>(mWindow, "FILTER GAMELIST",
|
||||||
(mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
|
||||||
mMenu.addRow(row);
|
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.
|
// Add a dummy entry when applicable as the menu looks quite ugly if it's just blank.
|
||||||
else if (!CollectionSystemsManager::get()->isEditing() &&
|
else if (!CollectionSystemsManager::get()->isEditing() &&
|
||||||
mSystem->getRootFolder()->getChildren().size() == 0 &&
|
mSystem->getRootFolder()->getChildren().size() == 0 && !mIsCustomCollectionGroup &&
|
||||||
!mIsCustomCollectionGroup && !mIsCustomCollection) {
|
!mIsCustomCollection) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>
|
row.addElement(std::make_shared<TextComponent>(mWindow, "THIS SYSTEM HAS NO GAMES",
|
||||||
(mWindow, "THIS SYSTEM HAS NO GAMES",
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
true);
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,34 +169,40 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
customSystem = system->getName();
|
customSystem = system->getName();
|
||||||
|
|
||||||
if (UIModeController::getInstance()->isUIModeFull() &&
|
if (UIModeController::getInstance()->isUIModeFull() &&
|
||||||
(mIsCustomCollection || mIsCustomCollectionGroup)) {
|
(mIsCustomCollection || mIsCustomCollectionGroup)) {
|
||||||
if (CollectionSystemsManager::get()->getEditingCollection() != customSystem) {
|
if (CollectionSystemsManager::get()->getEditingCollection() != customSystem) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(
|
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||||
mWindow, "ADD/REMOVE GAMES TO THIS COLLECTION",
|
"ADD/REMOVE GAMES TO THIS COLLECTION",
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::startEditMode, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::startEditMode, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UIModeController::getInstance()->isUIModeFull() &&
|
if (UIModeController::getInstance()->isUIModeFull() &&
|
||||||
CollectionSystemsManager::get()->isEditing()) {
|
CollectionSystemsManager::get()->isEditing()) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
mWindow, "FINISH EDITING '" + Utils::String::toUpper(
|
mWindow,
|
||||||
CollectionSystemsManager::get()->getEditingCollection()) +
|
"FINISH EDITING '" +
|
||||||
"' COLLECTION",Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Utils::String::toUpper(
|
||||||
|
CollectionSystemsManager::get()->getEditingCollection()) +
|
||||||
|
"' COLLECTION",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->getType() == FOLDER) {
|
if (file->getType() == FOLDER) {
|
||||||
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
||||||
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS FOLDER'S METADATA",
|
||||||
"EDIT THIS FOLDER'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
@ -206,10 +210,11 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder &&
|
||||||
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA",
|
||||||
"EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
@ -218,19 +223,25 @@ GuiGamelistOptions::GuiGamelistOptions(
|
||||||
|
|
||||||
// Buttons. The logic to apply or cancel settings are handled by the destructor.
|
// Buttons. The logic to apply or cancel settings are handled by the destructor.
|
||||||
if ((!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() == 0) ||
|
if ((!mIsCustomCollectionGroup && system->getRootFolder()->getChildren().size() == 0) ||
|
||||||
system->getName() == "recent") {
|
system->getName() == "recent") {
|
||||||
mMenu.addButton("CLOSE", "close", [&] { mCancelled = true; delete this; });
|
mMenu.addButton("CLOSE", "close", [&] {
|
||||||
|
mCancelled = true;
|
||||||
|
delete this;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mMenu.addButton("APPLY", "apply", [&] { delete this; });
|
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.
|
// Center the menu.
|
||||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f, (mSize.y() -
|
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f,
|
||||||
mMenu.getSize().y()) / 2.0f);
|
(mSize.y() - mMenu.getSize().y()) / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiGamelistOptions::~GuiGamelistOptions()
|
GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
|
@ -248,11 +259,12 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
if (!mFromPlaceholder) {
|
if (!mFromPlaceholder) {
|
||||||
ViewController::get()->reloadGameListView(mSystem);
|
ViewController::get()->reloadGameListView(mSystem);
|
||||||
}
|
}
|
||||||
else if (!mCustomCollectionSystem->getRootFolder()->
|
else if (!mCustomCollectionSystem->getRootFolder()
|
||||||
getChildrenListToDisplay().empty()) {
|
->getChildrenListToDisplay()
|
||||||
ViewController::get()->reloadGameListView(mSystem);
|
.empty()) {
|
||||||
getGamelist()->setCursor(mCustomCollectionSystem->
|
ViewController::get()->reloadGameListView(mSystem);
|
||||||
getRootFolder()->getChildrenListToDisplay().front());
|
getGamelist()->setCursor(
|
||||||
|
mCustomCollectionSystem->getRootFolder()->getChildrenListToDisplay().front());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,6 +274,7 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
|
|
||||||
if (!mFromPlaceholder) {
|
if (!mFromPlaceholder) {
|
||||||
FileData* root;
|
FileData* root;
|
||||||
|
|
||||||
if (mIsCustomCollection)
|
if (mIsCustomCollection)
|
||||||
root = getGamelist()->getCursor()->getSystem()->getRootFolder();
|
root = getGamelist()->getCursor()->getSystem()->getRootFolder();
|
||||||
else
|
else
|
||||||
|
@ -269,7 +282,7 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
|
|
||||||
// If a new sorting type was selected, then sort and update mSortTypeString for the system.
|
// If a new sorting type was selected, then sort and update mSortTypeString for the system.
|
||||||
if (!mIsCustomCollectionGroup &&
|
if (!mIsCustomCollectionGroup &&
|
||||||
(*mListSort->getSelected()).description != root->getSortTypeString()) {
|
(*mListSort->getSelected()).description != root->getSortTypeString()) {
|
||||||
// This will also recursively sort children.
|
// This will also recursively sort children.
|
||||||
root->sort(*mListSort->getSelected(), mFavoritesSorting);
|
root->sort(*mListSort->getSelected(), mFavoritesSorting);
|
||||||
root->setSortTypeString((*mListSort->getSelected()).description);
|
root->setSortTypeString((*mListSort->getSelected()).description);
|
||||||
|
@ -281,7 +294,7 @@ GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
// Has the user changed the letter using the quick selector?
|
// Has the user changed the letter using the quick selector?
|
||||||
if (mCurrentFirstCharacter != mJumpToLetterList->getSelected()) {
|
if (mCurrentFirstCharacter != mJumpToLetterList->getSelected()) {
|
||||||
if (mJumpToLetterList->getSelected() == ViewController::FAVORITE_CHAR ||
|
if (mJumpToLetterList->getSelected() == ViewController::FAVORITE_CHAR ||
|
||||||
mJumpToLetterList->getSelected() == ViewController::FOLDER_CHAR)
|
mJumpToLetterList->getSelected() == ViewController::FOLDER_CHAR)
|
||||||
jumpToFirstRow();
|
jumpToFirstRow();
|
||||||
else
|
else
|
||||||
jumpToLetter();
|
jumpToLetter();
|
||||||
|
@ -303,7 +316,7 @@ void GuiGamelistOptions::openGamelistFilter()
|
||||||
|
|
||||||
if (mIsCustomCollection)
|
if (mIsCustomCollection)
|
||||||
ggf = new GuiGamelistFilter(mWindow, getGamelist()->getCursor()->getSystem(),
|
ggf = new GuiGamelistFilter(mWindow, getGamelist()->getCursor()->getSystem(),
|
||||||
filtersChangedFunc);
|
filtersChangedFunc);
|
||||||
else
|
else
|
||||||
ggf = new GuiGamelistFilter(mWindow, mSystem, filtersChangedFunc);
|
ggf = new GuiGamelistFilter(mWindow, mSystem, filtersChangedFunc);
|
||||||
|
|
||||||
|
@ -329,10 +342,9 @@ void GuiGamelistOptions::startEditMode()
|
||||||
// Display the indication icons which show what games are part of the custom collection
|
// 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
|
// currently being edited. This is done cheaply using onFileChanged() which will trigger
|
||||||
// populateList().
|
// populateList().
|
||||||
for (auto it = SystemData::sSystemVector.begin();
|
for (auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++) {
|
||||||
it != SystemData::sSystemVector.end(); it++) {
|
|
||||||
ViewController::get()->getGameListView((*it))->onFileChanged(
|
ViewController::get()->getGameListView((*it))->onFileChanged(
|
||||||
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSystem->getRootFolder()->getChildren().size() == 0)
|
if (mSystem->getRootFolder()->getChildren().size() == 0)
|
||||||
|
@ -362,12 +374,12 @@ void GuiGamelistOptions::openMetaDataEd()
|
||||||
|
|
||||||
clearGameBtnFunc = [this, file] {
|
clearGameBtnFunc = [this, file] {
|
||||||
if (file->getType() == FOLDER) {
|
if (file->getType() == FOLDER) {
|
||||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder \"" <<
|
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder \""
|
||||||
file->getFullPath() << "\"";
|
<< file->getFullPath() << "\"";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the file \"" <<
|
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the file \""
|
||||||
file->getFullPath() << "\"";
|
<< file->getFullPath() << "\"";
|
||||||
}
|
}
|
||||||
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
||||||
|
|
||||||
|
@ -375,10 +387,10 @@ void GuiGamelistOptions::openMetaDataEd()
|
||||||
const std::vector<MetaDataDecl>& mdd = file->metadata.getMDD();
|
const std::vector<MetaDataDecl>& mdd = file->metadata.getMDD();
|
||||||
for (auto it = mdd.cbegin(); it != mdd.cend(); it++) {
|
for (auto it = mdd.cbegin(); it != mdd.cend(); it++) {
|
||||||
if (it->key == "name") {
|
if (it->key == "name") {
|
||||||
if (file->isArcadeGame()) {
|
if (file->isArcadeGame()) {
|
||||||
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
// If it's a MAME or Neo Geo game, expand the game name accordingly.
|
||||||
file->metadata.set(it->key, MameNames::getInstance()->
|
file->metadata.set(
|
||||||
getCleanName(file->getCleanName()));
|
it->key, MameNames::getInstance()->getCleanName(file->getCleanName()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
file->metadata.set(it->key, file->getDisplayName());
|
file->metadata.set(it->key, file->getDisplayName());
|
||||||
|
@ -408,8 +420,8 @@ void GuiGamelistOptions::openMetaDataEd()
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteGameBtnFunc = [this, file] {
|
deleteGameBtnFunc = [this, file] {
|
||||||
LOG(LogInfo) << "Deleting the game file \"" << file->getFullPath() <<
|
LOG(LogInfo) << "Deleting the game file \"" << file->getFullPath()
|
||||||
"\", all its media files and its gamelist.xml entry.";
|
<< "\", all its media files and its gamelist.xml entry.";
|
||||||
CollectionSystemsManager::get()->deleteCollectionFiles(file);
|
CollectionSystemsManager::get()->deleteCollectionFiles(file);
|
||||||
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
ViewController::get()->getGameListView(file->getSystem()).get()->removeMedia(file);
|
||||||
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true);
|
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true);
|
||||||
|
@ -420,20 +432,20 @@ void GuiGamelistOptions::openMetaDataEd()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (file->getType() == FOLDER) {
|
if (file->getType() == FOLDER) {
|
||||||
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata,
|
mWindow->pushGui(new GuiMetaDataEd(
|
||||||
file->metadata.getMDD(FOLDER_METADATA), p,
|
mWindow, &file->metadata, file->metadata.getMDD(FOLDER_METADATA), p,
|
||||||
Utils::FileSystem::getFileName(file->getPath()), std::bind(
|
Utils::FileSystem::getFileName(file->getPath()),
|
||||||
&IGameListView::onFileChanged, ViewController::get()->getGameListView(
|
std::bind(&IGameListView::onFileChanged,
|
||||||
file->getSystem()).get(), file, true),
|
ViewController::get()->getGameListView(file->getSystem()).get(), file, true),
|
||||||
clearGameBtnFunc, deleteGameBtnFunc));
|
clearGameBtnFunc, deleteGameBtnFunc));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata,
|
mWindow->pushGui(new GuiMetaDataEd(
|
||||||
file->metadata.getMDD(GAME_METADATA), p,
|
mWindow, &file->metadata, file->metadata.getMDD(GAME_METADATA), p,
|
||||||
Utils::FileSystem::getFileName(file->getPath()), std::bind(
|
Utils::FileSystem::getFileName(file->getPath()),
|
||||||
&IGameListView::onFileChanged, ViewController::get()->getGameListView(
|
std::bind(&IGameListView::onFileChanged,
|
||||||
file->getSystem()).get(), file, true),
|
ViewController::get()->getGameListView(file->getSystem()).get(), file, true),
|
||||||
clearGameBtnFunc, deleteGameBtnFunc));
|
clearGameBtnFunc, deleteGameBtnFunc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,14 +454,14 @@ void GuiGamelistOptions::jumpToLetter()
|
||||||
char letter = mJumpToLetterList->getSelected().front();
|
char letter = mJumpToLetterList->getSelected().front();
|
||||||
|
|
||||||
// Get the gamelist.
|
// Get the gamelist.
|
||||||
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
const std::vector<FileData*>& files =
|
||||||
getParent()->getChildrenListToDisplay();
|
getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < files.size(); i++) {
|
for (unsigned int i = 0; i < files.size(); i++) {
|
||||||
if (mFavoritesSorting && (mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR ||
|
if (mFavoritesSorting && (mFirstLetterIndex.front() == ViewController::FAVORITE_CHAR ||
|
||||||
mFirstLetterIndex.front() == ViewController::FOLDER_CHAR)) {
|
mFirstLetterIndex.front() == ViewController::FOLDER_CHAR)) {
|
||||||
if (static_cast<char>(toupper(files.at(i)->getSortName().front())) ==
|
if (static_cast<char>(toupper(files.at(i)->getSortName().front())) == letter &&
|
||||||
letter && !files.at(i)->getFavorite()) {
|
!files.at(i)->getFavorite()) {
|
||||||
if (!mOnlyHasFolders && mFoldersOnTop && files.at(i)->getType() == FOLDER) {
|
if (!mOnlyHasFolders && mFoldersOnTop && files.at(i)->getType() == FOLDER) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -477,8 +489,8 @@ void GuiGamelistOptions::jumpToFirstRow()
|
||||||
{
|
{
|
||||||
if (mFoldersOnTop && mJumpToLetterList->getSelected() == ViewController::FAVORITE_CHAR) {
|
if (mFoldersOnTop && mJumpToLetterList->getSelected() == ViewController::FAVORITE_CHAR) {
|
||||||
// Get the gamelist.
|
// Get the gamelist.
|
||||||
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
const std::vector<FileData*>& files =
|
||||||
getParent()->getChildrenListToDisplay();
|
getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||||
// Select the first game that is not a folder, unless it's a folder-only list in
|
// 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.
|
// which case the first line overall is selected.
|
||||||
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
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))
|
if (input.value != 0 && config->isMappedTo("back", input))
|
||||||
mCancelled = true;
|
mCancelled = true;
|
||||||
|
|
||||||
if (input.value != 0 && (config->isMappedTo("b", input) ||
|
if (input.value != 0 && (config->isMappedTo("b", input) || config->isMappedTo("back", input))) {
|
||||||
config->isMappedTo("back", input))) {
|
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -521,9 +532,8 @@ HelpStyle GuiGamelistOptions::getHelpStyle()
|
||||||
std::vector<HelpPrompt> GuiGamelistOptions::getHelpPrompts()
|
std::vector<HelpPrompt> GuiGamelistOptions::getHelpPrompts()
|
||||||
{
|
{
|
||||||
auto prompts = mMenu.getHelpPrompts();
|
auto prompts = mMenu.getHelpPrompts();
|
||||||
if (mSystem->getRootFolder()->getChildren().size() > 0 ||
|
if (mSystem->getRootFolder()->getChildren().size() > 0 || mIsCustomCollectionGroup ||
|
||||||
mIsCustomCollectionGroup || mIsCustomCollection ||
|
mIsCustomCollection || CollectionSystemsManager::get()->isEditing())
|
||||||
CollectionSystemsManager::get()->isEditing())
|
|
||||||
prompts.push_back(HelpPrompt("a", "select"));
|
prompts.push_back(HelpPrompt("a", "select"));
|
||||||
if (mSystem->getRootFolder()->getChildren().size() > 0 && mSystem->getName() != "recent") {
|
if (mSystem->getRootFolder()->getChildren().size() > 0 && mSystem->getName() != "recent") {
|
||||||
prompts.push_back(HelpPrompt("b", "close (apply)"));
|
prompts.push_back(HelpPrompt("b", "close (apply)"));
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H
|
#ifndef ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H
|
||||||
#define 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/MenuComponent.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "FileData.h"
|
|
||||||
#include "GuiComponent.h"
|
|
||||||
|
|
||||||
class IGameListView;
|
class IGameListView;
|
||||||
class SystemData;
|
class SystemData;
|
||||||
|
|
|
@ -14,21 +14,18 @@
|
||||||
|
|
||||||
#include <SDL2/SDL_timer.h>
|
#include <SDL2/SDL_timer.h>
|
||||||
|
|
||||||
GuiInfoPopup::GuiInfoPopup(
|
GuiInfoPopup::GuiInfoPopup(Window* window, std::string message, int duration)
|
||||||
Window* window,
|
: GuiComponent(window)
|
||||||
std::string message,
|
, mMessage(message)
|
||||||
int duration)
|
, mDuration(duration)
|
||||||
: GuiComponent(window),
|
, mRunning(true)
|
||||||
mMessage(message),
|
|
||||||
mDuration(duration),
|
|
||||||
mRunning(true)
|
|
||||||
{
|
{
|
||||||
mFrame = new NinePatchComponent(window);
|
mFrame = new NinePatchComponent(window);
|
||||||
float maxWidth = Renderer::getScreenWidth() * 0.9f;
|
float maxWidth = Renderer::getScreenWidth() * 0.9f;
|
||||||
float maxHeight = Renderer::getScreenHeight() * 0.2f;
|
float maxHeight = Renderer::getScreenHeight() * 0.2f;
|
||||||
|
|
||||||
std::shared_ptr<TextComponent> s = std::make_shared<TextComponent>(mWindow, "",
|
std::shared_ptr<TextComponent> s = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_MINI), 0x444444FF, ALIGN_CENTER);
|
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.
|
// We do this to force the text container to resize and return the actual expected popup size.
|
||||||
s->setSize(0.0f, 0.0f);
|
s->setSize(0.0f, 0.0f);
|
||||||
|
@ -51,13 +48,13 @@ GuiInfoPopup::GuiInfoPopup(
|
||||||
mSize[0] = mSize.x() + paddingX;
|
mSize[0] = mSize.x() + paddingX;
|
||||||
mSize[1] = mSize.y() + paddingY;
|
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;
|
float posY = Renderer::getScreenHeight() * 0.02f;
|
||||||
|
|
||||||
setPosition(posX, posY, 0);
|
setPosition(posX, posY, 0);
|
||||||
|
|
||||||
mFrame->setImagePath(":/graphics/frame.svg");
|
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);
|
addChild(mFrame);
|
||||||
|
|
||||||
// We only initialize the actual time when we first start to render.
|
// We only initialize the actual time when we first start to render.
|
||||||
|
|
|
@ -22,7 +22,7 @@ public:
|
||||||
~GuiInfoPopup();
|
~GuiInfoPopup();
|
||||||
|
|
||||||
void render(const Transform4x4f& parentTrans) override;
|
void render(const Transform4x4f& parentTrans) override;
|
||||||
inline void stop() override { mRunning = false; }
|
void stop() override { mRunning = false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool updateState();
|
bool updateState();
|
||||||
|
|
|
@ -8,20 +8,19 @@
|
||||||
|
|
||||||
#include "guis/GuiLaunchScreen.h"
|
#include "guis/GuiLaunchScreen.h"
|
||||||
|
|
||||||
|
#include "FileData.h"
|
||||||
|
#include "SystemData.h"
|
||||||
#include "components/ComponentGrid.h"
|
#include "components/ComponentGrid.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "math/Misc.h"
|
#include "math/Misc.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "FileData.h"
|
|
||||||
#include "SystemData.h"
|
|
||||||
|
|
||||||
GuiLaunchScreen::GuiLaunchScreen(
|
GuiLaunchScreen::GuiLaunchScreen(Window* window)
|
||||||
Window* window)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mBackground(window, ":/graphics/frame.svg")
|
||||||
mBackground(window, ":/graphics/frame.svg"),
|
, mGrid(nullptr)
|
||||||
mGrid(nullptr),
|
, mMarquee(nullptr)
|
||||||
mMarquee(nullptr),
|
, mWindow(window)
|
||||||
mWindow(window)
|
|
||||||
{
|
{
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
mWindow->setLaunchScreen(this);
|
mWindow->setLaunchScreen(this);
|
||||||
|
@ -29,6 +28,7 @@ GuiLaunchScreen::GuiLaunchScreen(
|
||||||
|
|
||||||
GuiLaunchScreen::~GuiLaunchScreen()
|
GuiLaunchScreen::~GuiLaunchScreen()
|
||||||
{
|
{
|
||||||
|
// This only executes when exiting the application.
|
||||||
closeLaunchScreen();
|
closeLaunchScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,49 +51,53 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
||||||
const float gameNameFontSize = 0.073f;
|
const float gameNameFontSize = 0.073f;
|
||||||
|
|
||||||
// Spacer row.
|
// Spacer row.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0), false, false,
|
||||||
false, false, Vector2i(1, 1));
|
Vector2i(1, 1));
|
||||||
|
|
||||||
// Title.
|
// Title.
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, "LAUNCHING GAME",
|
mTitle = std::make_shared<TextComponent>(
|
||||||
Font::get(static_cast<int>(titleFontSize * std::min(Renderer::getScreenHeight(),
|
mWindow, "LAUNCHING GAME",
|
||||||
Renderer::getScreenWidth()))), 0x666666FF, ALIGN_CENTER);
|
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));
|
mGrid->setEntry(mTitle, Vector2i(1, 1), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Spacer row.
|
// Spacer row.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 2),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 2), false, false,
|
||||||
false, false, Vector2i(1, 1));
|
Vector2i(1, 1));
|
||||||
|
|
||||||
// Row for the marquee.
|
// Row for the marquee.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 3),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 3), false, false,
|
||||||
false, false, Vector2i(1, 1));
|
Vector2i(1, 1));
|
||||||
|
|
||||||
// Spacer row.
|
// Spacer row.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 4),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 4), false, false,
|
||||||
false, false, Vector2i(1, 1));
|
Vector2i(1, 1));
|
||||||
|
|
||||||
// Game name.
|
// Game name.
|
||||||
mGameName = std::make_shared<TextComponent>(mWindow, "GAME NAME",
|
mGameName = std::make_shared<TextComponent>(
|
||||||
Font::get(static_cast<int>(gameNameFontSize * std::min(Renderer::getScreenHeight(),
|
mWindow, "GAME NAME",
|
||||||
Renderer::getScreenWidth()))), 0x444444FF, ALIGN_CENTER);
|
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));
|
mGrid->setEntry(mGameName, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// System name.
|
// System name.
|
||||||
mSystemName = std::make_shared<TextComponent>(mWindow, "SYSTEM NAME",
|
mSystemName = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x666666FF, ALIGN_CENTER);
|
mWindow, "SYSTEM NAME", Font::get(FONT_SIZE_MEDIUM), 0x666666FF, ALIGN_CENTER);
|
||||||
mGrid->setEntry(mSystemName, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
mGrid->setEntry(mSystemName, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Spacer row.
|
// Spacer row.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 7),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 7), false, false,
|
||||||
false, false, Vector2i(1, 1));
|
Vector2i(1, 1));
|
||||||
|
|
||||||
// Left spacer.
|
// Left spacer.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false, false,
|
||||||
false, false, Vector2i(1, 8));
|
Vector2i(1, 8));
|
||||||
|
|
||||||
// Right spacer.
|
// Right spacer.
|
||||||
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(2, 0),
|
mGrid->setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(2, 0), false, false,
|
||||||
false, false, Vector2i(1, 8));
|
Vector2i(1, 8));
|
||||||
|
|
||||||
// Adjust the width depending on the aspect ratio of the screen, to make the screen look
|
// 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
|
// 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 maxWidth = static_cast<float>(Renderer::getScreenWidth()) * maxWidthModifier;
|
||||||
float minWidth = static_cast<float>(Renderer::getScreenWidth()) * minWidthModifier;
|
float minWidth = static_cast<float>(Renderer::getScreenWidth()) * minWidthModifier;
|
||||||
|
|
||||||
float fontWidth = Font::get(static_cast<int>(gameNameFontSize *
|
float fontWidth =
|
||||||
std::min(Renderer::getScreenHeight(), Renderer::getScreenWidth())))->
|
Font::get(static_cast<int>(gameNameFontSize * std::min(Renderer::getScreenHeight(),
|
||||||
sizeText(Utils::String::toUpper(game->getName())).x();
|
Renderer::getScreenWidth())))
|
||||||
|
->sizeText(Utils::String::toUpper(game->getName()))
|
||||||
|
.x();
|
||||||
|
|
||||||
// Add a bit of width to compensate for the left and right spacers.
|
// Add a bit of width to compensate for the left and right spacers.
|
||||||
fontWidth += static_cast<float>(Renderer::getScreenWidth()) * 0.05f;
|
fontWidth += static_cast<float>(Renderer::getScreenWidth()) * 0.05f;
|
||||||
|
@ -159,7 +165,8 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
||||||
if (mImagePath != "") {
|
if (mImagePath != "") {
|
||||||
mMarquee->setImage(game->getMarqueePath(), false);
|
mMarquee->setImage(game->getMarqueePath(), false);
|
||||||
mMarquee->cropTransparentPadding(static_cast<float>(Renderer::getScreenWidth()) *
|
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);
|
mMarquee->setOrigin(0.5f, 0.5f);
|
||||||
Vector3f currentPos = mMarquee->getPosition();
|
Vector3f currentPos = mMarquee->getPosition();
|
||||||
|
@ -167,18 +174,18 @@ void GuiLaunchScreen::displayLaunchScreen(FileData* game)
|
||||||
|
|
||||||
// Position the image in the middle of row four.
|
// Position the image in the middle of row four.
|
||||||
currentPos.x() = mSize.x() / 2.0f;
|
currentPos.x() = mSize.x() / 2.0f;
|
||||||
currentPos.y() = mGrid->getRowHeight(0) + mGrid->getRowHeight(1) +
|
currentPos.y() = mGrid->getRowHeight(0) + mGrid->getRowHeight(1) + mGrid->getRowHeight(2) +
|
||||||
mGrid->getRowHeight(2) + mGrid->getRowHeight(3) / 2.0f;
|
mGrid->getRowHeight(3) / 2.0f;
|
||||||
mMarquee->setPosition(currentPos);
|
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.
|
// Center on the X axis and keep slightly off-center on the Y axis.
|
||||||
setPosition(static_cast<float>(Renderer::getScreenWidth()) / 2.0f,
|
setPosition(static_cast<float>(Renderer::getScreenWidth()) / 2.0f,
|
||||||
static_cast<float>(Renderer::getScreenHeight()) / 2.25f);
|
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);
|
mBackground.setEdgeColor(0xEEEEEEFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +210,7 @@ void GuiLaunchScreen::closeLaunchScreen()
|
||||||
|
|
||||||
void GuiLaunchScreen::onSizeChanged()
|
void GuiLaunchScreen::onSizeChanged()
|
||||||
{
|
{
|
||||||
|
// Update mGrid size.
|
||||||
mGrid->setSize(mSize);
|
mGrid->setSize(mSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_LAUNCH_SCREEN_H
|
#ifndef ES_APP_GUIS_GUI_LAUNCH_SCREEN_H
|
||||||
#define 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/ComponentGrid.h"
|
||||||
#include "components/ImageComponent.h"
|
#include "components/ImageComponent.h"
|
||||||
#include "components/NinePatchComponent.h"
|
#include "components/NinePatchComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "Window.h"
|
|
||||||
|
|
||||||
class FileData;
|
class FileData;
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ public:
|
||||||
private:
|
private:
|
||||||
Window* mWindow;
|
Window* mWindow;
|
||||||
ComponentGrid* mGrid;
|
ComponentGrid* mGrid;
|
||||||
|
|
||||||
NinePatchComponent mBackground;
|
NinePatchComponent mBackground;
|
||||||
|
|
||||||
std::shared_ptr<TextComponent> mTitle;
|
std::shared_ptr<TextComponent> mTitle;
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
|
|
||||||
#include "guis/GuiMediaViewerOptions.h"
|
#include "guis/GuiMediaViewerOptions.h"
|
||||||
|
|
||||||
#include "components/SwitchComponent.h"
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "components/SwitchComponent.h"
|
||||||
|
|
||||||
GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string& title)
|
GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string& title)
|
||||||
: GuiSettings(window, title)
|
: GuiSettings(window, title)
|
||||||
{
|
{
|
||||||
// Keep videos running when viewing images.
|
// Keep videos running when viewing images.
|
||||||
auto keep_video_running = std::make_shared<SwitchComponent>(mWindow);
|
auto keep_video_running = std::make_shared<SwitchComponent>(mWindow);
|
||||||
|
@ -21,9 +21,9 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
||||||
addWithLabel("KEEP VIDEOS RUNNING WHEN VIEWING IMAGES", keep_video_running);
|
addWithLabel("KEEP VIDEOS RUNNING WHEN VIEWING IMAGES", keep_video_running);
|
||||||
addSaveFunc([keep_video_running, this] {
|
addSaveFunc([keep_video_running, this] {
|
||||||
if (keep_video_running->getState() !=
|
if (keep_video_running->getState() !=
|
||||||
Settings::getInstance()->getBool("MediaViewerKeepVideoRunning")) {
|
Settings::getInstance()->getBool("MediaViewerKeepVideoRunning")) {
|
||||||
Settings::getInstance()->setBool("MediaViewerKeepVideoRunning",
|
Settings::getInstance()->setBool("MediaViewerKeepVideoRunning",
|
||||||
keep_video_running->getState());
|
keep_video_running->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -34,23 +34,23 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
||||||
addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", stretch_videos);
|
addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", stretch_videos);
|
||||||
addSaveFunc([stretch_videos, this] {
|
addSaveFunc([stretch_videos, this] {
|
||||||
if (stretch_videos->getState() !=
|
if (stretch_videos->getState() !=
|
||||||
Settings::getInstance()->getBool("MediaViewerStretchVideos")) {
|
Settings::getInstance()->getBool("MediaViewerStretchVideos")) {
|
||||||
Settings::getInstance()->setBool("MediaViewerStretchVideos",
|
Settings::getInstance()->setBool("MediaViewerStretchVideos",
|
||||||
stretch_videos->getState());
|
stretch_videos->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
// Render scanlines for videos using a shader.
|
// Render scanlines for videos using a shader.
|
||||||
auto video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
auto video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||||
video_scanlines->setState(Settings::getInstance()->getBool("MediaViewerVideoScanlines"));
|
video_scanlines->setState(Settings::getInstance()->getBool("MediaViewerVideoScanlines"));
|
||||||
addWithLabel("RENDER SCANLINES FOR VIDEOS", video_scanlines);
|
addWithLabel("RENDER SCANLINES FOR VIDEOS", video_scanlines);
|
||||||
addSaveFunc([video_scanlines, this] {
|
addSaveFunc([video_scanlines, this] {
|
||||||
if (video_scanlines->getState() !=
|
if (video_scanlines->getState() !=
|
||||||
Settings::getInstance()->getBool("MediaViewerVideoScanlines")) {
|
Settings::getInstance()->getBool("MediaViewerVideoScanlines")) {
|
||||||
Settings::getInstance()->setBool("MediaViewerVideoScanlines",
|
Settings::getInstance()->setBool("MediaViewerVideoScanlines",
|
||||||
video_scanlines->getState());
|
video_scanlines->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -60,26 +60,24 @@ GuiMediaViewerOptions::GuiMediaViewerOptions(Window* window, const std::string&
|
||||||
video_blur->setState(Settings::getInstance()->getBool("MediaViewerVideoBlur"));
|
video_blur->setState(Settings::getInstance()->getBool("MediaViewerVideoBlur"));
|
||||||
addWithLabel("RENDER BLUR FOR VIDEOS", video_blur);
|
addWithLabel("RENDER BLUR FOR VIDEOS", video_blur);
|
||||||
addSaveFunc([video_blur, this] {
|
addSaveFunc([video_blur, this] {
|
||||||
if (video_blur->getState() !=
|
if (video_blur->getState() != Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
||||||
Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
|
Settings::getInstance()->setBool("MediaViewerVideoBlur", video_blur->getState());
|
||||||
Settings::getInstance()->setBool("MediaViewerVideoBlur",
|
|
||||||
video_blur->getState());
|
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Render scanlines for screenshots using a shader.
|
// Render scanlines for screenshots using a shader.
|
||||||
auto screenshot_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
auto screenshot_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screenshot_scanlines->setState(Settings::getInstance()->
|
screenshot_scanlines->setState(
|
||||||
getBool("MediaViewerScreenshotScanlines"));
|
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines"));
|
||||||
addWithLabel("RENDER SCANLINES FOR SCREENSHOTS", screenshot_scanlines);
|
addWithLabel("RENDER SCANLINES FOR SCREENSHOTS", screenshot_scanlines);
|
||||||
addSaveFunc([screenshot_scanlines, this] {
|
addSaveFunc([screenshot_scanlines, this] {
|
||||||
if (screenshot_scanlines->getState() !=
|
if (screenshot_scanlines->getState() !=
|
||||||
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines")) {
|
Settings::getInstance()->getBool("MediaViewerScreenshotScanlines")) {
|
||||||
Settings::getInstance()->setBool("MediaViewerScreenshotScanlines",
|
Settings::getInstance()->setBool("MediaViewerScreenshotScanlines",
|
||||||
screenshot_scanlines->getState());
|
screenshot_scanlines->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -10,9 +10,9 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_MENU_H
|
#ifndef ES_APP_GUIS_GUI_MENU_H
|
||||||
#define ES_APP_GUIS_GUI_MENU_H
|
#define ES_APP_GUIS_GUI_MENU_H
|
||||||
|
|
||||||
|
#include "GuiComponent.h"
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "guis/GuiSettings.h"
|
#include "guis/GuiSettings.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
|
|
||||||
class GuiMenu : public GuiComponent
|
class GuiMenu : public GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -27,8 +27,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void close(bool closeAllWindows);
|
void close(bool closeAllWindows);
|
||||||
void addEntry(const std::string& name, unsigned int color,
|
void addEntry(const std::string& name,
|
||||||
bool add_arrow, const std::function<void()>& func);
|
unsigned int color,
|
||||||
|
bool add_arrow,
|
||||||
|
const std::function<void()>& func);
|
||||||
void addVersionInfo();
|
void addVersionInfo();
|
||||||
|
|
||||||
void openScraperOptions();
|
void openScraperOptions();
|
||||||
|
|
|
@ -11,6 +11,12 @@
|
||||||
|
|
||||||
#include "guis/GuiMetaDataEd.h"
|
#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/ButtonComponent.h"
|
||||||
#include "components/ComponentList.h"
|
#include "components/ComponentList.h"
|
||||||
#include "components/DateTimeEditComponent.h"
|
#include "components/DateTimeEditComponent.h"
|
||||||
|
@ -18,69 +24,63 @@
|
||||||
#include "components/RatingComponent.h"
|
#include "components/RatingComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
|
#include "guis/GuiComplexTextEditPopup.h"
|
||||||
#include "guis/GuiGameScraper.h"
|
#include "guis/GuiGameScraper.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "guis/GuiTextEditPopup.h"
|
#include "guis/GuiTextEditPopup.h"
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
|
||||||
#include "resources/Font.h"
|
#include "resources/Font.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "views/ViewController.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(
|
GuiMetaDataEd::GuiMetaDataEd(Window* window,
|
||||||
Window* window,
|
MetaDataList* md,
|
||||||
MetaDataList* md,
|
const std::vector<MetaDataDecl>& mdd,
|
||||||
const std::vector<MetaDataDecl>& mdd,
|
ScraperSearchParams scraperParams,
|
||||||
ScraperSearchParams scraperParams,
|
const std::string& /*header*/,
|
||||||
const std::string& /*header*/,
|
std::function<void()> saveCallback,
|
||||||
std::function<void()> saveCallback,
|
std::function<void()> clearGameFunc,
|
||||||
std::function<void()> clearGameFunc,
|
std::function<void()> deleteGameFunc)
|
||||||
std::function<void()> deleteGameFunc)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mScraperParams(scraperParams)
|
||||||
mScraperParams(scraperParams),
|
, mBackground(window, ":/graphics/frame.svg")
|
||||||
mBackground(window, ":/graphics/frame.svg"),
|
, mGrid(window, Vector2i(1, 3))
|
||||||
mGrid(window, Vector2i(1, 3)),
|
, mMetaDataDecl(mdd)
|
||||||
mMetaDataDecl(mdd),
|
, mMetaData(md)
|
||||||
mMetaData(md),
|
, mSavedCallback(saveCallback)
|
||||||
mSavedCallback(saveCallback),
|
, mClearGameFunc(clearGameFunc)
|
||||||
mClearGameFunc(clearGameFunc),
|
, mDeleteGameFunc(deleteGameFunc)
|
||||||
mDeleteGameFunc(deleteGameFunc),
|
, mMediaFilesUpdated(false)
|
||||||
mMediaFilesUpdated(false)
|
|
||||||
{
|
{
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
|
||||||
mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5));
|
mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5));
|
||||||
|
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA",
|
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA", Font::get(FONT_SIZE_LARGE),
|
||||||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
0x555555FF, ALIGN_CENTER);
|
||||||
|
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
std::string folderPath = Utils::String::replace(
|
std::string folderPath =
|
||||||
Utils::FileSystem::getParent(scraperParams.game->getPath()),
|
Utils::String::replace(Utils::FileSystem::getParent(scraperParams.game->getPath()),
|
||||||
scraperParams.system->getSystemEnvData()->mStartPath, "");
|
scraperParams.system->getSystemEnvData()->mStartPath, "");
|
||||||
|
|
||||||
if (folderPath.size() >= 2) {
|
if (folderPath.size() >= 2) {
|
||||||
folderPath.erase(0, 1);
|
folderPath.erase(0, 1);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
folderPath.push_back('\\');
|
folderPath.push_back('\\');
|
||||||
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
||||||
#else
|
#else
|
||||||
folderPath.push_back('/');
|
folderPath.push_back('/');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
mSubtitle = std::make_shared<TextComponent>(mWindow, folderPath +
|
mSubtitle = std::make_shared<TextComponent>(
|
||||||
Utils::FileSystem::getFileName(scraperParams.game->getPath()) +
|
mWindow,
|
||||||
" [" + Utils::String::toUpper(scraperParams.system->getName()) + "]" +
|
folderPath + Utils::FileSystem::getFileName(scraperParams.game->getPath()) + " [" +
|
||||||
|
Utils::String::toUpper(scraperParams.system->getName()) + "]" +
|
||||||
(scraperParams.game->getType() == FOLDER ? " " + ViewController::FOLDER_CHAR : ""),
|
(scraperParams.game->getType() == FOLDER ? " " + ViewController::FOLDER_CHAR : ""),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER, Vector3f(0.0f, 0.0f, 0.0f),
|
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER, Vector3f(0.0f, 0.0f, 0.0f),
|
||||||
Vector2f(0.0f, 0.0f), 0x00000000, 0.05f);
|
Vector2f(0.0f, 0.0f), 0x00000000, 0.05f);
|
||||||
mHeaderGrid->setEntry(mTitle, Vector2i(0, 1), false, true);
|
mHeaderGrid->setEntry(mTitle, Vector2i(0, 1), false, true);
|
||||||
mHeaderGrid->setEntry(mSubtitle, Vector2i(0, 3), false, true);
|
mHeaderGrid->setEntry(mSubtitle, Vector2i(0, 3), false, true);
|
||||||
|
|
||||||
|
@ -102,27 +102,26 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
|
|
||||||
// Don't show the launch command override entry if this option has been disabled.
|
// Don't show the launch command override entry if this option has been disabled.
|
||||||
if (!Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
if (!Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
||||||
iter->type == MD_LAUNCHCOMMAND) {
|
iter->type == MD_LAUNCHCOMMAND) {
|
||||||
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
ed = std::make_shared<TextComponent>(
|
||||||
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||||
assert(ed);
|
assert(ed);
|
||||||
ed->setValue(mMetaData->get(iter->key));
|
ed->setValue(mMetaData->get(iter->key));
|
||||||
mEditors.push_back(ed);
|
mEditors.push_back(ed);
|
||||||
continue;
|
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
|
// 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
|
// 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.
|
// always looks for the help prompt at the back of the element stack.
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
auto lbl = std::make_shared<TextComponent>(mWindow,
|
auto lbl =
|
||||||
Utils::String::toUpper(iter->displayName), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(iter->displayName),
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||||
row.addElement(lbl, true); // Label.
|
row.addElement(lbl, true); // Label.
|
||||||
|
|
||||||
switch (iter->type) {
|
switch (iter->type) {
|
||||||
case MD_BOOL: {
|
case MD_BOOL: {
|
||||||
ed = std::make_shared<SwitchComponent>(window);
|
ed = std::make_shared<SwitchComponent>(window);
|
||||||
// Make the switches slightly smaller.
|
// Make the switches slightly smaller.
|
||||||
auto switchSize = ed->getSize() * 0.9f;
|
auto switchSize = ed->getSize() * 0.9f;
|
||||||
|
@ -133,9 +132,9 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
row.addElement(ed, false, true);
|
row.addElement(ed, false, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MD_RATING: {
|
case MD_RATING: {
|
||||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(spacer, false);
|
||||||
|
|
||||||
ed = std::make_shared<RatingComponent>(window, true);
|
ed = std::make_shared<RatingComponent>(window, true);
|
||||||
|
@ -145,17 +144,17 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
row.addElement(ed, false, true);
|
row.addElement(ed, false, true);
|
||||||
|
|
||||||
auto ratingSpacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(ratingSpacer, false);
|
||||||
|
|
||||||
// Pass input to the actual RatingComponent instead of the spacer.
|
// Pass input to the actual RatingComponent instead of the spacer.
|
||||||
row.input_handler = std::bind(&GuiComponent::input,
|
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||||
ed.get(), std::placeholders::_1, std::placeholders::_2);
|
std::placeholders::_2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MD_DATE: {
|
case MD_DATE: {
|
||||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(spacer, false);
|
||||||
|
|
||||||
ed = std::make_shared<DateTimeEditComponent>(window, true);
|
ed = std::make_shared<DateTimeEditComponent>(window, true);
|
||||||
|
@ -164,29 +163,22 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
row.addElement(ed, false);
|
row.addElement(ed, false);
|
||||||
|
|
||||||
auto dateSpacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(dateSpacer, false);
|
||||||
|
|
||||||
// Pass input to the actual DateTimeEditComponent instead of the spacer.
|
// Pass input to the actual DateTimeEditComponent instead of the spacer.
|
||||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(),
|
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||||
std::placeholders::_1, std::placeholders::_2);
|
std::placeholders::_2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Not in use as 'lastplayed' is flagged as statistics and these are skipped.
|
case MD_LAUNCHCOMMAND: {
|
||||||
// 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, "",
|
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);
|
row.addElement(ed, true);
|
||||||
|
|
||||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(spacer, false);
|
||||||
|
|
||||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
@ -207,26 +199,27 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string staticTextString = "Default value from es_systems.xml:";
|
std::string staticTextString = "Default value from es_systems.xml:";
|
||||||
std::string defaultLaunchCommand = scraperParams.system->
|
std::string defaultLaunchCommand =
|
||||||
getSystemEnvData()->mLaunchCommand;
|
scraperParams.system->getSystemEnvData()->mLaunchCommand;
|
||||||
|
|
||||||
row.makeAcceptInputHandler([this, title, staticTextString,
|
row.makeAcceptInputHandler([this, title, staticTextString, defaultLaunchCommand, ed,
|
||||||
defaultLaunchCommand, ed, updateVal, multiLine] {
|
updateVal, multiLine] {
|
||||||
mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiComplexTextEditPopup(
|
||||||
title, staticTextString, defaultLaunchCommand, ed->getValue(),
|
mWindow, getHelpStyle(), title, staticTextString, defaultLaunchCommand,
|
||||||
updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MD_MULTILINE_STRING:
|
case MD_MULTILINE_STRING:
|
||||||
default: {
|
default: {
|
||||||
// MD_STRING.
|
// MD_STRING.
|
||||||
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
ed = std::make_shared<TextComponent>(window, "",
|
||||||
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT),
|
||||||
|
0x777777FF, ALIGN_RIGHT);
|
||||||
row.addElement(ed, true);
|
row.addElement(ed, true);
|
||||||
|
|
||||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
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);
|
row.addElement(spacer, false);
|
||||||
|
|
||||||
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
@ -239,9 +232,9 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
|
|
||||||
gamePath = Utils::FileSystem::getStem(mScraperParams.game->getPath());
|
gamePath = Utils::FileSystem::getStem(mScraperParams.game->getPath());
|
||||||
|
|
||||||
// OK callback (apply new value to ed).
|
// OK callback (apply new value to ed).
|
||||||
auto updateVal = [ed, currentKey, originalValue, gamePath]
|
auto updateVal = [ed, currentKey, originalValue,
|
||||||
(const std::string& newVal) {
|
gamePath](const std::string& newVal) {
|
||||||
// If the user has entered a blank game name, then set the name to the ROM
|
// If the user has entered a blank game name, then set the name to the ROM
|
||||||
// filename (minus the extension).
|
// filename (minus the extension).
|
||||||
if (currentKey == "name" && newVal == "") {
|
if (currentKey == "name" && newVal == "") {
|
||||||
|
@ -251,27 +244,28 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
else
|
else
|
||||||
ed->setColor(TEXTCOLOR_USERMARKED);
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
||||||
}
|
}
|
||||||
else if (newVal == "" && (currentKey == "developer" ||
|
else if (newVal == "" &&
|
||||||
currentKey == "publisher" || currentKey == "genre" ||
|
(currentKey == "developer" || currentKey == "publisher" ||
|
||||||
currentKey == "players")) {
|
currentKey == "genre" || currentKey == "players")) {
|
||||||
ed->setValue("unknown");
|
ed->setValue("unknown");
|
||||||
if (originalValue == "unknown")
|
if (originalValue == "unknown")
|
||||||
ed->setColor(DEFAULT_TEXTCOLOR);
|
ed->setColor(DEFAULT_TEXTCOLOR);
|
||||||
else
|
else
|
||||||
ed->setColor(TEXTCOLOR_USERMARKED);
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ed->setValue(newVal);
|
ed->setValue(newVal);
|
||||||
if (newVal == originalValue)
|
if (newVal == originalValue)
|
||||||
ed->setColor(DEFAULT_TEXTCOLOR);
|
ed->setColor(DEFAULT_TEXTCOLOR);
|
||||||
else
|
else
|
||||||
ed->setColor(TEXTCOLOR_USERMARKED);
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
||||||
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
ed->getValue(), updateVal, multiLine,
|
||||||
|
"APPLY", "APPLY CHANGES?"));
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -286,8 +280,8 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
if (!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
if (!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SCRAPE", "scrape",
|
buttons.push_back(std::make_shared<ButtonComponent>(
|
||||||
std::bind(&GuiMetaDataEd::fetch, this)));
|
mWindow, "SCRAPE", "scrape", std::bind(&GuiMetaDataEd::fetch, this)));
|
||||||
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save metadata", [&] {
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save metadata", [&] {
|
||||||
save();
|
save();
|
||||||
|
@ -295,49 +289,60 @@ GuiMetaDataEd::GuiMetaDataEd(
|
||||||
delete this;
|
delete this;
|
||||||
}));
|
}));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes",
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes",
|
||||||
[&] { delete this; }));
|
[&] { delete this; }));
|
||||||
|
|
||||||
if (scraperParams.game->getType() == FOLDER) {
|
if (scraperParams.game->getType() == FOLDER) {
|
||||||
if (mClearGameFunc) {
|
if (mClearGameFunc) {
|
||||||
auto clearSelf = [&] { mClearGameFunc(); delete this; };
|
auto clearSelf = [&] {
|
||||||
|
mClearGameFunc();
|
||||||
|
delete this;
|
||||||
|
};
|
||||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
"THIS WILL DELETE ANY MEDIA FILES AND\n"
|
"THIS WILL DELETE ANY MEDIA FILES AND\n"
|
||||||
"THE GAMELIST.XML ENTRY FOR THIS FOLDER,\n"
|
"THE GAMELIST.XML ENTRY FOR THIS FOLDER,\n"
|
||||||
"BUT NEITHER THE FOLDER ITSELF OR ANY\n"
|
"BUT NEITHER THE FOLDER ITSELF OR ANY\n"
|
||||||
"CONTENT INSIDE IT WILL BE REMOVED\n"
|
"CONTENT INSIDE IT WILL BE REMOVED\n"
|
||||||
"ARE YOU SURE?",
|
"ARE YOU SURE?",
|
||||||
"YES", clearSelf, "NO", nullptr)); };
|
"YES", clearSelf, "NO", nullptr));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR",
|
};
|
||||||
"clear folder", clearSelfBtnFunc));
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear folder",
|
||||||
|
clearSelfBtnFunc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mClearGameFunc) {
|
if (mClearGameFunc) {
|
||||||
auto clearSelf = [&] { mClearGameFunc(); delete this; };
|
auto clearSelf = [&] {
|
||||||
|
mClearGameFunc();
|
||||||
|
delete this;
|
||||||
|
};
|
||||||
auto clearSelfBtnFunc = [this, clearSelf] {
|
auto clearSelfBtnFunc = [this, clearSelf] {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
"THIS WILL DELETE ANY MEDIA FILES\n"
|
"THIS WILL DELETE ANY MEDIA FILES\n"
|
||||||
"AND THE GAMELIST.XML ENTRY FOR\n"
|
"AND THE GAMELIST.XML ENTRY FOR\n"
|
||||||
"THIS GAME, BUT THE GAME FILE\n"
|
"THIS GAME, BUT THE GAME FILE\n"
|
||||||
"ITSELF WILL NOT BE REMOVED\n"
|
"ITSELF WILL NOT BE REMOVED\n"
|
||||||
"ARE YOU SURE?",
|
"ARE YOU SURE?",
|
||||||
"YES", clearSelf, "NO", nullptr)); };
|
"YES", clearSelf, "NO", nullptr));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR",
|
};
|
||||||
"clear file", clearSelfBtnFunc));
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear file",
|
||||||
|
clearSelfBtnFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDeleteGameFunc) {
|
if (mDeleteGameFunc) {
|
||||||
auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
|
auto deleteFilesAndSelf = [&] {
|
||||||
|
mDeleteGameFunc();
|
||||||
|
delete this;
|
||||||
|
};
|
||||||
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
"THIS WILL DELETE THE GAME\n"
|
"THIS WILL DELETE THE GAME\n"
|
||||||
"FILE, ANY MEDIA FILES AND\n"
|
"FILE, ANY MEDIA FILES AND\n"
|
||||||
"THE GAMELIST.XML ENTRY\n"
|
"THE GAMELIST.XML ENTRY\n"
|
||||||
"ARE YOU SURE?",
|
"ARE YOU SURE?",
|
||||||
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
"YES", deleteFilesAndSelf, "NO", nullptr));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
|
};
|
||||||
"delete game", deleteGameBtnFunc));
|
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);
|
mGrid.setEntry(mButtons, Vector2i(0, 2), true, false);
|
||||||
|
|
||||||
// Resize + center.
|
// Resize + center.
|
||||||
float width = static_cast<float>(std::min(static_cast<int>(Renderer::getScreenHeight() *
|
float width =
|
||||||
1.05f), static_cast<int>(Renderer::getScreenWidth() * 0.90f)));
|
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);
|
setSize(width, Renderer::getScreenHeight() * 0.83f);
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
(Renderer::getScreenHeight() - mSize.y()) / 2);
|
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMetaDataEd::onSizeChanged()
|
void GuiMetaDataEd::onSizeChanged()
|
||||||
|
@ -360,8 +366,8 @@ void GuiMetaDataEd::onSizeChanged()
|
||||||
const float subtitleHeight = mSubtitle->getFont()->getLetterHeight();
|
const float subtitleHeight = mSubtitle->getFont()->getLetterHeight();
|
||||||
const float titleSubtitleSpacing = mSize.y() * 0.03f;
|
const float titleSubtitleSpacing = mSize.y() * 0.03f;
|
||||||
|
|
||||||
mGrid.setRowHeightPerc(0, (titleHeight + titleSubtitleSpacing + subtitleHeight +
|
mGrid.setRowHeightPerc(
|
||||||
TITLE_VERT_PADDING) / mSize.y());
|
0, (titleHeight + titleSubtitleSpacing + subtitleHeight + TITLE_VERT_PADDING) / mSize.y());
|
||||||
mGrid.setRowHeightPerc(2, mButtons->getSize().y() / 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.
|
// 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);
|
mList->setSize(mList->getSize().x(), listHeight);
|
||||||
Vector2f newWindowSize = mSize;
|
Vector2f newWindowSize = mSize;
|
||||||
newWindowSize.y() -= heightAdjustment;
|
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.
|
// Move the buttons up as well to make the layout align correctly after the resize.
|
||||||
Vector3f newButtonPos = mButtons->getPosition();
|
Vector3f newButtonPos = mButtons->getPosition();
|
||||||
|
@ -411,13 +417,13 @@ void GuiMetaDataEd::save()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!showHiddenGames && mMetaDataDecl.at(i).key == "hidden" &&
|
if (!showHiddenGames && mMetaDataDecl.at(i).key == "hidden" &&
|
||||||
mEditors.at(i)->getValue() != mMetaData->get("hidden"))
|
mEditors.at(i)->getValue() != mMetaData->get("hidden"))
|
||||||
hideGameWhileHidden = true;
|
hideGameWhileHidden = true;
|
||||||
|
|
||||||
// Check whether the flag to count the entry as a game was set to enabled.
|
// Check whether the flag to count the entry as a game was set to enabled.
|
||||||
if (mMetaDataDecl.at(i).key == "nogamecount" &&
|
if (mMetaDataDecl.at(i).key == "nogamecount" &&
|
||||||
mEditors.at(i)->getValue() != mMetaData->get("nogamecount") &&
|
mEditors.at(i)->getValue() != mMetaData->get("nogamecount") &&
|
||||||
mMetaData->get("nogamecount") == "true") {
|
mMetaData->get("nogamecount") == "true") {
|
||||||
setGameAsCounted = true;
|
setGameAsCounted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +456,7 @@ void GuiMetaDataEd::save()
|
||||||
for (FileData* child : mScraperParams.game->getChildrenRecursive()) {
|
for (FileData* child : mScraperParams.game->getChildrenRecursive()) {
|
||||||
if (!child->getHidden())
|
if (!child->getHidden())
|
||||||
child->metadata.set("hidden", "true");
|
child->metadata.set("hidden", "true");
|
||||||
hideGames.push_back(child);
|
hideGames.push_back(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -501,8 +507,8 @@ void GuiMetaDataEd::save()
|
||||||
|
|
||||||
void GuiMetaDataEd::fetch()
|
void GuiMetaDataEd::fetch()
|
||||||
{
|
{
|
||||||
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams,
|
GuiGameScraper* scr = new GuiGameScraper(
|
||||||
std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
mWindow, mScraperParams, std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
||||||
mWindow->pushGui(scr);
|
mWindow->pushGui(scr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,10 +520,6 @@ void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
|
||||||
|
|
||||||
mMediaFilesUpdated = result.savedNewMedia;
|
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.
|
// Check if any values were manually changed before starting the scraping.
|
||||||
// If so, it's these values we should compare against when scraping, not
|
// If so, it's these values we should compare against when scraping, not
|
||||||
// the values previously saved for the game.
|
// the values previously saved for the game.
|
||||||
|
@ -561,42 +563,31 @@ 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;
|
std::function<void()> closeFunc;
|
||||||
closeFunc = [this] {
|
closeFunc = [this] {
|
||||||
if (mMediaFilesUpdated) {
|
if (mMediaFilesUpdated) {
|
||||||
// Always reload the gamelist if media files were updated, even if the user
|
// Always reload the gamelist if media files were updated, even if the user
|
||||||
// chose to not save any metadata changes. Also manually unload the game image
|
// chose to not save any metadata changes. Also manually unload the game image
|
||||||
// and marquee, as otherwise they would not get updated until the user scrolls up
|
// and marquee, as otherwise they would not get updated until the user scrolls up
|
||||||
// and down the gamelist.
|
// and down the gamelist.
|
||||||
TextureResource::manualUnload(mScraperParams.game->getImagePath(), false);
|
TextureResource::manualUnload(mScraperParams.game->getImagePath(), false);
|
||||||
TextureResource::manualUnload(mScraperParams.game->getMarqueePath(), false);
|
TextureResource::manualUnload(mScraperParams.game->getMarqueePath(), false);
|
||||||
ViewController::get()->reloadGameListView(mScraperParams.system);
|
ViewController::get()->reloadGameListView(mScraperParams.system);
|
||||||
mWindow->invalidateCachedBackground();
|
mWindow->invalidateCachedBackground();
|
||||||
}
|
}
|
||||||
ViewController::get()->onPauseVideo();
|
ViewController::get()->onPauseVideo();
|
||||||
delete this;
|
delete this;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (metadataUpdated) {
|
if (metadataUpdated) {
|
||||||
// Changes were made, ask if the user wants to save them.
|
// Changes were made, ask if the user wants to save them.
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
"SAVE CHANGES?",
|
mWindow, getHelpStyle(), "SAVE CHANGES?", "YES",
|
||||||
"YES", [this, closeFunc] { save(); closeFunc(); },
|
[this, closeFunc] {
|
||||||
"NO", closeFunc
|
save();
|
||||||
));
|
closeFunc();
|
||||||
|
},
|
||||||
|
"NO", closeFunc));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Always save if the media files have been changed (i.e. newly scraped images).
|
// 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
|
#ifndef ES_APP_GUIS_GUI_META_DATA_ED_H
|
||||||
#define 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/ComponentGrid.h"
|
||||||
#include "components/NinePatchComponent.h"
|
#include "components/NinePatchComponent.h"
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "MetaData.h"
|
|
||||||
|
|
||||||
class ComponentList;
|
class ComponentList;
|
||||||
class TextComponent;
|
class TextComponent;
|
||||||
|
@ -24,14 +24,14 @@ class TextComponent;
|
||||||
class GuiMetaDataEd : public GuiComponent
|
class GuiMetaDataEd : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GuiMetaDataEd(
|
GuiMetaDataEd(Window* window,
|
||||||
Window* window,
|
MetaDataList* md,
|
||||||
MetaDataList* md, const std::vector<MetaDataDecl>&mdd,
|
const std::vector<MetaDataDecl>& mdd,
|
||||||
ScraperSearchParams params,
|
ScraperSearchParams params,
|
||||||
const std::string& header,
|
const std::string& header,
|
||||||
std::function<void()> savedCallback,
|
std::function<void()> savedCallback,
|
||||||
std::function<void()> clearGameFunc,
|
std::function<void()> clearGameFunc,
|
||||||
std::function<void()> deleteGameFunc);
|
std::function<void()> deleteGameFunc);
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
|
|
|
@ -9,17 +9,15 @@
|
||||||
|
|
||||||
#include "guis/GuiOfflineGenerator.h"
|
#include "guis/GuiOfflineGenerator.h"
|
||||||
|
|
||||||
|
#include "SystemData.h"
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "SystemData.h"
|
|
||||||
|
|
||||||
GuiOfflineGenerator::GuiOfflineGenerator(
|
GuiOfflineGenerator::GuiOfflineGenerator(Window* window, const std::queue<FileData*>& gameQueue)
|
||||||
Window* window,
|
: GuiComponent(window)
|
||||||
const std::queue<FileData*>& gameQueue)
|
, mBackground(window, ":/graphics/frame.svg")
|
||||||
: GuiComponent(window),
|
, mGrid(window, Vector2i(6, 13))
|
||||||
mBackground(window, ":/graphics/frame.svg"),
|
, mGameQueue(gameQueue)
|
||||||
mGrid(window, Vector2i(6, 13)),
|
|
||||||
mGameQueue(gameQueue)
|
|
||||||
{
|
{
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
@ -39,140 +37,139 @@ GuiOfflineGenerator::GuiOfflineGenerator(
|
||||||
|
|
||||||
// Header.
|
// Header.
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, "MIXIMAGE OFFLINE GENERATOR",
|
mTitle = std::make_shared<TextComponent>(mWindow, "MIXIMAGE OFFLINE GENERATOR",
|
||||||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true, Vector2i(6, 1));
|
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true, Vector2i(6, 1));
|
||||||
|
|
||||||
mStatus = std::make_shared<TextComponent>(mWindow, "NOT STARTED",
|
mStatus = std::make_shared<TextComponent>(mWindow, "NOT STARTED", Font::get(FONT_SIZE_MEDIUM),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
0x777777FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mStatus, Vector2i(0, 1), false, true, Vector2i(6, 1));
|
mGrid.setEntry(mStatus, Vector2i(0, 1), false, true, Vector2i(6, 1));
|
||||||
|
|
||||||
mGameCounter = std::make_shared<TextComponent>(mWindow,
|
mGameCounter = std::make_shared<TextComponent>(
|
||||||
std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
mWindow,
|
||||||
|
std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
||||||
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED",
|
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED",
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mGameCounter, Vector2i(0, 2), false, true, Vector2i(6, 1));
|
mGrid.setEntry(mGameCounter, Vector2i(0, 2), false, true, Vector2i(6, 1));
|
||||||
|
|
||||||
// Spacer row with top border.
|
// Spacer row with top border.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 3),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 3), false, false,
|
||||||
false, false, Vector2i(6, 1), GridFlags::BORDER_TOP);
|
Vector2i(6, 1), GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
// Left spacer.
|
// Left spacer.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 4),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 4), false, false,
|
||||||
false, false, Vector2i(1, 7));
|
Vector2i(1, 7));
|
||||||
|
|
||||||
// Generated label.
|
// Generated label.
|
||||||
mGeneratedLbl = std::make_shared<TextComponent>(mWindow, "Generated:",
|
mGeneratedLbl = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
mWindow, "Generated:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mGeneratedLbl, Vector2i(1, 4), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mGeneratedLbl, Vector2i(1, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Generated value/counter.
|
// Generated value/counter.
|
||||||
mGeneratedVal = std::make_shared<TextComponent>(mWindow,
|
mGeneratedVal =
|
||||||
std::to_string(mGamesProcessed),
|
std::make_shared<TextComponent>(mWindow, std::to_string(mGamesProcessed),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mGeneratedVal, Vector2i(2, 4), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mGeneratedVal, Vector2i(2, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Overwritten label.
|
// Overwritten label.
|
||||||
mOverwrittenLbl = std::make_shared<TextComponent>(mWindow, "Overwritten:",
|
mOverwrittenLbl = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
mWindow, "Overwritten:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mOverwrittenLbl, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mOverwrittenLbl, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Overwritten value/counter.
|
// Overwritten value/counter.
|
||||||
mOverwrittenVal = std::make_shared<TextComponent>(mWindow,
|
mOverwrittenVal =
|
||||||
std::to_string(mImagesOverwritten),
|
std::make_shared<TextComponent>(mWindow, std::to_string(mImagesOverwritten),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mOverwrittenVal, Vector2i(2, 5), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mOverwrittenVal, Vector2i(2, 5), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Skipping label.
|
// Skipping label.
|
||||||
mSkippedLbl = std::make_shared<TextComponent>(mWindow, "Skipped (existing):",
|
mSkippedLbl = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
mWindow, "Skipped (existing):", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mSkippedLbl, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mSkippedLbl, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Skipping value/counter.
|
// Skipping value/counter.
|
||||||
mSkippedVal= std::make_shared<TextComponent>(mWindow,
|
mSkippedVal = std::make_shared<TextComponent>(
|
||||||
std::to_string(mGamesSkipped),
|
mWindow, std::to_string(mGamesSkipped), Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
|
||||||
mGrid.setEntry(mSkippedVal, Vector2i(2, 6), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mSkippedVal, Vector2i(2, 6), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Failed label.
|
// Failed label.
|
||||||
mFailedLbl = std::make_shared<TextComponent>(mWindow, "Failed:",
|
mFailedLbl = std::make_shared<TextComponent>(mWindow, "Failed:", Font::get(FONT_SIZE_SMALL),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mFailedLbl, Vector2i(1, 7), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mFailedLbl, Vector2i(1, 7), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Failed value/counter.
|
// Failed value/counter.
|
||||||
mFailedVal = std::make_shared<TextComponent>(mWindow,
|
mFailedVal = std::make_shared<TextComponent>(
|
||||||
std::to_string(mGamesFailed),
|
mWindow, std::to_string(mGamesFailed), Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
|
||||||
mGrid.setEntry(mFailedVal, Vector2i(2, 7), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mFailedVal, Vector2i(2, 7), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Processing label.
|
// Processing label.
|
||||||
mProcessingLbl = std::make_shared<TextComponent>(mWindow, "Processing: ",
|
mProcessingLbl = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
mWindow, "Processing: ", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mProcessingLbl, Vector2i(3, 4), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mProcessingLbl, Vector2i(3, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Processing value.
|
// Processing value.
|
||||||
mProcessingVal = std::make_shared<TextComponent>(mWindow, "",
|
mProcessingVal = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mProcessingVal, Vector2i(4, 4), false, true, Vector2i(1, 1));
|
mGrid.setEntry(mProcessingVal, Vector2i(4, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
// Spacer row.
|
// Spacer row.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 8),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 8), false, false,
|
||||||
false, false, Vector2i(4, 1));
|
Vector2i(4, 1));
|
||||||
|
|
||||||
// Last error message label.
|
// Last error message label.
|
||||||
mLastErrorLbl = std::make_shared<TextComponent>(mWindow, "Last error message:",
|
mLastErrorLbl = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
mWindow, "Last error message:", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mLastErrorLbl, Vector2i(1, 9), false, true, Vector2i(4, 1));
|
mGrid.setEntry(mLastErrorLbl, Vector2i(1, 9), false, true, Vector2i(4, 1));
|
||||||
|
|
||||||
// Last error message value.
|
// Last error message value.
|
||||||
mLastErrorVal = std::make_shared<TextComponent>(mWindow, "",
|
mLastErrorVal = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_SMALL),
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
0x888888FF, ALIGN_LEFT);
|
||||||
mGrid.setEntry(mLastErrorVal, Vector2i(1, 10), false, true, Vector2i(4, 1));
|
mGrid.setEntry(mLastErrorVal, Vector2i(1, 10), false, true, Vector2i(4, 1));
|
||||||
|
|
||||||
// Right spacer.
|
// Right spacer.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(5, 4),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(5, 4), false, false,
|
||||||
false, false, Vector2i(1, 7));
|
Vector2i(1, 7));
|
||||||
|
|
||||||
// Spacer row with bottom border.
|
// Spacer row with bottom border.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 11),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 11), false, false,
|
||||||
false, false, Vector2i(6, 1), GridFlags::BORDER_BOTTOM);
|
Vector2i(6, 1), GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
// Buttons.
|
// Buttons.
|
||||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
mStartPauseButton = std::make_shared<ButtonComponent>(mWindow, "START",
|
mStartPauseButton =
|
||||||
"start processing", [this](){
|
std::make_shared<ButtonComponent>(mWindow, "START", "start processing", [this]() {
|
||||||
if (!mProcessing) {
|
if (!mProcessing) {
|
||||||
mProcessing = true;
|
mProcessing = true;
|
||||||
mPaused = false;
|
mPaused = false;
|
||||||
mStartPauseButton->setText("PAUSE", "pause processing");
|
mStartPauseButton->setText("PAUSE", "pause processing");
|
||||||
mCloseButton->setText("CLOSE", "close (abort processing)");
|
mCloseButton->setText("CLOSE", "close (abort processing)");
|
||||||
mStatus->setText("RUNNING...");
|
mStatus->setText("RUNNING...");
|
||||||
if (mGamesProcessed == 0) {
|
if (mGamesProcessed == 0) {
|
||||||
LOG(LogInfo) << "GuiOfflineGenerator: Processing " << mTotalGames << " games";
|
LOG(LogInfo) << "GuiOfflineGenerator: Processing " << mTotalGames << " games";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
if (mMiximageGeneratorThread.joinable())
|
||||||
if (mMiximageGeneratorThread.joinable())
|
mMiximageGeneratorThread.join();
|
||||||
mMiximageGeneratorThread.join();
|
mPaused = true;
|
||||||
mPaused = true;
|
update(1);
|
||||||
update(1);
|
mProcessing = false;
|
||||||
mProcessing = false;
|
this->mStartPauseButton->setText("START", "start processing");
|
||||||
this->mStartPauseButton->setText("START", "start processing");
|
this->mCloseButton->setText("CLOSE", "close (abort processing)");
|
||||||
this->mCloseButton->setText("CLOSE", "close (abort processing)");
|
mStatus->setText("PAUSED");
|
||||||
mStatus->setText("PAUSED");
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
buttons.push_back(mStartPauseButton);
|
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) {
|
if (mGamesProcessed != 0 && mGamesProcessed != mTotalGames) {
|
||||||
LOG(LogInfo) << "GuiOfflineGenerator: Aborted after processing " <<
|
LOG(LogInfo) << "GuiOfflineGenerator: Aborted after processing " << mGamesProcessed
|
||||||
mGamesProcessed << (mGamesProcessed == 1 ? " game (" : " games (") <<
|
<< (mGamesProcessed == 1 ? " game (" : " games (") << mImagesGenerated
|
||||||
mImagesGenerated << (mImagesGenerated == 1 ? " image " : " images ") <<
|
<< (mImagesGenerated == 1 ? " image " : " images ") << "generated, "
|
||||||
"generated, " << mGamesSkipped <<
|
<< mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ")
|
||||||
(mGamesSkipped == 1 ? " game " : " games ") << "skipped, " << mGamesFailed <<
|
<< "skipped, " << mGamesFailed
|
||||||
(mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
<< (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||||
}
|
}
|
||||||
delete this;
|
delete this;
|
||||||
});
|
});
|
||||||
|
@ -184,12 +181,12 @@ GuiOfflineGenerator::GuiOfflineGenerator(
|
||||||
|
|
||||||
// For narrower displays (e.g. in 4:3 ratio), allow the window to fill 95% of the screen
|
// 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.
|
// width rather than the 85% allowed for wider displays.
|
||||||
float width = Renderer::getScreenWidth() *
|
float width =
|
||||||
((Renderer::getScreenAspectRatio() < 1.4f) ? 0.95f : 0.85f);
|
Renderer::getScreenWidth() * ((Renderer::getScreenAspectRatio() < 1.4f) ? 0.95f : 0.85f);
|
||||||
|
|
||||||
setSize(width, Renderer::getScreenHeight() * 0.75f);
|
setSize(width, Renderer::getScreenHeight() * 0.75f);
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiOfflineGenerator::~GuiOfflineGenerator()
|
GuiOfflineGenerator::~GuiOfflineGenerator()
|
||||||
|
@ -281,12 +278,12 @@ void GuiOfflineGenerator::update(int deltaTime)
|
||||||
mGame = mGameQueue.front();
|
mGame = mGameQueue.front();
|
||||||
mGameQueue.pop();
|
mGameQueue.pop();
|
||||||
|
|
||||||
mGameName = mGame->getName() + " [" +
|
mGameName =
|
||||||
Utils::String::toUpper(mGame->getSystem()->getName()) + "]";
|
mGame->getName() + " [" + Utils::String::toUpper(mGame->getSystem()->getName()) + "]";
|
||||||
mProcessingVal->setText(mGameName);
|
mProcessingVal->setText(mGameName);
|
||||||
|
|
||||||
if (!Settings::getInstance()->getBool("MiximageOverwrite") &&
|
if (!Settings::getInstance()->getBool("MiximageOverwrite") &&
|
||||||
mGame->getMiximagePath() != "") {
|
mGame->getMiximagePath() != "") {
|
||||||
mGamesProcessed++;
|
mGamesProcessed++;
|
||||||
mGamesSkipped++;
|
mGamesSkipped++;
|
||||||
mSkippedVal->setText(std::to_string(mGamesSkipped));
|
mSkippedVal->setText(std::to_string(mGamesSkipped));
|
||||||
|
@ -303,14 +300,14 @@ void GuiOfflineGenerator::update(int deltaTime)
|
||||||
mGeneratorFuture = mGeneratorPromise.get_future();
|
mGeneratorFuture = mGeneratorPromise.get_future();
|
||||||
|
|
||||||
mMiximageGeneratorThread = std::thread(&MiximageGenerator::startThread,
|
mMiximageGeneratorThread = std::thread(&MiximageGenerator::startThread,
|
||||||
mMiximageGenerator.get(), &mGeneratorPromise);
|
mMiximageGenerator.get(), &mGeneratorPromise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the statistics.
|
// Update the statistics.
|
||||||
mStatus->setText("RUNNING...");
|
mStatus->setText("RUNNING...");
|
||||||
mGameCounter->setText(std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
mGameCounter->setText(std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
||||||
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED");
|
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED");
|
||||||
|
|
||||||
mGeneratedVal->setText(std::to_string(mImagesGenerated));
|
mGeneratedVal->setText(std::to_string(mImagesGenerated));
|
||||||
mFailedVal->setText(std::to_string(mGamesFailed));
|
mFailedVal->setText(std::to_string(mGamesFailed));
|
||||||
|
@ -319,13 +316,13 @@ void GuiOfflineGenerator::update(int deltaTime)
|
||||||
if (mGamesProcessed == mTotalGames) {
|
if (mGamesProcessed == mTotalGames) {
|
||||||
mStatus->setText("COMPLETED");
|
mStatus->setText("COMPLETED");
|
||||||
mStartPauseButton->setText("DONE", "done (close)");
|
mStartPauseButton->setText("DONE", "done (close)");
|
||||||
mStartPauseButton->setPressedFunc([this](){ delete this; });
|
mStartPauseButton->setPressedFunc([this]() { delete this; });
|
||||||
mCloseButton->setText("CLOSE", "close");
|
mCloseButton->setText("CLOSE", "close");
|
||||||
mProcessingVal->setText("");
|
mProcessingVal->setText("");
|
||||||
LOG(LogInfo) << "GuiOfflineGenerator: Completed processing (" << mImagesGenerated <<
|
LOG(LogInfo) << "GuiOfflineGenerator: Completed processing (" << mImagesGenerated
|
||||||
(mImagesGenerated == 1 ? " image " : " images ") << "generated, " <<
|
<< (mImagesGenerated == 1 ? " image " : " images ") << "generated, "
|
||||||
mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ") << "skipped, " <<
|
<< mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ") << "skipped, "
|
||||||
mGamesFailed << (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
<< mGamesFailed << (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||||
mProcessing = false;
|
mProcessing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
#ifndef ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
||||||
#define 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 "GuiComponent.h"
|
||||||
#include "MiximageGenerator.h"
|
#include "MiximageGenerator.h"
|
||||||
|
#include "components/ButtonComponent.h"
|
||||||
|
#include "components/ComponentGrid.h"
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
|
|
@ -10,23 +10,23 @@
|
||||||
|
|
||||||
#include "guis/GuiScraperMenu.h"
|
#include "guis/GuiScraperMenu.h"
|
||||||
|
|
||||||
|
#include "FileData.h"
|
||||||
|
#include "FileSorts.h"
|
||||||
|
#include "SystemData.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "guis/GuiOfflineGenerator.h"
|
#include "guis/GuiOfflineGenerator.h"
|
||||||
#include "guis/GuiScraperMulti.h"
|
#include "guis/GuiScraperMulti.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "FileData.h"
|
|
||||||
#include "FileSorts.h"
|
|
||||||
#include "SystemData.h"
|
|
||||||
|
|
||||||
|
|
||||||
GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
||||||
: GuiComponent(window), mMenu(window, title)
|
: GuiComponent(window)
|
||||||
|
, mMenu(window, title)
|
||||||
{
|
{
|
||||||
// Scraper service.
|
// Scraper service.
|
||||||
mScraper = std::make_shared<OptionListComponent<std::string>>
|
mScraper = std::make_shared<OptionListComponent<std::string>>(mWindow, getHelpStyle(),
|
||||||
(mWindow, getHelpStyle(), "SCRAPE FROM", false);
|
"SCRAPE FROM", false);
|
||||||
std::vector<std::string> scrapers = getScraperList();
|
std::vector<std::string> scrapers = getScraperList();
|
||||||
// Select either the first entry or the one read from the settings,
|
// Select either the first entry or the one read from the settings,
|
||||||
// just in case the scraper from settings has vanished.
|
// 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
|
// Search filters, getSearches() will generate a queue of games to scrape
|
||||||
// based on the outcome of the checks below.
|
// based on the outcome of the checks below.
|
||||||
mFilters = std::make_shared< OptionListComponent<GameFilterFunc>>
|
mFilters = std::make_shared<OptionListComponent<GameFilterFunc>>(mWindow, getHelpStyle(),
|
||||||
(mWindow, getHelpStyle(), "SCRAPE THESE GAMES", false);
|
"SCRAPE THESE GAMES", false);
|
||||||
mFilters->add("ALL GAMES", [](SystemData*, FileData*) -> bool { return true; }, false);
|
mFilters->add(
|
||||||
mFilters->add("FAVORITE GAMES", [](SystemData*, FileData* g) -> bool {
|
"ALL GAMES",
|
||||||
return g->getFavorite(); }, false);
|
[](SystemData*, FileData*) -> bool {
|
||||||
mFilters->add("NO METADATA", [](SystemData*, FileData* g) -> bool {
|
// All games.
|
||||||
return g->metadata.get("desc").empty(); }, false);
|
return true;
|
||||||
mFilters->add("NO GAME IMAGE",
|
},
|
||||||
[](SystemData*, FileData* g) -> bool {
|
false);
|
||||||
return g->getImagePath().empty(); }, false);
|
mFilters->add(
|
||||||
mFilters->add("NO GAME VIDEO",
|
"FAVORITE GAMES",
|
||||||
[](SystemData*, FileData* g) -> bool {
|
[](SystemData*, FileData* g) -> bool {
|
||||||
return g->getVideoPath().empty(); }, false);
|
// Favorite games.
|
||||||
mFilters->add("FOLDERS ONLY",
|
return g->getFavorite();
|
||||||
[](SystemData*, FileData* g) -> bool {
|
},
|
||||||
return g->getType() == FOLDER; }, false);
|
false);
|
||||||
|
mFilters->add(
|
||||||
|
"NO METADATA",
|
||||||
|
[](SystemData*, FileData* g) -> bool {
|
||||||
|
// No metadata.
|
||||||
|
return g->metadata.get("desc").empty();
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
mFilters->add(
|
||||||
|
"NO GAME IMAGE",
|
||||||
|
[](SystemData*, FileData* g) -> bool {
|
||||||
|
// 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"));
|
mFilters->selectEntry(Settings::getInstance()->getInt("ScraperFilter"));
|
||||||
mMenu.addWithLabel("SCRAPE THESE GAMES", mFilters);
|
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).
|
// Add systems (all systems with an existing platform ID are listed).
|
||||||
mSystems = std::make_shared< OptionListComponent<SystemData*>>
|
mSystems = std::make_shared<OptionListComponent<SystemData*>>(mWindow, getHelpStyle(),
|
||||||
(mWindow, getHelpStyle(), "SCRAPE THESE SYSTEMS", true);
|
"SCRAPE THESE SYSTEMS", true);
|
||||||
for (unsigned int i = 0; i < SystemData::sSystemVector.size(); i++) {
|
for (unsigned int i = 0; i < SystemData::sSystemVector.size(); i++) {
|
||||||
if (!SystemData::sSystemVector[i]->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) {
|
if (!SystemData::sSystemVector[i]->hasPlatformId(PlatformIds::PLATFORM_IGNORE)) {
|
||||||
mSystems->add(SystemData::sSystemVector[i]->getFullName(),
|
mSystems->add(SystemData::sSystemVector[i]->getFullName(), SystemData::sSystemVector[i],
|
||||||
SystemData::sSystemVector[i],
|
!SystemData::sSystemVector[i]->getPlatformIds().empty());
|
||||||
!SystemData::sSystemVector[i]->getPlatformIds().empty());
|
SystemData::sSystemVector[i]->getScrapeFlag() ? mSystems->selectEntry(i) :
|
||||||
SystemData::sSystemVector[i]->getScrapeFlag() ?
|
mSystems->unselectEntry(i);
|
||||||
mSystems->selectEntry(i) : mSystems->unselectEntry(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mMenu.addWithLabel("SCRAPE THESE SYSTEMS", mSystems);
|
mMenu.addWithLabel("SCRAPE THESE SYSTEMS", mSystems);
|
||||||
|
|
||||||
addEntry("ACCOUNT SETTINGS", 0x777777FF, true, [this] {
|
addEntry("ACCOUNT SETTINGS", 0x777777FF, true, [this] {
|
||||||
|
// Open the account options menu.
|
||||||
openAccountOptions();
|
openAccountOptions();
|
||||||
});
|
});
|
||||||
addEntry("CONTENT SETTINGS", 0x777777FF, true, [this] {
|
addEntry("CONTENT SETTINGS", 0x777777FF, true, [this] {
|
||||||
|
@ -93,6 +121,7 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
||||||
openContentOptions();
|
openContentOptions();
|
||||||
});
|
});
|
||||||
addEntry("MIXIMAGE SETTINGS", 0x777777FF, true, [this] {
|
addEntry("MIXIMAGE SETTINGS", 0x777777FF, true, [this] {
|
||||||
|
// Open the miximage options menu.
|
||||||
openMiximageOptions();
|
openMiximageOptions();
|
||||||
});
|
});
|
||||||
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] {
|
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] {
|
||||||
|
@ -111,8 +140,8 @@ GuiScraperMenu::GuiScraperMenu(Window* window, std::string title)
|
||||||
|
|
||||||
setSize(mMenu.getSize());
|
setSize(mMenu.getSize());
|
||||||
|
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
Renderer::getScreenHeight() * 0.13f);
|
Renderer::getScreenHeight() * 0.13f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiScraperMenu::~GuiScraperMenu()
|
GuiScraperMenu::~GuiScraperMenu()
|
||||||
|
@ -120,9 +149,9 @@ GuiScraperMenu::~GuiScraperMenu()
|
||||||
// Save the scrape flags to the system settings so that they are
|
// Save the scrape flags to the system settings so that they are
|
||||||
// remembered throughout the program session.
|
// remembered throughout the program session.
|
||||||
std::vector<SystemData*> sys = mSystems->getSelectedObjects();
|
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 != SystemData::sSystemVector.cend(); it++) {
|
||||||
(*it)->setScrapeFlag(false);
|
(*it)->setScrapeFlag(false);
|
||||||
for (auto it_sys = sys.cbegin(); it_sys != sys.cend(); it_sys++) {
|
for (auto it_sys = sys.cbegin(); it_sys != sys.cend(); it_sys++) {
|
||||||
if ((*it)->getFullName() == (*it_sys)->getFullName())
|
if ((*it)->getFullName() == (*it_sys)->getFullName())
|
||||||
(*it)->setScrapeFlag(true);
|
(*it)->setScrapeFlag(true);
|
||||||
|
@ -136,48 +165,48 @@ void GuiScraperMenu::openAccountOptions()
|
||||||
|
|
||||||
// Whether to use the ScreenScraper account when scraping.
|
// Whether to use the ScreenScraper account when scraping.
|
||||||
auto scraper_use_account_screenscraper = std::make_shared<SwitchComponent>(mWindow);
|
auto scraper_use_account_screenscraper = std::make_shared<SwitchComponent>(mWindow);
|
||||||
scraper_use_account_screenscraper->setState(Settings::getInstance()->
|
scraper_use_account_screenscraper->setState(
|
||||||
getBool("ScraperUseAccountScreenScraper"));
|
Settings::getInstance()->getBool("ScraperUseAccountScreenScraper"));
|
||||||
s->addWithLabel("USE THIS ACCOUNT FOR SCREENSCRAPER", scraper_use_account_screenscraper);
|
s->addWithLabel("USE THIS ACCOUNT FOR SCREENSCRAPER", scraper_use_account_screenscraper);
|
||||||
s->addSaveFunc([scraper_use_account_screenscraper, s] {
|
s->addSaveFunc([scraper_use_account_screenscraper, s] {
|
||||||
if (scraper_use_account_screenscraper->getState() !=
|
if (scraper_use_account_screenscraper->getState() !=
|
||||||
Settings::getInstance()->getBool("ScraperUseAccountScreenScraper")) {
|
Settings::getInstance()->getBool("ScraperUseAccountScreenScraper")) {
|
||||||
Settings::getInstance()->setBool("ScraperUseAccountScreenScraper",
|
Settings::getInstance()->setBool("ScraperUseAccountScreenScraper",
|
||||||
scraper_use_account_screenscraper->getState());
|
scraper_use_account_screenscraper->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ScreenScraper username.
|
// ScreenScraper username.
|
||||||
auto scraper_username_screenscraper = std::make_shared<TextComponent>(mWindow, "",
|
auto scraper_username_screenscraper = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||||
s->addEditableTextComponent("SCREENSCRAPER USERNAME", scraper_username_screenscraper,
|
s->addEditableTextComponent("SCREENSCRAPER USERNAME", scraper_username_screenscraper,
|
||||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper"));
|
Settings::getInstance()->getString("ScraperUsernameScreenScraper"));
|
||||||
s->addSaveFunc([scraper_username_screenscraper, s] {
|
s->addSaveFunc([scraper_username_screenscraper, s] {
|
||||||
if (scraper_username_screenscraper->getValue() !=
|
if (scraper_username_screenscraper->getValue() !=
|
||||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper")) {
|
Settings::getInstance()->getString("ScraperUsernameScreenScraper")) {
|
||||||
Settings::getInstance()->setString("ScraperUsernameScreenScraper",
|
Settings::getInstance()->setString("ScraperUsernameScreenScraper",
|
||||||
scraper_username_screenscraper->getValue());
|
scraper_username_screenscraper->getValue());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ScreenScraper password.
|
// ScreenScraper password.
|
||||||
auto scraper_password_screenscraper = std::make_shared<TextComponent>(mWindow, "",
|
auto scraper_password_screenscraper = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_RIGHT);
|
||||||
std::string passwordMasked;
|
std::string passwordMasked;
|
||||||
if (Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
if (Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
||||||
passwordMasked = "********";
|
passwordMasked = "********";
|
||||||
scraper_password_screenscraper->setHiddenValue(
|
scraper_password_screenscraper->setHiddenValue(
|
||||||
Settings::getInstance()->getString("ScraperPasswordScreenScraper"));
|
Settings::getInstance()->getString("ScraperPasswordScreenScraper"));
|
||||||
}
|
}
|
||||||
s->addEditableTextComponent("SCREENSCRAPER PASSWORD",
|
s->addEditableTextComponent("SCREENSCRAPER PASSWORD", scraper_password_screenscraper,
|
||||||
scraper_password_screenscraper, passwordMasked, "", true);
|
passwordMasked, "", true);
|
||||||
s->addSaveFunc([scraper_password_screenscraper, s] {
|
s->addSaveFunc([scraper_password_screenscraper, s] {
|
||||||
if (scraper_password_screenscraper->getHiddenValue() !=
|
if (scraper_password_screenscraper->getHiddenValue() !=
|
||||||
Settings::getInstance()->getString("ScraperPasswordScreenScraper")) {
|
Settings::getInstance()->getString("ScraperPasswordScreenScraper")) {
|
||||||
Settings::getInstance()->setString("ScraperPasswordScreenScraper",
|
Settings::getInstance()->setString("ScraperPasswordScreenScraper",
|
||||||
scraper_password_screenscraper->getHiddenValue());
|
scraper_password_screenscraper->getHiddenValue());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -215,8 +244,9 @@ void GuiScraperMenu::openContentOptions()
|
||||||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||||
scrape_ratings->setEnabled(false);
|
scrape_ratings->setEnabled(false);
|
||||||
scrape_ratings->setOpacity(DISABLED_OPACITY);
|
scrape_ratings->setOpacity(DISABLED_OPACITY);
|
||||||
scrape_ratings->getParent()->getChild(scrape_ratings->
|
scrape_ratings->getParent()
|
||||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
->getChild(scrape_ratings->getChildIndex() - 1)
|
||||||
|
->setOpacity(DISABLED_OPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scrape other metadata.
|
// Scrape other metadata.
|
||||||
|
@ -245,8 +275,9 @@ void GuiScraperMenu::openContentOptions()
|
||||||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||||
scrape_videos->setEnabled(false);
|
scrape_videos->setEnabled(false);
|
||||||
scrape_videos->setOpacity(DISABLED_OPACITY);
|
scrape_videos->setOpacity(DISABLED_OPACITY);
|
||||||
scrape_videos->getParent()->getChild(scrape_videos->
|
scrape_videos->getParent()
|
||||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
->getChild(scrape_videos->getChildIndex() - 1)
|
||||||
|
->setOpacity(DISABLED_OPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scrape screenshots images.
|
// Scrape screenshots images.
|
||||||
|
@ -255,7 +286,7 @@ void GuiScraperMenu::openContentOptions()
|
||||||
s->addWithLabel("SCRAPE SCREENSHOT IMAGES", scrape_screenshots);
|
s->addWithLabel("SCRAPE SCREENSHOT IMAGES", scrape_screenshots);
|
||||||
s->addSaveFunc([scrape_screenshots, s] {
|
s->addSaveFunc([scrape_screenshots, s] {
|
||||||
if (scrape_screenshots->getState() !=
|
if (scrape_screenshots->getState() !=
|
||||||
Settings::getInstance()->getBool("ScrapeScreenshots")) {
|
Settings::getInstance()->getBool("ScrapeScreenshots")) {
|
||||||
Settings::getInstance()->setBool("ScrapeScreenshots", scrape_screenshots->getState());
|
Settings::getInstance()->setBool("ScrapeScreenshots", scrape_screenshots->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
|
@ -299,8 +330,9 @@ void GuiScraperMenu::openContentOptions()
|
||||||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||||
scrape_3dboxes->setEnabled(false);
|
scrape_3dboxes->setEnabled(false);
|
||||||
scrape_3dboxes->setOpacity(DISABLED_OPACITY);
|
scrape_3dboxes->setOpacity(DISABLED_OPACITY);
|
||||||
scrape_3dboxes->getParent()->getChild(scrape_3dboxes->
|
scrape_3dboxes->getParent()
|
||||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
->getChild(scrape_3dboxes->getChildIndex() - 1)
|
||||||
|
->setOpacity(DISABLED_OPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
@ -311,12 +343,12 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
auto s = new GuiSettings(mWindow, "MIXIMAGE SETTINGS");
|
auto s = new GuiSettings(mWindow, "MIXIMAGE SETTINGS");
|
||||||
|
|
||||||
// Miximage resolution.
|
// Miximage resolution.
|
||||||
auto miximage_resolution = std::make_shared<OptionListComponent<std::string>>
|
auto miximage_resolution = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "MIXIMAGE RESOLUTION", false);
|
mWindow, getHelpStyle(), "MIXIMAGE RESOLUTION", false);
|
||||||
std::string selectedResolution = Settings::getInstance()->getString("MiximageResolution");
|
std::string selectedResolution = Settings::getInstance()->getString("MiximageResolution");
|
||||||
miximage_resolution->add("1280x960", "1280x960", selectedResolution == "1280x960");
|
miximage_resolution->add("1280x960", "1280x960", selectedResolution == "1280x960");
|
||||||
miximage_resolution->add("1920x1440", "1920x1440", selectedResolution == "1920x1440");
|
miximage_resolution->add("1920x1440", "1920x1440", selectedResolution == "1920x1440");
|
||||||
miximage_resolution->add("640x480", "640x480", selectedResolution == "640x480");
|
miximage_resolution->add("640x480", "640x480", selectedResolution == "640x480");
|
||||||
// If there are no objects returned, then there must be a manually modified entry in the
|
// If there are no objects returned, then there must be a manually modified entry in the
|
||||||
// configuration file. Simply set the resolution to "1280x960" in this case.
|
// configuration file. Simply set the resolution to "1280x960" in this case.
|
||||||
if (miximage_resolution->getSelectedObjects().size() == 0)
|
if (miximage_resolution->getSelectedObjects().size() == 0)
|
||||||
|
@ -324,19 +356,19 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("MIXIMAGE RESOLUTION", miximage_resolution);
|
s->addWithLabel("MIXIMAGE RESOLUTION", miximage_resolution);
|
||||||
s->addSaveFunc([miximage_resolution, s] {
|
s->addSaveFunc([miximage_resolution, s] {
|
||||||
if (miximage_resolution->getSelected() !=
|
if (miximage_resolution->getSelected() !=
|
||||||
Settings::getInstance()->getString("MiximageResolution")) {
|
Settings::getInstance()->getString("MiximageResolution")) {
|
||||||
Settings::getInstance()->
|
Settings::getInstance()->setString("MiximageResolution",
|
||||||
setString("MiximageResolution", miximage_resolution->getSelected());
|
miximage_resolution->getSelected());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Screenshot scaling method.
|
// Screenshot scaling method.
|
||||||
auto miximage_scaling = std::make_shared<OptionListComponent<std::string>>
|
auto miximage_scaling = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "SCREENSHOT SCALING", false);
|
mWindow, getHelpStyle(), "SCREENSHOT SCALING", false);
|
||||||
std::string selectedScaling = Settings::getInstance()->getString("MiximageScreenshotScaling");
|
std::string selectedScaling = Settings::getInstance()->getString("MiximageScreenshotScaling");
|
||||||
miximage_scaling->add("sharp", "sharp", selectedScaling == "sharp");
|
miximage_scaling->add("sharp", "sharp", selectedScaling == "sharp");
|
||||||
miximage_scaling->add("smooth", "smooth", selectedScaling == "smooth");
|
miximage_scaling->add("smooth", "smooth", selectedScaling == "smooth");
|
||||||
// If there are no objects returned, then there must be a manually modified entry in the
|
// If there are no objects returned, then there must be a manually modified entry in the
|
||||||
// configuration file. Simply set the scaling method to "sharp" in this case.
|
// configuration file. Simply set the scaling method to "sharp" in this case.
|
||||||
if (miximage_scaling->getSelectedObjects().size() == 0)
|
if (miximage_scaling->getSelectedObjects().size() == 0)
|
||||||
|
@ -344,9 +376,9 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("SCREENSHOT SCALING METHOD", miximage_scaling);
|
s->addWithLabel("SCREENSHOT SCALING METHOD", miximage_scaling);
|
||||||
s->addSaveFunc([miximage_scaling, s] {
|
s->addSaveFunc([miximage_scaling, s] {
|
||||||
if (miximage_scaling->getSelected() !=
|
if (miximage_scaling->getSelected() !=
|
||||||
Settings::getInstance()->getString("MiximageScreenshotScaling")) {
|
Settings::getInstance()->getString("MiximageScreenshotScaling")) {
|
||||||
Settings::getInstance()->
|
Settings::getInstance()->setString("MiximageScreenshotScaling",
|
||||||
setString("MiximageScreenshotScaling", miximage_scaling->getSelected());
|
miximage_scaling->getSelected());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -356,8 +388,7 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
miximage_generate->setState(Settings::getInstance()->getBool("MiximageGenerate"));
|
miximage_generate->setState(Settings::getInstance()->getBool("MiximageGenerate"));
|
||||||
s->addWithLabel("GENERATE MIXIMAGES WHEN SCRAPING", miximage_generate);
|
s->addWithLabel("GENERATE MIXIMAGES WHEN SCRAPING", miximage_generate);
|
||||||
s->addSaveFunc([miximage_generate, s] {
|
s->addSaveFunc([miximage_generate, s] {
|
||||||
if (miximage_generate->getState() !=
|
if (miximage_generate->getState() != Settings::getInstance()->getBool("MiximageGenerate")) {
|
||||||
Settings::getInstance()->getBool("MiximageGenerate")) {
|
|
||||||
Settings::getInstance()->setBool("MiximageGenerate", miximage_generate->getState());
|
Settings::getInstance()->setBool("MiximageGenerate", miximage_generate->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
|
@ -369,7 +400,7 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("OVERWRITE MIXIMAGES (SCRAPER/OFFLINE GENERATOR)", miximage_overwrite);
|
s->addWithLabel("OVERWRITE MIXIMAGES (SCRAPER/OFFLINE GENERATOR)", miximage_overwrite);
|
||||||
s->addSaveFunc([miximage_overwrite, s] {
|
s->addSaveFunc([miximage_overwrite, s] {
|
||||||
if (miximage_overwrite->getState() !=
|
if (miximage_overwrite->getState() !=
|
||||||
Settings::getInstance()->getBool("MiximageOverwrite")) {
|
Settings::getInstance()->getBool("MiximageOverwrite")) {
|
||||||
Settings::getInstance()->setBool("MiximageOverwrite", miximage_overwrite->getState());
|
Settings::getInstance()->setBool("MiximageOverwrite", miximage_overwrite->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
|
@ -381,9 +412,9 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("REMOVE LETTERBOXES FROM SCREENSHOTS", remove_letterboxes);
|
s->addWithLabel("REMOVE LETTERBOXES FROM SCREENSHOTS", remove_letterboxes);
|
||||||
s->addSaveFunc([remove_letterboxes, s] {
|
s->addSaveFunc([remove_letterboxes, s] {
|
||||||
if (remove_letterboxes->getState() !=
|
if (remove_letterboxes->getState() !=
|
||||||
Settings::getInstance()->getBool("MiximageRemoveLetterboxes")) {
|
Settings::getInstance()->getBool("MiximageRemoveLetterboxes")) {
|
||||||
Settings::getInstance()->setBool("MiximageRemoveLetterboxes",
|
Settings::getInstance()->setBool("MiximageRemoveLetterboxes",
|
||||||
remove_letterboxes->getState());
|
remove_letterboxes->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -394,9 +425,9 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("REMOVE PILLARBOXES FROM SCREENSHOTS", remove_pillarboxes);
|
s->addWithLabel("REMOVE PILLARBOXES FROM SCREENSHOTS", remove_pillarboxes);
|
||||||
s->addSaveFunc([remove_pillarboxes, s] {
|
s->addSaveFunc([remove_pillarboxes, s] {
|
||||||
if (remove_pillarboxes->getState() !=
|
if (remove_pillarboxes->getState() !=
|
||||||
Settings::getInstance()->getBool("MiximageRemovePillarboxes")) {
|
Settings::getInstance()->getBool("MiximageRemovePillarboxes")) {
|
||||||
Settings::getInstance()->setBool("MiximageRemovePillarboxes",
|
Settings::getInstance()->setBool("MiximageRemovePillarboxes",
|
||||||
remove_pillarboxes->getState());
|
remove_pillarboxes->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -407,9 +438,9 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("INCLUDE MARQUEE IMAGE", miximage_marquee);
|
s->addWithLabel("INCLUDE MARQUEE IMAGE", miximage_marquee);
|
||||||
s->addSaveFunc([miximage_marquee, s] {
|
s->addSaveFunc([miximage_marquee, s] {
|
||||||
if (miximage_marquee->getState() !=
|
if (miximage_marquee->getState() !=
|
||||||
Settings::getInstance()->getBool("MiximageIncludeMarquee")) {
|
Settings::getInstance()->getBool("MiximageIncludeMarquee")) {
|
||||||
Settings::getInstance()->
|
Settings::getInstance()->setBool("MiximageIncludeMarquee",
|
||||||
setBool("MiximageIncludeMarquee", miximage_marquee->getState());
|
miximage_marquee->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -419,10 +450,8 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
miximage_box->setState(Settings::getInstance()->getBool("MiximageIncludeBox"));
|
miximage_box->setState(Settings::getInstance()->getBool("MiximageIncludeBox"));
|
||||||
s->addWithLabel("INCLUDE BOX IMAGE", miximage_box);
|
s->addWithLabel("INCLUDE BOX IMAGE", miximage_box);
|
||||||
s->addSaveFunc([miximage_box, s] {
|
s->addSaveFunc([miximage_box, s] {
|
||||||
if (miximage_box->getState() !=
|
if (miximage_box->getState() != Settings::getInstance()->getBool("MiximageIncludeBox")) {
|
||||||
Settings::getInstance()->getBool("MiximageIncludeBox")) {
|
Settings::getInstance()->setBool("MiximageIncludeBox", miximage_box->getState());
|
||||||
Settings::getInstance()->
|
|
||||||
setBool("MiximageIncludeBox", miximage_box->getState());
|
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -433,9 +462,9 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
s->addWithLabel("USE COVER IMAGE IF 3D BOX IS MISSING", miximage_cover_fallback);
|
s->addWithLabel("USE COVER IMAGE IF 3D BOX IS MISSING", miximage_cover_fallback);
|
||||||
s->addSaveFunc([miximage_cover_fallback, s] {
|
s->addSaveFunc([miximage_cover_fallback, s] {
|
||||||
if (miximage_cover_fallback->getState() !=
|
if (miximage_cover_fallback->getState() !=
|
||||||
Settings::getInstance()->getBool("MiximageCoverFallback")) {
|
Settings::getInstance()->getBool("MiximageCoverFallback")) {
|
||||||
Settings::getInstance()->
|
Settings::getInstance()->setBool("MiximageCoverFallback",
|
||||||
setBool("MiximageCoverFallback", miximage_cover_fallback->getState());
|
miximage_cover_fallback->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -443,11 +472,13 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
// Miximage offline generator.
|
// Miximage offline generator.
|
||||||
ComponentListRow offline_generator_row;
|
ComponentListRow offline_generator_row;
|
||||||
offline_generator_row.elements.clear();
|
offline_generator_row.elements.clear();
|
||||||
offline_generator_row.addElement(std::make_shared<TextComponent>
|
offline_generator_row.addElement(std::make_shared<TextComponent>(mWindow, "OFFLINE GENERATOR",
|
||||||
(mWindow, "OFFLINE GENERATOR", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM),
|
||||||
|
0x777777FF),
|
||||||
|
true);
|
||||||
offline_generator_row.addElement(makeArrow(mWindow), false);
|
offline_generator_row.addElement(makeArrow(mWindow), false);
|
||||||
offline_generator_row.makeAcceptInputHandler(
|
offline_generator_row.makeAcceptInputHandler(
|
||||||
std::bind(&GuiScraperMenu::openOfflineGenerator, this, s));
|
std::bind(&GuiScraperMenu::openOfflineGenerator, this, s));
|
||||||
s->addRow(offline_generator_row);
|
s->addRow(offline_generator_row);
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
@ -457,9 +488,9 @@ void GuiScraperMenu::openOfflineGenerator(GuiSettings* settings)
|
||||||
{
|
{
|
||||||
if (mSystems->getSelectedObjects().empty()) {
|
if (mSystems->getSelectedObjects().empty()) {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
"THE MIXIMAGE GENERATOR USES THE SAME SYSTEM\n"
|
"THE MIXIMAGE GENERATOR USES THE SAME SYSTEM\n"
|
||||||
"SELECTIONS AS THE SCRAPER, SO PLEASE SELECT\n"
|
"SELECTIONS AS THE SCRAPER, SO PLEASE SELECT\n"
|
||||||
"AT LEAST ONE SYSTEM TO GENERATE IMAGES FOR"));
|
"AT LEAST ONE SYSTEM TO GENERATE IMAGES FOR"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,13 +523,15 @@ void GuiScraperMenu::openOtherOptions()
|
||||||
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
||||||
|
|
||||||
// Scraper region.
|
// Scraper region.
|
||||||
auto scraper_region = std::make_shared<OptionListComponent<std::string>>
|
auto scraper_region = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "REGION", false);
|
mWindow, getHelpStyle(), "REGION", false);
|
||||||
std::string selectedScraperRegion = Settings::getInstance()->getString("ScraperRegion");
|
std::string selectedScraperRegion = Settings::getInstance()->getString("ScraperRegion");
|
||||||
|
// clang-format off
|
||||||
scraper_region->add("Europe", "eu", selectedScraperRegion == "eu");
|
scraper_region->add("Europe", "eu", selectedScraperRegion == "eu");
|
||||||
scraper_region->add("Japan", "jp", selectedScraperRegion == "jp");
|
scraper_region->add("Japan", "jp", selectedScraperRegion == "jp");
|
||||||
scraper_region->add("USA", "us", selectedScraperRegion == "us");
|
scraper_region->add("USA", "us", selectedScraperRegion == "us");
|
||||||
scraper_region->add("World", "wor", selectedScraperRegion == "wor");
|
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
|
// 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.
|
// configuration file. Simply set the region to "Europe" in this case.
|
||||||
if (scraper_region->getSelectedObjects().size() == 0)
|
if (scraper_region->getSelectedObjects().size() == 0)
|
||||||
|
@ -515,14 +548,16 @@ void GuiScraperMenu::openOtherOptions()
|
||||||
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
|
||||||
scraper_region->setEnabled(false);
|
scraper_region->setEnabled(false);
|
||||||
scraper_region->setOpacity(DISABLED_OPACITY);
|
scraper_region->setOpacity(DISABLED_OPACITY);
|
||||||
scraper_region->getParent()->getChild(scraper_region->
|
scraper_region->getParent()
|
||||||
getChildIndex() - 1)->setOpacity(DISABLED_OPACITY);
|
->getChild(scraper_region->getChildIndex() - 1)
|
||||||
|
->setOpacity(DISABLED_OPACITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scraper language.
|
// Scraper language.
|
||||||
auto scraper_language = std::make_shared<OptionListComponent<std::string>>
|
auto scraper_language = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "PREFERRED LANGUAGE", false);
|
mWindow, getHelpStyle(), "PREFERRED LANGUAGE", false);
|
||||||
std::string selectedScraperLanguage = Settings::getInstance()->getString("ScraperLanguage");
|
std::string selectedScraperLanguage = Settings::getInstance()->getString("ScraperLanguage");
|
||||||
|
// clang-format off
|
||||||
scraper_language->add("English", "en", selectedScraperLanguage == "en");
|
scraper_language->add("English", "en", selectedScraperLanguage == "en");
|
||||||
scraper_language->add("Español", "es", selectedScraperLanguage == "es");
|
scraper_language->add("Español", "es", selectedScraperLanguage == "es");
|
||||||
scraper_language->add("Português", "pt", selectedScraperLanguage == "pt");
|
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("Čeština", "cz", selectedScraperLanguage == "cz");
|
||||||
scraper_language->add("Slovenčina", "sk", selectedScraperLanguage == "sk");
|
scraper_language->add("Slovenčina", "sk", selectedScraperLanguage == "sk");
|
||||||
scraper_language->add("Türkçe", "tr", selectedScraperLanguage == "tr");
|
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
|
// 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.
|
// configuration file. Simply set the language to "English" in this case.
|
||||||
if (scraper_language->getSelectedObjects().size() == 0)
|
if (scraper_language->getSelectedObjects().size() == 0)
|
||||||
|
|
|
@ -16,11 +16,10 @@
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
|
|
||||||
class FileData;
|
class FileData;
|
||||||
template<typename T>
|
|
||||||
class OptionListComponent;
|
|
||||||
class SwitchComponent;
|
class SwitchComponent;
|
||||||
class SystemData;
|
class SystemData;
|
||||||
|
|
||||||
|
template <typename T> class OptionListComponent;
|
||||||
typedef std::function<bool(SystemData*, FileData*)> GameFilterFunc;
|
typedef std::function<bool(SystemData*, FileData*)> GameFilterFunc;
|
||||||
|
|
||||||
class GuiScraperMenu : public GuiComponent
|
class GuiScraperMenu : public GuiComponent
|
||||||
|
@ -38,16 +37,18 @@ private:
|
||||||
void pressedStart();
|
void pressedStart();
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
void addEntry(const std::string&, unsigned int color,
|
void addEntry(const std::string&,
|
||||||
bool add_arrow, const std::function<void()>& func);
|
unsigned int color,
|
||||||
|
bool add_arrow,
|
||||||
|
const std::function<void()>& func);
|
||||||
void openAccountOptions();
|
void openAccountOptions();
|
||||||
void openContentOptions();
|
void openContentOptions();
|
||||||
void openMiximageOptions();
|
void openMiximageOptions();
|
||||||
void openOfflineGenerator(GuiSettings* settings);
|
void openOfflineGenerator(GuiSettings* settings);
|
||||||
void openOtherOptions();
|
void openOtherOptions();
|
||||||
|
|
||||||
std::queue<ScraperSearchParams> getSearches(
|
std::queue<ScraperSearchParams> getSearches(std::vector<SystemData*> systems,
|
||||||
std::vector<SystemData*> systems, GameFilterFunc selector);
|
GameFilterFunc selector);
|
||||||
|
|
||||||
std::shared_ptr<OptionListComponent<std::string>> mScraper;
|
std::shared_ptr<OptionListComponent<std::string>> mScraper;
|
||||||
std::shared_ptr<OptionListComponent<GameFilterFunc>> mFilters;
|
std::shared_ptr<OptionListComponent<GameFilterFunc>> mFilters;
|
||||||
|
|
|
@ -11,27 +11,26 @@
|
||||||
|
|
||||||
#include "guis/GuiScraperMulti.h"
|
#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/ButtonComponent.h"
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "guis/GuiScraperSearch.h"
|
#include "guis/GuiScraperSearch.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "CollectionSystemsManager.h"
|
|
||||||
#include "Gamelist.h"
|
|
||||||
#include "MameNames.h"
|
|
||||||
#include "SystemData.h"
|
|
||||||
#include "Window.h"
|
|
||||||
|
|
||||||
GuiScraperMulti::GuiScraperMulti(
|
GuiScraperMulti::GuiScraperMulti(Window* window,
|
||||||
Window* window,
|
const std::queue<ScraperSearchParams>& searches,
|
||||||
const std::queue<ScraperSearchParams>& searches,
|
bool approveResults)
|
||||||
bool approveResults)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mBackground(window, ":/graphics/frame.svg")
|
||||||
mBackground(window, ":/graphics/frame.svg"),
|
, mGrid(window, Vector2i(1, 5))
|
||||||
mGrid(window, Vector2i(1, 5)),
|
, mSearchQueue(searches)
|
||||||
mSearchQueue(searches),
|
, mApproveResults(approveResults)
|
||||||
mApproveResults(approveResults)
|
|
||||||
{
|
{
|
||||||
assert(mSearchQueue.size());
|
assert(mSearchQueue.size());
|
||||||
|
|
||||||
|
@ -47,41 +46,42 @@ GuiScraperMulti::GuiScraperMulti(
|
||||||
|
|
||||||
// Set up grid.
|
// Set up grid.
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, "SCRAPING IN PROGRESS",
|
mTitle = std::make_shared<TextComponent>(mWindow, "SCRAPING IN PROGRESS",
|
||||||
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
|
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
|
||||||
|
|
||||||
mSystem = std::make_shared<TextComponent>(mWindow, "SYSTEM",
|
mSystem = std::make_shared<TextComponent>(mWindow, "SYSTEM", Font::get(FONT_SIZE_MEDIUM),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
0x777777FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mSystem, Vector2i(0, 1), false, true);
|
mGrid.setEntry(mSystem, Vector2i(0, 1), false, true);
|
||||||
|
|
||||||
mSubtitle = std::make_shared<TextComponent>(mWindow, "subtitle text",
|
mSubtitle = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
mWindow, "subtitle text", Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||||
mGrid.setEntry(mSubtitle, Vector2i(0, 2), false, true);
|
mGrid.setEntry(mSubtitle, Vector2i(0, 2), false, true);
|
||||||
|
|
||||||
if (mApproveResults && !Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
if (mApproveResults && !Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
||||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||||
GuiScraperSearch::NEVER_AUTO_ACCEPT, mTotalGames);
|
mWindow, GuiScraperSearch::NEVER_AUTO_ACCEPT, mTotalGames);
|
||||||
else if (mApproveResults && Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
else if (mApproveResults && Settings::getInstance()->getBool("ScraperSemiautomatic"))
|
||||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||||
GuiScraperSearch::ACCEPT_SINGLE_MATCHES, mTotalGames);
|
mWindow, GuiScraperSearch::ACCEPT_SINGLE_MATCHES, mTotalGames);
|
||||||
else if (!mApproveResults)
|
else if (!mApproveResults)
|
||||||
mSearchComp = std::make_shared<GuiScraperSearch>(mWindow,
|
mSearchComp = std::make_shared<GuiScraperSearch>(
|
||||||
GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, mTotalGames);
|
mWindow, GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, mTotalGames);
|
||||||
mSearchComp->setAcceptCallback(std::bind(&GuiScraperMulti::acceptResult,
|
mSearchComp->setAcceptCallback(
|
||||||
this, std::placeholders::_1));
|
std::bind(&GuiScraperMulti::acceptResult, this, std::placeholders::_1));
|
||||||
mSearchComp->setSkipCallback(std::bind(&GuiScraperMulti::skip, this));
|
mSearchComp->setSkipCallback(std::bind(&GuiScraperMulti::skip, this));
|
||||||
mSearchComp->setCancelCallback(std::bind(&GuiScraperMulti::finish, this));
|
mSearchComp->setCancelCallback(std::bind(&GuiScraperMulti::finish, this));
|
||||||
mGrid.setEntry(mSearchComp, Vector2i(0, 3), mSearchComp->getSearchType() !=
|
mGrid.setEntry(mSearchComp, Vector2i(0, 3),
|
||||||
GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT, true);
|
mSearchComp->getSearchType() != GuiScraperSearch::ALWAYS_ACCEPT_FIRST_RESULT,
|
||||||
|
true);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
if (mApproveResults) {
|
if (mApproveResults) {
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH",
|
buttons.push_back(
|
||||||
"refine search", [&] {
|
std::make_shared<ButtonComponent>(mWindow, "REFINE SEARCH", "refine search", [&] {
|
||||||
mSearchComp->openInputScreen(mSearchQueue.front());
|
mSearchComp->openInputScreen(mSearchQueue.front());
|
||||||
mGrid.resetCursor();
|
mGrid.resetCursor();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SKIP", "skip game", [&] {
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SKIP", "skip game", [&] {
|
||||||
skip();
|
skip();
|
||||||
|
@ -89,8 +89,8 @@ GuiScraperMulti::GuiScraperMulti(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "STOP",
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "STOP", "stop",
|
||||||
"stop", std::bind(&GuiScraperMulti::finish, this)));
|
std::bind(&GuiScraperMulti::finish, this)));
|
||||||
|
|
||||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false);
|
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();
|
float width = Math::clamp(0.95f * aspectValue, 0.70f, 0.95f) * Renderer::getScreenWidth();
|
||||||
|
|
||||||
setSize(width, Renderer::getScreenHeight() * 0.849f);
|
setSize(width, Renderer::getScreenHeight() * 0.849f);
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() -
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
mSize.y()) / 2);
|
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||||
|
|
||||||
doNextSearch();
|
doNextSearch();
|
||||||
}
|
}
|
||||||
|
@ -111,8 +111,8 @@ GuiScraperMulti::~GuiScraperMulti()
|
||||||
{
|
{
|
||||||
if (mTotalSuccessful > 0) {
|
if (mTotalSuccessful > 0) {
|
||||||
// Sort all systems to possibly update their view style from Basic to Detailed or Video.
|
// Sort all systems to possibly update their view style from Basic to Detailed or Video.
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it !=SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
(*it)->sortSystem();
|
(*it)->sortSystem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,10 +121,10 @@ GuiScraperMulti::~GuiScraperMulti()
|
||||||
|
|
||||||
void GuiScraperMulti::onSizeChanged()
|
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(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(2, mSubtitle->getFont()->getHeight() * 1.75f / mSize.y(), false);
|
||||||
mGrid.setRowHeightPerc(4, mButtonGrid->getSize().y() / mSize.y(), false);
|
mGrid.setRowHeightPerc(4, mButtonGrid->getSize().y() / mSize.y(), false);
|
||||||
mGrid.setSize(mSize);
|
mGrid.setSize(mSize);
|
||||||
|
@ -148,34 +148,36 @@ void GuiScraperMulti::doNextSearch()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (mSearchQueue.front().game->isArcadeGame() &&
|
if (mSearchQueue.front().game->isArcadeGame() &&
|
||||||
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
||||||
scrapeName = Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath()) +
|
scrapeName =
|
||||||
" (" + MameNames::getInstance()->getCleanName(mSearchQueue.front().game->
|
Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath()) + " (" +
|
||||||
getCleanName()) + ")";
|
MameNames::getInstance()->getCleanName(mSearchQueue.front().game->getCleanName()) +
|
||||||
|
")";
|
||||||
else
|
else
|
||||||
scrapeName = Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath());
|
scrapeName = Utils::FileSystem::getFileName(mSearchQueue.front().game->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
std::string folderPath = Utils::String::replace(
|
std::string folderPath =
|
||||||
Utils::FileSystem::getParent(mSearchQueue.front().game->getPath()),
|
Utils::String::replace(Utils::FileSystem::getParent(mSearchQueue.front().game->getPath()),
|
||||||
mSearchQueue.front().system->getSystemEnvData()->mStartPath, "");
|
mSearchQueue.front().system->getSystemEnvData()->mStartPath, "");
|
||||||
|
|
||||||
if (folderPath.size() >= 2) {
|
if (folderPath.size() >= 2) {
|
||||||
folderPath.erase(0, 1);
|
folderPath.erase(0, 1);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
folderPath.push_back('\\');
|
folderPath.push_back('\\');
|
||||||
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
folderPath = Utils::String::replace(folderPath, "/", "\\");
|
||||||
#else
|
#else
|
||||||
folderPath.push_back('/');
|
folderPath.push_back('/');
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update subtitle.
|
// Update subtitle.
|
||||||
ss.str("");
|
ss.str("");
|
||||||
ss << "GAME " << (mCurrentGame + 1) << " OF " << mTotalGames << " - " << folderPath <<
|
ss << "GAME " << (mCurrentGame + 1) << " OF " << mTotalGames << " - " << folderPath
|
||||||
scrapeName << ((mSearchQueue.front().game->getType() == FOLDER) ? " " +
|
<< scrapeName
|
||||||
ViewController::FOLDER_CHAR : "");
|
<< ((mSearchQueue.front().game->getType() == FOLDER) ? " " + ViewController::FOLDER_CHAR :
|
||||||
|
"");
|
||||||
mSubtitle->setText(ss.str());
|
mSubtitle->setText(ss.str());
|
||||||
|
|
||||||
mSearchComp->search(mSearchQueue.front());
|
mSearchComp->search(mSearchQueue.front());
|
||||||
|
@ -212,12 +214,12 @@ void GuiScraperMulti::finish()
|
||||||
ss << "NO GAMES WERE SCRAPED";
|
ss << "NO GAMES WERE SCRAPED";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ss << mTotalSuccessful << " GAME" <<
|
ss << mTotalSuccessful << " GAME" << ((mTotalSuccessful > 1) ? "S" : "")
|
||||||
((mTotalSuccessful > 1) ? "S" : "") << " SUCCESSFULLY SCRAPED";
|
<< " SUCCESSFULLY SCRAPED";
|
||||||
|
|
||||||
if (mTotalSkipped > 0)
|
if (mTotalSkipped > 0)
|
||||||
ss << "\n" << mTotalSkipped << " GAME"
|
ss << "\n"
|
||||||
<< ((mTotalSkipped > 1) ? "S" : "") << " SKIPPED";
|
<< mTotalSkipped << " GAME" << ((mTotalSkipped > 1) ? "S" : "") << " SKIPPED";
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), ss.str(), "OK", [&] {
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), ss.str(), "OK", [&] {
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
#ifndef ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
||||||
#define 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/ComponentGrid.h"
|
||||||
#include "components/NinePatchComponent.h"
|
#include "components/NinePatchComponent.h"
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "MetaData.h"
|
|
||||||
|
|
||||||
class GuiScraperSearch;
|
class GuiScraperSearch;
|
||||||
class TextComponent;
|
class TextComponent;
|
||||||
|
@ -24,10 +24,9 @@ class TextComponent;
|
||||||
class GuiScraperMulti : public GuiComponent
|
class GuiScraperMulti : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GuiScraperMulti(
|
GuiScraperMulti(Window* window,
|
||||||
Window* window,
|
const std::queue<ScraperSearchParams>& searches,
|
||||||
const std::queue<ScraperSearchParams>& searches,
|
bool approveResults);
|
||||||
bool approveResults);
|
|
||||||
|
|
||||||
virtual ~GuiScraperMulti();
|
virtual ~GuiScraperMulti();
|
||||||
|
|
||||||
|
@ -40,15 +39,7 @@ private:
|
||||||
void acceptResult(const ScraperSearchResult& result);
|
void acceptResult(const ScraperSearchResult& result);
|
||||||
void skip();
|
void skip();
|
||||||
void doNextSearch();
|
void doNextSearch();
|
||||||
|
|
||||||
void finish();
|
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;
|
NinePatchComponent mBackground;
|
||||||
ComponentGrid mGrid;
|
ComponentGrid mGrid;
|
||||||
|
@ -58,6 +49,14 @@ private:
|
||||||
std::shared_ptr<TextComponent> mSubtitle;
|
std::shared_ptr<TextComponent> mSubtitle;
|
||||||
std::shared_ptr<GuiScraperSearch> mSearchComp;
|
std::shared_ptr<GuiScraperSearch> mSearchComp;
|
||||||
std::shared_ptr<ComponentGrid> mButtonGrid;
|
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
|
#endif // ES_APP_GUIS_GUI_SCRAPER_MULTI_H
|
||||||
|
|
|
@ -15,6 +15,13 @@
|
||||||
|
|
||||||
#include "guis/GuiScraperSearch.h"
|
#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/ComponentList.h"
|
||||||
#include "components/DateTimeEditComponent.h"
|
#include "components/DateTimeEditComponent.h"
|
||||||
#include "components/ImageComponent.h"
|
#include "components/ImageComponent.h"
|
||||||
|
@ -26,28 +33,18 @@
|
||||||
#include "resources/Font.h"
|
#include "resources/Font.h"
|
||||||
#include "utils/StringUtil.h"
|
#include "utils/StringUtil.h"
|
||||||
#include "views/ViewController.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
|
#define FAILED_VERIFICATION_RETRIES 8
|
||||||
|
|
||||||
GuiScraperSearch::GuiScraperSearch(
|
GuiScraperSearch::GuiScraperSearch(Window* window, SearchType type, unsigned int scrapeCount)
|
||||||
Window* window,
|
: GuiComponent(window)
|
||||||
SearchType type,
|
, mGrid(window, Vector2i(4, 3))
|
||||||
unsigned int scrapeCount)
|
, mBusyAnim(window)
|
||||||
: GuiComponent(window),
|
, mSearchType(type)
|
||||||
mGrid(window, Vector2i(4, 3)),
|
, mScrapeCount(scrapeCount)
|
||||||
mBusyAnim(window),
|
, mScrapeRatings(false)
|
||||||
mSearchType(type),
|
, mRefinedSearch(false)
|
||||||
mScrapeCount(scrapeCount),
|
, mFoundGame(false)
|
||||||
mScrapeRatings(false),
|
|
||||||
mRefinedSearch(false),
|
|
||||||
mFoundGame(false)
|
|
||||||
{
|
{
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
|
||||||
|
@ -56,12 +53,12 @@ GuiScraperSearch::GuiScraperSearch(
|
||||||
mRetryCount = 0;
|
mRetryCount = 0;
|
||||||
|
|
||||||
// Left spacer (empty component, needed for borders).
|
// Left spacer (empty component, needed for borders).
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 0), false, false,
|
||||||
false, false, Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
Vector2i(1, 3), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
// Selected result name.
|
// Selected result name.
|
||||||
mResultName = std::make_shared<TextComponent>(mWindow, "Result name",
|
mResultName = std::make_shared<TextComponent>(mWindow, "Result name",
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
|
|
||||||
// Selected result thumbnail.
|
// Selected result thumbnail.
|
||||||
mResultThumbnail = std::make_shared<ImageComponent>(mWindow);
|
mResultThumbnail = std::make_shared<ImageComponent>(mWindow);
|
||||||
|
@ -77,7 +74,7 @@ GuiScraperSearch::GuiScraperSearch(
|
||||||
mDescContainer->setScrollParameters(6000, 3000, 85);
|
mDescContainer->setScrollParameters(6000, 3000, 85);
|
||||||
|
|
||||||
mResultDesc = std::make_shared<TextComponent>(mWindow, "Result desc",
|
mResultDesc = std::make_shared<TextComponent>(mWindow, "Result desc",
|
||||||
Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||||
mDescContainer->addChild(mResultDesc.get());
|
mDescContainer->addChild(mResultDesc.get());
|
||||||
mDescContainer->setAutoScroll(true);
|
mDescContainer->setAutoScroll(true);
|
||||||
|
|
||||||
|
@ -89,40 +86,47 @@ GuiScraperSearch::GuiScraperSearch(
|
||||||
mMD_ReleaseDate = std::make_shared<DateTimeEditComponent>(mWindow);
|
mMD_ReleaseDate = std::make_shared<DateTimeEditComponent>(mWindow);
|
||||||
mMD_ReleaseDate->setColor(mdColor);
|
mMD_ReleaseDate->setColor(mdColor);
|
||||||
mMD_ReleaseDate->setUppercase(true);
|
mMD_ReleaseDate->setUppercase(true);
|
||||||
mMD_Developer = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
mMD_Developer =
|
||||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||||
mMD_Publisher = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
mMD_Publisher =
|
||||||
mMD_Genre = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT, Vector3f::Zero(),
|
||||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
Vector2f::Zero(), 0x00000000, 0.02f);
|
||||||
mMD_Players = std::make_shared<TextComponent>(mWindow, "", font, mdColor, ALIGN_LEFT,
|
mMD_Genre =
|
||||||
Vector3f::Zero(), Vector2f::Zero(), 0x00000000, 0.02f);
|
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);
|
mMD_Filler = std::make_shared<TextComponent>(mWindow, "", font, mdColor);
|
||||||
|
|
||||||
if (Settings::getInstance()->getString("Scraper") != "thegamesdb")
|
if (Settings::getInstance()->getString("Scraper") != "thegamesdb")
|
||||||
mScrapeRatings = true;
|
mScrapeRatings = true;
|
||||||
|
|
||||||
if (mScrapeRatings)
|
if (mScrapeRatings)
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(
|
||||||
(mWindow, "RATING:", font, mdLblColor), mMD_Rating, false));
|
MetaDataPair(std::make_shared<TextComponent>(mWindow, "RATING:", font, mdLblColor),
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Rating, false));
|
||||||
(mWindow, "RELEASED:", font, mdLblColor), mMD_ReleaseDate));
|
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(MetaDataPair(
|
||||||
(mWindow, "DEVELOPER:", font, mdLblColor), mMD_Developer));
|
std::make_shared<TextComponent>(mWindow, "RELEASED:", font, mdLblColor), mMD_ReleaseDate));
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(MetaDataPair(
|
||||||
(mWindow, "PUBLISHER:", font, mdLblColor), mMD_Publisher));
|
std::make_shared<TextComponent>(mWindow, "DEVELOPER:", font, mdLblColor), mMD_Developer));
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(MetaDataPair(
|
||||||
(mWindow, "GENRE:", font, mdLblColor), mMD_Genre));
|
std::make_shared<TextComponent>(mWindow, "PUBLISHER:", font, mdLblColor), mMD_Publisher));
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(MetaDataPair(
|
||||||
(mWindow, "PLAYERS:", font, mdLblColor), mMD_Players));
|
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
|
// If no rating is being scraped, add a filler to make sure that the fonts keep the same
|
||||||
// size so the GUI looks consistent.
|
// size so the GUI looks consistent.
|
||||||
if (!mScrapeRatings)
|
if (!mScrapeRatings)
|
||||||
mMD_Pairs.push_back(MetaDataPair(std::make_shared<TextComponent>
|
mMD_Pairs.push_back(MetaDataPair(
|
||||||
(mWindow, "", font, mdLblColor), mMD_Filler));
|
std::make_shared<TextComponent>(mWindow, "", font, mdLblColor), mMD_Filler));
|
||||||
|
|
||||||
mMD_Grid = std::make_shared<ComponentGrid>(mWindow,
|
mMD_Grid = std::make_shared<ComponentGrid>(
|
||||||
Vector2i(2, static_cast<int>(mMD_Pairs.size()*2 - 1)));
|
mWindow, Vector2i(2, static_cast<int>(mMD_Pairs.size() * 2 - 1)));
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
for (auto it = mMD_Pairs.cbegin(); it != mMD_Pairs.cend(); it++) {
|
for (auto it = mMD_Pairs.cbegin(); it != mMD_Pairs.cend(); it++) {
|
||||||
mMD_Grid->setEntry(it->first, Vector2i(0, i), false, true);
|
mMD_Grid->setEntry(it->first, Vector2i(0, i), false, true);
|
||||||
|
@ -135,7 +139,9 @@ GuiScraperSearch::GuiScraperSearch(
|
||||||
// Result list.
|
// Result list.
|
||||||
mResultList = std::make_shared<ComponentList>(mWindow);
|
mResultList = std::make_shared<ComponentList>(mWindow);
|
||||||
mResultList->setCursorChangedCallback([this](CursorState state) {
|
mResultList->setCursorChangedCallback([this](CursorState state) {
|
||||||
if (state == CURSOR_STOPPED) updateInfoPane(); });
|
if (state == CURSOR_STOPPED)
|
||||||
|
updateInfoPane();
|
||||||
|
});
|
||||||
|
|
||||||
updateViewStyle();
|
updateViewStyle();
|
||||||
}
|
}
|
||||||
|
@ -163,7 +169,7 @@ GuiScraperSearch::~GuiScraperSearch()
|
||||||
// This is required to properly refresh the gamelist view if the user aborted the
|
// This is required to properly refresh the gamelist view if the user aborted the
|
||||||
// scraping when the miximage was getting generated.
|
// scraping when the miximage was getting generated.
|
||||||
if (Settings::getInstance()->getBool("MiximageGenerate") &&
|
if (Settings::getInstance()->getBool("MiximageGenerate") &&
|
||||||
mMiximageGeneratorThread.joinable()) {
|
mMiximageGeneratorThread.joinable()) {
|
||||||
mScrapeResult.savedNewMedia = true;
|
mScrapeResult.savedNewMedia = true;
|
||||||
// We always let the miximage generator thread complete.
|
// We always let the miximage generator thread complete.
|
||||||
mMiximageGeneratorThread.join();
|
mMiximageGeneratorThread.join();
|
||||||
|
@ -196,7 +202,7 @@ void GuiScraperSearch::onSizeChanged()
|
||||||
// Row heights.
|
// Row heights.
|
||||||
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) // Show name.
|
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) // Show name.
|
||||||
mGrid.setRowHeightPerc(0, (mResultName->getFont()->getHeight() * 1.6f) /
|
mGrid.setRowHeightPerc(0, (mResultName->getFont()->getHeight() * 1.6f) /
|
||||||
mGrid.getSize().y()); // Result name.
|
mGrid.getSize().y()); // Result name.
|
||||||
else
|
else
|
||||||
mGrid.setRowHeightPerc(0, 0.0825f); // Hide name but do padding.
|
mGrid.setRowHeightPerc(0, 0.0825f); // Hide name but do padding.
|
||||||
|
|
||||||
|
@ -216,11 +222,11 @@ void GuiScraperSearch::onSizeChanged()
|
||||||
resizeMetadata();
|
resizeMetadata();
|
||||||
|
|
||||||
if (mSearchType != ALWAYS_ACCEPT_FIRST_RESULT)
|
if (mSearchType != ALWAYS_ACCEPT_FIRST_RESULT)
|
||||||
mDescContainer->setSize(mGrid.getColWidth(1) * boxartCellScale +
|
mDescContainer->setSize(mGrid.getColWidth(1) * boxartCellScale + mGrid.getColWidth(2),
|
||||||
mGrid.getColWidth(2), mResultDesc->getFont()->getHeight() * 3);
|
mResultDesc->getFont()->getHeight() * 3.0f);
|
||||||
else
|
else
|
||||||
mDescContainer->setSize(mGrid.getColWidth(3) * boxartCellScale,
|
mDescContainer->setSize(mGrid.getColWidth(3) * boxartCellScale,
|
||||||
mResultDesc->getFont()->getHeight() * 6);
|
mResultDesc->getFont()->getHeight() * 6.0f);
|
||||||
|
|
||||||
// Make description text wrap at edge of container.
|
// Make description text wrap at edge of container.
|
||||||
mResultDesc->setSize(mDescContainer->getSize().x(), 0);
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0);
|
||||||
|
@ -247,13 +253,14 @@ void GuiScraperSearch::resizeMetadata()
|
||||||
it->first->setFont(fontLbl);
|
it->first->setFont(fontLbl);
|
||||||
it->first->setSize(0, 0);
|
it->first->setSize(0, 0);
|
||||||
if (it->first->getSize().x() > maxLblWidth)
|
if (it->first->getSize().x() > maxLblWidth)
|
||||||
maxLblWidth = it->first->getSize().x() +
|
maxLblWidth =
|
||||||
(16.0f * Renderer::getScreenWidthModifier());
|
it->first->getSize().x() + (16.0f * Renderer::getScreenWidthModifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < mMD_Pairs.size(); i++)
|
for (unsigned int i = 0; i < mMD_Pairs.size(); i++)
|
||||||
mMD_Grid->setRowHeightPerc(i * 2, (fontLbl->getLetterHeight() +
|
mMD_Grid->setRowHeightPerc(
|
||||||
(2.0f * Renderer::getScreenHeightModifier())) / mMD_Grid->getSize().y());
|
i * 2, (fontLbl->getLetterHeight() + (2.0f * Renderer::getScreenHeightModifier())) /
|
||||||
|
mMD_Grid->getSize().y());
|
||||||
|
|
||||||
// Update component fonts.
|
// Update component fonts.
|
||||||
mMD_ReleaseDate->setFont(fontComp);
|
mMD_ReleaseDate->setFont(fontComp);
|
||||||
|
@ -286,30 +293,30 @@ void GuiScraperSearch::updateViewStyle()
|
||||||
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) {
|
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) {
|
||||||
// Show name.
|
// Show name.
|
||||||
mGrid.setEntry(mResultName, Vector2i(1, 0), false, false, Vector2i(2, 1),
|
mGrid.setEntry(mResultName, Vector2i(1, 0), false, false, Vector2i(2, 1),
|
||||||
GridFlags::BORDER_TOP);
|
GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
// Need a border on the bottom left.
|
// Need a border on the bottom left.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 2),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 2), false, false,
|
||||||
false, false, Vector2i(3, 1), GridFlags::BORDER_BOTTOM);
|
Vector2i(3, 1), GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
// Show description on the right.
|
// Show description on the right.
|
||||||
mGrid.setEntry(mDescContainer, Vector2i(3, 0), false, false, Vector2i(1, 3),
|
mGrid.setEntry(mDescContainer, Vector2i(3, 0), false, false, Vector2i(1, 3),
|
||||||
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
// Make description text wrap at edge of container.
|
// Make description text wrap at edge of container.
|
||||||
mResultDesc->setSize(mDescContainer->getSize().x(), 0.0f);
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Fake row where name would be.
|
// Fake row where name would be.
|
||||||
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0),
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 0), false, true,
|
||||||
false, true, Vector2i(2, 1), GridFlags::BORDER_TOP);
|
Vector2i(2, 1), GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
// Show result list on the right.
|
// Show result list on the right.
|
||||||
mGrid.setEntry(mResultList, Vector2i(3, 0), true, true, Vector2i(1, 3),
|
mGrid.setEntry(mResultList, Vector2i(3, 0), true, true, Vector2i(1, 3),
|
||||||
GridFlags::BORDER_LEFT | GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
GridFlags::BORDER_LEFT | GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
// Show description under image/info.
|
// Show description under image/info.
|
||||||
mGrid.setEntry(mDescContainer, Vector2i(1, 2), false, false, Vector2i(2, 1),
|
mGrid.setEntry(mDescContainer, Vector2i(1, 2), false, false, Vector2i(2, 1),
|
||||||
GridFlags::BORDER_BOTTOM);
|
GridFlags::BORDER_BOTTOM);
|
||||||
// Make description text wrap at edge of container.
|
// Make description text wrap at edge of container.
|
||||||
mResultDesc->setSize(mDescContainer->getSize().x(), 0);
|
mResultDesc->setSize(mDescContainer->getSize().x(), 0);
|
||||||
}
|
}
|
||||||
|
@ -355,16 +362,17 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
||||||
if (results.empty()) {
|
if (results.empty()) {
|
||||||
// Check if the scraper used is still valid.
|
// Check if the scraper used is still valid.
|
||||||
if (!isValidConfiguredScraper()) {
|
if (!isValidConfiguredScraper()) {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
Utils::String::toUpper("Configured scraper is no longer available.\n"
|
mWindow, getHelpStyle(),
|
||||||
"Please change the scraping source in the settings."),
|
Utils::String::toUpper("Configured scraper is no longer available.\n"
|
||||||
|
"Please change the scraping source in the settings."),
|
||||||
"FINISH", mSkipCallback));
|
"FINISH", mSkipCallback));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mFoundGame = false;
|
mFoundGame = false;
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "NO GAMES FOUND",
|
row.addElement(std::make_shared<TextComponent>(mWindow, "NO GAMES FOUND", font, color),
|
||||||
font, color), true);
|
true);
|
||||||
|
|
||||||
if (mSkipCallback)
|
if (mSkipCallback)
|
||||||
row.makeAcceptInputHandler(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++) {
|
for (size_t i = 0; i < results.size(); i++) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
row.addElement(
|
||||||
Utils::String::toUpper(results.at(i).mdl.get("name")), font, color), true);
|
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)); });
|
row.makeAcceptInputHandler([this, i] { returnResult(mScraperResults.at(i)); });
|
||||||
mResultList->addRow(row);
|
mResultList->addRow(row);
|
||||||
}
|
}
|
||||||
|
@ -393,14 +403,14 @@ void GuiScraperSearch::onSearchDone(const std::vector<ScraperSearchResult>& resu
|
||||||
// If there is no thumbnail to download and we're in semi-automatic mode, proceed to return
|
// If there is no thumbnail to download and we're in semi-automatic mode, proceed to return
|
||||||
// the results or we'll get stuck forever waiting for a thumbnail to be downloaded.
|
// the results or we'll get stuck forever waiting for a thumbnail to be downloaded.
|
||||||
if (mSearchType == ACCEPT_SINGLE_MATCHES && results.size() == 1 &&
|
if (mSearchType == ACCEPT_SINGLE_MATCHES && results.size() == 1 &&
|
||||||
mScraperResults.front().thumbnailImageUrl == "")
|
mScraperResults.front().thumbnailImageUrl == "")
|
||||||
returnResult(mScraperResults.front());
|
returnResult(mScraperResults.front());
|
||||||
|
|
||||||
// For automatic mode, if there's no thumbnail to download or no matching games found,
|
// For automatic mode, if there's no thumbnail to download or no matching games found,
|
||||||
// proceed directly or we'll get stuck forever.
|
// proceed directly or we'll get stuck forever.
|
||||||
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) {
|
if (mSearchType == ALWAYS_ACCEPT_FIRST_RESULT) {
|
||||||
if (mScraperResults.size() == 0 || (mScraperResults.size() > 0 &&
|
if (mScraperResults.size() == 0 ||
|
||||||
mScraperResults.front().thumbnailImageUrl == "")) {
|
(mScraperResults.size() > 0 && mScraperResults.front().thumbnailImageUrl == "")) {
|
||||||
if (mScraperResults.size() == 0)
|
if (mScraperResults.size() == 0)
|
||||||
mSkipCallback();
|
mSkipCallback();
|
||||||
else
|
else
|
||||||
|
@ -420,12 +430,12 @@ void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status s
|
||||||
// the error dialog will be presented to the user, and if the "Retry" button is pressed,
|
// the error dialog will be presented to the user, and if the "Retry" button is pressed,
|
||||||
// a new round of retries will take place.
|
// a new round of retries will take place.
|
||||||
if (status == HttpReq::REQ_FAILED_VERIFICATION && mRetryCount < FAILED_VERIFICATION_RETRIES &&
|
if (status == HttpReq::REQ_FAILED_VERIFICATION && mRetryCount < FAILED_VERIFICATION_RETRIES &&
|
||||||
Settings::getInstance()->getBool("ScraperRetryPeerVerification")) {
|
Settings::getInstance()->getBool("ScraperRetryPeerVerification")) {
|
||||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||||
mRetrySearch = true;
|
mRetrySearch = true;
|
||||||
mRetryCount++;
|
mRetryCount++;
|
||||||
LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount <<
|
LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount << " of "
|
||||||
" of " << FAILED_VERIFICATION_RETRIES;
|
<< FAILED_VERIFICATION_RETRIES;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -435,15 +445,16 @@ void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status s
|
||||||
if (mScrapeCount > 1) {
|
if (mScrapeCount > 1) {
|
||||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
||||||
"RETRY", std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
"RETRY",
|
||||||
"SKIP", mSkipCallback,
|
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||||
"CANCEL", mCancelCallback, true));
|
"SKIP", mSkipCallback, "CANCEL", mCancelCallback, true));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), Utils::String::toUpper(error),
|
||||||
"RETRY", std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
"RETRY",
|
||||||
"CANCEL", mCancelCallback, "", nullptr, true));
|
std::bind(&GuiScraperSearch::search, this, mLastSearch),
|
||||||
|
"CANCEL", mCancelCallback, "", nullptr, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,9 +500,9 @@ void GuiScraperSearch::updateInfoPane()
|
||||||
// Add an entry into the thumbnail map, this way we can track and download
|
// Add an entry into the thumbnail map, this way we can track and download
|
||||||
// each thumbnail separately even as they're downloading while scrolling
|
// each thumbnail separately even as they're downloading while scrolling
|
||||||
// through the result list.
|
// through the result list.
|
||||||
mThumbnailReqMap.insert(std::pair<std::string,
|
mThumbnailReqMap.insert(std::pair<std::string, std::unique_ptr<HttpReq>>(
|
||||||
std::unique_ptr<HttpReq>>(mScraperResults[i].thumbnailImageUrl,
|
mScraperResults[i].thumbnailImageUrl,
|
||||||
std::unique_ptr<HttpReq>(new HttpReq(thumb))));
|
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.
|
// Check if the thumbnail for the currently selected game has finished downloading.
|
||||||
if (mScraperResults.size() > 0) {
|
if (mScraperResults.size() > 0) {
|
||||||
auto it = mThumbnailReqMap.find(mScraperResults[mResultList->
|
auto it =
|
||||||
getCursorId()].thumbnailImageUrl);
|
mThumbnailReqMap.find(mScraperResults[mResultList->getCursorId()].thumbnailImageUrl);
|
||||||
if (it != mThumbnailReqMap.end() && it->second->status() != HttpReq::REQ_IN_PROGRESS)
|
if (it != mThumbnailReqMap.end() && it->second->status() != HttpReq::REQ_IN_PROGRESS)
|
||||||
updateThumbnail();
|
updateThumbnail();
|
||||||
}
|
}
|
||||||
|
@ -681,13 +692,14 @@ void GuiScraperSearch::update(int deltaTime)
|
||||||
mMDResolveHandle.reset();
|
mMDResolveHandle.reset();
|
||||||
|
|
||||||
if (mScrapeResult.mediaFilesDownloadStatus == COMPLETED &&
|
if (mScrapeResult.mediaFilesDownloadStatus == COMPLETED &&
|
||||||
Settings::getInstance()->getBool("MiximageGenerate")) {
|
Settings::getInstance()->getBool("MiximageGenerate")) {
|
||||||
std::string currentMiximage = mLastSearch.game->getMiximagePath();
|
std::string currentMiximage = mLastSearch.game->getMiximagePath();
|
||||||
if (currentMiximage == "" || (currentMiximage != "" &&
|
if (currentMiximage == "" ||
|
||||||
Settings::getInstance()->getBool("MiximageOverwrite"))) {
|
(currentMiximage != "" &&
|
||||||
|
Settings::getInstance()->getBool("MiximageOverwrite"))) {
|
||||||
|
|
||||||
mMiximageGenerator = std::make_unique<MiximageGenerator>(mLastSearch.game,
|
mMiximageGenerator =
|
||||||
mResultMessage);
|
std::make_unique<MiximageGenerator>(mLastSearch.game, mResultMessage);
|
||||||
|
|
||||||
// The promise/future mechanism is used as signaling for the thread to
|
// The promise/future mechanism is used as signaling for the thread to
|
||||||
// indicate that processing has been completed. The reason to run a separate
|
// 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);
|
std::promise<bool>().swap(mGeneratorPromise);
|
||||||
mGeneratorFuture = mGeneratorPromise.get_future();
|
mGeneratorFuture = mGeneratorPromise.get_future();
|
||||||
|
|
||||||
mMiximageGeneratorThread = std::thread(&MiximageGenerator::startThread,
|
mMiximageGeneratorThread =
|
||||||
mMiximageGenerator.get(), &mGeneratorPromise);
|
std::thread(&MiximageGenerator::startThread, mMiximageGenerator.get(),
|
||||||
|
&mGeneratorPromise);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
returnResult(mScrapeResult);
|
returnResult(mScrapeResult);
|
||||||
|
@ -724,7 +737,7 @@ void GuiScraperSearch::updateThumbnail()
|
||||||
// thumbnail download has been completed for this game.
|
// thumbnail download has been completed for this game.
|
||||||
if (mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus == IN_PROGRESS) {
|
if (mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus == IN_PROGRESS) {
|
||||||
mScraperResults[mResultList->getCursorId()].thumbnailImageData =
|
mScraperResults[mResultList->getCursorId()].thumbnailImageData =
|
||||||
it->second->getContent();
|
it->second->getContent();
|
||||||
mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus = COMPLETED;
|
mScraperResults[mResultList->getCursorId()].thumbnailDownloadStatus = COMPLETED;
|
||||||
}
|
}
|
||||||
// Activate the thumbnail in the GUI.
|
// Activate the thumbnail in the GUI.
|
||||||
|
@ -737,7 +750,7 @@ void GuiScraperSearch::updateThumbnail()
|
||||||
else {
|
else {
|
||||||
mResultThumbnail->setImage("");
|
mResultThumbnail->setImage("");
|
||||||
onSearchError("Error downloading thumbnail:\n " + it->second->getErrorMsg(),
|
onSearchError("Error downloading thumbnail:\n " + it->second->getErrorMsg(),
|
||||||
it->second->status());
|
it->second->status());
|
||||||
}
|
}
|
||||||
|
|
||||||
mThumbnailReqMap.erase(it);
|
mThumbnailReqMap.erase(it);
|
||||||
|
@ -746,9 +759,9 @@ void GuiScraperSearch::updateThumbnail()
|
||||||
// we are in semi-automatic mode with a single matching game result, we proceed
|
// we are in semi-automatic mode with a single matching game result, we proceed
|
||||||
// to immediately download the rest of the media files.
|
// to immediately download the rest of the media files.
|
||||||
if ((mSearchType == ALWAYS_ACCEPT_FIRST_RESULT ||
|
if ((mSearchType == ALWAYS_ACCEPT_FIRST_RESULT ||
|
||||||
(mSearchType == ACCEPT_SINGLE_MATCHES && mScraperResults.size() == 1 &&
|
(mSearchType == ACCEPT_SINGLE_MATCHES && mScraperResults.size() == 1 &&
|
||||||
mRefinedSearch == false)) &&
|
mRefinedSearch == false)) &&
|
||||||
mScraperResults.front().thumbnailDownloadStatus == COMPLETED) {
|
mScraperResults.front().thumbnailDownloadStatus == COMPLETED) {
|
||||||
mRefinedSearch = false;
|
mRefinedSearch = false;
|
||||||
if (mScraperResults.size() == 0)
|
if (mScraperResults.size() == 0)
|
||||||
mSkipCallback();
|
mSkipCallback();
|
||||||
|
@ -781,22 +794,23 @@ void GuiScraperSearch::openInputScreen(ScraperSearchParams& params)
|
||||||
// in case the scraper is set to TheGamesDB and it's an arcade game. This is required
|
// in case the scraper is set to TheGamesDB and it's an arcade game. This is required
|
||||||
// as TheGamesDB has issues with searches using the short MAME names.
|
// as TheGamesDB has issues with searches using the short MAME names.
|
||||||
if (params.game->isArcadeGame() &&
|
if (params.game->isArcadeGame() &&
|
||||||
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
Settings::getInstance()->getString("Scraper") == "thegamesdb")
|
||||||
searchString = MameNames::getInstance()->getCleanName(params.game->getCleanName());
|
searchString = MameNames::getInstance()->getCleanName(params.game->getCleanName());
|
||||||
else
|
else
|
||||||
searchString = params.game->getCleanName();
|
searchString = params.game->getCleanName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
searchString = params.nameOverride;
|
searchString = params.nameOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH",
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), "REFINE SEARCH", searchString,
|
||||||
searchString, searchForFunc, false, "SEARCH", "APPLY CHANGES?"));
|
searchForFunc, false, "SEARCH", "APPLY CHANGES?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiScraperSearch::saveMetadata(
|
bool GuiScraperSearch::saveMetadata(const ScraperSearchResult& result,
|
||||||
const ScraperSearchResult& result, MetaDataList& metadata, FileData* scrapedGame)
|
MetaDataList& metadata,
|
||||||
|
FileData* scrapedGame)
|
||||||
{
|
{
|
||||||
bool metadataUpdated = false;
|
bool metadataUpdated = false;
|
||||||
bool hasDefaultName = false;
|
bool hasDefaultName = false;
|
||||||
|
@ -825,7 +839,7 @@ bool GuiScraperSearch::saveMetadata(
|
||||||
// Skip element if the setting to not scrape metadata has been set,
|
// Skip element if the setting to not scrape metadata has been set,
|
||||||
// unless its type is rating or name.
|
// unless its type is rating or name.
|
||||||
if (!Settings::getInstance()->getBool("ScrapeMetadata") &&
|
if (!Settings::getInstance()->getBool("ScrapeMetadata") &&
|
||||||
(key != "rating" && key != "name"))
|
(key != "rating" && key != "name"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip saving of rating if the corresponding option has been set to false.
|
// Skip saving of rating if the corresponding option has been set to false.
|
||||||
|
@ -885,7 +899,7 @@ std::vector<HelpPrompt> GuiScraperSearch::getHelpPrompts()
|
||||||
if (mScrapeCount > 1)
|
if (mScrapeCount > 1)
|
||||||
prompts.push_back(HelpPrompt("x", "skip"));
|
prompts.push_back(HelpPrompt("x", "skip"));
|
||||||
if (mFoundGame && (mRefinedSearch || mSearchType != ACCEPT_SINGLE_MATCHES ||
|
if (mFoundGame && (mRefinedSearch || mSearchType != ACCEPT_SINGLE_MATCHES ||
|
||||||
(mSearchType == ACCEPT_SINGLE_MATCHES && mScraperResults.size() > 1)))
|
(mSearchType == ACCEPT_SINGLE_MATCHES && mScraperResults.size() > 1)))
|
||||||
prompts.push_back(HelpPrompt("a", "accept result"));
|
prompts.push_back(HelpPrompt("a", "accept result"));
|
||||||
|
|
||||||
return prompts;
|
return prompts;
|
||||||
|
@ -897,13 +911,3 @@ HelpStyle GuiScraperSearch::getHelpStyle()
|
||||||
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
|
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiScraperSearch::onFocusGained()
|
|
||||||
{
|
|
||||||
mGrid.onFocusGained();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiScraperSearch::onFocusLost()
|
|
||||||
{
|
|
||||||
mGrid.onFocusLost();
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_SCRAPER_SEARCH_H
|
#ifndef ES_APP_GUIS_GUI_SCRAPER_SEARCH_H
|
||||||
#define 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/BusyComponent.h"
|
||||||
#include "components/ComponentGrid.h"
|
#include "components/ComponentGrid.h"
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "MiximageGenerator.h"
|
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -36,9 +36,9 @@ class GuiScraperSearch : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum SearchType {
|
enum SearchType {
|
||||||
ALWAYS_ACCEPT_FIRST_RESULT,
|
ALWAYS_ACCEPT_FIRST_RESULT, // Automatic mode.
|
||||||
ACCEPT_SINGLE_MATCHES,
|
ACCEPT_SINGLE_MATCHES, // Semi-automatic mode.
|
||||||
NEVER_AUTO_ACCEPT
|
NEVER_AUTO_ACCEPT // Manual mode.
|
||||||
};
|
};
|
||||||
|
|
||||||
GuiScraperSearch(Window* window, SearchType searchType, unsigned int scrapeCount = 1);
|
GuiScraperSearch(Window* window, SearchType searchType, unsigned int scrapeCount = 1);
|
||||||
|
@ -47,20 +47,29 @@ public:
|
||||||
void search(const ScraperSearchParams& params);
|
void search(const ScraperSearchParams& params);
|
||||||
void openInputScreen(ScraperSearchParams& from);
|
void openInputScreen(ScraperSearchParams& from);
|
||||||
void stop();
|
void stop();
|
||||||
inline SearchType getSearchType() const { return mSearchType; }
|
SearchType getSearchType() const { return mSearchType; }
|
||||||
bool getSavedNewMedia()
|
bool getSavedNewMedia()
|
||||||
{ return (mMDResolveHandle ? mMDResolveHandle->getSavedNewMedia() : false); };
|
{
|
||||||
|
return (mMDResolveHandle ? mMDResolveHandle->getSavedNewMedia() : false);
|
||||||
|
}
|
||||||
static bool saveMetadata(const ScraperSearchResult& result,
|
static bool saveMetadata(const ScraperSearchResult& result,
|
||||||
MetaDataList& metadata, FileData* scrapedGame);
|
MetaDataList& metadata,
|
||||||
|
FileData* scrapedGame);
|
||||||
|
|
||||||
// Metadata assets will be resolved before calling the accept callback
|
// Metadata assets will be resolved before calling the accept callback.
|
||||||
// (e.g. result.mdl's "image" is automatically downloaded and properly set).
|
void setAcceptCallback(const std::function<void(const ScraperSearchResult&)>& acceptCallback)
|
||||||
inline void setAcceptCallback(const std::function<void(const ScraperSearchResult&)>&
|
{
|
||||||
acceptCallback) { mAcceptCallback = acceptCallback; }
|
mAcceptCallback = acceptCallback;
|
||||||
inline void setSkipCallback(const std::function<void()>&
|
}
|
||||||
skipCallback) { mSkipCallback = skipCallback; };
|
void setSkipCallback(const std::function<void()>& skipCallback)
|
||||||
inline void setCancelCallback(const std::function<void()>&
|
{
|
||||||
cancelCallback) { mScrapeCount -= 1; mCancelCallback = cancelCallback; }
|
mSkipCallback = skipCallback;
|
||||||
|
}
|
||||||
|
void setCancelCallback(const std::function<void()>& cancelCallback)
|
||||||
|
{
|
||||||
|
mScrapeCount -= 1;
|
||||||
|
mCancelCallback = cancelCallback;
|
||||||
|
}
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
|
@ -68,20 +77,19 @@ public:
|
||||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
HelpStyle getHelpStyle() override;
|
HelpStyle getHelpStyle() override;
|
||||||
void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
void onFocusGained() override;
|
|
||||||
void onFocusLost() override;
|
|
||||||
|
|
||||||
void unsetRefinedSearch() { mRefinedSearch = false; }
|
void unsetRefinedSearch() { mRefinedSearch = false; }
|
||||||
|
void onFocusGained() override { mGrid.onFocusGained(); }
|
||||||
|
void onFocusLost() override { mGrid.onFocusLost(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateViewStyle();
|
void updateViewStyle();
|
||||||
void updateThumbnail();
|
void updateThumbnail();
|
||||||
void updateInfoPane();
|
void updateInfoPane();
|
||||||
|
|
||||||
void resizeMetadata();
|
void resizeMetadata();
|
||||||
|
|
||||||
void onSearchError(const std::string& error, HttpReq::Status status =
|
void onSearchError(const std::string& error,
|
||||||
HttpReq::REQ_UNDEFINED_ERROR);
|
HttpReq::Status status = HttpReq::REQ_UNDEFINED_ERROR);
|
||||||
void onSearchDone(const std::vector<ScraperSearchResult>& results);
|
void onSearchDone(const std::vector<ScraperSearchResult>& results);
|
||||||
|
|
||||||
int getSelectedIndex();
|
int getSelectedIndex();
|
||||||
|
@ -117,8 +125,13 @@ private:
|
||||||
bool resize;
|
bool resize;
|
||||||
|
|
||||||
MetaDataPair(const std::shared_ptr<TextComponent>& f,
|
MetaDataPair(const std::shared_ptr<TextComponent>& f,
|
||||||
const std::shared_ptr<GuiComponent>& s, bool r = true)
|
const std::shared_ptr<GuiComponent>& s,
|
||||||
: first(f), second(s), resize(r) {};
|
bool r = true)
|
||||||
|
: first(f)
|
||||||
|
, second(s)
|
||||||
|
, resize(r)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<MetaDataPair> mMD_Pairs;
|
std::vector<MetaDataPair> mMD_Pairs;
|
||||||
|
|
|
@ -9,54 +9,55 @@
|
||||||
|
|
||||||
#include "guis/GuiScreensaverOptions.h"
|
#include "guis/GuiScreensaverOptions.h"
|
||||||
|
|
||||||
|
#include "Settings.h"
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "components/SliderComponent.h"
|
#include "components/SliderComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "Settings.h"
|
|
||||||
|
|
||||||
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string& title)
|
GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string& title)
|
||||||
: GuiSettings(window, title)
|
: GuiSettings(window, title)
|
||||||
{
|
{
|
||||||
// Screensaver timer.
|
// Screensaver timer.
|
||||||
auto screensaver_timer = std::make_shared<SliderComponent>(mWindow, 0.f, 30.f, 1.f, "m");
|
auto screensaver_timer = std::make_shared<SliderComponent>(mWindow, 0.0f, 30.0f, 1.0f, "m");
|
||||||
screensaver_timer->setValue(static_cast<float>(Settings::getInstance()->
|
screensaver_timer->setValue(
|
||||||
getInt("ScreensaverTimer") / (1000 * 60)));
|
static_cast<float>(Settings::getInstance()->getInt("ScreensaverTimer") / (1000 * 60)));
|
||||||
addWithLabel("START SCREENSAVER AFTER (MINUTES)", screensaver_timer);
|
addWithLabel("START SCREENSAVER AFTER (MINUTES)", screensaver_timer);
|
||||||
addSaveFunc([screensaver_timer, this] {
|
addSaveFunc([screensaver_timer, this] {
|
||||||
if (static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)) !=
|
if (static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)) !=
|
||||||
Settings::getInstance()->getInt("ScreensaverTimer")) {
|
Settings::getInstance()->getInt("ScreensaverTimer")) {
|
||||||
Settings::getInstance()->setInt("ScreensaverTimer",
|
Settings::getInstance()->setInt(
|
||||||
static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)));
|
"ScreensaverTimer",
|
||||||
|
static_cast<int>(std::round(screensaver_timer->getValue()) * (1000 * 60)));
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Screensaver type.
|
// Screensaver type.
|
||||||
auto screensaver_type = std::make_shared<OptionListComponent<std::string>>
|
auto screensaver_type = std::make_shared<OptionListComponent<std::string>>(
|
||||||
(mWindow, getHelpStyle(), "SCREENSAVER TYPE", false);
|
mWindow, getHelpStyle(), "SCREENSAVER TYPE", false);
|
||||||
std::vector<std::string> screensavers;
|
std::vector<std::string> screensavers;
|
||||||
screensavers.push_back("dim");
|
screensavers.push_back("dim");
|
||||||
screensavers.push_back("black");
|
screensavers.push_back("black");
|
||||||
screensavers.push_back("slideshow");
|
screensavers.push_back("slideshow");
|
||||||
screensavers.push_back("video");
|
screensavers.push_back("video");
|
||||||
for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++)
|
for (auto it = screensavers.cbegin(); it != screensavers.cend(); it++)
|
||||||
screensaver_type->add(*it, *it, Settings::getInstance()->
|
screensaver_type->add(*it, *it,
|
||||||
getString("ScreensaverType") == *it);
|
Settings::getInstance()->getString("ScreensaverType") == *it);
|
||||||
addWithLabel("SCREENSAVER TYPE", screensaver_type);
|
addWithLabel("SCREENSAVER TYPE", screensaver_type);
|
||||||
addSaveFunc([screensaver_type, this] {
|
addSaveFunc([screensaver_type, this] {
|
||||||
if (screensaver_type->getSelected() !=
|
if (screensaver_type->getSelected() !=
|
||||||
Settings::getInstance()->getString("ScreensaverType")) {
|
Settings::getInstance()->getString("ScreensaverType")) {
|
||||||
if (screensaver_type->getSelected() == "video") {
|
if (screensaver_type->getSelected() == "video") {
|
||||||
// If before it wasn't risky but now there's a risk of problems, show warning.
|
// 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(
|
||||||
"THE 'VIDEO' SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS\n\n"
|
mWindow, getHelpStyle(),
|
||||||
"IF YOU DO NOT HAVE ANY VIDEOS, THE\n"
|
"THE 'VIDEO' SCREENSAVER SHOWS\nVIDEOS FROM YOUR GAMELISTS\n\n"
|
||||||
"SCREENSAVER WILL DEFAULT TO 'DIM'",
|
"IF YOU DO NOT HAVE ANY VIDEOS, THE\n"
|
||||||
"OK", [] { return; }, "", nullptr, "", nullptr));
|
"SCREENSAVER WILL DEFAULT TO 'DIM'",
|
||||||
}
|
"OK", [] { return; }, "", nullptr, "", nullptr));
|
||||||
Settings::getInstance()->setString("ScreensaverType",
|
}
|
||||||
screensaver_type->getSelected());
|
Settings::getInstance()->setString("ScreensaverType", screensaver_type->getSelected());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -67,9 +68,9 @@ GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string&
|
||||||
addWithLabel("ENABLE SCREENSAVER CONTROLS", screensaver_controls);
|
addWithLabel("ENABLE SCREENSAVER CONTROLS", screensaver_controls);
|
||||||
addSaveFunc([screensaver_controls, this] {
|
addSaveFunc([screensaver_controls, this] {
|
||||||
if (screensaver_controls->getState() !=
|
if (screensaver_controls->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverControls")) {
|
Settings::getInstance()->getBool("ScreensaverControls")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverControls",
|
Settings::getInstance()->setBool("ScreensaverControls",
|
||||||
screensaver_controls->getState());
|
screensaver_controls->getState());
|
||||||
setNeedsSaving();
|
setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -77,19 +78,21 @@ GuiScreensaverOptions::GuiScreensaverOptions(Window* window, const std::string&
|
||||||
// Show filtered menu.
|
// Show filtered menu.
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
row.addElement(std::make_shared<TextComponent>(mWindow, "SLIDESHOW SCREENSAVER SETTINGS",
|
||||||
"SLIDESHOW SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(
|
row.makeAcceptInputHandler(
|
||||||
&GuiScreensaverOptions::openSlideshowScreensaverOptions, this));
|
std::bind(&GuiScreensaverOptions::openSlideshowScreensaverOptions, this));
|
||||||
addRow(row);
|
addRow(row);
|
||||||
|
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow,
|
row.addElement(std::make_shared<TextComponent>(mWindow, "VIDEO SCREENSAVER SETTINGS",
|
||||||
"VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF),
|
||||||
|
true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(
|
row.makeAcceptInputHandler(
|
||||||
&GuiScreensaverOptions::openVideoScreensaverOptions, this));
|
std::bind(&GuiScreensaverOptions::openVideoScreensaverOptions, this));
|
||||||
addRow(row);
|
addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,104 +102,105 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
|
||||||
|
|
||||||
// Timer for swapping images (in seconds).
|
// Timer for swapping images (in seconds).
|
||||||
auto screensaver_swap_image_timeout =
|
auto screensaver_swap_image_timeout =
|
||||||
std::make_shared<SliderComponent>(mWindow, 2.f, 120.f, 2.f, "s");
|
std::make_shared<SliderComponent>(mWindow, 2.0f, 120.0f, 2.0f, "s");
|
||||||
screensaver_swap_image_timeout->setValue(static_cast<float>(Settings::getInstance()->
|
screensaver_swap_image_timeout->setValue(static_cast<float>(
|
||||||
getInt("ScreensaverSwapImageTimeout") / (1000)));
|
Settings::getInstance()->getInt("ScreensaverSwapImageTimeout") / (1000)));
|
||||||
s->addWithLabel("SWAP IMAGES AFTER (SECONDS)", screensaver_swap_image_timeout);
|
s->addWithLabel("SWAP IMAGES AFTER (SECONDS)", screensaver_swap_image_timeout);
|
||||||
s->addSaveFunc([screensaver_swap_image_timeout, s] {
|
s->addSaveFunc([screensaver_swap_image_timeout, s] {
|
||||||
if (screensaver_swap_image_timeout->getValue() !=
|
if (screensaver_swap_image_timeout->getValue() !=
|
||||||
static_cast<float>(Settings::getInstance()->
|
static_cast<float>(Settings::getInstance()->getInt("ScreensaverSwapImageTimeout") /
|
||||||
getInt("ScreensaverSwapImageTimeout") / (1000))) {
|
(1000))) {
|
||||||
Settings::getInstance()->setInt("ScreensaverSwapImageTimeout",
|
Settings::getInstance()->setInt(
|
||||||
static_cast<int>(std::round(screensaver_swap_image_timeout->getValue()) *
|
"ScreensaverSwapImageTimeout",
|
||||||
(1000)));
|
static_cast<int>(std::round(screensaver_swap_image_timeout->getValue()) * (1000)));
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stretch images to screen resolution.
|
// Stretch images to screen resolution.
|
||||||
auto screensaver_stretch_images = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_stretch_images = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_stretch_images->
|
screensaver_stretch_images->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverStretchImages"));
|
Settings::getInstance()->getBool("ScreensaverStretchImages"));
|
||||||
s->addWithLabel("STRETCH IMAGES TO SCREEN RESOLUTION", screensaver_stretch_images);
|
s->addWithLabel("STRETCH IMAGES TO SCREEN RESOLUTION", screensaver_stretch_images);
|
||||||
s->addSaveFunc([screensaver_stretch_images, s] {
|
s->addSaveFunc([screensaver_stretch_images, s] {
|
||||||
if (screensaver_stretch_images->getState() !=
|
if (screensaver_stretch_images->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverStretchImages")) {
|
Settings::getInstance()->getBool("ScreensaverStretchImages")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverStretchImages",
|
Settings::getInstance()->setBool("ScreensaverStretchImages",
|
||||||
screensaver_stretch_images->getState());
|
screensaver_stretch_images->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show game info overlay for slideshow screensaver.
|
// Show game info overlay for slideshow screensaver.
|
||||||
auto screensaver_slideshow_game_info = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_slideshow_game_info = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_slideshow_game_info->
|
screensaver_slideshow_game_info->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"));
|
Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"));
|
||||||
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_slideshow_game_info);
|
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_slideshow_game_info);
|
||||||
s->addSaveFunc([screensaver_slideshow_game_info, s] {
|
s->addSaveFunc([screensaver_slideshow_game_info, s] {
|
||||||
if (screensaver_slideshow_game_info->getState() !=
|
if (screensaver_slideshow_game_info->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo")) {
|
Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverSlideshowGameInfo",
|
Settings::getInstance()->setBool("ScreensaverSlideshowGameInfo",
|
||||||
screensaver_slideshow_game_info->getState());
|
screensaver_slideshow_game_info->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
// Render scanlines using a shader.
|
// Render scanlines using a shader.
|
||||||
auto screensaver_slideshow_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_slideshow_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_slideshow_scanlines->
|
screensaver_slideshow_scanlines->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"));
|
Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"));
|
||||||
s->addWithLabel("RENDER SCANLINES", screensaver_slideshow_scanlines);
|
s->addWithLabel("RENDER SCANLINES", screensaver_slideshow_scanlines);
|
||||||
s->addSaveFunc([screensaver_slideshow_scanlines, s] {
|
s->addSaveFunc([screensaver_slideshow_scanlines, s] {
|
||||||
if (screensaver_slideshow_scanlines->getState() !=
|
if (screensaver_slideshow_scanlines->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverSlideshowScanlines")) {
|
Settings::getInstance()->getBool("ScreensaverSlideshowScanlines")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverSlideshowScanlines",
|
Settings::getInstance()->setBool("ScreensaverSlideshowScanlines",
|
||||||
screensaver_slideshow_scanlines->getState());
|
screensaver_slideshow_scanlines->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Whether to use custom images.
|
// Whether to use custom images.
|
||||||
auto screensaver_slideshow_custom_images = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_slideshow_custom_images = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_slideshow_custom_images->setState(Settings::getInstance()->
|
screensaver_slideshow_custom_images->setState(
|
||||||
getBool("ScreensaverSlideshowCustomImages"));
|
Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages"));
|
||||||
s->addWithLabel("USE CUSTOM IMAGES", screensaver_slideshow_custom_images);
|
s->addWithLabel("USE CUSTOM IMAGES", screensaver_slideshow_custom_images);
|
||||||
s->addSaveFunc([screensaver_slideshow_custom_images, s] {
|
s->addSaveFunc([screensaver_slideshow_custom_images, s] {
|
||||||
if (screensaver_slideshow_custom_images->getState() !=
|
if (screensaver_slideshow_custom_images->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) {
|
Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverSlideshowCustomImages",
|
Settings::getInstance()->setBool("ScreensaverSlideshowCustomImages",
|
||||||
screensaver_slideshow_custom_images->getState());
|
screensaver_slideshow_custom_images->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Whether to recurse the custom image directory.
|
// Whether to recurse the custom image directory.
|
||||||
auto screensaver_slideshow_recurse = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_slideshow_recurse = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_slideshow_recurse->setState(Settings::getInstance()->
|
screensaver_slideshow_recurse->setState(
|
||||||
getBool("ScreensaverSlideshowRecurse"));
|
Settings::getInstance()->getBool("ScreensaverSlideshowRecurse"));
|
||||||
s->addWithLabel("CUSTOM IMAGE DIRECTORY RECURSIVE SEARCH", screensaver_slideshow_recurse);
|
s->addWithLabel("CUSTOM IMAGE DIRECTORY RECURSIVE SEARCH", screensaver_slideshow_recurse);
|
||||||
s->addSaveFunc([screensaver_slideshow_recurse, s] {
|
s->addSaveFunc([screensaver_slideshow_recurse, s] {
|
||||||
if (screensaver_slideshow_recurse->getState() !=
|
if (screensaver_slideshow_recurse->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")) {
|
Settings::getInstance()->getBool("ScreensaverSlideshowRecurse")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverSlideshowRecurse",
|
Settings::getInstance()->setBool("ScreensaverSlideshowRecurse",
|
||||||
screensaver_slideshow_recurse->getState());
|
screensaver_slideshow_recurse->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Custom image directory.
|
// Custom image directory.
|
||||||
auto screensaver_slideshow_image_dir = std::make_shared<TextComponent>(mWindow, "",
|
auto screensaver_slideshow_image_dir = std::make_shared<TextComponent>(
|
||||||
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT);
|
mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_RIGHT);
|
||||||
s->addEditableTextComponent("CUSTOM IMAGE DIRECTORY", screensaver_slideshow_image_dir,
|
s->addEditableTextComponent(
|
||||||
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"),
|
"CUSTOM IMAGE DIRECTORY", screensaver_slideshow_image_dir,
|
||||||
Settings::getInstance()->getDefaultString("ScreensaverSlideshowImageDir"));
|
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"),
|
||||||
|
Settings::getInstance()->getDefaultString("ScreensaverSlideshowImageDir"));
|
||||||
s->addSaveFunc([screensaver_slideshow_image_dir, s] {
|
s->addSaveFunc([screensaver_slideshow_image_dir, s] {
|
||||||
if (screensaver_slideshow_image_dir->getValue() !=
|
if (screensaver_slideshow_image_dir->getValue() !=
|
||||||
Settings::getInstance()->getString("ScreensaverSlideshowImageDir")) {
|
Settings::getInstance()->getString("ScreensaverSlideshowImageDir")) {
|
||||||
Settings::getInstance()->setString("ScreensaverSlideshowImageDir",
|
Settings::getInstance()->setString("ScreensaverSlideshowImageDir",
|
||||||
screensaver_slideshow_image_dir->getValue());
|
screensaver_slideshow_image_dir->getValue());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -210,75 +214,75 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
||||||
|
|
||||||
// Timer for swapping videos (in seconds).
|
// Timer for swapping videos (in seconds).
|
||||||
auto screensaver_swap_video_timeout =
|
auto screensaver_swap_video_timeout =
|
||||||
std::make_shared<SliderComponent>(mWindow, 0.f, 120.f, 2.f, "s");
|
std::make_shared<SliderComponent>(mWindow, 0.0f, 120.0f, 2.0f, "s");
|
||||||
screensaver_swap_video_timeout->setValue(static_cast<float>(Settings::getInstance()->
|
screensaver_swap_video_timeout->setValue(static_cast<float>(
|
||||||
getInt("ScreensaverSwapVideoTimeout") / (1000)));
|
Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") / (1000)));
|
||||||
s->addWithLabel("SWAP VIDEOS AFTER (SECONDS)", screensaver_swap_video_timeout);
|
s->addWithLabel("SWAP VIDEOS AFTER (SECONDS)", screensaver_swap_video_timeout);
|
||||||
s->addSaveFunc([screensaver_swap_video_timeout, s] {
|
s->addSaveFunc([screensaver_swap_video_timeout, s] {
|
||||||
if (screensaver_swap_video_timeout->getValue() !=
|
if (screensaver_swap_video_timeout->getValue() !=
|
||||||
static_cast<float>(Settings::getInstance()->
|
static_cast<float>(Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout") /
|
||||||
getInt("ScreensaverSwapVideoTimeout") / (1000))) {
|
(1000))) {
|
||||||
Settings::getInstance()->setInt("ScreensaverSwapVideoTimeout",
|
Settings::getInstance()->setInt(
|
||||||
static_cast<int>(std::round(screensaver_swap_video_timeout->getValue()) *
|
"ScreensaverSwapVideoTimeout",
|
||||||
(1000)));
|
static_cast<int>(std::round(screensaver_swap_video_timeout->getValue()) * (1000)));
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stretch videos to screen resolution.
|
// Stretch videos to screen resolution.
|
||||||
auto screensaver_stretch_videos = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_stretch_videos = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_stretch_videos->
|
screensaver_stretch_videos->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverStretchVideos"));
|
Settings::getInstance()->getBool("ScreensaverStretchVideos"));
|
||||||
s->addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", screensaver_stretch_videos);
|
s->addWithLabel("STRETCH VIDEOS TO SCREEN RESOLUTION", screensaver_stretch_videos);
|
||||||
s->addSaveFunc([screensaver_stretch_videos, s] {
|
s->addSaveFunc([screensaver_stretch_videos, s] {
|
||||||
if (screensaver_stretch_videos->getState() !=
|
if (screensaver_stretch_videos->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverStretchVideos")) {
|
Settings::getInstance()->getBool("ScreensaverStretchVideos")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverStretchVideos",
|
Settings::getInstance()->setBool("ScreensaverStretchVideos",
|
||||||
screensaver_stretch_videos->getState());
|
screensaver_stretch_videos->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show game info overlay for video screensaver.
|
// Show game info overlay for video screensaver.
|
||||||
auto screensaver_video_game_info = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_video_game_info = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_video_game_info->
|
screensaver_video_game_info->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverVideoGameInfo"));
|
Settings::getInstance()->getBool("ScreensaverVideoGameInfo"));
|
||||||
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_video_game_info);
|
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_video_game_info);
|
||||||
s->addSaveFunc([screensaver_video_game_info, s] {
|
s->addSaveFunc([screensaver_video_game_info, s] {
|
||||||
if (screensaver_video_game_info->getState() !=
|
if (screensaver_video_game_info->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverVideoGameInfo")) {
|
Settings::getInstance()->getBool("ScreensaverVideoGameInfo")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverVideoGameInfo",
|
Settings::getInstance()->setBool("ScreensaverVideoGameInfo",
|
||||||
screensaver_video_game_info->getState());
|
screensaver_video_game_info->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(_RPI_)
|
#if defined(_RPI_)
|
||||||
// Use OMX player for screensaver.
|
// Use OMX player for screensaver.
|
||||||
auto screensaver_omx_player = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_omx_player = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_omx_player->setState(Settings::getInstance()->getBool("ScreensaverOmxPlayer"));
|
screensaver_omx_player->setState(Settings::getInstance()->getBool("ScreensaverOmxPlayer"));
|
||||||
s->addWithLabel("USE OMX PLAYER FOR SCREENSAVER", screensaver_omx_player);
|
s->addWithLabel("USE OMX PLAYER FOR SCREENSAVER", screensaver_omx_player);
|
||||||
s->addSaveFunc([screensaver_omx_player, s] {
|
s->addSaveFunc([screensaver_omx_player, s] {
|
||||||
if (screensaver_omx_player->getState() !=
|
if (screensaver_omx_player->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverOmxPlayer")) {
|
Settings::getInstance()->getBool("ScreensaverOmxPlayer")) {
|
||||||
Settings::getInstance()->
|
Settings::getInstance()->setBool("ScreensaverOmxPlayer",
|
||||||
setBool("ScreensaverOmxPlayer", screensaver_omx_player->getState());
|
screensaver_omx_player->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_OPENGL_21)
|
#if defined(USE_OPENGL_21)
|
||||||
// Render scanlines using a shader.
|
// Render scanlines using a shader.
|
||||||
auto screensaver_video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
auto screensaver_video_scanlines = std::make_shared<SwitchComponent>(mWindow);
|
||||||
screensaver_video_scanlines->
|
screensaver_video_scanlines->setState(
|
||||||
setState(Settings::getInstance()->getBool("ScreensaverVideoScanlines"));
|
Settings::getInstance()->getBool("ScreensaverVideoScanlines"));
|
||||||
s->addWithLabel("RENDER SCANLINES", screensaver_video_scanlines);
|
s->addWithLabel("RENDER SCANLINES", screensaver_video_scanlines);
|
||||||
s->addSaveFunc([screensaver_video_scanlines, s] {
|
s->addSaveFunc([screensaver_video_scanlines, s] {
|
||||||
if (screensaver_video_scanlines->getState() !=
|
if (screensaver_video_scanlines->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverVideoScanlines")) {
|
Settings::getInstance()->getBool("ScreensaverVideoScanlines")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverVideoScanlines",
|
Settings::getInstance()->setBool("ScreensaverVideoScanlines",
|
||||||
screensaver_video_scanlines->getState());
|
screensaver_video_scanlines->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -289,13 +293,13 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
|
||||||
s->addWithLabel("RENDER BLUR", screensaver_video_blur);
|
s->addWithLabel("RENDER BLUR", screensaver_video_blur);
|
||||||
s->addSaveFunc([screensaver_video_blur, s] {
|
s->addSaveFunc([screensaver_video_blur, s] {
|
||||||
if (screensaver_video_blur->getState() !=
|
if (screensaver_video_blur->getState() !=
|
||||||
Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
||||||
Settings::getInstance()->setBool("ScreensaverVideoBlur",
|
Settings::getInstance()->setBool("ScreensaverVideoBlur",
|
||||||
screensaver_video_blur->getState());
|
screensaver_video_blur->getState());
|
||||||
s->setNeedsSaving();
|
s->setNeedsSaving();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,33 +10,31 @@
|
||||||
|
|
||||||
#include "guis/GuiSettings.h"
|
#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 "CollectionSystemsManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
#include "components/HelpComponent.h"
|
||||||
|
#include "guis/GuiTextEditPopup.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
|
||||||
GuiSettings::GuiSettings(
|
GuiSettings::GuiSettings(Window* window, std::string title)
|
||||||
Window* window,
|
: GuiComponent(window)
|
||||||
std::string title)
|
, mMenu(window, title)
|
||||||
: GuiComponent(window),
|
, mNeedsSaving(false)
|
||||||
mMenu(window, title),
|
, mNeedsReloadHelpPrompts(false)
|
||||||
mNeedsSaving(false),
|
, mNeedsCollectionsUpdate(false)
|
||||||
mNeedsReloadHelpPrompts(false),
|
, mNeedsSorting(false)
|
||||||
mNeedsCollectionsUpdate(false),
|
, mNeedsSortingCollections(false)
|
||||||
mNeedsSorting(false),
|
, mNeedsResetFilters(false)
|
||||||
mNeedsSortingCollections(false),
|
, mNeedsReloading(false)
|
||||||
mNeedsResetFilters(false),
|
, mNeedsGoToStart(false)
|
||||||
mNeedsReloading(false),
|
, mNeedsGoToSystem(false)
|
||||||
mNeedsGoToStart(false),
|
, mNeedsGoToGroupedCollections(false)
|
||||||
mNeedsGoToSystem(false),
|
, mInvalidateCachedBackground(false)
|
||||||
mNeedsGoToGroupedCollections(false),
|
, mGoToSystem(nullptr)
|
||||||
mInvalidateCachedBackground(false),
|
|
||||||
mGoToSystem(nullptr)
|
|
||||||
{
|
{
|
||||||
addChild(&mMenu);
|
addChild(&mMenu);
|
||||||
mMenu.addButton("BACK", "back", [this] { delete this; });
|
mMenu.addButton("BACK", "back", [this] { delete this; });
|
||||||
|
@ -44,11 +42,12 @@ GuiSettings::GuiSettings(
|
||||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
static_cast<float>(Renderer::getScreenHeight()));
|
||||||
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f,
|
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2.0f,
|
||||||
Renderer::getScreenHeight() * 0.13f);
|
Renderer::getScreenHeight() * 0.13f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiSettings::~GuiSettings()
|
GuiSettings::~GuiSettings()
|
||||||
{
|
{
|
||||||
|
// Save on exit.
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +71,11 @@ void GuiSettings::save()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNeedsSorting) {
|
if (mNeedsSorting) {
|
||||||
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||||
SystemData::sSystemVector.cend(); it++) {
|
it++) {
|
||||||
if (!(!mNeedsSortingCollections && (*it)->isCollection())) {
|
if (!(!mNeedsSortingCollections && (*it)->isCollection()))
|
||||||
(*it)->sortSystem(true);
|
(*it)->sortSystem(true);
|
||||||
}
|
|
||||||
// Jump to the first row of the gamelist.
|
// Jump to the first row of the gamelist.
|
||||||
IGameListView* gameList = ViewController::get()->getGameListView((*it)).get();
|
IGameListView* gameList = ViewController::get()->getGameListView((*it)).get();
|
||||||
gameList->setCursor(gameList->getFirstEntry());
|
gameList->setCursor(gameList->getFirstEntry());
|
||||||
|
@ -84,11 +83,10 @@ void GuiSettings::save()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNeedsResetFilters) {
|
if (mNeedsResetFilters) {
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it != SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
if ((*it)->getThemeFolder() == "custom-collections") {
|
if ((*it)->getThemeFolder() == "custom-collections") {
|
||||||
for (FileData* customSystem :
|
for (FileData* customSystem : (*it)->getRootFolder()->getChildrenListToDisplay())
|
||||||
(*it)->getRootFolder()->getChildrenListToDisplay())
|
|
||||||
customSystem->getSystem()->getIndex()->resetFilters();
|
customSystem->getSystem()->getIndex()->resetFilters();
|
||||||
}
|
}
|
||||||
(*it)->getIndex()->resetFilters();
|
(*it)->getIndex()->resetFilters();
|
||||||
|
@ -125,7 +123,7 @@ void GuiSettings::save()
|
||||||
// these views can behave a bit strange during collection changes so it's better to be on
|
// these views can behave a bit strange during collection changes so it's better to be on
|
||||||
// the safe side.
|
// the safe side.
|
||||||
if (state.getSystem()->isCollection() &&
|
if (state.getSystem()->isCollection() &&
|
||||||
state.getSystem()->getThemeFolder() != "custom-collections") {
|
state.getSystem()->getThemeFolder() != "custom-collections") {
|
||||||
ViewController::get()->goToStart();
|
ViewController::get()->goToStart();
|
||||||
ViewController::get()->goToSystem(SystemData::sSystemVector.front(), false);
|
ViewController::get()->goToSystem(SystemData::sSystemVector.front(), false);
|
||||||
// We don't want to invalidate the cached background when there has been a collection
|
// We don't want to invalidate the cached background when there has been a collection
|
||||||
|
@ -135,7 +133,7 @@ void GuiSettings::save()
|
||||||
// If the last displayed custom collection was just disabled, then go to start (to the
|
// If the last displayed custom collection was just disabled, then go to start (to the
|
||||||
// system view).
|
// system view).
|
||||||
if (std::find(SystemData::sSystemVector.begin(), SystemData::sSystemVector.end(),
|
if (std::find(SystemData::sSystemVector.begin(), SystemData::sSystemVector.end(),
|
||||||
state.getSystem()) == SystemData::sSystemVector.end()) {
|
state.getSystem()) == SystemData::sSystemVector.end()) {
|
||||||
ViewController::get()->goToStart();
|
ViewController::get()->goToStart();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -152,18 +150,17 @@ void GuiSettings::save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiSettings::addEditableTextComponent(
|
void GuiSettings::addEditableTextComponent(const std::string label,
|
||||||
const std::string label,
|
std::shared_ptr<GuiComponent> ed,
|
||||||
std::shared_ptr<GuiComponent> ed,
|
std::string value,
|
||||||
std::string value,
|
std::string defaultValue,
|
||||||
std::string defaultValue,
|
bool isPassword)
|
||||||
bool isPassword)
|
|
||||||
{
|
{
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
|
|
||||||
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label),
|
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(label),
|
||||||
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
|
|
||||||
row.addElement(lbl, true);
|
row.addElement(lbl, true);
|
||||||
row.addElement(ed, true);
|
row.addElement(ed, true);
|
||||||
|
@ -200,11 +197,11 @@ void GuiSettings::addEditableTextComponent(
|
||||||
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
row.makeAcceptInputHandler([this, label, ed, updateVal, isPassword] {
|
||||||
// Never display the value if it's a password, instead set it to blank.
|
// Never display the value if it's a password, instead set it to blank.
|
||||||
if (isPassword)
|
if (isPassword)
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label,
|
mWindow->pushGui(
|
||||||
"", updateVal, false));
|
new GuiTextEditPopup(mWindow, getHelpStyle(), label, "", updateVal, false));
|
||||||
else
|
else
|
||||||
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label,
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), label, ed->getValue(),
|
||||||
ed->getValue(), updateVal, false));
|
updateVal, false));
|
||||||
});
|
});
|
||||||
assert(ed);
|
assert(ed);
|
||||||
addRow(row);
|
addRow(row);
|
||||||
|
@ -219,15 +216,6 @@ bool GuiSettings::input(InputConfig* config, Input input)
|
||||||
return true;
|
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);
|
return GuiComponent::input(config, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#ifndef ES_APP_GUIS_GUI_SETTINGS_H
|
#ifndef ES_APP_GUIS_GUI_SETTINGS_H
|
||||||
#define ES_APP_GUIS_GUI_SETTINGS_H
|
#define ES_APP_GUIS_GUI_SETTINGS_H
|
||||||
|
|
||||||
#include "components/MenuComponent.h"
|
|
||||||
#include "SystemData.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.
|
// This is just a really simple template for a GUI that calls some save functions when closed.
|
||||||
class GuiSettings : public GuiComponent
|
class GuiSettings : public GuiComponent
|
||||||
|
@ -22,29 +22,33 @@ public:
|
||||||
virtual ~GuiSettings();
|
virtual ~GuiSettings();
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
inline void addRow(const ComponentListRow& row) { mMenu.addRow(row); };
|
void addRow(const ComponentListRow& row) { mMenu.addRow(row); }
|
||||||
inline void addWithLabel(const std::string& label,
|
void addWithLabel(const std::string& label, const std::shared_ptr<GuiComponent>& comp)
|
||||||
const std::shared_ptr<GuiComponent>& comp) { mMenu.addWithLabel(label, comp); };
|
{
|
||||||
void addEditableTextComponent(
|
mMenu.addWithLabel(label, comp);
|
||||||
const std::string label,
|
}
|
||||||
std::shared_ptr<GuiComponent> ed,
|
void addEditableTextComponent(const std::string label,
|
||||||
std::string value,
|
std::shared_ptr<GuiComponent> ed,
|
||||||
std::string defaultValue = "",
|
std::string value,
|
||||||
bool isPassword = false);
|
std::string defaultValue = "",
|
||||||
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
bool isPassword = false);
|
||||||
|
void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); }
|
||||||
|
|
||||||
void setNeedsSaving(bool state = true) { mNeedsSaving = state; };
|
void setNeedsSaving(bool state = true) { mNeedsSaving = state; }
|
||||||
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; };
|
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; }
|
||||||
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; };
|
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; }
|
||||||
void setNeedsSorting() { mNeedsSorting = true; };
|
void setNeedsSorting() { mNeedsSorting = true; }
|
||||||
void setNeedsSortingCollections() { mNeedsSortingCollections = true; };
|
void setNeedsSortingCollections() { mNeedsSortingCollections = true; }
|
||||||
void setNeedsResetFilters() { mNeedsResetFilters = true; }
|
void setNeedsResetFilters() { mNeedsResetFilters = true; }
|
||||||
void setNeedsReloading() { mNeedsReloading = true; };
|
void setNeedsReloading() { mNeedsReloading = true; }
|
||||||
void setNeedsGoToStart() { mNeedsGoToStart = true; };
|
void setNeedsGoToStart() { mNeedsGoToStart = true; }
|
||||||
void setNeedsGoToSystem(SystemData* goToSystem)
|
void setNeedsGoToSystem(SystemData* goToSystem)
|
||||||
{ mNeedsGoToSystem = true; mGoToSystem = goToSystem; };
|
{
|
||||||
void setNeedsGoToGroupedCollections() { mNeedsGoToGroupedCollections = true; };
|
mNeedsGoToSystem = true;
|
||||||
void setInvalidateCachedBackground() { mInvalidateCachedBackground = true; };
|
mGoToSystem = goToSystem;
|
||||||
|
};
|
||||||
|
void setNeedsGoToGroupedCollections() { mNeedsGoToGroupedCollections = true; }
|
||||||
|
void setInvalidateCachedBackground() { mInvalidateCachedBackground = true; }
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
@ -53,6 +57,8 @@ public:
|
||||||
private:
|
private:
|
||||||
MenuComponent mMenu;
|
MenuComponent mMenu;
|
||||||
std::vector<std::function<void()>> mSaveFuncs;
|
std::vector<std::function<void()>> mSaveFuncs;
|
||||||
|
SystemData* mGoToSystem;
|
||||||
|
|
||||||
bool mNeedsSaving;
|
bool mNeedsSaving;
|
||||||
bool mNeedsReloadHelpPrompts;
|
bool mNeedsReloadHelpPrompts;
|
||||||
bool mNeedsCollectionsUpdate;
|
bool mNeedsCollectionsUpdate;
|
||||||
|
@ -64,8 +70,6 @@ private:
|
||||||
bool mNeedsGoToSystem;
|
bool mNeedsGoToSystem;
|
||||||
bool mNeedsGoToGroupedCollections;
|
bool mNeedsGoToGroupedCollections;
|
||||||
bool mInvalidateCachedBackground;
|
bool mInvalidateCachedBackground;
|
||||||
|
|
||||||
SystemData* mGoToSystem;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_GUIS_GUI_SETTINGS_H
|
#endif // ES_APP_GUIS_GUI_SETTINGS_H
|
||||||
|
|
|
@ -18,13 +18,6 @@
|
||||||
// environment and starts listening to SDL events.
|
// 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 "AudioManager.h"
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "EmulationStation.h"
|
#include "EmulationStation.h"
|
||||||
|
@ -37,6 +30,13 @@
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "SystemScreensaver.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_events.h>
|
||||||
#include <SDL2/SDL_main.h>
|
#include <SDL2/SDL_main.h>
|
||||||
|
@ -56,14 +56,14 @@ bool forceInputConfig = false;
|
||||||
bool settingsNeedSaving = false;
|
bool settingsNeedSaving = false;
|
||||||
|
|
||||||
enum loadSystemsReturnCode {
|
enum loadSystemsReturnCode {
|
||||||
LOADING_OK,
|
LOADING_OK, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
INVALID_FILE,
|
INVALID_FILE,
|
||||||
NO_ROMS
|
NO_ROMS
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
enum win64ConsoleType {
|
enum win64ConsoleType {
|
||||||
NO_CONSOLE,
|
NO_CONSOLE, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
PARENT_CONSOLE,
|
PARENT_CONSOLE,
|
||||||
ALLOCATED_CONSOLE
|
ALLOCATED_CONSOLE
|
||||||
};
|
};
|
||||||
|
@ -85,7 +85,7 @@ win64ConsoleType outputToConsole(bool allocConsole)
|
||||||
|
|
||||||
// Try to attach to a parent console process.
|
// Try to attach to a parent console process.
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS))
|
if (AttachConsole(ATTACH_PARENT_PROCESS))
|
||||||
outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
|
||||||
// If there is a parent console process, then attempt to retrieve its handle.
|
// If there is a parent console process, then attempt to retrieve its handle.
|
||||||
if (outputHandle != INVALID_HANDLE_VALUE && outputHandle != nullptr) {
|
if (outputHandle != INVALID_HANDLE_VALUE && outputHandle != nullptr) {
|
||||||
|
@ -131,11 +131,11 @@ bool parseArgs(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
Utils::FileSystem::setExePath(argv[0]);
|
Utils::FileSystem::setExePath(argv[0]);
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// Print any command line output to the console.
|
// Print any command line output to the console.
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
win64ConsoleType consoleType = outputToConsole(false);
|
win64ConsoleType consoleType = outputToConsole(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string portableFilePath = Utils::FileSystem::getExePath() + "/portable.txt";
|
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::cout << "Found portable.txt in the ES-DE executable directory\n";
|
||||||
std::ifstream portableFile;
|
std::ifstream portableFile;
|
||||||
std::string homePath;
|
std::string homePath;
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
portableFile.open(Utils::String::stringToWideString(portableFilePath).c_str());
|
portableFile.open(Utils::String::stringToWideString(portableFilePath).c_str());
|
||||||
#else
|
#else
|
||||||
portableFile.open(portableFilePath.c_str());
|
portableFile.open(portableFilePath.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (!portableFile.fail()) {
|
if (!portableFile.fail()) {
|
||||||
std::string relativePath;
|
std::string relativePath;
|
||||||
getline(portableFile, relativePath);
|
getline(portableFile, relativePath);
|
||||||
|
@ -159,9 +159,9 @@ bool parseArgs(int argc, char* argv[])
|
||||||
else
|
else
|
||||||
homePath = Utils::FileSystem::getExePath() + "/" + relativePath;
|
homePath = Utils::FileSystem::getExePath() + "/" + relativePath;
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
homePath = Utils::String::replace(homePath, "/", "\\");
|
homePath = Utils::String::replace(homePath, "/", "\\");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!Utils::FileSystem::exists(homePath)) {
|
if (!Utils::FileSystem::exists(homePath)) {
|
||||||
std::cerr << "Error: Defined home path \"" << homePath << "\" does not exist\n";
|
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";
|
std::cerr << "Error: No home path supplied with \'--home'\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
if (!Utils::FileSystem::exists(argv[i + 1]) &&
|
if (!Utils::FileSystem::exists(argv[i + 1]) &&
|
||||||
(!Utils::FileSystem::driveExists(argv[i + 1]))) {
|
(!Utils::FileSystem::driveExists(argv[i + 1]))) {
|
||||||
#else
|
#else
|
||||||
if (!Utils::FileSystem::exists(argv[i + 1])) {
|
if (!Utils::FileSystem::exists(argv[i + 1])) {
|
||||||
#endif
|
#endif
|
||||||
std::cerr << "Error: Home path \'" << argv[i + 1] << "\' does not exist\n";
|
std::cerr << "Error: Home path \'" << argv[i + 1] << "\' does not exist\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Utils::FileSystem::isRegularFile(argv[i + 1])) {
|
if (Utils::FileSystem::isRegularFile(argv[i + 1])) {
|
||||||
std::cerr << "Error: Home path \'" << argv[i + 1] <<
|
std::cerr << "Error: Home path \'" << argv[i + 1]
|
||||||
"\' is a file and not a directory\n";
|
<< "\' is a file and not a directory\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Utils::FileSystem::setHomePath(argv[i + 1]);
|
Utils::FileSystem::setHomePath(argv[i + 1]);
|
||||||
|
@ -228,16 +228,16 @@ bool parseArgs(int argc, char* argv[])
|
||||||
std::string widthArg = argv[i + 1];
|
std::string widthArg = argv[i + 1];
|
||||||
std::string heightArg = argv[i + 2];
|
std::string heightArg = argv[i + 2];
|
||||||
if (widthArg.find_first_not_of("0123456789") != std::string::npos ||
|
if (widthArg.find_first_not_of("0123456789") != std::string::npos ||
|
||||||
heightArg.find_first_not_of("0123456789") != std::string::npos) {
|
heightArg.find_first_not_of("0123456789") != std::string::npos) {
|
||||||
std::cerr << "Error: Invalid resolution values supplied.\n";
|
std::cerr << "Error: Invalid resolution values supplied.\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int width = atoi(argv[i + 1]);
|
int width = atoi(argv[i + 1]);
|
||||||
int height = atoi(argv[i + 2]);
|
int height = atoi(argv[i + 2]);
|
||||||
if (width < 640 || height < 480 || width > 7680 || height > 4320 ||
|
if (width < 640 || height < 480 || width > 7680 || height > 4320 ||
|
||||||
height < width / 4 || width < height / 2) {
|
height < width / 4 || width < height / 2) {
|
||||||
std::cerr << "Error: Unsupported resolution "
|
std::cerr << "Error: Unsupported resolution " << width << "x" << height
|
||||||
<< width << "x" << height << " supplied.\n";
|
<< " supplied.\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Settings::getInstance()->setInt("WindowWidth", width);
|
Settings::getInstance()->setInt("WindowWidth", width);
|
||||||
|
@ -277,7 +277,8 @@ bool parseArgs(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
// On Unix, enable settings for the fullscreen mode.
|
// On Unix, enable settings for the fullscreen mode.
|
||||||
// On macOS and Windows only windowed mode is supported.
|
// On macOS and Windows only windowed mode is supported.
|
||||||
#if defined(__unix__)
|
|
||||||
|
#if defined(__unix__)
|
||||||
else if (strcmp(argv[i], "--windowed") == 0) {
|
else if (strcmp(argv[i], "--windowed") == 0) {
|
||||||
Settings::getInstance()->setBool("Windowed", true);
|
Settings::getInstance()->setBool("Windowed", true);
|
||||||
}
|
}
|
||||||
|
@ -289,7 +290,7 @@ bool parseArgs(int argc, char* argv[])
|
||||||
Settings::getInstance()->setString("FullscreenMode", "borderless");
|
Settings::getInstance()->setString("FullscreenMode", "borderless");
|
||||||
settingsNeedSaving = true;
|
settingsNeedSaving = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (strcmp(argv[i], "--vsync") == 0) {
|
else if (strcmp(argv[i], "--vsync") == 0) {
|
||||||
if (i >= argc - 1) {
|
if (i >= argc - 1) {
|
||||||
std::cerr << "Error: No VSync value supplied.\n";
|
std::cerr << "Error: No VSync value supplied.\n";
|
||||||
|
@ -297,7 +298,7 @@ bool parseArgs(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
std::string vSyncValue = argv[i + 1];
|
std::string vSyncValue = argv[i + 1];
|
||||||
if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" &&
|
if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" &&
|
||||||
vSyncValue != "0") {
|
vSyncValue != "0") {
|
||||||
std::cerr << "Error: Invalid VSync value supplied.\n";
|
std::cerr << "Error: Invalid VSync value supplied.\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -350,12 +351,12 @@ bool parseArgs(int argc, char* argv[])
|
||||||
Log::setReportingLevel(LogDebug);
|
Log::setReportingLevel(LogDebug);
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
||||||
std::cout <<
|
std::cout << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << "\n";
|
||||||
"EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << "\n";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||||
std::cout <<
|
std::cout <<
|
||||||
|
// clang-format off
|
||||||
"Usage: emulationstation [options]\n"
|
"Usage: emulationstation [options]\n"
|
||||||
"EmulationStation Desktop Edition, Emulator Front-end\n\n"
|
"EmulationStation Desktop Edition, Emulator Front-end\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
@ -381,6 +382,7 @@ bool parseArgs(int argc, char* argv[])
|
||||||
" --debug Print debug information\n"
|
" --debug Print debug information\n"
|
||||||
" --version, -v Display version information\n"
|
" --version, -v Display version information\n"
|
||||||
" --help, -h Summon a sentient, angry tuba\n";
|
" --help, -h Summon a sentient, angry tuba\n";
|
||||||
|
// clang-format on
|
||||||
return false; // Exit after printing help.
|
return false; // Exit after printing help.
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -400,13 +402,13 @@ bool checkApplicationHomeDirectory()
|
||||||
std::string home = Utils::FileSystem::getHomePath();
|
std::string home = Utils::FileSystem::getHomePath();
|
||||||
std::string applicationHome = home + "/.emulationstation";
|
std::string applicationHome = home + "/.emulationstation";
|
||||||
if (!Utils::FileSystem::exists(applicationHome)) {
|
if (!Utils::FileSystem::exists(applicationHome)) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::cout << "First startup, creating application home directory \"" <<
|
std::cout << "First startup, creating application home directory \""
|
||||||
Utils::String::replace(applicationHome, "/", "\\") << "\"\n";
|
<< Utils::String::replace(applicationHome, "/", "\\") << "\"\n";
|
||||||
#else
|
#else
|
||||||
std::cout << "First startup, creating application home directory \"" <<
|
std::cout << "First startup, creating application home directory \"" << applicationHome
|
||||||
applicationHome << "\"\n";
|
<< "\"\n";
|
||||||
#endif
|
#endif
|
||||||
Utils::FileSystem::createDirectory(applicationHome);
|
Utils::FileSystem::createDirectory(applicationHome);
|
||||||
if (!Utils::FileSystem::exists(applicationHome)) {
|
if (!Utils::FileSystem::exists(applicationHome)) {
|
||||||
std::cerr << "Fatal error: Couldn't create directory, permission problems?\n";
|
std::cerr << "Fatal error: Couldn't create directory, permission problems?\n";
|
||||||
|
@ -424,16 +426,16 @@ loadSystemsReturnCode loadSystemConfigFile()
|
||||||
|
|
||||||
if (SystemData::sSystemVector.size() == 0) {
|
if (SystemData::sSystemVector.size() == 0) {
|
||||||
LOG(LogError) << "No game files were found, make sure that the system directories are "
|
LOG(LogError) << "No game files were found, make sure that the system directories are "
|
||||||
"setup correctly and that the file extensions are supported";
|
"setup correctly and that the file extensions are supported";
|
||||||
return NO_ROMS;
|
return NO_ROMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LOADING_OK;
|
return LOADING_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called on exit, assuming we get far enough to have the log initialized.
|
|
||||||
void onExit()
|
void onExit()
|
||||||
{
|
{
|
||||||
|
// Called on exit, assuming we get far enough to have the log initialized.
|
||||||
Log::close();
|
Log::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,12 +445,12 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
std::locale::global(std::locale("C"));
|
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
|
// 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
|
// 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.
|
// removes the splash screen on startup and it may have other adverse effects as well.
|
||||||
std::string saveStateDir = Utils::FileSystem::expandHomePath(
|
std::string saveStateDir = Utils::FileSystem::expandHomePath(
|
||||||
"~/Library/Saved Application State/org.es-de.EmulationStation.savedState");
|
"~/Library/Saved Application State/org.es-de.EmulationStation.savedState");
|
||||||
// Deletion of the state files should normally not be required as there shouldn't be any
|
// Deletion of the state files should normally not be required as there shouldn't be any
|
||||||
// files to begin with. But maybe the files can still be created for unknown reasons
|
// files to begin with. But maybe the files can still be created for unknown reasons
|
||||||
// as macOS really really loves to restore windows. Let's therefore include this deletion
|
// as macOS really really loves to restore windows. Let's therefore include this deletion
|
||||||
|
@ -465,22 +467,22 @@ int main(int argc, char* argv[])
|
||||||
// the functionality.
|
// the functionality.
|
||||||
std::string chmodCommand = "chmod 500 \"" + saveStateDir + "\"";
|
std::string chmodCommand = "chmod 500 \"" + saveStateDir + "\"";
|
||||||
system(chmodCommand.c_str());
|
system(chmodCommand.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!parseArgs(argc, argv)) {
|
if (!parseArgs(argc, argv)) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
FreeConsole();
|
FreeConsole();
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// Send debug output to the console..
|
// Send debug output to the console..
|
||||||
if (Settings::getInstance()->getBool("Debug"))
|
if (Settings::getInstance()->getBool("Debug"))
|
||||||
outputToConsole(true);
|
outputToConsole(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// Hide taskbar if the setting for this is enabled.
|
// Hide taskbar if the setting for this is enabled.
|
||||||
bool taskbarStateChanged = false;
|
bool taskbarStateChanged = false;
|
||||||
unsigned int taskbarState;
|
unsigned int taskbarState;
|
||||||
|
@ -490,12 +492,12 @@ int main(int argc, char* argv[])
|
||||||
taskbarState = getTaskbarState();
|
taskbarState = getTaskbarState();
|
||||||
hideTaskbar();
|
hideTaskbar();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(FREEIMAGE_LIB)
|
||||||
// Call this ONLY when linking with FreeImage as a static library.
|
// Call this ONLY when linking with FreeImage as a static library.
|
||||||
#if defined(FREEIMAGE_LIB)
|
|
||||||
FreeImage_Initialise();
|
FreeImage_Initialise();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If ~/.emulationstation doesn't exist and cannot be created, bail.
|
// If ~/.emulationstation doesn't exist and cannot be created, bail.
|
||||||
if (!checkApplicationHomeDirectory())
|
if (!checkApplicationHomeDirectory())
|
||||||
|
@ -504,8 +506,8 @@ int main(int argc, char* argv[])
|
||||||
// Start the logger.
|
// Start the logger.
|
||||||
Log::init();
|
Log::init();
|
||||||
Log::open();
|
Log::open();
|
||||||
LOG(LogInfo) << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING <<
|
LOG(LogInfo) << "EmulationStation Desktop Edition v" << PROGRAM_VERSION_STRING << ", built "
|
||||||
", built " << PROGRAM_BUILT_STRING;
|
<< PROGRAM_BUILT_STRING;
|
||||||
|
|
||||||
// Always close the log on exit.
|
// Always close the log on exit.
|
||||||
atexit(&onExit);
|
atexit(&onExit);
|
||||||
|
@ -513,7 +515,7 @@ int main(int argc, char* argv[])
|
||||||
// Check if the configuration file exists, and if not, create it.
|
// Check if the configuration file exists, and if not, create it.
|
||||||
// This should only happen on first application startup.
|
// This should only happen on first application startup.
|
||||||
if (!Utils::FileSystem::exists(Utils::FileSystem::getHomePath() +
|
if (!Utils::FileSystem::exists(Utils::FileSystem::getHomePath() +
|
||||||
"/.emulationstation/es_settings.xml")) {
|
"/.emulationstation/es_settings.xml")) {
|
||||||
LOG(LogInfo) << "Settings file es_settings.xml does not exist, creating it...";
|
LOG(LogInfo) << "Settings file es_settings.xml does not exist, creating it...";
|
||||||
Settings::getInstance()->saveFile();
|
Settings::getInstance()->saveFile();
|
||||||
}
|
}
|
||||||
|
@ -525,15 +527,15 @@ int main(int argc, char* argv[])
|
||||||
// Check if the application version has changed, which would normally mean that the
|
// Check if the application version has changed, which would normally mean that the
|
||||||
// user has upgraded to a newer release.
|
// user has upgraded to a newer release.
|
||||||
std::string applicationVersion;
|
std::string applicationVersion;
|
||||||
if ((applicationVersion = Settings::getInstance()->
|
if ((applicationVersion = Settings::getInstance()->getString("ApplicationVersion")) !=
|
||||||
getString("ApplicationVersion")) != PROGRAM_VERSION_STRING) {
|
PROGRAM_VERSION_STRING) {
|
||||||
if (applicationVersion != "") {
|
if (applicationVersion != "") {
|
||||||
LOG(LogInfo) << "Application version changed from previous startup, from \"" <<
|
LOG(LogInfo) << "Application version changed from previous startup, from \""
|
||||||
applicationVersion << "\" to \"" << PROGRAM_VERSION_STRING << "\"";
|
<< applicationVersion << "\" to \"" << PROGRAM_VERSION_STRING << "\"";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogInfo) << "Application version setting is blank, changing it to \"" <<
|
LOG(LogInfo) << "Application version setting is blank, changing it to \""
|
||||||
PROGRAM_VERSION_STRING << "\"";
|
<< PROGRAM_VERSION_STRING << "\"";
|
||||||
}
|
}
|
||||||
Settings::getInstance()->setString("ApplicationVersion", PROGRAM_VERSION_STRING);
|
Settings::getInstance()->setString("ApplicationVersion", PROGRAM_VERSION_STRING);
|
||||||
Settings::getInstance()->saveFile();
|
Settings::getInstance()->saveFile();
|
||||||
|
@ -582,11 +584,11 @@ int main(int argc, char* argv[])
|
||||||
if (event.type == SDL_QUIT)
|
if (event.type == SDL_QUIT)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
#if !defined(__APPLE__)
|
||||||
// This hides the mouse cursor during startup, i.e. before we have begun to capture SDL events.
|
// 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.
|
// 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);
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (splashScreen) {
|
if (splashScreen) {
|
||||||
std::string progressText = "Loading...";
|
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.
|
// Open the input configuration GUI if the flag to force this was passed from the command line.
|
||||||
if (!loadSystemsStatus) {
|
if (!loadSystemsStatus) {
|
||||||
if (forceInputConfig) {
|
if (forceInputConfig) {
|
||||||
window.pushGui(new GuiDetectDevice(&window, false, true, [] {
|
window.pushGui(new GuiDetectDevice(&window, false, true,
|
||||||
ViewController::get()->goToStart(); }));
|
[] { ViewController::get()->goToStart(); }));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ViewController::get()->goToStart();
|
ViewController::get()->goToStart();
|
||||||
|
@ -639,16 +641,19 @@ int main(int argc, char* argv[])
|
||||||
int lastTime = SDL_GetTicks();
|
int lastTime = SDL_GetTicks();
|
||||||
const auto applicationEndTime = std::chrono::system_clock::now();
|
const auto applicationEndTime = std::chrono::system_clock::now();
|
||||||
|
|
||||||
LOG(LogInfo) << "Application startup time: " <<
|
LOG(LogInfo) << "Application startup time: "
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(applicationEndTime -
|
||||||
(applicationEndTime - applicationStartTime).count() << " ms";
|
applicationStartTime)
|
||||||
|
.count()
|
||||||
|
<< " ms";
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
|
#if !defined(__APPLE__)
|
||||||
// Now that we've finished loading, disable the relative mouse mode or otherwise mouse
|
// Now that we've finished loading, disable the relative mouse mode or otherwise mouse
|
||||||
// input wouldn't work in any games that are launched.
|
// input wouldn't work in any games that are launched.
|
||||||
#if !defined(__APPLE__)
|
|
||||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
if (SDL_PollEvent(&event)) {
|
if (SDL_PollEvent(&event)) {
|
||||||
|
@ -657,8 +662,8 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (event.type == SDL_QUIT)
|
if (event.type == SDL_QUIT)
|
||||||
running = false;
|
running = false;
|
||||||
}
|
|
||||||
while (SDL_PollEvent(&event));
|
} while (SDL_PollEvent(&event));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.isSleeping()) {
|
if (window.isSleeping()) {
|
||||||
|
@ -694,24 +699,24 @@ int main(int argc, char* argv[])
|
||||||
NavigationSounds::getInstance()->deinit();
|
NavigationSounds::getInstance()->deinit();
|
||||||
Settings::deinit();
|
Settings::deinit();
|
||||||
|
|
||||||
|
#if defined(FREEIMAGE_LIB)
|
||||||
// Call this ONLY when linking with FreeImage as a static library.
|
// Call this ONLY when linking with FreeImage as a static library.
|
||||||
#if defined(FREEIMAGE_LIB)
|
|
||||||
FreeImage_DeInitialise();
|
FreeImage_DeInitialise();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// If the taskbar state was changed (taskbar was hidden), then revert it.
|
// If the taskbar state was changed (taskbar was hidden), then revert it.
|
||||||
if (taskbarStateChanged)
|
if (taskbarStateChanged)
|
||||||
revertTaskbarState(taskbarState);
|
revertTaskbarState(taskbarState);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
processQuitMode();
|
processQuitMode();
|
||||||
|
|
||||||
LOG(LogInfo) << "EmulationStation cleanly shutting down";
|
LOG(LogInfo) << "EmulationStation cleanly shutting down";
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
FreeConsole();
|
FreeConsole();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,20 @@
|
||||||
#include "scrapers/GamesDBJSONScraper.h"
|
#include "scrapers/GamesDBJSONScraper.h"
|
||||||
#include "scrapers/GamesDBJSONScraperResources.h"
|
#include "scrapers/GamesDBJSONScraperResources.h"
|
||||||
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "utils/TimeUtil.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "MameNames.h"
|
#include "MameNames.h"
|
||||||
#include "PlatformId.h"
|
#include "PlatformId.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "utils/TimeUtil.h"
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
|
||||||
#include <rapidjson/error/en.h>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
|
|
||||||
using namespace PlatformIds;
|
using namespace PlatformIds;
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
@ -103,10 +103,10 @@ const std::map<PlatformId, std::string> gamesdb_new_platformid_map {
|
||||||
{ SONY_PLAYSTATION_PORTABLE, "13" },
|
{ SONY_PLAYSTATION_PORTABLE, "13" },
|
||||||
{ SUPER_NINTENDO, "6" },
|
{ SUPER_NINTENDO, "6" },
|
||||||
{ SHARP_X1, "4977" },
|
{ SHARP_X1, "4977" },
|
||||||
{ SHARP_X68000, "4931"},
|
{ SHARP_X68000, "4931" },
|
||||||
{ NEC_SUPERGRAFX, "34" },
|
{ NEC_SUPERGRAFX, "34" },
|
||||||
{ NEC_PC_8800, "4933"},
|
{ NEC_PC_8800, "4933" },
|
||||||
{ NEC_PC_9800, "4934"},
|
{ NEC_PC_9800, "4934" },
|
||||||
{ NEC_PC_ENGINE, "34" },
|
{ NEC_PC_ENGINE, "34" },
|
||||||
{ NEC_PC_ENGINE_CD, "4955" },
|
{ NEC_PC_ENGINE_CD, "4955" },
|
||||||
{ BANDAI_WONDERSWAN, "4925" },
|
{ BANDAI_WONDERSWAN, "4925" },
|
||||||
|
@ -118,9 +118,10 @@ const std::map<PlatformId, std::string> gamesdb_new_platformid_map {
|
||||||
{ TANDY_TRS80, "4941" },
|
{ TANDY_TRS80, "4941" },
|
||||||
};
|
};
|
||||||
|
|
||||||
void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params,
|
void thegamesdb_generate_json_scraper_requests(
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
const ScraperSearchParams& params,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
resources.prepare();
|
resources.prepare();
|
||||||
std::string path = "https://api.thegamesdb.net/v1";
|
std::string path = "https://api.thegamesdb.net/v1";
|
||||||
|
@ -168,8 +169,8 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
||||||
if (!platforms.empty()) {
|
if (!platforms.empty()) {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
platformQueryParam += "&filter%5Bplatform%5D=";
|
platformQueryParam += "&filter%5Bplatform%5D=";
|
||||||
for (auto platformIt = platforms.cbegin();
|
for (auto platformIt = platforms.cbegin(); // Line break.
|
||||||
platformIt != platforms.cend(); platformIt++) {
|
platformIt != platforms.cend(); platformIt++) {
|
||||||
auto mapIt = gamesdb_new_platformid_map.find(*platformIt);
|
auto mapIt = gamesdb_new_platformid_map.find(*platformIt);
|
||||||
if (mapIt != gamesdb_new_platformid_map.cend()) {
|
if (mapIt != gamesdb_new_platformid_map.cend()) {
|
||||||
if (!first)
|
if (!first)
|
||||||
|
@ -178,8 +179,9 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogWarning) << "TheGamesDB scraper: No support for platform \"" <<
|
LOG(LogWarning)
|
||||||
getPlatformName(*platformIt) << "\", search will be inaccurate";
|
<< "TheGamesDB scraper: No support for platform \""
|
||||||
|
<< getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path += platformQueryParam;
|
path += platformQueryParam;
|
||||||
|
@ -188,15 +190,15 @@ void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params
|
||||||
LOG(LogWarning) << "TheGamesDB scraper: No platform defined, search will be inaccurate";
|
LOG(LogWarning) << "TheGamesDB scraper: No platform defined, search will be inaccurate";
|
||||||
}
|
}
|
||||||
|
|
||||||
requests.push(std::unique_ptr<ScraperRequest>
|
requests.push(
|
||||||
(new TheGamesDBJSONRequest(requests, results, path)));
|
std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void thegamesdb_generate_json_scraper_requests(
|
void thegamesdb_generate_json_scraper_requests(
|
||||||
const std::string& gameIDs,
|
const std::string& gameIDs,
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
resources.prepare();
|
resources.prepare();
|
||||||
std::string path = "https://api.thegamesdb.net/v1";
|
std::string path = "https://api.thegamesdb.net/v1";
|
||||||
|
@ -204,158 +206,158 @@ void thegamesdb_generate_json_scraper_requests(
|
||||||
|
|
||||||
path += "/Games/Images/GamesImages?" + apiKey + "&games_id=" + gameIDs;
|
path += "/Games/Images/GamesImages?" + apiKey + "&games_id=" + gameIDs;
|
||||||
|
|
||||||
requests.push(std::unique_ptr<ScraperRequest>
|
requests.push(
|
||||||
(new TheGamesDBJSONRequest(requests, results, path)));
|
std::unique_ptr<ScraperRequest>(new TheGamesDBJSONRequest(requests, results, path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
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()) {
|
||||||
if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsString()) {
|
throw std::runtime_error(
|
||||||
throw std::runtime_error(
|
|
||||||
"rapidjson internal assertion failure: missing or non string key:" + key);
|
"rapidjson internal assertion failure: missing or non string key:" + key);
|
||||||
|
}
|
||||||
|
return v[key.c_str()].GetString();
|
||||||
}
|
}
|
||||||
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()) {
|
if (!v.HasMember(key.c_str()) || !v[key.c_str()].IsInt()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"rapidjson internal assertion failure: missing or non int key:" + key);
|
"rapidjson internal assertion failure: missing or non int key:" + key);
|
||||||
}
|
}
|
||||||
return v[key.c_str()].GetInt();
|
return v[key.c_str()].GetInt();
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (!v.IsArray())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
std::string out = "";
|
|
||||||
bool first = true;
|
|
||||||
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
|
||||||
auto mapIt = resources.gamesdb_new_developers_map.find(getIntOrThrow(v[i]));
|
|
||||||
|
|
||||||
if (mapIt == resources.gamesdb_new_developers_map.cend())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!first)
|
|
||||||
out += ", ";
|
|
||||||
|
|
||||||
out += mapIt->second;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getPublisherString(const Value& v)
|
|
||||||
{
|
|
||||||
if (!v.IsArray())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
std::string out = "";
|
|
||||||
bool first = true;
|
|
||||||
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
|
||||||
auto mapIt = resources.gamesdb_new_publishers_map.find(getIntOrThrow(v[i]));
|
|
||||||
|
|
||||||
if (mapIt == resources.gamesdb_new_publishers_map.cend())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!first)
|
|
||||||
out += ", ";
|
|
||||||
|
|
||||||
out += mapIt->second;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getGenreString(const Value& v)
|
|
||||||
{
|
|
||||||
if (!v.IsArray())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
std::string out = "";
|
|
||||||
bool first = true;
|
|
||||||
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
|
||||||
auto mapIt = resources.gamesdb_new_genres_map.find(getIntOrThrow(v[i]));
|
|
||||||
|
|
||||||
if (mapIt == resources.gamesdb_new_genres_map.cend())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!first)
|
|
||||||
out += ", ";
|
|
||||||
|
|
||||||
out += mapIt->second;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void processGame(const Value& game, std::vector<ScraperSearchResult>& results)
|
|
||||||
{
|
|
||||||
ScraperSearchResult result;
|
|
||||||
|
|
||||||
if (game.HasMember("id") && game["id"].IsInt())
|
|
||||||
result.gameID = std::to_string(getIntOrThrow(game, "id"));
|
|
||||||
|
|
||||||
result.mdl.set("name", getStringOrThrow(game, "game_title"));
|
|
||||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Name: " << result.mdl.get("name");
|
|
||||||
|
|
||||||
if (game.HasMember("overview") && game["overview"].IsString())
|
|
||||||
result.mdl.set("desc", Utils::String::replace(game["overview"].GetString(), "\r", ""));
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.HasMember("developers") && game["developers"].IsArray()) {
|
int getIntOrThrow(const Value& v)
|
||||||
result.mdl.set("developer", getDeveloperString(game["developers"]));
|
{
|
||||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Developer: " <<
|
if (!v.IsInt()) {
|
||||||
result.mdl.get("developer");
|
throw std::runtime_error("rapidjson internal assertion failure: not an int");
|
||||||
|
}
|
||||||
|
return v.GetInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.HasMember("publishers") && game["publishers"].IsArray()) {
|
std::string getDeveloperString(const Value& v)
|
||||||
result.mdl.set("publisher", getPublisherString(game["publishers"]));
|
{
|
||||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Publisher: " <<
|
if (!v.IsArray())
|
||||||
result.mdl.get("publisher");
|
return "";
|
||||||
|
|
||||||
|
std::string out = "";
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
||||||
|
auto mapIt = resources.gamesdb_new_developers_map.find(getIntOrThrow(v[i]));
|
||||||
|
|
||||||
|
if (mapIt == resources.gamesdb_new_developers_map.cend())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
out += ", ";
|
||||||
|
|
||||||
|
out += mapIt->second;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.HasMember("genres") && game["genres"].IsArray()) {
|
std::string getPublisherString(const Value& v)
|
||||||
result.mdl.set("genre", getGenreString(game["genres"]));
|
{
|
||||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Genre: " <<
|
if (!v.IsArray())
|
||||||
result.mdl.get("genre");
|
return "";
|
||||||
|
|
||||||
|
std::string out = "";
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
||||||
|
auto mapIt = resources.gamesdb_new_publishers_map.find(getIntOrThrow(v[i]));
|
||||||
|
|
||||||
|
if (mapIt == resources.gamesdb_new_publishers_map.cend())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
out += ", ";
|
||||||
|
|
||||||
|
out += mapIt->second;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.HasMember("players") && game["players"].IsInt()) {
|
std::string getGenreString(const Value& v)
|
||||||
result.mdl.set("players", std::to_string(game["players"].GetInt()));
|
{
|
||||||
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Players: " <<
|
if (!v.IsArray())
|
||||||
result.mdl.get("players");
|
return "";
|
||||||
|
|
||||||
|
std::string out = "";
|
||||||
|
bool first = true;
|
||||||
|
for (int i = 0; i < static_cast<int>(v.Size()); i++) {
|
||||||
|
auto mapIt = resources.gamesdb_new_genres_map.find(getIntOrThrow(v[i]));
|
||||||
|
|
||||||
|
if (mapIt == resources.gamesdb_new_genres_map.cend())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
out += ", ";
|
||||||
|
|
||||||
|
out += mapIt->second;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.mediaURLFetch = NOT_STARTED;
|
void processGame(const Value& game, std::vector<ScraperSearchResult>& results)
|
||||||
results.push_back(result);
|
{
|
||||||
}
|
ScraperSearchResult result;
|
||||||
|
|
||||||
|
if (game.HasMember("id") && game["id"].IsInt())
|
||||||
|
result.gameID = std::to_string(getIntOrThrow(game, "id"));
|
||||||
|
|
||||||
|
result.mdl.set("name", getStringOrThrow(game, "game_title"));
|
||||||
|
LOG(LogDebug) << "GamesDBJSONScraper::processGame(): Name: " << result.mdl.get("name");
|
||||||
|
|
||||||
|
if (game.HasMember("overview") && game["overview"].IsString())
|
||||||
|
result.mdl.set("desc", Utils::String::replace(game["overview"].GetString(), "\r", ""));
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game.HasMember("developers") && game["developers"].IsArray()) {
|
||||||
|
result.mdl.set("developer", getDeveloperString(game["developers"]));
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game.HasMember("genres") && game["genres"].IsArray()) {
|
||||||
|
result.mdl.set("genre", getGenreString(game["genres"]));
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.mediaURLFetch = NOT_STARTED;
|
||||||
|
results.push_back(result);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void processMediaURLs(const Value& images, const std::string& base_url,
|
void processMediaURLs(const Value& images,
|
||||||
std::vector<ScraperSearchResult>& results)
|
const std::string& base_url,
|
||||||
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
ScraperSearchResult result;
|
ScraperSearchResult result;
|
||||||
|
|
||||||
|
@ -367,9 +369,8 @@ void processMediaURLs(const Value& images, const std::string& base_url,
|
||||||
result.marqueeUrl = "";
|
result.marqueeUrl = "";
|
||||||
result.screenshotUrl = "";
|
result.screenshotUrl = "";
|
||||||
|
|
||||||
// Quite excessive testing for valid values, but you never know
|
// Quite excessive testing for valid values, but you never know what the server has
|
||||||
// what the server has returned and we don't want to crash the
|
// returned and we don't want to crash the program due to malformed data.
|
||||||
// program due to malformed data.
|
|
||||||
if (gameMedia.IsArray()) {
|
if (gameMedia.IsArray()) {
|
||||||
for (SizeType i = 0; i < gameMedia.Size(); i++) {
|
for (SizeType i = 0; i < gameMedia.Size(); i++) {
|
||||||
std::string mediatype;
|
std::string mediatype;
|
||||||
|
@ -390,13 +391,13 @@ void processMediaURLs(const Value& images, const std::string& base_url,
|
||||||
result.screenshotUrl = base_url + gameMedia[i]["filename"].GetString();
|
result.screenshotUrl = base_url + gameMedia[i]["filename"].GetString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.mediaURLFetch = COMPLETED;
|
result.mediaURLFetch = COMPLETED;
|
||||||
results.push_back(result);
|
results.push_back(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
assert(req->status() == HttpReq::REQ_SUCCESS);
|
assert(req->status() == HttpReq::REQ_SUCCESS);
|
||||||
|
|
||||||
|
@ -404,9 +405,8 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
doc.Parse(req->getContent().c_str());
|
doc.Parse(req->getContent().c_str());
|
||||||
|
|
||||||
if (doc.HasParseError()) {
|
if (doc.HasParseError()) {
|
||||||
std::string err =
|
std::string err = std::string("TheGamesDBJSONRequest - Error parsing JSON \n\t") +
|
||||||
std::string("TheGamesDBJSONRequest - Error parsing JSON \n\t") +
|
GetParseError_En(doc.GetParseError());
|
||||||
GetParseError_En(doc.GetParseError());
|
|
||||||
setError(err);
|
setError(err);
|
||||||
LOG(LogError) << err;
|
LOG(LogError) << err;
|
||||||
return;
|
return;
|
||||||
|
@ -414,7 +414,7 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
|
|
||||||
// If the response contains the 'images' object, then it's a game media URL request.
|
// If the response contains the 'images' object, then it's a game media URL request.
|
||||||
if (doc.HasMember("data") && doc["data"].HasMember("images") &&
|
if (doc.HasMember("data") && doc["data"].HasMember("images") &&
|
||||||
doc["data"]["images"].IsObject()) {
|
doc["data"]["images"].IsObject()) {
|
||||||
|
|
||||||
const Value& images = doc["data"]["images"];
|
const Value& images = doc["data"]["images"];
|
||||||
const Value& base_url = doc["data"]["base_url"];
|
const Value& base_url = doc["data"]["base_url"];
|
||||||
|
@ -440,19 +440,18 @@ void TheGamesDBJSONRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
if (doc.HasMember("remaining_monthly_allowance") && doc.HasMember("extra_allowance")) {
|
if (doc.HasMember("remaining_monthly_allowance") && doc.HasMember("extra_allowance")) {
|
||||||
for (auto i = 0; i < results.size(); i++) {
|
for (auto i = 0; i < results.size(); i++) {
|
||||||
results[i].scraperRequestAllowance =
|
results[i].scraperRequestAllowance =
|
||||||
doc["remaining_monthly_allowance"].GetInt() +
|
doc["remaining_monthly_allowance"].GetInt() + doc["extra_allowance"].GetInt();
|
||||||
doc["extra_allowance"].GetInt();
|
|
||||||
}
|
}
|
||||||
LOG(LogDebug) << "TheGamesDBJSONRequest::process(): "
|
LOG(LogDebug) << "TheGamesDBJSONRequest::process(): "
|
||||||
"Remaining monthly scraping allowance: " <<
|
"Remaining monthly scraping allowance: "
|
||||||
results.back().scraperRequestAllowance;
|
<< results.back().scraperRequestAllowance;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These process steps are for the initial scraping response.
|
// These process steps are for the initial scraping response.
|
||||||
if (!doc.HasMember("data") || !doc["data"].HasMember("games") ||
|
if (!doc.HasMember("data") || !doc["data"].HasMember("games") ||
|
||||||
!doc["data"]["games"].IsArray()) {
|
!doc["data"]["games"].IsArray()) {
|
||||||
LOG(LogWarning) << "TheGamesDBJSONRequest - Response had no game data\n";
|
LOG(LogWarning) << "TheGamesDBJSONRequest - Response had no game data\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,39 +12,42 @@
|
||||||
|
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
|
|
||||||
namespace pugi {
|
namespace pugi
|
||||||
|
{
|
||||||
class xml_document;
|
class xml_document;
|
||||||
}
|
}
|
||||||
|
|
||||||
void thegamesdb_generate_json_scraper_requests(const ScraperSearchParams& params,
|
void thegamesdb_generate_json_scraper_requests(
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
const ScraperSearchParams& params,
|
||||||
std::vector<ScraperSearchResult>& results);
|
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(
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
const std::string& gameIDs,
|
||||||
std::vector<ScraperSearchResult>& results);
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
|
std::vector<ScraperSearchResult>& results);
|
||||||
|
|
||||||
class TheGamesDBJSONRequest : public ScraperHttpRequest
|
class TheGamesDBJSONRequest : public ScraperHttpRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Constructor for a GetGameList request.
|
// Constructor for a GetGameList request.
|
||||||
TheGamesDBJSONRequest(
|
TheGamesDBJSONRequest(std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
std::vector<ScraperSearchResult>& resultsWrite,
|
||||||
std::vector<ScraperSearchResult>& resultsWrite,
|
const std::string& url)
|
||||||
const std::string& url)
|
: ScraperHttpRequest(resultsWrite, url)
|
||||||
: ScraperHttpRequest(resultsWrite, url),
|
, mRequestQueue(&requestsWrite)
|
||||||
mRequestQueue(&requestsWrite)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
// Constructior for a GetGame request
|
// Constructior for a GetGame request
|
||||||
TheGamesDBJSONRequest(std::vector<ScraperSearchResult>& resultsWrite, const std::string& url)
|
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,
|
void process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::vector<ScraperSearchResult>& results) override;
|
std::vector<ScraperSearchResult>& results) override;
|
||||||
bool isGameRequest() { return !mRequestQueue; }
|
bool isGameRequest() { return !mRequestQueue; }
|
||||||
|
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>* mRequestQueue;
|
std::queue<std::unique_ptr<ScraperRequest>>* mRequestQueue;
|
||||||
|
|
|
@ -14,52 +14,53 @@
|
||||||
|
|
||||||
#include "scrapers/GamesDBJSONScraperResources.h"
|
#include "scrapers/GamesDBJSONScraperResources.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
|
||||||
#include <rapidjson/error/en.h>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
constexpr char GamesDBAPIKey[] =
|
{
|
||||||
|
constexpr char GamesDBAPIKey[] =
|
||||||
"445fcbc3f32bb2474bc27016b99eb963d318ee3a608212c543b9a79de1041600";
|
"445fcbc3f32bb2474bc27016b99eb963d318ee3a608212c543b9a79de1041600";
|
||||||
|
|
||||||
constexpr int MAX_WAIT_MS = 90000;
|
constexpr int MAX_WAIT_MS = 90000;
|
||||||
constexpr int POLL_TIME_MS = 500;
|
constexpr int POLL_TIME_MS = 500;
|
||||||
constexpr int MAX_WAIT_ITER = MAX_WAIT_MS / POLL_TIME_MS;
|
constexpr int MAX_WAIT_ITER = MAX_WAIT_MS / POLL_TIME_MS;
|
||||||
|
|
||||||
constexpr char SCRAPER_RESOURCES_DIR[] = "scrapers";
|
constexpr char SCRAPER_RESOURCES_DIR[] = "scrapers";
|
||||||
constexpr char DEVELOPERS_JSON_FILE[] = "gamesdb_developers.json";
|
constexpr char DEVELOPERS_JSON_FILE[] = "gamesdb_developers.json";
|
||||||
constexpr char PUBLISHERS_JSON_FILE[] = "gamesdb_publishers.json";
|
constexpr char PUBLISHERS_JSON_FILE[] = "gamesdb_publishers.json";
|
||||||
constexpr char GENRES_JSON_FILE[] = "gamesdb_genres.json";
|
constexpr char GENRES_JSON_FILE[] = "gamesdb_genres.json";
|
||||||
constexpr char DEVELOPERS_ENDPOINT[] = "/Developers";
|
constexpr char DEVELOPERS_ENDPOINT[] = "/Developers";
|
||||||
constexpr char PUBLISHERS_ENDPOINT[] = "/Publishers";
|
constexpr char PUBLISHERS_ENDPOINT[] = "/Publishers";
|
||||||
constexpr char GENRES_ENDPOINT[] = "/Genres";
|
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);
|
return Utils::FileSystem::getGenericPath(getScrapersResouceDir() + "/" + file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensureScrapersResourcesDir()
|
void ensureScrapersResourcesDir()
|
||||||
{
|
{
|
||||||
std::string path = getScrapersResouceDir();
|
std::string path = getScrapersResouceDir();
|
||||||
if (!Utils::FileSystem::exists(path))
|
if (!Utils::FileSystem::exists(path))
|
||||||
Utils::FileSystem::createDirectory(path);
|
Utils::FileSystem::createDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::string getScrapersResouceDir()
|
std::string getScrapersResouceDir()
|
||||||
{
|
{
|
||||||
return Utils::FileSystem::getGenericPath(
|
return Utils::FileSystem::getGenericPath(Utils::FileSystem::getHomePath() +
|
||||||
Utils::FileSystem::getHomePath() + "/.emulationstation/" + SCRAPER_RESOURCES_DIR);
|
"/.emulationstation/" + SCRAPER_RESOURCES_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TheGamesDBJSONRequestResources::getApiKey() const { return GamesDBAPIKey; }
|
std::string TheGamesDBJSONRequestResources::getApiKey() const { return GamesDBAPIKey; }
|
||||||
|
@ -69,16 +70,16 @@ void TheGamesDBJSONRequestResources::prepare()
|
||||||
if (checkLoaded())
|
if (checkLoaded())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (loadResource(gamesdb_new_developers_map, "developers",
|
if (loadResource(gamesdb_new_developers_map, "developers", genFilePath(DEVELOPERS_JSON_FILE)) &&
|
||||||
genFilePath(DEVELOPERS_JSON_FILE)) && !gamesdb_developers_resource_request)
|
!gamesdb_developers_resource_request)
|
||||||
gamesdb_developers_resource_request = fetchResource(DEVELOPERS_ENDPOINT);
|
gamesdb_developers_resource_request = fetchResource(DEVELOPERS_ENDPOINT);
|
||||||
|
|
||||||
if (loadResource(gamesdb_new_publishers_map, "publishers",
|
if (loadResource(gamesdb_new_publishers_map, "publishers", genFilePath(PUBLISHERS_JSON_FILE)) &&
|
||||||
genFilePath(PUBLISHERS_JSON_FILE)) && !gamesdb_publishers_resource_request)
|
!gamesdb_publishers_resource_request)
|
||||||
gamesdb_publishers_resource_request = fetchResource(PUBLISHERS_ENDPOINT);
|
gamesdb_publishers_resource_request = fetchResource(PUBLISHERS_ENDPOINT);
|
||||||
|
|
||||||
if (loadResource(gamesdb_new_genres_map, "genres",
|
if (loadResource(gamesdb_new_genres_map, "genres", genFilePath(GENRES_JSON_FILE)) &&
|
||||||
genFilePath(GENRES_JSON_FILE)) && !gamesdb_genres_resource_request)
|
!gamesdb_genres_resource_request)
|
||||||
gamesdb_genres_resource_request = fetchResource(GENRES_ENDPOINT);
|
gamesdb_genres_resource_request = fetchResource(GENRES_ENDPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,21 +91,22 @@ void TheGamesDBJSONRequestResources::ensureResources()
|
||||||
for (int i = 0; i < MAX_WAIT_ITER; i++) {
|
for (int i = 0; i < MAX_WAIT_ITER; i++) {
|
||||||
|
|
||||||
if (gamesdb_developers_resource_request &&
|
if (gamesdb_developers_resource_request &&
|
||||||
saveResource(gamesdb_developers_resource_request.get(),
|
saveResource(gamesdb_developers_resource_request.get(), gamesdb_new_developers_map,
|
||||||
gamesdb_new_developers_map, "developers", genFilePath(DEVELOPERS_JSON_FILE)))
|
"developers", genFilePath(DEVELOPERS_JSON_FILE)))
|
||||||
gamesdb_developers_resource_request.reset(nullptr);
|
gamesdb_developers_resource_request.reset(nullptr);
|
||||||
|
|
||||||
if (gamesdb_publishers_resource_request &&
|
if (gamesdb_publishers_resource_request &&
|
||||||
saveResource(gamesdb_publishers_resource_request.get(),
|
saveResource(gamesdb_publishers_resource_request.get(), gamesdb_new_publishers_map,
|
||||||
gamesdb_new_publishers_map, "publishers", genFilePath(PUBLISHERS_JSON_FILE)))
|
"publishers", genFilePath(PUBLISHERS_JSON_FILE)))
|
||||||
gamesdb_publishers_resource_request.reset(nullptr);
|
gamesdb_publishers_resource_request.reset(nullptr);
|
||||||
|
|
||||||
if (gamesdb_genres_resource_request && saveResource(gamesdb_genres_resource_request.get(),
|
if (gamesdb_genres_resource_request &&
|
||||||
gamesdb_new_genres_map, "genres", genFilePath(GENRES_JSON_FILE)))
|
saveResource(gamesdb_genres_resource_request.get(), gamesdb_new_genres_map, "genres",
|
||||||
|
genFilePath(GENRES_JSON_FILE)))
|
||||||
gamesdb_genres_resource_request.reset(nullptr);
|
gamesdb_genres_resource_request.reset(nullptr);
|
||||||
|
|
||||||
if (!gamesdb_developers_resource_request && !gamesdb_publishers_resource_request &&
|
if (!gamesdb_developers_resource_request && !gamesdb_publishers_resource_request &&
|
||||||
!gamesdb_genres_resource_request)
|
!gamesdb_genres_resource_request)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(POLL_TIME_MS));
|
std::this_thread::sleep_for(std::chrono::milliseconds(POLL_TIME_MS));
|
||||||
|
@ -115,14 +117,13 @@ void TheGamesDBJSONRequestResources::ensureResources()
|
||||||
bool TheGamesDBJSONRequestResources::checkLoaded()
|
bool TheGamesDBJSONRequestResources::checkLoaded()
|
||||||
{
|
{
|
||||||
return !gamesdb_new_genres_map.empty() && !gamesdb_new_developers_map.empty() &&
|
return !gamesdb_new_genres_map.empty() && !gamesdb_new_developers_map.empty() &&
|
||||||
!gamesdb_new_publishers_map.empty();
|
!gamesdb_new_publishers_map.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TheGamesDBJSONRequestResources::saveResource(
|
bool TheGamesDBJSONRequestResources::saveResource(HttpReq* req,
|
||||||
HttpReq* req,
|
std::unordered_map<int, std::string>& resource,
|
||||||
std::unordered_map<int, std::string>& resource,
|
const std::string& resource_name,
|
||||||
const std::string& resource_name,
|
const std::string& file_name)
|
||||||
const std::string& file_name)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (req == nullptr) {
|
if (req == nullptr) {
|
||||||
|
@ -133,8 +134,8 @@ bool TheGamesDBJSONRequestResources::saveResource(
|
||||||
return false; // Not ready: wait some more.
|
return false; // Not ready: wait some more.
|
||||||
}
|
}
|
||||||
if (req->status() != HttpReq::REQ_SUCCESS) {
|
if (req->status() != HttpReq::REQ_SUCCESS) {
|
||||||
LOG(LogError) << "Resource request for " << file_name <<
|
LOG(LogError) << "Resource request for " << file_name << " failed:\n\t"
|
||||||
" failed:\n\t" << req->getErrorMsg();
|
<< req->getErrorMsg();
|
||||||
return true; // Request failed, resetting request..
|
return true; // Request failed, resetting request..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,10 +157,9 @@ std::unique_ptr<HttpReq> TheGamesDBJSONRequestResources::fetchResource(const std
|
||||||
return std::unique_ptr<HttpReq>(new HttpReq(path));
|
return std::unique_ptr<HttpReq>(new HttpReq(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
int TheGamesDBJSONRequestResources::loadResource(
|
int TheGamesDBJSONRequestResources::loadResource(std::unordered_map<int, std::string>& resource,
|
||||||
std::unordered_map<int, std::string>& resource,
|
const std::string& resource_name,
|
||||||
const std::string& resource_name,
|
const std::string& file_name)
|
||||||
const std::string& file_name)
|
|
||||||
{
|
{
|
||||||
std::ifstream fin(file_name);
|
std::ifstream fin(file_name);
|
||||||
if (!fin.good())
|
if (!fin.good())
|
||||||
|
@ -172,8 +172,8 @@ int TheGamesDBJSONRequestResources::loadResource(
|
||||||
|
|
||||||
if (doc.HasParseError()) {
|
if (doc.HasParseError()) {
|
||||||
std::string err = std::string("TheGamesDBJSONRequest - "
|
std::string err = std::string("TheGamesDBJSONRequest - "
|
||||||
"Error parsing JSON for resource file ") + file_name +
|
"Error parsing JSON for resource file ") +
|
||||||
":\n\t" + GetParseError_En(doc.GetParseError());
|
file_name + ":\n\t" + GetParseError_En(doc.GetParseError());
|
||||||
LOG(LogError) << err;
|
LOG(LogError) << err;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ int TheGamesDBJSONRequestResources::loadResource(
|
||||||
for (Value::ConstMemberIterator itr = data.MemberBegin(); itr != data.MemberEnd(); itr++) {
|
for (Value::ConstMemberIterator itr = data.MemberBegin(); itr != data.MemberEnd(); itr++) {
|
||||||
auto& entry = itr->value;
|
auto& entry = itr->value;
|
||||||
if (!entry.IsObject() || !entry.HasMember("id") || !entry["id"].IsInt() ||
|
if (!entry.IsObject() || !entry.HasMember("id") || !entry["id"].IsInt() ||
|
||||||
!entry.HasMember("name") || !entry["name"].IsString())
|
!entry.HasMember("name") || !entry["name"].IsString())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
resource[entry["id"].GetInt()] = entry["name"].GetString();
|
resource[entry["id"].GetInt()] = entry["name"].GetString();
|
||||||
|
|
|
@ -33,20 +33,18 @@ struct TheGamesDBJSONRequestResources {
|
||||||
std::unordered_map<int, std::string> gamesdb_new_publishers_map;
|
std::unordered_map<int, std::string> gamesdb_new_publishers_map;
|
||||||
std::unordered_map<int, std::string> gamesdb_new_genres_map;
|
std::unordered_map<int, std::string> gamesdb_new_genres_map;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool checkLoaded();
|
bool checkLoaded();
|
||||||
|
|
||||||
bool saveResource(
|
bool saveResource(HttpReq* req,
|
||||||
HttpReq* req,
|
std::unordered_map<int, std::string>& resource,
|
||||||
std::unordered_map<int, std::string>& resource,
|
const std::string& resource_name,
|
||||||
const std::string& resource_name,
|
const std::string& file_name);
|
||||||
const std::string& file_name);
|
std::unique_ptr<HttpReq> fetchResource(const std::string& endpoint);
|
||||||
std::unique_ptr<HttpReq> fetchResource(const std::string& endpoint);
|
|
||||||
|
|
||||||
int loadResource(
|
int loadResource(std::unordered_map<int, std::string>& resource,
|
||||||
std::unordered_map<int, std::string>& resource,
|
const std::string& resource_name,
|
||||||
const std::string& resource_name,
|
const std::string& file_name);
|
||||||
const std::string& file_name);
|
|
||||||
|
|
||||||
std::unique_ptr<HttpReq> gamesdb_developers_resource_request;
|
std::unique_ptr<HttpReq> gamesdb_developers_resource_request;
|
||||||
std::unique_ptr<HttpReq> gamesdb_publishers_resource_request;
|
std::unique_ptr<HttpReq> gamesdb_publishers_resource_request;
|
||||||
|
|
|
@ -10,20 +10,20 @@
|
||||||
|
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "GamesDBJSONScraper.h"
|
#include "GamesDBJSONScraper.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "ScreenScraper.h"
|
#include "ScreenScraper.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <FreeImage.h>
|
#include <FreeImage.h>
|
||||||
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
const std::map<std::string, generate_scraper_requests_func> scraper_request_funcs {
|
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";
|
LOG(LogError) << "Configured scraper (" << name << ") unavailable, scraping aborted";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "Scraper::startScraperSearch(): Scraping system \"" <<
|
LOG(LogDebug) << "Scraper::startScraperSearch(): Scraping system \""
|
||||||
params.system->getName() << "\", game file \"" <<
|
<< params.system->getName() << "\", game file \""
|
||||||
params.game->getFileName() << "\"";
|
<< params.game->getFileName() << "\"";
|
||||||
scraper_request_funcs.at(name)(params, handle->mRequestQueue, handle->mResults);
|
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();
|
return scraper_request_funcs.find(name) != scraper_request_funcs.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScraperSearchHandle.
|
|
||||||
ScraperSearchHandle::ScraperSearchHandle()
|
|
||||||
{
|
|
||||||
setStatus(ASYNC_IN_PROGRESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScraperSearchHandle::update()
|
void ScraperSearchHandle::update()
|
||||||
{
|
{
|
||||||
if (mStatus == ASYNC_DONE)
|
if (mStatus == ASYNC_DONE)
|
||||||
|
@ -128,13 +122,14 @@ void ScraperSearchHandle::update()
|
||||||
|
|
||||||
// ScraperRequest.
|
// ScraperRequest.
|
||||||
ScraperRequest::ScraperRequest(std::vector<ScraperSearchResult>& resultsWrite)
|
ScraperRequest::ScraperRequest(std::vector<ScraperSearchResult>& resultsWrite)
|
||||||
: mResults(resultsWrite)
|
: mResults(resultsWrite)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScraperHttpRequest.
|
// ScraperHttpRequest.
|
||||||
ScraperHttpRequest::ScraperHttpRequest(std::vector<ScraperSearchResult>& resultsWrite,
|
ScraperHttpRequest::ScraperHttpRequest(std::vector<ScraperSearchResult>& resultsWrite,
|
||||||
const std::string& url) : ScraperRequest(resultsWrite)
|
const std::string& url)
|
||||||
|
: ScraperRequest(resultsWrite)
|
||||||
{
|
{
|
||||||
setStatus(ASYNC_IN_PROGRESS);
|
setStatus(ASYNC_IN_PROGRESS);
|
||||||
mReq = std::unique_ptr<HttpReq>(new HttpReq(url));
|
mReq = std::unique_ptr<HttpReq>(new HttpReq(url));
|
||||||
|
@ -155,20 +150,21 @@ void ScraperHttpRequest::update()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Everything else is some sort of error.
|
// Everything else is some sort of error.
|
||||||
LOG(LogError) << "ScraperHttpRequest network error (status: " << status<< ") - "
|
LOG(LogError) << "ScraperHttpRequest network error (status: " << status << ") - "
|
||||||
<< mReq->getErrorMsg();
|
<< mReq->getErrorMsg();
|
||||||
setError("Network error: " + mReq->getErrorMsg());
|
setError("Network error: " + mReq->getErrorMsg());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download and write the media files to disk.
|
// Download and write the media files to disk.
|
||||||
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,
|
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,
|
||||||
const ScraperSearchParams& search)
|
const ScraperSearchParams& search)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<MDResolveHandle>(new MDResolveHandle(result, search));
|
return std::unique_ptr<MDResolveHandle>(new MDResolveHandle(result, search));
|
||||||
}
|
}
|
||||||
|
|
||||||
MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
const ScraperSearchParams& search) : mResult(result)
|
const ScraperSearchParams& search)
|
||||||
|
: mResult(result)
|
||||||
{
|
{
|
||||||
struct mediaFileInfoStruct {
|
struct mediaFileInfoStruct {
|
||||||
std::string fileURL;
|
std::string fileURL;
|
||||||
|
@ -221,10 +217,10 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
mediaFileInfo.existingMediaFile = search.game->getVideoPath();
|
mediaFileInfo.existingMediaFile = search.game->getVideoPath();
|
||||||
mediaFileInfo.resizeFile = false;
|
mediaFileInfo.resizeFile = false;
|
||||||
scrapeFiles.push_back(mediaFileInfo);
|
scrapeFiles.push_back(mediaFileInfo);
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
// Required due to the idiotic file locking that exists on this operating system.
|
// Required due to the idiotic file locking that exists on this operating system.
|
||||||
ViewController::get()->onStopVideo();
|
ViewController::get()->onStopVideo();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = scrapeFiles.cbegin(); it != scrapeFiles.cend(); it++) {
|
for (auto it = scrapeFiles.cbegin(); it != scrapeFiles.cend(); it++) {
|
||||||
|
@ -248,13 +244,12 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
// If there is an existing media file on disk and the setting to overwrite data
|
// If there is an existing media file on disk and the setting to overwrite data
|
||||||
// has been set to no, then don't proceed with downloading or saving a new file.
|
// has been set to no, then don't proceed with downloading or saving a new file.
|
||||||
if (it->existingMediaFile != "" &&
|
if (it->existingMediaFile != "" &&
|
||||||
!Settings::getInstance()->getBool("ScraperOverwriteData"))
|
!Settings::getInstance()->getBool("ScraperOverwriteData"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If the image is cached already as the thumbnail, then we don't need
|
// 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.
|
// to download it again, in this case just save it to disk and resize it.
|
||||||
if (mResult.thumbnailImageUrl == it->fileURL &&
|
if (mResult.thumbnailImageUrl == it->fileURL && mResult.thumbnailImageData.size() > 0) {
|
||||||
mResult.thumbnailImageData.size() > 0) {
|
|
||||||
|
|
||||||
// This is just a temporary workaround to avoid saving media files to disk that
|
// 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
|
// are actually just containing error messages from the scraper service. The
|
||||||
|
@ -265,19 +260,19 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
// are sometimes returned from the scraper service and these can actually be
|
// are sometimes returned from the scraper service and these can actually be
|
||||||
// less than 350 bytes in size.
|
// less than 350 bytes in size.
|
||||||
if (Settings::getInstance()->getBool("ScraperHaltOnInvalidMedia") &&
|
if (Settings::getInstance()->getBool("ScraperHaltOnInvalidMedia") &&
|
||||||
mResult.thumbnailImageData.size() < 350) {
|
mResult.thumbnailImageData.size() < 350) {
|
||||||
|
|
||||||
FIMEMORY* memoryStream = FreeImage_OpenMemory(
|
FIMEMORY* memoryStream =
|
||||||
reinterpret_cast<BYTE*>(&mResult.thumbnailImageData.at(0)),
|
FreeImage_OpenMemory(reinterpret_cast<BYTE*>(&mResult.thumbnailImageData.at(0)),
|
||||||
static_cast<DWORD>(mResult.thumbnailImageData.size()));
|
static_cast<DWORD>(mResult.thumbnailImageData.size()));
|
||||||
|
|
||||||
FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
FREE_IMAGE_FORMAT imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
||||||
FreeImage_CloseMemory(memoryStream);
|
FreeImage_CloseMemory(memoryStream);
|
||||||
|
|
||||||
if (imageFormat == FIF_UNKNOWN) {
|
if (imageFormat == FIF_UNKNOWN) {
|
||||||
setError("The file \"" + Utils::FileSystem::getFileName(filePath) +
|
setError("The file \"" + Utils::FileSystem::getFileName(filePath) +
|
||||||
"\" returned by the scraper seems to be invalid as it's less than " +
|
"\" returned by the scraper seems to be invalid as it's less than " +
|
||||||
"350 bytes in size");
|
"350 bytes in size");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,18 +288,18 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
// problems or the MediaDirectory setting points to a file instead of a directory.
|
// problems or the MediaDirectory setting points to a file instead of a directory.
|
||||||
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(filePath))) {
|
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(filePath))) {
|
||||||
setError("Media directory does not exist and can't be created. "
|
setError("Media directory does not exist and can't be created. "
|
||||||
"Permission problems?");
|
"Permission problems?");
|
||||||
LOG(LogError) << "Couldn't create media directory: \"" <<
|
LOG(LogError) << "Couldn't create media directory: \""
|
||||||
Utils::FileSystem::getParent(filePath) << "\"";
|
<< Utils::FileSystem::getParent(filePath) << "\"";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::ofstream stream(Utils::String::stringToWideString(filePath).c_str(),
|
std::ofstream stream(Utils::String::stringToWideString(filePath).c_str(),
|
||||||
std::ios_base::out | std::ios_base::binary);
|
std::ios_base::out | std::ios_base::binary);
|
||||||
#else
|
#else
|
||||||
std::ofstream stream(filePath, std::ios_base::out | std::ios_base::binary);
|
std::ofstream stream(filePath, std::ios_base::out | std::ios_base::binary);
|
||||||
#endif
|
#endif
|
||||||
if (!stream || stream.bad()) {
|
if (!stream || stream.bad()) {
|
||||||
setError("Failed to open path for writing media file.\nPermission error?");
|
setError("Failed to open path for writing media file.\nPermission error?");
|
||||||
return;
|
return;
|
||||||
|
@ -331,8 +326,9 @@ MDResolveHandle::MDResolveHandle(const ScraperSearchResult& result,
|
||||||
// If it's not cached, then initiate the download.
|
// If it's not cached, then initiate the download.
|
||||||
else {
|
else {
|
||||||
mFuncs.push_back(ResolvePair(downloadMediaAsync(it->fileURL, filePath,
|
mFuncs.push_back(ResolvePair(downloadMediaAsync(it->fileURL, filePath,
|
||||||
it->existingMediaFile, it->subDirectory, it->resizeFile, mResult.savedNewMedia),
|
it->existingMediaFile, it->subDirectory,
|
||||||
[this, filePath] {}));
|
it->resizeFile, mResult.savedNewMedia),
|
||||||
|
[this, filePath] {}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,37 +357,30 @@ void MDResolveHandle::update()
|
||||||
setStatus(ASYNC_DONE);
|
setStatus(ASYNC_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(
|
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(const std::string& url,
|
||||||
const std::string& url,
|
const std::string& saveAs,
|
||||||
const std::string& saveAs,
|
const std::string& existingMediaPath,
|
||||||
const std::string& existingMediaPath,
|
const std::string& mediaType,
|
||||||
const std::string& mediaType,
|
const bool resizeFile,
|
||||||
const bool resizeFile,
|
bool& savedNewMedia)
|
||||||
bool& savedNewMedia)
|
|
||||||
{
|
{
|
||||||
return std::unique_ptr<MediaDownloadHandle>(new MediaDownloadHandle(
|
return std::unique_ptr<MediaDownloadHandle>(new MediaDownloadHandle(
|
||||||
url,
|
url, saveAs, existingMediaPath, mediaType, resizeFile, savedNewMedia));
|
||||||
saveAs,
|
|
||||||
existingMediaPath,
|
|
||||||
mediaType,
|
|
||||||
resizeFile,
|
|
||||||
savedNewMedia));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDownloadHandle::MediaDownloadHandle(
|
MediaDownloadHandle::MediaDownloadHandle(const std::string& url,
|
||||||
const std::string& url,
|
const std::string& path,
|
||||||
const std::string& path,
|
const std::string& existingMediaPath,
|
||||||
const std::string& existingMediaPath,
|
const std::string& mediaType,
|
||||||
const std::string& mediaType,
|
const bool resizeFile,
|
||||||
const bool resizeFile,
|
bool& savedNewMedia)
|
||||||
bool& savedNewMedia)
|
: mSavePath(path)
|
||||||
: mSavePath(path),
|
, mExistingMediaFile(existingMediaPath)
|
||||||
mExistingMediaFile(existingMediaPath),
|
, mMediaType(mediaType)
|
||||||
mMediaType(mediaType),
|
, mResizeFile(resizeFile)
|
||||||
mResizeFile(resizeFile),
|
, mReq(new HttpReq(url))
|
||||||
mReq(new HttpReq(url))
|
|
||||||
{
|
{
|
||||||
mSavedNewMediaPtr = &savedNewMedia;
|
mSavedNewMediaPtr = &savedNewMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaDownloadHandle::update()
|
void MediaDownloadHandle::update()
|
||||||
|
@ -421,25 +410,22 @@ void MediaDownloadHandle::update()
|
||||||
// Black/empty images are sometimes returned from the scraper service and these can actually
|
// Black/empty images are sometimes returned from the scraper service and these can actually
|
||||||
// be less than 350 bytes in size.
|
// be less than 350 bytes in size.
|
||||||
if (Settings::getInstance()->getBool("ScraperHaltOnInvalidMedia") &&
|
if (Settings::getInstance()->getBool("ScraperHaltOnInvalidMedia") &&
|
||||||
mReq->getContent().size() < 350) {
|
mReq->getContent().size() < 350) {
|
||||||
|
|
||||||
FREE_IMAGE_FORMAT imageFormat = FIF_UNKNOWN;
|
FREE_IMAGE_FORMAT imageFormat = FIF_UNKNOWN;
|
||||||
|
|
||||||
if (mMediaType != "videos") {
|
if (mMediaType != "videos") {
|
||||||
std::string imageData = mReq->getContent();
|
std::string imageData = mReq->getContent();
|
||||||
|
FIMEMORY* memoryStream = FreeImage_OpenMemory(reinterpret_cast<BYTE*>(&imageData.at(0)),
|
||||||
FIMEMORY* memoryStream = FreeImage_OpenMemory(
|
static_cast<DWORD>(imageData.size()));
|
||||||
reinterpret_cast<BYTE*>(&imageData.at(0)),
|
|
||||||
static_cast<DWORD>(imageData.size()));
|
|
||||||
|
|
||||||
imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
imageFormat = FreeImage_GetFileTypeFromMemory(memoryStream, 0);
|
||||||
FreeImage_CloseMemory(memoryStream);
|
FreeImage_CloseMemory(memoryStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageFormat == FIF_UNKNOWN) {
|
if (imageFormat == FIF_UNKNOWN) {
|
||||||
setError("The file \"" + Utils::FileSystem::getFileName(mSavePath) +
|
setError("The file \"" + Utils::FileSystem::getFileName(mSavePath) +
|
||||||
"\" returned by the scraper seems to be invalid as it's less than " +
|
"\" returned by the scraper seems to be invalid as it's less than " +
|
||||||
"350 bytes in size");
|
"350 bytes in size");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,17 +441,17 @@ void MediaDownloadHandle::update()
|
||||||
// problems or the MediaDirectory setting points to a file instead of a directory.
|
// problems or the MediaDirectory setting points to a file instead of a directory.
|
||||||
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(mSavePath))) {
|
if (!Utils::FileSystem::isDirectory(Utils::FileSystem::getParent(mSavePath))) {
|
||||||
setError("Media directory does not exist and can't be created. Permission problems?");
|
setError("Media directory does not exist and can't be created. Permission problems?");
|
||||||
LOG(LogError) << "Couldn't create media directory: \"" <<
|
LOG(LogError) << "Couldn't create media directory: \""
|
||||||
Utils::FileSystem::getParent(mSavePath) << "\"";
|
<< Utils::FileSystem::getParent(mSavePath) << "\"";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
std::ofstream stream(Utils::String::stringToWideString(mSavePath).c_str(),
|
std::ofstream stream(Utils::String::stringToWideString(mSavePath).c_str(),
|
||||||
std::ios_base::out | std::ios_base::binary);
|
std::ios_base::out | std::ios_base::binary);
|
||||||
#else
|
#else
|
||||||
std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary);
|
std::ofstream stream(mSavePath, std::ios_base::out | std::ios_base::binary);
|
||||||
#endif
|
#endif
|
||||||
if (!stream || stream.bad()) {
|
if (!stream || stream.bad()) {
|
||||||
setError("Failed to open path for writing media file.\nPermission error?");
|
setError("Failed to open path for writing media file.\nPermission error?");
|
||||||
return;
|
return;
|
||||||
|
@ -512,15 +498,16 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
||||||
FIBITMAP* image = nullptr;
|
FIBITMAP* image = nullptr;
|
||||||
|
|
||||||
// Detect the file format.
|
// Detect the file format.
|
||||||
#if defined(_WIN64)
|
|
||||||
|
#if defined(_WIN64)
|
||||||
format = FreeImage_GetFileTypeU(Utils::String::stringToWideString(path).c_str(), 0);
|
format = FreeImage_GetFileTypeU(Utils::String::stringToWideString(path).c_str(), 0);
|
||||||
if (format == FIF_UNKNOWN)
|
if (format == FIF_UNKNOWN)
|
||||||
format = FreeImage_GetFIFFromFilenameU(Utils::String::stringToWideString(path).c_str());
|
format = FreeImage_GetFIFFromFilenameU(Utils::String::stringToWideString(path).c_str());
|
||||||
#else
|
#else
|
||||||
format = FreeImage_GetFileType(path.c_str(), 0);
|
format = FreeImage_GetFileType(path.c_str(), 0);
|
||||||
if (format == FIF_UNKNOWN)
|
if (format == FIF_UNKNOWN)
|
||||||
format = FreeImage_GetFIFFromFilename(path.c_str());
|
format = FreeImage_GetFIFFromFilename(path.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (format == FIF_UNKNOWN) {
|
if (format == FIF_UNKNOWN) {
|
||||||
LOG(LogError) << "Could not detect filetype for image \"" << path << "\"!";
|
LOG(LogError) << "Could not detect filetype for image \"" << path << "\"!";
|
||||||
return false;
|
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.
|
// Make sure we can read this format, and if so, then load it.
|
||||||
if (FreeImage_FIFSupportsReading(format)) {
|
if (FreeImage_FIFSupportsReading(format)) {
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
image = FreeImage_LoadU(format, Utils::String::stringToWideString(path).c_str());
|
image = FreeImage_LoadU(format, Utils::String::stringToWideString(path).c_str());
|
||||||
#else
|
#else
|
||||||
image = FreeImage_Load(format, path.c_str());
|
image = FreeImage_Load(format, path.c_str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogError) << "File format not supported for image \"" << path << "\"";
|
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
|
// 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.
|
// do any scaling. It doesn't make sense to upscale the image and waste disk space.
|
||||||
if (maxWidth >= width && maxHeight >= height) {
|
if (maxWidth >= width && maxHeight >= height) {
|
||||||
LOG(LogDebug) << "Scraper::resizeImage(): Saving image \"" << path <<
|
LOG(LogDebug) << "Scraper::resizeImage(): Saving image \"" << path
|
||||||
"\" at its original resolution " << width << "x" << height;
|
<< "\" at its original resolution " << width << "x" << height;
|
||||||
FreeImage_Unload(image);
|
FreeImage_Unload(image);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +555,7 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
||||||
|
|
||||||
// We use Lanczos3 which is the highest quality resampling method available in FreeImage.
|
// We use Lanczos3 which is the highest quality resampling method available in FreeImage.
|
||||||
FIBITMAP* imageRescaled = FreeImage_Rescale(image, static_cast<int>(maxWidth),
|
FIBITMAP* imageRescaled = FreeImage_Rescale(image, static_cast<int>(maxWidth),
|
||||||
static_cast<int>(maxHeight), FILTER_LANCZOS3);
|
static_cast<int>(maxHeight), FILTER_LANCZOS3);
|
||||||
FreeImage_Unload(image);
|
FreeImage_Unload(image);
|
||||||
|
|
||||||
if (imageRescaled == nullptr) {
|
if (imageRescaled == nullptr) {
|
||||||
|
@ -576,12 +563,12 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
bool saved = (FreeImage_SaveU(format, imageRescaled,
|
bool saved = (FreeImage_SaveU(format, imageRescaled,
|
||||||
Utils::String::stringToWideString(path).c_str()) != 0);
|
Utils::String::stringToWideString(path).c_str()) != 0);
|
||||||
#else
|
#else
|
||||||
bool saved = (FreeImage_Save(format, imageRescaled, path.c_str()) != 0);
|
bool saved = (FreeImage_Save(format, imageRescaled, path.c_str()) != 0);
|
||||||
#endif
|
#endif
|
||||||
FreeImage_Unload(imageRescaled);
|
FreeImage_Unload(imageRescaled);
|
||||||
|
|
||||||
if (!saved) {
|
if (!saved) {
|
||||||
|
@ -589,14 +576,15 @@ bool resizeImage(const std::string& path, const std::string& mediaType)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "Scraper::resizeImage(): Downscaled image \"" << path << "\" from "
|
LOG(LogDebug) << "Scraper::resizeImage(): Downscaled image \"" << path << "\" from "
|
||||||
<< width << "x" << height << " to " << maxWidth << "x" << maxHeight;
|
<< width << "x" << height << " to " << maxWidth << "x" << maxHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getSaveAsPath(const ScraperSearchParams& params,
|
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 systemsubdirectory = params.system->getName();
|
||||||
const std::string name = Utils::FileSystem::getStem(params.game->getPath());
|
const std::string name = Utils::FileSystem::getStem(params.game->getPath());
|
||||||
|
@ -605,7 +593,7 @@ std::string getSaveAsPath(const ScraperSearchParams& params,
|
||||||
// Extract possible subfolders from the path.
|
// Extract possible subfolders from the path.
|
||||||
if (params.system->getSystemEnvData()->mStartPath != "")
|
if (params.system->getSystemEnvData()->mStartPath != "")
|
||||||
subFolders = Utils::String::replace(Utils::FileSystem::getParent(params.game->getPath()),
|
subFolders = Utils::String::replace(Utils::FileSystem::getParent(params.game->getPath()),
|
||||||
params.system->getSystemEnvData()->mStartPath, "");
|
params.system->getSystemEnvData()->mStartPath, "");
|
||||||
|
|
||||||
std::string path = FileData::getMediaDirectory();
|
std::string path = FileData::getMediaDirectory();
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class FileData;
|
||||||
class SystemData;
|
class SystemData;
|
||||||
|
|
||||||
enum downloadStatus {
|
enum downloadStatus {
|
||||||
NOT_STARTED,
|
NOT_STARTED, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
IN_PROGRESS,
|
IN_PROGRESS,
|
||||||
COMPLETED
|
COMPLETED
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,10 @@ struct ScraperSearchParams {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScraperSearchResult {
|
struct ScraperSearchResult {
|
||||||
ScraperSearchResult() : mdl(GAME_METADATA) {};
|
ScraperSearchResult()
|
||||||
|
: mdl(GAME_METADATA)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
MetaDataList mdl;
|
MetaDataList mdl;
|
||||||
std::string gameID;
|
std::string gameID;
|
||||||
|
@ -73,34 +76,6 @@ struct ScraperSearchResult {
|
||||||
bool savedNewMedia;
|
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.
|
// A scraper search gathers results from (potentially multiple) ScraperRequests.
|
||||||
class ScraperRequest : public AsyncHandle
|
class ScraperRequest : public AsyncHandle
|
||||||
{
|
{
|
||||||
|
@ -123,7 +98,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void process(const std::unique_ptr<HttpReq>& req,
|
virtual void process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::vector<ScraperSearchResult>& results) = 0;
|
std::vector<ScraperSearchResult>& results) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<HttpReq> mReq;
|
std::unique_ptr<HttpReq> mReq;
|
||||||
|
@ -133,21 +108,20 @@ private:
|
||||||
class ScraperSearchHandle : public AsyncHandle
|
class ScraperSearchHandle : public AsyncHandle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ScraperSearchHandle();
|
ScraperSearchHandle() { setStatus(ASYNC_IN_PROGRESS); }
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
inline const std::vector<ScraperSearchResult>& getResults() const
|
const std::vector<ScraperSearchResult>& getResults() const
|
||||||
{
|
{
|
||||||
assert(mStatus != ASYNC_IN_PROGRESS);
|
assert(mStatus != ASYNC_IN_PROGRESS);
|
||||||
return mResults;
|
return mResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend std::unique_ptr<ScraperSearchHandle>
|
friend std::unique_ptr<ScraperSearchHandle> startScraperSearch(
|
||||||
startScraperSearch(const ScraperSearchParams& params);
|
const ScraperSearchParams& params);
|
||||||
|
|
||||||
friend std::unique_ptr<ScraperSearchHandle>
|
friend std::unique_ptr<ScraperSearchHandle> startMediaURLsFetch(const std::string& gameIDs);
|
||||||
startMediaURLsFetch(const std::string& gameIDs);
|
|
||||||
|
|
||||||
std::queue<std::unique_ptr<ScraperRequest>> mRequestQueue;
|
std::queue<std::unique_ptr<ScraperRequest>> mRequestQueue;
|
||||||
std::vector<ScraperSearchResult> mResults;
|
std::vector<ScraperSearchResult> mResults;
|
||||||
|
@ -164,9 +138,10 @@ std::vector<std::string> getScraperList();
|
||||||
// Returns true if the scraper configured in the settings is still valid.
|
// Returns true if the scraper configured in the settings is still valid.
|
||||||
bool isValidConfiguredScraper();
|
bool isValidConfiguredScraper();
|
||||||
|
|
||||||
typedef void (*generate_scraper_requests_func)(const ScraperSearchParams& params,
|
typedef void (*generate_scraper_requests_func)(
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
const ScraperSearchParams& params,
|
||||||
std::vector<ScraperSearchResult>& results);
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
|
std::vector<ScraperSearchResult>& results);
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -177,8 +152,11 @@ public:
|
||||||
MDResolveHandle(const ScraperSearchResult& result, const ScraperSearchParams& search);
|
MDResolveHandle(const ScraperSearchResult& result, const ScraperSearchParams& search);
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
inline const ScraperSearchResult& getResult() const
|
const ScraperSearchResult& getResult() const
|
||||||
{ assert(mStatus == ASYNC_DONE); return mResult; }
|
{
|
||||||
|
assert(mStatus == ASYNC_DONE);
|
||||||
|
return mResult;
|
||||||
|
}
|
||||||
bool getSavedNewMedia() { return mResult.savedNewMedia; }
|
bool getSavedNewMedia() { return mResult.savedNewMedia; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -191,13 +169,12 @@ private:
|
||||||
class MediaDownloadHandle : public AsyncHandle
|
class MediaDownloadHandle : public AsyncHandle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MediaDownloadHandle(
|
MediaDownloadHandle(const std::string& url,
|
||||||
const std::string& url,
|
const std::string& path,
|
||||||
const std::string& path,
|
const std::string& existingMediaPath,
|
||||||
const std::string& existingMediaPath,
|
const std::string& mediaType,
|
||||||
const std::string& mediaType,
|
const bool resizeFile,
|
||||||
const bool resizeFile,
|
bool& savedNewMedia);
|
||||||
bool& savedNewMedia);
|
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|
||||||
|
@ -207,26 +184,26 @@ private:
|
||||||
std::string mExistingMediaFile;
|
std::string mExistingMediaFile;
|
||||||
std::string mMediaType;
|
std::string mMediaType;
|
||||||
bool mResizeFile;
|
bool mResizeFile;
|
||||||
bool *mSavedNewMediaPtr;
|
bool* mSavedNewMediaPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Downloads to the home directory, using this subdirectory structure:
|
// Downloads to the home directory, using this subdirectory structure:
|
||||||
// ".emulationstation/downloaded_media/[system_name]/[media_type]/[game_name].[file_extension]".
|
// ".emulationstation/downloaded_media/[system_name]/[media_type]/[game_name].[file_extension]".
|
||||||
// The subdirectories are automatically created if they do not exist.
|
// The subdirectories are automatically created if they do not exist.
|
||||||
std::string getSaveAsPath(const ScraperSearchParams& params,
|
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(
|
std::unique_ptr<MediaDownloadHandle> downloadMediaAsync(const std::string& url,
|
||||||
const std::string& url,
|
const std::string& saveAs,
|
||||||
const std::string& saveAs,
|
const std::string& existingMediaPath,
|
||||||
const std::string& existingMediaPath,
|
const std::string& mediaType,
|
||||||
const std::string& mediaType,
|
const bool resizeFile,
|
||||||
const bool resizeFile,
|
bool& savedNewMedia);
|
||||||
bool& savedNewMedia);
|
|
||||||
|
|
||||||
// Resolves all metadata assets that need to be downloaded.
|
// Resolves all metadata assets that need to be downloaded.
|
||||||
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,
|
std::unique_ptr<MDResolveHandle> resolveMetaDataAssets(const ScraperSearchResult& result,
|
||||||
const ScraperSearchParams& search);
|
const ScraperSearchParams& search);
|
||||||
|
|
||||||
bool resizeImage(const std::string& path, const std::string& mediaType);
|
bool resizeImage(const std::string& path, const std::string& mediaType);
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
|
|
||||||
#include "scrapers/ScreenScraper.h"
|
#include "scrapers/ScreenScraper.h"
|
||||||
|
|
||||||
#include "math/Misc.h"
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "utils/TimeUtil.h"
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "PlatformId.h"
|
#include "PlatformId.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "math/Misc.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "utils/TimeUtil.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -42,7 +42,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
||||||
{ ATARI_JAGUAR, 27 },
|
{ ATARI_JAGUAR, 27 },
|
||||||
{ ATARI_JAGUAR_CD, 171 },
|
{ ATARI_JAGUAR_CD, 171 },
|
||||||
{ ATARI_LYNX, 28 },
|
{ ATARI_LYNX, 28 },
|
||||||
{ ATARI_ST, 42},
|
{ ATARI_ST, 42 },
|
||||||
{ ATARI_XE, 43 },
|
{ ATARI_XE, 43 },
|
||||||
{ ATOMISWAVE, 53 },
|
{ ATOMISWAVE, 53 },
|
||||||
{ BBC_MICRO, 37 },
|
{ BBC_MICRO, 37 },
|
||||||
|
@ -62,7 +62,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
||||||
{ MSX_TURBO_R, 118 },
|
{ MSX_TURBO_R, 118 },
|
||||||
{ SNK_NEO_GEO, 142 },
|
{ SNK_NEO_GEO, 142 },
|
||||||
{ SNK_NEO_GEO_CD, 142 },
|
{ SNK_NEO_GEO_CD, 142 },
|
||||||
{ SNK_NEO_GEO_POCKET, 25},
|
{ SNK_NEO_GEO_POCKET, 25 },
|
||||||
{ SNK_NEO_GEO_POCKET_COLOR, 82 },
|
{ SNK_NEO_GEO_POCKET_COLOR, 82 },
|
||||||
{ NINTENDO_3DS, 17 },
|
{ NINTENDO_3DS, 17 },
|
||||||
{ NINTENDO_64, 14 },
|
{ NINTENDO_64, 14 },
|
||||||
|
@ -88,7 +88,7 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
||||||
{ NEC_PCFX, 72 },
|
{ NEC_PCFX, 72 },
|
||||||
{ GAMEENGINE_OPENBOR, 214 },
|
{ GAMEENGINE_OPENBOR, 214 },
|
||||||
{ TANGERINE_ORIC, 131 },
|
{ TANGERINE_ORIC, 131 },
|
||||||
{ GAMEENGINE_SCUMMVM, 123},
|
{ GAMEENGINE_SCUMMVM, 123 },
|
||||||
{ SEGA_32X, 19 },
|
{ SEGA_32X, 19 },
|
||||||
{ SEGA_CD, 20 },
|
{ SEGA_CD, 20 },
|
||||||
{ SEGA_DREAMCAST, 23 },
|
{ SEGA_DREAMCAST, 23 },
|
||||||
|
@ -98,8 +98,8 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
||||||
{ SEGA_MEGA_DRIVE, 1 },
|
{ SEGA_MEGA_DRIVE, 1 },
|
||||||
{ SEGA_SATURN, 22 },
|
{ SEGA_SATURN, 22 },
|
||||||
{ SEGA_SG1000, 109 },
|
{ SEGA_SG1000, 109 },
|
||||||
{ SHARP_X1, 220},
|
{ SHARP_X1, 220 },
|
||||||
{ SHARP_X68000, 79},
|
{ SHARP_X68000, 79 },
|
||||||
{ GAMEENGINE_SOLARUS, 223 },
|
{ GAMEENGINE_SOLARUS, 223 },
|
||||||
{ SONY_PLAYSTATION, 57 },
|
{ SONY_PLAYSTATION, 57 },
|
||||||
{ SONY_PLAYSTATION_2, 58 },
|
{ SONY_PLAYSTATION_2, 58 },
|
||||||
|
@ -110,8 +110,8 @@ const std::map<PlatformId, unsigned short> screenscraper_platformid_map {
|
||||||
{ SUPER_NINTENDO, 4 },
|
{ SUPER_NINTENDO, 4 },
|
||||||
{ NEC_SUPERGRAFX, 105 },
|
{ NEC_SUPERGRAFX, 105 },
|
||||||
{ GAMEENGINE_TIC80, 222 },
|
{ GAMEENGINE_TIC80, 222 },
|
||||||
{ NEC_PC_8800, 221},
|
{ NEC_PC_8800, 221 },
|
||||||
{ NEC_PC_9800, 208},
|
{ NEC_PC_9800, 208 },
|
||||||
{ NEC_PC_ENGINE, 31 },
|
{ NEC_PC_ENGINE, 31 },
|
||||||
{ NEC_PC_ENGINE_CD, 114 },
|
{ NEC_PC_ENGINE_CD, 114 },
|
||||||
{ BANDAI_WONDERSWAN, 45 },
|
{ 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.
|
// Helper XML parsing method, finding a node-by-name recursively.
|
||||||
pugi::xml_node find_node_by_name_re(const pugi::xml_node& node,
|
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) {
|
for (const std::string& _val : node_names) {
|
||||||
pugi::xpath_query query_node_name((static_cast<std::string>("//") + _val).c_str());
|
pugi::xpath_query query_node_name((static_cast<std::string>("//") + _val).c_str());
|
||||||
|
@ -147,8 +148,9 @@ 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
|
// Help XML parsing method, finding an direct child XML node starting from the parent and
|
||||||
// filtering by an attribute value list.
|
// filtering by an attribute value list.
|
||||||
pugi::xml_node find_child_by_attribute_list(const pugi::xml_node& node_parent,
|
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::vector<std::string> attribute_values)
|
const std::string& attribute_name,
|
||||||
|
const std::vector<std::string> attribute_values)
|
||||||
{
|
{
|
||||||
for (auto _val : attribute_values) {
|
for (auto _val : attribute_values) {
|
||||||
for (pugi::xml_node node : node_parent.children(node_name.c_str())) {
|
for (pugi::xml_node node : node_parent.children(node_name.c_str())) {
|
||||||
|
@ -161,22 +163,22 @@ pugi::xml_node find_child_by_attribute_list(const pugi::xml_node& node_parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
ScreenScraperRequest::ScreenScraperConfig ssConfig;
|
ScreenScraperRequest::ScreenScraperConfig ssConfig;
|
||||||
|
|
||||||
if (params.game->isArcadeGame())
|
if (params.game->isArcadeGame())
|
||||||
ssConfig.isArcadeSystem = true;
|
ssConfig.isArcadeSystem = true;
|
||||||
else
|
else
|
||||||
ssConfig.isArcadeSystem = false;
|
ssConfig.isArcadeSystem = false;
|
||||||
|
|
||||||
if (params.nameOverride == "") {
|
if (params.nameOverride == "") {
|
||||||
if (Settings::getInstance()->getBool("ScraperSearchMetadataName"))
|
if (Settings::getInstance()->getBool("ScraperSearchMetadataName"))
|
||||||
path = ssConfig.getGameSearchUrl(
|
path = ssConfig.getGameSearchUrl(
|
||||||
Utils::String::removeParenthesis(params.game->metadata.get("name")));
|
Utils::String::removeParenthesis(params.game->metadata.get("name")));
|
||||||
else
|
else
|
||||||
path = ssConfig.getGameSearchUrl(params.game->getCleanName());
|
path = ssConfig.getGameSearchUrl(params.game->getCleanName());
|
||||||
}
|
}
|
||||||
|
@ -195,19 +197,19 @@ void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
||||||
p_ids.push_back(mapIt->second);
|
p_ids.push_back(mapIt->second);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogWarning) << "ScreenScraper: No support for platform \"" <<
|
LOG(LogWarning) << "ScreenScraper: No support for platform \""
|
||||||
getPlatformName(*platformIt) << "\", search will be inaccurate";
|
<< getPlatformName(*platformIt) << "\", search will be inaccurate";
|
||||||
// Add the scrape request without a platform/system ID.
|
// Add the scrape request without a platform/system ID.
|
||||||
requests.push(std::unique_ptr<ScraperRequest>
|
requests.push(
|
||||||
(new ScreenScraperRequest(requests, results, path)));
|
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_ids.size() == 0) {
|
if (p_ids.size() == 0) {
|
||||||
LOG(LogWarning) << "ScreenScraper: No platform defined, search will be inaccurate";
|
LOG(LogWarning) << "ScreenScraper: No platform defined, search will be inaccurate";
|
||||||
// Add the scrape request without a platform/system ID.
|
// Add the scrape request without a platform/system ID.
|
||||||
requests.push(std::unique_ptr<ScraperRequest>
|
requests.push(
|
||||||
(new ScreenScraperRequest(requests, results, path)));
|
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the platform IDs and remove duplicates.
|
// Sort the platform IDs and remove duplicates.
|
||||||
|
@ -218,13 +220,13 @@ void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
||||||
for (auto platform = p_ids.cbegin(); platform != p_ids.cend(); platform++) {
|
for (auto platform = p_ids.cbegin(); platform != p_ids.cend(); platform++) {
|
||||||
path += "&systemeid=";
|
path += "&systemeid=";
|
||||||
path += HttpReq::urlEncode(std::to_string(*platform));
|
path += HttpReq::urlEncode(std::to_string(*platform));
|
||||||
requests.push(std::unique_ptr<ScraperRequest>
|
requests.push(
|
||||||
(new ScreenScraperRequest(requests, results, path)));
|
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(requests, results, path)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenScraperRequest::process(const std::unique_ptr<HttpReq>& req,
|
void ScreenScraperRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
assert(req->status() == HttpReq::REQ_SUCCESS);
|
assert(req->status() == HttpReq::REQ_SUCCESS);
|
||||||
|
|
||||||
|
@ -263,7 +265,7 @@ void ScreenScraperRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::string gameName = Utils::String::toUpper((*it).mdl.get("name"));
|
std::string gameName = Utils::String::toUpper((*it).mdl.get("name"));
|
||||||
if (gameName.substr(0, 12) == "ZZZ(NOTGAME)") {
|
if (gameName.substr(0, 12) == "ZZZ(NOTGAME)") {
|
||||||
LOG(LogWarning) << "ScreenScraperRequest - Received \"ZZZ(notgame)\" as game name, "
|
LOG(LogWarning) << "ScreenScraperRequest - Received \"ZZZ(notgame)\" as game name, "
|
||||||
"ignoring response";
|
"ignoring response";
|
||||||
results.pop_back();
|
results.pop_back();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -271,7 +273,7 @@ void ScreenScraperRequest::process(const std::unique_ptr<HttpReq>& req,
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
std::vector<ScraperSearchResult>& out_results)
|
std::vector<ScraperSearchResult>& out_results)
|
||||||
{
|
{
|
||||||
pugi::xml_node data = xmldoc.child("Data");
|
pugi::xml_node data = xmldoc.child("Data");
|
||||||
|
|
||||||
|
@ -280,17 +282,18 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
// also seems to correlate with missing scraper allowance data. This is however a scraper
|
// also seems to correlate with missing scraper allowance data. This is however a scraper
|
||||||
// service issue so we're not attempting to compensate for it here.
|
// service issue so we're not attempting to compensate for it here.
|
||||||
if (Settings::getInstance()->getBool("ScraperUseAccountScreenScraper") &&
|
if (Settings::getInstance()->getBool("ScraperUseAccountScreenScraper") &&
|
||||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper") != "" &&
|
Settings::getInstance()->getString("ScraperUsernameScreenScraper") != "" &&
|
||||||
Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
Settings::getInstance()->getString("ScraperPasswordScreenScraper") != "") {
|
||||||
std::string userID = data.child("ssuser").child("id").text().get();
|
std::string userID = data.child("ssuser").child("id").text().get();
|
||||||
if (userID != "") {
|
if (userID != "") {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Scraping using account \"" <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Scraping using account \""
|
||||||
userID << "\"";
|
<< userID << "\"";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): The configured account '" <<
|
LOG(LogDebug)
|
||||||
Settings::getInstance()->getString("ScraperUsernameScreenScraper") <<
|
<< "ScreenScraperRequest::processGame(): The configured account '"
|
||||||
"' was not included in the scraper response, wrong username or password?";
|
<< Settings::getInstance()->getString("ScraperUsernameScreenScraper")
|
||||||
|
<< "' was not included in the scraper response, wrong username or password?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,17 +307,17 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
|
|
||||||
// Scraping allowance.
|
// Scraping allowance.
|
||||||
if (maxRequestsPerDay > 0) {
|
if (maxRequestsPerDay > 0) {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: "
|
||||||
requestsToday << "/" << maxRequestsPerDay << " (" <<
|
<< requestsToday << "/" << maxRequestsPerDay << " ("
|
||||||
scraperRequestAllowance << " remaining)";
|
<< scraperRequestAllowance << " remaining)";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: "
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Daily scraping allowance: "
|
||||||
"No statistics were provided with the response";
|
"No statistics were provided with the response";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.child("jeux"))
|
if (data.child("jeux"))
|
||||||
data = data.child("jeux");
|
data = data.child("jeux");
|
||||||
|
|
||||||
for (pugi::xml_node game = data.child("jeu"); game; game = game.next_sibling("jeu")) {
|
for (pugi::xml_node game = data.child("jeu"); game; game = game.next_sibling("jeu")) {
|
||||||
ScraperSearchResult result;
|
ScraperSearchResult result;
|
||||||
|
@ -324,13 +327,16 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
result.gameID = game.attribute("id").as_string();
|
result.gameID = game.attribute("id").as_string();
|
||||||
|
|
||||||
std::string region =
|
std::string region =
|
||||||
Utils::String::toLower(Settings::getInstance()->getString("ScraperRegion"));
|
Utils::String::toLower(Settings::getInstance()->getString("ScraperRegion"));
|
||||||
std::string language =
|
std::string language =
|
||||||
Utils::String::toLower(Settings::getInstance()->getString("ScraperLanguage"));
|
Utils::String::toLower(Settings::getInstance()->getString("ScraperLanguage"));
|
||||||
|
|
||||||
// Name fallback: US, WOR(LD). (Xpath: Data/jeu[0]/noms/nom[*]).
|
// Name fallback: US, WOR(LD). (Xpath: Data/jeu[0]/noms/nom[*]).
|
||||||
result.mdl.set("name", find_child_by_attribute_list(game.child("noms"),
|
result.mdl.set("name",
|
||||||
"nom", "region", { region, "wor", "us" , "ss", "eu", "jp" }).text().get());
|
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");
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Name: " << result.mdl.get("name");
|
||||||
|
|
||||||
// Validate rating.
|
// Validate rating.
|
||||||
|
@ -346,14 +352,16 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
ss << ratingVal;
|
ss << ratingVal;
|
||||||
if (ratingVal > 0) {
|
if (ratingVal > 0) {
|
||||||
result.mdl.set("rating", ss.str());
|
result.mdl.set("rating", ss.str());
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Rating: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Rating: "
|
||||||
result.mdl.get("rating");
|
<< result.mdl.get("rating");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description fallback language: EN, WOR(LD).
|
// Description fallback language: EN, WOR(LD).
|
||||||
std::string description = find_child_by_attribute_list(game.child("synopsis"),
|
std::string description = find_child_by_attribute_list(game.child("synopsis"), "synopsis",
|
||||||
"synopsis", "langue", { language, "en", "wor" }).text().get();
|
"langue", { language, "en", "wor" })
|
||||||
|
.text()
|
||||||
|
.get();
|
||||||
|
|
||||||
// Translate some HTML character codes to UTF-8 characters.
|
// Translate some HTML character codes to UTF-8 characters.
|
||||||
if (!description.empty()) {
|
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'
|
// Get the date proper. The API returns multiple 'date' children nodes to the 'dates'
|
||||||
// main child of 'jeu'.
|
// main child of 'jeu'. Date fallback: WOR(LD), US, SS, JP, EU.
|
||||||
// Date fallback: WOR(LD), US, SS, JP, EU.
|
|
||||||
std::string _date = find_child_by_attribute_list(game.child("dates"), "date", "region",
|
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.
|
// Date can be YYYY-MM-DD or just YYYY.
|
||||||
if (_date.length() > 4) {
|
if (_date.length() > 4) {
|
||||||
result.mdl.set("releasedate", Utils::Time::DateTime(
|
result.mdl.set("releasedate",
|
||||||
Utils::Time::stringToTime(_date, "%Y-%m-%d")));
|
Utils::Time::DateTime(Utils::Time::stringToTime(_date, "%Y-%m-%d")));
|
||||||
}
|
}
|
||||||
else if (_date.length() > 0) {
|
else if (_date.length() > 0) {
|
||||||
result.mdl.set("releasedate", Utils::Time::DateTime(
|
result.mdl.set("releasedate",
|
||||||
Utils::Time::stringToTime(_date, "%Y")));
|
Utils::Time::DateTime(Utils::Time::stringToTime(_date, "%Y")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_date.length() > 0) {
|
if (_date.length() > 0) {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (unparsed): " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (unparsed): "
|
||||||
_date;
|
<< _date;
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (parsed): " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Release Date (parsed): "
|
||||||
result.mdl.get("releasedate");
|
<< result.mdl.get("releasedate");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Developer for the game (Xpath: Data/jeu[0]/developpeur).
|
// Developer for the game (Xpath: Data/jeu[0]/developpeur).
|
||||||
std::string developer = game.child("developpeur").text().get();
|
std::string developer = game.child("developpeur").text().get();
|
||||||
if (!developer.empty()) {
|
if (!developer.empty()) {
|
||||||
result.mdl.set("developer", Utils::String::replace(developer, " ", " "));
|
result.mdl.set("developer", Utils::String::replace(developer, " ", " "));
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Developer: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Developer: "
|
||||||
result.mdl.get("developer");
|
<< result.mdl.get("developer");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publisher for the game (Xpath: Data/jeu[0]/editeur).
|
// Publisher for the game (Xpath: Data/jeu[0]/editeur).
|
||||||
std::string publisher = game.child("editeur").text().get();
|
std::string publisher = game.child("editeur").text().get();
|
||||||
if (!publisher.empty()) {
|
if (!publisher.empty()) {
|
||||||
result.mdl.set("publisher", Utils::String::replace(publisher, " ", " "));
|
result.mdl.set("publisher", Utils::String::replace(publisher, " ", " "));
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Publisher: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Publisher: "
|
||||||
result.mdl.get("publisher");
|
<< result.mdl.get("publisher");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Genre fallback language: EN. (Xpath: Data/jeu[0]/genres/genre[*]).
|
// Genre fallback language: EN. (Xpath: Data/jeu[0]/genres/genre[*]).
|
||||||
std::string genre = find_child_by_attribute_list(game.child("genres"),
|
std::string genre = find_child_by_attribute_list(game.child("genres"), "genre", "langue",
|
||||||
"genre", "langue", { language, "en" }).text().get();
|
{ language, "en" })
|
||||||
|
.text()
|
||||||
|
.get();
|
||||||
if (!genre.empty()) {
|
if (!genre.empty()) {
|
||||||
result.mdl.set("genre", genre);
|
result.mdl.set("genre", genre);
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Genre: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Genre: "
|
||||||
result.mdl.get("genre");
|
<< result.mdl.get("genre");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Players.
|
// Players.
|
||||||
std::string players = game.child("joueurs").text().get();
|
std::string players = game.child("joueurs").text().get();
|
||||||
if (!players.empty()) {
|
if (!players.empty()) {
|
||||||
result.mdl.set("players", players);
|
result.mdl.set("players", players);
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Players: " <<
|
LOG(LogDebug) << "ScreenScraperRequest::processGame(): Players: "
|
||||||
result.mdl.get("players");
|
<< result.mdl.get("players");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Media super-node.
|
// Media super-node.
|
||||||
pugi::xml_node media_list = game.child("medias");
|
pugi::xml_node media_list = game.child("medias");
|
||||||
|
|
||||||
if (media_list) {
|
if (media_list) {
|
||||||
// 3D box
|
// 3D box.
|
||||||
processMedia(result, media_list, ssConfig.media_3dbox,
|
processMedia(result, media_list, ssConfig.media_3dbox, result.box3DUrl,
|
||||||
result.box3DUrl, result.box3DFormat, region);
|
result.box3DFormat, region);
|
||||||
// Cover
|
// Cover.
|
||||||
processMedia(result, media_list, ssConfig.media_cover,
|
processMedia(result, media_list, ssConfig.media_cover, result.coverUrl,
|
||||||
result.coverUrl, result.coverFormat, region);
|
result.coverFormat, region);
|
||||||
// Marquee (wheel)
|
// Marquee (wheel).
|
||||||
processMedia(result, media_list, ssConfig.media_marquee,
|
processMedia(result, media_list, ssConfig.media_marquee, result.marqueeUrl,
|
||||||
result.marqueeUrl, result.marqueeFormat, region);
|
result.marqueeFormat, region);
|
||||||
// Screenshot
|
// Screenshot.
|
||||||
processMedia(result, media_list, ssConfig.media_screenshot,
|
processMedia(result, media_list, ssConfig.media_screenshot, result.screenshotUrl,
|
||||||
result.screenshotUrl, result.screenshotFormat, region);
|
result.screenshotFormat, region);
|
||||||
// Video
|
// Video.
|
||||||
processMedia(result, media_list, ssConfig.media_video,
|
processMedia(result, media_list, ssConfig.media_video, result.videoUrl,
|
||||||
result.videoUrl, result.videoFormat, region);
|
result.videoFormat, region);
|
||||||
}
|
}
|
||||||
result.mediaURLFetch = COMPLETED;
|
result.mediaURLFetch = COMPLETED;
|
||||||
out_results.push_back(result);
|
out_results.push_back(result);
|
||||||
|
@ -446,13 +457,12 @@ void ScreenScraperRequest::processGame(const pugi::xml_document& xmldoc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenScraperRequest::processMedia(
|
void ScreenScraperRequest::processMedia(ScraperSearchResult& result,
|
||||||
ScraperSearchResult& result,
|
const pugi::xml_node& media_list,
|
||||||
const pugi::xml_node& media_list,
|
std::string mediaType,
|
||||||
std::string mediaType,
|
std::string& fileURL,
|
||||||
std::string& fileURL,
|
std::string& fileFormat,
|
||||||
std::string& fileFormat,
|
std::string region)
|
||||||
std::string region)
|
|
||||||
{
|
{
|
||||||
pugi::xml_node art = pugi::xml_node(nullptr);
|
pugi::xml_node art = pugi::xml_node(nullptr);
|
||||||
|
|
||||||
|
@ -460,51 +470,52 @@ void ScreenScraperRequest::processMedia(
|
||||||
// We need to do this because any child of 'medias' has the form
|
// We need to do this because any child of 'medias' has the form
|
||||||
// <media type="..." region="..." format="...">
|
// <media type="..." region="..." format="...">
|
||||||
// and we need to find the right media for the region.
|
// and we need to find the right media for the region.
|
||||||
pugi::xpath_node_set results = media_list.select_nodes((static_cast<std::string>
|
pugi::xpath_node_set results = media_list.select_nodes(
|
||||||
("media[@type='") + mediaType + "']").c_str());
|
(static_cast<std::string>("media[@type='") + mediaType + "']").c_str());
|
||||||
|
|
||||||
if (results.size()) {
|
if (results.size()) {
|
||||||
// Videos don't have any region attributes, so just take the first entry
|
// Videos don't have any region attributes, so just take the first entry
|
||||||
// (which should be the only entry as well).
|
// (which should be the only entry as well).
|
||||||
if (mediaType == "video" || mediaType == "video-normalized") {
|
if (mediaType == "video" || mediaType == "video-normalized") {
|
||||||
art = results.first().node();
|
art = results.first().node();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Region fallback: WOR(LD), US, CUS(TOM?), JP, EU.
|
// Region fallback: WOR(LD), US, CUS(TOM?), JP, EU.
|
||||||
for (auto _region : std::vector<std::string>{
|
for (auto _region :
|
||||||
region, "wor", "us", "cus", "jp", "eu" }) {
|
std::vector<std::string> { region, "wor", "us", "cus", "jp", "eu" }) {
|
||||||
if (art)
|
if (art)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (auto node : results) {
|
||||||
|
if (node.node().attribute("region").value() == _region) {
|
||||||
|
art = node.node();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (auto node : results) {
|
|
||||||
if (node.node().attribute("region").value() == _region) {
|
|
||||||
art = node.node();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (art) {
|
if (art) {
|
||||||
// Sending a 'softname' containing space will make the media URLs returned
|
// Sending a 'softname' containing space will make the media URLs returned
|
||||||
// by the API also contain the space. Escape any spaces in the URL here.
|
// by the API also contain the space. Escape any spaces in the URL here.
|
||||||
fileURL = Utils::String::replace(art.text().get(), " ", "%20");
|
fileURL = Utils::String::replace(art.text().get(), " ", "%20");
|
||||||
|
|
||||||
// Get the media type returned by ScreenScraper.
|
// Get the media type returned by ScreenScraper.
|
||||||
std::string media_type = art.attribute("format").value();
|
std::string media_type = art.attribute("format").value();
|
||||||
if (!media_type.empty())
|
if (!media_type.empty())
|
||||||
fileFormat = "." + media_type;
|
fileFormat = "." + media_type;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG(LogDebug) << "ScreenScraperRequest::processMedia(): "
|
LOG(LogDebug) << "ScreenScraperRequest::processMedia(): "
|
||||||
"Failed to find media XML node with name '" << mediaType << "'";
|
"Failed to find media XML node with name '"
|
||||||
}
|
<< mediaType << "'";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently not used in this module.
|
// Currently not used in this module.
|
||||||
void ScreenScraperRequest::processList(const pugi::xml_document& xmldoc,
|
void ScreenScraperRequest::processList(const pugi::xml_document& xmldoc,
|
||||||
std::vector<ScraperSearchResult>& results)
|
std::vector<ScraperSearchResult>& results)
|
||||||
{
|
{
|
||||||
assert(mRequestQueue != nullptr);
|
assert(mRequestQueue != nullptr);
|
||||||
|
|
||||||
|
@ -527,18 +538,18 @@ void ScreenScraperRequest::processList(const pugi::xml_document& xmldoc,
|
||||||
std::string id = game.child("id").text().get();
|
std::string id = game.child("id").text().get();
|
||||||
std::string name = game.child("nom").text().get();
|
std::string name = game.child("nom").text().get();
|
||||||
std::string platformId = game.child("systemeid").text().get();
|
std::string platformId = game.child("systemeid").text().get();
|
||||||
std::string path = ssConfig.getGameSearchUrl(name) + "&systemeid=" +
|
std::string path =
|
||||||
platformId + "&gameid=" + id;
|
ssConfig.getGameSearchUrl(name) + "&systemeid=" + platformId + "&gameid=" + id;
|
||||||
|
|
||||||
mRequestQueue->push(std::unique_ptr<ScraperRequest>
|
mRequestQueue->push(
|
||||||
(new ScreenScraperRequest(results, path)));
|
std::unique_ptr<ScraperRequest>(new ScreenScraperRequest(results, path)));
|
||||||
|
|
||||||
game = game.next_sibling("jeu");
|
game = game.next_sibling("jeu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
||||||
const std::string gameName) const
|
const std::string gameName) const
|
||||||
{
|
{
|
||||||
std::string screenScraperURL;
|
std::string screenScraperURL;
|
||||||
std::string searchName = gameName;
|
std::string searchName = gameName;
|
||||||
|
@ -546,12 +557,14 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
||||||
|
|
||||||
// Trim leading and trailing whitespaces.
|
// Trim leading and trailing whitespaces.
|
||||||
searchName.erase(searchName.begin(),
|
searchName.erase(searchName.begin(),
|
||||||
std::find_if(searchName.begin(), searchName.end(), [](char c) {
|
std::find_if(searchName.begin(), searchName.end(), [](char c) {
|
||||||
return !std::isspace(static_cast<unsigned char>(c));
|
return !std::isspace(static_cast<unsigned char>(c));
|
||||||
}));
|
}));
|
||||||
searchName.erase(std::find_if(searchName.rbegin(), searchName.rend(), [](char c) {
|
searchName.erase(
|
||||||
return !std::isspace(static_cast<unsigned char>(c));
|
std::find_if(searchName.rbegin(), searchName.rend(),
|
||||||
}).base(), searchName.end());
|
[](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
|
// 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
|
// 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.
|
// than four characters which would break the wide search.
|
||||||
std::string trimTrailingPluses = searchName;
|
std::string trimTrailingPluses = searchName;
|
||||||
trimTrailingPluses.erase(std::find_if(trimTrailingPluses.rbegin(),
|
trimTrailingPluses.erase(std::find_if(trimTrailingPluses.rbegin(),
|
||||||
trimTrailingPluses.rend(), [](char c) {
|
trimTrailingPluses.rend(),
|
||||||
return c != '+';
|
[](char c) { return c != '+'; })
|
||||||
}).base(), trimTrailingPluses.end());
|
.base(),
|
||||||
|
trimTrailingPluses.end());
|
||||||
|
|
||||||
if (trimTrailingPluses.size() < 4)
|
if (trimTrailingPluses.size() < 4)
|
||||||
singleSearch = true;
|
singleSearch = true;
|
||||||
|
@ -589,12 +603,12 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
||||||
// could also lead to an error for short game names.
|
// could also lead to an error for short game names.
|
||||||
if (!singleSearch) {
|
if (!singleSearch) {
|
||||||
std::string removeThe =
|
std::string removeThe =
|
||||||
Utils::String::replace(Utils::String::toUpper(searchName), "THE ", "");
|
Utils::String::replace(Utils::String::toUpper(searchName), "THE ", "");
|
||||||
// Any additional spaces must also be removed.
|
// Any additional spaces must also be removed.
|
||||||
removeThe.erase(removeThe.begin(),
|
removeThe.erase(removeThe.begin(),
|
||||||
std::find_if(removeThe.begin(), removeThe.end(), [](char c) {
|
std::find_if(removeThe.begin(), removeThe.end(), [](char c) {
|
||||||
return !std::isspace(static_cast<unsigned char>(c));
|
return !std::isspace(static_cast<unsigned char>(c));
|
||||||
}));
|
}));
|
||||||
// If "the" is placed at the end of the search string, ScreenScraper also removes it.
|
// If "the" is placed at the end of the search string, ScreenScraper also removes it.
|
||||||
if (removeThe.size() > 4) {
|
if (removeThe.size() > 4) {
|
||||||
if (removeThe.substr(removeThe.size() - 4, 4) == " THE")
|
if (removeThe.substr(removeThe.size() - 4, 4) == " THE")
|
||||||
|
@ -605,20 +619,18 @@ std::string ScreenScraperRequest::ScreenScraperConfig::getGameSearchUrl(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleSearch) {
|
if (singleSearch) {
|
||||||
screenScraperURL = API_URL_BASE
|
screenScraperURL = API_URL_BASE + "/jeuInfos.php?devid=" +
|
||||||
+ "/jeuInfos.php?devid=" + Utils::String::scramble(API_DEV_U, API_DEV_KEY)
|
Utils::String::scramble(API_DEV_U, API_DEV_KEY) +
|
||||||
+ "&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY)
|
"&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY) +
|
||||||
+ "&softname=" + HttpReq::urlEncode(API_SOFT_NAME)
|
"&softname=" + HttpReq::urlEncode(API_SOFT_NAME) + "&output=xml" +
|
||||||
+ "&output=xml"
|
"&romnom=" + HttpReq::urlEncode(searchName);
|
||||||
+ "&romnom=" + HttpReq::urlEncode(searchName);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
screenScraperURL = API_URL_BASE
|
screenScraperURL = API_URL_BASE + "/jeuRecherche.php?devid=" +
|
||||||
+ "/jeuRecherche.php?devid=" + Utils::String::scramble(API_DEV_U, API_DEV_KEY)
|
Utils::String::scramble(API_DEV_U, API_DEV_KEY) +
|
||||||
+ "&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY)
|
"&devpassword=" + Utils::String::scramble(API_DEV_P, API_DEV_KEY) +
|
||||||
+ "&softname=" + HttpReq::urlEncode(API_SOFT_NAME)
|
"&softname=" + HttpReq::urlEncode(API_SOFT_NAME) + "&output=xml" +
|
||||||
+ "&output=xml"
|
"&recherche=" + HttpReq::urlEncode(searchName);
|
||||||
+ "&recherche=" + HttpReq::urlEncode(searchName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Username / password, if this has been setup and activated.
|
// 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 username = Settings::getInstance()->getString("ScraperUsernameScreenScraper");
|
||||||
std::string password = Settings::getInstance()->getString("ScraperPasswordScreenScraper");
|
std::string password = Settings::getInstance()->getString("ScraperPasswordScreenScraper");
|
||||||
if (!username.empty() && !password.empty())
|
if (!username.empty() && !password.empty())
|
||||||
screenScraperURL += "&ssid=" + HttpReq::urlEncode(username) + "&sspassword=" +
|
screenScraperURL += "&ssid=" + HttpReq::urlEncode(username) +
|
||||||
HttpReq::urlEncode(password);
|
"&sspassword=" + HttpReq::urlEncode(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
return screenScraperURL;
|
return screenScraperURL;
|
||||||
|
|
|
@ -10,49 +10,54 @@
|
||||||
#ifndef ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
#ifndef ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
||||||
#define ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
#define ES_APP_SCRAPERS_SCREEN_SCRAPER_H
|
||||||
|
|
||||||
#include "scrapers/Scraper.h"
|
|
||||||
#include "EmulationStation.h"
|
#include "EmulationStation.h"
|
||||||
|
#include "scrapers/Scraper.h"
|
||||||
|
|
||||||
namespace pugi { class xml_document; }
|
namespace pugi
|
||||||
|
{
|
||||||
|
class xml_document;
|
||||||
|
}
|
||||||
|
|
||||||
void screenscraper_generate_scraper_requests(
|
void screenscraper_generate_scraper_requests(const ScraperSearchParams& params,
|
||||||
const ScraperSearchParams& params,
|
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>& requests,
|
std::vector<ScraperSearchResult>& results);
|
||||||
std::vector<ScraperSearchResult>& results);
|
|
||||||
|
|
||||||
class ScreenScraperRequest : public ScraperHttpRequest
|
class ScreenScraperRequest : public ScraperHttpRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// ctor for a GetGameList request.
|
// ctor for a GetGameList request.
|
||||||
ScreenScraperRequest(std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
ScreenScraperRequest(std::queue<std::unique_ptr<ScraperRequest>>& requestsWrite,
|
||||||
std::vector<ScraperSearchResult>& resultsWrite,
|
std::vector<ScraperSearchResult>& resultsWrite,
|
||||||
const std::string& url) : ScraperHttpRequest(resultsWrite, url),
|
const std::string& url)
|
||||||
mRequestQueue(&requestsWrite) {}
|
: ScraperHttpRequest(resultsWrite, url)
|
||||||
|
, mRequestQueue(&requestsWrite)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// ctor for a GetGame request.
|
// ctor for a GetGame request.
|
||||||
ScreenScraperRequest(std::vector<ScraperSearchResult>& resultsWrite,
|
ScreenScraperRequest(std::vector<ScraperSearchResult>& resultsWrite, const std::string& url)
|
||||||
const std::string& url) : ScraperHttpRequest(resultsWrite, url),
|
: ScraperHttpRequest(resultsWrite, url)
|
||||||
mRequestQueue(nullptr) {}
|
, mRequestQueue(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Settings for the scraper.
|
// Settings for the scraper.
|
||||||
static const struct ScreenScraperConfig {
|
static const struct ScreenScraperConfig {
|
||||||
std::string getGameSearchUrl(const std::string gameName) const;
|
std::string getGameSearchUrl(const std::string gameName) const;
|
||||||
|
|
||||||
// Access to the API.
|
// Access to the API.
|
||||||
const std::string API_DEV_U =
|
const std::string API_DEV_U = { 15, 21, 39, 22, 42, 40 };
|
||||||
{ 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_P =
|
const std::string API_DEV_KEY = { 67, 112, 72, 120, 121, 77, 119, 74, 84, 56,
|
||||||
{ 32, 70, 46, 54, 12, 5, 13, 120, 50, 66, 25 };
|
75, 122, 78, 98, 69, 86, 56, 120, 120, 49 };
|
||||||
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_URL_BASE = "https://www.screenscraper.fr/api2";
|
||||||
const std::string API_SOFT_NAME = "EmulationStation-DE " +
|
const std::string API_SOFT_NAME =
|
||||||
static_cast<std::string>(PROGRAM_VERSION_STRING);
|
"EmulationStation-DE " + static_cast<std::string>(PROGRAM_VERSION_STRING);
|
||||||
|
|
||||||
// Which type of image artwork we need. Possible values (not a comprehensive list):
|
// Which type of image artwork we need. Possible values (not a comprehensive list):
|
||||||
// - ss: in-game screenshot
|
// - ss: in-game screenshot
|
||||||
// - box-3D: 3D boxart
|
// - box-3D: 3D boxart
|
||||||
// - box-2D: 2D boxart (default)
|
// - box-2D: 2D boxart
|
||||||
// - screenmarque : marquee
|
// - screenmarque : marquee
|
||||||
// - sstitle: in-game start screenshot
|
// - sstitle: in-game start screenshot
|
||||||
// - steamgrid: Steam artwork
|
// - steamgrid: Steam artwork
|
||||||
|
@ -75,27 +80,27 @@ public:
|
||||||
|
|
||||||
// Which Region to use when selecting the artwork.
|
// Which Region to use when selecting the artwork.
|
||||||
// Applies to: artwork, name of the game, date of release.
|
// 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.
|
// Which Language to use when selecting the textual information.
|
||||||
// Applies to: description, genre.
|
// 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;
|
} configuration;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void process(const std::unique_ptr<HttpReq>& req,
|
void process(const std::unique_ptr<HttpReq>& req,
|
||||||
std::vector<ScraperSearchResult>& results) override;
|
std::vector<ScraperSearchResult>& results) override;
|
||||||
|
|
||||||
void processList(const pugi::xml_document& xmldoc, std::vector<ScraperSearchResult>& results);
|
void processList(const pugi::xml_document& xmldoc, std::vector<ScraperSearchResult>& results);
|
||||||
void processGame(const pugi::xml_document& xmldoc, std::vector<ScraperSearchResult>& results);
|
void processGame(const pugi::xml_document& xmldoc, std::vector<ScraperSearchResult>& results);
|
||||||
void processMedia(ScraperSearchResult& result,
|
void processMedia(ScraperSearchResult& result,
|
||||||
const pugi::xml_node& media_list,
|
const pugi::xml_node& media_list,
|
||||||
std::string mediaType,
|
std::string mediaType,
|
||||||
std::string& fileURL,
|
std::string& fileURL,
|
||||||
std::string& fileFormat,
|
std::string& fileFormat,
|
||||||
std::string region);
|
std::string region);
|
||||||
bool isGameRequest() { return !mRequestQueue; }
|
bool isGameRequest() { return !mRequestQueue; }
|
||||||
|
|
||||||
std::queue<std::unique_ptr<ScraperRequest>>* mRequestQueue;
|
std::queue<std::unique_ptr<ScraperRequest>>* mRequestQueue;
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
|
|
||||||
#include "views/SystemView.h"
|
#include "views/SystemView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
|
||||||
#include "guis/GuiMsgBox.h"
|
|
||||||
#include "views/UIModeController.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
#include "animations/LambdaAnimation.h"
|
||||||
|
#include "guis/GuiMsgBox.h"
|
||||||
|
#include "views/UIModeController.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -26,14 +26,12 @@
|
||||||
const int logoBuffersLeft[] = { -5, -2, -1 };
|
const int logoBuffersLeft[] = { -5, -2, -1 };
|
||||||
const int logoBuffersRight[] = { 1, 2, 5 };
|
const int logoBuffersRight[] = { 1, 2, 5 };
|
||||||
|
|
||||||
SystemView::SystemView(
|
SystemView::SystemView(Window* window)
|
||||||
Window* window)
|
: IList<SystemViewData, SystemData*>(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP)
|
||||||
: IList<SystemViewData, SystemData*>
|
, mPreviousScrollVelocity(0)
|
||||||
(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP),
|
, mUpdatedGameCount(false)
|
||||||
mPreviousScrollVelocity(0),
|
, mViewNeedsReload(true)
|
||||||
mUpdatedGameCount(false),
|
, mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
||||||
mViewNeedsReload(true),
|
|
||||||
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
|
|
||||||
{
|
{
|
||||||
mCamOffset = 0;
|
mCamOffset = 0;
|
||||||
mExtrasCamOffset = 0;
|
mExtrasCamOffset = 0;
|
||||||
|
@ -58,8 +56,8 @@ void SystemView::populate()
|
||||||
{
|
{
|
||||||
mEntries.clear();
|
mEntries.clear();
|
||||||
|
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it != SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
|
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
|
||||||
|
|
||||||
if (mViewNeedsReload)
|
if (mViewNeedsReload)
|
||||||
|
@ -74,11 +72,11 @@ void SystemView::populate()
|
||||||
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
const ThemeData::ThemeElement* logoElem = theme->getElement("system", "logo", "image");
|
||||||
if (logoElem) {
|
if (logoElem) {
|
||||||
std::string path = logoElem->get<std::string>("path");
|
std::string path = logoElem->get<std::string>("path");
|
||||||
std::string defaultPath = logoElem->has("default") ?
|
std::string defaultPath =
|
||||||
logoElem->get<std::string>("default") : "";
|
logoElem->has("default") ? logoElem->get<std::string>("default") : "";
|
||||||
if ((!path.empty() && ResourceManager::getInstance()->fileExists(path)) ||
|
if ((!path.empty() && ResourceManager::getInstance()->fileExists(path)) ||
|
||||||
(!defaultPath.empty() &&
|
(!defaultPath.empty() &&
|
||||||
ResourceManager::getInstance()->fileExists(defaultPath))) {
|
ResourceManager::getInstance()->fileExists(defaultPath))) {
|
||||||
ImageComponent* logo = new ImageComponent(mWindow, false, false);
|
ImageComponent* logo = new ImageComponent(mWindow, false, false);
|
||||||
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
logo->setMaxSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||||
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
logo->applyTheme(theme, "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
|
||||||
|
@ -88,16 +86,14 @@ void SystemView::populate()
|
||||||
}
|
}
|
||||||
if (!e.data.logo) {
|
if (!e.data.logo) {
|
||||||
// No logo in theme; use text.
|
// No logo in theme; use text.
|
||||||
TextComponent* text = new TextComponent(
|
TextComponent* text =
|
||||||
mWindow,
|
new TextComponent(mWindow, (*it)->getName(), Font::get(FONT_SIZE_LARGE),
|
||||||
(*it)->getName(),
|
0x000000FF, ALIGN_CENTER);
|
||||||
Font::get(FONT_SIZE_LARGE),
|
|
||||||
0x000000FF,
|
|
||||||
ALIGN_CENTER);
|
|
||||||
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
text->setSize(mCarousel.logoSize * mCarousel.logoScale);
|
||||||
text->applyTheme((*it)->getTheme(), "system", "logoText",
|
text->applyTheme((*it)->getTheme(), "system", "logoText",
|
||||||
ThemeFlags::FONT_PATH | ThemeFlags::FONT_SIZE | ThemeFlags::COLOR |
|
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);
|
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||||
|
|
||||||
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) {
|
if (mCarousel.type == VERTICAL || mCarousel.type == VERTICAL_WHEEL) {
|
||||||
|
@ -134,10 +130,9 @@ void SystemView::populate()
|
||||||
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
e.data.backgroundExtras = ThemeData::makeExtras((*it)->getTheme(), "system", mWindow);
|
||||||
|
|
||||||
// Sort the extras by z-index.
|
// Sort the extras by z-index.
|
||||||
std::stable_sort(e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(),
|
std::stable_sort(
|
||||||
[](GuiComponent* a, GuiComponent* b) {
|
e.data.backgroundExtras.begin(), e.data.backgroundExtras.end(),
|
||||||
return b->getZIndex() > a->getZIndex();
|
[](GuiComponent* a, GuiComponent* b) { return b->getZIndex() > a->getZIndex(); });
|
||||||
});
|
|
||||||
|
|
||||||
this->add(e);
|
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.
|
// Something is wrong, there is not a single system to show, check if UI mode is not full.
|
||||||
if (!UIModeController::getInstance()->isUIModeFull()) {
|
if (!UIModeController::getInstance()->isUIModeFull()) {
|
||||||
Settings::getInstance()->setString("UIMode", "full");
|
Settings::getInstance()->setString("UIMode", "full");
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
"The selected UI mode has nothing to show,\n returning to UI mode \"Full\"",
|
mWindow, getHelpStyle(),
|
||||||
"OK", nullptr));
|
"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";
|
ss << "CONFIGURATION";
|
||||||
else if (getSelected()->isCollection() && (getSelected()->getName() == "favorites"))
|
else if (getSelected()->isCollection() && (getSelected()->getName() == "favorites"))
|
||||||
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S");
|
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.
|
// its maximum limit of 50 games.
|
||||||
else if (getSelected()->isCollection() && (getSelected()->getName() == "recent"))
|
else if (getSelected()->isCollection() && (getSelected()->getName() == "recent"))
|
||||||
ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME" <<
|
ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME"
|
||||||
(gameCount.first == 1 ? " " : "S");
|
<< (gameCount.first == 1 ? " " : "S");
|
||||||
else
|
else
|
||||||
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "(" <<
|
ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "("
|
||||||
gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)");
|
<< gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)");
|
||||||
|
|
||||||
mSystemInfo.setText(ss.str());
|
mSystemInfo.setText(ss.str());
|
||||||
}
|
}
|
||||||
|
@ -190,40 +186,40 @@ bool SystemView::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
if (input.value != 0) {
|
if (input.value != 0) {
|
||||||
if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r &&
|
if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r &&
|
||||||
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
||||||
LOG(LogDebug) << "SystemView::input(): Reloading all";
|
LOG(LogDebug) << "SystemView::input(): Reloading all";
|
||||||
ViewController::get()->reloadAll();
|
ViewController::get()->reloadAll();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mCarousel.type) {
|
switch (mCarousel.type) {
|
||||||
case VERTICAL:
|
case VERTICAL:
|
||||||
case VERTICAL_WHEEL:
|
case VERTICAL_WHEEL:
|
||||||
if (config->isMappedLike("up", input)) {
|
if (config->isMappedLike("up", input)) {
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
listInput(-1);
|
listInput(-1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (config->isMappedLike("down", input)) {
|
if (config->isMappedLike("down", input)) {
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
listInput(1);
|
listInput(1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HORIZONTAL:
|
case HORIZONTAL:
|
||||||
case HORIZONTAL_WHEEL:
|
case HORIZONTAL_WHEEL:
|
||||||
default:
|
default:
|
||||||
if (config->isMappedLike("left", input)) {
|
if (config->isMappedLike("left", input)) {
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
listInput(-1);
|
listInput(-1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (config->isMappedLike("right", input)) {
|
if (config->isMappedLike("right", input)) {
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
listInput(1);
|
listInput(1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->isMappedTo("a", input)) {
|
if (config->isMappedTo("a", input)) {
|
||||||
|
@ -233,17 +229,16 @@ bool SystemView::input(InputConfig* config, Input input)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Settings::getInstance()->getBool("RandomAddButton") &&
|
if (Settings::getInstance()->getBool("RandomAddButton") &&
|
||||||
(config->isMappedTo("leftthumbstickclick", input) ||
|
(config->isMappedTo("leftthumbstickclick", input) ||
|
||||||
config->isMappedTo("rightthumbstickclick", input))) {
|
config->isMappedTo("rightthumbstickclick", input))) {
|
||||||
// Get a random system and jump to it.
|
// Get a random system and jump to it.
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||||
setCursor(SystemData::getRandomSystem(getSelected()));
|
setCursor(SystemData::getRandomSystem(getSelected()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
if (!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("back", input) &&
|
||||||
config->isMappedTo("back", input) &&
|
Settings::getInstance()->getBool("ScreensaverControls")) {
|
||||||
Settings::getInstance()->getBool("ScreensaverControls")) {
|
|
||||||
if (!mWindow->isScreensaverActive()) {
|
if (!mWindow->isScreensaverActive()) {
|
||||||
ViewController::get()->stopScrolling();
|
ViewController::get()->stopScrolling();
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
|
@ -254,10 +249,8 @@ bool SystemView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (config->isMappedLike("left", input) ||
|
if (config->isMappedLike("left", input) || config->isMappedLike("right", input) ||
|
||||||
config->isMappedLike("right", input) ||
|
config->isMappedLike("up", input) || config->isMappedLike("down", input))
|
||||||
config->isMappedLike("up", input) ||
|
|
||||||
config->isMappedLike("down", input))
|
|
||||||
listInput(0);
|
listInput(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,8 +295,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
||||||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||||
|
|
||||||
// To prevent ugly jumps with two systems when quickly repeating the same direction.
|
// To prevent ugly jumps with two systems when quickly repeating the same direction.
|
||||||
if (mPreviousScrollVelocity != 0 && posMax == 2 &&
|
if (mPreviousScrollVelocity != 0 && posMax == 2 && mScrollVelocity == mPreviousScrollVelocity) {
|
||||||
mScrollVelocity == mPreviousScrollVelocity ) {
|
|
||||||
if (fabs(endPos - startPos) < 0.5 || fabs(endPos - startPos) > 1.5) {
|
if (fabs(endPos - startPos) < 0.5 || fabs(endPos - startPos) > 1.5) {
|
||||||
(mScrollVelocity < 0) ? endPos -= 1 : endPos += 1;
|
(mScrollVelocity < 0) ? endPos -= 1 : endPos += 1;
|
||||||
(mCursor == 0) ? mCursor = 1 : mCursor = 0;
|
(mCursor == 0) ? mCursor = 1 : mCursor = 0;
|
||||||
|
@ -321,77 +313,84 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
||||||
if (transition_style == "fade") {
|
if (transition_style == "fade") {
|
||||||
float startExtrasFade = mExtrasFadeOpacity;
|
float startExtrasFade = mExtrasFadeOpacity;
|
||||||
anim = new LambdaAnimation(
|
anim = new LambdaAnimation(
|
||||||
[this, startExtrasFade, startPos, endPos, posMax](float t) {
|
[this, startExtrasFade, startPos, endPos, posMax](float t) {
|
||||||
t -= 1;
|
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)
|
if (f < 0)
|
||||||
f += posMax;
|
f += posMax;
|
||||||
if (f >= posMax)
|
if (f >= posMax)
|
||||||
f -= posMax;
|
f -= posMax;
|
||||||
|
|
||||||
this->mCamOffset = f;
|
this->mCamOffset = f;
|
||||||
|
|
||||||
t += 1;
|
t += 1;
|
||||||
if (t < 0.3f)
|
if (t < 0.3f)
|
||||||
this->mExtrasFadeOpacity = Math::lerp(0.0f, 1.0f, t / 0.2f + startExtrasFade);
|
this->mExtrasFadeOpacity = Math::lerp(0.0f, 1.0f, t / 0.2f + startExtrasFade);
|
||||||
else if (t < 0.7f)
|
else if (t < 0.7f)
|
||||||
this->mExtrasFadeOpacity = 1.0f;
|
this->mExtrasFadeOpacity = 1.0f;
|
||||||
else
|
else
|
||||||
this->mExtrasFadeOpacity = Math::lerp(1.0f, 0.0f, (t - 0.6f) / 0.3f);
|
this->mExtrasFadeOpacity = Math::lerp(1.0f, 0.0f, (t - 0.6f) / 0.3f);
|
||||||
|
|
||||||
if (t > 0.5f)
|
if (t > 0.5f)
|
||||||
this->mExtrasCamOffset = endPos;
|
this->mExtrasCamOffset = endPos;
|
||||||
|
|
||||||
// Update the game count when the entire animation has been completed.
|
// Update the game count when the entire animation has been completed.
|
||||||
if (mExtrasFadeOpacity == 1.0)
|
if (mExtrasFadeOpacity == 1.0f)
|
||||||
updateGameCount();
|
updateGameCount();
|
||||||
}, 500);
|
},
|
||||||
|
500);
|
||||||
}
|
}
|
||||||
else if (transition_style == "slide") {
|
else if (transition_style == "slide") {
|
||||||
mUpdatedGameCount = false;
|
mUpdatedGameCount = false;
|
||||||
anim = new LambdaAnimation(
|
anim = new LambdaAnimation(
|
||||||
[this, startPos, endPos, posMax](float t) {
|
[this, startPos, endPos, posMax](float t) {
|
||||||
t -= 1;
|
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)
|
if (f < 0)
|
||||||
f += posMax;
|
f += posMax;
|
||||||
if (f >= posMax)
|
if (f >= posMax)
|
||||||
f -= posMax;
|
f -= posMax;
|
||||||
|
|
||||||
this->mCamOffset = f;
|
this->mCamOffset = f;
|
||||||
this->mExtrasCamOffset = f;
|
this->mExtrasCamOffset = f;
|
||||||
|
|
||||||
// Hack to make the game count being updated in the middle of the animation.
|
// Hack to make the game count being updated in the middle of the animation.
|
||||||
bool update = false;
|
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 &&
|
||||||
update = true;
|
!mUpdatedGameCount) {
|
||||||
else if (endPos > posMax && fabs(endPos - posMax - fabs(mCamOffset)) <
|
update = true;
|
||||||
0.5 && !mUpdatedGameCount)
|
}
|
||||||
update = true;
|
else if (endPos > posMax && fabs(endPos - posMax - fabs(mCamOffset)) < 0.5f &&
|
||||||
else if (fabs(fabs(endPos) - fabs(mCamOffset)) < 0.5 && !mUpdatedGameCount)
|
!mUpdatedGameCount) {
|
||||||
update = true;
|
update = true;
|
||||||
|
}
|
||||||
|
else if (fabs(fabs(endPos) - fabs(mCamOffset)) < 0.5f && !mUpdatedGameCount) {
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (update) {
|
if (update) {
|
||||||
mUpdatedGameCount = true;
|
mUpdatedGameCount = true;
|
||||||
updateGameCount();
|
updateGameCount();
|
||||||
}
|
}
|
||||||
}, 500);
|
},
|
||||||
|
500);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Instant.
|
// Instant.
|
||||||
updateGameCount();
|
updateGameCount();
|
||||||
anim = new LambdaAnimation(
|
anim = new LambdaAnimation(
|
||||||
[this, startPos, endPos, posMax](float t) {
|
[this, startPos, endPos, posMax](float t) {
|
||||||
t -= 1;
|
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)
|
if (f < 0)
|
||||||
f += posMax;
|
f += posMax;
|
||||||
if (f >= posMax)
|
if (f >= posMax)
|
||||||
f -= posMax;
|
f -= posMax;
|
||||||
|
|
||||||
this->mCamOffset = f;
|
this->mCamOffset = f;
|
||||||
this->mExtrasCamOffset = endPos;
|
this->mExtrasCamOffset = endPos;
|
||||||
}, 500);
|
},
|
||||||
|
500);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAnimation(anim, 0, nullptr, false, 0);
|
setAnimation(anim, 0, nullptr, false, 0);
|
||||||
|
@ -400,7 +399,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/)
|
||||||
void SystemView::render(const Transform4x4f& parentTrans)
|
void SystemView::render(const Transform4x4f& parentTrans)
|
||||||
{
|
{
|
||||||
if (size() == 0)
|
if (size() == 0)
|
||||||
return; // Nothing to render.
|
return; // Nothing to render.
|
||||||
|
|
||||||
Transform4x4f trans = getTransform() * parentTrans;
|
Transform4x4f trans = getTransform() * parentTrans;
|
||||||
|
|
||||||
|
@ -430,7 +429,7 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
||||||
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
||||||
|
|
||||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||||
Settings::getInstance()->getBool("ScreensaverControls"))
|
Settings::getInstance()->getBool("ScreensaverControls"))
|
||||||
prompts.push_back(HelpPrompt("back", "toggle screensaver"));
|
prompts.push_back(HelpPrompt("back", "toggle screensaver"));
|
||||||
|
|
||||||
return prompts;
|
return prompts;
|
||||||
|
@ -443,7 +442,7 @@ HelpStyle SystemView::getHelpStyle()
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemView::onThemeChanged(const std::shared_ptr<ThemeData>& /*theme*/)
|
void SystemView::onThemeChanged(const std::shared_ptr<ThemeData>& /*theme*/)
|
||||||
{
|
{
|
||||||
LOG(LogDebug) << "SystemView::onThemeChanged()";
|
LOG(LogDebug) << "SystemView::onThemeChanged()";
|
||||||
mViewNeedsReload = true;
|
mViewNeedsReload = true;
|
||||||
|
@ -451,7 +450,7 @@ void SystemView::onThemeChanged(const std::shared_ptr<ThemeData>& /*theme*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the ThemeElements that make up the SystemView.
|
// Get the ThemeElements that make up the SystemView.
|
||||||
void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
||||||
{
|
{
|
||||||
LOG(LogDebug) << "SystemView::getViewElements()";
|
LOG(LogDebug) << "SystemView::getViewElements()";
|
||||||
|
|
||||||
|
@ -460,13 +459,14 @@ void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
|
||||||
if (!theme->hasView("system"))
|
if (!theme->hasView("system"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ThemeData::ThemeElement* carouselElem = theme->
|
const ThemeData::ThemeElement* carouselElem =
|
||||||
getElement("system", "systemcarousel", "carousel");
|
theme->getElement("system", "systemcarousel", "carousel");
|
||||||
|
|
||||||
if (carouselElem)
|
if (carouselElem)
|
||||||
getCarouselFromTheme(carouselElem);
|
getCarouselFromTheme(carouselElem);
|
||||||
|
|
||||||
const ThemeData::ThemeElement* sysInfoElem = theme->
|
const ThemeData::ThemeElement* sysInfoElem = theme->getElement("system", "systemInfo", "text");
|
||||||
getElement("system", "systemInfo", "text");
|
|
||||||
if (sysInfoElem)
|
if (sysInfoElem)
|
||||||
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
|
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
|
||||||
|
|
||||||
|
@ -479,71 +479,79 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
||||||
// Background box behind logos.
|
// Background box behind logos.
|
||||||
Transform4x4f carouselTrans = trans;
|
Transform4x4f carouselTrans = trans;
|
||||||
carouselTrans.translate(Vector3f(mCarousel.pos.x(), mCarousel.pos.y(), 0.0));
|
carouselTrans.translate(Vector3f(mCarousel.pos.x(), mCarousel.pos.y(), 0.0));
|
||||||
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1,
|
carouselTrans.translate(Vector3f(mCarousel.origin.x() * mCarousel.size.x() * -1.0f,
|
||||||
mCarousel.origin.y() * mCarousel.size.y() * -1, 0.0f));
|
mCarousel.origin.y() * mCarousel.size.y() * -1.0f, 0.0f));
|
||||||
|
|
||||||
Vector2f clipPos(carouselTrans.translation().x(), carouselTrans.translation().y());
|
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>(mCarousel.size.x()), static_cast<int>(mCarousel.size.y())));
|
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::setMatrix(carouselTrans);
|
||||||
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(),
|
Renderer::drawRect(0.0f, 0.0f, mCarousel.size.x(), mCarousel.size.y(), mCarousel.color,
|
||||||
mCarousel.color, mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
mCarousel.colorEnd, mCarousel.colorGradientHorizontal);
|
||||||
|
|
||||||
// Draw logos.
|
// Draw logos.
|
||||||
// Note: logoSpacing will also include the size of the logo itself.
|
// Note: logoSpacing will also include the size of the logo itself.
|
||||||
Vector2f logoSpacing(0.0, 0.0);
|
Vector2f logoSpacing(0.0f, 0.0f);
|
||||||
float xOff = 0.0;
|
float xOff = 0.0f;
|
||||||
float yOff = 0.0;
|
float yOff = 0.0f;
|
||||||
|
|
||||||
switch (mCarousel.type) {
|
switch (mCarousel.type) {
|
||||||
case VERTICAL_WHEEL:
|
case VERTICAL_WHEEL: {
|
||||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f -
|
||||||
(mCamOffset * logoSpacing[1]);
|
(mCamOffset * logoSpacing[1]);
|
||||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||||
xOff = mCarousel.logoSize.x() / 10.f;
|
xOff = mCarousel.logoSize.x() / 10.0f;
|
||||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||||
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
||||||
else
|
else
|
||||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f;
|
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f;
|
||||||
break;
|
break;
|
||||||
case VERTICAL:
|
}
|
||||||
logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() *
|
case VERTICAL: {
|
||||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y();
|
logoSpacing[1] =
|
||||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f -
|
((mCarousel.size.y() - (mCarousel.logoSize.y() * mCarousel.maxLogoCount)) /
|
||||||
(mCamOffset * logoSpacing[1]);
|
(mCarousel.maxLogoCount)) +
|
||||||
|
mCarousel.logoSize.y();
|
||||||
|
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f -
|
||||||
|
(mCamOffset * logoSpacing[1]);
|
||||||
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
if (mCarousel.logoAlignment == ALIGN_LEFT)
|
||||||
xOff = mCarousel.logoSize.x() / 10.f;
|
xOff = mCarousel.logoSize.x() / 10.0f;
|
||||||
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
else if (mCarousel.logoAlignment == ALIGN_RIGHT)
|
||||||
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
xOff = mCarousel.size.x() - (mCarousel.logoSize.x() * 1.1f);
|
||||||
else
|
else
|
||||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2;
|
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f;
|
||||||
break;
|
break;
|
||||||
case HORIZONTAL_WHEEL:
|
}
|
||||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 -
|
case HORIZONTAL_WHEEL: {
|
||||||
(mCamOffset * logoSpacing[1]);
|
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.0f -
|
||||||
|
(mCamOffset * logoSpacing[1]);
|
||||||
if (mCarousel.logoAlignment == ALIGN_TOP)
|
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||||
yOff = mCarousel.logoSize.y() / 10;
|
yOff = mCarousel.logoSize.y() / 10.0f;
|
||||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||||
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
||||||
else
|
else
|
||||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2;
|
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f;
|
||||||
break;
|
break;
|
||||||
case HORIZONTAL:
|
}
|
||||||
default:
|
case HORIZONTAL: {
|
||||||
logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() *
|
}
|
||||||
mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x();
|
default: {
|
||||||
xOff = (mCarousel.size.x() - mCarousel.logoSize.x()) / 2.f -
|
logoSpacing[0] =
|
||||||
(mCamOffset * 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)
|
if (mCarousel.logoAlignment == ALIGN_TOP)
|
||||||
yOff = mCarousel.logoSize.y() / 10.f;
|
yOff = mCarousel.logoSize.y() / 10.0f;
|
||||||
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
else if (mCarousel.logoAlignment == ALIGN_BOTTOM)
|
||||||
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
yOff = mCarousel.size.y() - (mCarousel.logoSize.y() * 1.1f);
|
||||||
else
|
else
|
||||||
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.f;
|
yOff = (mCarousel.size.y() - mCarousel.logoSize.y()) / 2.0f;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int center = static_cast<int>(mCamOffset);
|
int center = static_cast<int>(mCamOffset);
|
||||||
|
@ -558,9 +566,10 @@ void SystemView::renderCarousel(const Transform4x4f& trans)
|
||||||
bufferRight = 0;
|
bufferRight = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = center - logoCount / 2 + bufferLeft;
|
for (int i = center - logoCount / 2 + bufferLeft; // Line break.
|
||||||
i <= center + logoCount / 2 + bufferRight; i++) {
|
i <= center + logoCount / 2 + bufferRight; i++) {
|
||||||
int index = i;
|
int index = i;
|
||||||
|
|
||||||
while (index < 0)
|
while (index < 0)
|
||||||
index += static_cast<int>(mEntries.size());
|
index += static_cast<int>(mEntries.size());
|
||||||
while (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 = std::min(mCarousel.logoScale, std::max(1.0f, scale));
|
||||||
scale /= mCarousel.logoScale;
|
scale /= mCarousel.logoScale;
|
||||||
|
|
||||||
int opacity = static_cast<int>(std::round(0x80 + ((0xFF - 0x80) *
|
int opacity =
|
||||||
(1.0f - fabs(distance)))));
|
static_cast<int>(std::round(0x80 + ((0xFF - 0x80) * (1.0f - fabs(distance)))));
|
||||||
opacity = std::max(static_cast<int>(0x80), opacity);
|
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) {
|
if (mCarousel.type == VERTICAL_WHEEL || mCarousel.type == HORIZONTAL_WHEEL) {
|
||||||
comp->setRotationDegrees(mCarousel.logoRotation * distance);
|
comp->setRotationDegrees(mCarousel.logoRotation * distance);
|
||||||
comp->setRotationOrigin(mCarousel.logoRotationOrigin);
|
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.
|
// Adding texture loading buffers depending on scrolling speed and status.
|
||||||
int bufferIndex = getScrollingVelocity() + 1;
|
int bufferIndex = getScrollingVelocity() + 1;
|
||||||
|
|
||||||
Renderer::pushClipRect(Vector2i::Zero(), Vector2i(static_cast<int>(mSize.x()),
|
Renderer::pushClipRect(Vector2i::Zero(),
|
||||||
static_cast<int>(mSize.y())));
|
Vector2i(static_cast<int>(mSize.x()), static_cast<int>(mSize.y())));
|
||||||
|
|
||||||
for (int i = extrasCenter + logoBuffersLeft[bufferIndex]; i <= extrasCenter +
|
for (int i = extrasCenter + logoBuffersLeft[bufferIndex];
|
||||||
logoBuffersRight[bufferIndex]; i++) {
|
i <= extrasCenter + logoBuffersRight[bufferIndex]; i++) {
|
||||||
int index = i;
|
int index = i;
|
||||||
while (index < 0)
|
while (index < 0)
|
||||||
index += static_cast<int>(mEntries.size());
|
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());
|
index -= static_cast<int>(mEntries.size());
|
||||||
|
|
||||||
// Only render selected system when not showing.
|
// Only render selected system when not showing.
|
||||||
if (mShowing || index == mCursor)
|
if (mShowing || index == mCursor) {
|
||||||
{
|
|
||||||
Transform4x4f extrasTrans = trans;
|
Transform4x4f extrasTrans = trans;
|
||||||
if (mCarousel.type == HORIZONTAL || mCarousel.type == HORIZONTAL_WHEEL)
|
if (mCarousel.type == HORIZONTAL || mCarousel.type == HORIZONTAL_WHEEL)
|
||||||
extrasTrans.translate(Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0));
|
extrasTrans.translate(Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0));
|
||||||
else
|
else
|
||||||
extrasTrans.translate(Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0));
|
extrasTrans.translate(Vector3f(0, (i - mExtrasCamOffset) * mSize.y(), 0));
|
||||||
|
|
||||||
Renderer::pushClipRect(Vector2i(static_cast<int>(extrasTrans.translation()[0]),
|
Renderer::pushClipRect(
|
||||||
static_cast<int>(extrasTrans.translation()[1])),
|
Vector2i(static_cast<int>(extrasTrans.translation()[0]),
|
||||||
Vector2i(static_cast<int>(mSize.x()), static_cast<int>(mSize.y())));
|
static_cast<int>(extrasTrans.translation()[1])),
|
||||||
|
Vector2i(static_cast<int>(mSize.x()), static_cast<int>(mSize.y())));
|
||||||
SystemViewData data = mEntries.at(index).data;
|
SystemViewData data = mEntries.at(index).data;
|
||||||
for (unsigned int j = 0; j < data.backgroundExtras.size(); j++) {
|
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)
|
if (extra->getZIndex() >= lower && extra->getZIndex() < upper)
|
||||||
extra->render(extrasTrans);
|
extra->render(extrasTrans);
|
||||||
}
|
}
|
||||||
|
@ -637,13 +646,13 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp
|
||||||
|
|
||||||
void SystemView::renderFade(const Transform4x4f& trans)
|
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::setMatrix(trans);
|
||||||
Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor);
|
Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the system carousel with the legacy values.
|
// Populate the system carousel with the legacy values.
|
||||||
void SystemView::getDefaultElements(void)
|
void SystemView::getDefaultElements(void)
|
||||||
{
|
{
|
||||||
// Carousel.
|
// Carousel.
|
||||||
mCarousel.type = HORIZONTAL;
|
mCarousel.type = HORIZONTAL;
|
||||||
|
@ -658,13 +667,13 @@ void SystemView::getDefaultElements(void)
|
||||||
mCarousel.colorEnd = 0xFFFFFFD8;
|
mCarousel.colorEnd = 0xFFFFFFD8;
|
||||||
mCarousel.colorGradientHorizontal = true;
|
mCarousel.colorGradientHorizontal = true;
|
||||||
mCarousel.logoScale = 1.2f;
|
mCarousel.logoScale = 1.2f;
|
||||||
mCarousel.logoRotation = 7.5;
|
mCarousel.logoRotation = 7.5f;
|
||||||
mCarousel.logoRotationOrigin.x() = -5;
|
mCarousel.logoRotationOrigin.x() = -5.0f;
|
||||||
mCarousel.logoRotationOrigin.y() = 0.5;
|
mCarousel.logoRotationOrigin.y() = 0.5f;
|
||||||
mCarousel.logoSize.x() = 0.25f * mSize.x();
|
mCarousel.logoSize.x() = 0.25f * mSize.x();
|
||||||
mCarousel.logoSize.y() = 0.155f * mSize.y();
|
mCarousel.logoSize.y() = 0.155f * mSize.y();
|
||||||
mCarousel.maxLogoCount = 3;
|
mCarousel.maxLogoCount = 3;
|
||||||
mCarousel.zIndex = 40;
|
mCarousel.zIndex = 40.0f;
|
||||||
|
|
||||||
// System info bar.
|
// System info bar.
|
||||||
mSystemInfo.setSize(mSize.x(), mSystemInfo.getFont()->getLetterHeight() * 2.2f);
|
mSystemInfo.setSize(mSize.x(), mSystemInfo.getFont()->getLetterHeight() * 2.2f);
|
||||||
|
@ -702,7 +711,8 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
||||||
if (elem->has("colorEnd"))
|
if (elem->has("colorEnd"))
|
||||||
mCarousel.colorEnd = elem->get<unsigned int>("colorEnd");
|
mCarousel.colorEnd = elem->get<unsigned int>("colorEnd");
|
||||||
if (elem->has("gradientType"))
|
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"))
|
if (elem->has("logoScale"))
|
||||||
mCarousel.logoScale = elem->get<float>("logoScale");
|
mCarousel.logoScale = elem->get<float>("logoScale");
|
||||||
if (elem->has("logoSize"))
|
if (elem->has("logoSize"))
|
||||||
|
@ -727,14 +737,4 @@ void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
|
||||||
else
|
else
|
||||||
mCarousel.logoAlignment = ALIGN_CENTER;
|
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
|
#ifndef ES_APP_VIEWS_SYSTEM_VIEW_H
|
||||||
#define 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/IList.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
#include "resources/Font.h"
|
#include "resources/Font.h"
|
||||||
#include "GuiComponent.h"
|
|
||||||
#include "Sound.h"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ public:
|
||||||
SystemView(Window* window);
|
SystemView(Window* window);
|
||||||
~SystemView();
|
~SystemView();
|
||||||
|
|
||||||
virtual void onShow() override;
|
virtual void onShow() override { mShowing = true; }
|
||||||
virtual void onHide() override;
|
virtual void onHide() override { mShowing = false; }
|
||||||
|
|
||||||
void goToSystem(SystemData* system, bool animate);
|
void goToSystem(SystemData* system, bool animate);
|
||||||
|
|
||||||
|
@ -69,12 +69,14 @@ public:
|
||||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
virtual HelpStyle getHelpStyle() override;
|
virtual HelpStyle getHelpStyle() override;
|
||||||
|
|
||||||
CarouselType getCarouselType() { return mCarousel.type; };
|
CarouselType getCarouselType() { return mCarousel.type; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onCursorChanged(const CursorState& state) override;
|
void onCursorChanged(const CursorState& state) override;
|
||||||
virtual void onScroll() override {
|
virtual void onScroll() override
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND); }
|
{
|
||||||
|
NavigationSounds::getInstance()->playThemeNavigationSound(SYSTEMBROWSESOUND);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void populate();
|
void populate();
|
||||||
|
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
#include "UIModeController.h"
|
#include "UIModeController.h"
|
||||||
|
|
||||||
#include "utils/StringUtil.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
UIModeController* UIModeController::sInstance = nullptr;
|
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");
|
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
|
||||||
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
|
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
|
||||||
|
@ -47,13 +48,12 @@ void UIModeController::monitorUIMode()
|
||||||
if (uimode != mCurrentUIMode && !ViewController::get()->isCameraMoving()) {
|
if (uimode != mCurrentUIMode && !ViewController::get()->isCameraMoving()) {
|
||||||
mCurrentUIMode = uimode;
|
mCurrentUIMode = uimode;
|
||||||
// Reset filters and sort gamelists (which will update the game counter).
|
// Reset filters and sort gamelists (which will update the game counter).
|
||||||
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
(*it)->sortSystem(true);
|
(*it)->sortSystem(true);
|
||||||
(*it)->getIndex()->resetFilters();
|
(*it)->getIndex()->resetFilters();
|
||||||
if ((*it)->getThemeFolder() == "custom-collections") {
|
if ((*it)->getThemeFolder() == "custom-collections") {
|
||||||
for (FileData* customSystem :
|
for (FileData* customSystem : (*it)->getRootFolder()->getChildrenListToDisplay())
|
||||||
(*it)->getRootFolder()->getChildrenListToDisplay())
|
|
||||||
customSystem->getSystem()->getIndex()->resetFilters();
|
customSystem->getSystem()->getIndex()->resetFilters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ bool UIModeController::listen(InputConfig* config, Input input)
|
||||||
unlockUIMode();
|
unlockUIMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,21 +102,21 @@ void UIModeController::unlockUIMode()
|
||||||
|
|
||||||
bool UIModeController::isUIModeFull()
|
bool UIModeController::isUIModeFull()
|
||||||
{
|
{
|
||||||
return ((mCurrentUIMode == "full" || (isUIModeKid() &&
|
return ((mCurrentUIMode == "full" ||
|
||||||
Settings::getInstance()->getBool("EnableMenuKidMode")))
|
(isUIModeKid() && Settings::getInstance()->getBool("EnableMenuKidMode"))) &&
|
||||||
&& !Settings::getInstance()->getBool("ForceKiosk"));
|
!Settings::getInstance()->getBool("ForceKiosk"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIModeController::isUIModeKid()
|
bool UIModeController::isUIModeKid()
|
||||||
{
|
{
|
||||||
return (Settings::getInstance()->getBool("ForceKid") ||
|
return (Settings::getInstance()->getBool("ForceKid") ||
|
||||||
((mCurrentUIMode == "kid") && !Settings::getInstance()->getBool("ForceKiosk")));
|
((mCurrentUIMode == "kid") && !Settings::getInstance()->getBool("ForceKiosk")));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UIModeController::isUIModeKiosk()
|
bool UIModeController::isUIModeKiosk()
|
||||||
{
|
{
|
||||||
return (Settings::getInstance()->getBool("ForceKiosk") ||
|
return (Settings::getInstance()->getBool("ForceKiosk") ||
|
||||||
((mCurrentUIMode == "kiosk") && !Settings::getInstance()->getBool("ForceKid")));
|
((mCurrentUIMode == "kiosk") && !Settings::getInstance()->getBool("ForceKid")));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UIModeController::getFormattedPassKeyStr()
|
std::string UIModeController::getFormattedPassKeyStr()
|
||||||
|
@ -124,7 +125,7 @@ std::string UIModeController::getFormattedPassKeyStr()
|
||||||
|
|
||||||
std::string out = "";
|
std::string out = "";
|
||||||
for (auto c : mPassKeySequence) {
|
for (auto c : mPassKeySequence) {
|
||||||
out += (out == "") ? "" : " , "; // Add commas between the entries.
|
out += (out == "") ? "" : " , "; // Add commas between the entries.
|
||||||
|
|
||||||
std::string controllerType = Settings::getInstance()->getString("InputControllerType");
|
std::string controllerType = Settings::getInstance()->getString("InputControllerType");
|
||||||
std::string symbolA;
|
std::string symbolA;
|
||||||
|
@ -139,19 +140,19 @@ std::string UIModeController::getFormattedPassKeyStr()
|
||||||
symbolY = "X";
|
symbolY = "X";
|
||||||
}
|
}
|
||||||
else if (controllerType == "ps4" || controllerType == "ps5") {
|
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
|
// These symbols are far from perfect but you can at least understand what
|
||||||
// they are supposed to depict.
|
// they are supposed to depict.
|
||||||
#if defined(_MSC_VER) // MSVC compiler.
|
|
||||||
symbolA = Utils::String::wideStringToString(L"\uF00D"); // Cross.
|
symbolA = Utils::String::wideStringToString(L"\uF00D"); // Cross.
|
||||||
symbolB = Utils::String::wideStringToString(L"\uF111"); // Circle
|
symbolB = Utils::String::wideStringToString(L"\uF111"); // Circle
|
||||||
symbolX = Utils::String::wideStringToString(L"\uF04D"); // Square.
|
symbolX = Utils::String::wideStringToString(L"\uF04D"); // Square.
|
||||||
symbolY = Utils::String::wideStringToString(L"\uF0D8"); // Triangle.
|
symbolY = Utils::String::wideStringToString(L"\uF0D8"); // Triangle.
|
||||||
#else
|
#else
|
||||||
symbolA = "\uF00D"; // Cross.
|
symbolA = "\uF00D"; // Cross.
|
||||||
symbolB = "\uF111"; // Circle
|
symbolB = "\uF111"; // Circle
|
||||||
symbolX = "\uF04D"; // Square.
|
symbolX = "\uF04D"; // Square.
|
||||||
symbolY = "\uF0D8"; // Triangle.
|
symbolY = "\uF0D8"; // Triangle.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Xbox controller.
|
// Xbox controller.
|
||||||
|
@ -193,8 +194,8 @@ std::string UIModeController::getFormattedPassKeyStr()
|
||||||
|
|
||||||
bool UIModeController::isValidInput(InputConfig* config, Input input)
|
bool UIModeController::isValidInput(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if ((config->getMappedTo(input).size() == 0) || // Not a mapped input, so ignore it.
|
if ((config->getMappedTo(input).size() == 0) || // Not a mapped input, so ignore it.
|
||||||
(!input.value)) // Not a key-down event.
|
(!input.value)) // Not a key-down event.
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
bool isUIModeKid();
|
bool isUIModeKid();
|
||||||
bool isUIModeKiosk();
|
bool isUIModeKiosk();
|
||||||
|
|
||||||
void setCurrentUIMode(const std::string& mode) { mCurrentUIMode = mode; };
|
void setCurrentUIMode(const std::string& mode) { mCurrentUIMode = mode; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UIModeController();
|
UIModeController();
|
||||||
|
@ -58,8 +58,9 @@ private:
|
||||||
int mPassKeyCounter;
|
int mPassKeyCounter;
|
||||||
|
|
||||||
// These are Xbox button names, so they may be different in pracise on non-Xbox controllers.
|
// These are Xbox button names, so they may be different in pracise on non-Xbox controllers.
|
||||||
const std::vector<std::string> mInputVals =
|
const std::vector<std::string> mInputVals = {
|
||||||
{ "up", "down", "left", "right", "a", "b", "x", "y" };
|
"up", "down", "left", "right", "a", "b", "x", "y"
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_VIEWS_UI_MODE_CONTROLLER_H
|
#endif // ES_APP_VIEWS_UI_MODE_CONTROLLER_H
|
||||||
|
|
|
@ -12,17 +12,6 @@
|
||||||
|
|
||||||
#include "views/ViewController.h"
|
#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 "AudioManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "InputManager.h"
|
#include "InputManager.h"
|
||||||
|
@ -32,8 +21,20 @@
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "SystemView.h"
|
#include "SystemView.h"
|
||||||
#include "Window.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;
|
ViewController* ViewController::sInstance = nullptr;
|
||||||
|
|
||||||
#if defined(_MSC_VER) // MSVC compiler.
|
#if defined(_MSC_VER) // MSVC compiler.
|
||||||
const std::string ViewController::FAVORITE_CHAR = Utils::String::wideStringToString(L"\uF005");
|
const std::string ViewController::FAVORITE_CHAR = Utils::String::wideStringToString(L"\uF005");
|
||||||
const std::string ViewController::FOLDER_CHAR = Utils::String::wideStringToString(L"\uF07C");
|
const std::string ViewController::FOLDER_CHAR = Utils::String::wideStringToString(L"\uF07C");
|
||||||
|
@ -60,21 +61,20 @@ void ViewController::init(Window* window)
|
||||||
sInstance = new ViewController(window);
|
sInstance = new ViewController(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewController::ViewController(
|
ViewController::ViewController(Window* window)
|
||||||
Window* window)
|
: GuiComponent(window)
|
||||||
: GuiComponent(window),
|
, mCurrentView(nullptr)
|
||||||
mCurrentView(nullptr),
|
, mPreviousView(nullptr)
|
||||||
mPreviousView(nullptr),
|
, mSkipView(nullptr)
|
||||||
mSkipView(nullptr),
|
, mCamera(Transform4x4f::Identity())
|
||||||
mCamera(Transform4x4f::Identity()),
|
, mSystemViewTransition(false)
|
||||||
mSystemViewTransition(false),
|
, mWrappedViews(false)
|
||||||
mWrappedViews(false),
|
, mFadeOpacity(0)
|
||||||
mFadeOpacity(0),
|
, mCancelledTransition(false)
|
||||||
mCancelledTransition(false),
|
, mLockInput(false)
|
||||||
mLockInput(false),
|
, mNextSystem(false)
|
||||||
mNextSystem(false),
|
, mGameToLaunch(nullptr)
|
||||||
mGameToLaunch(nullptr),
|
, mNoGamesMessageBox(nullptr)
|
||||||
mNoGamesMessageBox(nullptr)
|
|
||||||
{
|
{
|
||||||
mState.viewing = NOTHING;
|
mState.viewing = NOTHING;
|
||||||
mState.viewstyle = AUTOMATIC;
|
mState.viewstyle = AUTOMATIC;
|
||||||
|
@ -89,108 +89,106 @@ ViewController::~ViewController()
|
||||||
|
|
||||||
void ViewController::invalidSystemsFileDialog()
|
void ViewController::invalidSystemsFileDialog()
|
||||||
{
|
{
|
||||||
std::string errorMessage =
|
std::string errorMessage = "COULDN'T PARSE THE SYSTEMS CONFIGURATION FILE.\n"
|
||||||
"COULDN'T PARSE THE SYSTEMS CONFIGURATION FILE.\n"
|
"IF YOU HAVE A CUSTOMIZED es_systems.xml FILE, THEN\n"
|
||||||
"IF YOU HAVE A CUSTOMIZED es_systems.xml FILE, THEN\n"
|
"SOMETHING IS LIKELY WRONG WITH YOUR XML SYNTAX.\n"
|
||||||
"SOMETHING IS LIKELY WRONG WITH YOUR XML SYNTAX.\n"
|
"IF YOU DON'T HAVE A CUSTOM SYSTEMS FILE, THEN THE\n"
|
||||||
"IF YOU DON'T HAVE A CUSTOM SYSTEMS FILE, THEN THE\n"
|
"EMULATIONSTATION INSTALLATION IS BROKEN. SEE THE\n"
|
||||||
"EMULATIONSTATION INSTALLATION IS BROKEN. SEE THE\n"
|
"APPLICATION LOG FILE es_log.txt FOR ADDITIONAL INFO.";
|
||||||
"APPLICATION LOG FILE es_log.txt FOR ADDITIONAL INFO.";
|
|
||||||
|
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
errorMessage.c_str(),
|
mWindow, HelpStyle(), errorMessage.c_str(), "QUIT",
|
||||||
"QUIT", [] {
|
[] {
|
||||||
SDL_Event quit;
|
SDL_Event quit;
|
||||||
quit.type = SDL_QUIT;
|
quit.type = SDL_QUIT;
|
||||||
SDL_PushEvent(&quit);
|
SDL_PushEvent(&quit);
|
||||||
}, "", nullptr, "", nullptr, true));
|
},
|
||||||
|
"", nullptr, "", nullptr, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::noGamesDialog()
|
void ViewController::noGamesDialog()
|
||||||
{
|
{
|
||||||
mNoGamesErrorMessage =
|
mNoGamesErrorMessage = "NO GAME FILES WERE FOUND. EITHER PLACE YOUR GAMES IN\n"
|
||||||
"NO GAME FILES WERE FOUND. EITHER PLACE YOUR GAMES IN\n"
|
"THE CURRENTLY CONFIGURED ROM DIRECTORY OR CHANGE\n"
|
||||||
"THE CURRENTLY CONFIGURED ROM DIRECTORY OR CHANGE\n"
|
"ITS PATH USING THE BUTTON BELOW. OPTIONALLY THE ROM\n"
|
||||||
"ITS PATH USING THE BUTTON BELOW. OPTIONALLY THE ROM\n"
|
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL\n"
|
||||||
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL\n"
|
"CREATE A TEXT FILE FOR EACH SYSTEM PROVIDING SOME\n"
|
||||||
"CREATE A TEXT FILE FOR EACH SYSTEM PROVIDING SOME\n"
|
"INFORMATION SUCH AS THE SUPPORTED FILE EXTENSIONS.\n"
|
||||||
"INFORMATION SUCH AS THE SUPPORTED FILE EXTENSIONS.\n"
|
"THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n";
|
||||||
"THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n";
|
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||||
#else
|
#else
|
||||||
mRomDirectory = FileData::getROMDirectory();
|
mRomDirectory = FileData::getROMDirectory();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mNoGamesMessageBox = new GuiMsgBox(mWindow, HelpStyle(), mNoGamesErrorMessage + mRomDirectory,
|
mNoGamesMessageBox = new GuiMsgBox(
|
||||||
"CHANGE ROM DIRECTORY", [this] {
|
mWindow, HelpStyle(), mNoGamesErrorMessage + mRomDirectory, "CHANGE ROM DIRECTORY",
|
||||||
std::string currentROMDirectory;
|
[this] {
|
||||||
#if defined(_WIN64)
|
std::string currentROMDirectory;
|
||||||
currentROMDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
#if defined(_WIN64)
|
||||||
#else
|
currentROMDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||||
currentROMDirectory = FileData::getROMDirectory();
|
#else
|
||||||
#endif
|
currentROMDirectory = FileData::getROMDirectory();
|
||||||
|
#endif
|
||||||
|
|
||||||
mWindow->pushGui(new GuiComplexTextEditPopup(
|
mWindow->pushGui(new GuiComplexTextEditPopup(
|
||||||
mWindow,
|
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH",
|
||||||
HelpStyle(),
|
"Currently configured path:", currentROMDirectory, currentROMDirectory,
|
||||||
"ENTER ROM DIRECTORY PATH",
|
|
||||||
"Currently configured path:",
|
|
||||||
currentROMDirectory,
|
|
||||||
currentROMDirectory,
|
|
||||||
[this](const std::string& newROMDirectory) {
|
[this](const std::string& newROMDirectory) {
|
||||||
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
||||||
Settings::getInstance()->saveFile();
|
Settings::getInstance()->saveFile();
|
||||||
#if defined(_WIN64)
|
#if defined(_WIN64)
|
||||||
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
||||||
#else
|
#else
|
||||||
mRomDirectory = FileData::getROMDirectory();
|
mRomDirectory = FileData::getROMDirectory();
|
||||||
#endif
|
#endif
|
||||||
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||||
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
||||||
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
||||||
"OK", nullptr, "", nullptr, "", nullptr, true));
|
"OK", nullptr, "", nullptr, "", nullptr, true));
|
||||||
},
|
},
|
||||||
false,
|
false, "SAVE", "SAVE CHANGES?", "LOAD CURRENT", "LOAD CURRENTLY CONFIGURED VALUE",
|
||||||
"SAVE",
|
"CLEAR", "CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)", false));
|
||||||
"SAVE CHANGES?",
|
},
|
||||||
"LOAD CURRENT",
|
"CREATE DIRECTORIES",
|
||||||
"LOAD CURRENTLY CONFIGURED VALUE",
|
[this] {
|
||||||
"CLEAR",
|
mWindow->pushGui(new GuiMsgBox(
|
||||||
"CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)",
|
mWindow, HelpStyle(),
|
||||||
false));
|
|
||||||
},
|
|
||||||
"CREATE DIRECTORIES", [this] {
|
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
|
||||||
"THIS WILL CREATE DIRECTORIES FOR ALL THE\n"
|
"THIS WILL CREATE DIRECTORIES FOR ALL THE\n"
|
||||||
"GAME SYSTEMS DEFINED IN es_systems.xml\n\n"
|
"GAME SYSTEMS DEFINED IN es_systems.xml\n\n"
|
||||||
"THIS MAY CREATE A LOT OF FOLDERS SO IT'S\n"
|
"THIS MAY CREATE A LOT OF FOLDERS SO IT'S\n"
|
||||||
"ADVICED TO REMOVE THE ONES YOU DON'T NEED\n\n"
|
"ADVICED TO REMOVE THE ONES YOU DON'T NEED\n\n"
|
||||||
"PROCEED?",
|
"PROCEED?",
|
||||||
"YES", [this] {
|
"YES",
|
||||||
if (!SystemData::createSystemDirectories()) {
|
[this] {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
if (!SystemData::createSystemDirectories()) {
|
||||||
"THE SYSTEM DIRECTORIES WERE SUCCESSFULLY\n"
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||||
"GENERATED, EXIT THE APPLICATION AND PLACE\n"
|
"THE SYSTEM DIRECTORIES WERE SUCCESSFULLY\n"
|
||||||
"YOUR GAMES IN THE NEWLY CREATED FOLDERS", "OK", nullptr,
|
"GENERATED, EXIT THE APPLICATION AND PLACE\n"
|
||||||
"", nullptr, "", nullptr, true));
|
"YOUR GAMES IN THE NEWLY CREATED FOLDERS",
|
||||||
}
|
"OK", nullptr, "", nullptr, "", nullptr,
|
||||||
else {
|
true));
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
}
|
||||||
"ERROR CREATING THE SYSTEM DIRECTORIES,\n"
|
else {
|
||||||
"PERMISSION PROBLEMS OR DISK FULL?\n\n"
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
||||||
"SEE THE LOG FILE FOR MORE DETAILS", "OK", nullptr,
|
"ERROR CREATING THE SYSTEM DIRECTORIES,\n"
|
||||||
"", nullptr, "", nullptr, true));
|
"PERMISSION PROBLEMS OR DISK FULL?\n\n"
|
||||||
}
|
"SEE THE LOG FILE FOR MORE DETAILS",
|
||||||
}, "NO", nullptr, "", nullptr, true));
|
"OK", nullptr, "", nullptr, "", nullptr,
|
||||||
},
|
true));
|
||||||
"QUIT", [] {
|
}
|
||||||
SDL_Event quit;
|
},
|
||||||
quit.type = SDL_QUIT;
|
"NO", nullptr, "", nullptr, true));
|
||||||
SDL_PushEvent(&quit);
|
},
|
||||||
}, true, false);
|
"QUIT",
|
||||||
|
[] {
|
||||||
|
SDL_Event quit;
|
||||||
|
quit.type = SDL_QUIT;
|
||||||
|
SDL_PushEvent(&quit);
|
||||||
|
},
|
||||||
|
true, false);
|
||||||
|
|
||||||
mWindow->pushGui(mNoGamesMessageBox);
|
mWindow->pushGui(mNoGamesMessageBox);
|
||||||
}
|
}
|
||||||
|
@ -205,8 +203,8 @@ void ViewController::goToStart()
|
||||||
// If a specific system is requested, go directly to its game list.
|
// If a specific system is requested, go directly to its game list.
|
||||||
auto requestedSystem = Settings::getInstance()->getString("StartupSystem");
|
auto requestedSystem = Settings::getInstance()->getString("StartupSystem");
|
||||||
if ("" != requestedSystem && "retropie" != requestedSystem) {
|
if ("" != requestedSystem && "retropie" != requestedSystem) {
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||||
it != SystemData::sSystemVector.cend(); it++) {
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
if ((*it)->getName() == requestedSystem) {
|
if ((*it)->getName() == requestedSystem) {
|
||||||
goToGameList(*it);
|
goToGameList(*it);
|
||||||
return;
|
return;
|
||||||
|
@ -237,7 +235,7 @@ bool ViewController::isCameraMoving()
|
||||||
{
|
{
|
||||||
if (mCurrentView) {
|
if (mCurrentView) {
|
||||||
if (mCamera.r3().x() - -mCurrentView->getPosition().x() != 0 ||
|
if (mCamera.r3().x() - -mCurrentView->getPosition().x() != 0 ||
|
||||||
mCamera.r3().y() - -mCurrentView->getPosition().y() != 0)
|
mCamera.r3().y() - -mCurrentView->getPosition().y() != 0)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -322,7 +320,7 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
|
||||||
|
|
||||||
auto systemList = getSystemListView();
|
auto systemList = getSystemListView();
|
||||||
systemList->setPosition(getSystemId(system) * static_cast<float>(Renderer::getScreenWidth()),
|
systemList->setPosition(getSystemId(system) * static_cast<float>(Renderer::getScreenWidth()),
|
||||||
systemList->getPosition().y());
|
systemList->getPosition().y());
|
||||||
|
|
||||||
systemList->goToSystem(system, false);
|
systemList->goToSystem(system, false);
|
||||||
mCurrentView = systemList;
|
mCurrentView = systemList;
|
||||||
|
@ -333,7 +331,7 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
|
||||||
mCamera.translation() = -mCurrentView->getPosition();
|
mCamera.translation() = -mCurrentView->getPosition();
|
||||||
if (Settings::getInstance()->getString("TransitionStyle") == "slide") {
|
if (Settings::getInstance()->getString("TransitionStyle") == "slide") {
|
||||||
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
||||||
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
||||||
mCamera.translation().y() += Renderer::getScreenHeight();
|
mCamera.translation().y() += Renderer::getScreenHeight();
|
||||||
else
|
else
|
||||||
mCamera.translation().x() -= Renderer::getScreenWidth();
|
mCamera.translation().x() -= Renderer::getScreenWidth();
|
||||||
|
@ -341,7 +339,7 @@ void ViewController::goToSystemView(SystemData* system, bool playTransition)
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") {
|
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") {
|
||||||
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
||||||
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
||||||
mCamera.translation().y() += Renderer::getScreenHeight();
|
mCamera.translation().y() += Renderer::getScreenHeight();
|
||||||
else
|
else
|
||||||
mCamera.translation().x() += Renderer::getScreenWidth();
|
mCamera.translation().x() += Renderer::getScreenWidth();
|
||||||
|
@ -396,8 +394,9 @@ void ViewController::goToGameList(SystemData* system)
|
||||||
restoreViewPosition();
|
restoreViewPosition();
|
||||||
|
|
||||||
if (mPreviousView && Settings::getInstance()->getString("TransitionStyle") == "fade" &&
|
if (mPreviousView && Settings::getInstance()->getString("TransitionStyle") == "fade" &&
|
||||||
isAnimationPlaying(0))
|
isAnimationPlaying(0)) {
|
||||||
mPreviousView->onHide();
|
mPreviousView->onHide();
|
||||||
|
}
|
||||||
|
|
||||||
if (mPreviousView) {
|
if (mPreviousView) {
|
||||||
mSkipView = mPreviousView;
|
mSkipView = mPreviousView;
|
||||||
|
@ -449,7 +448,7 @@ void ViewController::goToGameList(SystemData* system)
|
||||||
int sysId = getSystemId(system);
|
int sysId = getSystemId(system);
|
||||||
|
|
||||||
sysList->setPosition(sysId * static_cast<float>(Renderer::getScreenWidth()),
|
sysList->setPosition(sysId * static_cast<float>(Renderer::getScreenWidth()),
|
||||||
sysList->getPosition().y());
|
sysList->getPosition().y());
|
||||||
offsetX = sysList->getPosition().x() - offsetX;
|
offsetX = sysList->getPosition().x() - offsetX;
|
||||||
mCamera.translation().x() -= offsetX;
|
mCamera.translation().x() -= offsetX;
|
||||||
}
|
}
|
||||||
|
@ -464,7 +463,7 @@ void ViewController::goToGameList(SystemData* system)
|
||||||
float offsetX = getGameListView(system)->getPosition().x();
|
float offsetX = getGameListView(system)->getPosition().x();
|
||||||
// This is needed to move the camera in the correct direction if there are only two systems.
|
// This is needed to move the camera in the correct direction if there are only two systems.
|
||||||
if (SystemData::sSystemVector.size() == 2 && mNextSystem)
|
if (SystemData::sSystemVector.size() == 2 && mNextSystem)
|
||||||
offsetX -= Renderer::getScreenWidth();
|
offsetX -= Renderer::getScreenWidth();
|
||||||
else
|
else
|
||||||
offsetX += Renderer::getScreenWidth();
|
offsetX += Renderer::getScreenWidth();
|
||||||
currentPosition.x() = offsetX;
|
currentPosition.x() = offsetX;
|
||||||
|
@ -541,11 +540,13 @@ void ViewController::playViewTransition(bool instant)
|
||||||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||||
|
|
||||||
if (instant || transition_style == "instant") {
|
if (instant || transition_style == "instant") {
|
||||||
setAnimation(new LambdaAnimation([this, target](float /*t*/) {
|
setAnimation(new LambdaAnimation(
|
||||||
this->mCamera.translation() = -target;
|
[this, target](float /*t*/) {
|
||||||
if (mPreviousView)
|
this->mCamera.translation() = -target;
|
||||||
mPreviousView->onHide();
|
if (mPreviousView)
|
||||||
}, 1));
|
mPreviousView->onHide();
|
||||||
|
},
|
||||||
|
1));
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
}
|
}
|
||||||
else if (transition_style == "fade") {
|
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
|
// Without this, a (much shorter) fade transition would still play as
|
||||||
// finishedCallback is calling this function.
|
// finishedCallback is calling this function.
|
||||||
if (!mCancelledTransition)
|
if (!mCancelledTransition)
|
||||||
mFadeOpacity = Math::lerp(0, 1, t);
|
mFadeOpacity = Math::lerp(0.0f, 1.0f, t);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fadeCallback = [this]() {
|
auto fadeCallback = [this]() {
|
||||||
|
@ -569,12 +570,12 @@ void ViewController::playViewTransition(bool instant)
|
||||||
const static int FADE_DURATION = 120; // Fade in/out time.
|
const static int FADE_DURATION = 120; // Fade in/out time.
|
||||||
const static int FADE_WAIT = 200; // Time to wait between in/out.
|
const static int FADE_WAIT = 200; // Time to wait between in/out.
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0,
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0,
|
||||||
[this, fadeFunc, fadeCallback, target] {
|
[this, fadeFunc, fadeCallback, target] {
|
||||||
this->mCamera.translation() = -target;
|
this->mCamera.translation() = -target;
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION),
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT,
|
||||||
FADE_WAIT, fadeCallback, true);
|
fadeCallback, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fast-forward animation if we're partway faded.
|
// Fast-forward animation if we're partway faded.
|
||||||
if (target == -mCamera.translation()) {
|
if (target == -mCamera.translation()) {
|
||||||
|
@ -616,7 +617,7 @@ bool ViewController::runInBackground(SystemData* system)
|
||||||
// with the game. In that situation ES-DE would wait until the whole Steam application was
|
// with the game. In that situation ES-DE would wait until the whole Steam application was
|
||||||
// shut down before it would resume. I.e. it would not be enough to just stop the game.
|
// shut down before it would resume. I.e. it would not be enough to just stop the game.
|
||||||
if (system->hasPlatformId(PlatformIds::VALVE_STEAM) ||
|
if (system->hasPlatformId(PlatformIds::VALVE_STEAM) ||
|
||||||
Settings::getInstance()->getBool("RunInBackground"))
|
Settings::getInstance()->getBool("RunInBackground"))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -646,8 +647,9 @@ void ViewController::launch(FileData* game)
|
||||||
if (durationString == "disabled") {
|
if (durationString == "disabled") {
|
||||||
// If the game launch screen has been set as disabled, show a simple info popup
|
// If the game launch screen has been set as disabled, show a simple info popup
|
||||||
// notification instead.
|
// notification instead.
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow, "LAUNCHING GAME '" +
|
GuiInfoPopup* s = new GuiInfoPopup(
|
||||||
Utils::String::toUpper(game->metadata.get("name") + "'"), 10000);
|
mWindow, "LAUNCHING GAME '" + Utils::String::toUpper(game->metadata.get("name") + "'"),
|
||||||
|
10000);
|
||||||
mWindow->setInfoPopup(s);
|
mWindow->setInfoPopup(s);
|
||||||
duration = 1700;
|
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
|
// 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.
|
// to be displayed briefly, and for the navigation sound playing to be able to complete.
|
||||||
// During this time period, all user input is blocked.
|
// 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);
|
game->launchGame(mWindow);
|
||||||
// If the launch screen is disabled then this will do nothing.
|
// If the launch screen is disabled then this will do nothing.
|
||||||
mWindow->closeLaunchScreen();
|
mWindow->closeLaunchScreen();
|
||||||
onFileChanged(game, true);
|
onFileChanged(game, true);
|
||||||
// This is a workaround so that any keys or button presses used for exiting the emulator
|
// This is a workaround so that any keys or button presses used for exiting the emulator
|
||||||
// are not captured upon returning.
|
// are not captured upon returning.
|
||||||
setAnimation(new LambdaAnimation([](float t){}, 1), 0, [this] {
|
setAnimation(new LambdaAnimation([](float t) {}, 1), 0, [this] { mLockInput = false; });
|
||||||
mLockInput = false;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,38 +733,41 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the view.
|
// Create the view.
|
||||||
switch (selectedViewStyle)
|
switch (selectedViewStyle) {
|
||||||
{
|
case VIDEO: {
|
||||||
case VIDEO:
|
|
||||||
view = std::shared_ptr<IGameListView>(
|
view = std::shared_ptr<IGameListView>(
|
||||||
new VideoGameListView(mWindow, system->getRootFolder()));
|
new VideoGameListView(mWindow, system->getRootFolder()));
|
||||||
mState.viewstyle = VIDEO;
|
mState.viewstyle = VIDEO;
|
||||||
break;
|
break;
|
||||||
case DETAILED:
|
}
|
||||||
|
case DETAILED: {
|
||||||
view = std::shared_ptr<IGameListView>(
|
view = std::shared_ptr<IGameListView>(
|
||||||
new DetailedGameListView(mWindow, system->getRootFolder()));
|
new DetailedGameListView(mWindow, system->getRootFolder()));
|
||||||
mState.viewstyle = DETAILED;
|
mState.viewstyle = DETAILED;
|
||||||
break;
|
break;
|
||||||
case GRID:
|
}
|
||||||
|
case GRID: {
|
||||||
view = std::shared_ptr<IGameListView>(
|
view = std::shared_ptr<IGameListView>(
|
||||||
new GridGameListView(mWindow, system->getRootFolder()));
|
new GridGameListView(mWindow, system->getRootFolder()));
|
||||||
mState.viewstyle = GRID;
|
mState.viewstyle = GRID;
|
||||||
break;
|
break;
|
||||||
case BASIC:
|
}
|
||||||
default:
|
case BASIC: {
|
||||||
|
}
|
||||||
|
default: {
|
||||||
view = std::shared_ptr<IGameListView>(
|
view = std::shared_ptr<IGameListView>(
|
||||||
new BasicGameListView(mWindow, system->getRootFolder()));
|
new BasicGameListView(mWindow, system->getRootFolder()));
|
||||||
mState.viewstyle = BASIC;
|
mState.viewstyle = BASIC;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
view->setTheme(system->getTheme());
|
view->setTheme(system->getTheme());
|
||||||
|
|
||||||
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
||||||
int id = static_cast<int>(
|
int id = static_cast<int>(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
||||||
std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
|
||||||
view->setPosition(id * static_cast<float>(Renderer::getScreenWidth()),
|
view->setPosition(id * static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight() * 2));
|
static_cast<float>(Renderer::getScreenHeight() * 2));
|
||||||
|
|
||||||
addChild(view.get());
|
addChild(view.get());
|
||||||
|
|
||||||
|
@ -799,8 +802,8 @@ bool ViewController::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
// Open the main menu.
|
// Open the main menu.
|
||||||
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
||||||
!Settings::getInstance()->getBool("EnableMenuKidMode")) &&
|
!Settings::getInstance()->getBool("EnableMenuKidMode")) &&
|
||||||
config->isMappedTo("start", input) && input.value != 0) {
|
config->isMappedTo("start", input) && input.value != 0) {
|
||||||
// If we don't stop the scrolling here, it will continue to
|
// If we don't stop the scrolling here, it will continue to
|
||||||
// run after closing the menu.
|
// run after closing the menu.
|
||||||
if (mSystemListView->isScrolling())
|
if (mSystemListView->isScrolling())
|
||||||
|
@ -854,7 +857,7 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
||||||
// Camera position, position + size.
|
// Camera position, position + size.
|
||||||
Vector3f viewStart = transInverse.translation();
|
Vector3f viewStart = transInverse.translation();
|
||||||
Vector3f viewEnd = transInverse * Vector3f(static_cast<float>(Renderer::getScreenWidth()),
|
Vector3f viewEnd = transInverse * Vector3f(static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight(), 0));
|
static_cast<float>(Renderer::getScreenHeight(), 0));
|
||||||
|
|
||||||
// Keep track of UI mode changes.
|
// Keep track of UI mode changes.
|
||||||
UIModeController::getInstance()->monitorUIMode();
|
UIModeController::getInstance()->monitorUIMode();
|
||||||
|
@ -870,11 +873,11 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
||||||
if (it->second == mCurrentView || (it->second == mPreviousView && isCameraMoving())) {
|
if (it->second == mCurrentView || (it->second == mPreviousView && isCameraMoving())) {
|
||||||
// Clipping.
|
// Clipping.
|
||||||
Vector3f guiStart = it->second->getPosition();
|
Vector3f guiStart = it->second->getPosition();
|
||||||
Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(),
|
Vector3f guiEnd = it->second->getPosition() +
|
||||||
it->second->getSize().y(), 0);
|
Vector3f(it->second->getSize().x(), it->second->getSize().y(), 0);
|
||||||
|
|
||||||
if (guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() &&
|
if (guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() &&
|
||||||
guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y())
|
guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y())
|
||||||
it->second->render(trans);
|
it->second->render(trans);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -887,7 +890,7 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
||||||
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mFadeOpacity * 255);
|
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mFadeOpacity * 255);
|
||||||
Renderer::setMatrix(parentTrans);
|
Renderer::setMatrix(parentTrans);
|
||||||
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
||||||
static_cast<float>(Renderer::getScreenHeight()), fadeColor, fadeColor);
|
static_cast<float>(Renderer::getScreenHeight()), fadeColor, fadeColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,13 +898,14 @@ void ViewController::preload()
|
||||||
{
|
{
|
||||||
unsigned int systemCount = static_cast<int>(SystemData::sSystemVector.size());
|
unsigned int systemCount = static_cast<int>(SystemData::sSystemVector.size());
|
||||||
|
|
||||||
for (auto it = SystemData::sSystemVector.cbegin();
|
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||||
it != SystemData::sSystemVector.cend(); it ++) {
|
it++) {
|
||||||
if (Settings::getInstance()->getBool("SplashScreen") &&
|
if (Settings::getInstance()->getBool("SplashScreen") &&
|
||||||
Settings::getInstance()->getBool("SplashScreenProgress")) {
|
Settings::getInstance()->getBool("SplashScreenProgress")) {
|
||||||
mWindow->renderLoadingScreen("Loading '" + (*it)->getFullName() + "' (" +
|
mWindow->renderLoadingScreen(
|
||||||
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it)+1) +
|
"Loading '" + (*it)->getFullName() + "' (" +
|
||||||
"/" + std::to_string(systemCount) + ")");
|
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it) + 1) + "/" +
|
||||||
|
std::to_string(systemCount) + ")");
|
||||||
}
|
}
|
||||||
(*it)->getIndex()->resetFilters();
|
(*it)->getIndex()->resetFilters();
|
||||||
getGameListView(*it);
|
getGameListView(*it);
|
||||||
|
@ -1028,7 +1032,7 @@ std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
||||||
|
|
||||||
prompts = mCurrentView->getHelpPrompts();
|
prompts = mCurrentView->getHelpPrompts();
|
||||||
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
||||||
!Settings::getInstance()->getBool("EnableMenuKidMode")))
|
!Settings::getInstance()->getBool("EnableMenuKidMode")))
|
||||||
prompts.push_back(HelpPrompt("start", "menu"));
|
prompts.push_back(HelpPrompt("start", "menu"));
|
||||||
return prompts;
|
return prompts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
#ifndef ES_APP_VIEWS_VIEW_CONTROLLER_H
|
#ifndef ES_APP_VIEWS_VIEW_CONTROLLER_H
|
||||||
#define 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/GuiComplexTextEditPopup.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
#include "renderers/Renderer.h"
|
#include "renderers/Renderer.h"
|
||||||
#include "FileData.h"
|
|
||||||
#include "GuiComponent.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -46,8 +46,10 @@ public:
|
||||||
// If a basic view detected a metadata change, it can request to recreate
|
// If a basic view detected a metadata change, it can request to recreate
|
||||||
// the current gamelist view (as it may change to be detailed).
|
// the current gamelist view (as it may change to be detailed).
|
||||||
void reloadGameListView(IGameListView* gamelist, bool reloadTheme = false);
|
void reloadGameListView(IGameListView* gamelist, bool reloadTheme = false);
|
||||||
inline void reloadGameListView(SystemData* system, bool reloadTheme = false)
|
void reloadGameListView(SystemData* system, bool reloadTheme = false)
|
||||||
{ reloadGameListView(getGameListView(system).get(), reloadTheme); }
|
{
|
||||||
|
reloadGameListView(getGameListView(system).get(), reloadTheme);
|
||||||
|
}
|
||||||
// Reload everything with a theme.
|
// Reload everything with a theme.
|
||||||
// Used when the "ThemeSet" setting changes.
|
// Used when the "ThemeSet" setting changes.
|
||||||
void reloadAll();
|
void reloadAll();
|
||||||
|
@ -67,22 +69,26 @@ public:
|
||||||
void stopScrolling();
|
void stopScrolling();
|
||||||
|
|
||||||
void onFileChanged(FileData* file, bool reloadGameList);
|
void onFileChanged(FileData* file, bool reloadGameList);
|
||||||
void triggerGameLaunch(FileData* game) { mGameToLaunch = game; mLockInput = true; };
|
void triggerGameLaunch(FileData* game)
|
||||||
bool getGameLaunchTriggered() { return (mGameToLaunch != nullptr); };
|
{
|
||||||
|
mGameToLaunch = game;
|
||||||
|
mLockInput = true;
|
||||||
|
};
|
||||||
|
bool getGameLaunchTriggered() { return (mGameToLaunch != nullptr); }
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
void render(const Transform4x4f& parentTrans) override;
|
void render(const Transform4x4f& parentTrans) override;
|
||||||
|
|
||||||
enum ViewMode {
|
enum ViewMode {
|
||||||
NOTHING,
|
NOTHING, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
START_SCREEN,
|
START_SCREEN,
|
||||||
SYSTEM_SELECT,
|
SYSTEM_SELECT,
|
||||||
GAME_LIST
|
GAME_LIST
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GameListViewStyle {
|
enum GameListViewStyle {
|
||||||
AUTOMATIC,
|
AUTOMATIC, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
|
||||||
BASIC,
|
BASIC,
|
||||||
DETAILED,
|
DETAILED,
|
||||||
GRID,
|
GRID,
|
||||||
|
@ -93,18 +99,18 @@ public:
|
||||||
ViewMode viewing;
|
ViewMode viewing;
|
||||||
GameListViewStyle viewstyle;
|
GameListViewStyle viewstyle;
|
||||||
|
|
||||||
inline SystemData* getSystem() const
|
SystemData* getSystem() const
|
||||||
{
|
{
|
||||||
assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT);
|
assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT);
|
||||||
return system;
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend ViewController;
|
friend ViewController;
|
||||||
SystemData* system;
|
SystemData* system;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const State& getState() const { return mState; }
|
const State& getState() const { return mState; }
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
virtual HelpStyle getHelpStyle() override;
|
virtual HelpStyle getHelpStyle() override;
|
||||||
|
@ -143,6 +149,9 @@ private:
|
||||||
std::map<SystemData*, std::shared_ptr<IGameListView>> mGameListViews;
|
std::map<SystemData*, std::shared_ptr<IGameListView>> mGameListViews;
|
||||||
std::shared_ptr<SystemView> mSystemListView;
|
std::shared_ptr<SystemView> mSystemListView;
|
||||||
|
|
||||||
|
FileData* mGameToLaunch;
|
||||||
|
State mState;
|
||||||
|
|
||||||
Transform4x4f mCamera;
|
Transform4x4f mCamera;
|
||||||
bool mSystemViewTransition;
|
bool mSystemViewTransition;
|
||||||
bool mWrappedViews;
|
bool mWrappedViews;
|
||||||
|
@ -151,9 +160,6 @@ private:
|
||||||
bool mCancelledTransition; // Needed only for the Fade transition style.
|
bool mCancelledTransition; // Needed only for the Fade transition style.
|
||||||
bool mLockInput;
|
bool mLockInput;
|
||||||
bool mNextSystem;
|
bool mNextSystem;
|
||||||
FileData* mGameToLaunch;
|
|
||||||
|
|
||||||
State mState;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_APP_VIEWS_VIEW_CONTROLLER_H
|
#endif // ES_APP_VIEWS_VIEW_CONTROLLER_H
|
||||||
|
|
|
@ -8,15 +8,16 @@
|
||||||
|
|
||||||
#include "views/gamelist/BasicGameListView.h"
|
#include "views/gamelist/BasicGameListView.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "views/UIModeController.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
#include "views/UIModeController.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
BasicGameListView::BasicGameListView(Window* window, FileData* root)
|
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.setSize(mSize.x(), mSize.y() * 0.8f);
|
||||||
mList.setPosition(0, mSize.y() * 0.2f);
|
mList.setPosition(0, mSize.y() * 0.2f);
|
||||||
|
@ -89,16 +90,16 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files, FileDa
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*it)->getFavorite() && favoriteStar &&
|
if ((*it)->getFavorite() && favoriteStar &&
|
||||||
mRoot->getSystem()->getName() != "favorites") {
|
mRoot->getSystem()->getName() != "favorites") {
|
||||||
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
||||||
mList.add(inCollectionPrefix + "* " +
|
mList.add(inCollectionPrefix + "* " + (*it)->getName(), *it,
|
||||||
(*it)->getName(), *it, ((*it)->getType() == FOLDER));
|
((*it)->getType() == FOLDER));
|
||||||
else
|
else
|
||||||
mList.add(inCollectionPrefix + ViewController::FAVORITE_CHAR + " " +
|
mList.add(inCollectionPrefix + ViewController::FAVORITE_CHAR + " " +
|
||||||
(*it)->getName(), *it, ((*it)->getType() == FOLDER));
|
(*it)->getName(),
|
||||||
|
*it, ((*it)->getType() == FOLDER));
|
||||||
}
|
}
|
||||||
else if ((*it)->getType() == FOLDER &&
|
else if ((*it)->getType() == FOLDER && mRoot->getSystem()->getName() != "collections") {
|
||||||
mRoot->getSystem()->getName() != "collections") {
|
|
||||||
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
if (Settings::getInstance()->getBool("SpecialCharsASCII"))
|
||||||
mList.add("# " + (*it)->getName(), *it, true);
|
mList.add("# " + (*it)->getName(), *it, true);
|
||||||
else
|
else
|
||||||
|
@ -117,11 +118,6 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files, FileDa
|
||||||
generateFirstLetterIndex(files);
|
generateFirstLetterIndex(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* BasicGameListView::getCursor()
|
|
||||||
{
|
|
||||||
return mList.getSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasicGameListView::setCursor(FileData* cursor)
|
void BasicGameListView::setCursor(FileData* cursor)
|
||||||
{
|
{
|
||||||
if (!mList.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
if (!mList.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
||||||
|
@ -133,6 +129,7 @@ void BasicGameListView::setCursor(FileData* cursor)
|
||||||
if (mCursorStack.empty() || mCursorStack.top() != cursor->getParent()) {
|
if (mCursorStack.empty() || mCursorStack.top() != cursor->getParent()) {
|
||||||
std::stack<FileData*> tmp;
|
std::stack<FileData*> tmp;
|
||||||
FileData* ptr = cursor->getParent();
|
FileData* ptr = cursor->getParent();
|
||||||
|
|
||||||
while (ptr && ptr != mRoot) {
|
while (ptr && ptr != mRoot) {
|
||||||
tmp.push(ptr);
|
tmp.push(ptr);
|
||||||
ptr = ptr->getParent();
|
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)
|
void BasicGameListView::addPlaceholder(FileData* firstEntry)
|
||||||
{
|
{
|
||||||
// Empty list, add a placeholder.
|
// Empty list, add a placeholder.
|
||||||
|
@ -186,18 +158,9 @@ void BasicGameListView::addPlaceholder(FileData* firstEntry)
|
||||||
mList.add(placeholder->getName(), placeholder, (placeholder->getType() == PLACEHOLDER));
|
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)
|
void BasicGameListView::launch(FileData* game)
|
||||||
{
|
{
|
||||||
|
// This triggers ViewController to launch the game.
|
||||||
ViewController::get()->triggerGameLaunch(game);
|
ViewController::get()->triggerGameLaunch(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +198,7 @@ void BasicGameListView::remove(FileData* game, bool deleteFile)
|
||||||
|
|
||||||
if (deleteFile) {
|
if (deleteFile) {
|
||||||
parent->sort(parent->getSortTypeFromString(parent->getSortTypeString()),
|
parent->sort(parent->getSortTypeFromString(parent->getSortTypeString()),
|
||||||
Settings::getInstance()->getBool("FavoritesFirst"));
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
onFileChanged(parent, false);
|
onFileChanged(parent, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,8 +214,8 @@ void BasicGameListView::removeMedia(FileData* game)
|
||||||
|
|
||||||
// If there are no media files left in the directory after the deletion, then remove
|
// 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.
|
// the directory too. Remove any empty parent directories as well.
|
||||||
auto removeEmptyDirFunc = []
|
auto removeEmptyDirFunc = [](std::string systemMediaDir, std::string mediaType,
|
||||||
(std::string systemMediaDir, std::string mediaType, std::string path) {
|
std::string path) {
|
||||||
std::string parentPath = Utils::FileSystem::getParent(path);
|
std::string parentPath = Utils::FileSystem::getParent(path);
|
||||||
while (parentPath != systemMediaDir + "/" + mediaType) {
|
while (parentPath != systemMediaDir + "/" + mediaType) {
|
||||||
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
||||||
|
@ -321,13 +284,13 @@ std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
|
||||||
std::vector<HelpPrompt> prompts;
|
std::vector<HelpPrompt> prompts;
|
||||||
|
|
||||||
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
||||||
SystemData::sSystemVector.size() > 1)
|
SystemData::sSystemVector.size() > 1)
|
||||||
prompts.push_back(HelpPrompt("left/right", "system"));
|
prompts.push_back(HelpPrompt("left/right", "system"));
|
||||||
|
|
||||||
prompts.push_back(HelpPrompt("up/down", "choose"));
|
prompts.push_back(HelpPrompt("up/down", "choose"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" && mCursorStack.empty() &&
|
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" && mCursorStack.empty() &&
|
||||||
ViewController::get()->getState().viewing == ViewController::GAME_LIST)
|
ViewController::get()->getState().viewing == ViewController::GAME_LIST)
|
||||||
prompts.push_back(HelpPrompt("a", "enter"));
|
prompts.push_back(HelpPrompt("a", "enter"));
|
||||||
else
|
else
|
||||||
prompts.push_back(HelpPrompt("a", "launch"));
|
prompts.push_back(HelpPrompt("a", "launch"));
|
||||||
|
@ -341,24 +304,24 @@ std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
|
||||||
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||||
!CollectionSystemsManager::get()->isEditing() && mCursorStack.empty() &&
|
!CollectionSystemsManager::get()->isEditing() && mCursorStack.empty() &&
|
||||||
ViewController::get()->getState().viewing == ViewController::GAME_LIST &&
|
ViewController::get()->getState().viewing == ViewController::GAME_LIST &&
|
||||||
ViewController::get()->getState().viewstyle != ViewController::BASIC) {
|
ViewController::get()->getState().viewstyle != ViewController::BASIC) {
|
||||||
prompts.push_back(HelpPrompt("y", "jump to game"));
|
prompts.push_back(HelpPrompt("y", "jump to game"));
|
||||||
}
|
}
|
||||||
else if (mRoot->getSystem()->isGameSystem() &&
|
else if (mRoot->getSystem()->isGameSystem() &&
|
||||||
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
|
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
|
||||||
!mCursorStack.empty()) &&
|
!mCursorStack.empty()) &&
|
||||||
!UIModeController::getInstance()->isUIModeKid() &&
|
!UIModeController::getInstance()->isUIModeKid() &&
|
||||||
!UIModeController::getInstance()->isUIModeKiosk() &&
|
!UIModeController::getInstance()->isUIModeKiosk() &&
|
||||||
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
||||||
CollectionSystemsManager::get()->isEditing())) {
|
CollectionSystemsManager::get()->isEditing())) {
|
||||||
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
}
|
}
|
||||||
else if (mRoot->getSystem()->isGameSystem() &&
|
else if (mRoot->getSystem()->isGameSystem() &&
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||||
CollectionSystemsManager::get()->isEditing()) {
|
CollectionSystemsManager::get()->isEditing()) {
|
||||||
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,30 +21,33 @@ public:
|
||||||
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
||||||
|
|
||||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||||
|
|
||||||
virtual FileData* getCursor() override;
|
|
||||||
virtual void setCursor(FileData* cursor) override;
|
virtual void setCursor(FileData* cursor) override;
|
||||||
virtual FileData* getNextEntry() override;
|
|
||||||
virtual FileData* getPreviousEntry() override;
|
virtual FileData* getCursor() override { return mList.getSelected(); }
|
||||||
virtual FileData* getFirstEntry() override;
|
virtual FileData* getNextEntry() override { return mList.getNext(); }
|
||||||
virtual FileData* getLastEntry() override;
|
virtual FileData* getPreviousEntry() override { return mList.getPrevious(); }
|
||||||
virtual FileData* getFirstGameEntry() override;
|
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::string getName() const override { return "basic"; }
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
virtual void launch(FileData* game) override;
|
|
||||||
|
|
||||||
virtual bool isListScrolling() override { return mList.isScrolling(); };
|
virtual bool isListScrolling() override { return mList.isScrolling(); }
|
||||||
virtual void stopListScrolling() override { mList.stopScrolling(); };
|
virtual void stopListScrolling() override { mList.stopScrolling(); }
|
||||||
|
|
||||||
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
||||||
{ return mFirstLetterIndex; };
|
{
|
||||||
|
return mFirstLetterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
||||||
|
virtual void launch(FileData* game) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual std::string getQuickSystemSelectRightButton() override;
|
virtual std::string getQuickSystemSelectRightButton() override { return "right"; }
|
||||||
virtual std::string getQuickSystemSelectLeftButton() override;
|
virtual std::string getQuickSystemSelectLeftButton() override { return "left"; }
|
||||||
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
||||||
virtual void remove(FileData* game, bool deleteFile) override;
|
virtual void remove(FileData* game, bool deleteFile) override;
|
||||||
virtual void removeMedia(FileData* game) override;
|
virtual void removeMedia(FileData* game) override;
|
||||||
|
|
|
@ -8,45 +8,40 @@
|
||||||
|
|
||||||
#include "views/gamelist/DetailedGameListView.h"
|
#include "views/gamelist/DetailedGameListView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "animations/LambdaAnimation.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
#define FADE_IN_START_OPACITY 0.5f
|
#define FADE_IN_START_OPACITY 0.5f
|
||||||
#define FADE_IN_TIME 650
|
#define FADE_IN_TIME 650
|
||||||
|
|
||||||
DetailedGameListView::DetailedGameListView(
|
DetailedGameListView::DetailedGameListView(Window* window, FileData* root)
|
||||||
Window* window,
|
: BasicGameListView(window, root)
|
||||||
FileData* root)
|
, mDescContainer(window)
|
||||||
: BasicGameListView(window, root),
|
, mDescription(window)
|
||||||
mDescContainer(window),
|
, mGamelistInfo(window)
|
||||||
mDescription(window),
|
, mThumbnail(window)
|
||||||
mGamelistInfo(window),
|
, mMarquee(window)
|
||||||
|
, mImage(window)
|
||||||
mThumbnail(window),
|
, mLblRating(window)
|
||||||
mMarquee(window),
|
, mLblReleaseDate(window)
|
||||||
mImage(window),
|
, mLblDeveloper(window)
|
||||||
|
, mLblPublisher(window)
|
||||||
mLblRating(window),
|
, mLblGenre(window)
|
||||||
mLblReleaseDate(window),
|
, mLblPlayers(window)
|
||||||
mLblDeveloper(window),
|
, mLblLastPlayed(window)
|
||||||
mLblPublisher(window),
|
, mLblPlayCount(window)
|
||||||
mLblGenre(window),
|
, mRating(window)
|
||||||
mLblPlayers(window),
|
, mReleaseDate(window)
|
||||||
mLblLastPlayed(window),
|
, mDeveloper(window)
|
||||||
mLblPlayCount(window),
|
, mPublisher(window)
|
||||||
|
, mGenre(window)
|
||||||
mRating(window),
|
, mPlayers(window)
|
||||||
mReleaseDate(window),
|
, mLastPlayed(window)
|
||||||
mDeveloper(window),
|
, mPlayCount(window)
|
||||||
mPublisher(window),
|
, mName(window)
|
||||||
mGenre(window),
|
, mLastUpdated(nullptr)
|
||||||
mPlayers(window),
|
|
||||||
mLastPlayed(window),
|
|
||||||
mPlayCount(window),
|
|
||||||
mName(window),
|
|
||||||
mLastUpdated(nullptr)
|
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
|
@ -114,8 +109,8 @@ DetailedGameListView::DetailedGameListView(
|
||||||
addChild(&mName);
|
addChild(&mName);
|
||||||
|
|
||||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -140,20 +135,20 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mImage.applyTheme(theme, getName(), "md_image",
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mName.applyTheme(theme, getName(), "md_name", ALL);
|
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
assert(labels.size() == 8);
|
assert(labels.size() == 8);
|
||||||
std::vector<std::string> lblElements = {
|
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
"md_lbl_developer", "md_lbl_publisher",
|
||||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
"md_lbl_genre", "md_lbl_players",
|
||||||
};
|
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||||
|
|
||||||
for (unsigned int i = 0; i < labels.size(); i++)
|
for (unsigned int i = 0; i < labels.size(); i++)
|
||||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||||
|
@ -161,19 +156,19 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
assert(values.size() == 8);
|
assert(values.size() == 8);
|
||||||
std::vector<std::string> valElements = {
|
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
"md_publisher", "md_genre", "md_players",
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_lastplayed", "md_playcount" };
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < values.size(); i++)
|
for (unsigned int i = 0; i < values.size(); i++)
|
||||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||||
|
|
||||||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description",
|
mDescription.applyTheme(
|
||||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
||||||
// If there is no position defined in the theme for gamelistInfo, then hide it.
|
// If there is no position defined in the theme for gamelistInfo, then hide it.
|
||||||
|
@ -205,7 +200,7 @@ void DetailedGameListView::initMDLabels()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Work from the last component.
|
// 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);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,13 +227,13 @@ void DetailedGameListView::initMDValues()
|
||||||
|
|
||||||
float bottom = 0.0f;
|
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++) {
|
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() +
|
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]->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();
|
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.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailedGameListView::updateInfoPanel()
|
void DetailedGameListView::updateInfoPanel()
|
||||||
|
@ -267,7 +262,7 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
if (file) {
|
if (file) {
|
||||||
// Always hide the metadata fields if browsing grouped custom collections.
|
// Always hide the metadata fields if browsing grouped custom collections.
|
||||||
if (file->getSystem()->isCustomCollection() &&
|
if (file->getSystem()->isCustomCollection() &&
|
||||||
file->getPath() == file->getSystem()->getName())
|
file->getPath() == file->getSystem()->getName())
|
||||||
hideMetaDataFields = true;
|
hideMetaDataFields = true;
|
||||||
else
|
else
|
||||||
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
|
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
|
||||||
|
@ -283,9 +278,9 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
// or if we're in the grouped custom collection view.
|
// or if we're in the grouped custom collection view.
|
||||||
if (mList.isScrolling())
|
if (mList.isScrolling())
|
||||||
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
||||||
(mLastUpdated->getSystem()->isCustomCollection() &&
|
(mLastUpdated->getSystem()->isCustomCollection() &&
|
||||||
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
||||||
hideMetaDataFields = true;
|
hideMetaDataFields = true;
|
||||||
|
|
||||||
if (hideMetaDataFields) {
|
if (hideMetaDataFields) {
|
||||||
mLblRating.setVisible(false);
|
mLblRating.setVisible(false);
|
||||||
|
@ -333,9 +328,9 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
// which will generate a description of three random games and return a pointer to
|
// which will generate a description of three random games and return a pointer to
|
||||||
// the first of these so that we can display its game media.
|
// the first of these so that we can display its game media.
|
||||||
if (file->getSystem()->isCustomCollection() &&
|
if (file->getSystem()->isCustomCollection() &&
|
||||||
file->getPath() == file->getSystem()->getName()) {
|
file->getPath() == file->getSystem()->getName()) {
|
||||||
mRandomGame = CollectionSystemsManager::get()->
|
mRandomGame =
|
||||||
updateCollectionFolderMetadata(file->getSystem());
|
CollectionSystemsManager::get()->updateCollectionFolderMetadata(file->getSystem());
|
||||||
if (mRandomGame) {
|
if (mRandomGame) {
|
||||||
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
||||||
mMarquee.setImage(mRandomGame->getMarqueePath());
|
mMarquee.setImage(mRandomGame->getMarqueePath());
|
||||||
|
@ -366,21 +361,21 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
if (mIsFiltered) {
|
if (mIsFiltered) {
|
||||||
if (mFilteredGameCountAll == mFilteredGameCount)
|
if (mFilteredGameCountAll == mFilteredGameCount)
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
std::to_string(mFilteredGameCount) + " / " +
|
std::to_string(mFilteredGameCount) + " / " +
|
||||||
std::to_string(mGameCount);
|
std::to_string(mGameCount);
|
||||||
else
|
else
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
std::to_string(mFilteredGameCount) + " + " +
|
std::to_string(mFilteredGameCount) + " + " +
|
||||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||||
std::to_string(mGameCount);
|
" / " + std::to_string(mGameCount);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
gamelistInfoString +=
|
||||||
std::to_string(mGameCount);
|
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||||
if (!(file->getSystem()->isCollection() &&
|
if (!(file->getSystem()->isCollection() &&
|
||||||
file->getSystem()->getFullName() == "favorites"))
|
file->getSystem()->getFullName() == "favorites"))
|
||||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " "
|
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||||
+ std::to_string(mFavoritesGameCount);
|
std::to_string(mFavoritesGameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||||
|
@ -390,9 +385,9 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
|
|
||||||
// Fade in the game image.
|
// Fade in the game image.
|
||||||
auto func = [this](float t) {
|
auto func = [this](float t) {
|
||||||
mImage.setOpacity(static_cast<unsigned char>(Math::lerp(
|
mImage.setOpacity(static_cast<unsigned char>(
|
||||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||||
};
|
};
|
||||||
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||||
|
|
||||||
mDescription.setText(file->metadata.get("desc"));
|
mDescription.setText(file->metadata.get("desc"));
|
||||||
|
|
|
@ -8,48 +8,42 @@
|
||||||
|
|
||||||
#include "views/gamelist/GridGameListView.h"
|
#include "views/gamelist/GridGameListView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
|
||||||
#include "views/UIModeController.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.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_START_OPACITY 0.5f
|
||||||
#define FADE_IN_TIME 650
|
#define FADE_IN_TIME 650
|
||||||
|
|
||||||
GridGameListView::GridGameListView(
|
GridGameListView::GridGameListView(Window* window, FileData* root)
|
||||||
Window* window,
|
: ISimpleGameListView(window, root)
|
||||||
FileData* root)
|
, mGrid(window)
|
||||||
: ISimpleGameListView(window, root),
|
, mMarquee(window)
|
||||||
|
, mImage(window)
|
||||||
mGrid(window),
|
, mDescContainer(window)
|
||||||
mMarquee(window),
|
, mDescription(window)
|
||||||
mImage(window),
|
, mGamelistInfo(window)
|
||||||
|
, mLblRating(window)
|
||||||
mDescContainer(window),
|
, mLblReleaseDate(window)
|
||||||
mDescription(window),
|
, mLblDeveloper(window)
|
||||||
mGamelistInfo(window),
|
, mLblPublisher(window)
|
||||||
|
, mLblGenre(window)
|
||||||
mLblRating(window),
|
, mLblPlayers(window)
|
||||||
mLblReleaseDate(window),
|
, mLblLastPlayed(window)
|
||||||
mLblDeveloper(window),
|
, mLblPlayCount(window)
|
||||||
mLblPublisher(window),
|
, mRating(window)
|
||||||
mLblGenre(window),
|
, mReleaseDate(window)
|
||||||
mLblPlayers(window),
|
, mDeveloper(window)
|
||||||
mLblLastPlayed(window),
|
, mPublisher(window)
|
||||||
mLblPlayCount(window),
|
, mGenre(window)
|
||||||
|
, mPlayers(window)
|
||||||
mRating(window),
|
, mLastPlayed(window)
|
||||||
mReleaseDate(window),
|
, mPlayCount(window)
|
||||||
mDeveloper(window),
|
, mName(window)
|
||||||
mPublisher(window),
|
|
||||||
mGenre(window),
|
|
||||||
mPlayers(window),
|
|
||||||
mLastPlayed(window),
|
|
||||||
mPlayCount(window),
|
|
||||||
mName(window)
|
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
|
@ -95,8 +89,8 @@ GridGameListView::GridGameListView(
|
||||||
addChild(&mName);
|
addChild(&mName);
|
||||||
|
|
||||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -107,7 +101,7 @@ GridGameListView::GridGameListView(
|
||||||
|
|
||||||
mMarquee.setOrigin(0.5f, 0.5f);
|
mMarquee.setOrigin(0.5f, 0.5f);
|
||||||
mMarquee.setPosition(mSize.x() * 0.25f, mSize.y() * 0.10f);
|
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.setDefaultZIndex(35);
|
||||||
mMarquee.setVisible(false);
|
mMarquee.setVisible(false);
|
||||||
addChild(&mMarquee);
|
addChild(&mMarquee);
|
||||||
|
@ -130,10 +124,6 @@ GridGameListView::GridGameListView(
|
||||||
updateInfoPanel();
|
updateInfoPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
GridGameListView::~GridGameListView()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void GridGameListView::onFileChanged(FileData* file, bool reloadGameList)
|
void GridGameListView::onFileChanged(FileData* file, bool reloadGameList)
|
||||||
{
|
{
|
||||||
if (reloadGameList) {
|
if (reloadGameList) {
|
||||||
|
@ -145,11 +135,6 @@ void GridGameListView::onFileChanged(FileData* file, bool reloadGameList)
|
||||||
ISimpleGameListView::onFileChanged(file, reloadGameList);
|
ISimpleGameListView::onFileChanged(file, reloadGameList);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* GridGameListView::getCursor()
|
|
||||||
{
|
|
||||||
return mGrid.getSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GridGameListView::setCursor(FileData* cursor)
|
void GridGameListView::setCursor(FileData* cursor)
|
||||||
{
|
{
|
||||||
if (!mGrid.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
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)
|
bool GridGameListView::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if (input.value == 0 && (config->isMappedLike("left", input) ||
|
if (input.value == 0 &&
|
||||||
config->isMappedLike("right", input) ||
|
(config->isMappedLike("left", input) || config->isMappedLike("right", input) ||
|
||||||
(config->isMappedLike("up", input)) ||
|
(config->isMappedLike("up", input)) || (config->isMappedLike("down", input))))
|
||||||
(config->isMappedLike("down", input)) ))
|
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
|
||||||
if (input.value != 0 && config->isMappedLike("righttrigger", input)) {
|
if (input.value != 0 && config->isMappedLike("righttrigger", input)) {
|
||||||
|
@ -288,17 +237,17 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
mGrid.applyTheme(theme, getName(), "gamegrid", ALL);
|
mGrid.applyTheme(theme, getName(), "gamegrid", ALL);
|
||||||
mName.applyTheme(theme, getName(), "md_name", ALL);
|
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||||
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mImage.applyTheme(theme, getName(), "md_image",
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
assert(labels.size() == 8);
|
assert(labels.size() == 8);
|
||||||
std::vector<std::string> lblElements = {
|
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
"md_lbl_developer", "md_lbl_publisher",
|
||||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
"md_lbl_genre", "md_lbl_players",
|
||||||
};
|
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||||
|
|
||||||
for (unsigned int i = 0; i < labels.size(); i++)
|
for (unsigned int i = 0; i < labels.size(); i++)
|
||||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||||
|
@ -306,19 +255,19 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
assert(values.size() == 8);
|
assert(values.size() == 8);
|
||||||
std::vector<std::string> valElements = {
|
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
"md_publisher", "md_genre", "md_players",
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_lastplayed", "md_playcount" };
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < values.size(); i++)
|
for (unsigned int i = 0; i < values.size(); i++)
|
||||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||||
|
|
||||||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description",
|
mDescription.applyTheme(
|
||||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
// Repopulate list in case a new theme is displaying a different image.
|
// Repopulate list in case a new theme is displaying a different image.
|
||||||
// Preserve selection.
|
// Preserve selection.
|
||||||
|
@ -336,6 +285,12 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
sortChildren();
|
sortChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GridGameListView::onShow()
|
||||||
|
{
|
||||||
|
GuiComponent::onShow();
|
||||||
|
updateInfoPanel();
|
||||||
|
}
|
||||||
|
|
||||||
void GridGameListView::initMDLabels()
|
void GridGameListView::initMDLabels()
|
||||||
{
|
{
|
||||||
std::vector<TextComponent*> components = getMDLabels();
|
std::vector<TextComponent*> components = getMDLabels();
|
||||||
|
@ -356,7 +311,7 @@ void GridGameListView::initMDLabels()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Work from the last component.
|
// 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);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,11 +338,11 @@ void GridGameListView::initMDValues()
|
||||||
|
|
||||||
float bottom = 0.0f;
|
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++) {
|
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() +
|
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]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||||
values[i]->setDefaultZIndex(40);
|
values[i]->setDefaultZIndex(40);
|
||||||
|
|
||||||
|
@ -397,8 +352,8 @@ void GridGameListView::initMDValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridGameListView::updateInfoPanel()
|
void GridGameListView::updateInfoPanel()
|
||||||
|
@ -465,21 +420,22 @@ void GridGameListView::updateInfoPanel()
|
||||||
|
|
||||||
if (mIsFiltered) {
|
if (mIsFiltered) {
|
||||||
if (mFilteredGameCountAll == mFilteredGameCount)
|
if (mFilteredGameCountAll == mFilteredGameCount)
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " "
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
+ std::to_string(mFilteredGameCount) + " / " + std::to_string(mGameCount);
|
std::to_string(mFilteredGameCount) + " / " +
|
||||||
|
std::to_string(mGameCount);
|
||||||
else
|
else
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
std::to_string(mFilteredGameCount) + " + " +
|
std::to_string(mFilteredGameCount) + " + " +
|
||||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||||
std::to_string(mGameCount);
|
" / " + std::to_string(mGameCount);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
gamelistInfoString +=
|
||||||
std::to_string(mGameCount);
|
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||||
if (!(file->getSystem()->isCollection() &&
|
if (!(file->getSystem()->isCollection() &&
|
||||||
file->getSystem()->getFullName() == "favorites"))
|
file->getSystem()->getFullName() == "favorites"))
|
||||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||||
std::to_string(mFavoritesGameCount);
|
std::to_string(mFavoritesGameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||||
|
@ -489,9 +445,9 @@ void GridGameListView::updateInfoPanel()
|
||||||
|
|
||||||
// Fade in the game image.
|
// Fade in the game image.
|
||||||
auto func = [this](float t) {
|
auto func = [this](float t) {
|
||||||
mImage.setOpacity(static_cast<unsigned char>(Math::lerp(
|
mImage.setOpacity(static_cast<unsigned char>(
|
||||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||||
};
|
};
|
||||||
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||||
|
|
||||||
mDescription.setText(file->metadata.get("desc"));
|
mDescription.setText(file->metadata.get("desc"));
|
||||||
|
@ -535,10 +491,10 @@ void GridGameListView::updateInfoPanel()
|
||||||
// An animation is playing, then animate if reverse != fadingOut.
|
// An animation is playing, then animate if reverse != fadingOut.
|
||||||
// An animation is not playing, then animate if opacity != our target opacity.
|
// An animation is not playing, then animate if opacity != our target opacity.
|
||||||
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
||||||
auto func = [comp](float t) {
|
auto func = [comp](float t) {
|
||||||
// TEMPORARY - This does not seem to work, needs to be reviewed later.
|
// TEMPORARY - This does not seem to work, needs to be reviewed later.
|
||||||
// comp->setOpacity(static_cast<unsigned char>(Math::lerp(0.0f, 1.0f, t) * 255));
|
// comp->setOpacity(static_cast<unsigned char>(Math::lerp(0.0f, 1.0f, t) * 255));
|
||||||
};
|
};
|
||||||
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
|
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
|
||||||
}
|
}
|
||||||
|
@ -560,6 +516,7 @@ void GridGameListView::addPlaceholder(FileData* firstEntry)
|
||||||
|
|
||||||
void GridGameListView::launch(FileData* game)
|
void GridGameListView::launch(FileData* game)
|
||||||
{
|
{
|
||||||
|
// This triggers ViewController to launch the game.
|
||||||
ViewController::get()->triggerGameLaunch(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
|
// 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.
|
// the directory too. Remove any empty parent directories as well.
|
||||||
auto removeEmptyDirFunc = []
|
auto removeEmptyDirFunc = [](std::string systemMediaDir, std::string mediaType,
|
||||||
(std::string systemMediaDir, std::string mediaType, std::string path) {
|
std::string path) {
|
||||||
std::string parentPath = Utils::FileSystem::getParent(path);
|
std::string parentPath = Utils::FileSystem::getParent(path);
|
||||||
while (parentPath != systemMediaDir + "/" + mediaType) {
|
while (parentPath != systemMediaDir + "/" + mediaType) {
|
||||||
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
if (Utils::FileSystem::getDirContent(parentPath).size() == 0) {
|
||||||
|
@ -707,7 +664,7 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
||||||
prompts.push_back(HelpPrompt("up/down/left/right", "choose"));
|
prompts.push_back(HelpPrompt("up/down/left/right", "choose"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" && mCursorStack.empty() &&
|
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" && mCursorStack.empty() &&
|
||||||
ViewController::get()->getState().viewing == ViewController::GAME_LIST)
|
ViewController::get()->getState().viewing == ViewController::GAME_LIST)
|
||||||
prompts.push_back(HelpPrompt("a", "enter"));
|
prompts.push_back(HelpPrompt("a", "enter"));
|
||||||
else
|
else
|
||||||
prompts.push_back(HelpPrompt("a", "launch"));
|
prompts.push_back(HelpPrompt("a", "launch"));
|
||||||
|
@ -715,32 +672,30 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
||||||
prompts.push_back(HelpPrompt("b", "back"));
|
prompts.push_back(HelpPrompt("b", "back"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->isGameSystem() &&
|
if (mRoot->getSystem()->isGameSystem() &&
|
||||||
mRoot->getSystem()->getThemeFolder() != "custom-collections")
|
mRoot->getSystem()->getThemeFolder() != "custom-collections")
|
||||||
prompts.push_back(HelpPrompt("x", "view media"));
|
prompts.push_back(HelpPrompt("x", "view media"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->isGameSystem() && !mCursorStack.empty() &&
|
if (mRoot->getSystem()->isGameSystem() && !mCursorStack.empty() &&
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections")
|
mRoot->getSystem()->getThemeFolder() == "custom-collections")
|
||||||
prompts.push_back(HelpPrompt("x", "view media"));
|
prompts.push_back(HelpPrompt("x", "view media"));
|
||||||
|
|
||||||
if (!UIModeController::getInstance()->isUIModeKid())
|
if (!UIModeController::getInstance()->isUIModeKid())
|
||||||
prompts.push_back(HelpPrompt("back", "options"));
|
prompts.push_back(HelpPrompt("back", "options"));
|
||||||
if (mRoot->getSystem()->isGameSystem() &&
|
if (mRoot->getSystem()->isGameSystem() && Settings::getInstance()->getBool("RandomAddButton"))
|
||||||
Settings::getInstance()->getBool("RandomAddButton"))
|
|
||||||
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
||||||
|
|
||||||
if (mRoot->getSystem()->isGameSystem() &&
|
if (mRoot->getSystem()->isGameSystem() &&
|
||||||
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
|
(mRoot->getSystem()->getThemeFolder() != "custom-collections" || !mCursorStack.empty()) &&
|
||||||
!mCursorStack.empty()) &&
|
!UIModeController::getInstance()->isUIModeKid() &&
|
||||||
!UIModeController::getInstance()->isUIModeKid() &&
|
!UIModeController::getInstance()->isUIModeKiosk() &&
|
||||||
!UIModeController::getInstance()->isUIModeKiosk() &&
|
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
||||||
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
CollectionSystemsManager::get()->isEditing())) {
|
||||||
CollectionSystemsManager::get()->isEditing())) {
|
|
||||||
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
}
|
}
|
||||||
else if (mRoot->getSystem()->isGameSystem() &&
|
else if (mRoot->getSystem()->isGameSystem() &&
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||||
CollectionSystemsManager::get()->isEditing()) {
|
CollectionSystemsManager::get()->isEditing()) {
|
||||||
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemsManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
}
|
}
|
||||||
|
@ -749,11 +704,6 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
||||||
|
|
||||||
void GridGameListView::update(int deltaTime)
|
void GridGameListView::update(int deltaTime)
|
||||||
{
|
{
|
||||||
|
// Update.
|
||||||
ISimpleGameListView::update(deltaTime);
|
ISimpleGameListView::update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridGameListView::onShow()
|
|
||||||
{
|
|
||||||
GuiComponent::onShow();
|
|
||||||
updateInfoPanel();
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,48 +20,50 @@ class GridGameListView : public ISimpleGameListView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GridGameListView(Window* window, FileData* root);
|
GridGameListView(Window* window, FileData* root);
|
||||||
virtual ~GridGameListView();
|
virtual ~GridGameListView() {}
|
||||||
|
|
||||||
// Called when a FileData* is added, has its metadata changed, or is removed.
|
// Called when a FileData* is added, has its metadata changed, or is removed.
|
||||||
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
virtual void onFileChanged(FileData* file, bool reloadGameList) override;
|
||||||
|
|
||||||
virtual void onShow() override;
|
virtual void onShow() override;
|
||||||
|
|
||||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||||
|
|
||||||
virtual FileData* getCursor() override;
|
|
||||||
virtual void setCursor(FileData* cursor) 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 std::string getName() const override { return "grid"; }
|
||||||
|
|
||||||
|
virtual bool input(InputConfig* config, Input input) override;
|
||||||
|
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
virtual void launch(FileData* game) 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
|
virtual void stopListScrolling() override
|
||||||
{
|
{
|
||||||
mGrid.stopAllAnimations();
|
mGrid.stopAllAnimations();
|
||||||
mGrid.stopScrolling();
|
mGrid.stopScrolling();
|
||||||
};
|
}
|
||||||
|
|
||||||
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
virtual const std::vector<std::string>& getFirstLetterIndex() override
|
||||||
{ return mFirstLetterIndex; };
|
{
|
||||||
|
return mFirstLetterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
virtual void addPlaceholder(FileData* firstEntry = nullptr) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void update(int deltaTime) override;
|
virtual std::string getQuickSystemSelectRightButton() override { return "rightshoulder"; }
|
||||||
virtual std::string getQuickSystemSelectRightButton() override;
|
virtual std::string getQuickSystemSelectLeftButton() override { return "leftshoulder"; }
|
||||||
virtual std::string getQuickSystemSelectLeftButton() override;
|
|
||||||
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
virtual void populateList(const std::vector<FileData*>& files, FileData* firstEntry) override;
|
||||||
virtual void remove(FileData* game, bool deleteFile) override;
|
virtual void remove(FileData* game, bool deleteFile) override;
|
||||||
virtual void removeMedia(FileData* game) override;
|
virtual void removeMedia(FileData* game) override;
|
||||||
|
virtual void update(int deltaTime) override;
|
||||||
|
|
||||||
ImageGridComponent<FileData*> mGrid;
|
ImageGridComponent<FileData*> mGrid;
|
||||||
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
|
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
|
||||||
|
|
|
@ -8,18 +8,32 @@
|
||||||
|
|
||||||
#include "views/gamelist/IGameListView.h"
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
|
||||||
#include "guis/GuiGamelistOptions.h"
|
|
||||||
#include "views/UIModeController.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "AudioManager.h"
|
#include "AudioManager.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "Window.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)
|
bool IGameListView::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
// Select button opens GuiGamelistOptions.
|
// Select button opens GuiGamelistOptions.
|
||||||
if (!UIModeController::getInstance()->isUIModeKid() &&
|
if (!UIModeController::getInstance()->isUIModeKid() && // Line break.
|
||||||
config->isMappedTo("back", input) && input.value) {
|
config->isMappedTo("back", input) && input.value) {
|
||||||
ViewController::get()->cancelViewTransitions();
|
ViewController::get()->cancelViewTransitions();
|
||||||
stopListScrolling();
|
stopListScrolling();
|
||||||
mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
|
mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
|
||||||
|
@ -28,9 +42,9 @@ bool IGameListView::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
// Ctrl-R reloads the view when debugging.
|
// Ctrl-R reloads the view when debugging.
|
||||||
else if (Settings::getInstance()->getBool("Debug") &&
|
else if (Settings::getInstance()->getBool("Debug") &&
|
||||||
config->getDeviceId() == DEVICE_KEYBOARD &&
|
config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||||
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) &&
|
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) && input.id == SDLK_r &&
|
||||||
input.id == SDLK_r && input.value != 0) {
|
input.value != 0) {
|
||||||
LOG(LogDebug) << "IGameListView::input(): Reloading view";
|
LOG(LogDebug) << "IGameListView::input(): Reloading view";
|
||||||
ViewController::get()->reloadGameListView(this, true);
|
ViewController::get()->reloadGameListView(this, true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -39,12 +53,6 @@ bool IGameListView::input(InputConfig* config, Input input)
|
||||||
return GuiComponent::input(config, input);
|
return GuiComponent::input(config, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
|
|
||||||
{
|
|
||||||
mTheme = theme;
|
|
||||||
onThemeChanged(theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
HelpStyle IGameListView::getHelpStyle()
|
HelpStyle IGameListView::getHelpStyle()
|
||||||
{
|
{
|
||||||
HelpStyle style;
|
HelpStyle style;
|
||||||
|
@ -60,9 +68,9 @@ void IGameListView::render(const Transform4x4f& parentTrans)
|
||||||
float scaleY = trans.r1().y();
|
float scaleY = trans.r1().y();
|
||||||
|
|
||||||
Vector2i pos(static_cast<int>(std::round(trans.translation()[0])),
|
Vector2i pos(static_cast<int>(std::round(trans.translation()[0])),
|
||||||
static_cast<int>(std::round(trans.translation()[1])));
|
static_cast<int>(std::round(trans.translation()[1])));
|
||||||
Vector2i size(static_cast<int>(std::round(mSize.x() * scaleX)),
|
Vector2i size(static_cast<int>(std::round(mSize.x() * scaleX)),
|
||||||
static_cast<int>(std::round(mSize.y() * scaleY)));
|
static_cast<int>(std::round(mSize.y() * scaleY)));
|
||||||
|
|
||||||
Renderer::pushClipRect(pos, size);
|
Renderer::pushClipRect(pos, size);
|
||||||
renderChildren(trans);
|
renderChildren(trans);
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H
|
||||||
#define 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 "FileData.h"
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
|
#include "renderers/Renderer.h"
|
||||||
|
|
||||||
class ThemeData;
|
class ThemeData;
|
||||||
class Window;
|
class Window;
|
||||||
|
@ -20,12 +20,7 @@ class Window;
|
||||||
class IGameListView : public GuiComponent
|
class IGameListView : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IGameListView(Window* window, FileData* root) : GuiComponent(window), mRoot(root)
|
IGameListView(Window* window, FileData* root);
|
||||||
{
|
|
||||||
setSize(static_cast<float>(Renderer::getScreenWidth()),
|
|
||||||
static_cast<float>(Renderer::getScreenHeight()));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~IGameListView() {}
|
virtual ~IGameListView() {}
|
||||||
|
|
||||||
// Called when a FileData* is added, has its metadata changed, or is removed.
|
// 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;
|
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) = 0;
|
||||||
|
|
||||||
void setTheme(const std::shared_ptr<ThemeData>& theme);
|
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 FileData* getCursor() = 0;
|
||||||
virtual void setCursor(FileData*) = 0;
|
virtual void setCursor(FileData*) = 0;
|
||||||
|
|
|
@ -8,26 +8,24 @@
|
||||||
|
|
||||||
#include "views/gamelist/ISimpleGameListView.h"
|
#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 "CollectionSystemsManager.h"
|
||||||
#include "FileFilterIndex.h"
|
#include "FileFilterIndex.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "guis/GuiInfoPopup.h"
|
||||||
|
#include "utils/StringUtil.h"
|
||||||
|
#include "views/UIModeController.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
ISimpleGameListView::ISimpleGameListView(
|
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root)
|
||||||
Window* window,
|
: IGameListView(window, root)
|
||||||
FileData* root)
|
, mHeaderText(window)
|
||||||
: IGameListView(window, root),
|
, mHeaderImage(window)
|
||||||
mHeaderText(window),
|
, mBackground(window)
|
||||||
mHeaderImage(window),
|
, mRandomGame(nullptr)
|
||||||
mBackground(window),
|
|
||||||
mRandomGame(nullptr)
|
|
||||||
{
|
{
|
||||||
mHeaderText.setText("Logo Text");
|
mHeaderText.setText("Logo Text");
|
||||||
mHeaderText.setSize(mSize.x(), 0);
|
mHeaderText.setSize(mSize.x(), 0);
|
||||||
|
@ -124,10 +122,10 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
std::vector<FileData*> listEntries = cursor->getChildrenListToDisplay();
|
std::vector<FileData*> listEntries = cursor->getChildrenListToDisplay();
|
||||||
// Check if there is an entry in the cursor stack history matching any entry
|
// Check if there is an entry in the cursor stack history matching any entry
|
||||||
// in the currect folder. If so, select that 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++) {
|
it != mCursorStackHistory.end(); it++) {
|
||||||
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
||||||
listEntries.end()) {
|
listEntries.end()) {
|
||||||
newCursor = *it;
|
newCursor = *it;
|
||||||
mCursorStackHistory.erase(it);
|
mCursorStackHistory.erase(it);
|
||||||
break;
|
break;
|
||||||
|
@ -155,7 +153,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
mCursorStackHistory.push_back(getCursor());
|
mCursorStackHistory.push_back(getCursor());
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(BACKSOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(BACKSOUND);
|
||||||
populateList(mCursorStack.top()->getParent()->getChildrenListToDisplay(),
|
populateList(mCursorStack.top()->getParent()->getChildrenListToDisplay(),
|
||||||
mCursorStack.top()->getParent());
|
mCursorStack.top()->getParent());
|
||||||
setCursor(mCursorStack.top());
|
setCursor(mCursorStack.top());
|
||||||
if (mCursorStack.size() > 0)
|
if (mCursorStack.size() > 0)
|
||||||
mCursorStack.pop();
|
mCursorStack.pop();
|
||||||
|
@ -169,9 +167,9 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
stopListScrolling();
|
stopListScrolling();
|
||||||
SystemData* systemToView = getCursor()->getSystem();
|
SystemData* systemToView = getCursor()->getSystem();
|
||||||
if (systemToView->isCustomCollection() &&
|
if (systemToView->isCustomCollection() &&
|
||||||
systemToView->getRootFolder()->getParent())
|
systemToView->getRootFolder()->getParent())
|
||||||
ViewController::get()->goToSystemView(
|
ViewController::get()->goToSystemView(
|
||||||
systemToView->getRootFolder()->getParent()->getSystem(), true);
|
systemToView->getRootFolder()->getParent()->getSystem(), true);
|
||||||
else
|
else
|
||||||
ViewController::get()->goToSystemView(systemToView, true);
|
ViewController::get()->goToSystemView(systemToView, true);
|
||||||
}
|
}
|
||||||
|
@ -184,9 +182,9 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (config->isMappedTo("x", input) &&
|
else if (config->isMappedTo("x", input) &&
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||||
mCursorStack.empty() && ViewController::get()->getState().viewing ==
|
mCursorStack.empty() &&
|
||||||
ViewController::GAME_LIST) {
|
ViewController::get()->getState().viewing == ViewController::GAME_LIST) {
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
||||||
// Jump to the randomly selected game.
|
// Jump to the randomly selected game.
|
||||||
if (mRandomGame) {
|
if (mRandomGame) {
|
||||||
|
@ -206,7 +204,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
else if (config->isMappedLike(getQuickSystemSelectRightButton(), input)) {
|
else if (config->isMappedLike(getQuickSystemSelectRightButton(), input)) {
|
||||||
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
||||||
SystemData::sSystemVector.size() > 1) {
|
SystemData::sSystemVector.size() > 1) {
|
||||||
onPauseVideo();
|
onPauseVideo();
|
||||||
onFocusLost();
|
onFocusLost();
|
||||||
stopListScrolling();
|
stopListScrolling();
|
||||||
|
@ -216,7 +214,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
else if (config->isMappedLike(getQuickSystemSelectLeftButton(), input)) {
|
else if (config->isMappedLike(getQuickSystemSelectLeftButton(), input)) {
|
||||||
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
||||||
SystemData::sSystemVector.size() > 1) {
|
SystemData::sSystemVector.size() > 1) {
|
||||||
onPauseVideo();
|
onPauseVideo();
|
||||||
onFocusLost();
|
onFocusLost();
|
||||||
stopListScrolling();
|
stopListScrolling();
|
||||||
|
@ -225,8 +223,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Settings::getInstance()->getBool("RandomAddButton") &&
|
else if (Settings::getInstance()->getBool("RandomAddButton") &&
|
||||||
(config->isMappedTo("leftthumbstickclick", input) ||
|
(config->isMappedTo("leftthumbstickclick", input) ||
|
||||||
config->isMappedTo("rightthumbstickclick", input))) {
|
config->isMappedTo("rightthumbstickclick", input))) {
|
||||||
if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER) {
|
if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER) {
|
||||||
stopListScrolling();
|
stopListScrolling();
|
||||||
// Jump to a random game.
|
// Jump to a random game.
|
||||||
|
@ -238,21 +236,19 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (config->isMappedTo("y", input) &&
|
else if (config->isMappedTo("y", input) &&
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
||||||
!CollectionSystemsManager::get()->isEditing() &&
|
!CollectionSystemsManager::get()->isEditing() && mCursorStack.empty() &&
|
||||||
mCursorStack.empty() && ViewController::get()->getState().viewing ==
|
ViewController::get()->getState().viewing == ViewController::GAME_LIST) {
|
||||||
ViewController::GAME_LIST) {
|
|
||||||
// Jump to the randomly selected game.
|
// Jump to the randomly selected game.
|
||||||
if (mRandomGame) {
|
if (mRandomGame) {
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(SELECTSOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(SELECTSOUND);
|
||||||
// If there is already an mCursorStackHistory entry for the collection, then
|
// If there is already an mCursorStackHistory entry for the collection, then
|
||||||
// remove it so we don't get multiple entries.
|
// remove it so we don't get multiple entries.
|
||||||
std::vector<FileData*> listEntries =
|
std::vector<FileData*> listEntries =
|
||||||
mRandomGame->getSystem()->getRootFolder()->getChildrenListToDisplay();
|
mRandomGame->getSystem()->getRootFolder()->getChildrenListToDisplay();
|
||||||
for (auto it = mCursorStackHistory.begin();
|
for (auto it = mCursorStackHistory.begin(); it != mCursorStackHistory.end(); it++) {
|
||||||
it != mCursorStackHistory.end(); it++) {
|
|
||||||
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
if (std::find(listEntries.begin(), listEntries.end(), *it) !=
|
||||||
listEntries.end()) {
|
listEntries.end()) {
|
||||||
mCursorStackHistory.erase(it);
|
mCursorStackHistory.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -265,34 +261,33 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (config->isMappedTo("y", input) &&
|
else if (config->isMappedTo("y", input) &&
|
||||||
!Settings::getInstance()->getBool("FavoritesAddButton") &&
|
!Settings::getInstance()->getBool("FavoritesAddButton") &&
|
||||||
!CollectionSystemsManager::get()->isEditing()) {
|
!CollectionSystemsManager::get()->isEditing()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (config->isMappedTo("y", input) &&
|
else if (config->isMappedTo("y", input) &&
|
||||||
!UIModeController::getInstance()->isUIModeKid() &&
|
!UIModeController::getInstance()->isUIModeKid() &&
|
||||||
!UIModeController::getInstance()->isUIModeKiosk()) {
|
!UIModeController::getInstance()->isUIModeKiosk()) {
|
||||||
// Notify the user if attempting to add a custom collection to a custom collection.
|
// Notify the user if attempting to add a custom collection to a custom collection.
|
||||||
if (CollectionSystemsManager::get()->isEditing() &&
|
if (CollectionSystemsManager::get()->isEditing() &&
|
||||||
mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER &&
|
mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER &&
|
||||||
getCursor()->getParent()->getPath() == "collections") {
|
getCursor()->getParent()->getPath() == "collections") {
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||||
GuiInfoPopup* s;
|
GuiInfoPopup* s;
|
||||||
s = new GuiInfoPopup(mWindow,
|
s = new GuiInfoPopup(mWindow, "CAN'T ADD CUSTOM COLLECTIONS TO CUSTOM COLLECTIONS",
|
||||||
"CAN'T ADD CUSTOM COLLECTIONS TO CUSTOM COLLECTIONS", 4000);
|
4000);
|
||||||
mWindow->setInfoPopup(s);
|
mWindow->setInfoPopup(s);
|
||||||
}
|
}
|
||||||
// Notify the user if attempting to add a placeholder to a custom collection.
|
// Notify the user if attempting to add a placeholder to a custom collection.
|
||||||
if (CollectionSystemsManager::get()->isEditing() &&
|
if (CollectionSystemsManager::get()->isEditing() &&
|
||||||
mRoot->getSystem()->isGameSystem() && getCursor()->getType() == PLACEHOLDER) {
|
mRoot->getSystem()->isGameSystem() && getCursor()->getType() == PLACEHOLDER) {
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||||
GuiInfoPopup* s;
|
GuiInfoPopup* s;
|
||||||
s = new GuiInfoPopup(mWindow,
|
s = new GuiInfoPopup(mWindow, "CAN'T ADD PLACEHOLDERS TO CUSTOM COLLECTIONS", 4000);
|
||||||
"CAN'T ADD PLACEHOLDERS TO CUSTOM COLLECTIONS", 4000);
|
|
||||||
mWindow->setInfoPopup(s);
|
mWindow->setInfoPopup(s);
|
||||||
}
|
}
|
||||||
else if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER &&
|
else if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER &&
|
||||||
getCursor()->getParent()->getPath() != "collections") {
|
getCursor()->getParent()->getPath() != "collections") {
|
||||||
if (getCursor()->getType() == GAME || getCursor()->getType() == FOLDER)
|
if (getCursor()->getType() == GAME || getCursor()->getType() == FOLDER)
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||||
// When marking or unmarking a game as favorite, don't jump to the new position
|
// When marking or unmarking a game as favorite, don't jump to the new position
|
||||||
|
@ -312,13 +307,14 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
foldersOnTop = !getCursor()->getParent()->getOnlyFoldersFlag();
|
foldersOnTop = !getCursor()->getParent()->getOnlyFoldersFlag();
|
||||||
|
|
||||||
if (mRoot->getSystem()->isCustomCollection() ||
|
if (mRoot->getSystem()->isCustomCollection() ||
|
||||||
mRoot->getSystem()->getThemeFolder() == "custom-collections")
|
mRoot->getSystem()->getThemeFolder() == "custom-collections")
|
||||||
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
||||||
else
|
else
|
||||||
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||||
|
|
||||||
if (favoritesSorting && static_cast<std::string>(
|
if (favoritesSorting &&
|
||||||
mRoot->getSystem()->getName()) != "recent" && !isEditing) {
|
static_cast<std::string>(mRoot->getSystem()->getName()) != "recent" &&
|
||||||
|
!isEditing) {
|
||||||
FileData* entryToSelect;
|
FileData* entryToSelect;
|
||||||
// Add favorite flag.
|
// Add favorite flag.
|
||||||
if (!getCursor()->getFavorite()) {
|
if (!getCursor()->getFavorite()) {
|
||||||
|
@ -331,7 +327,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
entryToSelect = getNextEntry();
|
entryToSelect = getNextEntry();
|
||||||
}
|
}
|
||||||
else if (getCursor() == getLastEntry() &&
|
else if (getCursor() == getLastEntry() &&
|
||||||
getPreviousEntry()->getFavorite()) {
|
getPreviousEntry()->getFavorite()) {
|
||||||
entryToSelect = getLastEntry();
|
entryToSelect = getLastEntry();
|
||||||
selectLastEntry = true;
|
selectLastEntry = true;
|
||||||
}
|
}
|
||||||
|
@ -342,14 +338,14 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
// If we mark the second entry as favorite and the first entry is not a
|
// If we mark the second entry as favorite and the first entry is not a
|
||||||
// favorite, then select this entry if they are of the same type.
|
// favorite, then select this entry if they are of the same type.
|
||||||
else if (getPreviousEntry() == getFirstEntry() &&
|
else if (getPreviousEntry() == getFirstEntry() &&
|
||||||
getCursor()->getType() == getPreviousEntry()->getType()) {
|
getCursor()->getType() == getPreviousEntry()->getType()) {
|
||||||
entryToSelect = getPreviousEntry();
|
entryToSelect = getPreviousEntry();
|
||||||
}
|
}
|
||||||
// For all other scenarios try to select the next entry, and if it doesn't
|
// For all other scenarios try to select the next entry, and if it doesn't
|
||||||
// exist, select the previous entry.
|
// exist, select the previous entry.
|
||||||
else {
|
else {
|
||||||
entryToSelect = getCursor() != getNextEntry() ?
|
entryToSelect =
|
||||||
getNextEntry() : getPreviousEntry();
|
getCursor() != getNextEntry() ? getNextEntry() : getPreviousEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove favorite flag.
|
// Remove favorite flag.
|
||||||
|
@ -365,9 +361,10 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
// If we are on the favorite marking boundary, select the previous entry,
|
// If we are on the favorite marking boundary, select the previous entry,
|
||||||
// unless folders are sorted on top and the previous entry is a folder.
|
// unless folders are sorted on top and the previous entry is a folder.
|
||||||
else if (foldersOnTop &&
|
else if (foldersOnTop &&
|
||||||
getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
||||||
entryToSelect = getPreviousEntry()->getType() == FOLDER ?
|
entryToSelect = getPreviousEntry()->getType() == FOLDER ?
|
||||||
getCursor() : getPreviousEntry();
|
getCursor() :
|
||||||
|
getPreviousEntry();
|
||||||
}
|
}
|
||||||
// If we are on the favorite marking boundary, select the previous entry.
|
// If we are on the favorite marking boundary, select the previous entry.
|
||||||
else if (getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
else if (getCursor()->getFavorite() != getNextEntry()->getFavorite()) {
|
||||||
|
@ -376,17 +373,17 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
// For all other scenarios try to select the next entry, and if it doesn't
|
// For all other scenarios try to select the next entry, and if it doesn't
|
||||||
// exist, select the previous entry.
|
// exist, select the previous entry.
|
||||||
else {
|
else {
|
||||||
entryToSelect = getCursor() != getNextEntry() ?
|
entryToSelect =
|
||||||
getNextEntry() : getPreviousEntry();
|
getCursor() != getNextEntry() ? getNextEntry() : getPreviousEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we removed the last favorite marking, set the flag to jump to the
|
// If we removed the last favorite marking, set the flag to jump to the
|
||||||
// first list entry after the sorting has been performed.
|
// first list entry after the sorting has been performed.
|
||||||
if (foldersOnTop && getCursor() == getFirstGameEntry() &&
|
if (foldersOnTop && getCursor() == getFirstGameEntry() &&
|
||||||
!getNextEntry()->getFavorite())
|
!getNextEntry()->getFavorite())
|
||||||
removedLastFavorite = true;
|
removedLastFavorite = true;
|
||||||
else if (getCursor() == getFirstEntry() && !getNextEntry()->getFavorite())
|
else if (getCursor() == getFirstEntry() && !getNextEntry()->getFavorite())
|
||||||
removedLastFavorite = true;
|
removedLastFavorite = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursor(entryToSelect);
|
setCursor(entryToSelect);
|
||||||
|
@ -399,22 +396,30 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
if (entryToUpdate->getType() == FOLDER) {
|
if (entryToUpdate->getType() == FOLDER) {
|
||||||
GuiInfoPopup* s;
|
GuiInfoPopup* s;
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
s = new GuiInfoPopup(mWindow,
|
s = new GuiInfoPopup(mWindow, "CAN'T ADD FOLDERS TO CUSTOM COLLECTIONS",
|
||||||
"CAN'T ADD FOLDERS TO CUSTOM COLLECTIONS", 4000);
|
4000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MetaDataList* md = &entryToUpdate->getSourceFileData()->metadata;
|
MetaDataList* md = &entryToUpdate->getSourceFileData()->metadata;
|
||||||
if (md->get("favorite") == "false") {
|
if (md->get("favorite") == "false") {
|
||||||
md->set("favorite", "true");
|
md->set("favorite", "true");
|
||||||
s = new GuiInfoPopup(mWindow, "MARKED FOLDER '" +
|
s = new GuiInfoPopup(
|
||||||
|
mWindow,
|
||||||
|
"MARKED FOLDER '" +
|
||||||
Utils::String::toUpper(Utils::String::removeParenthesis(
|
Utils::String::toUpper(Utils::String::removeParenthesis(
|
||||||
entryToUpdate->getName())) + "' AS FAVORITE", 4000);
|
entryToUpdate->getName())) +
|
||||||
|
"' AS FAVORITE",
|
||||||
|
4000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
md->set("favorite", "false");
|
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(
|
Utils::String::toUpper(Utils::String::removeParenthesis(
|
||||||
entryToUpdate->getName())) + "'", 4000);
|
entryToUpdate->getName())) +
|
||||||
|
"'",
|
||||||
|
4000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,8 +427,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
entryToUpdate->getSourceFileData()->getSystem()->onMetaDataSavePoint();
|
entryToUpdate->getSourceFileData()->getSystem()->onMetaDataSavePoint();
|
||||||
|
|
||||||
getCursor()->getParent()->sort(
|
getCursor()->getParent()->sort(
|
||||||
mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
|
mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
|
||||||
Settings::getInstance()->getBool("FavoritesFirst"));
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
|
|
||||||
ViewController::get()->onFileChanged(getCursor(), false);
|
ViewController::get()->onFileChanged(getCursor(), false);
|
||||||
|
|
||||||
|
@ -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
|
// was unmarked. We couldn't do this earlier as we didn't have the list
|
||||||
// sorted yet.
|
// sorted yet.
|
||||||
if (removedLastFavorite) {
|
if (removedLastFavorite) {
|
||||||
ViewController::get()->getGameListView(entryToUpdate->
|
ViewController::get()
|
||||||
getSystem())->setCursor(ViewController::get()->
|
->getGameListView(entryToUpdate->getSystem())
|
||||||
getGameListView(entryToUpdate->getSystem())->getFirstEntry());
|
->setCursor(ViewController::get()
|
||||||
|
->getGameListView(entryToUpdate->getSystem())
|
||||||
|
->getFirstEntry());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (isEditing && entryToUpdate->metadata.get("nogamecount") == "true") {
|
else if (isEditing && entryToUpdate->metadata.get("nogamecount") == "true") {
|
||||||
GuiInfoPopup* s = new GuiInfoPopup(mWindow,
|
GuiInfoPopup* s = new GuiInfoPopup(mWindow,
|
||||||
"CAN'T ADD ENTRIES THAT ARE NOT COUNTED "
|
"CAN'T ADD ENTRIES THAT ARE NOT COUNTED "
|
||||||
"AS GAMES TO CUSTOM COLLECTIONS", 4000);
|
"AS GAMES TO CUSTOM COLLECTIONS",
|
||||||
|
4000);
|
||||||
mWindow->setInfoPopup(s);
|
mWindow->setInfoPopup(s);
|
||||||
}
|
}
|
||||||
else if (CollectionSystemsManager::get()->toggleGameInCollection(entryToUpdate)) {
|
else if (CollectionSystemsManager::get()->toggleGameInCollection(entryToUpdate)) {
|
||||||
|
@ -450,13 +458,15 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
IGameListView* view = ViewController::get()->getGameListView(system).get();
|
IGameListView* view = ViewController::get()->getGameListView(system).get();
|
||||||
// Jump to the first entry in the gamelist if the last favorite was unmarked.
|
// Jump to the first entry in the gamelist if the last favorite was unmarked.
|
||||||
if (foldersOnTop && removedLastFavorite &&
|
if (foldersOnTop && removedLastFavorite &&
|
||||||
!entryToUpdate->getSystem()->isCustomCollection()) {
|
!entryToUpdate->getSystem()->isCustomCollection()) {
|
||||||
ViewController::get()->getGameListView(entryToUpdate->getSystem())->
|
ViewController::get()
|
||||||
setCursor(ViewController::get()->getGameListView(entryToUpdate->
|
->getGameListView(entryToUpdate->getSystem())
|
||||||
getSystem())->getFirstGameEntry());
|
->setCursor(ViewController::get()
|
||||||
|
->getGameListView(entryToUpdate->getSystem())
|
||||||
|
->getFirstGameEntry());
|
||||||
}
|
}
|
||||||
else if (removedLastFavorite &&
|
else if (removedLastFavorite &&
|
||||||
!entryToUpdate->getSystem()->isCustomCollection()) {
|
!entryToUpdate->getSystem()->isCustomCollection()) {
|
||||||
view->setCursor(view->getFirstEntry());
|
view->setCursor(view->getFirstEntry());
|
||||||
}
|
}
|
||||||
else if (selectLastEntry) {
|
else if (selectLastEntry) {
|
||||||
|
@ -467,10 +477,9 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
// onFileChanged() which will trigger populateList().
|
// onFileChanged() which will trigger populateList().
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
for (auto it = SystemData::sSystemVector.begin();
|
for (auto it = SystemData::sSystemVector.begin();
|
||||||
it != SystemData::sSystemVector.end(); it++) {
|
it != SystemData::sSystemVector.end(); it++) {
|
||||||
ViewController::get()->getGameListView((*it))->onFileChanged(
|
ViewController::get()->getGameListView((*it))->onFileChanged(
|
||||||
ViewController::get()->getGameListView((*it))->
|
ViewController::get()->getGameListView((*it))->getCursor(), false);
|
||||||
getCursor(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -511,13 +520,13 @@ void ISimpleGameListView::generateGamelistInfo(FileData* cursor, FileData* first
|
||||||
|
|
||||||
if (idx->isFiltered()) {
|
if (idx->isFiltered()) {
|
||||||
mIsFiltered = true;
|
mIsFiltered = true;
|
||||||
mFilteredGameCount = static_cast<unsigned int>(rootFolder->
|
mFilteredGameCount =
|
||||||
getFilesRecursive(GAME, true, false).size());
|
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
|
// 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'
|
// apply to such entries as well and this will be indicated with a separate '+ XX'
|
||||||
// in the GamelistInfo field.
|
// in the GamelistInfo field.
|
||||||
mFilteredGameCountAll = static_cast<unsigned int>(rootFolder->
|
mFilteredGameCountAll =
|
||||||
getFilesRecursive(GAME, true, true).size());
|
static_cast<unsigned int>(rootFolder->getFilesRecursive(GAME, true, true).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstEntry->getParent() && firstEntry->getParent()->getType() == FOLDER)
|
if (firstEntry->getParent() && firstEntry->getParent()->getType() == FOLDER)
|
||||||
|
@ -541,7 +550,7 @@ void ISimpleGameListView::generateFirstLetterIndex(const std::vector<FileData*>&
|
||||||
else
|
else
|
||||||
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||||
|
|
||||||
bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop");
|
bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop");
|
||||||
|
|
||||||
// Find out if there are only favorites and/or only folders in the list.
|
// Find out if there are only favorites and/or only folders in the list.
|
||||||
for (auto it = files.begin(); it != files.end(); it++) {
|
for (auto it = files.begin(); it != files.end(); it++) {
|
||||||
|
@ -553,16 +562,20 @@ void ISimpleGameListView::generateFirstLetterIndex(const std::vector<FileData*>&
|
||||||
|
|
||||||
// Build the index.
|
// Build the index.
|
||||||
for (auto it = files.begin(); it != files.end(); it++) {
|
for (auto it = files.begin(); it != files.end(); it++) {
|
||||||
if ((*it)->getType() == FOLDER && (*it)->getFavorite() &&
|
if ((*it)->getType() == FOLDER && (*it)->getFavorite() && favoritesSorting &&
|
||||||
favoritesSorting && !onlyFavorites)
|
!onlyFavorites) {
|
||||||
hasFavorites = true;
|
hasFavorites = true;
|
||||||
else if ((*it)->getType() == FOLDER && foldersOnTop && !onlyFolders)
|
}
|
||||||
|
else if ((*it)->getType() == FOLDER && foldersOnTop && !onlyFolders) {
|
||||||
hasFolders = true;
|
hasFolders = true;
|
||||||
else if ((*it)->getType() == GAME && (*it)->getFavorite() &&
|
}
|
||||||
favoritesSorting && !onlyFavorites)
|
else if ((*it)->getType() == GAME && (*it)->getFavorite() && favoritesSorting &&
|
||||||
|
!onlyFavorites) {
|
||||||
hasFavorites = true;
|
hasFavorites = true;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
mFirstLetterIndex.push_back(Utils::String::getFirstCharacter((*it)->getSortName()));
|
mFirstLetterIndex.push_back(Utils::String::getFirstCharacter((*it)->getSortName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort and make each entry unique.
|
// Sort and make each entry unique.
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H
|
||||||
#define 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/ImageComponent.h"
|
||||||
#include "components/TextComponent.h"
|
#include "components/TextComponent.h"
|
||||||
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
|
@ -39,9 +39,13 @@ public:
|
||||||
// These functions are used to retain the folder cursor history, for instance
|
// These functions are used to retain the folder cursor history, for instance
|
||||||
// during a view reload. The calling function stores the history temporarily.
|
// during a view reload. The calling function stores the history temporarily.
|
||||||
void copyCursorHistory(std::vector<FileData*>& cursorHistory) override
|
void copyCursorHistory(std::vector<FileData*>& cursorHistory) override
|
||||||
{ cursorHistory = mCursorStackHistory; };
|
{
|
||||||
|
cursorHistory = mCursorStackHistory;
|
||||||
|
};
|
||||||
void populateCursorHistory(std::vector<FileData*>& cursorHistory) override
|
void populateCursorHistory(std::vector<FileData*>& cursorHistory) override
|
||||||
{ mCursorStackHistory = cursorHistory; };
|
{
|
||||||
|
mCursorStackHistory = cursorHistory;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual std::string getQuickSystemSelectRightButton() = 0;
|
virtual std::string getQuickSystemSelectRightButton() = 0;
|
||||||
|
|
|
@ -16,67 +16,62 @@
|
||||||
#if defined(BUILD_VLC_PLAYER)
|
#if defined(BUILD_VLC_PLAYER)
|
||||||
#include "components/VideoVlcComponent.h"
|
#include "components/VideoVlcComponent.h"
|
||||||
#endif
|
#endif
|
||||||
#include "utils/FileSystemUtil.h"
|
|
||||||
#include "views/ViewController.h"
|
|
||||||
#include "AudioManager.h"
|
#include "AudioManager.h"
|
||||||
#include "CollectionSystemsManager.h"
|
#include "CollectionSystemsManager.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
#define FADE_IN_START_OPACITY 0.5f
|
#define FADE_IN_START_OPACITY 0.5f
|
||||||
#define FADE_IN_TIME 650
|
#define FADE_IN_TIME 650
|
||||||
|
|
||||||
VideoGameListView::VideoGameListView(
|
VideoGameListView::VideoGameListView(Window* window, FileData* root)
|
||||||
Window* window,
|
: BasicGameListView(window, root)
|
||||||
FileData* root)
|
, mDescContainer(window)
|
||||||
: BasicGameListView(window, root),
|
, mDescription(window)
|
||||||
mDescContainer(window),
|
, mGamelistInfo(window)
|
||||||
mDescription(window),
|
, mThumbnail(window)
|
||||||
mGamelistInfo(window),
|
, mMarquee(window)
|
||||||
|
, mImage(window)
|
||||||
mThumbnail(window),
|
, mVideo(nullptr)
|
||||||
mMarquee(window),
|
, mVideoPlaying(false)
|
||||||
mImage(window),
|
, mLblRating(window)
|
||||||
mVideo(nullptr),
|
, mLblReleaseDate(window)
|
||||||
mVideoPlaying(false),
|
, mLblDeveloper(window)
|
||||||
|
, mLblPublisher(window)
|
||||||
mLblRating(window),
|
, mLblGenre(window)
|
||||||
mLblReleaseDate(window),
|
, mLblPlayers(window)
|
||||||
mLblDeveloper(window),
|
, mLblLastPlayed(window)
|
||||||
mLblPublisher(window),
|
, mLblPlayCount(window)
|
||||||
mLblGenre(window),
|
, mRating(window)
|
||||||
mLblPlayers(window),
|
, mReleaseDate(window)
|
||||||
mLblLastPlayed(window),
|
, mDeveloper(window)
|
||||||
mLblPlayCount(window),
|
, mPublisher(window)
|
||||||
|
, mGenre(window)
|
||||||
mRating(window),
|
, mPlayers(window)
|
||||||
mReleaseDate(window),
|
, mLastPlayed(window)
|
||||||
mDeveloper(window),
|
, mPlayCount(window)
|
||||||
mPublisher(window),
|
, mName(window)
|
||||||
mGenre(window),
|
, mLastUpdated(nullptr)
|
||||||
mPlayers(window),
|
|
||||||
mLastPlayed(window),
|
|
||||||
mPlayCount(window),
|
|
||||||
mName(window),
|
|
||||||
mLastUpdated(nullptr)
|
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
// Create the correct type of video window.
|
// Create the correct type of video window.
|
||||||
#if defined(_RPI_)
|
#if defined(_RPI_)
|
||||||
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
||||||
mVideo = new VideoOmxComponent(window);
|
mVideo = new VideoOmxComponent(window);
|
||||||
else if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
else if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||||
mVideo = new VideoVlcComponent(window);
|
mVideo = new VideoVlcComponent(window);
|
||||||
else
|
else
|
||||||
mVideo = new VideoFFmpegComponent(window);
|
mVideo = new VideoFFmpegComponent(window);
|
||||||
#elif defined(BUILD_VLC_PLAYER)
|
#elif defined(BUILD_VLC_PLAYER)
|
||||||
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
||||||
mVideo = new VideoVlcComponent(window);
|
mVideo = new VideoVlcComponent(window);
|
||||||
else
|
else
|
||||||
mVideo = new VideoFFmpegComponent(window);
|
mVideo = new VideoFFmpegComponent(window);
|
||||||
#else
|
#else
|
||||||
mVideo = new VideoFFmpegComponent(window);
|
mVideo = new VideoFFmpegComponent(window);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
||||||
mList.setSize(mSize.x() * (0.50f - padding), mList.getSize().y());
|
mList.setSize(mSize.x() * (0.50f - padding), mList.getSize().y());
|
||||||
|
@ -87,21 +82,21 @@ VideoGameListView::VideoGameListView(
|
||||||
mThumbnail.setOrigin(0.5f, 0.5f);
|
mThumbnail.setOrigin(0.5f, 0.5f);
|
||||||
mThumbnail.setPosition(2.0f, 2.0f);
|
mThumbnail.setPosition(2.0f, 2.0f);
|
||||||
mThumbnail.setVisible(false);
|
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);
|
mThumbnail.setDefaultZIndex(35);
|
||||||
addChild(&mThumbnail);
|
addChild(&mThumbnail);
|
||||||
|
|
||||||
// Marquee.
|
// Marquee.
|
||||||
mMarquee.setOrigin(0.5f, 0.5f);
|
mMarquee.setOrigin(0.5f, 0.5f);
|
||||||
mMarquee.setPosition(mSize.x() * 0.25f, mSize.y() * 0.10f);
|
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.setDefaultZIndex(35);
|
||||||
addChild(&mMarquee);
|
addChild(&mMarquee);
|
||||||
|
|
||||||
// Video.
|
// Video.
|
||||||
mVideo->setOrigin(0.5f, 0.5f);
|
mVideo->setOrigin(0.5f, 0.5f);
|
||||||
mVideo->setPosition(mSize.x() * 0.25f, mSize.y() * 0.4f);
|
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);
|
mVideo->setDefaultZIndex(30);
|
||||||
addChild(mVideo);
|
addChild(mVideo);
|
||||||
|
|
||||||
|
@ -140,8 +135,8 @@ VideoGameListView::VideoGameListView(
|
||||||
addChild(&mName);
|
addChild(&mName);
|
||||||
|
|
||||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||||
mDescContainer.setSize(mSize.x() * (0.50f - 2 * padding), mSize.y() -
|
mDescContainer.setSize(mSize.x() * (0.50f - 2.0f * padding),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -160,10 +155,7 @@ VideoGameListView::VideoGameListView(
|
||||||
initMDValues();
|
initMDValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoGameListView::~VideoGameListView()
|
VideoGameListView::~VideoGameListView() { delete mVideo; }
|
||||||
{
|
|
||||||
delete mVideo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
{
|
{
|
||||||
|
@ -171,22 +163,23 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mImage.applyTheme(theme, getName(), "md_image",
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mVideo->applyTheme(theme, getName(), "md_video",
|
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);
|
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
assert(labels.size() == 8);
|
assert(labels.size() == 8);
|
||||||
std::vector<std::string> lblElements = {
|
std::vector<std::string> lblElements = { "md_lbl_rating", "md_lbl_releasedate",
|
||||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
"md_lbl_developer", "md_lbl_publisher",
|
||||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
"md_lbl_genre", "md_lbl_players",
|
||||||
};
|
"md_lbl_lastplayed", "md_lbl_playcount" };
|
||||||
|
|
||||||
for (unsigned int i = 0; i < labels.size(); i++)
|
for (unsigned int i = 0; i < labels.size(); i++)
|
||||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||||
|
@ -194,19 +187,19 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
assert(values.size() == 8);
|
assert(values.size() == 8);
|
||||||
std::vector<std::string> valElements = {
|
std::vector<std::string> valElements = { "md_rating", "md_releasedate", "md_developer",
|
||||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
"md_publisher", "md_genre", "md_players",
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_lastplayed", "md_playcount" };
|
||||||
};
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < values.size(); i++)
|
for (unsigned int i = 0; i < values.size(); i++)
|
||||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||||
|
|
||||||
mDescContainer.applyTheme(theme, getName(), "md_description",
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description",
|
mDescription.applyTheme(
|
||||||
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT);
|
||||||
// If there is no position defined in the theme for gamelistInfo, then hide it.
|
// If there is no position defined in the theme for gamelistInfo, then hide it.
|
||||||
|
@ -238,7 +231,7 @@ void VideoGameListView::initMDLabels()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Work from the last component.
|
// 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);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,11 +258,11 @@ void VideoGameListView::initMDValues()
|
||||||
|
|
||||||
float bottom = 0.0f;
|
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++) {
|
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() +
|
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]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||||
values[i]->setDefaultZIndex(40);
|
values[i]->setDefaultZIndex(40);
|
||||||
|
|
||||||
|
@ -280,8 +273,8 @@ void VideoGameListView::initMDValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
mDescContainer.setSize(mDescContainer.getSize().x(),
|
||||||
mDescContainer.getPosition().y());
|
mSize.y() - mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoGameListView::updateInfoPanel()
|
void VideoGameListView::updateInfoPanel()
|
||||||
|
@ -300,7 +293,7 @@ void VideoGameListView::updateInfoPanel()
|
||||||
if (file) {
|
if (file) {
|
||||||
// Always hide the metadata fields if browsing grouped custom collections.
|
// Always hide the metadata fields if browsing grouped custom collections.
|
||||||
if (file->getSystem()->isCustomCollection() &&
|
if (file->getSystem()->isCustomCollection() &&
|
||||||
file->getPath() == file->getSystem()->getName())
|
file->getPath() == file->getSystem()->getName())
|
||||||
hideMetaDataFields = true;
|
hideMetaDataFields = true;
|
||||||
else
|
else
|
||||||
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
|
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
|
||||||
|
@ -316,9 +309,9 @@ void VideoGameListView::updateInfoPanel()
|
||||||
// or if we're in the grouped custom collection view.
|
// or if we're in the grouped custom collection view.
|
||||||
if (mList.isScrolling())
|
if (mList.isScrolling())
|
||||||
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
||||||
(mLastUpdated->getSystem()->isCustomCollection() &&
|
(mLastUpdated->getSystem()->isCustomCollection() &&
|
||||||
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
||||||
hideMetaDataFields = true;
|
hideMetaDataFields = true;
|
||||||
|
|
||||||
if (hideMetaDataFields) {
|
if (hideMetaDataFields) {
|
||||||
mLblRating.setVisible(false);
|
mLblRating.setVisible(false);
|
||||||
|
@ -367,9 +360,9 @@ void VideoGameListView::updateInfoPanel()
|
||||||
// which will generate a description of three random games and return a pointer to
|
// which will generate a description of three random games and return a pointer to
|
||||||
// the first of these so that we can display its game media.
|
// the first of these so that we can display its game media.
|
||||||
if (file->getSystem()->isCustomCollection() &&
|
if (file->getSystem()->isCustomCollection() &&
|
||||||
file->getPath() == file->getSystem()->getName()) {
|
file->getPath() == file->getSystem()->getName()) {
|
||||||
mRandomGame = CollectionSystemsManager::get()->
|
mRandomGame =
|
||||||
updateCollectionFolderMetadata(file->getSystem());
|
CollectionSystemsManager::get()->updateCollectionFolderMetadata(file->getSystem());
|
||||||
if (mRandomGame) {
|
if (mRandomGame) {
|
||||||
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
mThumbnail.setImage(mRandomGame->getThumbnailPath());
|
||||||
mMarquee.setImage(mRandomGame->getMarqueePath());
|
mMarquee.setImage(mRandomGame->getMarqueePath());
|
||||||
|
@ -398,7 +391,6 @@ void VideoGameListView::updateInfoPanel()
|
||||||
mVideo->setImage(file->getImagePath());
|
mVideo->setImage(file->getImagePath());
|
||||||
mVideo->onHide();
|
mVideo->onHide();
|
||||||
|
|
||||||
|
|
||||||
if (!mVideo->setVideo(file->getVideoPath()))
|
if (!mVideo->setVideo(file->getVideoPath()))
|
||||||
mVideo->setDefaultVideo();
|
mVideo->setDefaultVideo();
|
||||||
}
|
}
|
||||||
|
@ -418,21 +410,21 @@ void VideoGameListView::updateInfoPanel()
|
||||||
if (mIsFiltered) {
|
if (mIsFiltered) {
|
||||||
if (mFilteredGameCountAll == mFilteredGameCount)
|
if (mFilteredGameCountAll == mFilteredGameCount)
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
std::to_string(mFilteredGameCount) + " / " +
|
std::to_string(mFilteredGameCount) + " / " +
|
||||||
std::to_string(mGameCount);
|
std::to_string(mGameCount);
|
||||||
else
|
else
|
||||||
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
gamelistInfoString += ViewController::FILTER_CHAR + " " +
|
||||||
std::to_string(mFilteredGameCount) + " + " +
|
std::to_string(mFilteredGameCount) + " + " +
|
||||||
std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " +
|
std::to_string(mFilteredGameCountAll - mFilteredGameCount) +
|
||||||
std::to_string(mGameCount);
|
" / " + std::to_string(mGameCount);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gamelistInfoString += ViewController::CONTROLLER_CHAR + " " +
|
gamelistInfoString +=
|
||||||
std::to_string(mGameCount);
|
ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount);
|
||||||
if (!(file->getSystem()->isCollection() &&
|
if (!(file->getSystem()->isCollection() &&
|
||||||
file->getSystem()->getFullName() == "favorites"))
|
file->getSystem()->getFullName() == "favorites"))
|
||||||
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " "
|
gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " +
|
||||||
+ std::to_string(mFavoritesGameCount);
|
std::to_string(mFavoritesGameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
||||||
|
@ -442,9 +434,9 @@ void VideoGameListView::updateInfoPanel()
|
||||||
|
|
||||||
// Fade in the game image.
|
// Fade in the game image.
|
||||||
auto func = [this](float t) {
|
auto func = [this](float t) {
|
||||||
mVideo->setOpacity(static_cast<unsigned char>(Math::lerp(
|
mVideo->setOpacity(static_cast<unsigned char>(
|
||||||
static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
Math::lerp(static_cast<float>(FADE_IN_START_OPACITY), 1.0f, t) * 255));
|
||||||
};
|
};
|
||||||
mVideo->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
mVideo->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
||||||
|
|
||||||
mDescription.setText(file->metadata.get("desc"));
|
mDescription.setText(file->metadata.get("desc"));
|
||||||
|
@ -498,10 +490,7 @@ void VideoGameListView::updateInfoPanel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoGameListView::launch(FileData* game)
|
void VideoGameListView::launch(FileData* game) { ViewController::get()->triggerGameLaunch(game); }
|
||||||
{
|
|
||||||
ViewController::get()->triggerGameLaunch(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<TextComponent*> VideoGameListView::getMDLabels()
|
std::vector<TextComponent*> VideoGameListView::getMDLabels()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue