mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-18 07:05:39 +00:00
Monster commit. Rewrote gamelist sorting logic and made per-gamelist sort settings session-permanent. Cleaned up a lot of code and started to reformat for 100 characters line length.
This commit is contained in:
parent
f806285e06
commit
f2f7d34bb6
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,22 @@
|
||||||
|
//
|
||||||
|
// CollectionSystemManager.h
|
||||||
|
//
|
||||||
|
// Manages collections of the following two types:
|
||||||
|
// 1) Automatically populated (All games, Favorites and Recent/Last Played)
|
||||||
|
// 2) Custom/user-created (could be any number of these)
|
||||||
|
//
|
||||||
|
// The automatic collections are basically virtual systems that have no
|
||||||
|
// gamelist.xml files and that only exist in memory during the program session.
|
||||||
|
// SystemData sets up the basic data structures and CollectionSystemManager
|
||||||
|
// populates and manages the collections.
|
||||||
|
//
|
||||||
|
// The custom collections have simple data files which are just lists of ROM files.
|
||||||
|
//
|
||||||
|
// In addition to this, CollectionSystemManager also handles some logic for
|
||||||
|
// normal systems such as adding and removing favorite games, including triggering
|
||||||
|
// the required re-sort and refresh of the gamelists.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_COLLECTION_SYSTEM_MANAGER_H
|
#ifndef ES_APP_COLLECTION_SYSTEM_MANAGER_H
|
||||||
#define ES_APP_COLLECTION_SYSTEM_MANAGER_H
|
#define ES_APP_COLLECTION_SYSTEM_MANAGER_H
|
||||||
|
@ -11,26 +30,22 @@ class SystemData;
|
||||||
class Window;
|
class Window;
|
||||||
struct SystemEnvironmentData;
|
struct SystemEnvironmentData;
|
||||||
|
|
||||||
enum CollectionSystemType
|
enum CollectionSystemType {
|
||||||
{
|
|
||||||
AUTO_ALL_GAMES,
|
AUTO_ALL_GAMES,
|
||||||
AUTO_LAST_PLAYED,
|
AUTO_LAST_PLAYED,
|
||||||
AUTO_FAVORITES,
|
AUTO_FAVORITES,
|
||||||
CUSTOM_COLLECTION
|
CUSTOM_COLLECTION
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CollectionSystemDecl
|
struct CollectionSystemDecl {
|
||||||
{
|
CollectionSystemType type;
|
||||||
CollectionSystemType type; // type of system
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string longName;
|
std::string longName;
|
||||||
std::string defaultSort;
|
|
||||||
std::string themeFolder;
|
std::string themeFolder;
|
||||||
bool isCustom;
|
bool isCustom;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CollectionSystemData
|
struct CollectionSystemData {
|
||||||
{
|
|
||||||
SystemData* system;
|
SystemData* system;
|
||||||
CollectionSystemDecl decl;
|
CollectionSystemDecl decl;
|
||||||
bool isEnabled;
|
bool isEnabled;
|
||||||
|
@ -57,8 +72,10 @@ public:
|
||||||
void updateCollectionSystem(FileData* file, CollectionSystemData sysData);
|
void updateCollectionSystem(FileData* file, CollectionSystemData sysData);
|
||||||
void deleteCollectionFiles(FileData* file);
|
void deleteCollectionFiles(FileData* file);
|
||||||
|
|
||||||
inline std::map<std::string, CollectionSystemData> getAutoCollectionSystems() { return mAutoCollectionSystemsData; };
|
inline std::map<std::string, CollectionSystemData> getAutoCollectionSystems()
|
||||||
inline std::map<std::string, CollectionSystemData> getCustomCollectionSystems() { return mCustomCollectionSystemsData; };
|
{ return mAutoCollectionSystemsData; };
|
||||||
|
inline std::map<std::string, CollectionSystemData> getCustomCollectionSystems()
|
||||||
|
{ return mCustomCollectionSystemsData; };
|
||||||
inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; };
|
inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; };
|
||||||
std::vector<std::string> getUnusedSystemsFromTheme();
|
std::vector<std::string> getUnusedSystemsFromTheme();
|
||||||
SystemData* addNewCustomCollection(std::string name);
|
SystemData* addNewCustomCollection(std::string name);
|
||||||
|
@ -76,6 +93,8 @@ public:
|
||||||
SystemData* getSystemToView(SystemData* sys);
|
SystemData* getSystemToView(SystemData* sys);
|
||||||
void updateCollectionFolderMetadata(SystemData* sys);
|
void updateCollectionFolderMetadata(SystemData* sys);
|
||||||
|
|
||||||
|
bool getIsCustomCollection(SystemData* system);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CollectionSystemManager* sInstance;
|
static CollectionSystemManager* sInstance;
|
||||||
SystemEnvironmentData* mCollectionEnvData;
|
SystemEnvironmentData* mCollectionEnvData;
|
||||||
|
@ -90,12 +109,14 @@ private:
|
||||||
void initAutoCollectionSystems();
|
void initAutoCollectionSystems();
|
||||||
void initCustomCollectionSystems();
|
void initCustomCollectionSystems();
|
||||||
SystemData* getAllGamesCollection();
|
SystemData* getAllGamesCollection();
|
||||||
SystemData* createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, bool index = true);
|
SystemData* createNewCollectionEntry(std::string name,
|
||||||
|
CollectionSystemDecl sysDecl, bool index = true);
|
||||||
void populateAutoCollection(CollectionSystemData* sysData);
|
void populateAutoCollection(CollectionSystemData* sysData);
|
||||||
void populateCustomCollection(CollectionSystemData* sysData);
|
void populateCustomCollection(CollectionSystemData* sysData);
|
||||||
|
|
||||||
void removeCollectionsFromDisplayedSystems();
|
void removeCollectionsFromDisplayedSystems();
|
||||||
void addEnabledCollectionsToDisplayedSystems(std::map<std::string, CollectionSystemData>* colSystemData);
|
void addEnabledCollectionsToDisplayedSystems(std::map<std::string,
|
||||||
|
CollectionSystemData>* colSystemData);
|
||||||
|
|
||||||
std::vector<std::string> getSystemsFromConfig();
|
std::vector<std::string> getSystemsFromConfig();
|
||||||
std::vector<std::string> getSystemsFromTheme();
|
std::vector<std::string> getSystemsFromTheme();
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
//
|
||||||
|
// FileData.cpp
|
||||||
|
//
|
||||||
|
// Provides game file data structures and functions to access and sort this information.
|
||||||
|
// Also provides functions to look up paths to media files and for launching games
|
||||||
|
// (launching initiated by the ViewController).
|
||||||
|
//
|
||||||
|
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
#include "utils/FileSystemUtil.h"
|
||||||
|
@ -16,11 +24,22 @@
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
FileData::FileData(FileType type, const std::string& path, SystemEnvironmentData* envData, SystemData* system)
|
FileData::FileData(
|
||||||
: mType(type), mPath(path), mSystem(system), mEnvData(envData), mSourceFileData(NULL), mParent(NULL), metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA) // metadata is REALLY set in the constructor!
|
FileType type,
|
||||||
|
const std::string& path,
|
||||||
|
SystemEnvironmentData* envData,
|
||||||
|
SystemData* system)
|
||||||
|
: mType(type),
|
||||||
|
mPath(path),
|
||||||
|
mSystem(system),
|
||||||
|
mEnvData(envData),
|
||||||
|
mSourceFileData(nullptr),
|
||||||
|
mParent(nullptr),
|
||||||
|
// Metadata is REALLY set in the constructor!
|
||||||
|
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())
|
||||||
metadata.set("name", getDisplayName());
|
metadata.set("name", getDisplayName());
|
||||||
mSystemName = system->getName();
|
mSystemName = system->getName();
|
||||||
metadata.resetChangedFlag();
|
metadata.resetChangedFlag();
|
||||||
|
@ -28,10 +47,10 @@ FileData::FileData(FileType type, const std::string& path, SystemEnvironmentData
|
||||||
|
|
||||||
FileData::~FileData()
|
FileData::~FileData()
|
||||||
{
|
{
|
||||||
if(mParent)
|
if (mParent)
|
||||||
mParent->removeChild(this);
|
mParent->removeChild(this);
|
||||||
|
|
||||||
if(mType == GAME)
|
if (mType == GAME)
|
||||||
mSystem->getIndex()->removeFromIndex(this);
|
mSystem->getIndex()->removeFromIndex(this);
|
||||||
|
|
||||||
mChildren.clear();
|
mChildren.clear();
|
||||||
|
@ -40,9 +59,6 @@ FileData::~FileData()
|
||||||
std::string FileData::getDisplayName() const
|
std::string FileData::getDisplayName() const
|
||||||
{
|
{
|
||||||
std::string stem = Utils::FileSystem::getStem(mPath);
|
std::string stem = Utils::FileSystem::getStem(mPath);
|
||||||
// if(mSystem && mSystem->hasPlatformId(PlatformIds::ARCADE) || mSystem->hasPlatformId(PlatformIds::NEOGEO))
|
|
||||||
// stem = MameNames::getInstance()->getRealName(stem);
|
|
||||||
|
|
||||||
return stem;
|
return stem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,26 +93,20 @@ const std::string FileData::getMediaDirectory() const
|
||||||
std::string mediaDirSetting = Settings::getInstance()->getString("MediaDirectory");
|
std::string mediaDirSetting = Settings::getInstance()->getString("MediaDirectory");
|
||||||
std::string mediaDirPath = "";
|
std::string mediaDirPath = "";
|
||||||
|
|
||||||
if(mediaDirSetting == "")
|
if (mediaDirSetting == "") {
|
||||||
{
|
|
||||||
mediaDirPath = Utils::FileSystem::getHomePath() + "/.emulationstation/downloaded_media/";
|
mediaDirPath = Utils::FileSystem::getHomePath() + "/.emulationstation/downloaded_media/";
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
mediaDirPath = mediaDirSetting;
|
mediaDirPath = mediaDirSetting;
|
||||||
|
|
||||||
// Expand home symbol if the path starts with ~
|
// Expand home symbol if the path starts with ~
|
||||||
if(mediaDirPath[0] == '~')
|
if (mediaDirPath[0] == '~') {
|
||||||
{
|
|
||||||
mediaDirPath.erase(0, 1);
|
mediaDirPath.erase(0, 1);
|
||||||
mediaDirPath.insert(0, Utils::FileSystem::getHomePath());
|
mediaDirPath.insert(0, Utils::FileSystem::getHomePath());
|
||||||
}
|
}
|
||||||
|
if (mediaDirPath.back() != '/')
|
||||||
if(mediaDirPath.back() != '/')
|
|
||||||
{
|
|
||||||
mediaDirPath = mediaDirPath + "/";
|
mediaDirPath = mediaDirPath + "/";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return mediaDirPath;
|
return mediaDirPath;
|
||||||
}
|
}
|
||||||
|
@ -106,21 +116,21 @@ const std::string FileData::getThumbnailPath() const
|
||||||
const char* extList[2] = { ".png", ".jpg" };
|
const char* extList[2] = { ".png", ".jpg" };
|
||||||
std::string tempPath = getMediaDirectory() + mSystemName + "/thumbnails/" + getDisplayName();
|
std::string tempPath = getMediaDirectory() + mSystemName + "/thumbnails/" + getDisplayName();
|
||||||
|
|
||||||
// Look for media in the media directory
|
// Look for media in the media directory.
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
std::string mediaPath = tempPath + extList[i];
|
std::string mediaPath = tempPath + extList[i];
|
||||||
if(Utils::FileSystem::exists(mediaPath))
|
if (Utils::FileSystem::exists(mediaPath))
|
||||||
return mediaPath;
|
return mediaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No media found in the media directory, so look for local art as well (if configured to do so)
|
// No media found in the media directory, so look
|
||||||
if(Settings::getInstance()->getBool("LocalArt"))
|
// for local art as well (if configured to do so).
|
||||||
|
if (Settings::getInstance()->getBool("LocalArt"))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
std::string localMediaPath = mEnvData->mStartPath + "/images/" +
|
||||||
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() + "-thumbnail" + extList[i];
|
getDisplayName() + "-thumbnail" + extList[i];
|
||||||
if(Utils::FileSystem::exists(localMediaPath))
|
if (Utils::FileSystem::exists(localMediaPath))
|
||||||
return localMediaPath;
|
return localMediaPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,21 +143,21 @@ const std::string FileData::getVideoPath() const
|
||||||
const char* extList[5] = { ".avi", ".mkv", ".mov", ".mp4", ".wmv" };
|
const char* extList[5] = { ".avi", ".mkv", ".mov", ".mp4", ".wmv" };
|
||||||
std::string tempPath = getMediaDirectory() + mSystemName + "/videos/" + getDisplayName();
|
std::string tempPath = getMediaDirectory() + mSystemName + "/videos/" + getDisplayName();
|
||||||
|
|
||||||
// Look for media in the media directory
|
// Look for media in the media directory.
|
||||||
for(int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++) {
|
||||||
{
|
|
||||||
std::string mediaPath = tempPath + extList[i];
|
std::string mediaPath = tempPath + extList[i];
|
||||||
if(Utils::FileSystem::exists(mediaPath))
|
if (Utils::FileSystem::exists(mediaPath))
|
||||||
return mediaPath;
|
return mediaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No media found in the media directory, so look for local art as well (if configured to do so)
|
// No media found in the media directory, so look
|
||||||
if(Settings::getInstance()->getBool("LocalArt"))
|
// for local art as well (if configured to do so).
|
||||||
|
if (Settings::getInstance()->getBool("LocalArt"))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++) {
|
||||||
{
|
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() +
|
||||||
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() + "-video" + extList[i];
|
"-video" + extList[i];
|
||||||
if(Utils::FileSystem::exists(localMediaPath))
|
if (Utils::FileSystem::exists(localMediaPath))
|
||||||
return localMediaPath;
|
return localMediaPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,21 +170,21 @@ const std::string FileData::getMarqueePath() const
|
||||||
const char* extList[2] = { ".png", ".jpg" };
|
const char* extList[2] = { ".png", ".jpg" };
|
||||||
std::string tempPath = getMediaDirectory() + mSystemName + "/marquees/" + getDisplayName();
|
std::string tempPath = getMediaDirectory() + mSystemName + "/marquees/" + getDisplayName();
|
||||||
|
|
||||||
// Look for media in the media directory
|
// Look for media in the media directory.
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
std::string mediaPath = tempPath + extList[i];
|
std::string mediaPath = tempPath + extList[i];
|
||||||
if(Utils::FileSystem::exists(mediaPath))
|
if (Utils::FileSystem::exists(mediaPath))
|
||||||
return mediaPath;
|
return mediaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No media found in the media directory, so look for local art as well (if configured to do so)
|
// No media found in the media directory, so look
|
||||||
if(Settings::getInstance()->getBool("LocalArt"))
|
// for local art as well (if configured to do so).
|
||||||
|
if (Settings::getInstance()->getBool("LocalArt"))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() +
|
||||||
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() + "-marquee" + extList[i];
|
"-marquee" + extList[i];
|
||||||
if(Utils::FileSystem::exists(localMediaPath))
|
if (Utils::FileSystem::exists(localMediaPath))
|
||||||
return localMediaPath;
|
return localMediaPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,32 +196,30 @@ const std::string FileData::getImagePath() const
|
||||||
{
|
{
|
||||||
const char* extList[2] = { ".png", ".jpg" };
|
const char* extList[2] = { ".png", ".jpg" };
|
||||||
|
|
||||||
// Look for mix image (a combination of screenshot, 3D box and marquee) in the media directory
|
// Look for mix image (a combination of screenshot, 3D box and marquee) in the media directory.
|
||||||
std::string tempPath = getMediaDirectory() + mSystemName + "/miximages/" + getDisplayName();
|
std::string tempPath = getMediaDirectory() + mSystemName + "/miximages/" + getDisplayName();
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
std::string mediaPath = tempPath + extList[i];
|
std::string mediaPath = tempPath + extList[i];
|
||||||
if(Utils::FileSystem::exists(mediaPath))
|
if (Utils::FileSystem::exists(mediaPath))
|
||||||
return mediaPath;
|
return mediaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no mix image exists, try normal screenshot
|
// If no mix image exists, try normal screenshot.
|
||||||
tempPath = getMediaDirectory() + mSystemName + "/screenshots/" + getDisplayName();
|
tempPath = getMediaDirectory() + mSystemName + "/screenshots/" + getDisplayName();
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
std::string mediaPath = tempPath + extList[i];
|
std::string mediaPath = tempPath + extList[i];
|
||||||
if(Utils::FileSystem::exists(mediaPath))
|
if (Utils::FileSystem::exists(mediaPath))
|
||||||
return mediaPath;
|
return mediaPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No media found in the media directory, so look for local art as well (if configured to do so)
|
// No media found in the media directory, so look
|
||||||
if(Settings::getInstance()->getBool("LocalArt"))
|
// for local art as well (if configured to do so).
|
||||||
{
|
if (Settings::getInstance()->getBool("LocalArt")) {
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
std::string localMediaPath = mEnvData->mStartPath + "/images/" +
|
||||||
std::string localMediaPath = mEnvData->mStartPath + "/images/" + getDisplayName() + "-image" + extList[i];
|
getDisplayName() + "-image" + extList[i];
|
||||||
if(Utils::FileSystem::exists(localMediaPath))
|
if (Utils::FileSystem::exists(localMediaPath))
|
||||||
return localMediaPath;
|
return localMediaPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,17 +233,14 @@ const std::vector<FileData*>& FileData::getChildrenListToDisplay()
|
||||||
FileFilterIndex* idx = CollectionSystemManager::get()->getSystemToView(mSystem)->getIndex();
|
FileFilterIndex* idx = CollectionSystemManager::get()->getSystemToView(mSystem)->getIndex();
|
||||||
if (idx->isFiltered()) {
|
if (idx->isFiltered()) {
|
||||||
mFilteredChildren.clear();
|
mFilteredChildren.clear();
|
||||||
for(auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) {
|
||||||
{
|
|
||||||
if (idx->showFile((*it))) {
|
if (idx->showFile((*it))) {
|
||||||
mFilteredChildren.push_back(*it);
|
mFilteredChildren.push_back(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mFilteredChildren;
|
return mFilteredChildren;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
return mChildren;
|
return mChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,16 +250,12 @@ std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask, bool d
|
||||||
std::vector<FileData*> out;
|
std::vector<FileData*> out;
|
||||||
FileFilterIndex* idx = mSystem->getIndex();
|
FileFilterIndex* idx = mSystem->getIndex();
|
||||||
|
|
||||||
for(auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) {
|
||||||
{
|
if ((*it)->getType() & typeMask) {
|
||||||
if((*it)->getType() & typeMask)
|
|
||||||
{
|
|
||||||
if (!displayedOnly || !idx->isFiltered() || idx->showFile(*it))
|
if (!displayedOnly || !idx->isFiltered() || idx->showFile(*it))
|
||||||
out.push_back(*it);
|
out.push_back(*it);
|
||||||
}
|
}
|
||||||
|
if ((*it)->getChildren().size() > 0) {
|
||||||
if((*it)->getChildren().size() > 0)
|
|
||||||
{
|
|
||||||
std::vector<FileData*> subchildren = (*it)->getFilesRecursive(typeMask, displayedOnly);
|
std::vector<FileData*> subchildren = (*it)->getFilesRecursive(typeMask, displayedOnly);
|
||||||
out.insert(out.cend(), subchildren.cbegin(), subchildren.cend());
|
out.insert(out.cend(), subchildren.cbegin(), subchildren.cend());
|
||||||
}
|
}
|
||||||
|
@ -271,9 +272,10 @@ const bool FileData::isArcadeAsset()
|
||||||
{
|
{
|
||||||
const std::string stem = Utils::FileSystem::getStem(mPath);
|
const std::string stem = Utils::FileSystem::getStem(mPath);
|
||||||
return (
|
return (
|
||||||
(mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) || mSystem->hasPlatformId(PlatformIds::NEOGEO)))
|
(mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
|
||||||
&&
|
mSystem->hasPlatformId(PlatformIds::NEOGEO))) &&
|
||||||
(MameNames::getInstance()->isBios(stem) || MameNames::getInstance()->isDevice(stem))
|
(MameNames::getInstance()->isBios(stem) ||
|
||||||
|
MameNames::getInstance()->isDevice(stem))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +290,7 @@ void FileData::addChild(FileData* file)
|
||||||
assert(file->getParent() == NULL);
|
assert(file->getParent() == NULL);
|
||||||
|
|
||||||
const std::string key = file->getKey();
|
const std::string key = file->getKey();
|
||||||
if (mChildrenByFilename.find(key) == mChildrenByFilename.cend())
|
if (mChildrenByFilename.find(key) == mChildrenByFilename.cend()) {
|
||||||
{
|
|
||||||
mChildrenByFilename[key] = file;
|
mChildrenByFilename[key] = file;
|
||||||
mChildren.push_back(file);
|
mChildren.push_back(file);
|
||||||
file->mParent = this;
|
file->mParent = this;
|
||||||
|
@ -301,10 +302,8 @@ void FileData::removeChild(FileData* file)
|
||||||
assert(mType == FOLDER);
|
assert(mType == FOLDER);
|
||||||
assert(file->getParent() == this);
|
assert(file->getParent() == this);
|
||||||
mChildrenByFilename.erase(file->getKey());
|
mChildrenByFilename.erase(file->getKey());
|
||||||
for(auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) {
|
||||||
{
|
if (*it == file) {
|
||||||
if(*it == file)
|
|
||||||
{
|
|
||||||
file->mParent = NULL;
|
file->mParent = NULL;
|
||||||
mChildren.erase(it);
|
mChildren.erase(it);
|
||||||
return;
|
return;
|
||||||
|
@ -320,18 +319,58 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending)
|
||||||
{
|
{
|
||||||
std::stable_sort(mChildren.begin(), mChildren.end(), comparator);
|
std::stable_sort(mChildren.begin(), mChildren.end(), comparator);
|
||||||
|
|
||||||
for(auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++) {
|
||||||
{
|
if ((*it)->getChildren().size() > 0)
|
||||||
if((*it)->getChildren().size() > 0)
|
|
||||||
(*it)->sort(comparator, ascending);
|
(*it)->sort(comparator, ascending);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ascending)
|
if (!ascending)
|
||||||
std::reverse(mChildren.begin(), mChildren.end());
|
std::reverse(mChildren.begin(), mChildren.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileData::sort(const SortType& type)
|
void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending)
|
||||||
{
|
{
|
||||||
|
std::vector<FileData*> mChildrenFavorites;
|
||||||
|
std::vector<FileData*> mChildrenOthers;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mChildren.size(); i++) {
|
||||||
|
if (mChildren[i]->getFavorite())
|
||||||
|
mChildrenFavorites.push_back(mChildren[i]);
|
||||||
|
else
|
||||||
|
mChildrenOthers.push_back(mChildren[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort favorite games and the other games separately.
|
||||||
|
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(), comparator);
|
||||||
|
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
|
||||||
|
|
||||||
|
for (auto it = mChildrenFavorites.cbegin(); it != mChildrenFavorites.cend(); it++) {
|
||||||
|
if ((*it)->getChildren().size() > 0)
|
||||||
|
(*it)->sortFavoritesOnTop(comparator, ascending);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = mChildrenOthers.cbegin(); it != mChildrenOthers.cend(); it++) {
|
||||||
|
if ((*it)->getChildren().size() > 0)
|
||||||
|
(*it)->sortFavoritesOnTop(comparator, ascending);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ascending) {
|
||||||
|
std::reverse(mChildrenFavorites.begin(), mChildrenFavorites.end());
|
||||||
|
std::reverse(mChildrenOthers.begin(), mChildrenOthers.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine the individually sorted favorite games and other games vectors.
|
||||||
|
mChildren.erase(mChildren.begin(), mChildren.end());
|
||||||
|
mChildren.reserve(mChildrenFavorites.size() + mChildrenOthers.size());
|
||||||
|
mChildren.insert(mChildren.end(), mChildrenFavorites.begin(), mChildrenFavorites.end());
|
||||||
|
mChildren.insert(mChildren.end(), mChildrenOthers.begin(), mChildrenOthers.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileData::sort(const SortType& type, bool mFavoritesOnTop)
|
||||||
|
{
|
||||||
|
if (mFavoritesOnTop)
|
||||||
|
sortFavoritesOnTop(*type.comparisonFunction, type.ascending);
|
||||||
|
else
|
||||||
sort(*type.comparisonFunction, type.ascending);
|
sort(*type.comparisonFunction, type.ascending);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,15 +385,13 @@ void FileData::launchGame(Window* window)
|
||||||
|
|
||||||
std::string command = "";
|
std::string command = "";
|
||||||
|
|
||||||
// Check if there is a launch string override for the game and the corresponding option has been set
|
// Check if there is a launch string override for the game
|
||||||
if(Settings::getInstance()->getBool("LaunchstringOverride") && !metadata.get("launchstring").empty())
|
// and the corresponding option to use it has been set.
|
||||||
{
|
if (Settings::getInstance()->getBool("LaunchstringOverride") &&
|
||||||
|
!metadata.get("launchstring").empty())
|
||||||
command = metadata.get("launchstring");
|
command = metadata.get("launchstring");
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
command = mEnvData->mLaunchCommand;
|
command = mEnvData->mLaunchCommand;
|
||||||
}
|
|
||||||
|
|
||||||
const std::string rom = Utils::FileSystem::getEscapedPath(getPath());
|
const std::string rom = Utils::FileSystem::getEscapedPath(getPath());
|
||||||
const std::string basename = Utils::FileSystem::getStem(getPath());
|
const std::string basename = Utils::FileSystem::getStem(getPath());
|
||||||
|
@ -369,25 +406,23 @@ void FileData::launchGame(Window* window)
|
||||||
LOG(LogInfo) << " " << command;
|
LOG(LogInfo) << " " << command;
|
||||||
int exitCode = runSystemCommand(command);
|
int exitCode = runSystemCommand(command);
|
||||||
|
|
||||||
if(exitCode != 0)
|
if (exitCode != 0)
|
||||||
{
|
|
||||||
LOG(LogWarning) << "...launch terminated with nonzero exit code " << exitCode << "!";
|
LOG(LogWarning) << "...launch terminated with nonzero exit code " << exitCode << "!";
|
||||||
}
|
|
||||||
|
|
||||||
Scripting::fireEvent("game-end");
|
Scripting::fireEvent("game-end");
|
||||||
|
|
||||||
// window->init();
|
// window->init();
|
||||||
|
|
||||||
VolumeControl::getInstance()->init();
|
VolumeControl::getInstance()->init();
|
||||||
window->normalizeNextUpdate();
|
window->normalizeNextUpdate();
|
||||||
|
|
||||||
//update number of times the game has been launched
|
// Update number of times the game has been launched.
|
||||||
|
|
||||||
FileData* gameToUpdate = getSourceFileData();
|
FileData* gameToUpdate = getSourceFileData();
|
||||||
|
|
||||||
int timesPlayed = gameToUpdate->metadata.getInt("playcount") + 1;
|
int timesPlayed = gameToUpdate->metadata.getInt("playcount") + 1;
|
||||||
gameToUpdate->metadata.set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
|
gameToUpdate->metadata.set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
|
||||||
|
|
||||||
//update last played time
|
// Update last played time.
|
||||||
gameToUpdate->metadata.set("lastplayed", Utils::Time::DateTime(Utils::Time::now()));
|
gameToUpdate->metadata.set("lastplayed", Utils::Time::DateTime(Utils::Time::now()));
|
||||||
CollectionSystemManager::get()->refreshCollectionSystems(gameToUpdate);
|
CollectionSystemManager::get()->refreshCollectionSystems(gameToUpdate);
|
||||||
|
|
||||||
|
@ -395,9 +430,10 @@ void FileData::launchGame(Window* window)
|
||||||
}
|
}
|
||||||
|
|
||||||
CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
||||||
: FileData(file->getSourceFileData()->getType(), file->getSourceFileData()->getPath(), file->getSourceFileData()->getSystemEnvData(), system)
|
: FileData(file->getSourceFileData()->getType(), file->getSourceFileData()->getPath(),
|
||||||
|
file->getSourceFileData()->getSystemEnvData(), system)
|
||||||
{
|
{
|
||||||
// we use this constructor to create a clone of the filedata, and change its system
|
// We use this constructor to create a clone of the filedata, and change its system.
|
||||||
mSourceFileData = file->getSourceFileData();
|
mSourceFileData = file->getSourceFileData();
|
||||||
refreshMetadata();
|
refreshMetadata();
|
||||||
mParent = NULL;
|
mParent = NULL;
|
||||||
|
@ -407,8 +443,8 @@ CollectionFileData::CollectionFileData(FileData* file, SystemData* system)
|
||||||
|
|
||||||
CollectionFileData::~CollectionFileData()
|
CollectionFileData::~CollectionFileData()
|
||||||
{
|
{
|
||||||
// need to remove collection file data at the collection object destructor
|
// Need to remove collection file data at the collection object destructor.
|
||||||
if(mParent)
|
if (mParent)
|
||||||
mParent->removeChild(this);
|
mParent->removeChild(this);
|
||||||
mParent = NULL;
|
mParent = NULL;
|
||||||
}
|
}
|
||||||
|
@ -431,28 +467,28 @@ void CollectionFileData::refreshMetadata()
|
||||||
const std::string& CollectionFileData::getName()
|
const std::string& CollectionFileData::getName()
|
||||||
{
|
{
|
||||||
if (mDirty) {
|
if (mDirty) {
|
||||||
mCollectionFileName = Utils::String::removeParenthesis(mSourceFileData->metadata.get("name"));
|
mCollectionFileName =
|
||||||
mCollectionFileName += " [" + Utils::String::toUpper(mSourceFileData->getSystem()->getName()) + "]";
|
Utils::String::removeParenthesis(mSourceFileData->metadata.get("name"));
|
||||||
|
mCollectionFileName +=
|
||||||
|
" [" + Utils::String::toUpper(mSourceFileData->getSystem()->getName()) + "]";
|
||||||
mDirty = false;
|
mDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::getInstance()->getBool("CollectionShowSystemInfo"))
|
if (Settings::getInstance()->getBool("CollectionShowSystemInfo"))
|
||||||
return mCollectionFileName;
|
return mCollectionFileName;
|
||||||
|
|
||||||
return mSourceFileData->metadata.get("name");
|
return mSourceFileData->metadata.get("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns Sort Type based on a string description
|
// Return sort type based on a string description.
|
||||||
FileData::SortType getSortTypeFromString(std::string desc) {
|
FileData::SortType getSortTypeFromString(std::string desc) {
|
||||||
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
std::vector<FileData::SortType> SortTypes = FileSorts::SortTypes;
|
||||||
// find it
|
// Find it
|
||||||
for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++)
|
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||||
{
|
|
||||||
const FileData::SortType& sort = FileSorts::SortTypes.at(i);
|
const FileData::SortType& sort = FileSorts::SortTypes.at(i);
|
||||||
if(sort.description == desc)
|
if (sort.description == desc)
|
||||||
{
|
|
||||||
return sort;
|
return sort;
|
||||||
}
|
}
|
||||||
}
|
// If no type found then default to "filename, ascending".
|
||||||
// if not found default to name, ascending
|
|
||||||
return FileSorts::SortTypes.at(0);
|
return FileSorts::SortTypes.at(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
//
|
||||||
|
// FileData.h
|
||||||
|
//
|
||||||
|
// Provides game file data structures and functions to access and sort this information.
|
||||||
|
// Also provides functions to look up paths to media files and for launching games
|
||||||
|
// (launching initiated by the ViewController).
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_FILE_DATA_H
|
#ifndef ES_APP_FILE_DATA_H
|
||||||
#define ES_APP_FILE_DATA_H
|
#define ES_APP_FILE_DATA_H
|
||||||
|
@ -10,15 +18,13 @@ class SystemData;
|
||||||
class Window;
|
class Window;
|
||||||
struct SystemEnvironmentData;
|
struct SystemEnvironmentData;
|
||||||
|
|
||||||
enum FileType
|
enum FileType {
|
||||||
{
|
|
||||||
GAME = 1, // Cannot have children.
|
GAME = 1, // Cannot have children.
|
||||||
FOLDER = 2,
|
FOLDER = 2,
|
||||||
PLACEHOLDER = 3
|
PLACEHOLDER = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FileChangeType
|
enum FileChangeType {
|
||||||
{
|
|
||||||
FILE_ADDED,
|
FILE_ADDED,
|
||||||
FILE_METADATA_CHANGED,
|
FILE_METADATA_CHANGED,
|
||||||
FILE_REMOVED,
|
FILE_REMOVED,
|
||||||
|
@ -33,7 +39,11 @@ FileType stringToFileType(const char* str);
|
||||||
class FileData
|
class FileData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileData(FileType type, const std::string& path, SystemEnvironmentData* envData, SystemData* system);
|
FileData(FileType type,
|
||||||
|
const std::string& path,
|
||||||
|
SystemEnvironmentData* envData,
|
||||||
|
SystemData* system);
|
||||||
|
|
||||||
virtual ~FileData();
|
virtual ~FileData();
|
||||||
|
|
||||||
virtual const std::string& getName();
|
virtual const std::string& getName();
|
||||||
|
@ -42,7 +52,8 @@ public:
|
||||||
inline FileType getType() const { return mType; }
|
inline FileType getType() const { return mType; }
|
||||||
inline const std::string& getPath() const { return mPath; }
|
inline const std::string& getPath() const { return mPath; }
|
||||||
inline FileData* getParent() const { return mParent; }
|
inline FileData* getParent() const { return mParent; }
|
||||||
inline const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const { return mChildrenByFilename; }
|
inline const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const
|
||||||
|
{ return mChildrenByFilename; }
|
||||||
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
|
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
|
||||||
inline SystemData* getSystem() const { return mSystem; }
|
inline SystemData* getSystem() const { return mSystem; }
|
||||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||||
|
@ -53,7 +64,8 @@ public:
|
||||||
virtual const std::string getImagePath() const;
|
virtual const std::string getImagePath() const;
|
||||||
|
|
||||||
const std::vector<FileData*>& getChildrenListToDisplay();
|
const std::vector<FileData*>& getChildrenListToDisplay();
|
||||||
std::vector<FileData*> getFilesRecursive(unsigned int typeMask, bool displayedOnly = false) const;
|
std::vector<FileData*> getFilesRecursive(unsigned int typeMask,
|
||||||
|
bool displayedOnly = false) 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
|
||||||
|
@ -69,33 +81,42 @@ public:
|
||||||
virtual FileData* getSourceFileData();
|
virtual FileData* getSourceFileData();
|
||||||
inline std::string getSystemName() const { return mSystemName; };
|
inline std::string getSystemName() const { return mSystemName; };
|
||||||
|
|
||||||
// Returns our best guess at the "real" name for this file (will attempt to perform MAME name translation)
|
// Returns our best guess at the "real" name for this file
|
||||||
|
// (will attempt to perform MAME name translation).
|
||||||
std::string getDisplayName() const;
|
std::string getDisplayName() const;
|
||||||
|
|
||||||
// As above, but also remove parenthesis
|
// As above, but also remove parenthesis.
|
||||||
std::string getCleanName() const;
|
std::string getCleanName() const;
|
||||||
|
|
||||||
void launchGame(Window* window);
|
void launchGame(Window* window);
|
||||||
|
|
||||||
typedef bool ComparisonFunction(const FileData* a, const FileData* b);
|
typedef bool ComparisonFunction(const FileData* a, const FileData* b);
|
||||||
struct SortType
|
struct SortType {
|
||||||
{
|
|
||||||
ComparisonFunction* comparisonFunction;
|
ComparisonFunction* comparisonFunction;
|
||||||
bool ascending;
|
bool ascending;
|
||||||
std::string description;
|
std::string description;
|
||||||
|
|
||||||
SortType(ComparisonFunction* sortFunction, bool sortAscending, const std::string & sortDescription)
|
SortType(ComparisonFunction* sortFunction,
|
||||||
: comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {}
|
bool sortAscending,
|
||||||
|
const std::string& sortDescription)
|
||||||
|
: comparisonFunction(sortFunction),
|
||||||
|
ascending(sortAscending),
|
||||||
|
description(sortDescription) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
void sort(ComparisonFunction& comparator, bool ascending = true);
|
void sort(ComparisonFunction& comparator, bool ascending = true);
|
||||||
void sort(const SortType& type);
|
void sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending = true);
|
||||||
|
void sort(const SortType& type, bool mFavoritesOnTop = false);
|
||||||
MetaDataList metadata;
|
MetaDataList metadata;
|
||||||
|
|
||||||
|
inline void setSortTypeString(std::string typestring) { mSortTypeString = typestring; }
|
||||||
|
inline std::string getSortTypeString() { return mSortTypeString; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileData* mSourceFileData;
|
FileData* mSourceFileData;
|
||||||
FileData* mParent;
|
FileData* mParent;
|
||||||
std::string mSystemName;
|
std::string mSystemName;
|
||||||
|
std::string mSortTypeString = "";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileType mType;
|
FileType mType;
|
||||||
|
@ -117,7 +138,7 @@ public:
|
||||||
FileData* getSourceFileData();
|
FileData* getSourceFileData();
|
||||||
std::string getKey();
|
std::string getKey();
|
||||||
private:
|
private:
|
||||||
// needs to be updated when metadata changes
|
// Needs to be updated when metadata changes.
|
||||||
std::string mCollectionFileName;
|
std::string mCollectionFileName;
|
||||||
bool mDirty;
|
bool mDirty;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// Gamelist.cpp
|
||||||
|
//
|
||||||
|
// Parses and updates the gamelist.xml files.
|
||||||
|
//
|
||||||
|
|
||||||
#include "Gamelist.h"
|
#include "Gamelist.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -12,24 +18,24 @@
|
||||||
|
|
||||||
FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType type)
|
FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType type)
|
||||||
{
|
{
|
||||||
// first, verify that path is within the system's root folder
|
// First, verify that path is within the system's root folder.
|
||||||
FileData* root = system->getRootFolder();
|
FileData* root = system->getRootFolder();
|
||||||
bool contains = false;
|
bool contains = false;
|
||||||
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) << "File path \"" << path << "\" is outside system path \"" <<
|
||||||
LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\"";
|
system->getStartPath() << "\"";
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::FileSystem::stringList pathList = Utils::FileSystem::getPathList(relative);
|
Utils::FileSystem::stringList pathList = Utils::FileSystem::getPathList(relative);
|
||||||
auto path_it = pathList.begin();
|
auto path_it = pathList.begin();
|
||||||
FileData* treeNode = root;
|
FileData* treeNode = root;
|
||||||
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();
|
||||||
|
@ -37,40 +43,35 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
||||||
treeNode = children.at(key);
|
treeNode = children.at(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the end
|
// This is the end
|
||||||
if(path_it == --pathList.end())
|
if (path_it == --pathList.end()) {
|
||||||
{
|
if (found)
|
||||||
if(found)
|
|
||||||
return treeNode;
|
return treeNode;
|
||||||
|
|
||||||
if(type == FOLDER)
|
if (type == FOLDER) {
|
||||||
{
|
LOG(LogWarning) << "Gamelist: folder doesn't exist, won't create";
|
||||||
LOG(LogWarning) << "gameList: folder doesn't already exist, won't create";
|
return nullptr;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* file = new FileData(type, path, system->getSystemEnvData(), system);
|
FileData* file = new FileData(type, path, system->getSystemEnvData(), system);
|
||||||
|
|
||||||
// skipping arcade assets from gamelist
|
// Skipping arcade assets from gamelist.
|
||||||
if(!file->isArcadeAsset())
|
if (!file->isArcadeAsset())
|
||||||
{
|
|
||||||
treeNode->addChild(file);
|
treeNode->addChild(file);
|
||||||
}
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found)
|
if (!found) {
|
||||||
{
|
// Don't create folders unless they're including any games.
|
||||||
// don't create folders unless it's leading up to a game
|
// If the type is FOLDER it's going to be empty, so don't bother.
|
||||||
// if type is a folder it's gonna be empty, so don't bother
|
if (type == FOLDER) {
|
||||||
if(type == FOLDER)
|
LOG(LogWarning) << "Gamelist: folder doesn't exist, won't create";
|
||||||
{
|
return nullptr;
|
||||||
LOG(LogWarning) << "gameList: folder doesn't already exist, won't create";
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create missing folder
|
// Create missing folder.
|
||||||
FileData* folder = new FileData(FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it, system->getSystemEnvData(), system);
|
FileData* folder = new FileData(FOLDER, Utils::FileSystem::getStem(treeNode->getPath())
|
||||||
|
+ "/" + *path_it, system->getSystemEnvData(), system);
|
||||||
treeNode->addChild(folder);
|
treeNode->addChild(folder);
|
||||||
treeNode = folder;
|
treeNode = folder;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +79,7 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
||||||
path_it++;
|
path_it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseGamelist(SystemData* system)
|
void parseGamelist(SystemData* system)
|
||||||
|
@ -86,7 +87,7 @@ void parseGamelist(SystemData* system)
|
||||||
bool trustGamelist = Settings::getInstance()->getBool("ParseGamelistOnly");
|
bool trustGamelist = Settings::getInstance()->getBool("ParseGamelistOnly");
|
||||||
std::string xmlpath = system->getGamelistPath(false);
|
std::string xmlpath = system->getGamelistPath(false);
|
||||||
|
|
||||||
if(!Utils::FileSystem::exists(xmlpath))
|
if (!Utils::FileSystem::exists(xmlpath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
|
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
|
||||||
|
@ -94,15 +95,14 @@ void parseGamelist(SystemData* system)
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
||||||
|
|
||||||
if(!result)
|
if (!result) {
|
||||||
{
|
LOG(LogError) << "Error parsing XML file \"" << xmlpath <<
|
||||||
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description();
|
"\"!\n " <<result.description();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pugi::xml_node root = doc.child("gameList");
|
pugi::xml_node root = doc.child("gameList");
|
||||||
if(!root)
|
if (!root) {
|
||||||
{
|
|
||||||
LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlpath << "\"!";
|
LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlpath << "\"!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,33 +111,32 @@ void parseGamelist(SystemData* system)
|
||||||
|
|
||||||
const char* tagList[2] = { "game", "folder" };
|
const char* tagList[2] = { "game", "folder" };
|
||||||
FileType typeList[2] = { GAME, FOLDER };
|
FileType typeList[2] = { GAME, FOLDER };
|
||||||
for(int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++) {
|
||||||
{
|
|
||||||
const char* tag = tagList[i];
|
const char* tag = tagList[i];
|
||||||
FileType type = typeList[i];
|
FileType type = typeList[i];
|
||||||
for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag))
|
for (pugi::xml_node fileNode = root.child(tag); fileNode; fileNode =
|
||||||
{
|
fileNode.next_sibling(tag)) {
|
||||||
const std::string path = Utils::FileSystem::resolveRelativePath(fileNode.child("path").text().get(), relativeTo, false);
|
const std::string path =
|
||||||
|
Utils::FileSystem::resolveRelativePath(fileNode.child("path").text().get(),
|
||||||
|
relativeTo, false);
|
||||||
|
|
||||||
if(!trustGamelist && !Utils::FileSystem::exists(path))
|
if (!trustGamelist && !Utils::FileSystem::exists(path)) {
|
||||||
{
|
|
||||||
LOG(LogWarning) << "File \"" << path << "\" does not exist! Ignoring.";
|
LOG(LogWarning) << "File \"" << path << "\" does not exist! Ignoring.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileData* file = findOrCreateFile(system, path, type);
|
FileData* file = findOrCreateFile(system, path, type);
|
||||||
if(!file)
|
if (!file) {
|
||||||
{
|
LOG(LogError) << "Error finding/creating FileData for \"" <<
|
||||||
LOG(LogError) << "Error finding/creating FileData for \"" << path << "\", skipping.";
|
path << "\", skipping.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(!file->isArcadeAsset())
|
else if (!file->isArcadeAsset()) {
|
||||||
{
|
|
||||||
std::string defaultName = file->metadata.get("name");
|
std::string defaultName = file->metadata.get("name");
|
||||||
file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo);
|
file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo);
|
||||||
|
|
||||||
//make sure name gets set if one didn't exist
|
// Make sure a name gets set if one doesn't exist.
|
||||||
if(file->metadata.get("name").empty())
|
if (file->metadata.get("name").empty())
|
||||||
file->metadata.set("name", defaultName);
|
file->metadata.set("name", defaultName);
|
||||||
|
|
||||||
file->metadata.resetChangedFlag();
|
file->metadata.resetChangedFlag();
|
||||||
|
@ -146,128 +145,137 @@ void parseGamelist(SystemData* system)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* tag, SystemData* system)
|
void addFileDataNode(pugi::xml_node& parent, const FileData* file,
|
||||||
|
const char* 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);
|
pugi::xml_node newNode = parent.append_child(tag);
|
||||||
|
|
||||||
//write metadata
|
// Write metadata.
|
||||||
file->metadata.appendToXML(newNode, true, system->getStartPath());
|
file->metadata.appendToXML(newNode, true, system->getStartPath());
|
||||||
|
|
||||||
if(newNode.children().begin() == newNode.child("name") //first element is name
|
// First element is "name", there's only one element and the name is the default.
|
||||||
&& ++newNode.children().begin() == newNode.children().end() //theres only one element
|
if (newNode.children().begin() == newNode.child("name") &&
|
||||||
&& newNode.child("name").text().get() == file->getDisplayName()) //the name is the default
|
++newNode.children().begin() == newNode.children().end() &&
|
||||||
{
|
newNode.child("name").text().get() == file->getDisplayName()) {
|
||||||
//if the only info is the default name, don't bother with this node
|
|
||||||
//delete it and ultimately do nothing
|
|
||||||
parent.remove_child(newNode);
|
|
||||||
}else{
|
|
||||||
//there's something useful in there so we'll keep the node, add the path
|
|
||||||
|
|
||||||
// try and make the path relative if we can so things still work if we change the rom folder location in the future
|
// If the only info is the default name, don't bother
|
||||||
newNode.prepend_child("path").text().set(Utils::FileSystem::createRelativePath(file->getPath(), system->getStartPath(), false).c_str());
|
// with this node, delete it and ultimately do nothing.
|
||||||
|
parent.remove_child(newNode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// There's something useful in there so we'll keep the node, add the path.
|
||||||
|
|
||||||
|
// Try and make the path relative if we can so things still
|
||||||
|
// work if we change the ROM folder location in the future.
|
||||||
|
newNode.prepend_child("path").text().set(Utils::FileSystem::createRelativePath(file->
|
||||||
|
getPath(), system->getStartPath(), false).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateGamelist(SystemData* system)
|
void updateGamelist(SystemData* system)
|
||||||
{
|
{
|
||||||
//We do this by reading the XML again, adding changes and then writing it back,
|
// We do this by reading the XML again, adding changes and then writing them back,
|
||||||
//because there might be information missing in our systemdata which would then miss in the new XML.
|
// because there might be information missing in our systemdata which we would otherwise
|
||||||
//We have the complete information for every game though, so we can simply remove a game
|
// miss in the new XML file. We have the complete information for every game though, so
|
||||||
//we already have in the system from the XML, and then add it back from its GameData information...
|
// we can simply remove a game we already have in the system from the XML, and then add
|
||||||
|
// it back from its GameData information...
|
||||||
if(Settings::getInstance()->getBool("IgnoreGamelist"))
|
if (Settings::getInstance()->getBool("IgnoreGamelist"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
pugi::xml_node root;
|
pugi::xml_node root;
|
||||||
std::string xmlReadPath = system->getGamelistPath(false);
|
std::string xmlReadPath = system->getGamelistPath(false);
|
||||||
|
|
||||||
if(Utils::FileSystem::exists(xmlReadPath))
|
if (Utils::FileSystem::exists(xmlReadPath)) {
|
||||||
{
|
// Parse an existing file first.
|
||||||
//parse an existing file first
|
|
||||||
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
|
pugi::xml_parse_result result = doc.load_file(xmlReadPath.c_str());
|
||||||
|
|
||||||
if(!result)
|
if (!result) {
|
||||||
{
|
LOG(LogError) << "Error parsing XML file \"" << xmlReadPath << "\"!\n " <<
|
||||||
LOG(LogError) << "Error parsing XML file \"" << xmlReadPath << "\"!\n " << result.description();
|
result.description();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
root = doc.child("gameList");
|
root = doc.child("gameList");
|
||||||
if(!root)
|
if (!root) {
|
||||||
{
|
LOG(LogError) << "Could not find <gameList> node in gamelist \"" <<
|
||||||
LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlReadPath << "\"!";
|
xmlReadPath << "\"!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}else{
|
}
|
||||||
//set up an empty gamelist to append to
|
else {
|
||||||
|
// Set up an empty gamelist to append to.
|
||||||
root = doc.append_child("gameList");
|
root = doc.append_child("gameList");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now we have all the information from the XML file, so iterate
|
||||||
//now we have all the information from the XML. now iterate through all our games and add information from there
|
// through all our games and add the information from there.
|
||||||
FileData* rootFolder = system->getRootFolder();
|
FileData* rootFolder = system->getRootFolder();
|
||||||
if (rootFolder != nullptr)
|
if (rootFolder != nullptr) {
|
||||||
{
|
|
||||||
int numUpdated = 0;
|
int numUpdated = 0;
|
||||||
|
|
||||||
//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
|
// Iterate through all files, checking if they're already in the XML file.
|
||||||
for(std::vector<FileData*>::const_iterator fit = files.cbegin(); fit != files.cend(); ++fit)
|
for (std::vector<FileData*>::const_iterator fit = files.cbegin();
|
||||||
{
|
fit != files.cend(); ++fit) {
|
||||||
const char* tag = ((*fit)->getType() == GAME) ? "game" : "folder";
|
const char* tag = ((*fit)->getType() == GAME) ? "game" : "folder";
|
||||||
|
|
||||||
// do not touch if it wasn't changed anyway
|
// Do not touch if it wasn't changed.
|
||||||
if (!(*fit)->metadata.wasChanged())
|
if (!(*fit)->metadata.wasChanged())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check if the file already exists in the XML
|
// Check if the file already exists in the XML file.
|
||||||
// if it does, remove it before adding
|
// If it does, remove the entry before adding it back.
|
||||||
for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag))
|
for (pugi::xml_node fileNode = root.child(tag); fileNode;
|
||||||
{
|
fileNode = fileNode.next_sibling(tag)) {
|
||||||
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(Utils::FileSystem::resolveRelativePath(pathNode.text().get(), system->getStartPath(), true));
|
std::string nodePath =Utils::FileSystem::getCanonicalPath(
|
||||||
|
Utils::FileSystem::resolveRelativePath(pathNode.text().get(),
|
||||||
|
system->getStartPath(), true));
|
||||||
std::string gamePath = Utils::FileSystem::getCanonicalPath((*fit)->getPath());
|
std::string gamePath = Utils::FileSystem::getCanonicalPath((*fit)->getPath());
|
||||||
if(nodePath == gamePath)
|
if (nodePath == gamePath) {
|
||||||
{
|
// Found it
|
||||||
// found it
|
|
||||||
root.remove_child(fileNode);
|
root.remove_child(fileNode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// it was either removed or never existed to begin with; either way, we can add it now
|
// It was either removed or never existed to begin with.
|
||||||
|
// Either way, we can add it now.
|
||||||
addFileDataNode(root, *fit, tag, system);
|
addFileDataNode(root, *fit, tag, system);
|
||||||
++numUpdated;
|
++numUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
//now write the file
|
// Now write the file.
|
||||||
|
|
||||||
if (numUpdated > 0) {
|
if (numUpdated > 0) {
|
||||||
const auto startTs = std::chrono::system_clock::now();
|
const auto startTs = std::chrono::system_clock::now();
|
||||||
|
|
||||||
//make sure the folders leading up to this path exist (or the write will fail)
|
// Make sure the folders leading up to this path exist (or the write will fail).
|
||||||
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(LogInfo) << "Added/Updated " << numUpdated << " entities in '" << xmlReadPath << "'";
|
LOG(LogInfo) << "Added/Updated " << numUpdated <<
|
||||||
|
" entities in '" << xmlReadPath << "'";
|
||||||
|
|
||||||
if (!doc.save_file(xmlWritePath.c_str())) {
|
if (!doc.save_file(xmlWritePath.c_str())) {
|
||||||
LOG(LogError) << "Error saving gamelist.xml to \"" << xmlWritePath << "\" (for system " << system->getName() << ")!";
|
LOG(LogError) << "Error saving gamelist.xml to \"" <<
|
||||||
|
xmlWritePath << "\" (for system " << system->getName() << ")!";
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto endTs = std::chrono::system_clock::now();
|
const auto endTs = std::chrono::system_clock::now();
|
||||||
LOG(LogInfo) << "Saved gamelist.xml for system \"" << system->getName() << "\" in " << std::chrono::duration_cast<std::chrono::milliseconds>(endTs - startTs).count() << " ms";
|
LOG(LogInfo) << "Saved gamelist.xml for system \"" << system->getName() << "\" in " <<
|
||||||
|
std::chrono::duration_cast<std::chrono::milliseconds>
|
||||||
|
(endTs - startTs).count() << " ms";
|
||||||
}
|
}
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!";
|
LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// Gamelist.h
|
||||||
|
//
|
||||||
|
// Parses and updates the gamelist.xml files.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_GAME_LIST_H
|
#ifndef ES_APP_GAME_LIST_H
|
||||||
#define ES_APP_GAME_LIST_H
|
#define ES_APP_GAME_LIST_H
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
//
|
||||||
|
// MetaData.cpp
|
||||||
|
//
|
||||||
|
// Static data for default metadata values as well as functions
|
||||||
|
// to read and write metadata from the gamelist files.
|
||||||
|
//
|
||||||
|
|
||||||
#include "MetaData.h"
|
#include "MetaData.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
#include "utils/FileSystemUtil.h"
|
||||||
|
@ -24,7 +31,8 @@ MetaDataDecl gameDecls[] = {
|
||||||
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date"}
|
{"lastplayed", MD_TIME, "0", true, "last played", "enter last played date"}
|
||||||
|
|
||||||
};
|
};
|
||||||
const std::vector<MetaDataDecl> gameMDD(gameDecls, gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0]));
|
const std::vector<MetaDataDecl> gameMDD(gameDecls, gameDecls +
|
||||||
|
sizeof(gameDecls) / sizeof(gameDecls[0]));
|
||||||
|
|
||||||
MetaDataDecl folderDecls[] = {
|
MetaDataDecl folderDecls[] = {
|
||||||
{"name", MD_STRING, "", false, "name", "enter game name"},
|
{"name", MD_STRING, "", false, "name", "enter game name"},
|
||||||
|
@ -37,12 +45,12 @@ MetaDataDecl folderDecls[] = {
|
||||||
{"genre", MD_STRING, "unknown", false, "genre", "enter game genre"},
|
{"genre", MD_STRING, "unknown", false, "genre", "enter game genre"},
|
||||||
{"players", MD_INT, "1", false, "players", "enter number of players"}
|
{"players", MD_INT, "1", false, "players", "enter number of players"}
|
||||||
};
|
};
|
||||||
const std::vector<MetaDataDecl> folderMDD(folderDecls, folderDecls + sizeof(folderDecls) / sizeof(folderDecls[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:
|
||||||
|
@ -53,36 +61,31 @@ const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
|
||||||
return gameMDD;
|
return gameMDD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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++)
|
||||||
set(iter->key, iter->defaultValue);
|
set(iter->key, iter->defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
const std::vector<MetaDataDecl>& mdd = mdl.getMDD();
|
const std::vector<MetaDataDecl>& mdd = mdl.getMDD();
|
||||||
|
|
||||||
for(auto iter = mdd.cbegin(); iter != mdd.cend(); iter++)
|
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++) {
|
||||||
{
|
|
||||||
pugi::xml_node md = node.child(iter->key.c_str());
|
pugi::xml_node md = node.child(iter->key.c_str());
|
||||||
if(md)
|
if (md) {
|
||||||
{
|
// If it's a path, resolve relative paths.
|
||||||
// if it's a path, resolve relative paths
|
|
||||||
std::string value = md.text().get();
|
std::string value = md.text().get();
|
||||||
if (iter->type == MD_PATH)
|
if (iter->type == MD_PATH)
|
||||||
{
|
|
||||||
value = Utils::FileSystem::resolveRelativePath(value, relativeTo, true);
|
value = Utils::FileSystem::resolveRelativePath(value, relativeTo, true);
|
||||||
}
|
|
||||||
mdl.set(iter->key, value);
|
mdl.set(iter->key, value);
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
mdl.set(iter->key, iter->defaultValue);
|
mdl.set(iter->key, iter->defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,21 +93,20 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node&
|
||||||
return mdl;
|
return mdl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaDataList::appendToXML(pugi::xml_node& parent, bool ignoreDefaults, const std::string& relativeTo) const
|
void MetaDataList::appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
||||||
|
const std::string& relativeTo) const
|
||||||
{
|
{
|
||||||
const std::vector<MetaDataDecl>& mdd = getMDD();
|
const std::vector<MetaDataDecl>& mdd = getMDD();
|
||||||
|
|
||||||
for(auto mddIter = mdd.cbegin(); mddIter != mdd.cend(); mddIter++)
|
for (auto mddIter = mdd.cbegin(); mddIter != mdd.cend(); mddIter++) {
|
||||||
{
|
|
||||||
auto mapIter = mMap.find(mddIter->key);
|
auto mapIter = mMap.find(mddIter->key);
|
||||||
if(mapIter != mMap.cend())
|
if (mapIter != mMap.cend()) {
|
||||||
{
|
// We have this value!
|
||||||
// we have this value!
|
// If it's just the default (and we ignore defaults), don't write it.
|
||||||
// if it's just the default (and we ignore defaults), don't write it
|
if (ignoreDefaults && mapIter->second == mddIter->defaultValue)
|
||||||
if(ignoreDefaults && mapIter->second == mddIter->defaultValue)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// try and make paths relative if we can
|
// Try and make paths relative if we can.
|
||||||
std::string value = mapIter->second;
|
std::string value = mapIter->second;
|
||||||
if (mddIter->type == MD_PATH)
|
if (mddIter->type == MD_PATH)
|
||||||
value = Utils::FileSystem::createRelativePath(value, relativeTo, true);
|
value = Utils::FileSystem::createRelativePath(value, relativeTo, true);
|
||||||
|
@ -122,7 +124,12 @@ 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.
|
||||||
|
if (mMap.count(key) > 0)
|
||||||
return mMap.at(key);
|
return mMap.at(key);
|
||||||
|
else
|
||||||
|
|
||||||
|
return mNoResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MetaDataList::getInt(const std::string& key) const
|
int MetaDataList::getInt(const std::string& key) const
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
//
|
||||||
|
// MetaData.h
|
||||||
|
//
|
||||||
|
// Static data for default metadata values as well as functions
|
||||||
|
// to read and write metadata from the gamelist files.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_META_DATA_H
|
#ifndef ES_APP_META_DATA_H
|
||||||
#define ES_APP_META_DATA_H
|
#define ES_APP_META_DATA_H
|
||||||
|
@ -7,35 +14,35 @@
|
||||||
|
|
||||||
namespace pugi { class xml_node; }
|
namespace pugi { class xml_node; }
|
||||||
|
|
||||||
enum MetaDataType
|
enum MetaDataType {
|
||||||
{
|
// Generic types
|
||||||
//generic types
|
|
||||||
MD_STRING,
|
MD_STRING,
|
||||||
MD_INT,
|
MD_INT,
|
||||||
MD_FLOAT,
|
MD_FLOAT,
|
||||||
MD_BOOL,
|
MD_BOOL,
|
||||||
|
|
||||||
//specialized types
|
// Specialized types
|
||||||
MD_MULTILINE_STRING,
|
MD_MULTILINE_STRING,
|
||||||
MD_LAUNCHSTRING,
|
MD_LAUNCHSTRING,
|
||||||
MD_PATH,
|
MD_PATH,
|
||||||
MD_RATING,
|
MD_RATING,
|
||||||
MD_DATE,
|
MD_DATE,
|
||||||
MD_TIME //used for lastplayed
|
MD_TIME // Used for lastplayed
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MetaDataDecl
|
struct MetaDataDecl {
|
||||||
{
|
|
||||||
std::string key;
|
std::string key;
|
||||||
MetaDataType type;
|
MetaDataType type;
|
||||||
std::string defaultValue;
|
std::string defaultValue;
|
||||||
bool isStatistic; //if true, ignore values for this metadata
|
// If true, ignore values for this metadata.
|
||||||
std::string displayName; // displayed as this in editors
|
bool isStatistic;
|
||||||
std::string displayPrompt; // phrase displayed in editors when prompted to enter value (currently only for strings)
|
// Displayed as this in editors.
|
||||||
|
std::string displayName;
|
||||||
|
// Phrase displayed in editors when prompted to enter value (currently only for strings).
|
||||||
|
std::string displayPrompt;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MetaDataListType
|
enum MetaDataListType {
|
||||||
{
|
|
||||||
GAME_METADATA,
|
GAME_METADATA,
|
||||||
FOLDER_METADATA
|
FOLDER_METADATA
|
||||||
};
|
};
|
||||||
|
@ -45,8 +52,10 @@ const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type);
|
||||||
class MetaDataList
|
class MetaDataList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static MetaDataList createFromXML(MetaDataListType type, pugi::xml_node& node, const std::string& relativeTo);
|
static MetaDataList createFromXML(MetaDataListType type,
|
||||||
void appendToXML(pugi::xml_node& parent, bool ignoreDefaults, const std::string& relativeTo) const;
|
pugi::xml_node& node, const std::string& relativeTo);
|
||||||
|
void appendToXML(pugi::xml_node& parent, bool ignoreDefaults,
|
||||||
|
const std::string& relativeTo) const;
|
||||||
|
|
||||||
MetaDataList(MetaDataListType type);
|
MetaDataList(MetaDataListType type);
|
||||||
|
|
||||||
|
@ -65,6 +74,7 @@ public:
|
||||||
private:
|
private:
|
||||||
MetaDataListType mType;
|
MetaDataListType mType;
|
||||||
std::map<std::string, std::string> mMap;
|
std::map<std::string, std::string> mMap;
|
||||||
|
std::string mNoResult = "";
|
||||||
bool mWasChanged;
|
bool mWasChanged;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
//
|
||||||
|
// SystemData.cpp
|
||||||
|
//
|
||||||
|
// Provides data structures for the game systems and populates and indexes them based
|
||||||
|
// on the configuration in es_systems.cfg as well as the presence of game ROM files.
|
||||||
|
// Also provides functions to read and write to the gamelist files and to handle theme
|
||||||
|
// loading.
|
||||||
|
//
|
||||||
|
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
#include "utils/FileSystemUtil.h"
|
||||||
|
@ -18,31 +27,44 @@
|
||||||
|
|
||||||
std::vector<SystemData*> SystemData::sSystemVector;
|
std::vector<SystemData*> SystemData::sSystemVector;
|
||||||
|
|
||||||
SystemData::SystemData(const std::string& name, const std::string& fullName, SystemEnvironmentData* envData, const std::string& themeFolder, bool CollectionSystem) :
|
SystemData::SystemData(
|
||||||
mName(name), mFullName(fullName), mEnvData(envData), mThemeFolder(themeFolder), mIsCollectionSystem(CollectionSystem), mIsGameSystem(true)
|
const std::string& name,
|
||||||
|
const std::string& fullName,
|
||||||
|
SystemEnvironmentData* envData,
|
||||||
|
const std::string& themeFolder,
|
||||||
|
bool CollectionSystem)
|
||||||
|
: mName(name),
|
||||||
|
mFullName(fullName),
|
||||||
|
mEnvData(envData),
|
||||||
|
mThemeFolder(themeFolder),
|
||||||
|
mIsCollectionSystem(CollectionSystem),
|
||||||
|
mIsGameSystem(true)
|
||||||
{
|
{
|
||||||
mFilterIndex = new FileFilterIndex();
|
mFilterIndex = new FileFilterIndex();
|
||||||
|
|
||||||
// if it's an actual system, initialize it, if not, just create the data structure
|
// If it's an actual system, initialize it, if not, just create the data structure.
|
||||||
if(!CollectionSystem)
|
if (!CollectionSystem) {
|
||||||
{
|
|
||||||
mRootFolder = new FileData(FOLDER, mEnvData->mStartPath, mEnvData, this);
|
mRootFolder = new FileData(FOLDER, mEnvData->mStartPath, mEnvData, this);
|
||||||
mRootFolder->metadata.set("name", mFullName);
|
mRootFolder->metadata.set("name", mFullName);
|
||||||
|
|
||||||
if(!Settings::getInstance()->getBool("ParseGamelistOnly"))
|
if (!Settings::getInstance()->getBool("ParseGamelistOnly"))
|
||||||
populateFolder(mRootFolder);
|
populateFolder(mRootFolder);
|
||||||
|
|
||||||
if(!Settings::getInstance()->getBool("IgnoreGamelist"))
|
if (!Settings::getInstance()->getBool("IgnoreGamelist"))
|
||||||
parseGamelist(this);
|
parseGamelist(this);
|
||||||
|
|
||||||
mRootFolder->sort(FileSorts::SortTypes.at(0));
|
setupSystemSortType(mRootFolder);
|
||||||
|
|
||||||
|
mRootFolder->sort(getSortTypeFromString(mRootFolder->getSortTypeString()),
|
||||||
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
|
|
||||||
indexAllGameFilters(mRootFolder);
|
indexAllGameFilters(mRootFolder);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
// Virtual systems are updated afterwards by CollectionSystemManager.
|
||||||
// virtual systems are updated afterwards, we're just creating the data structure
|
// We're just creating the data structure here.
|
||||||
mRootFolder = new FileData(FOLDER, "" + name, mEnvData, this);
|
mRootFolder = new FileData(FOLDER, "" + name, mEnvData, this);
|
||||||
|
setupSystemSortType(mRootFolder);
|
||||||
}
|
}
|
||||||
setIsGameSystemStatus();
|
setIsGameSystemStatus();
|
||||||
loadTheme();
|
loadTheme();
|
||||||
|
@ -50,7 +72,7 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, Sys
|
||||||
|
|
||||||
SystemData::~SystemData()
|
SystemData::~SystemData()
|
||||||
{
|
{
|
||||||
if(Settings::getInstance()->getString("SaveGamelistsMode") == "on exit")
|
if (Settings::getInstance()->getString("SaveGamelistsMode") == "on exit")
|
||||||
writeMetaData();
|
writeMetaData();
|
||||||
|
|
||||||
delete mRootFolder;
|
delete mRootFolder;
|
||||||
|
@ -59,27 +81,25 @@ SystemData::~SystemData()
|
||||||
|
|
||||||
void SystemData::setIsGameSystemStatus()
|
void SystemData::setIsGameSystemStatus()
|
||||||
{
|
{
|
||||||
// we exclude non-game systems from specific operations (i.e. the "RetroPie" system, at least)
|
// We exclude non-game systems from specific operations (i.e. the "RetroPie" system, at least).
|
||||||
// if/when there are more in the future, maybe this can be a more complex method, with a proper list
|
// If/when there are more in the future, maybe this can be a more complex method, with a proper
|
||||||
// but for now a simple string comparison is more performant
|
// list but for now a simple string comparison is more performant.
|
||||||
mIsGameSystem = (mName != "retropie");
|
mIsGameSystem = (mName != "retropie");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::populateFolder(FileData* folder)
|
void SystemData::populateFolder(FileData* folder)
|
||||||
{
|
{
|
||||||
const std::string& folderPath = folder->getPath();
|
const std::string& folderPath = folder->getPath();
|
||||||
if(!Utils::FileSystem::isDirectory(folderPath))
|
if (!Utils::FileSystem::isDirectory(folderPath)) {
|
||||||
{
|
|
||||||
LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!";
|
LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure that this isn't a symlink to a thing we already have
|
// Make sure that this isn't a symlink to an object we already have.
|
||||||
if(Utils::FileSystem::isSymlink(folderPath))
|
if (Utils::FileSystem::isSymlink(folderPath)) {
|
||||||
{
|
// If this symlink resolves to somewhere that's at the beginning of our
|
||||||
//if this symlink resolves to somewhere that's at the beginning of our path, it's gonna recurse
|
// path, it's going to create a recursive loop. Make sure to avoid this.
|
||||||
if(folderPath.find(Utils::FileSystem::getCanonicalPath(folderPath)) == 0)
|
if (folderPath.find(Utils::FileSystem::getCanonicalPath(folderPath)) == 0) {
|
||||||
{
|
|
||||||
LOG(LogWarning) << "Skipping infinitely recursive symlink \"" << folderPath << "\"";
|
LOG(LogWarning) << "Skipping infinitely recursive symlink \"" << folderPath << "\"";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -90,42 +110,42 @@ void SystemData::populateFolder(FileData* folder)
|
||||||
bool isGame;
|
bool isGame;
|
||||||
bool showHidden = Settings::getInstance()->getBool("ShowHiddenFiles");
|
bool showHidden = Settings::getInstance()->getBool("ShowHiddenFiles");
|
||||||
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(folderPath);
|
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(folderPath);
|
||||||
for(Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin(); it != dirContent.cend(); ++it)
|
for (Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin();
|
||||||
{
|
it != dirContent.cend(); ++it) {
|
||||||
filePath = *it;
|
filePath = *it;
|
||||||
|
|
||||||
// skip hidden files and folders
|
// Skip hidden files and folders.
|
||||||
if(!showHidden && Utils::FileSystem::isHidden(filePath))
|
if (!showHidden && Utils::FileSystem::isHidden(filePath))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//this is a little complicated because we allow a list of extensions to be defined (delimited with a space)
|
// This is a little complicated because we allow a list
|
||||||
//we first get the extension of the file itself:
|
// of extensions to be defined (delimited with a space).
|
||||||
|
// We first get the extension of the file itself:
|
||||||
extension = Utils::FileSystem::getExtension(filePath);
|
extension = Utils::FileSystem::getExtension(filePath);
|
||||||
|
|
||||||
//fyi, folders *can* also match the extension and be added as games - this is mostly just to support higan
|
// FYI, folders *can* also match the extension and be added as games.
|
||||||
//see issue #75: https://github.com/Aloshi/EmulationStation/issues/75
|
// This is mostly just to support higan.
|
||||||
|
// See issue #75: https://github.com/Aloshi/EmulationStation/issues/75
|
||||||
|
|
||||||
isGame = false;
|
isGame = false;
|
||||||
if(std::find(mEnvData->mSearchExtensions.cbegin(), mEnvData->mSearchExtensions.cend(), extension) != mEnvData->mSearchExtensions.cend())
|
if (std::find(mEnvData->mSearchExtensions.cbegin(), mEnvData->mSearchExtensions.cend(),
|
||||||
{
|
extension) != mEnvData->mSearchExtensions.cend()) {
|
||||||
FileData* newGame = new FileData(GAME, filePath, mEnvData, this);
|
FileData* newGame = new FileData(GAME, filePath, mEnvData, this);
|
||||||
|
|
||||||
// preventing new arcade assets to be added
|
// Prevent new arcade assets from being added.
|
||||||
if(!newGame->isArcadeAsset())
|
if (!newGame->isArcadeAsset()) {
|
||||||
{
|
|
||||||
folder->addChild(newGame);
|
folder->addChild(newGame);
|
||||||
isGame = true;
|
isGame = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//add directories that also do not match an extension as folders
|
// Add directories that also do not match an extension as folders.
|
||||||
if(!isGame && Utils::FileSystem::isDirectory(filePath))
|
if (!isGame && Utils::FileSystem::isDirectory(filePath)) {
|
||||||
{
|
|
||||||
FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this);
|
FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this);
|
||||||
populateFolder(newFolder);
|
populateFolder(newFolder);
|
||||||
|
|
||||||
//ignore folders that do not contain games
|
// Ignore folders that do not contain games.
|
||||||
if(newFolder->getChildrenByFilename().size() == 0)
|
if (newFolder->getChildrenByFilename().size() == 0)
|
||||||
delete newFolder;
|
delete newFolder;
|
||||||
else
|
else
|
||||||
folder->addChild(newFolder);
|
folder->addChild(newFolder);
|
||||||
|
@ -137,12 +157,17 @@ 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(); it != children.cend(); ++it)
|
for (std::vector<FileData*>::const_iterator it = children.cbegin();
|
||||||
{
|
it != children.cend(); ++it) {
|
||||||
switch((*it)->getType())
|
switch ((*it)->getType()) {
|
||||||
{
|
case GAME: {
|
||||||
case GAME: { mFilterIndex->addToIndex(*it); } break;
|
mFilterIndex->addToIndex(*it);
|
||||||
case FOLDER: { indexAllGameFilters(*it); } break;
|
}
|
||||||
|
break;
|
||||||
|
case FOLDER: {
|
||||||
|
indexAllGameFilters(*it);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,8 +178,7 @@ std::vector<std::string> readList(const std::string& str, const char* delims = "
|
||||||
|
|
||||||
size_t prevOff = str.find_first_not_of(delims, 0);
|
size_t prevOff = str.find_first_not_of(delims, 0);
|
||||||
size_t off = str.find_first_of(delims, prevOff);
|
size_t off = str.find_first_of(delims, prevOff);
|
||||||
while(off != std::string::npos || prevOff != std::string::npos)
|
while (off != std::string::npos || prevOff != std::string::npos) {
|
||||||
{
|
|
||||||
ret.push_back(str.substr(prevOff, off - prevOff));
|
ret.push_back(str.substr(prevOff, off - prevOff));
|
||||||
|
|
||||||
prevOff = str.find_first_not_of(delims, off);
|
prevOff = str.find_first_not_of(delims, off);
|
||||||
|
@ -164,7 +188,7 @@ std::vector<std::string> readList(const std::string& str, const char* delims = "
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//creates systems from information located in a config file
|
// Creates systems from information located in a config file.
|
||||||
bool SystemData::loadConfig()
|
bool SystemData::loadConfig()
|
||||||
{
|
{
|
||||||
deleteSystems();
|
deleteSystems();
|
||||||
|
@ -173,8 +197,7 @@ bool SystemData::loadConfig()
|
||||||
|
|
||||||
LOG(LogInfo) << "Loading system config file " << path << "...";
|
LOG(LogInfo) << "Loading system config file " << path << "...";
|
||||||
|
|
||||||
if(!Utils::FileSystem::exists(path))
|
if (!Utils::FileSystem::exists(path)) {
|
||||||
{
|
|
||||||
LOG(LogError) << "es_systems.cfg file does not exist!";
|
LOG(LogError) << "es_systems.cfg file does not exist!";
|
||||||
writeExampleConfig(getConfigPath(true));
|
writeExampleConfig(getConfigPath(true));
|
||||||
return false;
|
return false;
|
||||||
|
@ -183,80 +206,78 @@ bool SystemData::loadConfig()
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
pugi::xml_parse_result res = doc.load_file(path.c_str());
|
||||||
|
|
||||||
if(!res)
|
if (!res) {
|
||||||
{
|
|
||||||
LOG(LogError) << "Could not parse es_systems.cfg file!";
|
LOG(LogError) << "Could not parse es_systems.cfg file!";
|
||||||
LOG(LogError) << res.description();
|
LOG(LogError) << res.description();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//actually read the file
|
// Actually read the file.
|
||||||
pugi::xml_node systemList = doc.child("systemList");
|
pugi::xml_node systemList = doc.child("systemList");
|
||||||
|
|
||||||
if(!systemList)
|
if (!systemList) {
|
||||||
{
|
|
||||||
LOG(LogError) << "es_systems.cfg is missing the <systemList> tag!";
|
LOG(LogError) << "es_systems.cfg is missing the <systemList> tag!";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(pugi::xml_node system = systemList.child("system"); system; system = system.next_sibling("system"))
|
for (pugi::xml_node system = systemList.child("system"); system;
|
||||||
{
|
system = system.next_sibling("system")) {
|
||||||
std::string name, fullname, path, cmd, themeFolder;
|
std::string name, fullname, path, cmd, themeFolder;
|
||||||
|
|
||||||
name = system.child("name").text().get();
|
name = system.child("name").text().get();
|
||||||
fullname = system.child("fullname").text().get();
|
fullname = system.child("fullname").text().get();
|
||||||
path = system.child("path").text().get();
|
path = system.child("path").text().get();
|
||||||
|
|
||||||
// convert extensions list from a string into a vector of strings
|
// Convert extensions list from a string into a vector of strings.
|
||||||
std::vector<std::string> extensions = readList(system.child("extension").text().get());
|
std::vector<std::string> extensions = readList(system.child("extension").text().get());
|
||||||
|
|
||||||
cmd = system.child("command").text().get();
|
cmd = system.child("command").text().get();
|
||||||
|
|
||||||
// platform id list
|
// Platform ID list
|
||||||
const char* platformList = system.child("platform").text().get();
|
const char* platformList = 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++) {
|
||||||
{
|
|
||||||
const char* str = it->c_str();
|
const char* str = it->c_str();
|
||||||
PlatformIds::PlatformId platformId = PlatformIds::getPlatformId(str);
|
PlatformIds::PlatformId platformId = PlatformIds::getPlatformId(str);
|
||||||
|
|
||||||
if(platformId == PlatformIds::PLATFORM_IGNORE)
|
if (platformId == PlatformIds::PLATFORM_IGNORE) {
|
||||||
{
|
// When platform is PLATFORM_IGNORE, do not allow other platforms.
|
||||||
// when platform is ignore, do not allow other platforms
|
|
||||||
platformIds.clear();
|
platformIds.clear();
|
||||||
platformIds.push_back(platformId);
|
platformIds.push_back(platformId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there appears to be an actual platform ID supplied but it didn't match the list, warn
|
// If there appears to be an actual platform ID supplied
|
||||||
if(str != NULL && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN)
|
// but it didn't match the list, generate a warning.
|
||||||
LOG(LogWarning) << " Unknown platform for system \"" << name << "\" (platform \"" << str << "\" from list \"" << platformList << "\")";
|
if (str != NULL && str[0] != '\0' && platformId == PlatformIds::PLATFORM_UNKNOWN)
|
||||||
else if(platformId != PlatformIds::PLATFORM_UNKNOWN)
|
LOG(LogWarning) << " Unknown platform for system \"" << name << "\" (platform \""
|
||||||
|
<< str << "\" from list \"" << platformList << "\")";
|
||||||
|
else if (platformId != PlatformIds::PLATFORM_UNKNOWN)
|
||||||
platformIds.push_back(platformId);
|
platformIds.push_back(platformId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// theme folder
|
// Theme folder.
|
||||||
themeFolder = system.child("theme").text().as_string(name.c_str());
|
themeFolder = system.child("theme").text().as_string(name.c_str());
|
||||||
|
|
||||||
//validate
|
// Validate.
|
||||||
if(name.empty() || path.empty() || extensions.empty() || cmd.empty())
|
if (name.empty() || path.empty() || extensions.empty() || cmd.empty()) {
|
||||||
{
|
LOG(LogError) << "System \"" << name <<
|
||||||
LOG(LogError) << "System \"" << name << "\" is missing name, path, extension, or command!";
|
"\" is missing name, path, extension, or command!";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//convert path to generic directory seperators
|
// Convert path to generic directory seperators.
|
||||||
path = Utils::FileSystem::getGenericPath(path);
|
path = Utils::FileSystem::getGenericPath(path);
|
||||||
|
|
||||||
//expand home symbol if the startpath contains ~
|
// Expand home symbol if the startpath contains ~
|
||||||
if(path[0] == '~')
|
if (path[0] == '~')
|
||||||
{
|
{
|
||||||
path.erase(0, 1);
|
path.erase(0, 1);
|
||||||
path.insert(0, Utils::FileSystem::getHomePath());
|
path.insert(0, Utils::FileSystem::getHomePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//create the system runtime environment data
|
// Create the system runtime environment data.
|
||||||
SystemEnvironmentData* envData = new SystemEnvironmentData;
|
SystemEnvironmentData* envData = new SystemEnvironmentData;
|
||||||
envData->mStartPath = path;
|
envData->mStartPath = path;
|
||||||
envData->mSearchExtensions = extensions;
|
envData->mSearchExtensions = extensions;
|
||||||
|
@ -264,11 +285,11 @@ bool SystemData::loadConfig()
|
||||||
envData->mPlatformIds = platformIds;
|
envData->mPlatformIds = platformIds;
|
||||||
|
|
||||||
SystemData* newSys = new SystemData(name, fullname, envData, themeFolder);
|
SystemData* newSys = new SystemData(name, fullname, envData, themeFolder);
|
||||||
if(newSys->getRootFolder()->getChildrenByFilename().size() == 0)
|
if (newSys->getRootFolder()->getChildrenByFilename().size() == 0) {
|
||||||
{
|
|
||||||
LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it.";
|
LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it.";
|
||||||
delete newSys;
|
delete newSys;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
sSystemVector.push_back(newSys);
|
sSystemVector.push_back(newSys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -325,17 +346,16 @@ void SystemData::writeExampleConfig(const std::string& path)
|
||||||
|
|
||||||
void SystemData::deleteSystems()
|
void SystemData::deleteSystems()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < sSystemVector.size(); i++)
|
for (unsigned int i = 0; i < sSystemVector.size(); i++)
|
||||||
{
|
|
||||||
delete sSystemVector.at(i);
|
delete sSystemVector.at(i);
|
||||||
}
|
|
||||||
sSystemVector.clear();
|
sSystemVector.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SystemData::getConfigPath(bool forWrite)
|
std::string SystemData::getConfigPath(bool forWrite)
|
||||||
{
|
{
|
||||||
std::string path = Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
std::string path = Utils::FileSystem::getHomePath() + "/.emulationstation/es_systems.cfg";
|
||||||
if(forWrite || Utils::FileSystem::exists(path))
|
if (forWrite || Utils::FileSystem::exists(path))
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
return "/etc/emulationstation/es_systems.cfg";
|
return "/etc/emulationstation/es_systems.cfg";
|
||||||
|
@ -352,12 +372,13 @@ SystemData* SystemData::getNext() const
|
||||||
{
|
{
|
||||||
std::vector<SystemData*>::const_iterator it = getIterator();
|
std::vector<SystemData*>::const_iterator it = getIterator();
|
||||||
|
|
||||||
|
// As we are starting in a valid gamelistview, this will
|
||||||
|
// always succeed, even if we have to come full circle.
|
||||||
do {
|
do {
|
||||||
it++;
|
it++;
|
||||||
if (it == sSystemVector.cend())
|
if (it == sSystemVector.cend())
|
||||||
it = sSystemVector.cbegin();
|
it = sSystemVector.cbegin();
|
||||||
} while (!(*it)->isVisible());
|
} while (!(*it)->isVisible());
|
||||||
// as we are starting in a valid gamelistview, this will always succeed, even if we have to come full circle.
|
|
||||||
|
|
||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
|
@ -366,12 +387,13 @@ SystemData* SystemData::getPrev() const
|
||||||
{
|
{
|
||||||
std::vector<SystemData*>::const_reverse_iterator it = getRevIterator();
|
std::vector<SystemData*>::const_reverse_iterator it = getRevIterator();
|
||||||
|
|
||||||
|
// As we are starting in a valid gamelistview, this will
|
||||||
|
// always succeed, even if we have to come full circle.
|
||||||
do {
|
do {
|
||||||
it++;
|
it++;
|
||||||
if (it == sSystemVector.crend())
|
if (it == sSystemVector.crend())
|
||||||
it = sSystemVector.crbegin();
|
it = sSystemVector.crbegin();
|
||||||
} while (!(*it)->isVisible());
|
} while (!(*it)->isVisible());
|
||||||
// as we are starting in a valid gamelistview, this will always succeed, even if we have to come full circle.
|
|
||||||
|
|
||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
|
@ -381,13 +403,15 @@ std::string SystemData::getGamelistPath(bool forWrite) const
|
||||||
std::string filePath;
|
std::string filePath;
|
||||||
|
|
||||||
filePath = mRootFolder->getPath() + "/gamelist.xml";
|
filePath = mRootFolder->getPath() + "/gamelist.xml";
|
||||||
if(Utils::FileSystem::exists(filePath))
|
if (Utils::FileSystem::exists(filePath))
|
||||||
return filePath;
|
return filePath;
|
||||||
|
|
||||||
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" + mName + "/gamelist.xml";
|
filePath = Utils::FileSystem::getHomePath() + "/.emulationstation/gamelists/" +
|
||||||
if(forWrite) // make sure the directory exists if we're going to write to it, or crashes will happen
|
mName + "/gamelist.xml";
|
||||||
|
// Make sure the directory exists if we're going to write to it, or crashes will happen.
|
||||||
|
if (forWrite)
|
||||||
Utils::FileSystem::createDirectory(Utils::FileSystem::getParent(filePath));
|
Utils::FileSystem::createDirectory(Utils::FileSystem::getParent(filePath));
|
||||||
if(forWrite || Utils::FileSystem::exists(filePath))
|
if (forWrite || Utils::FileSystem::exists(filePath))
|
||||||
return filePath;
|
return filePath;
|
||||||
|
|
||||||
return "/etc/emulationstation/gamelists/" + mName + "/gamelist.xml";
|
return "/etc/emulationstation/gamelists/" + mName + "/gamelist.xml";
|
||||||
|
@ -395,24 +419,25 @@ std::string SystemData::getGamelistPath(bool forWrite) const
|
||||||
|
|
||||||
std::string SystemData::getThemePath() const
|
std::string SystemData::getThemePath() const
|
||||||
{
|
{
|
||||||
// where we check for themes, in order:
|
// Locations where we check for themes, in the following order:
|
||||||
// 1. [SYSTEM_PATH]/theme.xml
|
// 1. [SYSTEM_PATH]/theme.xml
|
||||||
// 2. system theme from currently selected theme set [CURRENT_THEME_PATH]/[SYSTEM]/theme.xml
|
// 2. System theme from currently selected theme set [CURRENT_THEME_PATH]/[SYSTEM]/theme.xml
|
||||||
// 3. default system theme from currently selected theme set [CURRENT_THEME_PATH]/theme.xml
|
// 3. Default system theme from currently selected theme set [CURRENT_THEME_PATH]/theme.xml
|
||||||
|
|
||||||
// first, check game folder
|
// First, check game folder.
|
||||||
std::string localThemePath = mRootFolder->getPath() + "/theme.xml";
|
std::string localThemePath = mRootFolder->getPath() + "/theme.xml";
|
||||||
if(Utils::FileSystem::exists(localThemePath))
|
if (Utils::FileSystem::exists(localThemePath))
|
||||||
return localThemePath;
|
return localThemePath;
|
||||||
|
|
||||||
// not in game folder, try system theme in theme sets
|
// Not in game folder, try system theme in theme sets.
|
||||||
localThemePath = ThemeData::getThemeFromCurrentSet(mThemeFolder);
|
localThemePath = ThemeData::getThemeFromCurrentSet(mThemeFolder);
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(localThemePath))
|
if (Utils::FileSystem::exists(localThemePath))
|
||||||
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)) + "/theme.xml";
|
localThemePath = Utils::FileSystem::getParent(Utils::FileSystem::getParent(localThemePath)) +
|
||||||
|
"/theme.xml";
|
||||||
|
|
||||||
return localThemePath;
|
return localThemePath;
|
||||||
}
|
}
|
||||||
|
@ -429,32 +454,27 @@ unsigned int SystemData::getGameCount() const
|
||||||
|
|
||||||
SystemData* SystemData::getRandomSystem()
|
SystemData* SystemData::getRandomSystem()
|
||||||
{
|
{
|
||||||
// this is a bit brute force. It might be more efficient to just to a while (!gameSystem) do random again...
|
// This is a bit brute force.
|
||||||
|
// It might be more efficient to just do a while (!gameSystem) do random again...
|
||||||
unsigned int total = 0;
|
unsigned int total = 0;
|
||||||
for(auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++)
|
for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++) {
|
||||||
{
|
|
||||||
if ((*it)->isGameSystem())
|
if ((*it)->isGameSystem())
|
||||||
total ++;
|
total++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get random number in range
|
// Get a random number in range.
|
||||||
int target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1));
|
int target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1));
|
||||||
for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++)
|
for (auto it = sSystemVector.cbegin(); it != sSystemVector.cend(); it++)
|
||||||
{
|
{
|
||||||
if ((*it)->isGameSystem())
|
if ((*it)->isGameSystem()) {
|
||||||
{
|
|
||||||
if (target > 0)
|
if (target > 0)
|
||||||
{
|
|
||||||
target--;
|
target--;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return (*it);
|
return (*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// if we end up here, there is no valid system
|
// If we end up here, there is no valid system.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,10 +483,12 @@ FileData* SystemData::getRandomGame()
|
||||||
std::vector<FileData*> list = mRootFolder->getFilesRecursive(GAME, true);
|
std::vector<FileData*> list = mRootFolder->getFilesRecursive(GAME, true);
|
||||||
unsigned int total = (int)list.size();
|
unsigned int total = (int)list.size();
|
||||||
int target = 0;
|
int target = 0;
|
||||||
// get random number in range
|
|
||||||
|
// Get a random number in range.
|
||||||
if (total == 0)
|
if (total == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1));
|
target = (int)Math::round((std::rand() / (float)RAND_MAX) * (total - 1));
|
||||||
|
|
||||||
return list.at(target);
|
return list.at(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,36 +503,54 @@ void SystemData::loadTheme()
|
||||||
|
|
||||||
std::string path = getThemePath();
|
std::string path = getThemePath();
|
||||||
|
|
||||||
if(!Utils::FileSystem::exists(path)) // no theme available for this platform
|
if (!Utils::FileSystem::exists(path)) // No theme available for this platform.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
// Build map with system variables for theme to use.
|
||||||
// build map with system variables for theme to use,
|
|
||||||
std::map<std::string, std::string> sysData;
|
std::map<std::string, std::string> sysData;
|
||||||
sysData.insert(std::pair<std::string, std::string>("system.name", getName()));
|
sysData.insert(std::pair<std::string, std::string>("system.name", getName()));
|
||||||
sysData.insert(std::pair<std::string, std::string>("system.theme", getThemeFolder()));
|
sysData.insert(std::pair<std::string, std::string>("system.theme", getThemeFolder()));
|
||||||
sysData.insert(std::pair<std::string, std::string>("system.fullName", getFullName()));
|
sysData.insert(std::pair<std::string, std::string>("system.fullName", getFullName()));
|
||||||
|
|
||||||
mTheme->loadFile(sysData, path);
|
mTheme->loadFile(sysData, path);
|
||||||
} catch(ThemeException& e)
|
}
|
||||||
{
|
catch (ThemeException& e) {
|
||||||
LOG(LogError) << e.what();
|
LOG(LogError) << e.what();
|
||||||
mTheme = std::make_shared<ThemeData>(); // reset to empty
|
mTheme = std::make_shared<ThemeData>(); // Reset to empty.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::writeMetaData() {
|
void SystemData::writeMetaData() {
|
||||||
if(Settings::getInstance()->getBool("IgnoreGamelist") || mIsCollectionSystem)
|
if (Settings::getInstance()->getBool("IgnoreGamelist") || mIsCollectionSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//save changed game data back to xml
|
// Save changed game data back to xml.
|
||||||
updateGamelist(this);
|
updateGamelist(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemData::onMetaDataSavePoint() {
|
void SystemData::onMetaDataSavePoint() {
|
||||||
if(Settings::getInstance()->getString("SaveGamelistsMode") != "always")
|
if (Settings::getInstance()->getString("SaveGamelistsMode") != "always")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
writeMetaData();
|
writeMetaData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemData::setupSystemSortType(FileData* mRootFolder)
|
||||||
|
{
|
||||||
|
// If DefaultSortOrder is set to something, check that it is actually a valid value.
|
||||||
|
if (Settings::getInstance()->getString("DefaultSortOrder") != "") {
|
||||||
|
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||||
|
if (FileSorts::SortTypes.at(i).description ==
|
||||||
|
Settings::getInstance()->getString("DefaultSortOrder")) {
|
||||||
|
mRootFolder->setSortTypeString(Settings::getInstance()->
|
||||||
|
getString("DefaultSortOrder"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no valid sort type was defined in the configuration
|
||||||
|
// file, set sorting to "filename, ascending".
|
||||||
|
if (mRootFolder->getSortTypeString() == "")
|
||||||
|
mRootFolder->setSortTypeString(FileSorts::SortTypes.at(0).description);
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
//
|
||||||
|
// SystemData.h
|
||||||
|
//
|
||||||
|
// Provides data structures for the game systems and populates and indexes them based
|
||||||
|
// on the configuration in es_systems.cfg as well as the presence of game ROM files.
|
||||||
|
// Also provides functions to read and write to the gamelist files and to handle theme
|
||||||
|
// loading.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_SYSTEM_DATA_H
|
#ifndef ES_APP_SYSTEM_DATA_H
|
||||||
#define ES_APP_SYSTEM_DATA_H
|
#define ES_APP_SYSTEM_DATA_H
|
||||||
|
@ -23,18 +32,27 @@ struct SystemEnvironmentData
|
||||||
class SystemData
|
class SystemData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SystemData(const std::string& name, const std::string& fullName, SystemEnvironmentData* envData, const std::string& themeFolder, bool CollectionSystem = false);
|
SystemData(const std::string& name,
|
||||||
|
const std::string& fullName,
|
||||||
|
SystemEnvironmentData* envData,
|
||||||
|
const std::string& themeFolder,
|
||||||
|
bool CollectionSystem = false);
|
||||||
|
|
||||||
~SystemData();
|
~SystemData();
|
||||||
|
|
||||||
inline FileData* getRootFolder() const { return mRootFolder; };
|
inline FileData* getRootFolder() const { return mRootFolder; };
|
||||||
inline const std::string& getName() const { return mName; }
|
inline const std::string& getName() const { return mName; }
|
||||||
inline const std::string& getFullName() const { return mFullName; }
|
inline const std::string& getFullName() const { return mFullName; }
|
||||||
inline const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
inline const std::string& getStartPath() const { return mEnvData->mStartPath; }
|
||||||
inline const std::vector<std::string>& getExtensions() const { return mEnvData->mSearchExtensions; }
|
inline const std::vector<std::string>& getExtensions() const
|
||||||
|
{ return mEnvData->mSearchExtensions; }
|
||||||
inline const std::string& getThemeFolder() const { return mThemeFolder; }
|
inline const std::string& getThemeFolder() const { return mThemeFolder; }
|
||||||
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
inline SystemEnvironmentData* getSystemEnvData() const { return mEnvData; }
|
||||||
inline const std::vector<PlatformIds::PlatformId>& getPlatformIds() const { return mEnvData->mPlatformIds; }
|
inline const std::vector<PlatformIds::PlatformId>& getPlatformIds() const
|
||||||
inline bool hasPlatformId(PlatformIds::PlatformId id) { if (!mEnvData) return false; return std::find(mEnvData->mPlatformIds.cbegin(), mEnvData->mPlatformIds.cend(), id) != mEnvData->mPlatformIds.cend(); }
|
{ return mEnvData->mPlatformIds; }
|
||||||
|
inline bool hasPlatformId(PlatformIds::PlatformId id) { if (!mEnvData) return false;
|
||||||
|
return std::find(mEnvData->mPlatformIds.cbegin(), mEnvData->mPlatformIds.cend(), id)
|
||||||
|
!= mEnvData->mPlatformIds.cend(); }
|
||||||
|
|
||||||
inline const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
inline const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
|
||||||
|
|
||||||
|
@ -46,14 +64,21 @@ public:
|
||||||
unsigned int getDisplayedGameCount() const;
|
unsigned int getDisplayedGameCount() const;
|
||||||
|
|
||||||
static void deleteSystems();
|
static void deleteSystems();
|
||||||
static bool loadConfig(); //Load the system config file at getConfigPath(). Returns true if no errors were encountered. An example will be written if the file doesn't exist.
|
// Load the system config file at getConfigPath().
|
||||||
|
// Returns true if no errors were encountered.
|
||||||
|
// An example will be written if the file doesn't exist.
|
||||||
|
static bool loadConfig();
|
||||||
static void writeExampleConfig(const std::string& path);
|
static void writeExampleConfig(const std::string& path);
|
||||||
static std::string getConfigPath(bool forWrite); // if forWrite, will only return ~/.emulationstation/es_systems.cfg, never /etc/emulationstation/es_systems.cfg
|
// If forWrite, will only return ~/.emulationstation/es_systems.cfg,
|
||||||
|
// never /etc/emulationstation/es_systems.cfg.
|
||||||
|
static std::string getConfigPath(bool forWrite);
|
||||||
|
|
||||||
static std::vector<SystemData*> sSystemVector;
|
static std::vector<SystemData*> sSystemVector;
|
||||||
|
|
||||||
inline std::vector<SystemData*>::const_iterator getIterator() const { return std::find(sSystemVector.cbegin(), sSystemVector.cend(), this); };
|
inline std::vector<SystemData*>::const_iterator getIterator() const
|
||||||
inline std::vector<SystemData*>::const_reverse_iterator getRevIterator() const { return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this); };
|
{ return std::find(sSystemVector.cbegin(), sSystemVector.cend(), this); };
|
||||||
|
inline std::vector<SystemData*>::const_reverse_iterator getRevIterator() const
|
||||||
|
{ return std::find(sSystemVector.crbegin(), sSystemVector.crend(), this); };
|
||||||
inline bool isCollection() { return mIsCollectionSystem; };
|
inline bool isCollection() { return mIsCollectionSystem; };
|
||||||
inline bool isGameSystem() { return mIsGameSystem; };
|
inline bool isGameSystem() { return mIsGameSystem; };
|
||||||
|
|
||||||
|
@ -70,6 +95,8 @@ public:
|
||||||
FileFilterIndex* getIndex() { return mFilterIndex; };
|
FileFilterIndex* getIndex() { return mFilterIndex; };
|
||||||
void onMetaDataSavePoint();
|
void onMetaDataSavePoint();
|
||||||
|
|
||||||
|
void setupSystemSortType(FileData* mRootFolder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mIsCollectionSystem;
|
bool mIsCollectionSystem;
|
||||||
bool mIsGameSystem;
|
bool mIsGameSystem;
|
||||||
|
|
|
@ -71,9 +71,9 @@ void GuiCollectionSystemsOptions::initializeMenu()
|
||||||
bundleCustomCollections->setState(Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
|
bundleCustomCollections->setState(Settings::getInstance()->getBool("UseCustomCollectionsSystem"));
|
||||||
mMenu.addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", bundleCustomCollections);
|
mMenu.addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", bundleCustomCollections);
|
||||||
|
|
||||||
sortAllSystemsSwitch = std::make_shared<SwitchComponent>(mWindow);
|
sortFavFirstCustomSwitch = std::make_shared<SwitchComponent>(mWindow);
|
||||||
sortAllSystemsSwitch->setState(Settings::getInstance()->getBool("SortAllSystems"));
|
sortFavFirstCustomSwitch->setState(Settings::getInstance()->getBool("FavFirstCustom"));
|
||||||
mMenu.addWithLabel("SORT CUSTOM COLLECTIONS AND SYSTEMS", sortAllSystemsSwitch);
|
mMenu.addWithLabel("SORT FAVORITES ON TOP FOR CUSTOM COLLECTIONS", sortFavFirstCustomSwitch);
|
||||||
|
|
||||||
toggleSystemNameInCollections = std::make_shared<SwitchComponent>(mWindow);
|
toggleSystemNameInCollections = std::make_shared<SwitchComponent>(mWindow);
|
||||||
toggleSystemNameInCollections->setState(Settings::getInstance()->getBool("CollectionShowSystemInfo"));
|
toggleSystemNameInCollections->setState(Settings::getInstance()->getBool("CollectionShowSystemInfo"));
|
||||||
|
@ -170,8 +170,8 @@ void GuiCollectionSystemsOptions::applySettings()
|
||||||
std::string prevAuto = Settings::getInstance()->getString("CollectionSystemsAuto");
|
std::string prevAuto = Settings::getInstance()->getString("CollectionSystemsAuto");
|
||||||
std::string outCustom = Utils::String::vectorToCommaString(customOptionList->getSelectedObjects());
|
std::string outCustom = Utils::String::vectorToCommaString(customOptionList->getSelectedObjects());
|
||||||
std::string prevCustom = Settings::getInstance()->getString("CollectionSystemsCustom");
|
std::string prevCustom = Settings::getInstance()->getString("CollectionSystemsCustom");
|
||||||
bool outSort = sortAllSystemsSwitch->getState();
|
bool outSort = sortFavFirstCustomSwitch->getState();
|
||||||
bool prevSort = Settings::getInstance()->getBool("SortAllSystems");
|
bool prevSort = Settings::getInstance()->getBool("FavFirstCustom");
|
||||||
bool outBundle = bundleCustomCollections->getState();
|
bool outBundle = bundleCustomCollections->getState();
|
||||||
bool prevBundle = Settings::getInstance()->getBool("UseCustomCollectionsSystem");
|
bool prevBundle = Settings::getInstance()->getBool("UseCustomCollectionsSystem");
|
||||||
bool prevShow = Settings::getInstance()->getBool("CollectionShowSystemInfo");
|
bool prevShow = Settings::getInstance()->getBool("CollectionShowSystemInfo");
|
||||||
|
@ -189,7 +189,7 @@ void GuiCollectionSystemsOptions::updateSettings(std::string newAutoSettings, st
|
||||||
{
|
{
|
||||||
Settings::getInstance()->setString("CollectionSystemsAuto", newAutoSettings);
|
Settings::getInstance()->setString("CollectionSystemsAuto", newAutoSettings);
|
||||||
Settings::getInstance()->setString("CollectionSystemsCustom", newCustomSettings);
|
Settings::getInstance()->setString("CollectionSystemsCustom", newCustomSettings);
|
||||||
Settings::getInstance()->setBool("SortAllSystems", sortAllSystemsSwitch->getState());
|
Settings::getInstance()->setBool("FavFirstCustom", sortFavFirstCustomSwitch->getState());
|
||||||
Settings::getInstance()->setBool("UseCustomCollectionsSystem", bundleCustomCollections->getState());
|
Settings::getInstance()->setBool("UseCustomCollectionsSystem", bundleCustomCollections->getState());
|
||||||
Settings::getInstance()->setBool("CollectionShowSystemInfo", toggleSystemNameInCollections->getState());
|
Settings::getInstance()->setBool("CollectionShowSystemInfo", toggleSystemNameInCollections->getState());
|
||||||
Settings::getInstance()->saveFile();
|
Settings::getInstance()->saveFile();
|
||||||
|
|
|
@ -28,8 +28,8 @@ private:
|
||||||
void exitEditMode();
|
void exitEditMode();
|
||||||
std::shared_ptr< OptionListComponent<std::string> > autoOptionList;
|
std::shared_ptr< OptionListComponent<std::string> > autoOptionList;
|
||||||
std::shared_ptr< OptionListComponent<std::string> > customOptionList;
|
std::shared_ptr< OptionListComponent<std::string> > customOptionList;
|
||||||
std::shared_ptr<SwitchComponent> sortAllSystemsSwitch;
|
|
||||||
std::shared_ptr<SwitchComponent> bundleCustomCollections;
|
std::shared_ptr<SwitchComponent> bundleCustomCollections;
|
||||||
|
std::shared_ptr<SwitchComponent> sortFavFirstCustomSwitch;
|
||||||
std::shared_ptr<SwitchComponent> toggleSystemNameInCollections;
|
std::shared_ptr<SwitchComponent> toggleSystemNameInCollections;
|
||||||
MenuComponent mMenu;
|
MenuComponent mMenu;
|
||||||
SystemData* mSystem;
|
SystemData* mSystem;
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
//
|
||||||
|
// GuiGamelistOptions.cpp
|
||||||
|
//
|
||||||
|
// Gamelist options menu for the 'Jump to...' quick selector,
|
||||||
|
// game sorting, game filters, and metadata edit.
|
||||||
|
//
|
||||||
|
|
||||||
#include "GuiGamelistOptions.h"
|
#include "GuiGamelistOptions.h"
|
||||||
|
|
||||||
#include "guis/GuiGamelistFilter.h"
|
#include "guis/GuiGamelistFilter.h"
|
||||||
|
@ -12,43 +19,50 @@
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : GuiComponent(window),
|
GuiGamelistOptions::GuiGamelistOptions(
|
||||||
mSystem(system), mMenu(window, "OPTIONS"), fromPlaceholder(false), mFiltersChanged(false)
|
Window* window,
|
||||||
|
SystemData* system)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mSystem(system),
|
||||||
|
mMenu(window, "OPTIONS"),
|
||||||
|
fromPlaceholder(false),
|
||||||
|
mFiltersChanged(false)
|
||||||
{
|
{
|
||||||
addChild(&mMenu);
|
addChild(&mMenu);
|
||||||
|
|
||||||
// check it's not a placeholder folder - if it is, only show "Filter Options"
|
// Check that it's not a placeholder folder - if it is, only show "Filter Options".
|
||||||
FileData* file = getGamelist()->getCursor();
|
FileData* file = getGamelist()->getCursor();
|
||||||
fromPlaceholder = file->isPlaceHolder();
|
fromPlaceholder = file->isPlaceHolder();
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
|
|
||||||
|
// Read the applicable favorite sorting setting depending on whether the
|
||||||
|
// system is a custom collection or not.
|
||||||
|
if (CollectionSystemManager::get()->getIsCustomCollection(file->getSystem()))
|
||||||
|
mFavoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
||||||
|
else
|
||||||
|
mFavoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||||
|
|
||||||
if (!fromPlaceholder) {
|
if (!fromPlaceholder) {
|
||||||
// jump to letter
|
// Jump to letter.
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
|
|
||||||
// define supported character range
|
// Define supported character range.
|
||||||
// this range includes all numbers, capital letters, and most reasonable symbols
|
// This range includes all numbers, capital letters, and most reasonable symbols.
|
||||||
char startChar = '!';
|
char startChar = '!';
|
||||||
char endChar = '_';
|
char endChar = '_';
|
||||||
|
|
||||||
char curChar = (char)toupper(getGamelist()->getCursor()->getSortName()[0]);
|
char curChar = (char)toupper(getGamelist()->getCursor()->getSortName()[0]);
|
||||||
if(curChar < startChar || curChar > endChar)
|
if (curChar < startChar || curChar > endChar)
|
||||||
curChar = startChar;
|
curChar = startChar;
|
||||||
|
|
||||||
mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO...", false);
|
mJumpToLetterList = std::make_shared<LetterList>(mWindow, "JUMP TO...", false);
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("FavoritesFirst") && system->getName() != "favorites" && system->getName() != "recent")
|
if (mFavoritesSorting && system->getName() != "favorites" &&
|
||||||
{
|
system->getName() != "recent") {
|
||||||
// set firstFavorite to the numerical entry of the first favorite game in the list
|
// Check whether the first game in the list is a favorite, if it's
|
||||||
// if no favorites are found set it to -1
|
// not, then there are no favorites currently visible in this gamelist.
|
||||||
findFirstFavorite();
|
if (getGamelist()->getCursor()->getParent()->getChildrenListToDisplay()[0]->
|
||||||
|
getFavorite()) {
|
||||||
// if the currently selected game is a favorite, set curChar to 0 so we don't get two current positions
|
|
||||||
if(getGamelist()->getCursor()->getFavorite())
|
|
||||||
curChar = 0;
|
|
||||||
|
|
||||||
if (firstFavorite != -1)
|
|
||||||
{
|
|
||||||
if (getGamelist()->getCursor()->getFavorite())
|
if (getGamelist()->getCursor()->getFavorite())
|
||||||
mJumpToLetterList->add(FAVORITE_CHAR, FAVORITE_CHAR, 1);
|
mJumpToLetterList->add(FAVORITE_CHAR, FAVORITE_CHAR, 1);
|
||||||
else
|
else
|
||||||
|
@ -56,117 +70,147 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (char c = startChar; c <= endChar; c++)
|
for (char c = startChar; c <= endChar; c++) {
|
||||||
{
|
// Check if c is a valid first letter in the current list.
|
||||||
// check if c is a valid first letter in current list
|
const std::vector<FileData*>& files =
|
||||||
const std::vector<FileData*>& files = getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
getGamelist()->getCursor()->getParent()->getChildrenListToDisplay();
|
||||||
for (auto file : files)
|
for (auto file : files) {
|
||||||
{
|
|
||||||
char candidate = (char)toupper(file->getSortName()[0]);
|
char candidate = (char)toupper(file->getSortName()[0]);
|
||||||
if (c == candidate)
|
if (c == candidate) {
|
||||||
{
|
// If the game is a favorite, continue to the next entry in the list.
|
||||||
// if the game is a favorite, continue to the next entry in the list
|
if (mFavoritesSorting && system->getName() != "favorites" &&
|
||||||
if (firstFavorite != -1 && file->getFavorite())
|
system->getName() != "recent" && file->getFavorite())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// If the currently selected game is a favorite, set the character
|
||||||
|
// as not selected so we don't get two current positions.
|
||||||
|
if (mFavoritesSorting && system->getName() != "favorites" &&
|
||||||
|
system->getName() != "recent" &&
|
||||||
|
getGamelist()->getCursor()->getFavorite())
|
||||||
|
mJumpToLetterList->add(std::string(1, c), std::string(1, c), 0);
|
||||||
|
else
|
||||||
mJumpToLetterList->add(std::string(1, c), std::string(1, c), c == curChar);
|
mJumpToLetterList->add(std::string(1, c), std::string(1, c), c == curChar);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "JUMP TO...", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
|
mWindow, "JUMP TO...", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
row.addElement(mJumpToLetterList, false);
|
row.addElement(mJumpToLetterList, false);
|
||||||
row.input_handler = [&](InputConfig* config, Input input) {
|
row.input_handler = [&](InputConfig* config, Input input) {
|
||||||
if(config->isMappedTo("a", input) && input.value)
|
if (config->isMappedTo("a", input) && input.value) {
|
||||||
{
|
|
||||||
if(mJumpToLetterList->getSelected() == FAVORITE_CHAR)
|
|
||||||
{
|
|
||||||
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
|
||||||
jumpToFirstFavorite();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
if (mJumpToLetterList->getSelected() == FAVORITE_CHAR)
|
||||||
|
jumpToFirstRow();
|
||||||
|
else
|
||||||
jumpToLetter();
|
jumpToLetter();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(mJumpToLetterList->input(config, input))
|
else if (mJumpToLetterList->input(config, input)) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
if (system->getName() != "recent")
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
|
|
||||||
// sort list by
|
// Sort list by selected sort type (persistent throughout the program session).
|
||||||
mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false);
|
mListSort = std::make_shared<SortList>(mWindow, "SORT GAMES BY", false);
|
||||||
for(unsigned int i = 0; i < FileSorts::SortTypes.size(); i++)
|
FileData* root = mSystem->getRootFolder();
|
||||||
{
|
std::string sortType = root->getSortTypeString();
|
||||||
const FileData::SortType& sort = FileSorts::SortTypes.at(i);
|
|
||||||
mListSort->add(sort.description, &sort, i == 0); // TODO - actually make the sort type persistent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < FileSorts::SortTypes.size(); i++) {
|
||||||
|
const FileData::SortType& sort = FileSorts::SortTypes.at(i);
|
||||||
|
if (sort.description == sortType)
|
||||||
|
mListSort->add(sort.description, &sort, 1);
|
||||||
|
else
|
||||||
|
mListSort->add(sort.description, &sort, 0);
|
||||||
|
}
|
||||||
|
// Don't show the sort type option if the gamelist type is recent/last played.
|
||||||
|
if (system->getName() != "recent")
|
||||||
mMenu.addWithLabel("SORT GAMES BY", mListSort);
|
mMenu.addWithLabel("SORT GAMES BY", mListSort);
|
||||||
}
|
}
|
||||||
// show filtered menu
|
|
||||||
if(!Settings::getInstance()->getBool("ForceDisableFilters"))
|
// Show filtered menu.
|
||||||
{
|
if (system->getName() != "recent" && !Settings::getInstance()->getBool("ForceDisableFilters")) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
|
mWindow, "FILTER GAMELIST", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openGamelistFilter, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, CollectionSystemData> customCollections = CollectionSystemManager::get()->getCustomCollectionSystems();
|
std::map<std::string, CollectionSystemData> customCollections =
|
||||||
|
CollectionSystemManager::get()->getCustomCollectionSystems();
|
||||||
|
|
||||||
if(UIModeController::getInstance()->isUIModeFull() &&
|
if (UIModeController::getInstance()->isUIModeFull() &&
|
||||||
((customCollections.find(system->getName()) != customCollections.cend() && CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
|
((customCollections.find(system->getName()) != customCollections.cend() &&
|
||||||
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() == system->getName()))
|
CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
|
||||||
{
|
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() ==
|
||||||
|
system->getName())) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "ADD/REMOVE GAMES TO THIS GAME COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
|
mWindow, "ADD/REMOVE GAMES TO THIS GAME COLLECTION", 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() && CollectionSystemManager::get()->isEditing())
|
if (UIModeController::getInstance()->isUIModeFull() &&
|
||||||
{
|
CollectionSystemManager::get()->isEditing()) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" + Utils::String::toUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(
|
||||||
|
mWindow, "FINISH EDITING '" + Utils::String::toUpper(
|
||||||
|
CollectionSystemManager::get()->getEditingCollection()) +
|
||||||
|
"' COLLECTION",Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::exitEditMode, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UIModeController::getInstance()->isUIModeFull() && !fromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER))
|
if (UIModeController::getInstance()->isUIModeFull() && !fromPlaceholder &&
|
||||||
{
|
!(mSystem->isCollection() && file->getType() == FOLDER)) {
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(mWindow,
|
||||||
|
"EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
row.addElement(makeArrow(mWindow), false);
|
row.addElement(makeArrow(mWindow), false);
|
||||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||||
mMenu.addRow(row);
|
mMenu.addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
// center the menu
|
// Center the menu.
|
||||||
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() - mMenu.getSize().y()) / 2);
|
mMenu.setPosition((mSize.x() - mMenu.getSize().x()) / 2, (mSize.y() -
|
||||||
|
mMenu.getSize().y()) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuiGamelistOptions::~GuiGamelistOptions()
|
GuiGamelistOptions::~GuiGamelistOptions()
|
||||||
{
|
{
|
||||||
// apply sort
|
|
||||||
if (!fromPlaceholder) {
|
if (!fromPlaceholder) {
|
||||||
FileData* root = mSystem->getRootFolder();
|
FileData* root = mSystem->getRootFolder();
|
||||||
root->sort(*mListSort->getSelected()); // will also recursively sort children
|
|
||||||
|
|
||||||
// notify that the root folder was sorted
|
// If a new sorting type was selected, then sort and update mSortTypeString for the system.
|
||||||
|
if ((*mListSort->getSelected()).description != root->getSortTypeString()) {
|
||||||
|
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
|
||||||
|
// This will also recursively sort children.
|
||||||
|
root->sort(*mListSort->getSelected(), mFavoritesSorting);
|
||||||
|
root->setSortTypeString((*mListSort->getSelected()).description);
|
||||||
|
|
||||||
|
// Select the first row of the gamelist.
|
||||||
|
FileData* firstRow = getGamelist()->getCursor()->getParent()->
|
||||||
|
getChildrenListToDisplay()[0];
|
||||||
|
getGamelist()->setCursor(firstRow);
|
||||||
|
|
||||||
|
// Notify that the root folder was sorted.
|
||||||
getGamelist()->onFileChanged(root, FILE_SORTED);
|
getGamelist()->onFileChanged(root, FILE_SORTED);
|
||||||
}
|
}
|
||||||
if (mFiltersChanged)
|
}
|
||||||
{
|
if (mFiltersChanged) {
|
||||||
// only reload full view if we came from a placeholder
|
// Only reload full view if we came from a placeholder as we need to
|
||||||
// as we need to re-display the remaining elements for whatever new
|
// re-display the remaining elements for whatever new game is selected.
|
||||||
// game is selected
|
|
||||||
ViewController::get()->reloadGameListView(mSystem);
|
ViewController::get()->reloadGameListView(mSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,21 +225,17 @@ void GuiGamelistOptions::openGamelistFilter()
|
||||||
void GuiGamelistOptions::startEditMode()
|
void GuiGamelistOptions::startEditMode()
|
||||||
{
|
{
|
||||||
std::string editingSystem = mSystem->getName();
|
std::string editingSystem = mSystem->getName();
|
||||||
// need to check if we're editing the collections bundle, as we will want to edit the selected collection within
|
// Need to check if we're editing the collections bundle,
|
||||||
if(editingSystem == CollectionSystemManager::get()->getCustomCollectionsBundle()->getName())
|
// as we will want to edit the selected collection within.
|
||||||
{
|
if (editingSystem == CollectionSystemManager::get()->getCustomCollectionsBundle()->getName()) {
|
||||||
FileData* file = getGamelist()->getCursor();
|
FileData* file = getGamelist()->getCursor();
|
||||||
// do we have the cursor on a specific collection?
|
// Do we have the cursor on a specific collection?.
|
||||||
if (file->getType() == FOLDER)
|
if (file->getType() == FOLDER)
|
||||||
{
|
|
||||||
editingSystem = file->getName();
|
editingSystem = file->getName();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
// We are inside a specific collection. We want to edit that one.
|
||||||
// we are inside a specific collection. We want to edit that one.
|
|
||||||
editingSystem = file->getSystem()->getName();
|
editingSystem = file->getSystem()->getName();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
CollectionSystemManager::get()->setEditMode(editingSystem);
|
CollectionSystemManager::get()->setEditMode(editingSystem);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
@ -208,8 +248,8 @@ void GuiGamelistOptions::exitEditMode()
|
||||||
|
|
||||||
void GuiGamelistOptions::openMetaDataEd()
|
void GuiGamelistOptions::openMetaDataEd()
|
||||||
{
|
{
|
||||||
// open metadata editor
|
// Open metadata editor.
|
||||||
// get the FileData that hosts the original metadata
|
// Get the FileData that holds the original metadata.
|
||||||
FileData* file = getGamelist()->getCursor()->getSourceFileData();
|
FileData* file = getGamelist()->getCursor()->getSourceFileData();
|
||||||
ScraperSearchParams p;
|
ScraperSearchParams p;
|
||||||
p.game = file;
|
p.game = file;
|
||||||
|
@ -217,106 +257,63 @@ void GuiGamelistOptions::openMetaDataEd()
|
||||||
|
|
||||||
std::function<void()> deleteBtnFunc;
|
std::function<void()> deleteBtnFunc;
|
||||||
|
|
||||||
if (file->getType() == FOLDER)
|
if (file->getType() == FOLDER) {
|
||||||
{
|
|
||||||
deleteBtnFunc = NULL;
|
deleteBtnFunc = NULL;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
deleteBtnFunc = [this, file] {
|
deleteBtnFunc = [this, file] {
|
||||||
CollectionSystemManager::get()->deleteCollectionFiles(file);
|
CollectionSystemManager::get()->deleteCollectionFiles(file);
|
||||||
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true);
|
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(), p, Utils::FileSystem::getFileName(file->getPath()),
|
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(), p,
|
||||||
std::bind(&IGameListView::onFileChanged, ViewController::get()->getGameListView(file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc));
|
Utils::FileSystem::getFileName(file->getPath()), std::bind(
|
||||||
|
&IGameListView::onFileChanged, ViewController::get()->getGameListView(
|
||||||
|
file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiGamelistOptions::jumpToLetter()
|
void GuiGamelistOptions::jumpToLetter()
|
||||||
{
|
{
|
||||||
char letter = mJumpToLetterList->getSelected()[0];
|
char letter = mJumpToLetterList->getSelected()[0];
|
||||||
IGameListView* gamelist = getGamelist();
|
|
||||||
|
|
||||||
// this is a really shitty way to get a list of files
|
// Get first row of the gamelist.
|
||||||
const std::vector<FileData*>& files = gamelist->getCursor()->getParent()->getChildrenListToDisplay();
|
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
||||||
|
getParent()->getChildrenListToDisplay();
|
||||||
|
|
||||||
long min = 0;
|
for (unsigned int i = 0; i < files.size(); i++) {
|
||||||
long max = (long)files.size() - 1;
|
if (mFavoritesSorting && mSystem->getName() != "favorites") {
|
||||||
long mid = 0;
|
if ((char)toupper(files.at(i)->getSortName()[0]) ==
|
||||||
|
letter && !files.at(i)->getFavorite()) {
|
||||||
while(max >= min)
|
getGamelist()->setCursor(files.at(i));
|
||||||
{
|
|
||||||
mid = ((max - min) / 2) + min;
|
|
||||||
|
|
||||||
// game somehow has no first character to check
|
|
||||||
if(files.at(mid)->getName().empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
char checkLetter = (char)toupper(files.at(mid)->getSortName()[0]);
|
|
||||||
|
|
||||||
if(checkLetter < letter)
|
|
||||||
min = mid + 1;
|
|
||||||
else if(checkLetter > letter || (mid > 0 && (letter == toupper(files.at(mid - 1)->getSortName()[0]))))
|
|
||||||
max = mid - 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// exact match found
|
|
||||||
// step through games to exclude favorites
|
|
||||||
if (firstFavorite != -1)
|
|
||||||
{
|
|
||||||
while(files[mid]->getFavorite())
|
|
||||||
mid++;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
gamelist->setCursor(files.at(mid));
|
if ((char)toupper(files.at(i)->getSortName()[0]) == letter) {
|
||||||
|
getGamelist()->setCursor(files.at(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiGamelistOptions::findFirstFavorite()
|
void GuiGamelistOptions::jumpToFirstRow()
|
||||||
{
|
{
|
||||||
IGameListView* gamelist = getGamelist();
|
// Get first row of the gamelist.
|
||||||
|
const std::vector<FileData*>& files = getGamelist()->getCursor()->
|
||||||
// this is a really shitty way to get a list of files
|
getParent()->getChildrenListToDisplay();
|
||||||
const std::vector<FileData*>& files = gamelist->getCursor()->getParent()->getChildrenListToDisplay();
|
getGamelist()->setCursor(files.at(0));
|
||||||
|
|
||||||
long loop = 0;
|
|
||||||
long max = (long)files.size() - 1;
|
|
||||||
|
|
||||||
// Loop through the game list looking for the first game marked as a favorite
|
|
||||||
while (!files[loop]->getFavorite() and loop < max)
|
|
||||||
loop++;
|
|
||||||
|
|
||||||
// if the last entry in the game list was not a favorite then there were none for this system
|
|
||||||
if (!files[loop]->getFavorite())
|
|
||||||
{
|
|
||||||
firstFavorite = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstFavorite = loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GuiGamelistOptions::jumpToFirstFavorite()
|
|
||||||
{
|
|
||||||
IGameListView* gamelist = getGamelist();
|
|
||||||
|
|
||||||
// this is a really shitty way to get a list of files
|
|
||||||
const std::vector<FileData*>& files = gamelist->getCursor()->getParent()->getChildrenListToDisplay();
|
|
||||||
|
|
||||||
gamelist->setCursor(files.at(firstFavorite));
|
|
||||||
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiGamelistOptions::input(InputConfig* config, Input input)
|
bool GuiGamelistOptions::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if((config->isMappedTo("b", input) || config->isMappedTo("select", input)) && input.value)
|
if ((config->isMappedTo("b", input) ||
|
||||||
{
|
config->isMappedTo("select", input)) && input.value) {
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
//
|
||||||
|
// GuiGamelistOptions.h
|
||||||
|
//
|
||||||
|
// Gamelist options menu for the 'Jump to...' quick selector,
|
||||||
|
// game sorting, game filters, and metadata edit.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#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
|
||||||
|
@ -26,12 +33,11 @@ private:
|
||||||
void openMetaDataEd();
|
void openMetaDataEd();
|
||||||
void startEditMode();
|
void startEditMode();
|
||||||
void exitEditMode();
|
void exitEditMode();
|
||||||
|
|
||||||
void jumpToLetter();
|
void jumpToLetter();
|
||||||
void findFirstFavorite();
|
void jumpToFirstRow();
|
||||||
void jumpToFirstFavorite();
|
|
||||||
|
|
||||||
const std::string FAVORITE_CHAR = "\uF005";
|
const std::string FAVORITE_CHAR = "\uF005";
|
||||||
long firstFavorite = -1;
|
|
||||||
|
|
||||||
MenuComponent mMenu;
|
MenuComponent mMenu;
|
||||||
|
|
||||||
|
@ -43,6 +49,7 @@ private:
|
||||||
|
|
||||||
SystemData* mSystem;
|
SystemData* mSystem;
|
||||||
IGameListView* getGamelist();
|
IGameListView* getGamelist();
|
||||||
|
bool mFavoritesSorting;
|
||||||
bool fromPlaceholder;
|
bool fromPlaceholder;
|
||||||
bool mFiltersChanged;
|
bool mFiltersChanged;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GuiMenu.cpp
|
||||||
|
//
|
||||||
|
// Main menu.
|
||||||
|
//
|
||||||
|
|
||||||
#include "guis/GuiMenu.h"
|
#include "guis/GuiMenu.h"
|
||||||
|
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
|
@ -11,6 +17,7 @@
|
||||||
#include "guis/GuiSettings.h"
|
#include "guis/GuiSettings.h"
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
|
#include "views/gamelist/IGameListView.h"
|
||||||
#include "CollectionSystemManager.h"
|
#include "CollectionSystemManager.h"
|
||||||
#include "EmulationStation.h"
|
#include "EmulationStation.h"
|
||||||
#include "Scripting.h"
|
#include "Scripting.h"
|
||||||
|
@ -20,7 +27,11 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MENU"), mVersion(window)
|
GuiMenu::GuiMenu(
|
||||||
|
Window* window)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mMenu(window, "MAIN MENU"),
|
||||||
|
mVersion(window)
|
||||||
{
|
{
|
||||||
bool isFullUI = UIModeController::getInstance()->isUIModeFull();
|
bool isFullUI = UIModeController::getInstance()->isUIModeFull();
|
||||||
|
|
||||||
|
@ -29,12 +40,12 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
|
|
||||||
addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundSettings(); });
|
addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundSettings(); });
|
||||||
|
|
||||||
|
|
||||||
if (isFullUI)
|
if (isFullUI)
|
||||||
addEntry("UI SETTINGS", 0x777777FF, true, [this] { openUISettings(); });
|
addEntry("UI SETTINGS", 0x777777FF, true, [this] { openUISettings(); });
|
||||||
|
|
||||||
if (isFullUI)
|
if (isFullUI)
|
||||||
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true, [this] { openCollectionSystemSettings(); });
|
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true, [this] {
|
||||||
|
openCollectionSystemSettings(); });
|
||||||
|
|
||||||
if (isFullUI)
|
if (isFullUI)
|
||||||
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherSettings(); });
|
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherSettings(); });
|
||||||
|
@ -47,38 +58,44 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
|
||||||
addChild(&mMenu);
|
addChild(&mMenu);
|
||||||
addVersionInfo();
|
addVersionInfo();
|
||||||
setSize(mMenu.getSize());
|
setSize(mMenu.getSize());
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f);
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
||||||
|
Renderer::getScreenHeight() * 0.15f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMenu::openScraperSettings()
|
void GuiMenu::openScraperSettings()
|
||||||
{
|
{
|
||||||
auto s = new GuiSettings(mWindow, "SCRAPER");
|
auto s = new GuiSettings(mWindow, "SCRAPER");
|
||||||
|
|
||||||
// scrape from
|
// Scrape from.
|
||||||
auto scraper_list = std::make_shared< OptionListComponent< std::string > >(mWindow, "SCRAPE FROM", false);
|
auto scraper_list = std::make_shared< OptionListComponent< std::string >
|
||||||
|
>(mWindow, "SCRAPE FROM", false);
|
||||||
std::vector<std::string> scrapers = getScraperList();
|
std::vector<std::string> scrapers = getScraperList();
|
||||||
|
|
||||||
// Select either the first entry of the one read from the settings, just in case the scraper from settings has vanished.
|
// Select either the first entry of the one read from the settings,
|
||||||
for(auto it = scrapers.cbegin(); it != scrapers.cend(); it++)
|
// just in case the scraper from settings has vanished.
|
||||||
|
for (auto it = scrapers.cbegin(); it != scrapers.cend(); it++)
|
||||||
scraper_list->add(*it, *it, *it == Settings::getInstance()->getString("Scraper"));
|
scraper_list->add(*it, *it, *it == Settings::getInstance()->getString("Scraper"));
|
||||||
|
|
||||||
s->addWithLabel("SCRAPE FROM", scraper_list);
|
s->addWithLabel("SCRAPE FROM", scraper_list);
|
||||||
s->addSaveFunc([scraper_list] { Settings::getInstance()->setString("Scraper", scraper_list->getSelected()); });
|
s->addSaveFunc([scraper_list] { Settings::getInstance()->setString("Scraper",
|
||||||
|
scraper_list->getSelected()); });
|
||||||
|
|
||||||
// scrape ratings
|
// Scrape ratings.
|
||||||
auto scrape_ratings = std::make_shared<SwitchComponent>(mWindow);
|
auto scrape_ratings = std::make_shared<SwitchComponent>(mWindow);
|
||||||
scrape_ratings->setState(Settings::getInstance()->getBool("ScrapeRatings"));
|
scrape_ratings->setState(Settings::getInstance()->getBool("ScrapeRatings"));
|
||||||
s->addWithLabel("SCRAPE RATINGS", scrape_ratings);
|
s->addWithLabel("SCRAPE RATINGS", scrape_ratings);
|
||||||
s->addSaveFunc([scrape_ratings] { Settings::getInstance()->setBool("ScrapeRatings", scrape_ratings->getState()); });
|
s->addSaveFunc([scrape_ratings] { Settings::getInstance()->setBool("ScrapeRatings",
|
||||||
|
scrape_ratings->getState()); });
|
||||||
|
|
||||||
// scrape now
|
// Scrape now.
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
|
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
|
||||||
std::function<void()> openAndSave = openScrapeNow;
|
std::function<void()> openAndSave = openScrapeNow;
|
||||||
openAndSave = [s, openAndSave] { s->save(); openAndSave(); };
|
openAndSave = [s, openAndSave] { s->save(); openAndSave(); };
|
||||||
row.makeAcceptInputHandler(openAndSave);
|
row.makeAcceptInputHandler(openAndSave);
|
||||||
|
|
||||||
auto scrape_now = std::make_shared<TextComponent>(mWindow, "SCRAPE NOW", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
auto scrape_now = std::make_shared<TextComponent>
|
||||||
|
(mWindow, "SCRAPE NOW", Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
|
||||||
auto bracket = makeArrow(mWindow);
|
auto bracket = makeArrow(mWindow);
|
||||||
row.addElement(scrape_now, true);
|
row.addElement(scrape_now, true);
|
||||||
row.addElement(bracket, false);
|
row.addElement(bracket, false);
|
||||||
|
@ -91,24 +108,25 @@ void GuiMenu::openSoundSettings()
|
||||||
{
|
{
|
||||||
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
|
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
|
||||||
|
|
||||||
// volume
|
// System volume.
|
||||||
auto volume = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
auto volume = std::make_shared<SliderComponent>(mWindow, 0.f, 100.f, 1.f, "%");
|
||||||
volume->setValue((float)VolumeControl::getInstance()->getVolume());
|
volume->setValue((float)VolumeControl::getInstance()->getVolume());
|
||||||
s->addWithLabel("SYSTEM VOLUME", volume);
|
s->addWithLabel("SYSTEM VOLUME", volume);
|
||||||
s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)Math::round(volume->getValue())); });
|
s->addSaveFunc([volume] { VolumeControl::getInstance()->
|
||||||
|
setVolume((int)Math::round(volume->getValue())); });
|
||||||
|
|
||||||
if (UIModeController::getInstance()->isUIModeFull())
|
if (UIModeController::getInstance()->isUIModeFull()) {
|
||||||
{
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
// audio card
|
// audio card
|
||||||
auto audio_card = std::make_shared< OptionListComponent<std::string> >(mWindow, "AUDIO CARD", false);
|
auto audio_card = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "AUDIO CARD", false);
|
||||||
std::vector<std::string> audio_cards;
|
std::vector<std::string> audio_cards;
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
// RPi Specific Audio Cards
|
// RPi Specific Audio Cards
|
||||||
audio_cards.push_back("local");
|
audio_cards.push_back("local");
|
||||||
audio_cards.push_back("hdmi");
|
audio_cards.push_back("hdmi");
|
||||||
audio_cards.push_back("both");
|
audio_cards.push_back("both");
|
||||||
#endif
|
#endif
|
||||||
audio_cards.push_back("default");
|
audio_cards.push_back("default");
|
||||||
audio_cards.push_back("sysdefault");
|
audio_cards.push_back("sysdefault");
|
||||||
audio_cards.push_back("dmix");
|
audio_cards.push_back("dmix");
|
||||||
|
@ -116,11 +134,12 @@ void GuiMenu::openSoundSettings()
|
||||||
audio_cards.push_back("plughw");
|
audio_cards.push_back("plughw");
|
||||||
audio_cards.push_back("null");
|
audio_cards.push_back("null");
|
||||||
if (Settings::getInstance()->getString("AudioCard") != "") {
|
if (Settings::getInstance()->getString("AudioCard") != "") {
|
||||||
if(std::find(audio_cards.begin(), audio_cards.end(), Settings::getInstance()->getString("AudioCard")) == audio_cards.end()) {
|
if (std::find(audio_cards.begin(), audio_cards.end(),
|
||||||
|
Settings::getInstance()->getString("AudioCard")) == audio_cards.end()) {
|
||||||
audio_cards.push_back(Settings::getInstance()->getString("AudioCard"));
|
audio_cards.push_back(Settings::getInstance()->getString("AudioCard"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto ac = audio_cards.cbegin(); ac != audio_cards.cend(); ac++)
|
for (auto ac = audio_cards.cbegin(); ac != audio_cards.cend(); ac++)
|
||||||
audio_card->add(*ac, *ac, Settings::getInstance()->getString("AudioCard") == *ac);
|
audio_card->add(*ac, *ac, Settings::getInstance()->getString("AudioCard") == *ac);
|
||||||
s->addWithLabel("AUDIO CARD", audio_card);
|
s->addWithLabel("AUDIO CARD", audio_card);
|
||||||
s->addSaveFunc([audio_card] {
|
s->addSaveFunc([audio_card] {
|
||||||
|
@ -129,8 +148,9 @@ void GuiMenu::openSoundSettings()
|
||||||
VolumeControl::getInstance()->init();
|
VolumeControl::getInstance()->init();
|
||||||
});
|
});
|
||||||
|
|
||||||
// volume control device
|
// Volume control device.
|
||||||
auto vol_dev = std::make_shared< OptionListComponent<std::string> >(mWindow, "AUDIO DEVICE", false);
|
auto vol_dev = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "AUDIO DEVICE", false);
|
||||||
std::vector<std::string> transitions;
|
std::vector<std::string> transitions;
|
||||||
transitions.push_back("PCM");
|
transitions.push_back("PCM");
|
||||||
transitions.push_back("Speaker");
|
transitions.push_back("Speaker");
|
||||||
|
@ -138,11 +158,12 @@ void GuiMenu::openSoundSettings()
|
||||||
transitions.push_back("Digital");
|
transitions.push_back("Digital");
|
||||||
transitions.push_back("Analogue");
|
transitions.push_back("Analogue");
|
||||||
if (Settings::getInstance()->getString("AudioDevice") != "") {
|
if (Settings::getInstance()->getString("AudioDevice") != "") {
|
||||||
if(std::find(transitions.begin(), transitions.end(), Settings::getInstance()->getString("AudioDevice")) == transitions.end()) {
|
if (std::find(transitions.begin(), transitions.end(),
|
||||||
|
Settings::getInstance()->getString("AudioDevice")) == transitions.end()) {
|
||||||
transitions.push_back(Settings::getInstance()->getString("AudioDevice"));
|
transitions.push_back(Settings::getInstance()->getString("AudioDevice"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto it = transitions.cbegin(); it != transitions.cend(); it++)
|
for (auto it = transitions.cbegin(); it != transitions.cend(); it++)
|
||||||
vol_dev->add(*it, *it, Settings::getInstance()->getString("AudioDevice") == *it);
|
vol_dev->add(*it, *it, Settings::getInstance()->getString("AudioDevice") == *it);
|
||||||
s->addWithLabel("AUDIO DEVICE", vol_dev);
|
s->addWithLabel("AUDIO DEVICE", vol_dev);
|
||||||
s->addSaveFunc([vol_dev] {
|
s->addSaveFunc([vol_dev] {
|
||||||
|
@ -152,7 +173,7 @@ void GuiMenu::openSoundSettings()
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// disable sounds
|
// Disable sounds.
|
||||||
auto sounds_enabled = std::make_shared<SwitchComponent>(mWindow);
|
auto sounds_enabled = std::make_shared<SwitchComponent>(mWindow);
|
||||||
sounds_enabled->setState(Settings::getInstance()->getBool("EnableSounds"));
|
sounds_enabled->setState(Settings::getInstance()->getBool("EnableSounds"));
|
||||||
s->addWithLabel("ENABLE NAVIGATION SOUNDS", sounds_enabled);
|
s->addWithLabel("ENABLE NAVIGATION SOUNDS", sounds_enabled);
|
||||||
|
@ -170,11 +191,13 @@ void GuiMenu::openSoundSettings()
|
||||||
auto video_audio = std::make_shared<SwitchComponent>(mWindow);
|
auto video_audio = std::make_shared<SwitchComponent>(mWindow);
|
||||||
video_audio->setState(Settings::getInstance()->getBool("VideoAudio"));
|
video_audio->setState(Settings::getInstance()->getBool("VideoAudio"));
|
||||||
s->addWithLabel("ENABLE VIDEO AUDIO", video_audio);
|
s->addWithLabel("ENABLE VIDEO AUDIO", video_audio);
|
||||||
s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("VideoAudio", video_audio->getState()); });
|
s->addSaveFunc([video_audio] { Settings::getInstance()->setBool("VideoAudio",
|
||||||
|
video_audio->getState()); });
|
||||||
|
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
// OMX player Audio Device
|
// OMX player Audio Device
|
||||||
auto omx_audio_dev = std::make_shared< OptionListComponent<std::string> >(mWindow, "OMX PLAYER AUDIO DEVICE", false);
|
auto omx_audio_dev = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "OMX PLAYER AUDIO DEVICE", false);
|
||||||
std::vector<std::string> omx_cards;
|
std::vector<std::string> omx_cards;
|
||||||
// RPi Specific Audio Cards
|
// RPi Specific Audio Cards
|
||||||
omx_cards.push_back("local");
|
omx_cards.push_back("local");
|
||||||
|
@ -183,7 +206,8 @@ void GuiMenu::openSoundSettings()
|
||||||
omx_cards.push_back("alsa:hw:0,0");
|
omx_cards.push_back("alsa:hw:0,0");
|
||||||
omx_cards.push_back("alsa:hw:1,0");
|
omx_cards.push_back("alsa:hw:1,0");
|
||||||
if (Settings::getInstance()->getString("OMXAudioDev") != "") {
|
if (Settings::getInstance()->getString("OMXAudioDev") != "") {
|
||||||
if (std::find(omx_cards.begin(), omx_cards.end(), Settings::getInstance()->getString("OMXAudioDev")) == omx_cards.end()) {
|
if (std::find(omx_cards.begin(), omx_cards.end(),
|
||||||
|
Settings::getInstance()->getString("OMXAudioDev")) == omx_cards.end()) {
|
||||||
omx_cards.push_back(Settings::getInstance()->getString("OMXAudioDev"));
|
omx_cards.push_back(Settings::getInstance()->getString("OMXAudioDev"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,26 +222,25 @@ void GuiMenu::openSoundSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMenu::openUISettings()
|
void GuiMenu::openUISettings()
|
||||||
{
|
{
|
||||||
auto s = new GuiSettings(mWindow, "UI SETTINGS");
|
auto s = new GuiSettings(mWindow, "UI SETTINGS");
|
||||||
|
|
||||||
//UI mode
|
// UI mode.
|
||||||
auto UImodeSelection = std::make_shared< OptionListComponent<std::string> >(mWindow, "UI MODE", false);
|
auto UImodeSelection = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "UI MODE", false);
|
||||||
std::vector<std::string> UImodes = UIModeController::getInstance()->getUIModes();
|
std::vector<std::string> UImodes = UIModeController::getInstance()->getUIModes();
|
||||||
for (auto it = UImodes.cbegin(); it != UImodes.cend(); it++)
|
for (auto it = UImodes.cbegin(); it != UImodes.cend(); it++)
|
||||||
UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it);
|
UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it);
|
||||||
s->addWithLabel("UI MODE", UImodeSelection);
|
s->addWithLabel("UI MODE", UImodeSelection);
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
s->addSaveFunc([ UImodeSelection, window]
|
s->addSaveFunc([ UImodeSelection, window] {
|
||||||
{
|
|
||||||
std::string selectedMode = UImodeSelection->getSelected();
|
std::string selectedMode = UImodeSelection->getSelected();
|
||||||
if (selectedMode != "Full")
|
if (selectedMode != "Full") {
|
||||||
{
|
std::string msg = "You are changing the UI to a restricted mode:\n" +
|
||||||
std::string msg = "You are changing the UI to a restricted mode:\n" + selectedMode + "\n";
|
selectedMode + "\n";
|
||||||
msg += "This will hide most menu-options to prevent changes to the system.\n";
|
msg += "This will hide most menu-options to prevent changes to the system.\n";
|
||||||
msg += "To unlock and return to the full UI, enter this code: \n";
|
msg += "To unlock and return to the full UI, enter this code: \n";
|
||||||
msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n";
|
msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n";
|
||||||
|
@ -231,109 +254,114 @@ void GuiMenu::openUISettings()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// fullscreen mode
|
// Fullscreen mode.
|
||||||
auto fullscreen_mode = std::make_shared< OptionListComponent<std::string> >(mWindow, "FULLSCREEN MODE", false);
|
auto fullscreen_mode = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "FULLSCREEN MODE", false);
|
||||||
std::vector<std::string> screenmode;
|
std::vector<std::string> screenmode;
|
||||||
screenmode.push_back("normal");
|
screenmode.push_back("normal");
|
||||||
screenmode.push_back("borderless");
|
screenmode.push_back("borderless");
|
||||||
for(auto it = screenmode.cbegin(); it != screenmode.cend(); it++)
|
for (auto it = screenmode.cbegin(); it != screenmode.cend(); it++)
|
||||||
fullscreen_mode->add(*it, *it, Settings::getInstance()->getString("FullscreenMode") == *it);
|
fullscreen_mode->add(*it, *it, Settings::getInstance()->getString("FullscreenMode") == *it);
|
||||||
s->addWithLabel("FULLSCREEN MODE (REQUIRES RESTART)", fullscreen_mode);
|
s->addWithLabel("FULLSCREEN MODE (REQUIRES RESTART)", fullscreen_mode);
|
||||||
s->addSaveFunc([fullscreen_mode] {
|
s->addSaveFunc([fullscreen_mode] {
|
||||||
if (Settings::getInstance()->getString("FullscreenMode") == "normal"
|
if (Settings::getInstance()->getString("FullscreenMode") == "normal"
|
||||||
&& fullscreen_mode->getSelected() != "normal")
|
&& fullscreen_mode->getSelected() != "normal") {
|
||||||
{
|
|
||||||
Settings::getInstance()->setString("PowerSaverMode", "default");
|
Settings::getInstance()->setString("PowerSaverMode", "default");
|
||||||
PowerSaver::init();
|
PowerSaver::init();
|
||||||
}
|
}
|
||||||
Settings::getInstance()->setString("FullscreenMode", fullscreen_mode->getSelected());
|
Settings::getInstance()->setString("FullscreenMode", fullscreen_mode->getSelected());
|
||||||
});
|
});
|
||||||
|
|
||||||
// screensaver
|
// Screensaver.
|
||||||
ComponentListRow screensaver_row;
|
ComponentListRow screensaver_row;
|
||||||
screensaver_row.elements.clear();
|
screensaver_row.elements.clear();
|
||||||
screensaver_row.addElement(std::make_shared<TextComponent>(mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
screensaver_row.addElement(std::make_shared<TextComponent>
|
||||||
|
(mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
screensaver_row.addElement(makeArrow(mWindow), false);
|
screensaver_row.addElement(makeArrow(mWindow), false);
|
||||||
screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
|
screensaver_row.makeAcceptInputHandler(std::bind(&GuiMenu::openScreensaverOptions, this));
|
||||||
s->addRow(screensaver_row);
|
s->addRow(screensaver_row);
|
||||||
|
|
||||||
// quick system select (left/right in game list view)
|
// Quick system select (left/right in game list view).
|
||||||
auto quick_sys_select = std::make_shared<SwitchComponent>(mWindow);
|
auto quick_sys_select = std::make_shared<SwitchComponent>(mWindow);
|
||||||
quick_sys_select->setState(Settings::getInstance()->getBool("QuickSystemSelect"));
|
quick_sys_select->setState(Settings::getInstance()->getBool("QuickSystemSelect"));
|
||||||
s->addWithLabel("QUICK SYSTEM SELECT", quick_sys_select);
|
s->addWithLabel("QUICK SYSTEM SELECT", quick_sys_select);
|
||||||
s->addSaveFunc([quick_sys_select] { Settings::getInstance()->setBool("QuickSystemSelect", quick_sys_select->getState()); });
|
s->addSaveFunc([quick_sys_select] { Settings::getInstance()->setBool("QuickSystemSelect",
|
||||||
|
quick_sys_select->getState()); });
|
||||||
|
|
||||||
// carousel transition option
|
// Carousel transition option.
|
||||||
auto move_carousel = std::make_shared<SwitchComponent>(mWindow);
|
auto move_carousel = std::make_shared<SwitchComponent>(mWindow);
|
||||||
move_carousel->setState(Settings::getInstance()->getBool("MoveCarousel"));
|
move_carousel->setState(Settings::getInstance()->getBool("MoveCarousel"));
|
||||||
s->addWithLabel("CAROUSEL TRANSITIONS", move_carousel);
|
s->addWithLabel("CAROUSEL TRANSITIONS", move_carousel);
|
||||||
s->addSaveFunc([move_carousel] {
|
s->addSaveFunc([move_carousel] {
|
||||||
if (move_carousel->getState()
|
if (move_carousel->getState()
|
||||||
&& !Settings::getInstance()->getBool("MoveCarousel")
|
&& !Settings::getInstance()->getBool("MoveCarousel")
|
||||||
&& PowerSaver::getMode() == PowerSaver::INSTANT)
|
&& PowerSaver::getMode() == PowerSaver::INSTANT) {
|
||||||
{
|
|
||||||
Settings::getInstance()->setString("PowerSaverMode", "default");
|
Settings::getInstance()->setString("PowerSaverMode", "default");
|
||||||
PowerSaver::init();
|
PowerSaver::init();
|
||||||
}
|
}
|
||||||
Settings::getInstance()->setBool("MoveCarousel", move_carousel->getState());
|
Settings::getInstance()->setBool("MoveCarousel", move_carousel->getState());
|
||||||
});
|
});
|
||||||
|
|
||||||
// transition style
|
// Transition style.
|
||||||
auto transition_style = std::make_shared< OptionListComponent<std::string> >(mWindow, "TRANSITION STYLE", false);
|
auto transition_style = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "TRANSITION STYLE", false);
|
||||||
std::vector<std::string> transitions;
|
std::vector<std::string> transitions;
|
||||||
transitions.push_back("fade");
|
transitions.push_back("fade");
|
||||||
transitions.push_back("slide");
|
transitions.push_back("slide");
|
||||||
transitions.push_back("instant");
|
transitions.push_back("instant");
|
||||||
for(auto it = transitions.cbegin(); it != transitions.cend(); it++)
|
for (auto it = transitions.cbegin(); it != transitions.cend(); it++)
|
||||||
transition_style->add(*it, *it, Settings::getInstance()->getString("TransitionStyle") == *it);
|
transition_style->add(*it, *it, Settings::getInstance()->
|
||||||
|
getString("TransitionStyle") == *it);
|
||||||
s->addWithLabel("TRANSITION STYLE", transition_style);
|
s->addWithLabel("TRANSITION STYLE", transition_style);
|
||||||
s->addSaveFunc([transition_style] {
|
s->addSaveFunc([transition_style] {
|
||||||
if (Settings::getInstance()->getString("TransitionStyle") == "instant"
|
if (Settings::getInstance()->getString("TransitionStyle") == "instant"
|
||||||
&& transition_style->getSelected() != "instant"
|
&& transition_style->getSelected() != "instant"
|
||||||
&& PowerSaver::getMode() == PowerSaver::INSTANT)
|
&& PowerSaver::getMode() == PowerSaver::INSTANT) {
|
||||||
{
|
|
||||||
Settings::getInstance()->setString("PowerSaverMode", "default");
|
Settings::getInstance()->setString("PowerSaverMode", "default");
|
||||||
PowerSaver::init();
|
PowerSaver::init();
|
||||||
}
|
}
|
||||||
Settings::getInstance()->setString("TransitionStyle", transition_style->getSelected());
|
Settings::getInstance()->setString("TransitionStyle", transition_style->getSelected());
|
||||||
});
|
});
|
||||||
|
|
||||||
// theme set
|
// Theme selection.
|
||||||
auto themeSets = ThemeData::getThemeSets();
|
auto themeSets = ThemeData::getThemeSets();
|
||||||
|
|
||||||
if(!themeSets.empty())
|
if (!themeSets.empty())
|
||||||
{
|
{
|
||||||
std::map<std::string, ThemeSet>::const_iterator selectedSet = themeSets.find(Settings::getInstance()->getString("ThemeSet"));
|
std::map<std::string, ThemeSet>::const_iterator selectedSet =
|
||||||
if(selectedSet == themeSets.cend())
|
themeSets.find(Settings::getInstance()->getString("ThemeSet"));
|
||||||
|
if (selectedSet == themeSets.cend())
|
||||||
selectedSet = themeSets.cbegin();
|
selectedSet = themeSets.cbegin();
|
||||||
|
|
||||||
auto theme_set = std::make_shared< OptionListComponent<std::string> >(mWindow, "THEME SET", false);
|
auto theme_set = std::make_shared< OptionListComponent<std::string>
|
||||||
for(auto it = themeSets.cbegin(); it != themeSets.cend(); it++)
|
>(mWindow, "THEME SET", false);
|
||||||
|
for (auto it = themeSets.cbegin(); it != themeSets.cend(); it++)
|
||||||
theme_set->add(it->first, it->first, it == selectedSet);
|
theme_set->add(it->first, it->first, it == selectedSet);
|
||||||
s->addWithLabel("THEME SET", theme_set);
|
s->addWithLabel("THEME SET", theme_set);
|
||||||
|
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
s->addSaveFunc([window, theme_set]
|
s->addSaveFunc([window, theme_set] {
|
||||||
{
|
|
||||||
bool needReload = false;
|
bool needReload = false;
|
||||||
std::string oldTheme = Settings::getInstance()->getString("ThemeSet");
|
std::string oldTheme = Settings::getInstance()->getString("ThemeSet");
|
||||||
if(oldTheme != theme_set->getSelected())
|
if (oldTheme != theme_set->getSelected())
|
||||||
needReload = true;
|
needReload = true;
|
||||||
|
|
||||||
Settings::getInstance()->setString("ThemeSet", theme_set->getSelected());
|
Settings::getInstance()->setString("ThemeSet", theme_set->getSelected());
|
||||||
|
|
||||||
if(needReload)
|
if (needReload)
|
||||||
{
|
{
|
||||||
Scripting::fireEvent("theme-changed", theme_set->getSelected(), oldTheme);
|
Scripting::fireEvent("theme-changed", theme_set->getSelected(), oldTheme);
|
||||||
CollectionSystemManager::get()->updateSystemsList();
|
CollectionSystemManager::get()->updateSystemsList();
|
||||||
ViewController::get()->goToStart();
|
ViewController::get()->goToStart();
|
||||||
ViewController::get()->reloadAll(); // TODO - replace this with some sort of signal-based implementation
|
// TODO - replace this with some sort of signal-based implementation.
|
||||||
|
ViewController::get()->reloadAll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// GameList view style
|
// GameList view style.
|
||||||
auto gamelist_style = std::make_shared< OptionListComponent<std::string> >(mWindow, "GAMELIST VIEW STYLE", false);
|
auto gamelist_style = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "GAMELIST VIEW STYLE", false);
|
||||||
std::vector<std::string> styles;
|
std::vector<std::string> styles;
|
||||||
styles.push_back("automatic");
|
styles.push_back("automatic");
|
||||||
styles.push_back("basic");
|
styles.push_back("basic");
|
||||||
|
@ -342,92 +370,121 @@ void GuiMenu::openUISettings()
|
||||||
styles.push_back("grid");
|
styles.push_back("grid");
|
||||||
|
|
||||||
for (auto it = styles.cbegin(); it != styles.cend(); it++)
|
for (auto it = styles.cbegin(); it != styles.cend(); it++)
|
||||||
gamelist_style->add(*it, *it, Settings::getInstance()->getString("GamelistViewStyle") == *it);
|
gamelist_style->add(*it, *it, Settings::getInstance()->
|
||||||
|
getString("GamelistViewStyle") == *it);
|
||||||
s->addWithLabel("GAMELIST VIEW STYLE", gamelist_style);
|
s->addWithLabel("GAMELIST VIEW STYLE", gamelist_style);
|
||||||
s->addSaveFunc([gamelist_style] {
|
s->addSaveFunc([gamelist_style] {
|
||||||
bool needReload = false;
|
bool needReload = false;
|
||||||
if (Settings::getInstance()->getString("GamelistViewStyle") != gamelist_style->getSelected())
|
if (Settings::getInstance()->getString("GamelistViewStyle") !=
|
||||||
|
gamelist_style->getSelected())
|
||||||
needReload = true;
|
needReload = true;
|
||||||
Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected());
|
Settings::getInstance()->setString("GamelistViewStyle", gamelist_style->getSelected());
|
||||||
if (needReload)
|
if (needReload)
|
||||||
ViewController::get()->reloadAll();
|
ViewController::get()->reloadAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optionally start in selected system
|
// Optionally start in selected system.
|
||||||
auto systemfocus_list = std::make_shared< OptionListComponent<std::string> >(mWindow, "START ON SYSTEM", false);
|
auto systemfocus_list = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "START ON SYSTEM", false);
|
||||||
systemfocus_list->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == "");
|
systemfocus_list->add("NONE", "", Settings::getInstance()->getString("StartupSystem") == "");
|
||||||
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); it++)
|
for (auto it = SystemData::sSystemVector.cbegin();
|
||||||
{
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
if ("retropie" != (*it)->getName())
|
if ("retropie" != (*it)->getName())
|
||||||
{
|
systemfocus_list->add((*it)->getName(), (*it)->getName(),
|
||||||
systemfocus_list->add((*it)->getName(), (*it)->getName(), Settings::getInstance()->getString("StartupSystem") == (*it)->getName());
|
Settings::getInstance()->getString("StartupSystem") == (*it)->getName());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
s->addWithLabel("START ON SYSTEM", systemfocus_list);
|
s->addWithLabel("START ON SYSTEM", systemfocus_list);
|
||||||
s->addSaveFunc([systemfocus_list] {
|
s->addSaveFunc([systemfocus_list] {
|
||||||
Settings::getInstance()->setString("StartupSystem", systemfocus_list->getSelected());
|
Settings::getInstance()->setString("StartupSystem", systemfocus_list->getSelected());
|
||||||
});
|
});
|
||||||
|
|
||||||
// show help
|
// Show help.
|
||||||
auto show_help = std::make_shared<SwitchComponent>(mWindow);
|
auto show_help = std::make_shared<SwitchComponent>(mWindow);
|
||||||
show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts"));
|
show_help->setState(Settings::getInstance()->getBool("ShowHelpPrompts"));
|
||||||
s->addWithLabel("ON-SCREEN HELP", show_help);
|
s->addWithLabel("ON-SCREEN HELP", show_help);
|
||||||
s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", show_help->getState()); });
|
s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts",
|
||||||
|
show_help->getState()); });
|
||||||
|
|
||||||
// enable filters (ForceDisableFilters)
|
// Enable filters (ForceDisableFilters).
|
||||||
auto enable_filter = std::make_shared<SwitchComponent>(mWindow);
|
auto enable_filter = std::make_shared<SwitchComponent>(mWindow);
|
||||||
enable_filter->setState(!Settings::getInstance()->getBool("ForceDisableFilters"));
|
enable_filter->setState(!Settings::getInstance()->getBool("ForceDisableFilters"));
|
||||||
s->addWithLabel("ENABLE FILTERS", enable_filter);
|
s->addWithLabel("ENABLE GAMELIST FILTERS", enable_filter);
|
||||||
s->addSaveFunc([enable_filter] {
|
s->addSaveFunc([enable_filter] {
|
||||||
bool filter_is_enabled = !Settings::getInstance()->getBool("ForceDisableFilters");
|
bool filter_is_enabled = !Settings::getInstance()->getBool("ForceDisableFilters");
|
||||||
Settings::getInstance()->setBool("ForceDisableFilters", !enable_filter->getState());
|
Settings::getInstance()->setBool("ForceDisableFilters", !enable_filter->getState());
|
||||||
if (enable_filter->getState() != filter_is_enabled) ViewController::get()->ReloadAndGoToStart();
|
if (enable_filter->getState() != filter_is_enabled)
|
||||||
|
ViewController::get()->ReloadAndGoToStart();
|
||||||
});
|
});
|
||||||
|
|
||||||
// hide start menu in Kid Mode
|
// Hide start menu in Kid Mode.
|
||||||
auto disable_start = std::make_shared<SwitchComponent>(mWindow);
|
auto disable_start = std::make_shared<SwitchComponent>(mWindow);
|
||||||
disable_start->setState(Settings::getInstance()->getBool("DisableKidStartMenu"));
|
disable_start->setState(Settings::getInstance()->getBool("DisableKidStartMenu"));
|
||||||
s->addWithLabel("DISABLE START MENU IN KID MODE", disable_start);
|
s->addWithLabel("DISABLE START MENU IN KID MODE", disable_start);
|
||||||
s->addSaveFunc([disable_start] { Settings::getInstance()->setBool("DisableKidStartMenu", disable_start->getState()); });
|
s->addSaveFunc([disable_start] { Settings::getInstance()->setBool("DisableKidStartMenu",
|
||||||
|
disable_start->getState()); });
|
||||||
|
|
||||||
// hide Reboot System option in the Quit menu
|
// Hide Reboot System option in the quit menu.
|
||||||
auto show_rebootsystem = std::make_shared<SwitchComponent>(mWindow);
|
auto show_rebootsystem = std::make_shared<SwitchComponent>(mWindow);
|
||||||
show_rebootsystem->setState(Settings::getInstance()->getBool("ShowRebootSystem"));
|
show_rebootsystem->setState(Settings::getInstance()->getBool("ShowRebootSystem"));
|
||||||
s->addWithLabel("SHOW \"REBOOT SYSTEM\" MENU ENTRY", show_rebootsystem);
|
s->addWithLabel("SHOW \"REBOOT SYSTEM\" MENU ENTRY", show_rebootsystem);
|
||||||
s->addSaveFunc([show_rebootsystem] { Settings::getInstance()->setBool("ShowRebootSystem", show_rebootsystem->getState()); });
|
s->addSaveFunc([show_rebootsystem] { Settings::getInstance()->setBool("ShowRebootSystem",
|
||||||
|
show_rebootsystem->getState()); });
|
||||||
|
|
||||||
// hide Power Off System option in the Quit menu
|
// Hide Power Off System option in the quit menu.
|
||||||
auto show_poweroffsystem = std::make_shared<SwitchComponent>(mWindow);
|
auto show_poweroffsystem = std::make_shared<SwitchComponent>(mWindow);
|
||||||
show_poweroffsystem->setState(Settings::getInstance()->getBool("ShowPoweroffSystem"));
|
show_poweroffsystem->setState(Settings::getInstance()->getBool("ShowPoweroffSystem"));
|
||||||
s->addWithLabel("SHOW \"POWER OFF SYSTEM\" MENU ENTRY", show_poweroffsystem);
|
s->addWithLabel("SHOW \"POWER OFF SYSTEM\" MENU ENTRY", show_poweroffsystem);
|
||||||
s->addSaveFunc([show_poweroffsystem] { Settings::getInstance()->setBool("ShowPoweroffSystem", show_poweroffsystem->getState()); });
|
s->addSaveFunc([show_poweroffsystem] { Settings::getInstance()->setBool("ShowPoweroffSystem",
|
||||||
|
show_poweroffsystem->getState()); });
|
||||||
|
|
||||||
// Show favorites first in gamelists
|
// Sort favorites on top of the gamelists.
|
||||||
auto favoritesFirstSwitch = std::make_shared<SwitchComponent>(mWindow);
|
auto favoritesFirstSwitch = std::make_shared<SwitchComponent>(mWindow);
|
||||||
favoritesFirstSwitch->setState(Settings::getInstance()->getBool("FavoritesFirst"));
|
favoritesFirstSwitch->setState(Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
s->addWithLabel("SHOW FAVORITES ON TOP OF GAMELIST", favoritesFirstSwitch);
|
s->addWithLabel("SORT FAVORITES ON TOP OF GAMELISTS", favoritesFirstSwitch);
|
||||||
s->addSaveFunc([favoritesFirstSwitch]
|
s->addSaveFunc([favoritesFirstSwitch] {
|
||||||
{
|
|
||||||
if (Settings::getInstance()->setBool("FavoritesFirst", favoritesFirstSwitch->getState()))
|
if (Settings::getInstance()->setBool("FavoritesFirst", favoritesFirstSwitch->getState()))
|
||||||
ViewController::get()->reloadAll();
|
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
||||||
|
SystemData::sSystemVector.cend(); it++) {
|
||||||
|
|
||||||
|
// The favorites and recent gamelists never sort favorites on top.
|
||||||
|
if ((*it)->getName() == "favorites" || (*it)->getName() == "recent")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Don't re-sort custom collections as they have their own option
|
||||||
|
// for whether to sort favorites on top or not (FavFirstCustom).
|
||||||
|
if (CollectionSystemManager::get()->getIsCustomCollection((*it)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FileData* rootFolder = (*it)->getRootFolder();
|
||||||
|
|
||||||
|
rootFolder->sort(getSortTypeFromString(rootFolder->getSortTypeString()),
|
||||||
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
|
ViewController::get()->reloadGameListView(*it);
|
||||||
|
|
||||||
|
// Jump to the first row of the game list.
|
||||||
|
IGameListView* gameList = ViewController::get()->getGameListView((*it)).get();
|
||||||
|
FileData* firstRow = gameList->getCursor()->getParent()->getChildrenListToDisplay()[0];
|
||||||
|
gameList->setCursor(firstRow);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMenu::openOtherSettings()
|
void GuiMenu::openOtherSettings()
|
||||||
{
|
{
|
||||||
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
||||||
|
|
||||||
// maximum vram
|
// Maximum VRAM.
|
||||||
auto max_vram = std::make_shared<SliderComponent>(mWindow, 0.f, 1000.f, 10.f, "Mb");
|
auto max_vram = std::make_shared<SliderComponent>(mWindow, 0.f, 1000.f, 10.f, "Mb");
|
||||||
max_vram->setValue((float)(Settings::getInstance()->getInt("MaxVRAM")));
|
max_vram->setValue((float)(Settings::getInstance()->getInt("MaxVRAM")));
|
||||||
s->addWithLabel("VRAM LIMIT", max_vram);
|
s->addWithLabel("VRAM LIMIT", max_vram);
|
||||||
s->addSaveFunc([max_vram] { Settings::getInstance()->setInt("MaxVRAM", (int)Math::round(max_vram->getValue())); });
|
s->addSaveFunc([max_vram] { Settings::getInstance()->setInt("MaxVRAM",
|
||||||
|
(int)Math::round(max_vram->getValue())); });
|
||||||
|
|
||||||
// power saver
|
// Power saver.
|
||||||
auto power_saver = std::make_shared< OptionListComponent<std::string> >(mWindow, "POWER SAVER MODES", false);
|
auto power_saver = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "POWER SAVER MODES", false);
|
||||||
std::vector<std::string> modes;
|
std::vector<std::string> modes;
|
||||||
modes.push_back("disabled");
|
modes.push_back("disabled");
|
||||||
modes.push_back("default");
|
modes.push_back("default");
|
||||||
|
@ -437,7 +494,8 @@ void GuiMenu::openOtherSettings()
|
||||||
power_saver->add(*it, *it, Settings::getInstance()->getString("PowerSaverMode") == *it);
|
power_saver->add(*it, *it, Settings::getInstance()->getString("PowerSaverMode") == *it);
|
||||||
s->addWithLabel("POWER SAVER MODES", power_saver);
|
s->addWithLabel("POWER SAVER MODES", power_saver);
|
||||||
s->addSaveFunc([this, power_saver] {
|
s->addSaveFunc([this, power_saver] {
|
||||||
if (Settings::getInstance()->getString("PowerSaverMode") != "instant" && power_saver->getSelected() == "instant") {
|
if (Settings::getInstance()->getString("PowerSaverMode") !=
|
||||||
|
"instant" && power_saver->getSelected() == "instant") {
|
||||||
Settings::getInstance()->setString("TransitionStyle", "instant");
|
Settings::getInstance()->setString("TransitionStyle", "instant");
|
||||||
Settings::getInstance()->setBool("MoveCarousel", false);
|
Settings::getInstance()->setBool("MoveCarousel", false);
|
||||||
Settings::getInstance()->setBool("EnableSounds", false);
|
Settings::getInstance()->setBool("EnableSounds", false);
|
||||||
|
@ -446,15 +504,17 @@ void GuiMenu::openOtherSettings()
|
||||||
PowerSaver::init();
|
PowerSaver::init();
|
||||||
});
|
});
|
||||||
|
|
||||||
// gamelists
|
// Gamelists.
|
||||||
auto gamelistsSaveMode = std::make_shared< OptionListComponent<std::string> >(mWindow, "SAVE METADATA", false);
|
auto gamelistsSaveMode = std::make_shared< OptionListComponent<std::string>
|
||||||
|
>(mWindow, "SAVE METADATA", false);
|
||||||
std::vector<std::string> saveModes;
|
std::vector<std::string> saveModes;
|
||||||
saveModes.push_back("on exit");
|
saveModes.push_back("on exit");
|
||||||
saveModes.push_back("always");
|
saveModes.push_back("always");
|
||||||
saveModes.push_back("never");
|
saveModes.push_back("never");
|
||||||
|
|
||||||
for(auto it = saveModes.cbegin(); it != saveModes.cend(); it++)
|
for (auto it = saveModes.cbegin(); it != saveModes.cend(); it++)
|
||||||
gamelistsSaveMode->add(*it, *it, Settings::getInstance()->getString("SaveGamelistsMode") == *it);
|
gamelistsSaveMode->add(*it, *it, Settings::getInstance()->
|
||||||
|
getString("SaveGamelistsMode") == *it);
|
||||||
s->addWithLabel("SAVE METADATA", gamelistsSaveMode);
|
s->addWithLabel("SAVE METADATA", gamelistsSaveMode);
|
||||||
s->addSaveFunc([gamelistsSaveMode] {
|
s->addSaveFunc([gamelistsSaveMode] {
|
||||||
Settings::getInstance()->setString("SaveGamelistsMode", gamelistsSaveMode->getSelected());
|
Settings::getInstance()->setString("SaveGamelistsMode", gamelistsSaveMode->getSelected());
|
||||||
|
@ -463,51 +523,56 @@ void GuiMenu::openOtherSettings()
|
||||||
auto parse_gamelists = std::make_shared<SwitchComponent>(mWindow);
|
auto parse_gamelists = std::make_shared<SwitchComponent>(mWindow);
|
||||||
parse_gamelists->setState(Settings::getInstance()->getBool("ParseGamelistOnly"));
|
parse_gamelists->setState(Settings::getInstance()->getBool("ParseGamelistOnly"));
|
||||||
s->addWithLabel("PARSE GAMESLISTS ONLY", parse_gamelists);
|
s->addWithLabel("PARSE GAMESLISTS ONLY", parse_gamelists);
|
||||||
s->addSaveFunc([parse_gamelists] { Settings::getInstance()->setBool("ParseGamelistOnly", parse_gamelists->getState()); });
|
s->addSaveFunc([parse_gamelists] { Settings::getInstance()->
|
||||||
|
setBool("ParseGamelistOnly", parse_gamelists->getState()); });
|
||||||
|
|
||||||
auto local_art = std::make_shared<SwitchComponent>(mWindow);
|
auto local_art = std::make_shared<SwitchComponent>(mWindow);
|
||||||
local_art->setState(Settings::getInstance()->getBool("LocalArt"));
|
local_art->setState(Settings::getInstance()->getBool("LocalArt"));
|
||||||
s->addWithLabel("SEARCH FOR LOCAL ART", local_art);
|
s->addWithLabel("SEARCH FOR LOCAL ART", local_art);
|
||||||
s->addSaveFunc([local_art] { Settings::getInstance()->setBool("LocalArt", local_art->getState()); });
|
s->addSaveFunc([local_art] { Settings::getInstance()->
|
||||||
|
setBool("LocalArt", local_art->getState()); });
|
||||||
|
|
||||||
// Allow overriding of the launch string per game (the option to disable this is intended primarily for testing purposes)
|
// Allow overriding of the launch string per game (the option
|
||||||
|
// to disable this is intended primarily for testing purposes).
|
||||||
auto launchstring_override = std::make_shared<SwitchComponent>(mWindow);
|
auto launchstring_override = std::make_shared<SwitchComponent>(mWindow);
|
||||||
launchstring_override->setState(Settings::getInstance()->getBool("LaunchstringOverride"));
|
launchstring_override->setState(Settings::getInstance()->getBool("LaunchstringOverride"));
|
||||||
s->addWithLabel("PER GAME OVERRIDE OF LAUNCH STRING", launchstring_override);
|
s->addWithLabel("PER GAME LAUNCH STRING OVERRIDE", launchstring_override);
|
||||||
s->addSaveFunc([launchstring_override] { Settings::getInstance()->setBool("LaunchstringOverride", launchstring_override->getState()); });
|
s->addSaveFunc([launchstring_override] { Settings::getInstance()->
|
||||||
|
setBool("LaunchstringOverride", launchstring_override->getState()); });
|
||||||
|
|
||||||
// hidden files
|
// Hidden files.
|
||||||
auto hidden_files = std::make_shared<SwitchComponent>(mWindow);
|
auto hidden_files = std::make_shared<SwitchComponent>(mWindow);
|
||||||
hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles"));
|
hidden_files->setState(Settings::getInstance()->getBool("ShowHiddenFiles"));
|
||||||
s->addWithLabel("SHOW HIDDEN FILES", hidden_files);
|
s->addWithLabel("SHOW HIDDEN FILES", hidden_files);
|
||||||
s->addSaveFunc([hidden_files] { Settings::getInstance()->setBool("ShowHiddenFiles", hidden_files->getState()); });
|
s->addSaveFunc([hidden_files] { Settings::getInstance()->setBool("ShowHiddenFiles",
|
||||||
|
hidden_files->getState()); });
|
||||||
|
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
// Video Player - VideoOmxPlayer
|
// Video Player - VideoOmxPlayer.
|
||||||
auto omx_player = std::make_shared<SwitchComponent>(mWindow);
|
auto omx_player = std::make_shared<SwitchComponent>(mWindow);
|
||||||
omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer"));
|
omx_player->setState(Settings::getInstance()->getBool("VideoOmxPlayer"));
|
||||||
s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", omx_player);
|
s->addWithLabel("USE OMX PLAYER (HW ACCELERATED)", omx_player);
|
||||||
s->addSaveFunc([omx_player]
|
s->addSaveFunc([omx_player]
|
||||||
{
|
{
|
||||||
// need to reload all views to re-create the right video components
|
// Need to reload all views to re-create the right video components.
|
||||||
bool needReload = false;
|
bool needReload = false;
|
||||||
if(Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState())
|
if (Settings::getInstance()->getBool("VideoOmxPlayer") != omx_player->getState())
|
||||||
needReload = true;
|
needReload = true;
|
||||||
|
|
||||||
Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState());
|
Settings::getInstance()->setBool("VideoOmxPlayer", omx_player->getState());
|
||||||
|
|
||||||
if(needReload)
|
if (needReload)
|
||||||
ViewController::get()->reloadAll();
|
ViewController::get()->reloadAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// framerate
|
// Framerate.
|
||||||
auto framerate = std::make_shared<SwitchComponent>(mWindow);
|
auto framerate = std::make_shared<SwitchComponent>(mWindow);
|
||||||
framerate->setState(Settings::getInstance()->getBool("DrawFramerate"));
|
framerate->setState(Settings::getInstance()->getBool("DrawFramerate"));
|
||||||
s->addWithLabel("SHOW FRAMERATE", framerate);
|
s->addWithLabel("SHOW FRAMERATE", framerate);
|
||||||
s->addSaveFunc([framerate] { Settings::getInstance()->setBool("DrawFramerate", framerate->getState()); });
|
s->addSaveFunc([framerate] { Settings::getInstance()->setBool("DrawFramerate",
|
||||||
|
framerate->getState()); });
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
|
|
||||||
|
@ -521,7 +586,6 @@ void GuiMenu::openConfigInput()
|
||||||
window->pushGui(new GuiDetectDevice(window, false, nullptr));
|
window->pushGui(new GuiDetectDevice(window, false, nullptr));
|
||||||
}, "NO", nullptr)
|
}, "NO", nullptr)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMenu::openQuitMenu()
|
void GuiMenu::openQuitMenu()
|
||||||
|
@ -531,10 +595,8 @@ void GuiMenu::openQuitMenu()
|
||||||
Window* window = mWindow;
|
Window* window = mWindow;
|
||||||
|
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
if (UIModeController::getInstance()->isUIModeFull())
|
if (UIModeController::getInstance()->isUIModeFull()) {
|
||||||
{
|
if (Settings::getInstance()->getBool("ShowExit")) {
|
||||||
if(Settings::getInstance()->getBool("ShowExit"))
|
|
||||||
{
|
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
|
||||||
[] {
|
[] {
|
||||||
|
@ -542,13 +604,13 @@ void GuiMenu::openQuitMenu()
|
||||||
quitES();
|
quitES();
|
||||||
}, "NO", nullptr));
|
}, "NO", nullptr));
|
||||||
});
|
});
|
||||||
row.addElement(std::make_shared<TextComponent>(window, "QUIT EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(window, "QUIT EMULATIONSTATION",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
s->addRow(row);
|
s->addRow(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("ShowRebootSystem"))
|
if (Settings::getInstance()->getBool("ShowRebootSystem")) {
|
||||||
{
|
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY REBOOT?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY REBOOT?", "YES",
|
||||||
|
@ -559,12 +621,12 @@ void GuiMenu::openQuitMenu()
|
||||||
LOG(LogWarning) << "Reboot terminated with non-zero result!";
|
LOG(LogWarning) << "Reboot terminated with non-zero result!";
|
||||||
}, "NO", nullptr));
|
}, "NO", nullptr));
|
||||||
});
|
});
|
||||||
row.addElement(std::make_shared<TextComponent>(window, "REBOOT SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(window, "REBOOT SYSTEM",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
s->addRow(row);
|
s->addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("ShowPoweroffSystem"))
|
if (Settings::getInstance()->getBool("ShowPoweroffSystem")) {
|
||||||
{
|
|
||||||
row.elements.clear();
|
row.elements.clear();
|
||||||
row.makeAcceptInputHandler([window] {
|
row.makeAcceptInputHandler([window] {
|
||||||
window->pushGui(new GuiMsgBox(window, "REALLY POWER OFF?", "YES",
|
window->pushGui(new GuiMsgBox(window, "REALLY POWER OFF?", "YES",
|
||||||
|
@ -575,7 +637,8 @@ void GuiMenu::openQuitMenu()
|
||||||
LOG(LogWarning) << "Power off terminated with non-zero result!";
|
LOG(LogWarning) << "Power off terminated with non-zero result!";
|
||||||
}, "NO", nullptr));
|
}, "NO", nullptr));
|
||||||
});
|
});
|
||||||
row.addElement(std::make_shared<TextComponent>(window, "POWER OFF SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
row.addElement(std::make_shared<TextComponent>(window, "POWER OFF SYSTEM",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
s->addRow(row);
|
s->addRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,8 +647,6 @@ void GuiMenu::openQuitMenu()
|
||||||
|
|
||||||
void GuiMenu::addVersionInfo()
|
void GuiMenu::addVersionInfo()
|
||||||
{
|
{
|
||||||
// std::string buildDate = (Settings::getInstance()->getBool("Debug") ? std::string( " (" + Utils::String::toUpper(PROGRAM_BUILT_STRING) + ")") : (""));
|
|
||||||
|
|
||||||
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
|
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
|
||||||
mVersion.setColor(0x5E5E5EFF);
|
mVersion.setColor(0x5E5E5EFF);
|
||||||
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING));
|
mVersion.setText("EMULATIONSTATION-DE V" + Utils::String::toUpper(PROGRAM_VERSION_STRING));
|
||||||
|
@ -607,16 +668,19 @@ void GuiMenu::onSizeChanged()
|
||||||
mVersion.setPosition(0, mSize.y() - mVersion.getSize().y());
|
mVersion.setPosition(0, mSize.y() - mVersion.getSize().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func)
|
void GuiMenu::addEntry(
|
||||||
|
const char* name,
|
||||||
|
unsigned int color,
|
||||||
|
bool add_arrow,
|
||||||
|
const std::function<void()>& func)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
|
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
|
||||||
|
|
||||||
// populate the list
|
// Populate the list.
|
||||||
ComponentListRow row;
|
ComponentListRow row;
|
||||||
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
|
row.addElement(std::make_shared<TextComponent>(mWindow, name, font, color), true);
|
||||||
|
|
||||||
if(add_arrow)
|
if (add_arrow) {
|
||||||
{
|
|
||||||
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
|
std::shared_ptr<ImageComponent> bracket = makeArrow(mWindow);
|
||||||
row.addElement(bracket, false);
|
row.addElement(bracket, false);
|
||||||
}
|
}
|
||||||
|
@ -628,11 +692,11 @@ void GuiMenu::addEntry(const char* name, unsigned int color, bool add_arrow, con
|
||||||
|
|
||||||
bool GuiMenu::input(InputConfig* config, Input input)
|
bool GuiMenu::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(GuiComponent::input(config, input))
|
if (GuiComponent::input(config, input))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if((config->isMappedTo("b", input) || config->isMappedTo("start", input)) && input.value != 0)
|
if ((config->isMappedTo("b", input) || config->isMappedTo("start", input)) &&
|
||||||
{
|
input.value != 0) {
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GuiMenu.h
|
||||||
|
//
|
||||||
|
// Main menu.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#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
|
||||||
|
@ -16,7 +22,8 @@ public:
|
||||||
HelpStyle getHelpStyle() override;
|
HelpStyle getHelpStyle() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
|
void addEntry(const char* name, unsigned int color,
|
||||||
|
bool add_arrow, const std::function<void()>& func);
|
||||||
void addVersionInfo();
|
void addVersionInfo();
|
||||||
void openCollectionSystemSettings();
|
void openCollectionSystemSettings();
|
||||||
void openConfigInput();
|
void openConfigInput();
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
//
|
||||||
|
// ViewController.cpp
|
||||||
|
//
|
||||||
|
// Handles overall system navigation including animations and transitions.
|
||||||
|
// Also creates the gamelist views and handles refresh and reloads of these when needed
|
||||||
|
// (for example when metadata has been changed or when a list sorting has taken place).
|
||||||
|
// Initiates the launching of games, calling FileData to do the actual launch.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
#include "animations/Animation.h"
|
#include "animations/Animation.h"
|
||||||
|
@ -18,7 +27,7 @@
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
ViewController* ViewController::sInstance = NULL;
|
ViewController* ViewController::sInstance = nullptr;
|
||||||
NavigationSounds navigationsounds;
|
NavigationSounds navigationsounds;
|
||||||
|
|
||||||
ViewController* ViewController::get()
|
ViewController* ViewController::get()
|
||||||
|
@ -33,8 +42,13 @@ void ViewController::init(Window* window)
|
||||||
sInstance = new ViewController(window);
|
sInstance = new ViewController(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewController::ViewController(Window* window)
|
ViewController::ViewController(
|
||||||
: GuiComponent(window), mCurrentView(nullptr), mCamera(Transform4x4f::Identity()), mFadeOpacity(0), mLockInput(false)
|
Window* window)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mCurrentView(nullptr),
|
||||||
|
mCamera(Transform4x4f::Identity()),
|
||||||
|
mFadeOpacity(0),
|
||||||
|
mLockInput(false)
|
||||||
{
|
{
|
||||||
mState.viewing = NOTHING;
|
mState.viewing = NOTHING;
|
||||||
}
|
}
|
||||||
|
@ -42,24 +56,23 @@ ViewController::ViewController(Window* window)
|
||||||
ViewController::~ViewController()
|
ViewController::~ViewController()
|
||||||
{
|
{
|
||||||
assert(sInstance == this);
|
assert(sInstance == this);
|
||||||
sInstance = NULL;
|
sInstance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::goToStart()
|
void ViewController::goToStart()
|
||||||
{
|
{
|
||||||
// If specific system is requested, go directly to the 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(); it != SystemData::sSystemVector.cend(); it++){
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
if ((*it)->getName() == requestedSystem)
|
if ((*it)->getName() == requestedSystem) {
|
||||||
{
|
|
||||||
goToGameList(*it);
|
goToGameList(*it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requested system doesn't exist
|
// Requested system doesn't exist.
|
||||||
Settings::getInstance()->setString("StartupSystem", "");
|
Settings::getInstance()->setString("StartupSystem", "");
|
||||||
}
|
}
|
||||||
goToSystemView(SystemData::sSystemVector.at(0));
|
goToSystemView(SystemData::sSystemVector.at(0));
|
||||||
|
@ -80,17 +93,16 @@ int ViewController::getSystemId(SystemData* system)
|
||||||
|
|
||||||
void ViewController::goToSystemView(SystemData* system)
|
void ViewController::goToSystemView(SystemData* system)
|
||||||
{
|
{
|
||||||
// Tell any current view it's about to be hidden
|
// Tell any current view it's about to be hidden.
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
{
|
|
||||||
mCurrentView->onHide();
|
mCurrentView->onHide();
|
||||||
}
|
|
||||||
|
|
||||||
mState.viewing = SYSTEM_SELECT;
|
mState.viewing = SYSTEM_SELECT;
|
||||||
mState.system = system;
|
mState.system = system;
|
||||||
|
|
||||||
auto systemList = getSystemListView();
|
auto systemList = getSystemListView();
|
||||||
systemList->setPosition(getSystemId(system) * (float)Renderer::getScreenWidth(), systemList->getPosition().y());
|
systemList->setPosition(getSystemId(system) * (float)Renderer::getScreenWidth(),
|
||||||
|
systemList->getPosition().y());
|
||||||
|
|
||||||
systemList->goToSystem(system, false);
|
systemList->goToSystem(system, false);
|
||||||
mCurrentView = systemList;
|
mCurrentView = systemList;
|
||||||
|
@ -120,13 +132,14 @@ void ViewController::goToPrevGameList()
|
||||||
|
|
||||||
void ViewController::goToGameList(SystemData* system)
|
void ViewController::goToGameList(SystemData* system)
|
||||||
{
|
{
|
||||||
if(mState.viewing == SYSTEM_SELECT)
|
if (mState.viewing == SYSTEM_SELECT) {
|
||||||
{
|
// Move system list.
|
||||||
// move system list
|
|
||||||
auto sysList = getSystemListView();
|
auto sysList = getSystemListView();
|
||||||
float offX = sysList->getPosition().x();
|
float offX = sysList->getPosition().x();
|
||||||
int sysId = getSystemId(system);
|
int sysId = getSystemId(system);
|
||||||
sysList->setPosition(sysId * (float)Renderer::getScreenWidth(), sysList->getPosition().y());
|
|
||||||
|
sysList->setPosition(sysId * (float)Renderer::getScreenWidth(),
|
||||||
|
sysList->getPosition().y());
|
||||||
offX = sysList->getPosition().x() - offX;
|
offX = sysList->getPosition().x() - offX;
|
||||||
mCamera.translation().x() -= offX;
|
mCamera.translation().x() -= offX;
|
||||||
}
|
}
|
||||||
|
@ -135,67 +148,65 @@ void ViewController::goToGameList(SystemData* system)
|
||||||
mState.system = system;
|
mState.system = system;
|
||||||
|
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
{
|
|
||||||
mCurrentView->onHide();
|
mCurrentView->onHide();
|
||||||
}
|
|
||||||
mCurrentView = getGameListView(system);
|
mCurrentView = getGameListView(system);
|
||||||
|
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
{
|
|
||||||
mCurrentView->onShow();
|
mCurrentView->onShow();
|
||||||
}
|
|
||||||
playViewTransition();
|
playViewTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::playViewTransition()
|
void ViewController::playViewTransition()
|
||||||
{
|
{
|
||||||
Vector3f target(Vector3f::Zero());
|
Vector3f target(Vector3f::Zero());
|
||||||
if(mCurrentView)
|
if (mCurrentView)
|
||||||
target = mCurrentView->getPosition();
|
target = mCurrentView->getPosition();
|
||||||
|
|
||||||
// no need to animate, we're not going anywhere (probably goToNextGamelist() or goToPrevGamelist() when there's only 1 system)
|
// No need to animate, we're not going anywhere (probably due to goToNextGamelist()
|
||||||
if(target == -mCamera.translation() && !isAnimationPlaying(0))
|
// or goToPrevGamelist() being called when there's only 1 system).
|
||||||
|
if (target == -mCamera.translation() && !isAnimationPlaying(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||||
if(transition_style == "fade")
|
|
||||||
{
|
if (transition_style == "fade") {
|
||||||
// fade
|
// Fade.
|
||||||
// stop whatever's currently playing, leaving mFadeOpacity wherever it is
|
// Stop whatever's currently playing, leaving mFadeOpacity wherever it is.
|
||||||
cancelAnimation(0);
|
cancelAnimation(0);
|
||||||
|
|
||||||
auto fadeFunc = [this](float t) {
|
auto fadeFunc = [this](float t) {
|
||||||
mFadeOpacity = Math::lerp(0, 1, t);
|
mFadeOpacity = Math::lerp(0, 1, t);
|
||||||
};
|
};
|
||||||
|
|
||||||
const static int FADE_DURATION = 240; // fade in/out time
|
const static int FADE_DURATION = 240; // Fade in/out time.
|
||||||
const static int FADE_WAIT = 320; // time to wait between in/out
|
const static int FADE_WAIT = 320; // Time to wait between in/out.
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0, [this, fadeFunc, target] {
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0, [this, fadeFunc, target] {
|
||||||
this->mCamera.translation() = -target;
|
this->mCamera.translation() = -target;
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT, nullptr, true);
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT, nullptr, 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()) {
|
||||||
{
|
// Not changing screens, so cancel the first half entirely.
|
||||||
// not changing screens, so cancel the first half entirely
|
|
||||||
advanceAnimation(0, FADE_DURATION);
|
advanceAnimation(0, FADE_DURATION);
|
||||||
advanceAnimation(0, FADE_WAIT);
|
advanceAnimation(0, FADE_WAIT);
|
||||||
advanceAnimation(0, FADE_DURATION - (int)(mFadeOpacity * FADE_DURATION));
|
advanceAnimation(0, FADE_DURATION - (int)(mFadeOpacity * FADE_DURATION));
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
advanceAnimation(0, (int)(mFadeOpacity * FADE_DURATION));
|
advanceAnimation(0, (int)(mFadeOpacity * FADE_DURATION));
|
||||||
}
|
}
|
||||||
} else if (transition_style == "slide"){
|
}
|
||||||
// slide or simple slide
|
else if (transition_style == "slide") {
|
||||||
|
// Slide or simple slide.
|
||||||
setAnimation(new MoveCameraAnimation(mCamera, target));
|
setAnimation(new MoveCameraAnimation(mCamera, target));
|
||||||
updateHelpPrompts(); // update help prompts immediately
|
updateHelpPrompts(); // Update help prompts immediately.
|
||||||
} else {
|
}
|
||||||
// instant
|
else {
|
||||||
setAnimation(new LambdaAnimation(
|
// Instant.
|
||||||
[this, target](float /*t*/)
|
setAnimation(new LambdaAnimation([this, target](float /*t*/) {
|
||||||
{
|
this->mCamera.translation() = -target; }, 1));
|
||||||
this->mCamera.translation() = -target;
|
|
||||||
}, 1));
|
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,19 +214,18 @@ void ViewController::playViewTransition()
|
||||||
void ViewController::onFileChanged(FileData* file, FileChangeType change)
|
void ViewController::onFileChanged(FileData* file, FileChangeType change)
|
||||||
{
|
{
|
||||||
auto it = mGameListViews.find(file->getSystem());
|
auto it = mGameListViews.find(file->getSystem());
|
||||||
if(it != mGameListViews.cend())
|
if (it != mGameListViews.cend())
|
||||||
it->second->onFileChanged(file, change);
|
it->second->onFileChanged(file, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::launch(FileData* game, Vector3f center)
|
void ViewController::launch(FileData* game, Vector3f center)
|
||||||
{
|
{
|
||||||
if(game->getType() != GAME)
|
if (game->getType() != GAME) {
|
||||||
{
|
|
||||||
LOG(LogError) << "tried to launch something that isn't a game";
|
LOG(LogError) << "tried to launch something that isn't a game";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the current view
|
// Hide the current view.
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
mCurrentView->onHide();
|
mCurrentView->onHide();
|
||||||
|
|
||||||
|
@ -223,47 +233,51 @@ void ViewController::launch(FileData* game, Vector3f center)
|
||||||
origCamera.translation() = -mCurrentView->getPosition();
|
origCamera.translation() = -mCurrentView->getPosition();
|
||||||
|
|
||||||
center += mCurrentView->getPosition();
|
center += mCurrentView->getPosition();
|
||||||
stopAnimation(1); // make sure the fade in isn't still playing
|
stopAnimation(1); // Make sure the fade in isn't still playing.
|
||||||
mWindow->stopInfoPopup(); // make sure we disable any existing info popup
|
mWindow->stopInfoPopup(); // Make sure we disable any existing info popup.
|
||||||
mLockInput = true;
|
mLockInput = true;
|
||||||
|
|
||||||
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
std::string transition_style = Settings::getInstance()->getString("TransitionStyle");
|
||||||
|
|
||||||
navigationsounds.playThemeNavigationSound(LAUNCHSOUND);
|
navigationsounds.playThemeNavigationSound(LAUNCHSOUND);
|
||||||
// let launch sound play to the end before launching game
|
// Let launch sound play to the end before launching game.
|
||||||
while(navigationsounds.isPlayingThemeNavigationSound(LAUNCHSOUND));
|
while(navigationsounds.isPlayingThemeNavigationSound(LAUNCHSOUND));
|
||||||
|
|
||||||
if(transition_style == "fade")
|
if (transition_style == "fade") {
|
||||||
{
|
// Fade out, launch game, fade back in.
|
||||||
// fade out, launch game, fade back in
|
|
||||||
auto fadeFunc = [this](float t) {
|
auto fadeFunc = [this](float t) {
|
||||||
mFadeOpacity = Math::lerp(0.0f, 1.0f, t);
|
mFadeOpacity = Math::lerp(0.0f, 1.0f, t);
|
||||||
};
|
};
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this, game, fadeFunc]
|
setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this, game, fadeFunc] {
|
||||||
{
|
|
||||||
game->launchGame(mWindow);
|
game->launchGame(mWindow);
|
||||||
setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this] { mLockInput = false; }, true);
|
setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this] {
|
||||||
|
mLockInput = false; }, true);
|
||||||
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
mCurrentView->onShow();
|
mCurrentView->onShow();
|
||||||
});
|
});
|
||||||
} else if (transition_style == "slide"){
|
}
|
||||||
// move camera to zoom in on center + fade out, launch game, come back in
|
else if (transition_style == "slide") {
|
||||||
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 1500), 0, [this, origCamera, center, game]
|
// Move camera to zoom in on center + fade out, launch game, come back in.
|
||||||
{
|
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 1500), 0,
|
||||||
|
[this, origCamera, center, game] {
|
||||||
game->launchGame(mWindow);
|
game->launchGame(mWindow);
|
||||||
mCamera = origCamera;
|
mCamera = origCamera;
|
||||||
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 600), 0, [this] { mLockInput = false; }, true);
|
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 600), 0, [this] {
|
||||||
|
mLockInput = false; }, true);
|
||||||
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
mCurrentView->onShow();
|
mCurrentView->onShow();
|
||||||
});
|
});
|
||||||
} else { // instant
|
}
|
||||||
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, [this, origCamera, center, game]
|
// Instant
|
||||||
{
|
else {
|
||||||
|
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0,
|
||||||
|
[this, origCamera, center, game] {
|
||||||
game->launchGame(mWindow);
|
game->launchGame(mWindow);
|
||||||
mCamera = origCamera;
|
mCamera = origCamera;
|
||||||
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, [this] { mLockInput = false; }, true);
|
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0,
|
||||||
|
[this] { mLockInput = false; }, true);
|
||||||
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
this->onFileChanged(game, FILE_METADATA_CHANGED);
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
mCurrentView->onShow();
|
mCurrentView->onShow();
|
||||||
|
@ -273,10 +287,8 @@ void ViewController::launch(FileData* game, Vector3f center)
|
||||||
|
|
||||||
void ViewController::removeGameListView(SystemData* system)
|
void ViewController::removeGameListView(SystemData* system)
|
||||||
{
|
{
|
||||||
//if we already made one, return that one
|
|
||||||
auto exists = mGameListViews.find(system);
|
auto exists = mGameListViews.find(system);
|
||||||
if(exists != mGameListViews.cend())
|
if (exists != mGameListViews.cend()) {
|
||||||
{
|
|
||||||
exists->second.reset();
|
exists->second.reset();
|
||||||
mGameListViews.erase(system);
|
mGameListViews.erase(system);
|
||||||
}
|
}
|
||||||
|
@ -284,18 +296,18 @@ void ViewController::removeGameListView(SystemData* system)
|
||||||
|
|
||||||
std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system)
|
std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system)
|
||||||
{
|
{
|
||||||
//if we already made one, return that one
|
// If we already made one, return that one.
|
||||||
auto exists = mGameListViews.find(system);
|
auto exists = mGameListViews.find(system);
|
||||||
if(exists != mGameListViews.cend())
|
if (exists != mGameListViews.cend())
|
||||||
return exists->second;
|
return exists->second;
|
||||||
|
|
||||||
system->getIndex()->setUIModeFilters();
|
system->getIndex()->setUIModeFilters();
|
||||||
//if we didn't, make it, remember it, and return it
|
// If we didn't, make it, remember it, and return it.
|
||||||
std::shared_ptr<IGameListView> view;
|
std::shared_ptr<IGameListView> view;
|
||||||
|
|
||||||
bool themeHasVideoView = system->getTheme()->hasView("video");
|
bool themeHasVideoView = system->getTheme()->hasView("video");
|
||||||
|
|
||||||
//decide type
|
// Decide type.
|
||||||
GameListViewType selectedViewType = AUTOMATIC;
|
GameListViewType selectedViewType = AUTOMATIC;
|
||||||
|
|
||||||
std::string viewPreference = Settings::getInstance()->getString("GamelistViewStyle");
|
std::string viewPreference = Settings::getInstance()->getString("GamelistViewStyle");
|
||||||
|
@ -308,39 +320,39 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
||||||
if (viewPreference.compare("video") == 0)
|
if (viewPreference.compare("video") == 0)
|
||||||
selectedViewType = VIDEO;
|
selectedViewType = VIDEO;
|
||||||
|
|
||||||
if (selectedViewType == AUTOMATIC)
|
if (selectedViewType == AUTOMATIC) {
|
||||||
{
|
|
||||||
std::vector<FileData*> files = system->getRootFolder()->getFilesRecursive(GAME | FOLDER);
|
std::vector<FileData*> files = system->getRootFolder()->getFilesRecursive(GAME | FOLDER);
|
||||||
for (auto it = files.cbegin(); it != files.cend(); it++)
|
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
||||||
{
|
if (themeHasVideoView && !(*it)->getVideoPath().empty()) {
|
||||||
if (themeHasVideoView && !(*it)->getVideoPath().empty())
|
|
||||||
{
|
|
||||||
selectedViewType = VIDEO;
|
selectedViewType = VIDEO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (!(*it)->getThumbnailPath().empty())
|
else if (!(*it)->getThumbnailPath().empty()) {
|
||||||
{
|
|
||||||
selectedViewType = DETAILED;
|
selectedViewType = DETAILED;
|
||||||
// Don't break out in case any subsequent files have video
|
// Don't break out in case any subsequent files have videos.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the view
|
// Create the view.
|
||||||
switch (selectedViewType)
|
switch (selectedViewType)
|
||||||
{
|
{
|
||||||
case VIDEO:
|
case VIDEO:
|
||||||
view = std::shared_ptr<IGameListView>(new VideoGameListView(mWindow, system->getRootFolder()));
|
view = std::shared_ptr<IGameListView>(
|
||||||
|
new VideoGameListView(mWindow, system->getRootFolder()));
|
||||||
break;
|
break;
|
||||||
case DETAILED:
|
case DETAILED:
|
||||||
view = std::shared_ptr<IGameListView>(new DetailedGameListView(mWindow, system->getRootFolder()));
|
view = std::shared_ptr<IGameListView>(
|
||||||
|
new DetailedGameListView(mWindow, system->getRootFolder()));
|
||||||
break;
|
break;
|
||||||
case GRID:
|
case GRID:
|
||||||
view = std::shared_ptr<IGameListView>(new GridGameListView(mWindow, system->getRootFolder()));
|
view = std::shared_ptr<IGameListView>(
|
||||||
|
new GridGameListView(mWindow, system->getRootFolder()));
|
||||||
break;
|
break;
|
||||||
case BASIC:
|
case BASIC:
|
||||||
default:
|
default:
|
||||||
view = std::shared_ptr<IGameListView>(new BasicGameListView(mWindow, system->getRootFolder()));
|
view = std::shared_ptr<IGameListView>(
|
||||||
|
new BasicGameListView(mWindow, system->getRootFolder()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,7 +360,8 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
||||||
|
|
||||||
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
||||||
int id = (int)(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
int id = (int)(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
||||||
view->setPosition(id * (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight() * 2);
|
view->setPosition(id * (float)Renderer::getScreenWidth(),
|
||||||
|
(float)Renderer::getScreenHeight() * 2);
|
||||||
|
|
||||||
addChild(view.get());
|
addChild(view.get());
|
||||||
|
|
||||||
|
@ -358,8 +371,8 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
||||||
|
|
||||||
std::shared_ptr<SystemView> ViewController::getSystemListView()
|
std::shared_ptr<SystemView> ViewController::getSystemListView()
|
||||||
{
|
{
|
||||||
//if we already made one, return that one
|
// If we already made one, return that one.
|
||||||
if(mSystemListView)
|
if (mSystemListView)
|
||||||
return mSystemListView;
|
return mSystemListView;
|
||||||
|
|
||||||
mSystemListView = std::shared_ptr<SystemView>(new SystemView(mWindow));
|
mSystemListView = std::shared_ptr<SystemView>(new SystemView(mWindow));
|
||||||
|
@ -371,23 +384,22 @@ std::shared_ptr<SystemView> ViewController::getSystemListView()
|
||||||
|
|
||||||
bool ViewController::input(InputConfig* config, Input input)
|
bool ViewController::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(mLockInput)
|
if (mLockInput)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// open menu
|
// Open menu.
|
||||||
if(!(UIModeController::getInstance()->isUIModeKid() && Settings::getInstance()->getBool("DisableKidStartMenu")) && config->isMappedTo("start", input) && input.value != 0)
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
||||||
{
|
Settings::getInstance()->getBool("DisableKidStartMenu")) &&
|
||||||
// open menu
|
config->isMappedTo("start", input) && input.value != 0) {
|
||||||
mWindow->pushGui(new GuiMenu(mWindow));
|
mWindow->pushGui(new GuiMenu(mWindow));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(UIModeController::getInstance()->listen(config, input)) // check if UI mode has changed due to passphrase completion
|
// Check if UI mode has changed due to passphrase completion.
|
||||||
{
|
if (UIModeController::getInstance()->listen(config, input))
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if(mCurrentView)
|
if (mCurrentView)
|
||||||
return mCurrentView->input(config, input);
|
return mCurrentView->input(config, input);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -395,10 +407,8 @@ bool ViewController::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
void ViewController::update(int deltaTime)
|
void ViewController::update(int deltaTime)
|
||||||
{
|
{
|
||||||
if(mCurrentView)
|
if (mCurrentView)
|
||||||
{
|
|
||||||
mCurrentView->update(deltaTime);
|
mCurrentView->update(deltaTime);
|
||||||
}
|
|
||||||
|
|
||||||
updateSelf(deltaTime);
|
updateSelf(deltaTime);
|
||||||
}
|
}
|
||||||
|
@ -409,48 +419,48 @@ void ViewController::render(const Transform4x4f& parentTrans)
|
||||||
Transform4x4f transInverse;
|
Transform4x4f transInverse;
|
||||||
transInverse.invert(trans);
|
transInverse.invert(trans);
|
||||||
|
|
||||||
// camera position, position + size
|
// Camera position, position + size.
|
||||||
Vector3f viewStart = transInverse.translation();
|
Vector3f viewStart = transInverse.translation();
|
||||||
Vector3f viewEnd = transInverse * Vector3f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), 0);
|
Vector3f viewEnd = transInverse * Vector3f((float)Renderer::getScreenWidth(),
|
||||||
|
(float)Renderer::getScreenHeight(), 0);
|
||||||
|
|
||||||
// Keep track of UI mode changes.
|
// Keep track of UI mode changes.
|
||||||
UIModeController::getInstance()->monitorUIMode();
|
UIModeController::getInstance()->monitorUIMode();
|
||||||
|
|
||||||
// draw systemview
|
// Draw system view.
|
||||||
getSystemListView()->render(trans);
|
getSystemListView()->render(trans);
|
||||||
|
|
||||||
// draw gamelists
|
// Draw gamelists.
|
||||||
for(auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++) {
|
||||||
{
|
// Clipping.
|
||||||
// clipping
|
|
||||||
Vector3f guiStart = it->second->getPosition();
|
Vector3f guiStart = it->second->getPosition();
|
||||||
Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(), it->second->getSize().y(), 0);
|
Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(),
|
||||||
|
it->second->getSize().y(), 0);
|
||||||
|
|
||||||
if(guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() &&
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mWindow->peekGui() == this)
|
if (mWindow->peekGui() == this)
|
||||||
mWindow->renderHelpPromptsEarly();
|
mWindow->renderHelpPromptsEarly();
|
||||||
|
|
||||||
// fade out
|
// Fade out.
|
||||||
if(mFadeOpacity)
|
if (mFadeOpacity) {
|
||||||
{
|
|
||||||
unsigned int fadeColor = 0x00000000 | (unsigned char)(mFadeOpacity * 255);
|
unsigned int fadeColor = 0x00000000 | (unsigned char)(mFadeOpacity * 255);
|
||||||
Renderer::setMatrix(parentTrans);
|
Renderer::setMatrix(parentTrans);
|
||||||
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), fadeColor, fadeColor);
|
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
|
||||||
|
Renderer::getScreenHeight(), fadeColor, fadeColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::preload()
|
void ViewController::preload()
|
||||||
{
|
{
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for(auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); it++)
|
for (auto it = SystemData::sSystemVector.cbegin();
|
||||||
{
|
it != SystemData::sSystemVector.cend(); it++) {
|
||||||
if(Settings::getInstance()->getBool("SplashScreen") &&
|
if (Settings::getInstance()->getBool("SplashScreen") &&
|
||||||
Settings::getInstance()->getBool("SplashScreenProgress"))
|
Settings::getInstance()->getBool("SplashScreenProgress")) {
|
||||||
{
|
|
||||||
i++;
|
i++;
|
||||||
char buffer[100];
|
char buffer[100];
|
||||||
sprintf (buffer, "Loading '%s' (%d/%d)",
|
sprintf (buffer, "Loading '%s' (%d/%d)",
|
||||||
|
@ -461,80 +471,74 @@ void ViewController::preload()
|
||||||
(*it)->getIndex()->resetFilters();
|
(*it)->getIndex()->resetFilters();
|
||||||
getGameListView(*it);
|
getGameListView(*it);
|
||||||
}
|
}
|
||||||
// load navigation sounds
|
// Load navigation sounds.
|
||||||
navigationsounds.loadThemeNavigationSounds(SystemData::sSystemVector[0]->getTheme());
|
navigationsounds.loadThemeNavigationSounds(SystemData::sSystemVector[0]->getTheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
|
void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
|
||||||
{
|
{
|
||||||
for(auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++) {
|
||||||
{
|
if (it->second.get() == view) {
|
||||||
if(it->second.get() == view)
|
|
||||||
{
|
|
||||||
bool isCurrent = (mCurrentView == it->second);
|
bool isCurrent = (mCurrentView == it->second);
|
||||||
SystemData* system = it->first;
|
SystemData* system = it->first;
|
||||||
FileData* cursor = view->getCursor();
|
FileData* cursor = view->getCursor();
|
||||||
mGameListViews.erase(it);
|
mGameListViews.erase(it);
|
||||||
|
|
||||||
if(reloadTheme)
|
if (reloadTheme)
|
||||||
system->loadTheme();
|
system->loadTheme();
|
||||||
system->getIndex()->setUIModeFilters();
|
system->getIndex()->setUIModeFilters();
|
||||||
std::shared_ptr<IGameListView> newView = getGameListView(system);
|
std::shared_ptr<IGameListView> newView = getGameListView(system);
|
||||||
|
|
||||||
// to counter having come from a placeholder
|
// To counter having come from a placeholder.
|
||||||
if (!cursor->isPlaceHolder()) {
|
if (!cursor->isPlaceHolder()) {
|
||||||
newView->setCursor(cursor);
|
newView->setCursor(cursor);
|
||||||
}
|
}
|
||||||
if(isCurrent)
|
if (isCurrent)
|
||||||
mCurrentView = newView;
|
mCurrentView = newView;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Redisplay the current view
|
// Redisplay the current view.
|
||||||
if (mCurrentView)
|
if (mCurrentView)
|
||||||
mCurrentView->onShow();
|
mCurrentView->onShow();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewController::reloadAll()
|
void ViewController::reloadAll()
|
||||||
{
|
{
|
||||||
// clear all gamelistviews
|
// Clear all GameListViews.
|
||||||
std::map<SystemData*, FileData*> cursorMap;
|
std::map<SystemData*, FileData*> cursorMap;
|
||||||
for(auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
|
||||||
{
|
|
||||||
cursorMap[it->first] = it->second->getCursor();
|
cursorMap[it->first] = it->second->getCursor();
|
||||||
}
|
|
||||||
mGameListViews.clear();
|
mGameListViews.clear();
|
||||||
|
|
||||||
|
// Load themes, create GameListViews and reset filters.
|
||||||
// load themes, create gamelistviews and reset filters
|
for (auto it = cursorMap.cbegin(); it != cursorMap.cend(); it++) {
|
||||||
for(auto it = cursorMap.cbegin(); it != cursorMap.cend(); it++)
|
|
||||||
{
|
|
||||||
it->first->loadTheme();
|
it->first->loadTheme();
|
||||||
it->first->getIndex()->resetFilters();
|
it->first->getIndex()->resetFilters();
|
||||||
getGameListView(it->first)->setCursor(it->second);
|
getGameListView(it->first)->setCursor(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild SystemListView
|
// Rebuild SystemListView.
|
||||||
mSystemListView.reset();
|
mSystemListView.reset();
|
||||||
getSystemListView();
|
getSystemListView();
|
||||||
|
|
||||||
// update mCurrentView since the pointers changed
|
// Update mCurrentView since the pointers changed.
|
||||||
if(mState.viewing == GAME_LIST)
|
if (mState.viewing == GAME_LIST) {
|
||||||
{
|
|
||||||
mCurrentView = getGameListView(mState.getSystem());
|
mCurrentView = getGameListView(mState.getSystem());
|
||||||
}else if(mState.viewing == SYSTEM_SELECT)
|
}
|
||||||
{
|
else if (mState.viewing == SYSTEM_SELECT) {
|
||||||
SystemData* system = mState.getSystem();
|
SystemData* system = mState.getSystem();
|
||||||
goToSystemView(SystemData::sSystemVector.front());
|
goToSystemView(SystemData::sSystemVector.front());
|
||||||
mSystemListView->goToSystem(system, false);
|
mSystemListView->goToSystem(system, false);
|
||||||
mCurrentView = mSystemListView;
|
mCurrentView = mSystemListView;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
goToSystemView(SystemData::sSystemVector.front());
|
goToSystemView(SystemData::sSystemVector.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
// load navigation sounds
|
// Load navigation sounds.
|
||||||
navigationsounds.loadThemeNavigationSounds(SystemData::sSystemVector[0]->getTheme());
|
navigationsounds.loadThemeNavigationSounds(SystemData::sSystemVector[0]->getTheme());
|
||||||
|
|
||||||
updateHelpPrompts();
|
updateHelpPrompts();
|
||||||
|
@ -543,19 +547,19 @@ void ViewController::reloadAll()
|
||||||
std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts;
|
std::vector<HelpPrompt> prompts;
|
||||||
if(!mCurrentView)
|
if (!mCurrentView)
|
||||||
return prompts;
|
return prompts;
|
||||||
|
|
||||||
prompts = mCurrentView->getHelpPrompts();
|
prompts = mCurrentView->getHelpPrompts();
|
||||||
if(!(UIModeController::getInstance()->isUIModeKid() && Settings::getInstance()->getBool("DisableKidStartMenu")))
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
||||||
|
Settings::getInstance()->getBool("DisableKidStartMenu")))
|
||||||
prompts.push_back(HelpPrompt("start", "menu"));
|
prompts.push_back(HelpPrompt("start", "menu"));
|
||||||
|
|
||||||
return prompts;
|
return prompts;
|
||||||
}
|
}
|
||||||
|
|
||||||
HelpStyle ViewController::getHelpStyle()
|
HelpStyle ViewController::getHelpStyle()
|
||||||
{
|
{
|
||||||
if(!mCurrentView)
|
if (!mCurrentView)
|
||||||
return GuiComponent::getHelpStyle();
|
return GuiComponent::getHelpStyle();
|
||||||
|
|
||||||
return mCurrentView->getHelpStyle();
|
return mCurrentView->getHelpStyle();
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
//
|
||||||
|
// ViewController.h
|
||||||
|
//
|
||||||
|
// Handles overall system navigation including animations and transitions.
|
||||||
|
// Also creates the gamelist views and handles refresh and reloads of these when needed
|
||||||
|
// (for example when metadata has been changed or when a list sorting has taken place).
|
||||||
|
// Initiates the launching of games, calling FileData to do the actual launch.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#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
|
||||||
|
@ -11,7 +20,8 @@ class IGameListView;
|
||||||
class SystemData;
|
class SystemData;
|
||||||
class SystemView;
|
class SystemView;
|
||||||
|
|
||||||
// Used to smoothly transition the camera between multiple views (e.g. from system to system, from gamelist to gamelist).
|
// Handles transitions between views, e.g. from system to system and from gamelist to gamelist.
|
||||||
|
// Also sets up the initial gamelists and refreshes and reloads them as required.
|
||||||
class ViewController : public GuiComponent
|
class ViewController : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -27,8 +37,11 @@ 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) { reloadGameListView(getGameListView(system).get(), reloadTheme); }
|
inline void reloadGameListView(SystemData* system, bool reloadTheme = false)
|
||||||
void reloadAll(); // Reload everything with a theme. Used when the "ThemeSet" setting changes.
|
{ reloadGameListView(getGameListView(system).get(), reloadTheme); }
|
||||||
|
// Reload everything with a theme.
|
||||||
|
// Used when the "ThemeSet" setting changes.
|
||||||
|
void reloadAll();
|
||||||
|
|
||||||
// Navigation.
|
// Navigation.
|
||||||
void goToNextGameList();
|
void goToNextGameList();
|
||||||
|
@ -42,22 +55,21 @@ public:
|
||||||
|
|
||||||
// Plays a nice launch effect and launches the game at the end of it.
|
// Plays a nice launch effect and launches the game at the end of it.
|
||||||
// Once the game terminates, plays a return effect.
|
// Once the game terminates, plays a return effect.
|
||||||
void launch(FileData* game, Vector3f centerCameraOn = Vector3f(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0));
|
void launch(FileData* game, Vector3f centerCameraOn =
|
||||||
|
Vector3f(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0));
|
||||||
|
|
||||||
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,
|
||||||
START_SCREEN,
|
START_SCREEN,
|
||||||
SYSTEM_SELECT,
|
SYSTEM_SELECT,
|
||||||
GAME_LIST
|
GAME_LIST
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GameListViewType
|
enum GameListViewType {
|
||||||
{
|
|
||||||
AUTOMATIC,
|
AUTOMATIC,
|
||||||
BASIC,
|
BASIC,
|
||||||
DETAILED,
|
DETAILED,
|
||||||
|
@ -65,11 +77,11 @@ public:
|
||||||
VIDEO
|
VIDEO
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State
|
struct State {
|
||||||
{
|
|
||||||
ViewMode viewing;
|
ViewMode viewing;
|
||||||
|
|
||||||
inline SystemData* getSystem() const { assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT); return system; }
|
inline SystemData* getSystem() const
|
||||||
|
{ assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT); return system; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend ViewController;
|
friend ViewController;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// BasicGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'Basic'.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/BasicGameListView.h"
|
#include "views/gamelist/BasicGameListView.h"
|
||||||
|
|
||||||
#include "utils/FileSystemUtil.h"
|
#include "utils/FileSystemUtil.h"
|
||||||
|
@ -7,8 +13,11 @@
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
|
||||||
BasicGameListView::BasicGameListView(Window* window, FileData* root)
|
BasicGameListView::BasicGameListView(
|
||||||
: ISimpleGameListView(window, root), mList(window)
|
Window* window,
|
||||||
|
FileData* root)
|
||||||
|
: 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);
|
||||||
|
@ -29,9 +38,9 @@ void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
|
|
||||||
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
|
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
|
||||||
{
|
{
|
||||||
if(change == FILE_METADATA_CHANGED)
|
if (change == FILE_METADATA_CHANGED)
|
||||||
{
|
{
|
||||||
// might switch to a detailed view
|
// Might switch to a detailed view.
|
||||||
ViewController::get()->reloadGameListView(this);
|
ViewController::get()->reloadGameListView(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -43,55 +52,23 @@ void BasicGameListView::populateList(const std::vector<FileData*>& files)
|
||||||
{
|
{
|
||||||
mList.clear();
|
mList.clear();
|
||||||
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
||||||
if (files.size() > 0)
|
if (files.size() > 0) {
|
||||||
{
|
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
||||||
|
if ((*it)->getFavorite() &&
|
||||||
std::string systemName = mRoot->getSystem()->getName();
|
mRoot->getSystem()->getName() != "favorites") {
|
||||||
|
mList.add(FAVORITE_GAME_CHAR + " " + (*it)->getName(),
|
||||||
bool favoritesFirst = Settings::getInstance()->getBool("FavoritesFirst");
|
*it, ((*it)->getType() == FOLDER));
|
||||||
|
}
|
||||||
bool showFavoriteIcon = (systemName != "favorites" && systemName != "recent");
|
else if ((*it)->getType() == FOLDER &&
|
||||||
if (!showFavoriteIcon)
|
mRoot->getSystem()->getName() != "collections") {
|
||||||
favoritesFirst = false;
|
mList.add(FAVORITE_FOLDER_CHAR + " " + (*it)->getName(), *it, true);
|
||||||
|
}
|
||||||
if (favoritesFirst)
|
else {
|
||||||
{
|
mList.add((*it)->getName(), *it, ((*it)->getType() == FOLDER));
|
||||||
for (auto file : files)
|
|
||||||
{
|
|
||||||
if (!file->getFavorite())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (showFavoriteIcon)
|
|
||||||
mList.add(FAVORITE_GAME_CHAR + " " + file->getName(), file, file->getType() == FOLDER);
|
|
||||||
else if (file->getType() == FOLDER)
|
|
||||||
mList.add(FAVORITE_FOLDER_CHAR + " " + file->getName(), file, true);
|
|
||||||
else
|
|
||||||
mList.add(file->getName(), file, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto file : files)
|
|
||||||
{
|
|
||||||
if (file->getFavorite())
|
|
||||||
{
|
|
||||||
if (favoritesFirst)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (showFavoriteIcon)
|
|
||||||
{
|
|
||||||
mList.add(FAVORITE_GAME_CHAR + " " + file->getName(), file, file->getType() == FOLDER);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
|
||||||
if (file->getType() == FOLDER)
|
|
||||||
mList.add(FAVORITE_FOLDER_CHAR + " " + file->getName(), file, true);
|
|
||||||
else
|
|
||||||
mList.add(file->getName(), file, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
addPlaceholder();
|
addPlaceholder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,25 +80,25 @@ FileData* BasicGameListView::getCursor()
|
||||||
|
|
||||||
void BasicGameListView::setCursor(FileData* cursor)
|
void BasicGameListView::setCursor(FileData* cursor)
|
||||||
{
|
{
|
||||||
if(!mList.setCursor(cursor) && (!cursor->isPlaceHolder()))
|
if (!mList.setCursor(cursor) && (!cursor->isPlaceHolder())) {
|
||||||
{
|
|
||||||
populateList(cursor->getParent()->getChildrenListToDisplay());
|
populateList(cursor->getParent()->getChildrenListToDisplay());
|
||||||
mList.setCursor(cursor);
|
mList.setCursor(cursor);
|
||||||
|
|
||||||
// update our cursor stack in case our cursor just got set to some folder we weren't in before
|
// Update our cursor stack in case our cursor just
|
||||||
if(mCursorStack.empty() || mCursorStack.top() != cursor->getParent())
|
// got set to some folder we weren't in before.
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
// flip the stack and put it in mCursorStack
|
// Flip the stack and put it in mCursorStack.
|
||||||
mCursorStack = std::stack<FileData*>();
|
mCursorStack = std::stack<FileData*>();
|
||||||
while(!tmp.empty())
|
while (!tmp.empty())
|
||||||
{
|
{
|
||||||
mCursorStack.push(tmp.top());
|
mCursorStack.push(tmp.top());
|
||||||
tmp.pop();
|
tmp.pop();
|
||||||
|
@ -132,8 +109,9 @@ void BasicGameListView::setCursor(FileData* cursor)
|
||||||
|
|
||||||
void BasicGameListView::addPlaceholder()
|
void BasicGameListView::addPlaceholder()
|
||||||
{
|
{
|
||||||
// empty list - add a placeholder
|
// Empty list - add a placeholder.
|
||||||
FileData* placeholder = new FileData(PLACEHOLDER, "<No Entries Found>", this->mRoot->getSystem()->getSystemEnvData(), this->mRoot->getSystem());
|
FileData* placeholder = new FileData(PLACEHOLDER, "<No Entries Found>",
|
||||||
|
this->mRoot->getSystem()->getSystemEnvData(), this->mRoot->getSystem());
|
||||||
mList.add(placeholder->getName(), placeholder, (placeholder->getType() == PLACEHOLDER));
|
mList.add(placeholder->getName(), placeholder, (placeholder->getType() == PLACEHOLDER));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,47 +132,47 @@ void BasicGameListView::launch(FileData* game)
|
||||||
|
|
||||||
void BasicGameListView::remove(FileData *game, bool deleteFile)
|
void BasicGameListView::remove(FileData *game, bool deleteFile)
|
||||||
{
|
{
|
||||||
|
// Actually delete the file on the filesystem.
|
||||||
if (deleteFile)
|
if (deleteFile)
|
||||||
Utils::FileSystem::removeFile(game->getPath()); // actually delete the file on the filesystem
|
Utils::FileSystem::removeFile(game->getPath());
|
||||||
|
|
||||||
FileData* parent = game->getParent();
|
FileData* parent = game->getParent();
|
||||||
if (getCursor() == game) // Select next element in list, or prev if none
|
// Select next element in list, or previous if none.
|
||||||
{
|
if (getCursor() == game) {
|
||||||
std::vector<FileData*> siblings = parent->getChildrenListToDisplay();
|
std::vector<FileData*> siblings = parent->getChildrenListToDisplay();
|
||||||
auto gameIter = std::find(siblings.cbegin(), siblings.cend(), game);
|
auto gameIter = std::find(siblings.cbegin(), siblings.cend(), game);
|
||||||
unsigned int gamePos = (int)std::distance(siblings.cbegin(), gameIter);
|
unsigned int gamePos = (int)std::distance(siblings.cbegin(), gameIter);
|
||||||
if (gameIter != siblings.cend())
|
if (gameIter != siblings.cend()) {
|
||||||
{
|
|
||||||
if ((gamePos + 1) < siblings.size())
|
if ((gamePos + 1) < siblings.size())
|
||||||
{
|
|
||||||
setCursor(siblings.at(gamePos + 1));
|
setCursor(siblings.at(gamePos + 1));
|
||||||
} else if (gamePos > 1) {
|
else if (gamePos > 1)
|
||||||
setCursor(siblings.at(gamePos - 1));
|
setCursor(siblings.at(gamePos - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mList.remove(game);
|
mList.remove(game);
|
||||||
if(mList.size() == 0)
|
|
||||||
{
|
if (mList.size() == 0)
|
||||||
addPlaceholder();
|
addPlaceholder();
|
||||||
}
|
|
||||||
delete game; // remove before repopulating (removes from parent)
|
// Remove before repopulating (removes from parent), then update the view.
|
||||||
onFileChanged(parent, FILE_REMOVED); // update the view, with game removed
|
delete game;
|
||||||
|
onFileChanged(parent, FILE_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
|
std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts;
|
std::vector<HelpPrompt> prompts;
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("QuickSystemSelect"))
|
if (Settings::getInstance()->getBool("QuickSystemSelect"))
|
||||||
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"));
|
||||||
prompts.push_back(HelpPrompt("a", "launch"));
|
prompts.push_back(HelpPrompt("a", "launch"));
|
||||||
prompts.push_back(HelpPrompt("b", "back"));
|
prompts.push_back(HelpPrompt("b", "back"));
|
||||||
if(!UIModeController::getInstance()->isUIModeKid())
|
if (!UIModeController::getInstance()->isUIModeKid())
|
||||||
prompts.push_back(HelpPrompt("select", "options"));
|
prompts.push_back(HelpPrompt("select", "options"));
|
||||||
if(mRoot->getSystem()->isGameSystem())
|
if (mRoot->getSystem()->isGameSystem())
|
||||||
prompts.push_back(HelpPrompt("x", "random"));
|
prompts.push_back(HelpPrompt("x", "random"));
|
||||||
if(mRoot->getSystem()->isGameSystem() && !UIModeController::getInstance()->isUIModeKid())
|
if (mRoot->getSystem()->isGameSystem() && !UIModeController::getInstance()->isUIModeKid())
|
||||||
{
|
{
|
||||||
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// BasicGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'basic'.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_BASIC_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_BASIC_GAME_LIST_VIEW_H
|
||||||
#define ES_APP_VIEWS_GAME_LIST_BASIC_GAME_LIST_VIEW_H
|
#define ES_APP_VIEWS_GAME_LIST_BASIC_GAME_LIST_VIEW_H
|
||||||
|
@ -10,7 +16,7 @@ class BasicGameListView : public ISimpleGameListView
|
||||||
public:
|
public:
|
||||||
BasicGameListView(Window* window, FileData* root);
|
BasicGameListView(Window* window, FileData* root);
|
||||||
|
|
||||||
// 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, FileChangeType change);
|
virtual void onFileChanged(FileData* file, FileChangeType change);
|
||||||
|
|
||||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
|
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
|
||||||
|
|
|
@ -1,24 +1,44 @@
|
||||||
|
//
|
||||||
|
// DetailedGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'detailed'.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/DetailedGameListView.h"
|
#include "views/gamelist/DetailedGameListView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
#include "animations/LambdaAnimation.h"
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
|
|
||||||
DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
DetailedGameListView::DetailedGameListView(
|
||||||
BasicGameListView(window, root),
|
Window* window,
|
||||||
mDescContainer(window), mDescription(window),
|
FileData* root)
|
||||||
|
: BasicGameListView(window, root),
|
||||||
|
mDescContainer(window),
|
||||||
|
mDescription(window),
|
||||||
|
|
||||||
mThumbnail(window),
|
mThumbnail(window),
|
||||||
mMarquee(window),
|
mMarquee(window),
|
||||||
mImage(window),
|
mImage(window),
|
||||||
|
|
||||||
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
mLblRating(window),
|
||||||
mLblGenre(window), mLblPlayers(window), mLblLastPlayed(window), mLblPlayCount(window),
|
mLblReleaseDate(window),
|
||||||
|
mLblDeveloper(window),
|
||||||
|
mLblPublisher(window),
|
||||||
|
mLblGenre(window),
|
||||||
|
mLblPlayers(window),
|
||||||
|
mLblLastPlayed(window),
|
||||||
|
mLblPlayCount(window),
|
||||||
|
|
||||||
mRating(window), mReleaseDate(window), mDeveloper(window), mPublisher(window),
|
mRating(window),
|
||||||
mGenre(window), mPlayers(window), mLastPlayed(window), mPlayCount(window),
|
mReleaseDate(window),
|
||||||
|
mDeveloper(window),
|
||||||
|
mPublisher(window),
|
||||||
|
mGenre(window),
|
||||||
|
mPlayers(window),
|
||||||
|
mLastPlayed(window),
|
||||||
|
mPlayCount(window),
|
||||||
mName(window)
|
mName(window)
|
||||||
{
|
{
|
||||||
//mHeaderImage.setPosition(mSize.x() * 0.25f, 0);
|
|
||||||
|
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
mList.setPosition(mSize.x() * (0.50f + padding), mList.getPosition().y());
|
||||||
|
@ -26,7 +46,7 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
||||||
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
||||||
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
||||||
|
|
||||||
// Thumbnail
|
// Thumbnail.
|
||||||
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);
|
||||||
|
@ -34,23 +54,23 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
||||||
mThumbnail.setDefaultZIndex(25);
|
mThumbnail.setDefaultZIndex(25);
|
||||||
addChild(&mThumbnail);
|
addChild(&mThumbnail);
|
||||||
|
|
||||||
// Marquee
|
// Marquee.
|
||||||
mMarquee.setOrigin(0.5f, 0.5f);
|
mMarquee.setOrigin(0.5f, 0.5f);
|
||||||
// Default to off the screen
|
// Default to off the screen.
|
||||||
mMarquee.setPosition(2.0f, 2.0f);
|
mMarquee.setPosition(2.0f, 2.0f);
|
||||||
mMarquee.setVisible(false);
|
mMarquee.setVisible(false);
|
||||||
mMarquee.setMaxSize(mSize.x() * (0.5f - 2*padding), mSize.y() * 0.18f);
|
mMarquee.setMaxSize(mSize.x() * (0.5f - 2*padding), mSize.y() * 0.18f);
|
||||||
mMarquee.setDefaultZIndex(35);
|
mMarquee.setDefaultZIndex(35);
|
||||||
addChild(&mMarquee);
|
addChild(&mMarquee);
|
||||||
|
|
||||||
// image
|
// Image.
|
||||||
mImage.setOrigin(0.5f, 0.5f);
|
mImage.setOrigin(0.5f, 0.5f);
|
||||||
mImage.setPosition(mSize.x() * 0.25f, mList.getPosition().y() + mSize.y() * 0.2125f);
|
mImage.setPosition(mSize.x() * 0.25f, mList.getPosition().y() + mSize.y() * 0.2125f);
|
||||||
mImage.setMaxSize(mSize.x() * (0.50f - 2*padding), mSize.y() * 0.4f);
|
mImage.setMaxSize(mSize.x() * (0.50f - 2*padding), mSize.y() * 0.4f);
|
||||||
mImage.setDefaultZIndex(30);
|
mImage.setDefaultZIndex(30);
|
||||||
addChild(&mImage);
|
addChild(&mImage);
|
||||||
|
|
||||||
// metadata labels + values
|
// Metadata labels + values.
|
||||||
mLblRating.setText("Rating: ");
|
mLblRating.setText("Rating: ");
|
||||||
addChild(&mLblRating);
|
addChild(&mLblRating);
|
||||||
addChild(&mRating);
|
addChild(&mRating);
|
||||||
|
@ -85,7 +105,8 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mSize.x() * (0.50f - 2*padding), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -94,7 +115,6 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescContainer.addChild(&mDescription);
|
mDescContainer.addChild(&mDescription);
|
||||||
|
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
initMDValues();
|
initMDValues();
|
||||||
updateInfoPanel();
|
updateInfoPanel();
|
||||||
|
@ -105,9 +125,12 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
BasicGameListView::onThemeChanged(theme);
|
BasicGameListView::onThemeChanged(theme);
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mThumbnail.applyTheme(theme, getName(), "md_thumbnail", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
||||||
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", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mName.applyTheme(theme, getName(), "md_name", ALL);
|
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
|
@ -118,11 +141,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
"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);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
|
@ -132,14 +152,14 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_genre", "md_players", "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", POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
mDescription.applyTheme(theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
sortChildren();
|
sortChildren();
|
||||||
}
|
}
|
||||||
|
@ -156,15 +176,14 @@ void DetailedGameListView::initMDLabels()
|
||||||
const float colSize = (mSize.x() * 0.48f) / colCount;
|
const float colSize = (mSize.x() * 0.48f) / colCount;
|
||||||
const float rowPadding = 0.01f * mSize.y();
|
const float rowPadding = 0.01f * mSize.y();
|
||||||
|
|
||||||
for(unsigned int i = 0; i < components.size(); i++)
|
for (unsigned int i = 0; i < components.size(); i++) {
|
||||||
{
|
|
||||||
const unsigned int row = i % rowCount;
|
const unsigned int row = i % rowCount;
|
||||||
Vector3f pos(0.0f, 0.0f, 0.0f);
|
Vector3f pos(0.0f, 0.0f, 0.0f);
|
||||||
if(row == 0)
|
if (row == 0) {
|
||||||
{
|
|
||||||
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
||||||
}else{
|
}
|
||||||
// work from the last component
|
else {
|
||||||
|
// Work from the last component.
|
||||||
GuiComponent* lc = components[i-1];
|
GuiComponent* lc = components[i-1];
|
||||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
@ -193,20 +212,22 @@ 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;
|
||||||
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;
|
||||||
values[i]->setPosition(labels[i]->getPosition() + Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
values[i]->setPosition(labels[i]->getPosition() +
|
||||||
|
Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||||
values[i]->setDefaultZIndex(40);
|
values[i]->setDefaultZIndex(40);
|
||||||
|
|
||||||
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
||||||
if(testBot > bottom)
|
|
||||||
|
if (testBot > bottom)
|
||||||
bottom = testBot;
|
bottom = testBot;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailedGameListView::updateInfoPanel()
|
void DetailedGameListView::updateInfoPanel()
|
||||||
|
@ -214,12 +235,12 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
|
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
|
||||||
|
|
||||||
bool fadingOut;
|
bool fadingOut;
|
||||||
if(file == NULL)
|
if (file == nullptr) {
|
||||||
{
|
|
||||||
//mImage.setImage("");
|
//mImage.setImage("");
|
||||||
//mDescription.setText("");
|
//mDescription.setText("");
|
||||||
fadingOut = true;
|
fadingOut = true;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
mThumbnail.setImage(file->getThumbnailPath());
|
mThumbnail.setImage(file->getThumbnailPath());
|
||||||
mMarquee.setImage(file->getMarqueePath());
|
mMarquee.setImage(file->getMarqueePath());
|
||||||
mImage.setImage(file->getImagePath());
|
mImage.setImage(file->getImagePath());
|
||||||
|
@ -234,8 +255,7 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
mPlayers.setValue(file->metadata.get("players"));
|
mPlayers.setValue(file->metadata.get("players"));
|
||||||
mName.setValue(file->metadata.get("name"));
|
mName.setValue(file->metadata.get("name"));
|
||||||
|
|
||||||
if(file->getType() == GAME)
|
if (file->getType() == GAME) {
|
||||||
{
|
|
||||||
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
||||||
mPlayCount.setValue(file->metadata.get("playcount"));
|
mPlayCount.setValue(file->metadata.get("playcount"));
|
||||||
}
|
}
|
||||||
|
@ -252,18 +272,13 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
||||||
|
|
||||||
for(auto it = comps.cbegin(); it != comps.cend(); it++)
|
for (auto it = comps.cbegin(); it != comps.cend(); it++) {
|
||||||
{
|
|
||||||
GuiComponent* comp = *it;
|
GuiComponent* comp = *it;
|
||||||
// an animation is playing
|
// An animation is playing, then animate if reverse != fadingOut
|
||||||
// then animate if reverse != fadingOut
|
// An animation is not playing, then animate if opacity != our target opacity
|
||||||
// an animation is not playing
|
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||||
// then animate if opacity != our target opacity
|
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
||||||
if((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
auto func = [comp](float t) {
|
||||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255)))
|
|
||||||
{
|
|
||||||
auto func = [comp](float t)
|
|
||||||
{
|
|
||||||
comp->setOpacity((unsigned char)(Math::lerp(0.0f, 1.0f, t)*255));
|
comp->setOpacity((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);
|
||||||
|
@ -274,7 +289,7 @@ void DetailedGameListView::updateInfoPanel()
|
||||||
void DetailedGameListView::launch(FileData* game)
|
void DetailedGameListView::launch(FileData* game)
|
||||||
{
|
{
|
||||||
Vector3f target(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0);
|
Vector3f target(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0);
|
||||||
if(mImage.hasImage())
|
if (mImage.hasImage())
|
||||||
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
||||||
|
|
||||||
ViewController::get()->launch(game, target);
|
ViewController::get()->launch(game, target);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// DetailedGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'detailed'.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_DETAILED_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_DETAILED_GAME_LIST_VIEW_H
|
||||||
#define ES_APP_VIEWS_GAME_LIST_DETAILED_GAME_LIST_VIEW_H
|
#define ES_APP_VIEWS_GAME_LIST_DETAILED_GAME_LIST_VIEW_H
|
||||||
|
@ -28,7 +34,14 @@ private:
|
||||||
ImageComponent mMarquee;
|
ImageComponent mMarquee;
|
||||||
ImageComponent mImage;
|
ImageComponent mImage;
|
||||||
|
|
||||||
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
TextComponent mLblRating;
|
||||||
|
TextComponent mLblReleaseDate;
|
||||||
|
TextComponent mLblDeveloper;
|
||||||
|
TextComponent mLblPublisher;
|
||||||
|
TextComponent mLblGenre;
|
||||||
|
TextComponent mLblPlayers;
|
||||||
|
TextComponent mLblLastPlayed;
|
||||||
|
TextComponent mLblPlayCount;
|
||||||
|
|
||||||
RatingComponent mRating;
|
RatingComponent mRating;
|
||||||
DateTimeComponent mReleaseDate;
|
DateTimeComponent mReleaseDate;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GridGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'grid'.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/GridGameListView.h"
|
#include "views/gamelist/GridGameListView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
#include "animations/LambdaAnimation.h"
|
||||||
|
@ -12,24 +18,42 @@
|
||||||
#endif
|
#endif
|
||||||
#include "components/VideoVlcComponent.h"
|
#include "components/VideoVlcComponent.h"
|
||||||
|
|
||||||
GridGameListView::GridGameListView(Window* window, FileData* root) :
|
GridGameListView::GridGameListView(
|
||||||
ISimpleGameListView(window, root),
|
Window* window,
|
||||||
mGrid(window), mMarquee(window),
|
FileData* root)
|
||||||
|
: ISimpleGameListView(window, root),
|
||||||
|
|
||||||
|
mGrid(window),
|
||||||
|
mMarquee(window),
|
||||||
mImage(window),
|
mImage(window),
|
||||||
mVideo(nullptr),
|
mVideo(nullptr),
|
||||||
mVideoPlaying(false),
|
mVideoPlaying(false),
|
||||||
mDescContainer(window), mDescription(window),
|
|
||||||
|
|
||||||
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
mDescContainer(window),
|
||||||
mLblGenre(window), mLblPlayers(window), mLblLastPlayed(window), mLblPlayCount(window),
|
mDescription(window),
|
||||||
|
|
||||||
mRating(window), mReleaseDate(window), mDeveloper(window), mPublisher(window),
|
mLblRating(window),
|
||||||
mGenre(window), mPlayers(window), mLastPlayed(window), mPlayCount(window),
|
mLblReleaseDate(window),
|
||||||
|
mLblDeveloper(window),
|
||||||
|
mLblPublisher(window),
|
||||||
|
mLblGenre(window),
|
||||||
|
mLblPlayers(window),
|
||||||
|
mLblLastPlayed(window),
|
||||||
|
mLblPlayCount(window),
|
||||||
|
|
||||||
|
mRating(window),
|
||||||
|
mReleaseDate(window),
|
||||||
|
mDeveloper(window),
|
||||||
|
mPublisher(window),
|
||||||
|
mGenre(window),
|
||||||
|
mPlayers(window),
|
||||||
|
mLastPlayed(window),
|
||||||
|
mPlayCount(window),
|
||||||
mName(window)
|
mName(window)
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
// Create the correct type of video window
|
// Create the correct type of video window.
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
||||||
mVideo = new VideoPlayerComponent(window, "");
|
mVideo = new VideoPlayerComponent(window, "");
|
||||||
|
@ -46,7 +70,7 @@ GridGameListView::GridGameListView(Window* window, FileData* root) :
|
||||||
|
|
||||||
populateList(root->getChildrenListToDisplay());
|
populateList(root->getChildrenListToDisplay());
|
||||||
|
|
||||||
// metadata labels + values
|
// Metadata labels + values.
|
||||||
mLblRating.setText("Rating: ");
|
mLblRating.setText("Rating: ");
|
||||||
addChild(&mLblRating);
|
addChild(&mLblRating);
|
||||||
addChild(&mRating);
|
addChild(&mRating);
|
||||||
|
@ -81,7 +105,8 @@ GridGameListView::GridGameListView(Window* window, FileData* root) :
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mSize.x() * (0.50f - 2*padding), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -128,7 +153,7 @@ FileData* GridGameListView::getCursor()
|
||||||
|
|
||||||
void GridGameListView::setCursor(FileData* file)
|
void GridGameListView::setCursor(FileData* file)
|
||||||
{
|
{
|
||||||
if(!mGrid.setCursor(file))
|
if (!mGrid.setCursor(file))
|
||||||
{
|
{
|
||||||
populateList(file->getParent()->getChildrenListToDisplay());
|
populateList(file->getParent()->getChildrenListToDisplay());
|
||||||
mGrid.setCursor(file);
|
mGrid.setCursor(file);
|
||||||
|
@ -147,11 +172,13 @@ std::string GridGameListView::getQuickSystemSelectLeftButton()
|
||||||
|
|
||||||
bool GridGameListView::input(InputConfig* config, Input input)
|
bool GridGameListView::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if (input.value == 0 and (config->isMappedLike("left", input) || config->isMappedLike("right", input)
|
if (input.value == 0 and (config->isMappedLike("left", input) ||
|
||||||
|| (config->isMappedLike("up", input)) || (config->isMappedLike("down", input)) ))
|
config->isMappedLike("right", input) ||
|
||||||
|
(config->isMappedLike("up", input)) ||
|
||||||
|
(config->isMappedLike("down", input)) ))
|
||||||
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
|
||||||
if(config->isMappedLike("left", input) || config->isMappedLike("right", input))
|
if (config->isMappedLike("left", input) || config->isMappedLike("right", input))
|
||||||
return GuiComponent::input(config, input);
|
return GuiComponent::input(config, input);
|
||||||
|
|
||||||
return ISimpleGameListView::input(config, input);
|
return ISimpleGameListView::input(config, input);
|
||||||
|
@ -167,8 +194,8 @@ const std::string GridGameListView::getImagePath(FileData* file)
|
||||||
else if (src == ImageSource::MARQUEE)
|
else if (src == ImageSource::MARQUEE)
|
||||||
return file->getMarqueePath();
|
return file->getMarqueePath();
|
||||||
|
|
||||||
// If no thumbnail was found, then use the image media type
|
// If no thumbnail was found, then use the image media type.
|
||||||
if(file->getThumbnailPath() == "");
|
if (file->getThumbnailPath() == "");
|
||||||
return file->getImagePath();
|
return file->getImagePath();
|
||||||
|
|
||||||
return file->getThumbnailPath();
|
return file->getThumbnailPath();
|
||||||
|
@ -178,17 +205,12 @@ void GridGameListView::populateList(const std::vector<FileData*>& files)
|
||||||
{
|
{
|
||||||
mGrid.clear();
|
mGrid.clear();
|
||||||
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
||||||
if (files.size() > 0)
|
if (files.size() > 0) {
|
||||||
{
|
|
||||||
for (auto it = files.cbegin(); it != files.cend(); it++)
|
for (auto it = files.cbegin(); it != files.cend(); it++)
|
||||||
{
|
|
||||||
mGrid.add((*it)->getName(), getImagePath(*it), *it);
|
mGrid.add((*it)->getName(), getImagePath(*it), *it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
addPlaceholder();
|
addPlaceholder();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
|
@ -199,9 +221,12 @@ 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", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
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", POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
mVideo->applyTheme(theme, getName(), "md_video",
|
||||||
|
POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
|
@ -211,11 +236,8 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
"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);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
|
@ -225,16 +247,17 @@ void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_genre", "md_players", "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", POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
mDescription.applyTheme(theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
// Repopulate list in case new theme is displaying a different image. Preserve selection.
|
// Repopulate list in case a new theme is displaying a different image.
|
||||||
|
// Preserve selection.
|
||||||
FileData* file = mGrid.getSelected();
|
FileData* file = mGrid.getSelected();
|
||||||
populateList(mRoot->getChildrenListToDisplay());
|
populateList(mRoot->getChildrenListToDisplay());
|
||||||
mGrid.setCursor(file);
|
mGrid.setCursor(file);
|
||||||
|
@ -254,15 +277,14 @@ void GridGameListView::initMDLabels()
|
||||||
const float colSize = (mSize.x() * 0.48f) / colCount;
|
const float colSize = (mSize.x() * 0.48f) / colCount;
|
||||||
const float rowPadding = 0.01f * mSize.y();
|
const float rowPadding = 0.01f * mSize.y();
|
||||||
|
|
||||||
for(unsigned int i = 0; i < components.size(); i++)
|
for (unsigned int i = 0; i < components.size(); i++) {
|
||||||
{
|
|
||||||
const unsigned int row = i % rowCount;
|
const unsigned int row = i % rowCount;
|
||||||
Vector3f pos(0.0f, 0.0f, 0.0f);
|
Vector3f pos(0.0f, 0.0f, 0.0f);
|
||||||
if(row == 0)
|
if (row == 0) {
|
||||||
{
|
|
||||||
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
||||||
}else{
|
}
|
||||||
// work from the last component
|
else {
|
||||||
|
// Work from the last component.
|
||||||
GuiComponent* lc = components[i-1];
|
GuiComponent* lc = components[i-1];
|
||||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
@ -291,36 +313,37 @@ 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;
|
||||||
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;
|
||||||
values[i]->setPosition(labels[i]->getPosition() + Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
values[i]->setPosition(labels[i]->getPosition() +
|
||||||
|
Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||||
values[i]->setDefaultZIndex(40);
|
values[i]->setDefaultZIndex(40);
|
||||||
|
|
||||||
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
||||||
if(testBot > bottom)
|
if (testBot > bottom)
|
||||||
bottom = testBot;
|
bottom = testBot;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridGameListView::updateInfoPanel()
|
void GridGameListView::updateInfoPanel()
|
||||||
{
|
{
|
||||||
FileData* file = (mGrid.size() == 0 || mGrid.isScrolling()) ? NULL : mGrid.getSelected();
|
FileData* file = (mGrid.size() == 0 || mGrid.isScrolling()) ? nullptr : mGrid.getSelected();
|
||||||
|
|
||||||
bool fadingOut;
|
bool fadingOut;
|
||||||
if(file == NULL)
|
if (file == nullptr)
|
||||||
{
|
{
|
||||||
mVideo->setVideo("");
|
mVideo->setVideo("");
|
||||||
mVideo->setImage("");
|
mVideo->setImage("");
|
||||||
mVideoPlaying = false;
|
mVideoPlaying = false;
|
||||||
|
|
||||||
//mDescription.setText("");
|
|
||||||
fadingOut = true;
|
fadingOut = true;
|
||||||
}else{
|
}else{
|
||||||
|
// Temporary fix to disable only audio from playing
|
||||||
// if (!mVideo->setVideo(file->getVideoPath()))
|
// if (!mVideo->setVideo(file->getVideoPath()))
|
||||||
// {
|
// {
|
||||||
// mVideo->setDefaultVideo();
|
// mVideo->setDefaultVideo();
|
||||||
|
@ -342,8 +365,7 @@ void GridGameListView::updateInfoPanel()
|
||||||
mPlayers.setValue(file->metadata.get("players"));
|
mPlayers.setValue(file->metadata.get("players"));
|
||||||
mName.setValue(file->metadata.get("name"));
|
mName.setValue(file->metadata.get("name"));
|
||||||
|
|
||||||
if(file->getType() == GAME)
|
if (file->getType() == GAME) {
|
||||||
{
|
|
||||||
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
||||||
mPlayCount.setValue(file->metadata.get("playcount"));
|
mPlayCount.setValue(file->metadata.get("playcount"));
|
||||||
}
|
}
|
||||||
|
@ -360,18 +382,13 @@ void GridGameListView::updateInfoPanel()
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
||||||
|
|
||||||
for(auto it = comps.cbegin(); it != comps.cend(); it++)
|
for (auto it = comps.cbegin(); it != comps.cend(); it++) {
|
||||||
{
|
|
||||||
GuiComponent* comp = *it;
|
GuiComponent* comp = *it;
|
||||||
// an animation is playing
|
// An animation is playing, then animate if reverse != fadingOut
|
||||||
// then animate if reverse != fadingOut
|
// An animation is not playing, then animate if opacity != our target opacity
|
||||||
// an animation is not playing
|
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||||
// then animate if opacity != our target opacity
|
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
||||||
if((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
auto func = [comp](float t) {
|
||||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255)))
|
|
||||||
{
|
|
||||||
auto func = [comp](float t)
|
|
||||||
{
|
|
||||||
comp->setOpacity((unsigned char)(Math::lerp(0.0f, 1.0f, t)*255));
|
comp->setOpacity((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);
|
||||||
|
@ -381,8 +398,9 @@ void GridGameListView::updateInfoPanel()
|
||||||
|
|
||||||
void GridGameListView::addPlaceholder()
|
void GridGameListView::addPlaceholder()
|
||||||
{
|
{
|
||||||
// empty grid - add a placeholder
|
// Empty grid - add a placeholder.
|
||||||
FileData* placeholder = new FileData(PLACEHOLDER, "<No Entries Found>", this->mRoot->getSystem()->getSystemEnvData(), this->mRoot->getSystem());
|
FileData* placeholder = new FileData(PLACEHOLDER, "<No Entries Found>",
|
||||||
|
this->mRoot->getSystem()->getSystemEnvData(), this->mRoot->getSystem());
|
||||||
mGrid.add(placeholder->getName(), "", placeholder);
|
mGrid.add(placeholder->getName(), "", placeholder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,55 +411,49 @@ void GridGameListView::launch(FileData* game)
|
||||||
|
|
||||||
Vector3f target(screenWidth / 2.0f, screenHeight / 2.0f, 0);
|
Vector3f target(screenWidth / 2.0f, screenHeight / 2.0f, 0);
|
||||||
|
|
||||||
if(mMarquee.hasImage() &&
|
if (mMarquee.hasImage() &&
|
||||||
(mMarquee.getPosition().x() < screenWidth && mMarquee.getPosition().x() > 0.0f &&
|
(mMarquee.getPosition().x() < screenWidth && mMarquee.getPosition().x() > 0.0f &&
|
||||||
mMarquee.getPosition().y() < screenHeight && mMarquee.getPosition().y() > 0.0f))
|
mMarquee.getPosition().y() < screenHeight && mMarquee.getPosition().y() > 0.0f))
|
||||||
{
|
|
||||||
target = Vector3f(mMarquee.getCenter().x(), mMarquee.getCenter().y(), 0);
|
target = Vector3f(mMarquee.getCenter().x(), mMarquee.getCenter().y(), 0);
|
||||||
}
|
else if (mImage.hasImage() &&
|
||||||
else if(mImage.hasImage() &&
|
|
||||||
(mImage.getPosition().x() < screenWidth && mImage.getPosition().x() > 2.0f &&
|
(mImage.getPosition().x() < screenWidth && mImage.getPosition().x() > 2.0f &&
|
||||||
mImage.getPosition().y() < screenHeight && mImage.getPosition().y() > 2.0f))
|
mImage.getPosition().y() < screenHeight && mImage.getPosition().y() > 2.0f))
|
||||||
{
|
|
||||||
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
||||||
}
|
else if (mVideo->getPosition().x() < screenWidth && mVideo->getPosition().x() > 0.0f &&
|
||||||
else if(mVideo->getPosition().x() < screenWidth && mVideo->getPosition().x() > 0.0f &&
|
|
||||||
mVideo->getPosition().y() < screenHeight && mVideo->getPosition().y() > 0.0f)
|
mVideo->getPosition().y() < screenHeight && mVideo->getPosition().y() > 0.0f)
|
||||||
{
|
|
||||||
target = Vector3f(mVideo->getCenter().x(), mVideo->getCenter().y(), 0);
|
target = Vector3f(mVideo->getCenter().x(), mVideo->getCenter().y(), 0);
|
||||||
}
|
|
||||||
|
|
||||||
ViewController::get()->launch(game, target);
|
ViewController::get()->launch(game, target);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridGameListView::remove(FileData *game, bool deleteFile)
|
void GridGameListView::remove(FileData *game, bool deleteFile)
|
||||||
{
|
{
|
||||||
|
// Actually delete the file on the filesystem.
|
||||||
if (deleteFile)
|
if (deleteFile)
|
||||||
Utils::FileSystem::removeFile(game->getPath()); // actually delete the file on the filesystem
|
Utils::FileSystem::removeFile(game->getPath());
|
||||||
|
|
||||||
FileData* parent = game->getParent();
|
FileData* parent = game->getParent();
|
||||||
if (getCursor() == game) // Select next element in list, or prev if none
|
// Select next element in list, or previous if none.
|
||||||
{
|
if (getCursor() == game) {
|
||||||
std::vector<FileData*> siblings = parent->getChildrenListToDisplay();
|
std::vector<FileData*> siblings = parent->getChildrenListToDisplay();
|
||||||
auto gameIter = std::find(siblings.cbegin(), siblings.cend(), game);
|
auto gameIter = std::find(siblings.cbegin(), siblings.cend(), game);
|
||||||
int gamePos = (int)std::distance(siblings.cbegin(), gameIter);
|
int gamePos = (int)std::distance(siblings.cbegin(), gameIter);
|
||||||
if (gameIter != siblings.cend())
|
if (gameIter != siblings.cend()) {
|
||||||
{
|
|
||||||
if ((gamePos + 1) < (int)siblings.size())
|
if ((gamePos + 1) < (int)siblings.size())
|
||||||
{
|
|
||||||
setCursor(siblings.at(gamePos + 1));
|
setCursor(siblings.at(gamePos + 1));
|
||||||
} else if ((gamePos - 1) > 0) {
|
else if ((gamePos - 1) > 0)
|
||||||
setCursor(siblings.at(gamePos - 1));
|
setCursor(siblings.at(gamePos - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mGrid.remove(game);
|
mGrid.remove(game);
|
||||||
if(mGrid.size() == 0)
|
|
||||||
{
|
if (mGrid.size() == 0)
|
||||||
addPlaceholder();
|
addPlaceholder();
|
||||||
}
|
|
||||||
delete game; // remove before repopulating (removes from parent)
|
// Remove before repopulating (removes from parent).
|
||||||
onFileChanged(parent, FILE_REMOVED); // update the view, with game removed
|
// Update the view, with game removed.
|
||||||
|
delete game;
|
||||||
|
onFileChanged(parent, FILE_REMOVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TextComponent*> GridGameListView::getMDLabels()
|
std::vector<TextComponent*> GridGameListView::getMDLabels()
|
||||||
|
@ -476,17 +488,16 @@ std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
||||||
{
|
{
|
||||||
std::vector<HelpPrompt> prompts;
|
std::vector<HelpPrompt> prompts;
|
||||||
|
|
||||||
if(Settings::getInstance()->getBool("QuickSystemSelect"))
|
if (Settings::getInstance()->getBool("QuickSystemSelect"))
|
||||||
prompts.push_back(HelpPrompt("lr", "system"));
|
prompts.push_back(HelpPrompt("lr", "system"));
|
||||||
prompts.push_back(HelpPrompt("up/down/left/right", "choose"));
|
prompts.push_back(HelpPrompt("up/down/left/right", "choose"));
|
||||||
prompts.push_back(HelpPrompt("a", "launch"));
|
prompts.push_back(HelpPrompt("a", "launch"));
|
||||||
prompts.push_back(HelpPrompt("b", "back"));
|
prompts.push_back(HelpPrompt("b", "back"));
|
||||||
if(!UIModeController::getInstance()->isUIModeKid())
|
if (!UIModeController::getInstance()->isUIModeKid())
|
||||||
prompts.push_back(HelpPrompt("select", "options"));
|
prompts.push_back(HelpPrompt("select", "options"));
|
||||||
if(mRoot->getSystem()->isGameSystem())
|
if (mRoot->getSystem()->isGameSystem())
|
||||||
prompts.push_back(HelpPrompt("x", "random"));
|
prompts.push_back(HelpPrompt("x", "random"));
|
||||||
if(mRoot->getSystem()->isGameSystem() && !UIModeController::getInstance()->isUIModeKid())
|
if (mRoot->getSystem()->isGameSystem() && !UIModeController::getInstance()->isUIModeKid()) {
|
||||||
{
|
|
||||||
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
|
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
|
||||||
prompts.push_back(HelpPrompt("y", prompt));
|
prompts.push_back(HelpPrompt("y", prompt));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GridGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'grid'.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||||
#define ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
#define ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||||
|
@ -46,7 +52,14 @@ private:
|
||||||
void initMDLabels();
|
void initMDLabels();
|
||||||
void initMDValues();
|
void initMDValues();
|
||||||
|
|
||||||
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
TextComponent mLblRating;
|
||||||
|
TextComponent mLblReleaseDate;
|
||||||
|
TextComponent mLblDeveloper;
|
||||||
|
TextComponent mLblPublisher;
|
||||||
|
TextComponent mLblGenre;
|
||||||
|
TextComponent mLblPlayers;
|
||||||
|
TextComponent mLblLastPlayed;
|
||||||
|
TextComponent mLblPlayCount;
|
||||||
|
|
||||||
ImageComponent mMarquee;
|
ImageComponent mMarquee;
|
||||||
VideoComponent* mVideo;
|
VideoComponent* mVideo;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// IGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines the minimum for a GameListView.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/IGameListView.h"
|
#include "views/gamelist/IGameListView.h"
|
||||||
|
|
||||||
#include "guis/GuiGamelistOptions.h"
|
#include "guis/GuiGamelistOptions.h"
|
||||||
|
@ -8,16 +14,17 @@
|
||||||
|
|
||||||
bool IGameListView::input(InputConfig* config, Input input)
|
bool IGameListView::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
// select to open GuiGamelistOptions
|
// Select button opens GuiGamelistOptions.
|
||||||
if(!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("select", input) && input.value)
|
if (!UIModeController::getInstance()->isUIModeKid() &&
|
||||||
{
|
config->isMappedTo("select", input) && input.value) {
|
||||||
mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
|
mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
// Ctrl-R to reload a view when debugging
|
// Ctrl-R reloads the view when debugging.
|
||||||
}else if(Settings::getInstance()->getBool("Debug") && config->getDeviceId() == DEVICE_KEYBOARD &&
|
else if (Settings::getInstance()->getBool("Debug") &&
|
||||||
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) && input.id == SDLK_r && input.value != 0)
|
config->getDeviceId() == DEVICE_KEYBOARD &&
|
||||||
{
|
(SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) &&
|
||||||
|
input.id == SDLK_r && input.value != 0) {
|
||||||
LOG(LogDebug) << "reloading view";
|
LOG(LogDebug) << "reloading view";
|
||||||
ViewController::get()->reloadGameListView(this, true);
|
ViewController::get()->reloadGameListView(this, true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -46,8 +53,10 @@ void IGameListView::render(const Transform4x4f& parentTrans)
|
||||||
float scaleX = trans.r0().x();
|
float scaleX = trans.r0().x();
|
||||||
float scaleY = trans.r1().y();
|
float scaleY = trans.r1().y();
|
||||||
|
|
||||||
Vector2i pos((int)Math::round(trans.translation()[0]), (int)Math::round(trans.translation()[1]));
|
Vector2i pos((int)Math::round(trans.translation()[0]),
|
||||||
Vector2i size((int)Math::round(mSize.x() * scaleX), (int)Math::round(mSize.y() * scaleY));
|
(int)Math::round(trans.translation()[1]));
|
||||||
|
Vector2i size((int)Math::round(mSize.x() * scaleX),
|
||||||
|
(int)Math::round(mSize.y() * scaleY));
|
||||||
|
|
||||||
Renderer::pushClipRect(pos, size);
|
Renderer::pushClipRect(pos, size);
|
||||||
renderChildren(trans);
|
renderChildren(trans);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// IGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines the minimum for a GameListView.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#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
|
||||||
|
@ -13,12 +19,18 @@ class Window;
|
||||||
class IGameListView : public GuiComponent
|
class IGameListView : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IGameListView(Window* window, FileData* root) : GuiComponent(window), mRoot(root)
|
IGameListView(
|
||||||
{ setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); }
|
Window* window,
|
||||||
|
FileData* root)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mRoot(root)
|
||||||
|
{ setSize((float)Renderer::getScreenWidth(),
|
||||||
|
(float)Renderer::getScreenHeight()); }
|
||||||
|
|
||||||
virtual ~IGameListView() {}
|
virtual ~IGameListView() {}
|
||||||
|
|
||||||
// Called when a new file is added, a file is removed, a file's metadata changes, or a file's children are sorted.
|
// Called when a new file is added, a file is removed, a file's metadata changes,
|
||||||
|
// or a file's children are sorted.
|
||||||
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.
|
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.
|
||||||
// Since sorts are recursive, that FileData's children probably changed too.
|
// Since sorts are recursive, that FileData's children probably changed too.
|
||||||
virtual void onFileChanged(FileData* file, FileChangeType change) = 0;
|
virtual void onFileChanged(FileData* file, FileChangeType change) = 0;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// ISimpleGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines a simple GameListView.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/ISimpleGameListView.h"
|
#include "views/gamelist/ISimpleGameListView.h"
|
||||||
|
|
||||||
#include "views/UIModeController.h"
|
#include "views/UIModeController.h"
|
||||||
|
@ -7,8 +13,13 @@
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
|
||||||
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGameListView(window, root),
|
ISimpleGameListView::ISimpleGameListView(
|
||||||
mHeaderText(window), mHeaderImage(window), mBackground(window)
|
Window* window,
|
||||||
|
FileData* root)
|
||||||
|
: IGameListView(window, root),
|
||||||
|
mHeaderText(window),
|
||||||
|
mHeaderImage(window),
|
||||||
|
mBackground(window)
|
||||||
{
|
{
|
||||||
mHeaderText.setText("Logo Text");
|
mHeaderText.setText("Logo Text");
|
||||||
mHeaderText.setSize(mSize.x(), 0);
|
mHeaderText.setSize(mSize.x(), 0);
|
||||||
|
@ -35,7 +46,7 @@ void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme
|
||||||
mHeaderImage.applyTheme(theme, getName(), "logo", ALL);
|
mHeaderImage.applyTheme(theme, getName(), "logo", ALL);
|
||||||
mHeaderText.applyTheme(theme, getName(), "logoText", ALL);
|
mHeaderText.applyTheme(theme, getName(), "logoText", ALL);
|
||||||
|
|
||||||
// Remove old theme extras
|
// Remove old theme extras.
|
||||||
for (auto extra : mThemeExtras)
|
for (auto extra : mThemeExtras)
|
||||||
{
|
{
|
||||||
removeChild(extra);
|
removeChild(extra);
|
||||||
|
@ -43,18 +54,16 @@ void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme
|
||||||
}
|
}
|
||||||
mThemeExtras.clear();
|
mThemeExtras.clear();
|
||||||
|
|
||||||
// Add new theme extras
|
// Add new theme extras.
|
||||||
mThemeExtras = ThemeData::makeExtras(theme, getName(), mWindow);
|
mThemeExtras = ThemeData::makeExtras(theme, getName(), mWindow);
|
||||||
for (auto extra : mThemeExtras)
|
for (auto extra : mThemeExtras)
|
||||||
{
|
|
||||||
addChild(extra);
|
addChild(extra);
|
||||||
}
|
|
||||||
|
|
||||||
if(mHeaderImage.hasImage())
|
if (mHeaderImage.hasImage()) {
|
||||||
{
|
|
||||||
removeChild(&mHeaderText);
|
removeChild(&mHeaderText);
|
||||||
addChild(&mHeaderImage);
|
addChild(&mHeaderImage);
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
addChild(&mHeaderText);
|
addChild(&mHeaderText);
|
||||||
removeChild(&mHeaderImage);
|
removeChild(&mHeaderImage);
|
||||||
}
|
}
|
||||||
|
@ -62,8 +71,8 @@ void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme
|
||||||
|
|
||||||
void ISimpleGameListView::onFileChanged(FileData* /*file*/, FileChangeType /*change*/)
|
void ISimpleGameListView::onFileChanged(FileData* /*file*/, FileChangeType /*change*/)
|
||||||
{
|
{
|
||||||
// we could be tricky here to be efficient;
|
// We could be tricky here to be efficient;
|
||||||
// but this shouldn't happen very often so we'll just always repopulate
|
// but this shouldn't happen very often so we'll just always repopulate.
|
||||||
FileData* cursor = getCursor();
|
FileData* cursor = getCursor();
|
||||||
if (!cursor->isPlaceHolder()) {
|
if (!cursor->isPlaceHolder()) {
|
||||||
populateList(cursor->getParent()->getChildrenListToDisplay());
|
populateList(cursor->getParent()->getChildrenListToDisplay());
|
||||||
|
@ -80,18 +89,15 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Sound> soundfile;
|
std::shared_ptr<Sound> soundfile;
|
||||||
|
|
||||||
if(input.value != 0)
|
if (input.value != 0) {
|
||||||
{
|
if (config->isMappedTo("a", input)) {
|
||||||
if(config->isMappedTo("a", input))
|
|
||||||
{
|
|
||||||
FileData* cursor = getCursor();
|
FileData* cursor = getCursor();
|
||||||
if(cursor->getType() == GAME)
|
if (cursor->getType() == GAME) {
|
||||||
{
|
|
||||||
launch(cursor);
|
launch(cursor);
|
||||||
}else{
|
}
|
||||||
// it's a folder
|
else {
|
||||||
if(cursor->getChildren().size() > 0)
|
// It's a folder.
|
||||||
{
|
if (cursor->getChildren().size() > 0) {
|
||||||
mCursorStack.push(cursor);
|
mCursorStack.push(cursor);
|
||||||
populateList(cursor->getChildrenListToDisplay());
|
populateList(cursor->getChildrenListToDisplay());
|
||||||
FileData* cursor = getCursor();
|
FileData* cursor = getCursor();
|
||||||
|
@ -100,14 +106,14 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}else if(config->isMappedTo("b", input))
|
}
|
||||||
{
|
else if (config->isMappedTo("b", input)) {
|
||||||
if(mCursorStack.size())
|
if (mCursorStack.size()) {
|
||||||
{
|
|
||||||
populateList(mCursorStack.top()->getParent()->getChildren());
|
populateList(mCursorStack.top()->getParent()->getChildren());
|
||||||
setCursor(mCursorStack.top());
|
setCursor(mCursorStack.top());
|
||||||
mCursorStack.pop();
|
mCursorStack.pop();
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
navigationsounds.playThemeNavigationSound(BACKSOUND);
|
navigationsounds.playThemeNavigationSound(BACKSOUND);
|
||||||
onFocusLost();
|
onFocusLost();
|
||||||
SystemData* systemToView = getCursor()->getSystem();
|
SystemData* systemToView = getCursor()->getSystem();
|
||||||
|
@ -119,57 +125,40 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}else if(config->isMappedLike(getQuickSystemSelectRightButton(), input))
|
}
|
||||||
{
|
else if (config->isMappedLike(getQuickSystemSelectRightButton(), input)) {
|
||||||
if(Settings::getInstance()->getBool("QuickSystemSelect"))
|
if (Settings::getInstance()->getBool("QuickSystemSelect")) {
|
||||||
{
|
|
||||||
onFocusLost();
|
onFocusLost();
|
||||||
ViewController::get()->goToNextGameList();
|
ViewController::get()->goToNextGameList();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else if(config->isMappedLike(getQuickSystemSelectLeftButton(), input))
|
}
|
||||||
{
|
else if (config->isMappedLike(getQuickSystemSelectLeftButton(), input)) {
|
||||||
if(Settings::getInstance()->getBool("QuickSystemSelect"))
|
if (Settings::getInstance()->getBool("QuickSystemSelect")) {
|
||||||
{
|
|
||||||
onFocusLost();
|
onFocusLost();
|
||||||
ViewController::get()->goToPrevGameList();
|
ViewController::get()->goToPrevGameList();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else if (config->isMappedTo("x", input))
|
}
|
||||||
{
|
else if (config->isMappedTo("x", input)) {
|
||||||
if (mRoot->getSystem()->isGameSystem())
|
if (mRoot->getSystem()->isGameSystem()) {
|
||||||
{
|
// Go to random system game.
|
||||||
// go to random system game
|
|
||||||
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
navigationsounds.playThemeNavigationSound(SCROLLSOUND);
|
||||||
FileData* randomGame = getCursor()->getSystem()->getRandomGame();
|
FileData* randomGame = getCursor()->getSystem()->getRandomGame();
|
||||||
if (randomGame)
|
if (randomGame)
|
||||||
{
|
|
||||||
setCursor(randomGame);
|
setCursor(randomGame);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}else if (config->isMappedTo("y", input) && !UIModeController::getInstance()->isUIModeKid())
|
}
|
||||||
{
|
else if (config->isMappedTo("y", input) &&
|
||||||
if(mRoot->getSystem()->isGameSystem())
|
!UIModeController::getInstance()->isUIModeKid()) {
|
||||||
{
|
if (mRoot->getSystem()->isGameSystem()) {
|
||||||
navigationsounds.playThemeNavigationSound(FAVORITESOUND);
|
navigationsounds.playThemeNavigationSound(FAVORITESOUND);
|
||||||
if(CollectionSystemManager::get()->toggleGameInCollection(getCursor()))
|
if (CollectionSystemManager::get()->toggleGameInCollection(getCursor()))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return IGameListView::input(config, input);
|
return IGameListView::input(config, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// ISimpleGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines a simple GameListView.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#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
|
||||||
|
@ -11,9 +17,11 @@ class ISimpleGameListView : public IGameListView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ISimpleGameListView(Window* window, FileData* root);
|
ISimpleGameListView(Window* window, FileData* root);
|
||||||
|
|
||||||
virtual ~ISimpleGameListView() {}
|
virtual ~ISimpleGameListView() {}
|
||||||
|
|
||||||
// Called when a new file is added, a file is removed, a file's metadata changes, or a file's children are sorted.
|
// Called when a new file is added, a file is removed, a file's metadata changes,
|
||||||
|
// or a file's children are sorted.
|
||||||
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.
|
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.
|
||||||
// Since sorts are recursive, that FileData's children probably changed too.
|
// Since sorts are recursive, that FileData's children probably changed too.
|
||||||
virtual void onFileChanged(FileData* file, FileChangeType change);
|
virtual void onFileChanged(FileData* file, FileChangeType change);
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// VideoGameListView.cpp
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'video'.
|
||||||
|
//
|
||||||
|
|
||||||
#include "views/gamelist/VideoGameListView.h"
|
#include "views/gamelist/VideoGameListView.h"
|
||||||
|
|
||||||
#include "animations/LambdaAnimation.h"
|
#include "animations/LambdaAnimation.h"
|
||||||
|
@ -11,25 +17,41 @@
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
VideoGameListView::VideoGameListView(
|
||||||
BasicGameListView(window, root),
|
Window* window,
|
||||||
mDescContainer(window), mDescription(window),
|
FileData* root)
|
||||||
|
: BasicGameListView(window, root),
|
||||||
|
mDescContainer(window),
|
||||||
|
mDescription(window),
|
||||||
|
|
||||||
mThumbnail(window),
|
mThumbnail(window),
|
||||||
mMarquee(window),
|
mMarquee(window),
|
||||||
mImage(window),
|
mImage(window),
|
||||||
mVideo(nullptr),
|
mVideo(nullptr),
|
||||||
mVideoPlaying(false),
|
mVideoPlaying(false),
|
||||||
|
|
||||||
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
mLblRating(window),
|
||||||
mLblGenre(window), mLblPlayers(window), mLblLastPlayed(window), mLblPlayCount(window),
|
mLblReleaseDate(window),
|
||||||
|
mLblDeveloper(window),
|
||||||
|
mLblPublisher(window),
|
||||||
|
mLblGenre(window),
|
||||||
|
mLblPlayers(window),
|
||||||
|
mLblLastPlayed(window),
|
||||||
|
mLblPlayCount(window),
|
||||||
|
|
||||||
mRating(window), mReleaseDate(window), mDeveloper(window), mPublisher(window),
|
mRating(window),
|
||||||
mGenre(window), mPlayers(window), mLastPlayed(window), mPlayCount(window),
|
mReleaseDate(window),
|
||||||
|
mDeveloper(window),
|
||||||
|
mPublisher(window),
|
||||||
|
mGenre(window),
|
||||||
|
mPlayers(window),
|
||||||
|
mLastPlayed(window),
|
||||||
|
mPlayCount(window),
|
||||||
mName(window)
|
mName(window)
|
||||||
{
|
{
|
||||||
const float padding = 0.01f;
|
const float padding = 0.01f;
|
||||||
|
|
||||||
// Create the correct type of video window
|
// Create the correct type of video window.
|
||||||
#ifdef _RPI_
|
#ifdef _RPI_
|
||||||
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
if (Settings::getInstance()->getBool("VideoOmxPlayer"))
|
||||||
mVideo = new VideoPlayerComponent(window, "");
|
mVideo = new VideoPlayerComponent(window, "");
|
||||||
|
@ -44,7 +66,7 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
mList.setAlignment(TextListComponent<FileData*>::ALIGN_LEFT);
|
||||||
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
||||||
|
|
||||||
// Thumbnail
|
// Thumbnail.
|
||||||
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);
|
||||||
|
@ -52,30 +74,30 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
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*padding), mSize.y() * 0.18f);
|
||||||
mMarquee.setDefaultZIndex(35);
|
mMarquee.setDefaultZIndex(35);
|
||||||
addChild(&mMarquee);
|
addChild(&mMarquee);
|
||||||
|
|
||||||
// Image
|
// Image.
|
||||||
mImage.setOrigin(0.5f, 0.5f);
|
mImage.setOrigin(0.5f, 0.5f);
|
||||||
// Default to off the screen
|
// Default to off the screen.
|
||||||
mImage.setPosition(mSize.x() * 0.25f, mList.getPosition().y() + mSize.y() * 0.2125f);
|
mImage.setPosition(mSize.x() * 0.25f, mList.getPosition().y() + mSize.y() * 0.2125f);
|
||||||
mImage.setVisible(false);
|
mImage.setVisible(false);
|
||||||
mImage.setMaxSize(mSize.x() * (0.50f - 2*padding), mSize.y() * 0.4f);
|
mImage.setMaxSize(mSize.x() * (0.50f - 2*padding), mSize.y() * 0.4f);
|
||||||
mImage.setDefaultZIndex(30);
|
mImage.setDefaultZIndex(30);
|
||||||
addChild(&mImage);
|
addChild(&mImage);
|
||||||
|
|
||||||
// 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*padding), mSize.y() * 0.4f);
|
||||||
mVideo->setDefaultZIndex(30);
|
mVideo->setDefaultZIndex(30);
|
||||||
addChild(mVideo);
|
addChild(mVideo);
|
||||||
|
|
||||||
// metadata labels + values
|
// Metadata labels + values.
|
||||||
mLblRating.setText("Rating: ");
|
mLblRating.setText("Rating: ");
|
||||||
addChild(&mLblRating);
|
addChild(&mLblRating);
|
||||||
addChild(&mRating);
|
addChild(&mRating);
|
||||||
|
@ -110,7 +132,8 @@ VideoGameListView::VideoGameListView(Window* window, FileData* root) :
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mSize.x() * (0.50f - 2*padding), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
mDescContainer.setAutoScroll(true);
|
mDescContainer.setAutoScroll(true);
|
||||||
mDescContainer.setDefaultZIndex(40);
|
mDescContainer.setDefaultZIndex(40);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
@ -133,10 +156,14 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
BasicGameListView::onThemeChanged(theme);
|
BasicGameListView::onThemeChanged(theme);
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mThumbnail.applyTheme(theme, getName(), "md_thumbnail", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
mThumbnail.applyTheme(theme, getName(), "md_thumbnail",
|
||||||
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", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
mMarquee.applyTheme(theme, getName(), "md_marquee",
|
||||||
mVideo->applyTheme(theme, getName(), "md_video", POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
mImage.applyTheme(theme, getName(), "md_image",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE);
|
||||||
|
mVideo->applyTheme(theme, getName(), "md_video",
|
||||||
|
POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE);
|
||||||
mName.applyTheme(theme, getName(), "md_name", ALL);
|
mName.applyTheme(theme, getName(), "md_name", ALL);
|
||||||
|
|
||||||
initMDLabels();
|
initMDLabels();
|
||||||
|
@ -147,11 +174,8 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
"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);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
initMDValues();
|
initMDValues();
|
||||||
std::vector<GuiComponent*> values = getMDValues();
|
std::vector<GuiComponent*> values = getMDValues();
|
||||||
|
@ -161,14 +185,14 @@ void VideoGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
"md_genre", "md_players", "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", POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
mDescContainer.applyTheme(theme, getName(), "md_description",
|
||||||
|
POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE);
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
mDescription.applyTheme(theme, getName(), "md_description",
|
||||||
|
ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||||
|
|
||||||
sortChildren();
|
sortChildren();
|
||||||
}
|
}
|
||||||
|
@ -185,15 +209,14 @@ void VideoGameListView::initMDLabels()
|
||||||
const float colSize = (mSize.x() * 0.48f) / colCount;
|
const float colSize = (mSize.x() * 0.48f) / colCount;
|
||||||
const float rowPadding = 0.01f * mSize.y();
|
const float rowPadding = 0.01f * mSize.y();
|
||||||
|
|
||||||
for(unsigned int i = 0; i < components.size(); i++)
|
for (unsigned int i = 0; i < components.size(); i++) {
|
||||||
{
|
|
||||||
const unsigned int row = i % rowCount;
|
const unsigned int row = i % rowCount;
|
||||||
Vector3f pos(0.0f, 0.0f, 0.0f);
|
Vector3f pos(0.0f, 0.0f, 0.0f);
|
||||||
if(row == 0)
|
if (row == 0) {
|
||||||
{
|
|
||||||
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
||||||
}else{
|
}
|
||||||
// work from the last component
|
else {
|
||||||
|
// Work from the last component.
|
||||||
GuiComponent* lc = components[i-1];
|
GuiComponent* lc = components[i-1];
|
||||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||||
}
|
}
|
||||||
|
@ -222,24 +245,23 @@ 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;
|
||||||
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;
|
||||||
values[i]->setPosition(labels[i]->getPosition() + Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
values[i]->setPosition(labels[i]->getPosition() +
|
||||||
|
Vector3f(labels[i]->getSize().x(),heightDiff, 0));
|
||||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||||
values[i]->setDefaultZIndex(40);
|
values[i]->setDefaultZIndex(40);
|
||||||
|
|
||||||
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
||||||
if(testBot > bottom)
|
if (testBot > bottom)
|
||||||
bottom = testBot;
|
bottom = testBot;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.getPosition().y());
|
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() -
|
||||||
|
mDescContainer.getPosition().y());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void VideoGameListView::updateInfoPanel()
|
void VideoGameListView::updateInfoPanel()
|
||||||
{
|
{
|
||||||
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
|
FileData* file = (mList.size() == 0 || mList.isScrolling()) ? NULL : mList.getSelected();
|
||||||
|
@ -247,8 +269,7 @@ void VideoGameListView::updateInfoPanel()
|
||||||
Utils::FileSystem::removeFile(getTitlePath());
|
Utils::FileSystem::removeFile(getTitlePath());
|
||||||
|
|
||||||
bool fadingOut;
|
bool fadingOut;
|
||||||
if(file == NULL)
|
if (file == nullptr) {
|
||||||
{
|
|
||||||
mVideo->setVideo("");
|
mVideo->setVideo("");
|
||||||
mVideo->setImage("");
|
mVideo->setImage("");
|
||||||
mVideoPlaying = false;
|
mVideoPlaying = false;
|
||||||
|
@ -256,14 +277,13 @@ void VideoGameListView::updateInfoPanel()
|
||||||
//mDescription.setText("");
|
//mDescription.setText("");
|
||||||
fadingOut = true;
|
fadingOut = true;
|
||||||
|
|
||||||
}else{
|
|
||||||
if (!mVideo->setVideo(file->getVideoPath()))
|
|
||||||
{
|
|
||||||
mVideo->setDefaultVideo();
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (!mVideo->setVideo(file->getVideoPath()))
|
||||||
|
mVideo->setDefaultVideo();
|
||||||
|
|
||||||
mVideoPlaying = true;
|
mVideoPlaying = true;
|
||||||
|
|
||||||
// mVideo->setImage(file->getThumbnailPath());
|
|
||||||
mVideo->setImage(file->getImagePath());
|
mVideo->setImage(file->getImagePath());
|
||||||
mThumbnail.setImage(file->getThumbnailPath());
|
mThumbnail.setImage(file->getThumbnailPath());
|
||||||
mMarquee.setImage(file->getMarqueePath());
|
mMarquee.setImage(file->getMarqueePath());
|
||||||
|
@ -280,8 +300,7 @@ void VideoGameListView::updateInfoPanel()
|
||||||
mPlayers.setValue(file->metadata.get("players"));
|
mPlayers.setValue(file->metadata.get("players"));
|
||||||
mName.setValue(file->metadata.get("name"));
|
mName.setValue(file->metadata.get("name"));
|
||||||
|
|
||||||
if(file->getType() == GAME)
|
if (file->getType() == GAME) {
|
||||||
{
|
|
||||||
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
||||||
mPlayCount.setValue(file->metadata.get("playcount"));
|
mPlayCount.setValue(file->metadata.get("playcount"));
|
||||||
}
|
}
|
||||||
|
@ -299,18 +318,13 @@ void VideoGameListView::updateInfoPanel()
|
||||||
std::vector<TextComponent*> labels = getMDLabels();
|
std::vector<TextComponent*> labels = getMDLabels();
|
||||||
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
||||||
|
|
||||||
for(auto it = comps.cbegin(); it != comps.cend(); it++)
|
for (auto it = comps.cbegin(); it != comps.cend(); it++) {
|
||||||
{
|
|
||||||
GuiComponent* comp = *it;
|
GuiComponent* comp = *it;
|
||||||
// an animation is playing
|
// An animation is playing, then animate if reverse != fadingOut
|
||||||
// then animate if reverse != fadingOut
|
// An animation is not playing, then animate if opacity != our target opacity
|
||||||
// an animation is not playing
|
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||||
// then animate if opacity != our target opacity
|
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) {
|
||||||
if((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
auto func = [comp](float t) {
|
||||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255)))
|
|
||||||
{
|
|
||||||
auto func = [comp](float t)
|
|
||||||
{
|
|
||||||
comp->setOpacity((unsigned char)(Math::lerp(0.0f, 1.0f, t)*255));
|
comp->setOpacity((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);
|
||||||
|
@ -325,35 +339,31 @@ void VideoGameListView::launch(FileData* game)
|
||||||
|
|
||||||
Vector3f target(screenWidth / 2.0f, screenHeight / 2.0f, 0);
|
Vector3f target(screenWidth / 2.0f, screenHeight / 2.0f, 0);
|
||||||
|
|
||||||
if(mMarquee.hasImage() &&
|
if (mMarquee.hasImage() &&
|
||||||
(mMarquee.getPosition().x() < screenWidth && mMarquee.getPosition().x() > 0.0f &&
|
(mMarquee.getPosition().x() < screenWidth && mMarquee.getPosition().x() > 0.0f &&
|
||||||
mMarquee.getPosition().y() < screenHeight && mMarquee.getPosition().y() > 0.0f))
|
mMarquee.getPosition().y() < screenHeight && mMarquee.getPosition().y() > 0.0f))
|
||||||
{
|
|
||||||
target = Vector3f(mMarquee.getCenter().x(), mMarquee.getCenter().y(), 0);
|
target = Vector3f(mMarquee.getCenter().x(), mMarquee.getCenter().y(), 0);
|
||||||
}
|
|
||||||
else if(mThumbnail.hasImage() &&
|
else if (mThumbnail.hasImage() &&
|
||||||
(mThumbnail.getPosition().x() < screenWidth && mThumbnail.getPosition().x() > 2.0f &&
|
(mThumbnail.getPosition().x() < screenWidth && mThumbnail.getPosition().x() > 2.0f &&
|
||||||
mThumbnail.getPosition().y() < screenHeight && mThumbnail.getPosition().y() > 2.0f))
|
mThumbnail.getPosition().y() < screenHeight && mThumbnail.getPosition().y() > 2.0f))
|
||||||
{
|
|
||||||
target = Vector3f(mThumbnail.getCenter().x(), mThumbnail.getCenter().y(), 0);
|
target = Vector3f(mThumbnail.getCenter().x(), mThumbnail.getCenter().y(), 0);
|
||||||
}
|
|
||||||
else if(mImage.hasImage() &&
|
else if (mImage.hasImage() &&
|
||||||
(mImage.getPosition().x() < screenWidth && mImage.getPosition().x() > 2.0f &&
|
(mImage.getPosition().x() < screenWidth && mImage.getPosition().x() > 2.0f &&
|
||||||
mImage.getPosition().y() < screenHeight && mImage.getPosition().y() > 2.0f))
|
mImage.getPosition().y() < screenHeight && mImage.getPosition().y() > 2.0f))
|
||||||
{
|
|
||||||
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
target = Vector3f(mImage.getCenter().x(), mImage.getCenter().y(), 0);
|
||||||
}
|
|
||||||
else if(mHeaderImage.hasImage() &&
|
else if (mHeaderImage.hasImage() &&
|
||||||
(mHeaderImage.getPosition().x() < screenWidth && mHeaderImage.getPosition().x() > 0.0f &&
|
(mHeaderImage.getPosition().x() < screenWidth &&
|
||||||
mHeaderImage.getPosition().y() < screenHeight && mHeaderImage.getPosition().y() > 0.0f))
|
mHeaderImage.getPosition().x() > 0.0f &&
|
||||||
{
|
mHeaderImage.getPosition().y() < screenHeight &&
|
||||||
|
mHeaderImage.getPosition().y() > 0.0f))
|
||||||
target = Vector3f(mHeaderImage.getCenter().x(), mHeaderImage.getCenter().y(), 0);
|
target = Vector3f(mHeaderImage.getCenter().x(), mHeaderImage.getCenter().y(), 0);
|
||||||
}
|
|
||||||
else if(mVideo->getPosition().x() < screenWidth && mVideo->getPosition().x() > 0.0f &&
|
else if (mVideo->getPosition().x() < screenWidth && mVideo->getPosition().x() > 0.0f &&
|
||||||
mVideo->getPosition().y() < screenHeight && mVideo->getPosition().y() > 0.0f)
|
mVideo->getPosition().y() < screenHeight && mVideo->getPosition().y() > 0.0f)
|
||||||
{
|
|
||||||
target = Vector3f(mVideo->getCenter().x(), mVideo->getCenter().y(), 0);
|
target = Vector3f(mVideo->getCenter().x(), mVideo->getCenter().y(), 0);
|
||||||
}
|
|
||||||
|
|
||||||
ViewController::get()->launch(game, target);
|
ViewController::get()->launch(game, target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// VideoGameListView.h
|
||||||
|
//
|
||||||
|
// Interface that defines a GameListView of the type 'video'.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_VIDEO_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_VIDEO_GAME_LIST_VIEW_H
|
||||||
#define ES_APP_VIEWS_GAME_LIST_VIDEO_GAME_LIST_VIEW_H
|
#define ES_APP_VIEWS_GAME_LIST_VIDEO_GAME_LIST_VIEW_H
|
||||||
|
@ -36,7 +42,14 @@ private:
|
||||||
VideoComponent* mVideo;
|
VideoComponent* mVideo;
|
||||||
ImageComponent mImage;
|
ImageComponent mImage;
|
||||||
|
|
||||||
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
TextComponent mLblRating;
|
||||||
|
TextComponent mLblReleaseDate;
|
||||||
|
TextComponent mLblDeveloper;
|
||||||
|
TextComponent mLblPublisher;
|
||||||
|
TextComponent mLblGenre;
|
||||||
|
TextComponent mLblPlayers;
|
||||||
|
TextComponent mLblLastPlayed;
|
||||||
|
TextComponent mLblPlayCount;
|
||||||
|
|
||||||
RatingComponent mRating;
|
RatingComponent mRating;
|
||||||
DateTimeComponent mReleaseDate;
|
DateTimeComponent mReleaseDate;
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GuiComponent.cpp
|
||||||
|
//
|
||||||
|
// Basic GUI component handling such as placement, rotation, Z-order, rendering and animation.
|
||||||
|
//
|
||||||
|
|
||||||
#include "GuiComponent.h"
|
#include "GuiComponent.h"
|
||||||
|
|
||||||
#include "animations/Animation.h"
|
#include "animations/Animation.h"
|
||||||
|
@ -8,11 +14,19 @@
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
|
GuiComponent::GuiComponent(Window* window)
|
||||||
mPosition(Vector3f::Zero()), mOrigin(Vector2f::Zero()), mRotationOrigin(0.5, 0.5),
|
: mWindow(window),
|
||||||
mSize(Vector2f::Zero()), mTransform(Transform4x4f::Identity()), mIsProcessing(false), mVisible(true)
|
mParent(NULL),
|
||||||
|
mOpacity(255),
|
||||||
|
mPosition(Vector3f::Zero()),
|
||||||
|
mOrigin(Vector2f::Zero()),
|
||||||
|
mRotationOrigin(0.5, 0.5),
|
||||||
|
mSize(Vector2f::Zero()),
|
||||||
|
mTransform(Transform4x4f::Identity()),
|
||||||
|
mIsProcessing(false),
|
||||||
|
mVisible(true)
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
for (unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
||||||
mAnimationMap[i] = NULL;
|
mAnimationMap[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +36,17 @@ GuiComponent::~GuiComponent()
|
||||||
|
|
||||||
cancelAllAnimations();
|
cancelAllAnimations();
|
||||||
|
|
||||||
if(mParent)
|
if (mParent)
|
||||||
mParent->removeChild(this);
|
mParent->removeChild(this);
|
||||||
|
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->setParent(NULL);
|
getChild(i)->setParent(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiComponent::input(InputConfig* config, Input input)
|
bool GuiComponent::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++) {
|
||||||
{
|
if (getChild(i)->input(config, input))
|
||||||
if(getChild(i)->input(config, input))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,16 +55,14 @@ bool GuiComponent::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
void GuiComponent::updateSelf(int deltaTime)
|
void GuiComponent::updateSelf(int deltaTime)
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
for (unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
||||||
advanceAnimation(i, deltaTime);
|
advanceAnimation(i, deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::updateChildren(int deltaTime)
|
void GuiComponent::updateChildren(int deltaTime)
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
{
|
|
||||||
getChild(i)->update(deltaTime);
|
getChild(i)->update(deltaTime);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::update(int deltaTime)
|
void GuiComponent::update(int deltaTime)
|
||||||
|
@ -71,10 +82,8 @@ void GuiComponent::render(const Transform4x4f& parentTrans)
|
||||||
|
|
||||||
void GuiComponent::renderChildren(const Transform4x4f& transform) const
|
void GuiComponent::renderChildren(const Transform4x4f& transform) const
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
{
|
|
||||||
getChild(i)->render(transform);
|
getChild(i)->render(transform);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3f GuiComponent::getPosition() const
|
Vector3f GuiComponent::getPosition() const
|
||||||
|
@ -175,12 +184,12 @@ Vector2f GuiComponent::getCenter() const
|
||||||
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
|
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Children stuff.
|
// Children stuff.
|
||||||
void GuiComponent::addChild(GuiComponent* cmp)
|
void GuiComponent::addChild(GuiComponent* cmp)
|
||||||
{
|
{
|
||||||
mChildren.push_back(cmp);
|
mChildren.push_back(cmp);
|
||||||
|
|
||||||
if(cmp->getParent())
|
if (cmp->getParent())
|
||||||
cmp->getParent()->removeChild(cmp);
|
cmp->getParent()->removeChild(cmp);
|
||||||
|
|
||||||
cmp->setParent(this);
|
cmp->setParent(this);
|
||||||
|
@ -188,20 +197,16 @@ void GuiComponent::addChild(GuiComponent* cmp)
|
||||||
|
|
||||||
void GuiComponent::removeChild(GuiComponent* cmp)
|
void GuiComponent::removeChild(GuiComponent* cmp)
|
||||||
{
|
{
|
||||||
if(!cmp->getParent())
|
if (!cmp->getParent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(cmp->getParent() != this)
|
if (cmp->getParent() != this)
|
||||||
{
|
|
||||||
LOG(LogError) << "Tried to remove child from incorrect parent!";
|
LOG(LogError) << "Tried to remove child from incorrect parent!";
|
||||||
}
|
|
||||||
|
|
||||||
cmp->setParent(NULL);
|
cmp->setParent(NULL);
|
||||||
|
|
||||||
for(auto i = mChildren.cbegin(); i != mChildren.cend(); i++)
|
for (auto i = mChildren.cbegin(); i != mChildren.cend(); i++) {
|
||||||
{
|
if (*i == cmp) {
|
||||||
if(*i == cmp)
|
|
||||||
{
|
|
||||||
mChildren.erase(i);
|
mChildren.erase(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -248,10 +253,8 @@ unsigned char GuiComponent::getOpacity() const
|
||||||
void GuiComponent::setOpacity(unsigned char opacity)
|
void GuiComponent::setOpacity(unsigned char opacity)
|
||||||
{
|
{
|
||||||
mOpacity = opacity;
|
mOpacity = opacity;
|
||||||
for(auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
for (auto it = mChildren.cbegin(); it != mChildren.cend(); it++)
|
||||||
{
|
|
||||||
(*it)->setOpacity(opacity);
|
(*it)->setOpacity(opacity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transform4x4f& GuiComponent::getTransform()
|
const Transform4x4f& GuiComponent::getTransform()
|
||||||
|
@ -259,28 +262,26 @@ const Transform4x4f& GuiComponent::getTransform()
|
||||||
mTransform = Transform4x4f::Identity();
|
mTransform = Transform4x4f::Identity();
|
||||||
mTransform.translate(mPosition);
|
mTransform.translate(mPosition);
|
||||||
if (mScale != 1.0)
|
if (mScale != 1.0)
|
||||||
{
|
|
||||||
mTransform.scale(mScale);
|
mTransform.scale(mScale);
|
||||||
}
|
if (mRotation != 0.0) {
|
||||||
if (mRotation != 0.0)
|
|
||||||
{
|
|
||||||
// Calculate offset as difference between origin and rotation origin
|
// Calculate offset as difference between origin and rotation origin
|
||||||
Vector2f rotationSize = getRotationSize();
|
Vector2f rotationSize = getRotationSize();
|
||||||
float xOff = (mOrigin.x() - mRotationOrigin.x()) * rotationSize.x();
|
float xOff = (mOrigin.x() - mRotationOrigin.x()) * rotationSize.x();
|
||||||
float yOff = (mOrigin.y() - mRotationOrigin.y()) * rotationSize.y();
|
float yOff = (mOrigin.y() - mRotationOrigin.y()) * rotationSize.y();
|
||||||
|
|
||||||
// transform to offset point
|
// Transform to offset point
|
||||||
if (xOff != 0.0 || yOff != 0.0)
|
if (xOff != 0.0 || yOff != 0.0)
|
||||||
mTransform.translate(Vector3f(xOff * -1, yOff * -1, 0.0f));
|
mTransform.translate(Vector3f(xOff * -1, yOff * -1, 0.0f));
|
||||||
|
|
||||||
// apply rotation transform
|
// Apply rotation transform
|
||||||
mTransform.rotateZ(mRotation);
|
mTransform.rotateZ(mRotation);
|
||||||
|
|
||||||
// Tranform back to original point
|
// Tranform back to original point
|
||||||
if (xOff != 0.0 || yOff != 0.0)
|
if (xOff != 0.0 || yOff != 0.0)
|
||||||
mTransform.translate(Vector3f(xOff, yOff, 0.0f));
|
mTransform.translate(Vector3f(xOff, yOff, 0.0f));
|
||||||
}
|
}
|
||||||
mTransform.translate(Vector3f(mOrigin.x() * mSize.x() * -1, mOrigin.y() * mSize.y() * -1, 0.0f));
|
mTransform.translate(Vector3f(mOrigin.x() * mSize.x() * -1,
|
||||||
|
mOrigin.y() * mSize.y() * -1, 0.0f));
|
||||||
return mTransform;
|
return mTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,32 +296,31 @@ std::string GuiComponent::getValue() const
|
||||||
|
|
||||||
void GuiComponent::textInput(const char* text)
|
void GuiComponent::textInput(const char* text)
|
||||||
{
|
{
|
||||||
for(auto iter = mChildren.cbegin(); iter != mChildren.cend(); iter++)
|
for (auto iter = mChildren.cbegin(); iter != mChildren.cend(); iter++)
|
||||||
{
|
|
||||||
(*iter)->textInput(text);
|
(*iter)->textInput(text);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::setAnimation(Animation* anim, int delay, std::function<void()> finishedCallback, bool reverse, unsigned char slot)
|
void GuiComponent::setAnimation(Animation* anim, int delay,
|
||||||
|
std::function<void()> finishedCallback, bool reverse, unsigned char slot)
|
||||||
{
|
{
|
||||||
assert(slot < MAX_ANIMATIONS);
|
assert(slot < MAX_ANIMATIONS);
|
||||||
|
|
||||||
AnimationController* oldAnim = mAnimationMap[slot];
|
AnimationController* oldAnim = mAnimationMap[slot];
|
||||||
mAnimationMap[slot] = new AnimationController(anim, delay, finishedCallback, reverse);
|
mAnimationMap[slot] = new AnimationController(anim, delay, finishedCallback, reverse);
|
||||||
|
|
||||||
if(oldAnim)
|
if (oldAnim)
|
||||||
delete oldAnim;
|
delete oldAnim;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GuiComponent::stopAnimation(unsigned char slot)
|
bool GuiComponent::stopAnimation(unsigned char slot)
|
||||||
{
|
{
|
||||||
assert(slot < MAX_ANIMATIONS);
|
assert(slot < MAX_ANIMATIONS);
|
||||||
if(mAnimationMap[slot])
|
if (mAnimationMap[slot]) {
|
||||||
{
|
|
||||||
delete mAnimationMap[slot];
|
delete mAnimationMap[slot];
|
||||||
mAnimationMap[slot] = NULL;
|
mAnimationMap[slot] = NULL;
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,13 +328,13 @@ bool GuiComponent::stopAnimation(unsigned char slot)
|
||||||
bool GuiComponent::cancelAnimation(unsigned char slot)
|
bool GuiComponent::cancelAnimation(unsigned char slot)
|
||||||
{
|
{
|
||||||
assert(slot < MAX_ANIMATIONS);
|
assert(slot < MAX_ANIMATIONS);
|
||||||
if(mAnimationMap[slot])
|
if (mAnimationMap[slot]) {
|
||||||
{
|
|
||||||
mAnimationMap[slot]->removeFinishedCallback();
|
mAnimationMap[slot]->removeFinishedCallback();
|
||||||
delete mAnimationMap[slot];
|
delete mAnimationMap[slot];
|
||||||
mAnimationMap[slot] = NULL;
|
mAnimationMap[slot] = NULL;
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,16 +342,17 @@ bool GuiComponent::cancelAnimation(unsigned char slot)
|
||||||
bool GuiComponent::finishAnimation(unsigned char slot)
|
bool GuiComponent::finishAnimation(unsigned char slot)
|
||||||
{
|
{
|
||||||
assert(slot < MAX_ANIMATIONS);
|
assert(slot < MAX_ANIMATIONS);
|
||||||
if(mAnimationMap[slot])
|
if (mAnimationMap[slot]) {
|
||||||
{
|
// Skip to animation's end
|
||||||
// skip to animation's end
|
const bool done = mAnimationMap[slot]->update(mAnimationMap[slot]->
|
||||||
const bool done = mAnimationMap[slot]->update(mAnimationMap[slot]->getAnimation()->getDuration() - mAnimationMap[slot]->getTime());
|
getAnimation()->getDuration() - mAnimationMap[slot]->getTime());
|
||||||
assert(done);
|
assert(done);
|
||||||
|
|
||||||
delete mAnimationMap[slot]; // will also call finishedCallback
|
delete mAnimationMap[slot]; // Will also call finishedCallback
|
||||||
mAnimationMap[slot] = NULL;
|
mAnimationMap[slot] = NULL;
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,29 +361,28 @@ bool GuiComponent::advanceAnimation(unsigned char slot, unsigned int time)
|
||||||
{
|
{
|
||||||
assert(slot < MAX_ANIMATIONS);
|
assert(slot < MAX_ANIMATIONS);
|
||||||
AnimationController* anim = mAnimationMap[slot];
|
AnimationController* anim = mAnimationMap[slot];
|
||||||
if(anim)
|
if (anim) {
|
||||||
{
|
|
||||||
bool done = anim->update(time);
|
bool done = anim->update(time);
|
||||||
if(done)
|
if (done) {
|
||||||
{
|
|
||||||
mAnimationMap[slot] = NULL;
|
mAnimationMap[slot] = NULL;
|
||||||
delete anim;
|
delete anim;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::stopAllAnimations()
|
void GuiComponent::stopAllAnimations()
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
for (unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
||||||
stopAnimation(i);
|
stopAnimation(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::cancelAllAnimations()
|
void GuiComponent::cancelAllAnimations()
|
||||||
{
|
{
|
||||||
for(unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
for (unsigned char i = 0; i < MAX_ANIMATIONS; i++)
|
||||||
cancelAnimation(i);
|
cancelAnimation(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,41 +403,44 @@ int GuiComponent::getAnimationTime(unsigned char slot) const
|
||||||
return mAnimationMap[slot]->getTime();
|
return mAnimationMap[slot]->getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
|
const std::string& view, const std::string& element, unsigned int properties)
|
||||||
{
|
{
|
||||||
Vector2f scale = getParent() ? getParent()->getSize() : Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
Vector2f scale = getParent() ? getParent()->getSize()
|
||||||
|
: Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
|
|
||||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
|
||||||
if(!elem)
|
if (!elem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
if(properties & POSITION && elem->has("pos"))
|
if (properties & POSITION && elem->has("pos")) {
|
||||||
{
|
|
||||||
Vector2f denormalized = elem->get<Vector2f>("pos") * scale;
|
Vector2f denormalized = elem->get<Vector2f>("pos") * scale;
|
||||||
setPosition(Vector3f(denormalized.x(), denormalized.y(), 0));
|
setPosition(Vector3f(denormalized.x(), denormalized.y(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
if (properties & ThemeFlags::SIZE && elem->has("size"))
|
||||||
setSize(elem->get<Vector2f>("size") * scale);
|
setSize(elem->get<Vector2f>("size") * scale);
|
||||||
|
|
||||||
// position + size also implies origin
|
// Position + size also implies origin
|
||||||
if((properties & ORIGIN || (properties & POSITION && properties & ThemeFlags::SIZE)) && elem->has("origin"))
|
if ((properties & ORIGIN || (properties & POSITION &&
|
||||||
|
properties & ThemeFlags::SIZE)) && elem->has("origin")) {
|
||||||
setOrigin(elem->get<Vector2f>("origin"));
|
setOrigin(elem->get<Vector2f>("origin"));
|
||||||
|
}
|
||||||
|
|
||||||
if(properties & ThemeFlags::ROTATION) {
|
if (properties & ThemeFlags::ROTATION) {
|
||||||
if(elem->has("rotation"))
|
if (elem->has("rotation"))
|
||||||
setRotationDegrees(elem->get<float>("rotation"));
|
setRotationDegrees(elem->get<float>("rotation"));
|
||||||
if(elem->has("rotationOrigin"))
|
if (elem->has("rotationOrigin"))
|
||||||
setRotationOrigin(elem->get<Vector2f>("rotationOrigin"));
|
setRotationOrigin(elem->get<Vector2f>("rotationOrigin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(properties & ThemeFlags::Z_INDEX && elem->has("zIndex"))
|
if (properties & ThemeFlags::Z_INDEX && elem->has("zIndex"))
|
||||||
setZIndex(elem->get<float>("zIndex"));
|
setZIndex(elem->get<float>("zIndex"));
|
||||||
else
|
else
|
||||||
setZIndex(getDefaultZIndex());
|
setZIndex(getDefaultZIndex());
|
||||||
|
|
||||||
if(properties & ThemeFlags::VISIBLE && elem->has("visible"))
|
if (properties & ThemeFlags::VISIBLE && elem->has("visible"))
|
||||||
setVisible(elem->get<bool>("visible"));
|
setVisible(elem->get<bool>("visible"));
|
||||||
else
|
else
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
@ -445,15 +448,14 @@ void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std
|
||||||
|
|
||||||
void GuiComponent::updateHelpPrompts()
|
void GuiComponent::updateHelpPrompts()
|
||||||
{
|
{
|
||||||
if(getParent())
|
if (getParent()) {
|
||||||
{
|
|
||||||
getParent()->updateHelpPrompts();
|
getParent()->updateHelpPrompts();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<HelpPrompt> prompts = getHelpPrompts();
|
std::vector<HelpPrompt> prompts = getHelpPrompts();
|
||||||
|
|
||||||
if(mWindow->peekGui() == this)
|
if (mWindow->peekGui() == this)
|
||||||
mWindow->setHelpPrompts(prompts, getHelpStyle());
|
mWindow->setHelpPrompts(prompts, getHelpStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,30 +471,30 @@ bool GuiComponent::isProcessing() const
|
||||||
|
|
||||||
void GuiComponent::onShow()
|
void GuiComponent::onShow()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->onShow();
|
getChild(i)->onShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::onHide()
|
void GuiComponent::onHide()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->onHide();
|
getChild(i)->onHide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::onScreenSaverActivate()
|
void GuiComponent::onScreenSaverActivate()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->onScreenSaverActivate();
|
getChild(i)->onScreenSaverActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::onScreenSaverDeactivate()
|
void GuiComponent::onScreenSaverDeactivate()
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->onScreenSaverDeactivate();
|
getChild(i)->onScreenSaverDeactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComponent::topWindow(bool isTop)
|
void GuiComponent::topWindow(bool isTop)
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < getChildCount(); i++)
|
for (unsigned int i = 0; i < getChildCount(); i++)
|
||||||
getChild(i)->topWindow(isTop);
|
getChild(i)->topWindow(isTop);
|
||||||
}
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
|
//
|
||||||
|
// GuiComponent.h
|
||||||
|
//
|
||||||
|
// Basic GUI component handling such as placement, rotation, Z-order, rendering and animation.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_CORE_GUI_COMPONENT_H
|
#ifndef ES_CORE_GUI_COMPONENT_H
|
||||||
#define ES_CORE_GUI_COMPONENT_H
|
#define ES_CORE_GUI_COMPONENT_H
|
||||||
|
@ -25,36 +31,47 @@ public:
|
||||||
|
|
||||||
virtual void textInput(const char* text);
|
virtual void textInput(const char* text);
|
||||||
|
|
||||||
//Called when input is received.
|
// Called when input is received.
|
||||||
//Return true if the input is consumed, false if it should continue to be passed to other children.
|
// Return true if the input is consumed, false if
|
||||||
|
// it should continue to be passed to other children.
|
||||||
virtual bool input(InputConfig* config, Input input);
|
virtual bool input(InputConfig* config, Input input);
|
||||||
|
|
||||||
//Called when time passes. Default implementation calls updateSelf(deltaTime) and updateChildren(deltaTime) - so you should probably call GuiComponent::update(deltaTime) at some point (or at least updateSelf so animations work).
|
// Called when time passes.
|
||||||
|
// Default implementation calls updateSelf(deltaTime) and updateChildren(deltaTime).
|
||||||
|
// So you should probably call GuiComponent::update(deltaTime) at some point (or at
|
||||||
|
// least updateSelf so animations work).
|
||||||
virtual void update(int deltaTime);
|
virtual void update(int deltaTime);
|
||||||
|
|
||||||
//Called when it's time to render. By default, just calls renderChildren(parentTrans * getTransform()).
|
// Called when it's time to render.
|
||||||
//You probably want to override this like so:
|
// By default, just calls renderChildren(parentTrans * getTransform()).
|
||||||
//1. Calculate the new transform that your control will draw at with Transform4x4f t = parentTrans * getTransform().
|
// You probably want to override this like so:
|
||||||
//2. Set the renderer to use that new transform as the model matrix - Renderer::setMatrix(t);
|
// 1. Calculate the new transform that your control will draw at with
|
||||||
//3. Draw your component.
|
// Transform4x4f t = parentTrans * getTransform().
|
||||||
//4. Tell your children to render, based on your component's transform - renderChildren(t).
|
// 2. Set the renderer to use that new transform as the model matrix
|
||||||
|
// Renderer::setMatrix(t);
|
||||||
|
// 3. Draw your component.
|
||||||
|
// 4. Tell your children to render, based on your component's transform - renderChildren(t).
|
||||||
virtual void render(const Transform4x4f& parentTrans);
|
virtual void render(const Transform4x4f& parentTrans);
|
||||||
|
|
||||||
Vector3f getPosition() const;
|
Vector3f getPosition() const;
|
||||||
inline void setPosition(const Vector3f& offset) { setPosition(offset.x(), offset.y(), offset.z()); }
|
inline void setPosition(const Vector3f& offset)
|
||||||
|
{ setPosition(offset.x(), offset.y(), offset.z()); }
|
||||||
void setPosition(float x, float y, float z = 0.0f);
|
void setPosition(float x, float y, float z = 0.0f);
|
||||||
virtual void onPositionChanged() {};
|
virtual void onPositionChanged() {};
|
||||||
|
|
||||||
//Sets the origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
// Sets the origin as a percentage of this image.
|
||||||
|
// (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
||||||
Vector2f getOrigin() const;
|
Vector2f getOrigin() const;
|
||||||
void setOrigin(float originX, float originY);
|
void setOrigin(float originX, float originY);
|
||||||
inline void setOrigin(Vector2f origin) { setOrigin(origin.x(), origin.y()); }
|
inline void setOrigin(Vector2f origin) { setOrigin(origin.x(), origin.y()); }
|
||||||
virtual void onOriginChanged() {};
|
virtual void onOriginChanged() {};
|
||||||
|
|
||||||
//Sets the rotation origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
// Sets the rotation origin as a percentage of this image.
|
||||||
|
// (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
|
||||||
Vector2f getRotationOrigin() const;
|
Vector2f getRotationOrigin() const;
|
||||||
void setRotationOrigin(float originX, float originY);
|
void setRotationOrigin(float originX, float originY);
|
||||||
inline void setRotationOrigin(Vector2f origin) { setRotationOrigin(origin.x(), origin.y()); }
|
inline void setRotationOrigin(Vector2f origin)
|
||||||
|
{ setRotationOrigin(origin.x(), origin.y()); }
|
||||||
|
|
||||||
virtual Vector2f getSize() const;
|
virtual Vector2f getSize() const;
|
||||||
inline void setSize(const Vector2f& size) { setSize(size.x(), size.y()); }
|
inline void setSize(const Vector2f& size) { setSize(size.x(), size.y()); }
|
||||||
|
@ -92,15 +109,22 @@ public:
|
||||||
unsigned int getChildCount() const;
|
unsigned int getChildCount() const;
|
||||||
GuiComponent* getChild(unsigned int i) const;
|
GuiComponent* getChild(unsigned int i) const;
|
||||||
|
|
||||||
// animation will be automatically deleted when it completes or is stopped.
|
// Animation will be automatically deleted when it completes or is stopped.
|
||||||
bool isAnimationPlaying(unsigned char slot) const;
|
bool isAnimationPlaying(unsigned char slot) const;
|
||||||
bool isAnimationReversed(unsigned char slot) const;
|
bool isAnimationReversed(unsigned char slot) const;
|
||||||
int getAnimationTime(unsigned char slot) const;
|
int getAnimationTime(unsigned char slot) const;
|
||||||
void setAnimation(Animation* animation, int delay = 0, std::function<void()> finishedCallback = nullptr, bool reverse = false, unsigned char slot = 0);
|
void setAnimation(Animation* animation, int delay = 0,
|
||||||
|
std::function<void()> finishedCallback = nullptr,
|
||||||
|
bool reverse = false, unsigned char slot = 0);
|
||||||
bool stopAnimation(unsigned char slot);
|
bool stopAnimation(unsigned char slot);
|
||||||
bool cancelAnimation(unsigned char slot); // Like stopAnimation, but doesn't call finishedCallback - only removes the animation, leaving things in their current state. Returns true if successful (an animation was in this slot).
|
// Like stopAnimation, but doesn't call finishedCallback - only removes the animation, leaving
|
||||||
bool finishAnimation(unsigned char slot); // Calls update(1.f) and finishedCallback, then deletes the animation - basically skips to the end. Returns true if successful (an animation was in this slot).
|
// things in their current state. Returns true if successful (an animation was in this slot).
|
||||||
bool advanceAnimation(unsigned char slot, unsigned int time); // Returns true if successful (an animation was in this slot).
|
bool cancelAnimation(unsigned char slot);
|
||||||
|
// Calls update(1.f) and finishedCallback, then deletes the animation - basically skips
|
||||||
|
// to the end. Returns true if successful (an animation was in this slot).
|
||||||
|
bool finishAnimation(unsigned char slot);
|
||||||
|
// Returns true if successful (an animation was in this slot).
|
||||||
|
bool advanceAnimation(unsigned char slot, unsigned int time);
|
||||||
void stopAllAnimations();
|
void stopAllAnimations();
|
||||||
void cancelAllAnimations();
|
void cancelAllAnimations();
|
||||||
|
|
||||||
|
@ -124,7 +148,8 @@ public:
|
||||||
|
|
||||||
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
||||||
// You probably want to keep this behavior for any derived classes as well as add your own.
|
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties);
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
|
const std::string& view, const std::string& element, unsigned int properties);
|
||||||
|
|
||||||
// Returns a list of help prompts.
|
// Returns a list of help prompts.
|
||||||
virtual std::vector<HelpPrompt> getHelpPrompts() { return std::vector<HelpPrompt>(); };
|
virtual std::vector<HelpPrompt> getHelpPrompts() { return std::vector<HelpPrompt>(); };
|
||||||
|
@ -137,10 +162,12 @@ public:
|
||||||
// Returns true if the component is busy doing background processing (e.g. HTTP downloads)
|
// Returns true if the component is busy doing background processing (e.g. HTTP downloads)
|
||||||
bool isProcessing() const;
|
bool isProcessing() const;
|
||||||
|
|
||||||
|
const static unsigned char MAX_ANIMATIONS = 4;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void renderChildren(const Transform4x4f& transform) const;
|
void renderChildren(const Transform4x4f& transform) const;
|
||||||
void updateSelf(int deltaTime); // updates animations
|
void updateSelf(int deltaTime); // Updates animations
|
||||||
void updateChildren(int deltaTime); // updates animations
|
void updateChildren(int deltaTime); // Updates animations
|
||||||
|
|
||||||
unsigned char mOpacity;
|
unsigned char mOpacity;
|
||||||
Window* mWindow;
|
Window* mWindow;
|
||||||
|
@ -162,11 +189,9 @@ protected:
|
||||||
bool mIsProcessing;
|
bool mIsProcessing;
|
||||||
bool mVisible;
|
bool mVisible;
|
||||||
|
|
||||||
public:
|
|
||||||
const static unsigned char MAX_ANIMATIONS = 4;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Transform4x4f mTransform; //Don't access this directly! Use getTransform()!
|
// Don't access this directly! Use getTransform()!
|
||||||
|
Transform4x4f mTransform;
|
||||||
AnimationController* mAnimationMap[MAX_ANIMATIONS];
|
AnimationController* mAnimationMap[MAX_ANIMATIONS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ void Settings::setDefaults()
|
||||||
mStringMap["StartupSystem"] = "";
|
mStringMap["StartupSystem"] = "";
|
||||||
mBoolMap["DisableKidStartMenu"] = true;
|
mBoolMap["DisableKidStartMenu"] = true;
|
||||||
mStringMap["MediaDirectory"] = "";
|
mStringMap["MediaDirectory"] = "";
|
||||||
|
mStringMap["DefaultSortOrder"] = "";
|
||||||
|
|
||||||
mBoolMap["VSync"] = true;
|
mBoolMap["VSync"] = true;
|
||||||
|
|
||||||
|
@ -139,9 +140,9 @@ void Settings::setDefaults()
|
||||||
mStringMap["CollectionSystemsAuto"] = "";
|
mStringMap["CollectionSystemsAuto"] = "";
|
||||||
mStringMap["CollectionSystemsCustom"] = "";
|
mStringMap["CollectionSystemsCustom"] = "";
|
||||||
mBoolMap["CollectionShowSystemInfo"] = true;
|
mBoolMap["CollectionShowSystemInfo"] = true;
|
||||||
mBoolMap["SortAllSystems"] = false;
|
|
||||||
mBoolMap["UseCustomCollectionsSystem"] = true;
|
mBoolMap["UseCustomCollectionsSystem"] = true;
|
||||||
|
|
||||||
|
mBoolMap["FavFirstCustom"] = true;
|
||||||
mBoolMap["FavoritesFirst"] = true;
|
mBoolMap["FavoritesFirst"] = true;
|
||||||
mBoolMap["LaunchstringOverride"] = true;
|
mBoolMap["LaunchstringOverride"] = true;
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,77 @@
|
||||||
|
//
|
||||||
|
// GuiComplexTextEditPopup.cpp
|
||||||
|
//
|
||||||
|
// Text edit popup with a title, two text strings, a text input box and buttons
|
||||||
|
// to load the second text string and to clear the input field.
|
||||||
|
// Intended for updating settings for configuration files and similar.
|
||||||
|
//
|
||||||
|
|
||||||
#include "guis/GuiComplexTextEditPopup.h"
|
#include "guis/GuiComplexTextEditPopup.h"
|
||||||
|
|
||||||
#include "components/ButtonComponent.h"
|
#include "components/ButtonComponent.h"
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
#include "components/TextEditComponent.h"
|
#include "components/TextEditComponent.h"
|
||||||
|
|
||||||
GuiComplexTextEditPopup::GuiComplexTextEditPopup(Window* window, const std::string& title, const std::string& infoString1, const std::string& infoString2,
|
GuiComplexTextEditPopup::GuiComplexTextEditPopup(
|
||||||
const std::string& initValue, const std::function<void(const std::string&)>& okCallback, bool multiLine, const char* acceptBtnText)
|
Window* window,
|
||||||
: GuiComponent(window), mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 5)), mMultiLine(multiLine)
|
const std::string& title,
|
||||||
|
const std::string& infoString1,
|
||||||
|
const std::string& infoString2,
|
||||||
|
const std::string& initValue,
|
||||||
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
|
bool multiLine, const char* acceptBtnText)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mBackground(window, ":/frame.png"),
|
||||||
|
mGrid(window, Vector2i(1, 5)),
|
||||||
|
mMultiLine(multiLine)
|
||||||
{
|
{
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
addChild(&mGrid);
|
addChild(&mGrid);
|
||||||
|
|
||||||
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title), Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
mTitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(title),
|
||||||
mInfoString1 = std::make_shared<TextComponent>(mWindow, infoString1, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
Font::get(FONT_SIZE_MEDIUM), 0x555555FF, ALIGN_CENTER);
|
||||||
mInfoString2 = std::make_shared<TextComponent>(mWindow, infoString2, Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
mInfoString1 = std::make_shared<TextComponent>(mWindow, infoString1,
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
||||||
|
mInfoString2 = std::make_shared<TextComponent>(mWindow, infoString2,
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x555555FF, ALIGN_CENTER);
|
||||||
|
|
||||||
mText = std::make_shared<TextEditComponent>(mWindow);
|
mText = std::make_shared<TextEditComponent>(mWindow);
|
||||||
mText->setValue(initValue);
|
mText->setValue(initValue);
|
||||||
|
|
||||||
if(!multiLine)
|
if (!multiLine)
|
||||||
mText->setCursor(initValue.size());
|
mText->setCursor(initValue.size());
|
||||||
|
|
||||||
std::vector< std::shared_ptr<ButtonComponent> > buttons;
|
std::vector< std::shared_ptr<ButtonComponent> > buttons;
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, acceptBtnText, acceptBtnText, [this, okCallback] { okCallback(mText->getValue()); delete this; }));
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, acceptBtnText, acceptBtnText,
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "LOAD", "load default string", [this, infoString2] { mText->setValue(infoString2); }));
|
[this, okCallback] { okCallback(mText->getValue()); delete this; }));
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear string", [this] { mText->setValue(""); }));
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "LOAD", "load default string",
|
||||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "discard changes", [this] { delete this; }));
|
[this, infoString2] { mText->setValue(infoString2); }));
|
||||||
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CLEAR", "clear string",
|
||||||
|
[this] { mText->setValue(""); }));
|
||||||
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "discard changes",
|
||||||
|
[this] { delete this; }));
|
||||||
|
|
||||||
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||||
|
|
||||||
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
|
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
|
||||||
mGrid.setEntry(mInfoString1, Vector2i(0, 1), false, true);
|
mGrid.setEntry(mInfoString1, Vector2i(0, 1), false, true);
|
||||||
mGrid.setEntry(mInfoString2, Vector2i(0, 2), false, true);
|
mGrid.setEntry(mInfoString2, Vector2i(0, 2), false, true);
|
||||||
mGrid.setEntry(mText, Vector2i(0, 3), true, false, Vector2i(1, 1), GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
mGrid.setEntry(mText, Vector2i(0, 3), true, false, Vector2i(1, 1),
|
||||||
|
GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM);
|
||||||
mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false);
|
mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false);
|
||||||
mGrid.setRowHeightPerc(1, 0.15, true);
|
mGrid.setRowHeightPerc(1, 0.15, true);
|
||||||
|
|
||||||
float textHeight = mText->getFont()->getHeight();
|
float textHeight = mText->getFont()->getHeight();
|
||||||
if(multiLine)
|
|
||||||
|
if (multiLine)
|
||||||
textHeight *= 6;
|
textHeight *= 6;
|
||||||
|
|
||||||
mText->setSize(0, textHeight);
|
mText->setSize(0, textHeight);
|
||||||
|
|
||||||
setSize(Renderer::getScreenWidth() * 0.75f, mTitle->getFont()->getHeight() + textHeight + mButtonGrid->getSize().y() + 220);
|
setSize(Renderer::getScreenWidth() * 0.75f,mTitle->getFont()->getHeight() +
|
||||||
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2);
|
textHeight + mButtonGrid->getSize().y() + 220);
|
||||||
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
||||||
|
(Renderer::getScreenHeight() - mSize.y()) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuiComplexTextEditPopup::onSizeChanged()
|
void GuiComplexTextEditPopup::onSizeChanged()
|
||||||
|
@ -51,7 +80,7 @@ void GuiComplexTextEditPopup::onSizeChanged()
|
||||||
|
|
||||||
mText->setSize(mSize.x() - 40, mText->getSize().y());
|
mText->setSize(mSize.x() - 40, mText->getSize().y());
|
||||||
|
|
||||||
// update grid
|
// Update grid
|
||||||
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y());
|
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y());
|
||||||
mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y() / mSize.y());
|
mGrid.setRowHeightPerc(2, mButtonGrid->getSize().y() / mSize.y());
|
||||||
mGrid.setSize(mSize);
|
mGrid.setSize(mSize);
|
||||||
|
@ -59,12 +88,11 @@ void GuiComplexTextEditPopup::onSizeChanged()
|
||||||
|
|
||||||
bool GuiComplexTextEditPopup::input(InputConfig* config, Input input)
|
bool GuiComplexTextEditPopup::input(InputConfig* config, Input input)
|
||||||
{
|
{
|
||||||
if(GuiComponent::input(config, input))
|
if (GuiComponent::input(config, input))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// pressing back when not text editing closes us
|
// Pressing back button when not text editing closes us
|
||||||
if(config->isMappedTo("b", input) && input.value)
|
if (config->isMappedTo("b", input) && input.value) {
|
||||||
{
|
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
//
|
||||||
|
// GuiComplexTextEditPopup.h
|
||||||
|
//
|
||||||
|
// Text edit popup with a title, two text strings, a text input box and buttons
|
||||||
|
// to load the second text string and to clear the input field.
|
||||||
|
// Intended for updating settings for configuration files and similar.
|
||||||
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
#ifndef ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
||||||
#define ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
#define ES_CORE_GUIS_GUI_COMPLEX_TEXT_EDIT_POPUP_H
|
||||||
|
@ -12,8 +20,15 @@ class TextEditComponent;
|
||||||
class GuiComplexTextEditPopup : public GuiComponent
|
class GuiComplexTextEditPopup : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GuiComplexTextEditPopup(Window* window, const std::string& title, const std::string& infoString1, const std::string& infoString2,
|
GuiComplexTextEditPopup(
|
||||||
const std::string& initValue, const std::function<void(const std::string&)>& okCallback, bool multiLine, const char* acceptBtnText = "OK");
|
Window* window,
|
||||||
|
const std::string& title,
|
||||||
|
const std::string& infoString1,
|
||||||
|
const std::string& infoString2,
|
||||||
|
const std::string& initValue,
|
||||||
|
const std::function<void(const std::string&)>& okCallback,
|
||||||
|
bool multiLine,
|
||||||
|
const char* acceptBtnText = "OK");
|
||||||
|
|
||||||
bool input(InputConfig* config, Input input);
|
bool input(InputConfig* config, Input input);
|
||||||
void onSizeChanged();
|
void onSizeChanged();
|
||||||
|
|
Loading…
Reference in a new issue