Added support for defining multiple imageType entries.

Also made some improvements to GameSelectorComponent and related logic.
This commit is contained in:
Leon Styhre 2022-02-14 19:32:07 +01:00
parent eb3729a5fb
commit 4f019c3775
17 changed files with 369 additions and 154 deletions

View file

@ -765,6 +765,9 @@ void FileData::countGames(std::pair<unsigned int, unsigned int>& gameCount)
void FileData::updateLastPlayedList() void FileData::updateLastPlayedList()
{ {
if (mUpdateListCallback)
mUpdateListCallback();
if (!mUpdateChildrenLastPlayed) if (!mUpdateChildrenLastPlayed)
return; return;
@ -780,6 +783,9 @@ void FileData::updateLastPlayedList()
void FileData::updateMostPlayedList() void FileData::updateMostPlayedList()
{ {
if (mUpdateListCallback)
mUpdateListCallback();
if (!mUpdateChildrenMostPlayed) if (!mUpdateChildrenMostPlayed)
return; return;

View file

@ -14,6 +14,7 @@
#include "MetaData.h" #include "MetaData.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include <functional>
#include <unordered_map> #include <unordered_map>
class SystemData; class SystemData;
@ -62,6 +63,7 @@ public:
const std::vector<FileData*>& getChildrenMostPlayed() const { return mChildrenMostPlayed; } const std::vector<FileData*>& getChildrenMostPlayed() const { return mChildrenMostPlayed; }
void setUpdateChildrenLastPlayed(bool state) { mUpdateChildrenLastPlayed = state; } void setUpdateChildrenLastPlayed(bool state) { mUpdateChildrenLastPlayed = state; }
void setUpdateChildrenMostPlayed(bool state) { mUpdateChildrenMostPlayed = state; } void setUpdateChildrenMostPlayed(bool state) { mUpdateChildrenMostPlayed = state; }
void setUpdateListCallback(const std::function<void()>& func) { mUpdateListCallback = func; }
const bool getOnlyFoldersFlag() const { return mOnlyFolders; } const bool getOnlyFoldersFlag() const { return mOnlyFolders; }
const bool getHasFoldersFlag() const { return mHasFolders; } const bool getHasFoldersFlag() const { return mHasFolders; }
@ -156,6 +158,7 @@ private:
std::vector<FileData*> mFilteredChildren; std::vector<FileData*> mFilteredChildren;
std::vector<FileData*> mChildrenLastPlayed; std::vector<FileData*> mChildrenLastPlayed;
std::vector<FileData*> mChildrenMostPlayed; std::vector<FileData*> mChildrenMostPlayed;
std::function<void()> mUpdateListCallback;
// The pair includes all games, and favorite games. // The pair includes all games, and favorite games.
std::pair<unsigned int, unsigned int> mGameCount; std::pair<unsigned int, unsigned int> mGameCount;
bool mOnlyFolders; bool mOnlyFolders;

View file

@ -107,7 +107,7 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
mImageComponents.push_back(std::make_unique<ImageComponent>()); mImageComponents.push_back(std::make_unique<ImageComponent>());
mImageComponents.back()->setDefaultZIndex(30.0f); mImageComponents.back()->setDefaultZIndex(30.0f);
mImageComponents.back()->applyTheme(theme, "gamelist", element.first, ALL); mImageComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
if (mImageComponents.back()->getThemeImageType() != "") if (mImageComponents.back()->getThemeImageTypes().size() != 0)
mImageComponents.back()->setScrollHide(true); mImageComponents.back()->setScrollHide(true);
addChild(mImageComponents.back().get()); addChild(mImageComponents.back().get());
} }
@ -116,7 +116,7 @@ void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
mVideoComponents.back()->setDefaultZIndex(30.0f); mVideoComponents.back()->setDefaultZIndex(30.0f);
addChild(mVideoComponents.back().get()); addChild(mVideoComponents.back().get());
mVideoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL); mVideoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
if (mVideoComponents.back()->getThemeImageType() != "") if (mVideoComponents.back()->getThemeImageTypes().size() != 0)
mVideoComponents.back()->setScrollHide(true); mVideoComponents.back()->setScrollHide(true);
} }
else if (element.second.type == "animation") { else if (element.second.type == "animation") {
@ -387,50 +387,11 @@ void GamelistView::updateInfoPanel()
mRandomGame = CollectionSystemsManager::getInstance()->updateCollectionFolderMetadata( mRandomGame = CollectionSystemsManager::getInstance()->updateCollectionFolderMetadata(
file->getSystem()); file->getSystem());
if (mRandomGame) { if (mRandomGame) {
for (auto& image : mImageComponents) { for (auto& image : mImageComponents)
if (image->getThemeImageType() == "image") setGameImage(mRandomGame, image.get());
image->setImage(mRandomGame->getImagePath());
else if (image->getThemeImageType() == "miximage")
image->setImage(mRandomGame->getMiximagePath());
else if (image->getThemeImageType() == "marquee")
image->setImage(mRandomGame->getMarqueePath());
else if (image->getThemeImageType() == "screenshot")
image->setImage(mRandomGame->getScreenshotPath());
else if (image->getThemeImageType() == "titlescreen")
image->setImage(mRandomGame->getTitleScreenPath());
else if (image->getThemeImageType() == "cover")
image->setImage(mRandomGame->getCoverPath());
else if (image->getThemeImageType() == "backcover")
image->setImage(mRandomGame->getBackCoverPath());
else if (image->getThemeImageType() == "3dbox")
image->setImage(mRandomGame->get3DBoxPath());
else if (image->getThemeImageType() == "fanart")
image->setImage(mRandomGame->getFanArtPath());
else if (image->getThemeImageType() == "thumbnail")
image->setImage(mRandomGame->getThumbnailPath());
}
for (auto& video : mVideoComponents) { for (auto& video : mVideoComponents) {
if (video->getThemeImageType() == "image") setGameImage(mRandomGame, video.get());
video->setImage(mRandomGame->getImagePath());
else if (video->getThemeImageType() == "miximage")
video->setImage(mRandomGame->getMiximagePath());
else if (video->getThemeImageType() == "marquee")
video->setImage(mRandomGame->getMarqueePath());
else if (video->getThemeImageType() == "screenshot")
video->setImage(mRandomGame->getScreenshotPath());
else if (video->getThemeImageType() == "titlescreen")
video->setImage(mRandomGame->getTitleScreenPath());
else if (video->getThemeImageType() == "cover")
video->setImage(mRandomGame->getCoverPath());
else if (video->getThemeImageType() == "backcover")
video->setImage(mRandomGame->getBackCoverPath());
else if (video->getThemeImageType() == "3dbox")
video->setImage(mRandomGame->get3DBoxPath());
else if (video->getThemeImageType() == "fanart")
video->setImage(mRandomGame->getFanArtPath());
else if (video->getThemeImageType() == "thumbnail")
video->setImage(mRandomGame->getThumbnailPath());
// Always stop the video before setting a new video as it will otherwise // Always stop the video before setting a new video as it will otherwise
// continue to play if it has the same path (i.e. it is the same physical // continue to play if it has the same path (i.e. it is the same physical
@ -447,7 +408,7 @@ void GamelistView::updateInfoPanel()
} }
else { else {
for (auto& image : mImageComponents) { for (auto& image : mImageComponents) {
if (image->getThemeImageType() != "") if (image->getThemeImageTypes().size() != 0)
image->setImage(""); image->setImage("");
} }
@ -465,51 +426,11 @@ void GamelistView::updateInfoPanel()
} }
} }
else { else {
for (auto& image : mImageComponents) { for (auto& image : mImageComponents)
if (image->getThemeImageType() == "image") setGameImage(file, image.get());
image->setImage(file->getImagePath());
else if (image->getThemeImageType() == "miximage")
image->setImage(file->getMiximagePath());
else if (image->getThemeImageType() == "marquee")
image->setImage(file->getMarqueePath());
else if (image->getThemeImageType() == "screenshot")
image->setImage(file->getScreenshotPath());
else if (image->getThemeImageType() == "titlescreen")
image->setImage(file->getTitleScreenPath());
else if (image->getThemeImageType() == "cover")
image->setImage(file->getCoverPath());
else if (image->getThemeImageType() == "backcover")
image->setImage(file->getBackCoverPath());
else if (image->getThemeImageType() == "3dbox")
image->setImage(file->get3DBoxPath());
else if (image->getThemeImageType() == "fanart")
image->setImage(file->getFanArtPath());
else if (image->getThemeImageType() == "thumbnail")
image->setImage(file->getThumbnailPath());
}
for (auto& video : mVideoComponents) { for (auto& video : mVideoComponents) {
if (video->getThemeImageType() == "image") setGameImage(file, video.get());
video->setImage(file->getImagePath());
else if (video->getThemeImageType() == "miximage")
video->setImage(file->getMiximagePath());
else if (video->getThemeImageType() == "marquee")
video->setImage(file->getMarqueePath());
else if (video->getThemeImageType() == "screenshot")
video->setImage(file->getScreenshotPath());
else if (video->getThemeImageType() == "titlescreen")
video->setImage(file->getTitleScreenPath());
else if (video->getThemeImageType() == "cover")
video->setImage(file->getCoverPath());
else if (video->getThemeImageType() == "backcover")
video->setImage(file->getBackCoverPath());
else if (video->getThemeImageType() == "3dbox")
video->setImage(file->get3DBoxPath());
else if (video->getThemeImageType() == "fanart")
video->setImage(file->getFanArtPath());
else if (video->getThemeImageType() == "thumbnail")
video->setImage(file->getThumbnailPath());
video->onHide(); video->onHide();
if (video->hasStaticVideo()) if (video->hasStaticVideo())
@ -767,3 +688,83 @@ void GamelistView::updateInfoPanel()
} }
} }
} }
void GamelistView::setGameImage(FileData* file, GuiComponent* comp)
{
std::string path;
for (auto& imageType : comp->getThemeImageTypes()) {
if (imageType == "image") {
path = file->getImagePath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "miximage") {
path = file->getMiximagePath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "marquee") {
path = file->getMarqueePath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "screenshot") {
path = file->getScreenshotPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "titlescreen") {
path = file->getTitleScreenPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "cover") {
path = file->getCoverPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "backcover") {
path = file->getBackCoverPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "3dbox") {
path = file->get3DBoxPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "fanart") {
path = file->getFanArtPath();
if (path != "") {
comp->setImage(path);
break;
}
}
else if (imageType == "thumbnail") {
path = file->getThumbnailPath();
if (path != "") {
comp->setImage(path);
break;
}
}
}
// This is needed so the default image is set if no game media was found.
if (path == "" && comp->getThemeImageTypes().size() > 0)
comp->setImage("");
}

View file

@ -57,6 +57,7 @@ public:
private: private:
void updateInfoPanel(); void updateInfoPanel();
void setGameImage(FileData* file, GuiComponent* comp);
// Legacy (backward compatibility) functions. // Legacy (backward compatibility) functions.
void legacyPopulateFields(); void legacyPopulateFields();

View file

@ -62,8 +62,14 @@ SystemView::~SystemView()
void SystemView::goToSystem(SystemData* system, bool animate) void SystemView::goToSystem(SystemData* system, bool animate)
{ {
mCarousel->setCursor(system); mCarousel->setCursor(system);
for (auto& selector : mSystemElements[mCarousel->getCursor()].gameSelectors) {
if (selector->getGameSelection() == GameSelectorComponent::GameSelection::RANDOM)
selector->setNeedsRefresh();
}
updateGameSelectors();
updateGameCount(); updateGameCount();
updateGameSelector();
if (!animate) if (!animate)
finishSystemAnimation(0); finishSystemAnimation(0);
@ -174,13 +180,20 @@ HelpStyle SystemView::getHelpStyle()
void SystemView::onCursorChanged(const CursorState& /*state*/) void SystemView::onCursorChanged(const CursorState& /*state*/)
{ {
int cursor {mCarousel->getCursor()};
for (auto& selector : mSystemElements[cursor].gameSelectors) {
if (selector->getGameSelection() == GameSelectorComponent::GameSelection::RANDOM)
selector->setNeedsRefresh();
}
updateGameSelectors();
updateHelpPrompts(); updateHelpPrompts();
updateGameSelector();
int scrollVelocity {mCarousel->getScrollingVelocity()}; int scrollVelocity {mCarousel->getScrollingVelocity()};
float startPos {mCamOffset}; float startPos {mCamOffset};
float posMax {static_cast<float>(mCarousel->getNumEntries())}; float posMax {static_cast<float>(mCarousel->getNumEntries())};
float target {static_cast<float>(mCarousel->getCursor())}; float target {static_cast<float>(cursor)};
// Find the shortest path to the target. // Find the shortest path to the target.
float endPos {target}; // Directly. float endPos {target}; // Directly.
@ -337,10 +350,11 @@ void SystemView::populate()
elements.fullName = it->getFullName(); elements.fullName = it->getFullName();
for (auto& element : theme->getViewElements("system").elements) { for (auto& element : theme->getViewElements("system").elements) {
if (element.second.type == "gameselector") { if (element.second.type == "gameselector") {
elements.gameSelector = std::make_unique<GameSelectorComponent>(it); elements.gameSelectors.emplace_back(
elements.gameSelector->applyTheme(theme, "system", element.first, std::make_unique<GameSelectorComponent>(it));
ThemeFlags::ALL); elements.gameSelectors.back()->applyTheme(theme, "system", element.first,
elements.gameSelector->refreshGames(); ThemeFlags::ALL);
elements.gameSelectors.back()->setNeedsRefresh();
} }
if (element.second.type == "carousel") { if (element.second.type == "carousel") {
mCarousel->applyTheme(theme, "system", element.first, ThemeFlags::ALL); mCarousel->applyTheme(theme, "system", element.first, ThemeFlags::ALL);
@ -354,7 +368,7 @@ void SystemView::populate()
elements.imageComponents.back()->setDefaultZIndex(30.0f); elements.imageComponents.back()->setDefaultZIndex(30.0f);
elements.imageComponents.back()->applyTheme(theme, "system", element.first, elements.imageComponents.back()->applyTheme(theme, "system", element.first,
ThemeFlags::ALL); ThemeFlags::ALL);
if (elements.imageComponents.back()->getThemeImageType() != "") if (elements.imageComponents.back()->getThemeImageTypes().size() != 0)
elements.imageComponents.back()->setScrollHide(true); elements.imageComponents.back()->setScrollHide(true);
elements.children.emplace_back(elements.imageComponents.back().get()); elements.children.emplace_back(elements.imageComponents.back().get());
} }
@ -426,7 +440,7 @@ void SystemView::populate()
} }
} }
updateGameSelector(); updateGameSelectors();
if (mCarousel->getNumEntries() == 0) { if (mCarousel->getNumEntries() == 0) {
// Something is wrong, there is not a single system to show, check if UI mode is not full. // Something is wrong, there is not a single system to show, check if UI mode is not full.
@ -497,39 +511,182 @@ void SystemView::updateGameCount()
} }
} }
void SystemView::updateGameSelector() void SystemView::updateGameSelectors()
{ {
if (mLegacyMode)
return;
int cursor {mCarousel->getCursor()}; int cursor {mCarousel->getCursor()};
if (mSystemElements[cursor].gameSelector != nullptr) { if (mSystemElements[cursor].gameSelectors.size() == 0)
mSystemElements[mCarousel->getCursor()].gameSelector->refreshGames(); return;
std::vector<FileData*> games {mSystemElements[cursor].gameSelector->getGames()};
bool multipleSelectors {mSystemElements[cursor].gameSelectors.size() > 1};
for (auto& image : mSystemElements[cursor].imageComponents) {
if (image->getThemeImageTypes().size() == 0)
continue;
GameSelectorComponent* gameSelector {nullptr};
if (multipleSelectors) {
const std::string& imageSelector {image->getThemeGameSelector()};
if (imageSelector == "") {
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
LOG(LogWarning) << "SystemView::updateGameSelectors(): Multiple gameselector "
"elements defined but image element does not state which one to "
"use, so selecting first entry";
}
else {
for (auto& selector : mSystemElements[cursor].gameSelectors) {
if (selector->getSelectorName() == imageSelector)
gameSelector = selector.get();
}
if (gameSelector == nullptr)
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
}
}
else {
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
}
gameSelector->refreshGames();
std::vector<FileData*> games {gameSelector->getGames()};
if (!games.empty()) { if (!games.empty()) {
if (!mLegacyMode) { std::string path;
for (auto& image : mSystemElements[cursor].imageComponents) { for (auto& imageType : image->getThemeImageTypes()) {
const std::string imageType {image->getThemeImageType()}; if (imageType == "image") {
if (imageType == "image") path = games.front()->getImagePath();
image->setImage(games.front()->getImagePath()); if (path != "") {
else if (image->getThemeImageType() == "miximage") image->setImage(path);
image->setImage(games.front()->getMiximagePath()); break;
else if (image->getThemeImageType() == "marquee") }
image->setImage(games.front()->getMarqueePath()); }
else if (image->getThemeImageType() == "screenshot") else if (imageType == "miximage") {
image->setImage(games.front()->getScreenshotPath()); path = games.front()->getMiximagePath();
else if (image->getThemeImageType() == "titlescreen") if (path != "") {
image->setImage(games.front()->getTitleScreenPath()); image->setImage(path);
else if (image->getThemeImageType() == "cover") break;
image->setImage(games.front()->getCoverPath()); }
else if (image->getThemeImageType() == "backcover") }
image->setImage(games.front()->getBackCoverPath()); else if (imageType == "marquee") {
else if (image->getThemeImageType() == "3dbox") path = games.front()->getMarqueePath();
image->setImage(games.front()->get3DBoxPath()); if (path != "") {
else if (image->getThemeImageType() == "fanart") image->setImage(path);
image->setImage(games.front()->getFanArtPath()); break;
else if (image->getThemeImageType() == "thumbnail") }
image->setImage(games.front()->getThumbnailPath()); }
else if (imageType == "screenshot") {
path = games.front()->getScreenshotPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "titlescreen") {
path = games.front()->getTitleScreenPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "cover") {
path = games.front()->getCoverPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "backcover") {
path = games.front()->getBackCoverPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "3dbox") {
path = games.front()->get3DBoxPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "fanart") {
path = games.front()->getFanArtPath();
if (path != "") {
image->setImage(path);
break;
}
}
else if (imageType == "thumbnail") {
path = games.front()->getThumbnailPath();
if (path != "") {
image->setImage(path);
break;
}
} }
} }
// This is needed so the default image is set if no game media was found.
if (path == "" && image->getThemeImageTypes().size() > 0)
image->setImage("");
}
else {
image->setImage("");
}
}
for (auto& text : mSystemElements[cursor].textComponents) {
if (text->getThemeMetadata() == "")
continue;
GameSelectorComponent* gameSelector {nullptr};
if (multipleSelectors) {
const std::string& textSelector {text->getThemeGameSelector()};
if (textSelector == "") {
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
LOG(LogWarning) << "SystemView::updateGameSelectors(): Multiple gameselector "
"elements defined but text element does not state which one to "
"use, so selecting first entry";
}
else {
for (auto& selector : mSystemElements[cursor].gameSelectors) {
if (selector->getSelectorName() == textSelector)
gameSelector = selector.get();
}
if (gameSelector == nullptr)
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
}
}
else {
gameSelector = mSystemElements[cursor].gameSelectors.front().get();
}
gameSelector->refreshGames();
std::vector<FileData*> games {gameSelector->getGames()};
if (!games.empty()) {
const std::string metadata {text->getThemeMetadata()};
if (metadata == "name")
text->setValue(games.front()->metadata.get("name"));
if (metadata == "description")
text->setValue(games.front()->metadata.get("desc"));
if (metadata == "developer")
text->setValue(games.front()->metadata.get("developer"));
if (metadata == "publisher")
text->setValue(games.front()->metadata.get("publisher"));
if (metadata == "genre")
text->setValue(games.front()->metadata.get("genre"));
if (metadata == "players")
text->setValue(games.front()->metadata.get("players"));
if (metadata == "favorite")
text->setValue(games.front()->metadata.get("favorite") == "true" ? "yes" : "no");
if (metadata == "completed")
text->setValue(games.front()->metadata.get("completed") == "true" ? "yes" : "no");
if (metadata == "kidgame")
text->setValue(games.front()->metadata.get("kidgame") == "true" ? "yes" : "no");
if (metadata == "broken")
text->setValue(games.front()->metadata.get("broken") == "true" ? "yes" : "no");
if (metadata == "playcount")
text->setValue(games.front()->metadata.get("playcount"));
if (metadata == "altemulator")
text->setValue(games.front()->metadata.get("altemulator"));
}
else {
text->setValue("");
} }
} }
} }

View file

@ -28,7 +28,7 @@ class SystemData;
struct SystemViewElements { struct SystemViewElements {
std::string name; std::string name;
std::string fullName; std::string fullName;
std::unique_ptr<GameSelectorComponent> gameSelector; std::vector<std::unique_ptr<GameSelectorComponent>> gameSelectors;
std::vector<GuiComponent*> legacyExtras; std::vector<GuiComponent*> legacyExtras;
std::vector<GuiComponent*> children; std::vector<GuiComponent*> children;
@ -77,7 +77,7 @@ protected:
private: private:
void populate(); void populate();
void updateGameCount(); void updateGameCount();
void updateGameSelector(); void updateGameSelectors();
void legacyApplyTheme(const std::shared_ptr<ThemeData>& theme); void legacyApplyTheme(const std::shared_ptr<ThemeData>& theme);
void renderElements(const glm::mat4& parentTrans, bool abovePrimary); void renderElements(const glm::mat4& parentTrans, bool abovePrimary);

View file

@ -364,6 +364,9 @@ void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
mThemeOpacity = 0.0f; mThemeOpacity = 0.0f;
else else
setVisible(true); setVisible(true);
if (properties && elem->has("gameselector"))
mThemeGameSelector = elem->get<std::string>("gameselector");
} }
void GuiComponent::updateHelpPrompts() void GuiComponent::updateHelpPrompts()

View file

@ -207,16 +207,18 @@ public:
virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = color; } virtual void setOriginalColor(unsigned int color) { mColorOriginalValue = color; }
virtual void setChangedColor(unsigned int color) { mColorChangedValue = color; } virtual void setChangedColor(unsigned int color) { mColorChangedValue = color; }
virtual void setImage(const std::string& path, bool tile = false) {}
// These functions are used to enable and disable options in menus, i.e. switches and similar. // These functions are used to enable and disable options in menus, i.e. switches and similar.
virtual bool getEnabled() { return mEnabled; } virtual bool getEnabled() { return mEnabled; }
virtual void setEnabled(bool state) { mEnabled = state; } virtual void setEnabled(bool state) { mEnabled = state; }
const std::string getThemeSystemdata() { return mThemeSystemdata; } const std::string& getThemeSystemdata() { return mThemeSystemdata; }
void setThemeSystemdata(const std::string& text) { mThemeSystemdata = text; } void setThemeSystemdata(const std::string& text) { mThemeSystemdata = text; }
const std::string getThemeMetadata() { return mThemeMetadata; } const std::string& getThemeMetadata() { return mThemeMetadata; }
void setThemeMetadata(const std::string& text) { mThemeMetadata = text; } void setThemeMetadata(const std::string& text) { mThemeMetadata = text; }
const std::string getThemeImageType() { return mThemeImageType; } const std::vector<std::string>& getThemeImageTypes() { return mThemeImageTypes; }
void setThemeImageType(const std::string& text) { mThemeImageType = text; } const std::string& getThemeGameSelector() { return mThemeGameSelector; }
virtual std::shared_ptr<Font> getFont() const { return nullptr; } virtual std::shared_ptr<Font> getFont() const { return nullptr; }
@ -279,9 +281,10 @@ protected:
GuiComponent* mParent; GuiComponent* mParent;
std::vector<GuiComponent*> mChildren; std::vector<GuiComponent*> mChildren;
std::vector<std::string> mThemeImageTypes;
std::string mThemeSystemdata; std::string mThemeSystemdata;
std::string mThemeMetadata; std::string mThemeMetadata;
std::string mThemeImageType; std::string mThemeGameSelector;
unsigned int mColor; unsigned int mColor;
float mSaturation; float mSaturation;

View file

@ -89,6 +89,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"path", PATH}, {"path", PATH},
{"default", PATH}, {"default", PATH},
{"imageType", STRING}, {"imageType", STRING},
{"gameselector", STRING},
{"tile", BOOLEAN}, {"tile", BOOLEAN},
{"interpolation", STRING}, {"interpolation", STRING},
{"color", COLOR}, {"color", COLOR},
@ -161,6 +162,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"text", STRING}, {"text", STRING},
{"systemdata", STRING}, {"systemdata", STRING},
{"metadata", STRING}, {"metadata", STRING},
{"gameselector", STRING},
{"container", BOOLEAN}, {"container", BOOLEAN},
{"containerScrollSpeed", FLOAT}, {"containerScrollSpeed", FLOAT},
{"containerStartDelay", FLOAT}, {"containerStartDelay", FLOAT},
@ -281,7 +283,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"zIndex", FLOAT}}}, {"zIndex", FLOAT}}},
{"gameselector", {"gameselector",
{{"selection", STRING}, {{"selection", STRING},
{"count", UNSIGNED_INTEGER}}}, {"gameCount", UNSIGNED_INTEGER}}},
{"helpsystem", {"helpsystem",
{{"pos", NORMALIZED_PAIR}, {{"pos", NORMALIZED_PAIR},
{"origin", NORMALIZED_PAIR}, {"origin", NORMALIZED_PAIR},

View file

@ -311,6 +311,7 @@ void CarouselComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
mCarouselColor = 0xFFFFFFD8; mCarouselColor = 0xFFFFFFD8;
mCarouselColorEnd = 0xFFFFFFD8; mCarouselColorEnd = 0xFFFFFFD8;
mDefaultZIndex = 50.0f; mDefaultZIndex = 50.0f;
mText = "";
if (!elem) if (!elem)
return; return;

View file

@ -19,15 +19,30 @@ public:
GameSelectorComponent(SystemData* system) GameSelectorComponent(SystemData* system)
: mSystem {system} : mSystem {system}
, mGameSelection {GameSelection::RANDOM} , mGameSelection {GameSelection::RANDOM}
, mNeedsRefresh {false}
, mGameCount {1} , mGameCount {1}
{ {
mSystem->getRootFolder()->setUpdateListCallback([&]() { mNeedsRefresh = true; });
} }
enum class GameSelection {
RANDOM, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
LAST_PLAYED,
MOST_PLAYED
};
const std::vector<FileData*>& getGames() const { return mGames; } const std::vector<FileData*>& getGames() const { return mGames; }
void setNeedsRefresh() { mNeedsRefresh = true; }
const bool getNeedsRefresh() { return mNeedsRefresh; }
const GameSelection getGameSelection() const { return mGameSelection; }
const std::string& getSelectorName() const { return mSelectorName; }
void refreshGames() void refreshGames()
{ {
if (!mNeedsRefresh)
return;
mGames.clear(); mGames.clear();
mNeedsRefresh = false;
bool isKidMode {(Settings::getInstance()->getString("UIMode") == "kid" || bool isKidMode {(Settings::getInstance()->getString("UIMode") == "kid" ||
Settings::getInstance()->getBool("ForceKid"))}; Settings::getInstance()->getBool("ForceKid"))};
@ -82,6 +97,10 @@ public:
if (!elem) if (!elem)
return; return;
// Remove the leading "gameselector_" part of the element string in order to directly
// match with the optional "gameselector" property used in other elements.
mSelectorName = element.substr(13, std::string::npos);
if (elem->has("selection")) { if (elem->has("selection")) {
const std::string selection {elem->get<std::string>("selection")}; const std::string selection {elem->get<std::string>("selection")};
if (selection == "random") { if (selection == "random") {
@ -105,21 +124,17 @@ public:
} }
} }
if (elem->has("count")) if (elem->has("gameCount"))
mGameCount = glm::clamp(static_cast<int>(elem->get<unsigned int>("count")), 1, 30); mGameCount = glm::clamp(static_cast<int>(elem->get<unsigned int>("gameCount")), 1, 30);
} }
private: private:
enum class GameSelection {
RANDOM, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
LAST_PLAYED,
MOST_PLAYED
};
SystemData* mSystem; SystemData* mSystem;
std::vector<FileData*> mGames; std::vector<FileData*> mGames;
std::string mSelectorName;
GameSelection mGameSelection; GameSelection mGameSelection;
bool mNeedsRefresh;
int mGameCount; int mGameCount;
}; };

View file

@ -148,7 +148,7 @@ bool GridTileComponent::isSelected() const
return mSelected; return mSelected;
} }
void GridTileComponent::setImage(const std::string& path) void GridTileComponent::setImageOLD(const std::string& path)
{ {
mImage->setImage(path); mImage->setImage(path);
@ -156,7 +156,7 @@ void GridTileComponent::setImage(const std::string& path)
resize(); resize();
} }
void GridTileComponent::setImage(const std::shared_ptr<TextureResource>& texture) void GridTileComponent::setImageOLD(const std::shared_ptr<TextureResource>& texture)
{ {
mImage->setImage(texture); mImage->setImage(texture);

View file

@ -39,10 +39,10 @@ public:
glm::vec2 getSelectedTileSize() const; glm::vec2 getSelectedTileSize() const;
bool isSelected() const; bool isSelected() const;
void reset() { setImage(""); } void reset() { setImageOLD(""); }
void setImage(const std::string& path); void setImageOLD(const std::string& path);
void setImage(const std::shared_ptr<TextureResource>& texture); void setImageOLD(const std::shared_ptr<TextureResource>& texture);
void setSelected(bool selected, void setSelected(bool selected,
bool allowAnimation = true, bool allowAnimation = true,
glm::vec3* pPosition = nullptr, glm::vec3* pPosition = nullptr,

View file

@ -14,6 +14,7 @@
#include "Window.h" #include "Window.h"
#include "resources/TextureResource.h" #include "resources/TextureResource.h"
#include "utils/CImgUtil.h" #include "utils/CImgUtil.h"
#include "utils/StringUtil.h"
glm::ivec2 ImageComponent::getTextureSize() const glm::ivec2 ImageComponent::getTextureSize() const
{ {
@ -522,8 +523,15 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
setImage(elem->get<std::string>("path"), tile); setImage(elem->get<std::string>("path"), tile);
} }
if (properties & METADATA && elem->has("imageType")) if (properties && elem->has("imageType")) {
mThemeImageType = elem->get<std::string>("imageType"); std::string imageTypes {elem->get<std::string>("imageType")};
for (auto& character : imageTypes) {
if (std::isspace(character))
character = ',';
}
imageTypes = Utils::String::replace(imageTypes, ",,", ",");
mThemeImageTypes = Utils::String::delimitedStringToVector(imageTypes, ",");
}
if (properties & COLOR) { if (properties & COLOR) {
if (elem->has("color")) if (elem->has("color"))

View file

@ -24,7 +24,7 @@ public:
// Loads the image at the given filepath. Will tile if tile is true (retrieves texture // Loads the image at the given filepath. Will tile if tile is true (retrieves texture
// as tiling, creates vertices accordingly). // as tiling, creates vertices accordingly).
void setImage(const std::string& path, bool tile = false); void setImage(const std::string& path, bool tile = false) override;
// Loads an image from memory. // Loads an image from memory.
void setImage(const char* data, size_t length, bool tile = false); void setImage(const char* data, size_t length, bool tile = false);
// Use an already existing texture. // Use an already existing texture.

View file

@ -12,6 +12,7 @@
#include "Window.h" #include "Window.h"
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
#include "utils/FileSystemUtil.h" #include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include <SDL2/SDL_timer.h> #include <SDL2/SDL_timer.h>
@ -80,12 +81,17 @@ bool VideoComponent::setVideo(std::string path)
void VideoComponent::setImage(const std::string& path, bool tile) void VideoComponent::setImage(const std::string& path, bool tile)
{ {
std::string imagePath {path};
if (imagePath == "")
imagePath = mDefaultImagePath;
// Check that the image has changed. // Check that the image has changed.
if (path == mStaticImagePath) if (imagePath == mStaticImagePath)
return; return;
mStaticImage.setImage(path, tile); mStaticImage.setImage(imagePath, tile);
mStaticImagePath = path; mStaticImagePath = imagePath;
} }
void VideoComponent::onShow() void VideoComponent::onShow()
@ -268,6 +274,7 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (elem->has("defaultImage")) { if (elem->has("defaultImage")) {
mStaticImage.setDefaultImage(elem->get<std::string>("defaultImage")); mStaticImage.setDefaultImage(elem->get<std::string>("defaultImage"));
mStaticImage.setImage(mStaticImagePath); mStaticImage.setImage(mStaticImagePath);
mDefaultImagePath = elem->get<std::string>("defaultImage");
} }
if (elem->has("path")) if (elem->has("path"))
@ -287,8 +294,15 @@ void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
else if (elem->has("showSnapshotDelay")) else if (elem->has("showSnapshotDelay"))
mConfig.showSnapshotDelay = elem->get<bool>("showSnapshotDelay"); mConfig.showSnapshotDelay = elem->get<bool>("showSnapshotDelay");
if (properties & METADATA && elem->has("imageType")) if (properties && elem->has("imageType")) {
mThemeImageType = elem->get<std::string>("imageType"); std::string imageTypes {elem->get<std::string>("imageType")};
for (auto& character : imageTypes) {
if (std::isspace(character))
character = ',';
}
imageTypes = Utils::String::replace(imageTypes, ",,", ",");
mThemeImageTypes = Utils::String::delimitedStringToVector(imageTypes, ",");
}
if (elem->has("pillarboxes")) if (elem->has("pillarboxes"))
mDrawPillarboxes = elem->get<bool>("pillarboxes"); mDrawPillarboxes = elem->get<bool>("pillarboxes");

View file

@ -40,7 +40,7 @@ public:
// Configures the component to show the static video. // Configures the component to show the static video.
void setStaticVideo() { setVideo(mConfig.staticVideoPath); } void setStaticVideo() { setVideo(mConfig.staticVideoPath); }
// Loads a static image that is displayed if the video cannot be played. // Loads a static image that is displayed if the video cannot be played.
void setImage(const std::string& path, bool tile = false); void setImage(const std::string& path, bool tile = false) override;
// Sets whether we're in media viewer mode. // Sets whether we're in media viewer mode.
void setMediaViewerMode(bool isMediaViewer) { mMediaViewerMode = isMediaViewer; } void setMediaViewerMode(bool isMediaViewer) { mMediaViewerMode = isMediaViewer; }
// Sets whether we're in screensaver mode. // Sets whether we're in screensaver mode.
@ -125,6 +125,7 @@ protected:
glm::vec2 mVideoAreaSize; glm::vec2 mVideoAreaSize;
std::shared_ptr<TextureResource> mTexture; std::shared_ptr<TextureResource> mTexture;
std::string mStaticImagePath; std::string mStaticImagePath;
std::string mDefaultImagePath;
std::string mVideoPath; std::string mVideoPath;
std::string mPlayingVideoPath; std::string mPlayingVideoPath;