2022-01-18 16:14:17 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//
|
|
|
|
// EmulationStation Desktop Edition
|
|
|
|
// GamelistView.cpp
|
|
|
|
//
|
|
|
|
// Main gamelist logic.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "views/GamelistView.h"
|
2022-01-22 20:42:43 +00:00
|
|
|
#include "views/GamelistLegacy.h"
|
2022-01-18 16:14:17 +00:00
|
|
|
|
|
|
|
#include "CollectionSystemsManager.h"
|
|
|
|
#include "UIModeController.h"
|
|
|
|
#include "animations/LambdaAnimation.h"
|
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
#define FADE_IN_START_OPACITY 0.5f
|
|
|
|
#define FADE_IN_TIME 325
|
2022-01-18 16:14:17 +00:00
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
GamelistView::GamelistView(FileData* root)
|
2022-01-19 17:01:54 +00:00
|
|
|
: GamelistBase {root}
|
2022-03-14 18:51:48 +00:00
|
|
|
, mRenderer {Renderer::getInstance()}
|
2022-01-18 21:04:05 +00:00
|
|
|
, mViewStyle {ViewController::BASIC}
|
2022-03-14 18:51:48 +00:00
|
|
|
, mLegacyMode {false}
|
2022-01-18 16:14:17 +00:00
|
|
|
{
|
2022-01-22 20:42:43 +00:00
|
|
|
mViewStyle = ViewController::getInstance()->getState().viewstyle;
|
2022-01-18 20:09:06 +00:00
|
|
|
|
2022-01-22 20:42:43 +00:00
|
|
|
if (mLegacyMode)
|
|
|
|
return;
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GamelistView::~GamelistView()
|
|
|
|
{
|
2022-01-18 19:42:50 +00:00
|
|
|
// Remove theme extras.
|
|
|
|
for (auto extra : mThemeExtras) {
|
|
|
|
removeChild(extra);
|
|
|
|
delete extra;
|
|
|
|
}
|
|
|
|
mThemeExtras.clear();
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GamelistView::onFileChanged(FileData* file, bool reloadGamelist)
|
|
|
|
{
|
|
|
|
if (reloadGamelist) {
|
|
|
|
// Might switch to a detailed view.
|
2022-01-18 19:42:50 +00:00
|
|
|
ViewController::getInstance()->reloadGamelistView(this);
|
2022-01-18 16:14:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We could be tricky here to be efficient;
|
|
|
|
// but this shouldn't happen very often so we'll just always repopulate.
|
|
|
|
FileData* cursor {getCursor()};
|
|
|
|
if (!cursor->isPlaceHolder()) {
|
|
|
|
populateList(cursor->getParent()->getChildrenListToDisplay(), cursor->getParent());
|
|
|
|
setCursor(cursor);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
populateList(mRoot->getChildrenListToDisplay(), mRoot);
|
|
|
|
setCursor(cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GamelistView::onShow()
|
|
|
|
{
|
2022-01-29 17:41:22 +00:00
|
|
|
for (auto& animation : mLottieAnimComponents)
|
|
|
|
animation->resetFileAnimation();
|
|
|
|
|
2022-03-05 20:04:22 +00:00
|
|
|
for (auto& animation : mGIFAnimComponents)
|
|
|
|
animation->resetFileAnimation();
|
2022-01-18 16:14:17 +00:00
|
|
|
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& video : mStaticVideoComponents)
|
|
|
|
video->stopVideoPlayer();
|
|
|
|
|
2022-01-18 16:14:17 +00:00
|
|
|
mLastUpdated = nullptr;
|
|
|
|
GuiComponent::onShow();
|
2022-03-05 20:04:22 +00:00
|
|
|
|
2022-01-22 20:42:43 +00:00
|
|
|
if (mLegacyMode)
|
2022-08-19 15:14:20 +00:00
|
|
|
legacyUpdateView(CursorState::CURSOR_STOPPED);
|
2022-01-22 20:42:43 +00:00
|
|
|
else
|
2022-08-19 15:14:20 +00:00
|
|
|
updateView(CursorState::CURSOR_STOPPED);
|
2022-03-24 22:05:23 +00:00
|
|
|
|
|
|
|
mPrimary->finishAnimation(0);
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
2022-02-19 21:44:02 +00:00
|
|
|
void GamelistView::onTransition()
|
|
|
|
{
|
|
|
|
for (auto& animation : mLottieAnimComponents)
|
|
|
|
animation->setPauseAnimation(true);
|
2022-03-05 20:04:22 +00:00
|
|
|
|
|
|
|
for (auto& animation : mGIFAnimComponents)
|
|
|
|
animation->setPauseAnimation(true);
|
2022-02-19 21:44:02 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 16:14:17 +00:00
|
|
|
void GamelistView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
|
|
|
{
|
2022-02-06 12:58:50 +00:00
|
|
|
auto themeSets = ThemeData::getThemeSets();
|
2022-04-09 13:57:37 +00:00
|
|
|
std::map<std::string, ThemeData::ThemeSet, ThemeData::StringComparator>::const_iterator
|
|
|
|
selectedSet {themeSets.find(Settings::getInstance()->getString("ThemeSet"))};
|
2022-02-06 12:58:50 +00:00
|
|
|
|
|
|
|
assert(selectedSet != themeSets.cend());
|
|
|
|
mLegacyMode = selectedSet->second.capabilities.legacyTheme;
|
2022-01-29 17:41:22 +00:00
|
|
|
|
2022-01-22 20:42:43 +00:00
|
|
|
if (mLegacyMode) {
|
|
|
|
legacyOnThemeChanged(theme);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-10 14:07:43 +00:00
|
|
|
const bool isStartupSystem {Settings::getInstance()->getString("StartupSystem") ==
|
|
|
|
mRoot->getSystem()->getName()};
|
|
|
|
|
2022-01-18 16:14:17 +00:00
|
|
|
using namespace ThemeFlags;
|
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
if (mTheme->hasView("gamelist")) {
|
|
|
|
for (auto& element : mTheme->getViewElements("gamelist").elements) {
|
2022-03-24 22:05:23 +00:00
|
|
|
if (element.second.type == "textlist" || element.second.type == "carousel") {
|
|
|
|
if (element.second.type == "carousel" && mTextList != nullptr) {
|
|
|
|
LOG(LogWarning) << "SystemView::populate(): Multiple primary components "
|
|
|
|
<< "defined, skipping <carousel> configuration entry";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (element.second.type == "textlist" && mCarousel != nullptr) {
|
|
|
|
LOG(LogWarning) << "SystemView::populate(): Multiple primary components "
|
|
|
|
<< "defined, skipping <textlist> configuration entry";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (element.second.type == "textlist") {
|
|
|
|
if (mTextList == nullptr) {
|
|
|
|
mTextList = std::make_unique<TextListComponent<FileData*>>();
|
|
|
|
mPrimary = mTextList.get();
|
|
|
|
}
|
2022-08-16 17:10:14 +00:00
|
|
|
mPrimary->setPosition(0.0f, mSize.y * 0.1f);
|
|
|
|
mPrimary->setSize(mSize.x, mSize.y * 0.8f);
|
2022-03-24 22:05:23 +00:00
|
|
|
mPrimary->setAlignment(TextListComponent<FileData*>::PrimaryAlignment::ALIGN_LEFT);
|
|
|
|
mPrimary->setCursorChangedCallback(
|
2022-08-19 15:14:20 +00:00
|
|
|
[&](const CursorState& state) { updateView(state); });
|
2022-03-24 22:05:23 +00:00
|
|
|
mPrimary->setDefaultZIndex(50.0f);
|
|
|
|
mPrimary->setZIndex(50.0f);
|
|
|
|
mPrimary->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
addChild(mPrimary);
|
|
|
|
}
|
|
|
|
if (element.second.type == "carousel") {
|
|
|
|
if (mCarousel == nullptr) {
|
|
|
|
mCarousel = std::make_unique<CarouselComponent<FileData*>>();
|
2022-04-16 19:54:58 +00:00
|
|
|
if (element.second.has("itemType")) {
|
|
|
|
const std::string itemType {element.second.get<std::string>("itemType")};
|
2022-06-07 15:32:42 +00:00
|
|
|
if (itemType == "marquee" || itemType == "cover" ||
|
|
|
|
itemType == "backcover" || itemType == "3dbox" ||
|
|
|
|
itemType == "physicalmedia" || itemType == "screenshot" ||
|
|
|
|
itemType == "titlescreen" || itemType == "miximage" ||
|
2022-04-16 19:54:58 +00:00
|
|
|
itemType == "fanart") {
|
|
|
|
mCarousel->setItemType(itemType);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogWarning)
|
|
|
|
<< "GamelistView::onThemeChanged(): Invalid theme configuration, "
|
|
|
|
"<itemType> property defined as \""
|
|
|
|
<< itemType << "\"";
|
|
|
|
mCarousel->setItemType("marquee");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mCarousel->setItemType("marquee");
|
|
|
|
}
|
|
|
|
if (element.second.has("defaultItem"))
|
|
|
|
mCarousel->setDefaultItem(element.second.get<std::string>("defaultItem"));
|
2022-03-24 22:05:23 +00:00
|
|
|
mPrimary = mCarousel.get();
|
|
|
|
}
|
|
|
|
mPrimary->setCursorChangedCallback(
|
2022-08-19 15:14:20 +00:00
|
|
|
[&](const CursorState& state) { updateView(state); });
|
2022-03-24 22:05:23 +00:00
|
|
|
mPrimary->setDefaultZIndex(50.0f);
|
|
|
|
mPrimary->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
addChild(mPrimary);
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
if (element.second.type == "image") {
|
2022-09-10 14:07:43 +00:00
|
|
|
// If this is the startup system, then forceload the images to avoid texture pop-in.
|
|
|
|
if (isStartupSystem)
|
|
|
|
mImageComponents.push_back(std::make_unique<ImageComponent>(true));
|
|
|
|
else
|
|
|
|
mImageComponents.push_back(std::make_unique<ImageComponent>());
|
2022-01-29 17:41:22 +00:00
|
|
|
mImageComponents.back()->setDefaultZIndex(30.0f);
|
|
|
|
mImageComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
2022-02-14 18:32:07 +00:00
|
|
|
if (mImageComponents.back()->getThemeImageTypes().size() != 0)
|
2022-01-29 17:41:22 +00:00
|
|
|
mImageComponents.back()->setScrollHide(true);
|
2022-08-18 20:51:21 +00:00
|
|
|
else if (mImageComponents.back()->getMetadataElement())
|
|
|
|
mImageComponents.back()->setScrollHide(true);
|
2022-01-29 17:41:22 +00:00
|
|
|
addChild(mImageComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (element.second.type == "video") {
|
2022-08-18 20:51:21 +00:00
|
|
|
if (element.second.has("path")) {
|
|
|
|
mStaticVideoComponents.push_back(std::make_unique<VideoFFmpegComponent>());
|
|
|
|
mStaticVideoComponents.back()->setDefaultZIndex(30.0f);
|
|
|
|
addChild(mStaticVideoComponents.back().get());
|
|
|
|
mStaticVideoComponents.back()->applyTheme(theme, "gamelist", element.first,
|
|
|
|
ALL);
|
|
|
|
if (mStaticVideoComponents.back()->getMetadataElement())
|
|
|
|
mStaticVideoComponents.back()->setScrollHide(true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mVideoComponents.push_back(std::make_unique<VideoFFmpegComponent>());
|
|
|
|
mVideoComponents.back()->setDefaultZIndex(30.0f);
|
|
|
|
addChild(mVideoComponents.back().get());
|
|
|
|
mVideoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
if (mVideoComponents.back()->getThemeImageTypes().size() != 0)
|
|
|
|
mVideoComponents.back()->setScrollHide(true);
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
2022-03-05 20:04:22 +00:00
|
|
|
else if (element.second.type == "animation" && element.second.has("path")) {
|
|
|
|
const std::string extension {
|
|
|
|
Utils::FileSystem::getExtension(element.second.get<std::string>("path"))};
|
|
|
|
if (extension == ".json") {
|
|
|
|
mLottieAnimComponents.push_back(std::make_unique<LottieAnimComponent>());
|
|
|
|
mLottieAnimComponents.back()->setDefaultZIndex(35.0f);
|
|
|
|
mLottieAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
2022-08-18 20:51:21 +00:00
|
|
|
if (mLottieAnimComponents.back()->getMetadataElement())
|
|
|
|
mLottieAnimComponents.back()->setScrollHide(true);
|
2022-03-05 20:04:22 +00:00
|
|
|
addChild(mLottieAnimComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (extension == ".gif") {
|
|
|
|
mGIFAnimComponents.push_back(std::make_unique<GIFAnimComponent>());
|
|
|
|
mGIFAnimComponents.back()->setDefaultZIndex(35.0f);
|
|
|
|
mGIFAnimComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
2022-08-18 20:51:21 +00:00
|
|
|
if (mGIFAnimComponents.back()->getMetadataElement())
|
|
|
|
mGIFAnimComponents.back()->setScrollHide(true);
|
2022-03-05 20:04:22 +00:00
|
|
|
addChild(mGIFAnimComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (extension == ".") {
|
|
|
|
LOG(LogWarning)
|
|
|
|
<< "GamelistView::onThemeChanged(): Invalid theme configuration, "
|
|
|
|
"animation file extension is missing";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogWarning)
|
|
|
|
<< "GamelistView::onThemeChanged(): Invalid theme configuration, "
|
|
|
|
"animation file extension defined as \""
|
|
|
|
<< extension << "\"";
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
else if (element.second.type == "badges") {
|
|
|
|
mBadgeComponents.push_back(std::make_unique<BadgeComponent>());
|
|
|
|
mBadgeComponents.back()->setDefaultZIndex(35.0f);
|
|
|
|
mBadgeComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
mBadgeComponents.back()->setScrollHide(true);
|
|
|
|
addChild(mBadgeComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (element.second.type == "text") {
|
|
|
|
if (element.second.has("container") && element.second.get<bool>("container")) {
|
|
|
|
mContainerComponents.push_back(std::make_unique<ScrollableContainer>());
|
2022-01-30 18:30:38 +00:00
|
|
|
mContainerComponents.back()->setDefaultZIndex(40.0f);
|
|
|
|
addChild(mContainerComponents.back().get());
|
|
|
|
mContainerTextComponents.push_back(std::make_unique<TextComponent>());
|
|
|
|
mContainerTextComponents.back()->setDefaultZIndex(40.0f);
|
2022-01-29 17:41:22 +00:00
|
|
|
mContainerComponents.back()->addChild(mContainerTextComponents.back().get());
|
|
|
|
mContainerComponents.back()->applyTheme(theme, "gamelist", element.first,
|
|
|
|
POSITION | ThemeFlags::SIZE | Z_INDEX |
|
|
|
|
VISIBLE);
|
2022-02-10 19:02:56 +00:00
|
|
|
mContainerComponents.back()->setAutoScroll(true);
|
2022-01-29 17:41:22 +00:00
|
|
|
mContainerTextComponents.back()->setSize(
|
|
|
|
mContainerComponents.back()->getSize().x, 0.0f);
|
2022-01-30 18:30:38 +00:00
|
|
|
mContainerTextComponents.back()->applyTheme(
|
|
|
|
theme, "gamelist", element.first,
|
2022-02-10 19:02:56 +00:00
|
|
|
ALL ^ POSITION ^ Z_INDEX ^ ThemeFlags::SIZE ^ VISIBLE ^ ROTATION);
|
2022-08-18 20:51:21 +00:00
|
|
|
if (mContainerTextComponents.back()->getThemeMetadata() != "")
|
|
|
|
mContainerComponents.back()->setScrollHide(true);
|
|
|
|
else if (mContainerTextComponents.back()->getMetadataElement())
|
|
|
|
mContainerComponents.back()->setScrollHide(true);
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mTextComponents.push_back(std::make_unique<TextComponent>());
|
|
|
|
mTextComponents.back()->setDefaultZIndex(40.0f);
|
|
|
|
mTextComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
2022-08-18 20:51:21 +00:00
|
|
|
if (mTextComponents.back()->getThemeMetadata() != "") {
|
|
|
|
mTextComponents.back()->setScrollHide(true);
|
|
|
|
}
|
|
|
|
else if (mTextComponents.back()->getMetadataElement()) {
|
2022-01-29 17:41:22 +00:00
|
|
|
mTextComponents.back()->setScrollHide(true);
|
2022-08-18 20:51:21 +00:00
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
addChild(mTextComponents.back().get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (element.second.type == "datetime") {
|
|
|
|
mDateTimeComponents.push_back(std::make_unique<DateTimeComponent>());
|
|
|
|
mDateTimeComponents.back()->setDefaultZIndex(40.0f);
|
|
|
|
mDateTimeComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
2022-02-13 10:45:06 +00:00
|
|
|
if (mDateTimeComponents.back()->getThemeMetadata() != "")
|
2022-01-29 17:41:22 +00:00
|
|
|
mDateTimeComponents.back()->setScrollHide(true);
|
|
|
|
addChild(mDateTimeComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (element.second.type == "gamelistinfo") {
|
|
|
|
mGamelistInfoComponents.push_back(std::make_unique<TextComponent>());
|
|
|
|
mGamelistInfoComponents.back()->setDefaultZIndex(45.0f);
|
|
|
|
mGamelistInfoComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
addChild(mGamelistInfoComponents.back().get());
|
|
|
|
}
|
|
|
|
else if (element.second.type == "rating") {
|
|
|
|
mRatingComponents.push_back(std::make_unique<RatingComponent>());
|
|
|
|
mRatingComponents.back()->setDefaultZIndex(45.0f);
|
|
|
|
mRatingComponents.back()->applyTheme(theme, "gamelist", element.first, ALL);
|
|
|
|
mRatingComponents.back()->setScrollHide(true);
|
2022-08-17 15:07:52 +00:00
|
|
|
mRatingComponents.back()->setOpacity(mRatingComponents.back()->getOpacity());
|
2022-01-29 17:41:22 +00:00
|
|
|
addChild(mRatingComponents.back().get());
|
|
|
|
}
|
|
|
|
}
|
2022-03-24 22:05:23 +00:00
|
|
|
|
2022-03-18 19:14:51 +00:00
|
|
|
mHelpStyle.applyTheme(mTheme, "gamelist");
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
2022-03-25 20:50:50 +00:00
|
|
|
if (mPrimary == nullptr) {
|
|
|
|
mTextList = std::make_unique<TextListComponent<FileData*>>();
|
|
|
|
mPrimary = mTextList.get();
|
2022-08-16 17:10:14 +00:00
|
|
|
mPrimary->setPosition(0.0f, mSize.y * 0.1f);
|
|
|
|
mPrimary->setSize(mSize.x, mSize.y * 0.8f);
|
2022-03-25 20:50:50 +00:00
|
|
|
mPrimary->setAlignment(TextListComponent<FileData*>::PrimaryAlignment::ALIGN_LEFT);
|
2022-08-19 15:14:20 +00:00
|
|
|
mPrimary->setCursorChangedCallback([&](const CursorState& state) { updateView(state); });
|
2022-03-25 20:50:50 +00:00
|
|
|
mPrimary->setDefaultZIndex(50.0f);
|
|
|
|
mPrimary->setZIndex(50.0f);
|
|
|
|
mPrimary->applyTheme(theme, "gamelist", "", ALL);
|
|
|
|
addChild(mPrimary);
|
|
|
|
}
|
|
|
|
|
|
|
|
populateList(mRoot->getChildrenListToDisplay(), mRoot);
|
|
|
|
|
2022-03-24 22:05:23 +00:00
|
|
|
// Disable quick system select if the primary component uses the left and right buttons.
|
|
|
|
if (mCarousel != nullptr) {
|
|
|
|
if (mCarousel->getType() == CarouselComponent<FileData*>::CarouselType::HORIZONTAL ||
|
|
|
|
mCarousel->getType() == CarouselComponent<FileData*>::CarouselType::HORIZONTAL_WHEEL)
|
|
|
|
mLeftRightAvailable = false;
|
|
|
|
}
|
2022-01-18 16:14:17 +00:00
|
|
|
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& video : mStaticVideoComponents) {
|
|
|
|
if (video->hasStaticVideo())
|
|
|
|
video->setStaticVideo();
|
|
|
|
}
|
|
|
|
|
2022-01-18 16:14:17 +00:00
|
|
|
sortChildren();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GamelistView::update(int deltaTime)
|
|
|
|
{
|
2022-01-22 20:42:43 +00:00
|
|
|
if (mLegacyMode) {
|
|
|
|
legacyUpdate(deltaTime);
|
|
|
|
return;
|
2022-01-18 21:04:05 +00:00
|
|
|
}
|
2022-01-19 17:01:54 +00:00
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
if (ViewController::getInstance()->getGameLaunchTriggered()) {
|
|
|
|
for (auto& image : mImageComponents) {
|
|
|
|
if (image->isAnimationPlaying(0))
|
|
|
|
image->finishAnimation(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-18 20:51:21 +00:00
|
|
|
// We need to manually advance fade-in and fade-out animations since they will not get updated
|
|
|
|
// via GuiComponent as these components override the update() function.
|
|
|
|
for (auto& anim : mLottieAnimComponents) {
|
|
|
|
if (anim->isAnimationPlaying(0))
|
|
|
|
anim->advanceAnimation(0, deltaTime);
|
|
|
|
}
|
|
|
|
for (auto& anim : mGIFAnimComponents) {
|
|
|
|
if (anim->isAnimationPlaying(0))
|
|
|
|
anim->advanceAnimation(0, deltaTime);
|
|
|
|
}
|
|
|
|
|
2022-01-19 17:01:54 +00:00
|
|
|
updateChildren(deltaTime);
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GamelistView::render(const glm::mat4& parentTrans)
|
|
|
|
{
|
|
|
|
glm::mat4 trans {parentTrans * getTransform()};
|
|
|
|
|
|
|
|
float scaleX {trans[0].x};
|
|
|
|
float scaleY {trans[1].y};
|
|
|
|
|
|
|
|
glm::ivec2 pos {static_cast<int>(std::round(trans[3].x)),
|
|
|
|
static_cast<int>(std::round(trans[3].y))};
|
|
|
|
glm::ivec2 size {static_cast<int>(std::round(mSize.x * scaleX)),
|
|
|
|
static_cast<int>(std::round(mSize.y * scaleY))};
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
mRenderer->pushClipRect(pos, size);
|
2022-01-18 16:14:17 +00:00
|
|
|
renderChildren(trans);
|
2022-03-14 18:51:48 +00:00
|
|
|
mRenderer->popClipRect();
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> GamelistView::getHelpPrompts()
|
|
|
|
{
|
|
|
|
std::vector<HelpPrompt> prompts;
|
|
|
|
|
|
|
|
if (Settings::getInstance()->getBool("QuickSystemSelect") &&
|
2022-03-24 22:05:23 +00:00
|
|
|
SystemData::sSystemVector.size() > 1 && mLeftRightAvailable)
|
2022-01-18 16:14:17 +00:00
|
|
|
prompts.push_back(HelpPrompt("left/right", "system"));
|
|
|
|
|
|
|
|
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" && mCursorStack.empty() &&
|
|
|
|
ViewController::getInstance()->getState().viewing == ViewController::GAMELIST)
|
|
|
|
prompts.push_back(HelpPrompt("a", "enter"));
|
|
|
|
else
|
|
|
|
prompts.push_back(HelpPrompt("a", "launch"));
|
|
|
|
|
|
|
|
prompts.push_back(HelpPrompt("b", "back"));
|
|
|
|
prompts.push_back(HelpPrompt("x", "view media"));
|
|
|
|
|
|
|
|
if (!UIModeController::getInstance()->isUIModeKid())
|
|
|
|
prompts.push_back(HelpPrompt("back", "options"));
|
|
|
|
if (mRoot->getSystem()->isGameSystem() && Settings::getInstance()->getBool("RandomAddButton"))
|
|
|
|
prompts.push_back(HelpPrompt("thumbstickclick", "random"));
|
|
|
|
|
|
|
|
if (mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
|
|
|
!CollectionSystemsManager::getInstance()->isEditing() && mCursorStack.empty() &&
|
|
|
|
ViewController::getInstance()->getState().viewing == ViewController::GAMELIST &&
|
|
|
|
ViewController::getInstance()->getState().viewstyle != ViewController::BASIC) {
|
|
|
|
prompts.push_back(HelpPrompt("y", "jump to game"));
|
|
|
|
}
|
|
|
|
else if (mRoot->getSystem()->isGameSystem() &&
|
|
|
|
(mRoot->getSystem()->getThemeFolder() != "custom-collections" ||
|
|
|
|
!mCursorStack.empty()) &&
|
|
|
|
!UIModeController::getInstance()->isUIModeKid() &&
|
|
|
|
!UIModeController::getInstance()->isUIModeKiosk() &&
|
|
|
|
(Settings::getInstance()->getBool("FavoritesAddButton") ||
|
|
|
|
CollectionSystemsManager::getInstance()->isEditing())) {
|
|
|
|
std::string prompt = CollectionSystemsManager::getInstance()->getEditingCollection();
|
|
|
|
prompts.push_back(HelpPrompt("y", prompt));
|
|
|
|
}
|
|
|
|
else if (mRoot->getSystem()->isGameSystem() &&
|
|
|
|
mRoot->getSystem()->getThemeFolder() == "custom-collections" &&
|
|
|
|
CollectionSystemsManager::getInstance()->isEditing()) {
|
|
|
|
std::string prompt = CollectionSystemsManager::getInstance()->getEditingCollection();
|
|
|
|
prompts.push_back(HelpPrompt("y", prompt));
|
|
|
|
}
|
|
|
|
return prompts;
|
|
|
|
}
|
|
|
|
|
2022-08-19 15:14:20 +00:00
|
|
|
void GamelistView::updateView(const CursorState& state)
|
2022-01-18 16:14:17 +00:00
|
|
|
{
|
2022-01-29 17:41:22 +00:00
|
|
|
if (mLegacyMode) {
|
2022-08-19 15:14:20 +00:00
|
|
|
legacyUpdateView(state);
|
2022-01-29 17:41:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-24 22:05:23 +00:00
|
|
|
FileData* file {(mPrimary->size() > 0 && state == CursorState::CURSOR_STOPPED) ?
|
|
|
|
mPrimary->getSelected() :
|
|
|
|
nullptr};
|
2022-01-18 16:14:17 +00:00
|
|
|
|
2022-04-20 21:00:53 +00:00
|
|
|
if (mCarousel != nullptr)
|
|
|
|
mCarousel->onDemandTextureLoad();
|
|
|
|
|
2022-08-18 20:51:21 +00:00
|
|
|
// If the game data has already been rendered to the view, then skip it this time.
|
|
|
|
// This also happens when fast-scrolling.
|
2022-01-18 16:14:17 +00:00
|
|
|
if (file == mLastUpdated)
|
|
|
|
return;
|
|
|
|
|
2022-03-24 22:05:23 +00:00
|
|
|
if (state == CursorState::CURSOR_STOPPED)
|
2022-01-18 16:14:17 +00:00
|
|
|
mLastUpdated = file;
|
|
|
|
|
|
|
|
bool hideMetaDataFields {false};
|
|
|
|
|
|
|
|
if (file) {
|
|
|
|
// Always hide the metadata fields if browsing grouped custom collections.
|
|
|
|
if (file->getSystem()->isCustomCollection() &&
|
|
|
|
file->getPath() == file->getSystem()->getName())
|
|
|
|
hideMetaDataFields = true;
|
|
|
|
else
|
|
|
|
hideMetaDataFields = (file->metadata.get("hidemetadata") == "true");
|
|
|
|
|
|
|
|
// Always hide the metadata fields for placeholders as well.
|
|
|
|
if (file->getType() == PLACEHOLDER) {
|
|
|
|
hideMetaDataFields = true;
|
|
|
|
mLastUpdated = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
// If we're scrolling, hide the metadata fields if the last game had this options set,
|
|
|
|
// or if we're in the grouped custom collection view.
|
2022-03-24 22:05:23 +00:00
|
|
|
if (state == CursorState::CURSOR_SCROLLING) {
|
2022-01-29 17:41:22 +00:00
|
|
|
if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") ||
|
|
|
|
(mLastUpdated->getSystem()->isCustomCollection() &&
|
|
|
|
mLastUpdated->getPath() == mLastUpdated->getSystem()->getName()))
|
|
|
|
hideMetaDataFields = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hideMetaDataFields) {
|
|
|
|
for (auto& text : mTextComponents) {
|
2022-08-18 20:51:21 +00:00
|
|
|
if (text->getMetadataElement() || text->getThemeMetadata() != "")
|
2022-01-29 17:41:22 +00:00
|
|
|
text->setVisible(false);
|
|
|
|
}
|
|
|
|
for (auto& date : mDateTimeComponents)
|
|
|
|
date->setVisible(false);
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& image : mImageComponents) {
|
|
|
|
if (image->getMetadataElement())
|
|
|
|
image->setVisible(false);
|
|
|
|
}
|
|
|
|
for (auto& video : mStaticVideoComponents) {
|
|
|
|
if (video->getMetadataElement())
|
|
|
|
video->setVisible(false);
|
|
|
|
}
|
|
|
|
for (auto& anim : mLottieAnimComponents) {
|
|
|
|
if (anim->getMetadataElement())
|
|
|
|
anim->setVisible(false);
|
|
|
|
}
|
|
|
|
for (auto& anim : mGIFAnimComponents) {
|
|
|
|
if (anim->getMetadataElement())
|
|
|
|
anim->setVisible(false);
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
for (auto& badge : mBadgeComponents)
|
|
|
|
badge->setVisible(false);
|
|
|
|
for (auto& rating : mRatingComponents)
|
|
|
|
rating->setVisible(false);
|
|
|
|
for (auto& cText : mContainerTextComponents) {
|
2022-08-18 20:51:21 +00:00
|
|
|
if (cText->getThemeMetadata() != "description" || cText->getMetadataElement())
|
2022-01-29 17:41:22 +00:00
|
|
|
cText->setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (auto& text : mTextComponents) {
|
2022-08-18 20:51:21 +00:00
|
|
|
if (text->getMetadataElement() || text->getThemeMetadata() != "")
|
2022-01-29 17:41:22 +00:00
|
|
|
text->setVisible(true);
|
|
|
|
}
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& image : mImageComponents) {
|
|
|
|
if (image->getMetadataElement())
|
|
|
|
image->setVisible(true);
|
|
|
|
}
|
|
|
|
for (auto& video : mStaticVideoComponents) {
|
|
|
|
if (video->getMetadataElement())
|
|
|
|
video->setVisible(true);
|
|
|
|
}
|
|
|
|
for (auto& anim : mLottieAnimComponents) {
|
|
|
|
if (anim->getMetadataElement())
|
|
|
|
anim->setVisible(true);
|
|
|
|
}
|
|
|
|
for (auto& anim : mGIFAnimComponents) {
|
|
|
|
if (anim->getMetadataElement())
|
|
|
|
anim->setVisible(true);
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
for (auto& date : mDateTimeComponents)
|
|
|
|
date->setVisible(true);
|
|
|
|
for (auto& badge : mBadgeComponents)
|
|
|
|
badge->setVisible(true);
|
|
|
|
for (auto& rating : mRatingComponents)
|
|
|
|
rating->setVisible(true);
|
|
|
|
for (auto& cText : mContainerTextComponents) {
|
2022-08-18 20:51:21 +00:00
|
|
|
if (cText->getThemeMetadata() != "description" || cText->getMetadataElement())
|
2022-01-29 17:41:22 +00:00
|
|
|
cText->setVisible(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool fadingOut = false;
|
|
|
|
if (file == nullptr) {
|
2022-02-19 16:04:23 +00:00
|
|
|
if (mVideoPlaying) {
|
|
|
|
for (auto& video : mVideoComponents) {
|
|
|
|
video->stopVideoPlayer();
|
|
|
|
video->setVideo("");
|
|
|
|
if (!video->hasStartDelay())
|
|
|
|
video->setImage("");
|
|
|
|
}
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
mVideoPlaying = false;
|
|
|
|
fadingOut = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// If we're browsing a grouped custom collection, then update the folder metadata
|
|
|
|
// which will generate a description of three random games and return a pointer to
|
|
|
|
// the first of these so that we can display its game media.
|
|
|
|
if (file->getSystem()->isCustomCollection() &&
|
|
|
|
file->getPath() == file->getSystem()->getName()) {
|
|
|
|
mRandomGame = CollectionSystemsManager::getInstance()->updateCollectionFolderMetadata(
|
|
|
|
file->getSystem());
|
|
|
|
if (mRandomGame) {
|
2022-02-14 18:32:07 +00:00
|
|
|
for (auto& image : mImageComponents)
|
|
|
|
setGameImage(mRandomGame, image.get());
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
for (auto& video : mVideoComponents) {
|
2022-02-14 18:32:07 +00:00
|
|
|
setGameImage(mRandomGame, video.get());
|
2022-01-29 17:41:22 +00:00
|
|
|
|
2022-02-19 16:04:23 +00:00
|
|
|
video->stopVideoPlayer();
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
if (video->hasStaticVideo())
|
|
|
|
video->setStaticVideo();
|
|
|
|
else if (!video->setVideo(mRandomGame->getVideoPath()))
|
|
|
|
video->setDefaultVideo();
|
2022-02-19 16:04:23 +00:00
|
|
|
|
|
|
|
video->startVideoPlayer();
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (auto& image : mImageComponents) {
|
2022-02-14 18:32:07 +00:00
|
|
|
if (image->getThemeImageTypes().size() != 0)
|
2022-01-29 17:41:22 +00:00
|
|
|
image->setImage("");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& video : mVideoComponents) {
|
2022-02-19 16:04:23 +00:00
|
|
|
video->stopVideoPlayer();
|
2022-01-29 17:41:22 +00:00
|
|
|
video->setImage("");
|
|
|
|
video->setVideo("");
|
|
|
|
if (video->hasStaticVideo()) {
|
|
|
|
video->setStaticVideo();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
video->setDefaultVideo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2022-02-19 16:04:23 +00:00
|
|
|
for (auto& image : mImageComponents) {
|
2022-02-14 18:32:07 +00:00
|
|
|
setGameImage(file, image.get());
|
2022-02-19 16:04:23 +00:00
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
for (auto& video : mVideoComponents) {
|
2022-02-14 18:32:07 +00:00
|
|
|
setGameImage(file, video.get());
|
2022-02-19 16:04:23 +00:00
|
|
|
video->stopVideoPlayer();
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
if (video->hasStaticVideo())
|
|
|
|
video->setStaticVideo();
|
|
|
|
else if (!video->setVideo(file->getVideoPath()))
|
|
|
|
video->setDefaultVideo();
|
2022-02-19 16:04:23 +00:00
|
|
|
|
|
|
|
video->startVideoPlayer();
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mVideoPlaying = true;
|
|
|
|
|
|
|
|
// Populate the gamelistInfo field which shows an icon if a folder has been entered
|
|
|
|
// as well as the game count for the entire system (total and favorites separately).
|
|
|
|
// If a filter has been applied, then the number of filtered and total games replaces
|
|
|
|
// the game counter.
|
|
|
|
for (auto& gamelistInfo : mGamelistInfoComponents) {
|
|
|
|
std::string gamelistInfoString;
|
2022-09-10 09:35:55 +00:00
|
|
|
Alignment infoAlign {gamelistInfo->getHorizontalAlignment()};
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
if (mIsFolder && infoAlign == ALIGN_RIGHT)
|
|
|
|
gamelistInfoString = ViewController::FOLDER_CHAR + " ";
|
|
|
|
|
|
|
|
if (mIsFiltered) {
|
|
|
|
if (mFilteredGameCountAll == mFilteredGameCount)
|
2022-09-10 09:35:55 +00:00
|
|
|
gamelistInfoString.append(ViewController::FILTER_CHAR)
|
|
|
|
.append(" ")
|
|
|
|
.append(std::to_string(mFilteredGameCount))
|
|
|
|
.append(" / ")
|
|
|
|
.append(std::to_string(mGameCount));
|
2022-01-29 17:41:22 +00:00
|
|
|
else
|
2022-09-10 09:35:55 +00:00
|
|
|
gamelistInfoString.append(ViewController::FILTER_CHAR)
|
|
|
|
.append(" ")
|
|
|
|
.append(std::to_string(mFilteredGameCount))
|
|
|
|
.append(" + ")
|
|
|
|
.append(std::to_string(mFilteredGameCountAll - mFilteredGameCount))
|
|
|
|
.append(" / ")
|
|
|
|
.append(std::to_string(mGameCount));
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-09-10 09:35:55 +00:00
|
|
|
gamelistInfoString.append(ViewController::CONTROLLER_CHAR)
|
|
|
|
.append(" ")
|
|
|
|
.append(std::to_string(mGameCount));
|
2022-01-29 17:41:22 +00:00
|
|
|
if (!(file->getSystem()->isCollection() &&
|
|
|
|
file->getSystem()->getFullName() == "favorites"))
|
2022-09-10 09:35:55 +00:00
|
|
|
gamelistInfoString.append(" ")
|
|
|
|
.append(ViewController::FAVORITE_CHAR)
|
|
|
|
.append(" ")
|
|
|
|
.append(std::to_string(mFavoritesGameCount));
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mIsFolder && infoAlign != ALIGN_RIGHT)
|
2022-09-10 09:35:55 +00:00
|
|
|
gamelistInfoString.append(" ").append(ViewController::FOLDER_CHAR);
|
2022-01-29 17:41:22 +00:00
|
|
|
|
|
|
|
gamelistInfo->setValue(gamelistInfoString);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& image : mImageComponents) {
|
2022-01-30 18:30:38 +00:00
|
|
|
if (image->getScrollFadeIn()) {
|
2022-01-29 17:41:22 +00:00
|
|
|
auto func = [&image](float t) {
|
2022-02-11 21:10:25 +00:00
|
|
|
image->setOpacity(glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
|
2022-01-29 17:41:22 +00:00
|
|
|
};
|
|
|
|
image->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& video : mVideoComponents) {
|
2022-01-30 18:30:38 +00:00
|
|
|
if (video->getScrollFadeIn()) {
|
2022-01-29 17:41:22 +00:00
|
|
|
auto func = [&video](float t) {
|
2022-02-11 21:10:25 +00:00
|
|
|
video->setOpacity(glm::mix(FADE_IN_START_OPACITY, 1.0f, t));
|
2022-01-29 17:41:22 +00:00
|
|
|
};
|
|
|
|
video->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& container : mContainerComponents)
|
|
|
|
container->reset();
|
|
|
|
|
|
|
|
for (auto& rating : mRatingComponents)
|
|
|
|
rating->setValue(file->metadata.get("rating"));
|
|
|
|
|
|
|
|
// Populate the badge slots based on game metadata.
|
|
|
|
std::vector<BadgeComponent::BadgeInfo> badgeSlots;
|
|
|
|
for (auto& badgeComponent : mBadgeComponents) {
|
|
|
|
for (auto& badge : badgeComponent->getBadgeTypes()) {
|
|
|
|
BadgeComponent::BadgeInfo badgeInfo;
|
|
|
|
badgeInfo.badgeType = badge;
|
2022-04-15 17:27:38 +00:00
|
|
|
if (badge == "collection" && CollectionSystemsManager::getInstance()->isEditing()) {
|
|
|
|
if (CollectionSystemsManager::getInstance()->inCustomCollection(
|
|
|
|
CollectionSystemsManager::getInstance()->getEditingCollection(),
|
|
|
|
file)) {
|
|
|
|
badgeSlots.emplace_back(badgeInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (badge == "folder") {
|
2022-04-13 14:53:28 +00:00
|
|
|
if (file->getType() == FOLDER) {
|
|
|
|
if (file->metadata.get("folderlink") != "")
|
|
|
|
badgeInfo.folderLink = true;
|
|
|
|
badgeSlots.emplace_back(badgeInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (badge == "controller") {
|
2022-02-11 17:39:16 +00:00
|
|
|
if (file->metadata.get("controller") != "") {
|
2022-01-29 17:41:22 +00:00
|
|
|
badgeInfo.gameController = file->metadata.get("controller");
|
2022-04-13 14:53:28 +00:00
|
|
|
badgeSlots.emplace_back(badgeInfo);
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (badge == "altemulator") {
|
2022-02-11 17:39:16 +00:00
|
|
|
if (file->metadata.get(badge) != "")
|
2022-04-13 14:53:28 +00:00
|
|
|
badgeSlots.emplace_back(badgeInfo);
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-02-11 17:39:16 +00:00
|
|
|
if (file->metadata.get(badge) == "true")
|
2022-04-13 14:53:28 +00:00
|
|
|
badgeSlots.emplace_back(badgeInfo);
|
2022-01-29 17:41:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
badgeComponent->setBadges(badgeSlots);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& text : mTextComponents) {
|
2022-02-13 10:45:06 +00:00
|
|
|
if (text->getThemeMetadata() == "name")
|
2022-01-29 17:41:22 +00:00
|
|
|
text->setText(file->metadata.get("name"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file->getType() == GAME) {
|
|
|
|
if (!hideMetaDataFields) {
|
|
|
|
for (auto& date : mDateTimeComponents) {
|
2022-02-13 10:45:06 +00:00
|
|
|
if (date->getThemeMetadata() == "lastplayed")
|
2022-01-29 17:41:22 +00:00
|
|
|
date->setValue(file->metadata.get("lastplayed"));
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (date->getThemeMetadata() == "playcount")
|
2022-01-29 17:41:22 +00:00
|
|
|
date->setValue(file->metadata.get("playcount"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (file->getType() == FOLDER) {
|
|
|
|
if (!hideMetaDataFields) {
|
|
|
|
for (auto& date : mDateTimeComponents) {
|
2022-02-13 10:45:06 +00:00
|
|
|
if (date->getThemeMetadata() == "lastplayed") {
|
2022-01-29 17:41:22 +00:00
|
|
|
date->setValue(file->metadata.get("lastplayed"));
|
|
|
|
date->setVisible(false);
|
|
|
|
date->setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string metadata;
|
|
|
|
|
|
|
|
auto getMetadataValue = [&file, &metadata]() -> std::string {
|
2022-02-13 10:45:06 +00:00
|
|
|
if (metadata == "name")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("name");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "description")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("desc");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "developer")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("developer");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "publisher")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("publisher");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "genre")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("genre");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "players")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("players");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "favorite")
|
|
|
|
return file->metadata.get("favorite") == "true" ? "yes" : "no";
|
|
|
|
else if (metadata == "completed")
|
|
|
|
return file->metadata.get("completed") == "true" ? "yes" : "no";
|
|
|
|
else if (metadata == "kidgame")
|
|
|
|
return file->metadata.get("kidgame") == "true" ? "yes" : "no";
|
|
|
|
else if (metadata == "broken")
|
|
|
|
return file->metadata.get("broken") == "true" ? "yes" : "no";
|
|
|
|
else if (metadata == "playcount")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("playcount");
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "altemulator")
|
2022-01-29 17:41:22 +00:00
|
|
|
return file->metadata.get("altemulator");
|
|
|
|
else
|
|
|
|
return metadata;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto& text : mContainerTextComponents) {
|
2022-02-13 10:45:06 +00:00
|
|
|
metadata = text->getThemeMetadata();
|
2022-01-29 17:41:22 +00:00
|
|
|
if (metadata == "")
|
|
|
|
continue;
|
|
|
|
|
2022-02-13 10:45:06 +00:00
|
|
|
if (metadata == "rating") {
|
2022-06-06 20:28:24 +00:00
|
|
|
text->setValue(RatingComponent::getRatingValue(file->metadata.get("rating")));
|
2022-01-29 17:41:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "controller") {
|
|
|
|
std::string controller {
|
|
|
|
BadgeComponent::getDisplayName(file->metadata.get("controller"))};
|
2022-01-29 17:41:22 +00:00
|
|
|
text->setValue(controller == "unknown" ? "" : controller);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
text->setValue(getMetadataValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& text : mTextComponents) {
|
2022-02-13 10:45:06 +00:00
|
|
|
metadata = text->getThemeMetadata();
|
2022-01-29 17:41:22 +00:00
|
|
|
if (metadata == "")
|
|
|
|
continue;
|
|
|
|
|
2022-02-13 10:45:06 +00:00
|
|
|
if (metadata == "rating") {
|
2022-06-06 20:28:24 +00:00
|
|
|
text->setValue(RatingComponent::getRatingValue(file->metadata.get("rating")));
|
2022-01-29 17:41:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "controller") {
|
2022-01-29 17:41:22 +00:00
|
|
|
std::string controller =
|
|
|
|
BadgeComponent::getDisplayName(file->metadata.get("controller"));
|
|
|
|
text->setValue(controller == "unknown" ? "" : controller);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
text->setValue(getMetadataValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto& date : mDateTimeComponents) {
|
2022-09-10 09:35:55 +00:00
|
|
|
std::string metadata {date->getThemeMetadata()};
|
2022-01-29 17:41:22 +00:00
|
|
|
if (metadata == "")
|
|
|
|
continue;
|
|
|
|
|
2022-02-13 10:45:06 +00:00
|
|
|
if (metadata == "releasedate") {
|
2022-01-29 17:41:22 +00:00
|
|
|
date->setValue(file->metadata.get("releasedate"));
|
|
|
|
}
|
2022-02-13 10:45:06 +00:00
|
|
|
else if (metadata == "lastplayed") {
|
2022-01-29 17:41:22 +00:00
|
|
|
date->setValue(file->metadata.get("lastplayed"));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
date->setValue("19700101T000000");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<GuiComponent*> comps;
|
2022-01-22 20:50:42 +00:00
|
|
|
|
2022-01-29 17:41:22 +00:00
|
|
|
for (auto& text : mTextComponents) {
|
|
|
|
if (text->getScrollHide())
|
|
|
|
comps.emplace_back(text.get());
|
|
|
|
}
|
|
|
|
for (auto& date : mDateTimeComponents) {
|
|
|
|
if (date->getScrollHide())
|
|
|
|
comps.emplace_back(date.get());
|
|
|
|
}
|
|
|
|
for (auto& image : mImageComponents) {
|
|
|
|
if (image->getScrollHide())
|
|
|
|
comps.emplace_back(image.get());
|
|
|
|
}
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& video : mStaticVideoComponents) {
|
|
|
|
if (video->getScrollHide())
|
|
|
|
comps.emplace_back(video.get());
|
|
|
|
}
|
2022-02-09 17:16:15 +00:00
|
|
|
for (auto& video : mVideoComponents) {
|
|
|
|
if (video->getScrollHide())
|
|
|
|
comps.emplace_back(video.get());
|
|
|
|
}
|
2022-08-18 20:51:21 +00:00
|
|
|
for (auto& anim : mLottieAnimComponents) {
|
|
|
|
if (anim->getScrollHide())
|
|
|
|
comps.emplace_back(anim.get());
|
|
|
|
}
|
|
|
|
for (auto& anim : mGIFAnimComponents) {
|
|
|
|
if (anim->getScrollHide())
|
|
|
|
comps.emplace_back(anim.get());
|
|
|
|
}
|
2022-01-29 17:41:22 +00:00
|
|
|
for (auto& badge : mBadgeComponents) {
|
|
|
|
if (badge->getScrollHide())
|
|
|
|
comps.emplace_back(badge.get());
|
|
|
|
}
|
|
|
|
for (auto& rating : mRatingComponents) {
|
|
|
|
if (rating->getScrollHide())
|
|
|
|
comps.emplace_back(rating.get());
|
|
|
|
}
|
|
|
|
for (auto& container : mContainerComponents) {
|
|
|
|
if (container->getScrollHide())
|
|
|
|
comps.emplace_back(container.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto it = comps.cbegin(); it != comps.cend(); ++it) {
|
2022-02-12 16:50:44 +00:00
|
|
|
GuiComponent* comp {*it};
|
2022-01-29 17:41:22 +00:00
|
|
|
if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
2022-08-17 15:04:19 +00:00
|
|
|
(!comp->isAnimationPlaying(0) &&
|
|
|
|
comp->getOpacity() != (fadingOut ? 0.0f : comp->getColorOpacity()))) {
|
2022-02-11 21:10:25 +00:00
|
|
|
auto func = [comp](float t) { comp->setOpacity(glm::mix(0.0f, 1.0f, t)); };
|
2022-01-29 17:41:22 +00:00
|
|
|
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
|
|
|
|
}
|
|
|
|
}
|
2022-03-24 22:05:23 +00:00
|
|
|
|
|
|
|
if (state == CursorState::CURSOR_SCROLLING)
|
|
|
|
mLastUpdated = nullptr;
|
2022-01-18 16:14:17 +00:00
|
|
|
}
|
2022-02-14 18:32:07 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2022-06-07 15:32:42 +00:00
|
|
|
else if (imageType == "physicalmedia") {
|
|
|
|
path = file->getPhysicalMediaPath();
|
|
|
|
if (path != "") {
|
|
|
|
comp->setImage(path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-02-14 18:32:07 +00:00
|
|
|
else if (imageType == "fanart") {
|
|
|
|
path = file->getFanArtPath();
|
|
|
|
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("");
|
|
|
|
}
|