From 62d5c1e6566539a362cb952605ff87c1712afdee Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 22 Jan 2022 21:42:43 +0100 Subject: [PATCH] Rewrote the gamelist logic for the new theme engine. Also split out all legacy mode (backward compatibility) functions to a separate header file. --- es-app/CMakeLists.txt | 1 + es-app/src/views/GamelistBase.cpp | 2 +- es-app/src/views/GamelistLegacy.h | 768 ++++++++++++++++++++++++++++++ es-app/src/views/GamelistView.cpp | 544 +-------------------- es-app/src/views/GamelistView.h | 83 ++-- 5 files changed, 842 insertions(+), 556 deletions(-) create mode 100644 es-app/src/views/GamelistLegacy.h diff --git a/es-app/CMakeLists.txt b/es-app/CMakeLists.txt index 9510737e6..db52a8e55 100644 --- a/es-app/CMakeLists.txt +++ b/es-app/CMakeLists.txt @@ -50,6 +50,7 @@ set(ES_HEADERS # Views ${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistLegacy.h ${CMAKE_CURRENT_SOURCE_DIR}/src/views/GamelistView.h ${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.h ${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.h diff --git a/es-app/src/views/GamelistBase.cpp b/es-app/src/views/GamelistBase.cpp index c0a0cf90b..77b1f4996 100644 --- a/es-app/src/views/GamelistBase.cpp +++ b/es-app/src/views/GamelistBase.cpp @@ -660,7 +660,7 @@ void GamelistBase::generateGamelistInfo(FileData* cursor, FileData* firstEntry) void GamelistBase::remove(FileData* game, bool deleteFile) { - // Delete the game file on the filesystem. + // Optionally delete the game file on the filesystem. if (deleteFile) Utils::FileSystem::removeFile(game->getPath()); diff --git a/es-app/src/views/GamelistLegacy.h b/es-app/src/views/GamelistLegacy.h new file mode 100644 index 000000000..ac0e424f1 --- /dev/null +++ b/es-app/src/views/GamelistLegacy.h @@ -0,0 +1,768 @@ +// SPDX-License-Identifier: MIT +// +// EmulationStation Desktop Edition +// GamelistLegacy.h +// +// Specific gamelist functions for backward compatibility (legacy mode). +// + +#ifndef ES_APP_VIEWS_GAMELIST_LEGACY_H +#define ES_APP_VIEWS_GAMELIST_LEGACY_H + +#include "CollectionSystemsManager.h" +#include "animations/LambdaAnimation.h" + +#define FADE_IN_START_OPACITY 0.5f +#define FADE_IN_TIME 325 + +void GamelistView::legacyPopulateFields() +{ + const float padding {0.01f}; + + // Logo text (fallback if no logo image exists). + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText(mRoot->getSystem()->getFullName(), false); + mTextComponents.back()->setSize(mSize.x, 0.0f); + mTextComponents.back()->setPosition(0.0f, 0.0f); + mTextComponents.back()->setHorizontalAlignment(ALIGN_CENTER); + mTextComponents.back()->setColor(0xFFFFFFFF); + mTextComponents.back()->setDefaultZIndex(50.0f); + addChild(mTextComponents.back().get()); + + // Logo. + mImageComponents.push_back(std::make_unique()); + mImageComponents.back()->setResize(0.0f, mSize.y * 0.185f); + mImageComponents.back()->setOrigin(0.5f, 0.0f); + mImageComponents.back()->setPosition(mSize.x / 2.0f, 0.0f); + mImageComponents.back()->setDefaultZIndex(50.0f); + addChild(mImageComponents.back().get()); + + // Background. + mImageComponents.push_back(std::make_unique()); + mImageComponents.back()->setResize(mSize.x, mSize.y); + mImageComponents.back()->setDefaultZIndex(0.0f); + addChild(mImageComponents.back().get()); + + // Thumbnails. + mImageComponents.push_back(std::make_unique()); + mImageComponents.back()->setMetadataField("md_thumbnail"); + mImageComponents.back()->setOrigin(0.5f, 0.5f); + mImageComponents.back()->setVisible(false); + mImageComponents.back()->setMaxSize(mSize.x * (0.25f - 2.0f * padding), mSize.y * 0.10f); + mImageComponents.back()->setDefaultZIndex(25.0f); + addChild(mImageComponents.back().get()); + + // Marquee. + mImageComponents.push_back(std::make_unique()); + mImageComponents.back()->setMetadataField("md_marquee"); + mImageComponents.back()->setOrigin(0.5f, 0.5f); + mImageComponents.back()->setVisible(false); + mImageComponents.back()->setMaxSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.18f); + mImageComponents.back()->setDefaultZIndex(35.0f); + addChild(mImageComponents.back().get()); + + // Image. + mImageComponents.push_back(std::make_unique()); + mImageComponents.back()->setMetadataField("md_image"); + mImageComponents.back()->setOrigin(0.5f, 0.5f); + mImageComponents.back()->setPosition(mSize.x * 0.25f, + mList.getPosition().y + mSize.y * 0.2125f); + mImageComponents.back()->setMaxSize(mSize.x * (0.50f - 2.0f * padding), mSize.y * 0.4f); + mImageComponents.back()->setDefaultZIndex(30.0f); + addChild(mImageComponents.back().get()); + + if (mViewStyle == ViewController::VIDEO) { + // Video. + mVideoComponents.push_back(std::make_unique()); + mVideoComponents.back()->setMetadataField("md_video"); + mVideoComponents.back()->setOrigin(0.5f, 0.5f); + mVideoComponents.back()->setPosition(mSize.x * 0.25f, mSize.y * 0.4f); + mVideoComponents.back()->setSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.4f); + mVideoComponents.back()->setDefaultZIndex(30.0f); + addChild(mVideoComponents.back().get()); + } + + mList.setPosition(mSize.x * (0.50f + padding), mList.getPosition().y); + mList.setSize(mSize.x * (0.50f - padding), mList.getSize().y); + mList.setAlignment(TextListComponent::ALIGN_LEFT); + mList.setCursorChangedCallback([&](const CursorState& /*state*/) { legacyUpdateInfoPanel(); }); + + // Metadata labels + values. + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Rating: ", false); + mTextComponents.back()->setMetadataField("md_lbl_rating"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Released: ", false); + mTextComponents.back()->setMetadataField("md_lbl_releasedate"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Developer: ", false); + mTextComponents.back()->setMetadataField("md_lbl_developer"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Publisher: ", false); + mTextComponents.back()->setMetadataField("md_lbl_publisher"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Genre: ", false); + mTextComponents.back()->setMetadataField("md_lbl_genre"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Players: ", false); + mTextComponents.back()->setMetadataField("md_lbl_players"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Last played: ", false); + mTextComponents.back()->setMetadataField("md_lbl_lastplayed"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setText("Times played: ", false); + mTextComponents.back()->setMetadataField("md_lbl_playcount"); + addChild(mTextComponents.back().get()); + + mRatingComponents.push_back(std::make_unique()); + mRatingComponents.back()->setMetadataField("md_rating"); + mRatingComponents.back()->setDefaultZIndex(40.0f); + addChild(mRatingComponents.back().get()); + + mDateTimeComponents.push_back(std::make_unique()); + mDateTimeComponents.back()->setMetadataField("md_releasedate"); + addChild(mDateTimeComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_developer"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_publisher"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_genre"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_players"); + addChild(mTextComponents.back().get()); + + mDateTimeComponents.push_back(std::make_unique()); + mDateTimeComponents.back()->setMetadataField("md_lastplayed"); + addChild(mDateTimeComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_playcount"); + addChild(mTextComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setMetadataField("md_name"); + mTextComponents.back()->setPosition(mSize.x, mSize.y); + mTextComponents.back()->setFont(Font::get(FONT_SIZE_MEDIUM)); + mTextComponents.back()->setHorizontalAlignment(ALIGN_CENTER); + mTextComponents.back()->setColor(0xAAAAAAFF); + mTextComponents.back()->setDefaultZIndex(40.0f); + addChild(mTextComponents.back().get()); + + // Badges. + mBadgeComponents.push_back(std::make_unique()); + mBadgeComponents.back()->setMetadataField("md_badges"); + mBadgeComponents.back()->setOrigin(0.5f, 0.5f); + mBadgeComponents.back()->setPosition(mSize.x * 0.8f, mSize.y * 0.7f); + mBadgeComponents.back()->setSize(mSize.x * 0.15f, mSize.y * 0.2f); + mBadgeComponents.back()->setDefaultZIndex(50.0f); + addChild(mBadgeComponents.back().get()); + + // Scrollable container (game description). + mScrollableContainerComponents.push_back(std::make_unique()); + mScrollableContainerComponents.back()->setMetadataField("md_description"); + mScrollableContainerComponents.back()->setSize( + mSize.x * (0.50f - 2.0f * padding), + mSize.y - mScrollableContainerComponents.back()->getPosition().y); + mScrollableContainerComponents.back()->setAutoScroll(true); + mScrollableContainerComponents.back()->setDefaultZIndex(40.0f); + addChild(mScrollableContainerComponents.back().get()); + + mTextComponents.push_back(std::make_unique()); + mTextComponents.back()->setFont(Font::get(FONT_SIZE_SMALL)); + mTextComponents.back()->setSize(mScrollableContainerComponents.back()->getSize().x, 0.0f); + mScrollableContainerComponents.back()->addChild(mTextComponents.back().get()); + + mGamelistInfoComponents.push_back(std::make_unique()); + mGamelistInfoComponents.back()->setMetadataField("gamelistInfo"); + mGamelistInfoComponents.back()->setOrigin(0.5f, 0.5f); + mGamelistInfoComponents.back()->setFont(Font::get(FONT_SIZE_SMALL)); + mGamelistInfoComponents.back()->setDefaultZIndex(50.0f); + mGamelistInfoComponents.back()->setVisible(true); + addChild(mGamelistInfoComponents.back().get()); +} + +void GamelistView::legacyOnThemeChanged(const std::shared_ptr& theme) +{ + legacyPopulateFields(); + + using namespace ThemeFlags; + + mTextComponents[LOGOTEXT]->applyTheme(theme, getName(), "logoText", ALL); + mImageComponents[LOGO]->applyTheme(theme, getName(), "logo", ALL); + mImageComponents[BACKGROUND]->applyTheme(theme, getName(), "background", ALL); + + // Remove old theme extras. + for (auto extra : mThemeExtras) { + removeChild(extra); + delete extra; + } + mThemeExtras.clear(); + + // Add new theme extras. + mThemeExtras = ThemeData::makeExtras(theme, getName()); + for (auto extra : mThemeExtras) + addChild(extra); + + mList.applyTheme(theme, getName(), "gamelist", ALL); + + mImageComponents[LegacyImage::MD_THUMBNAIL]->applyTheme( + theme, getName(), mImageComponents[LegacyImage::MD_THUMBNAIL]->getMetadataField(), ALL); + mImageComponents[LegacyImage::MD_MARQUEE]->applyTheme( + theme, getName(), "md_marquee", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE); + + if (mViewStyle == ViewController::DETAILED) { + mImageComponents[LegacyImage::MD_IMAGE]->applyTheme( + theme, getName(), mImageComponents[LegacyImage::MD_IMAGE]->getMetadataField(), + POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION | VISIBLE); + } + else if (mViewStyle == ViewController::VIDEO) { + mVideoComponents.front()->applyTheme( + theme, getName(), mVideoComponents.front()->getMetadataField(), + POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | VISIBLE); + } + + legacyInitMDLabels(); + legacyInitMDValues(); + + mTextComponents[LegacyText::MD_NAME]->applyTheme( + theme, getName(), mTextComponents[LegacyText::MD_NAME]->getMetadataField(), ALL); + + for (size_t i = 0; i < mBadgeComponents.size(); ++i) + mBadgeComponents[i]->applyTheme(theme, getName(), mBadgeComponents[i]->getMetadataField(), + ALL); + + for (size_t i = 0; i < mRatingComponents.size(); ++i) + mRatingComponents[i]->applyTheme(theme, getName(), mRatingComponents[i]->getMetadataField(), + ALL); + + mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->applyTheme( + theme, getName(), mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->getMetadataField(), + ALL); + + mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->applyTheme( + theme, getName(), mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->getMetadataField(), + ALL); + + if (mLegacyMode) { + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_NAME; ++i) + mTextComponents[i]->applyTheme(theme, getName(), mTextComponents[i]->getMetadataField(), + ALL ^ ThemeFlags::TEXT); + } + else { + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_NAME; ++i) + mTextComponents[i]->applyTheme(theme, getName(), mTextComponents[i]->getMetadataField(), + ALL); + } + + for (auto& container : mScrollableContainerComponents) { + container->applyTheme(theme, getName(), container->getMetadataField(), + POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE); + } + + mTextComponents[LegacyText::MD_DESCRIPTION]->setSize( + mScrollableContainerComponents.front()->getSize().x, 0.0f); + mTextComponents[LegacyText::MD_DESCRIPTION]->applyTheme( + theme, getName(), "md_description", + ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION)); + + for (auto& gamelistInfo : mGamelistInfoComponents) + gamelistInfo->applyTheme(theme, getName(), gamelistInfo->getMetadataField(), + ALL ^ ThemeFlags::TEXT); + + // If there is no position defined in the theme for gamelistInfo, then hide it. + if (mGamelistInfoComponents.front()->getPosition() == glm::vec3 {}) + mGamelistInfoComponents.front()->setVisible(false); + else + mGamelistInfoComponents.front()->setVisible(true); + + // Hide some components if we're in Basic mode. + if (mViewStyle == ViewController::BASIC) { + if (mTheme->getElement(getName(), "logoText", "text") == nullptr) + mTextComponents[LegacyText::LOGOTEXT]->setVisible(false); + mImageComponents[LegacyImage::MD_IMAGE]->setVisible(false); + for (auto& container : mScrollableContainerComponents) + container->setVisible(false); + } + + sortChildren(); +} + +void GamelistView::legacyUpdateInfoPanel() +{ + FileData* file {(mList.size() == 0 || mList.isScrolling()) ? nullptr : mList.getSelected()}; + + // If the game data has already been rendered to the info panel, then skip it this time. + if (file == mLastUpdated) + return; + + if (!mList.isScrolling()) + 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; + } + } + + // 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. + if (mList.isScrolling()) + if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") || + (mLastUpdated->getSystem()->isCustomCollection() && + mLastUpdated->getPath() == mLastUpdated->getSystem()->getName())) + hideMetaDataFields = true; + + if (hideMetaDataFields || mViewStyle == ViewController::BASIC) { + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DESCRIPTION; ++i) + mTextComponents[i]->setVisible(false); + for (auto& date : mDateTimeComponents) + date->setVisible(false); + for (auto& badge : mBadgeComponents) + badge->setVisible(false); + for (auto& rating : mRatingComponents) + rating->setVisible(false); + } + else { + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DESCRIPTION; ++i) + mTextComponents[i]->setVisible(true); + for (auto& date : mDateTimeComponents) + date->setVisible(true); + for (auto& badge : mBadgeComponents) + badge->setVisible(true); + for (auto& rating : mRatingComponents) + rating->setVisible(true); + } + + bool fadingOut = false; + if (file == nullptr) { + 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) { + mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage( + mRandomGame->getThumbnailPath()); + mImageComponents[LegacyImage::MD_MARQUEE]->setImage(mRandomGame->getMarqueePath(), + false, true); + mImageComponents[LegacyImage::MD_IMAGE]->setImage(mRandomGame->getImagePath()); + if (mViewStyle == ViewController::VIDEO) { + mVideoComponents.front()->setImage(mRandomGame->getImagePath()); + // 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 + // video file) as the previously set video. That may happen when entering a + // folder with the same name as the first game file inside, or as in this + // case, when entering a custom collection. + mVideoComponents.front()->onHide(); + + if (!mVideoComponents.front()->setVideo(mRandomGame->getVideoPath())) + mVideoComponents.front()->setDefaultVideo(); + } + } + else { + mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage(""); + mImageComponents[LegacyImage::MD_MARQUEE]->setImage(""); + mImageComponents[LegacyImage::MD_IMAGE]->setImage(""); + if (mViewStyle == ViewController::VIDEO) { + mVideoComponents.front()->setImage(""); + mVideoComponents.front()->setVideo(""); + mVideoComponents.front()->setDefaultVideo(); + } + } + } + else { + mImageComponents[LegacyImage::MD_THUMBNAIL]->setImage(file->getThumbnailPath()); + mImageComponents[LegacyImage::MD_MARQUEE]->setImage(file->getMarqueePath(), false, + true); + if (mViewStyle == ViewController::VIDEO) { + mVideoComponents.front()->setImage(file->getImagePath()); + mVideoComponents.front()->onHide(); + + if (!mVideoComponents.front()->setVideo(file->getVideoPath())) + mVideoComponents.front()->setDefaultVideo(); + } + else { + mImageComponents[LegacyImage::MD_IMAGE]->setImage(file->getImagePath()); + } + } + + 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; + Alignment infoAlign = gamelistInfo->getHorizontalAlignment(); + + if (mIsFolder && infoAlign == ALIGN_RIGHT) + gamelistInfoString = ViewController::FOLDER_CHAR + " "; + + if (mIsFiltered) { + if (mFilteredGameCountAll == mFilteredGameCount) + gamelistInfoString += ViewController::FILTER_CHAR + " " + + std::to_string(mFilteredGameCount) + " / " + + std::to_string(mGameCount); + else + gamelistInfoString += + ViewController::FILTER_CHAR + " " + std::to_string(mFilteredGameCount) + + " + " + std::to_string(mFilteredGameCountAll - mFilteredGameCount) + " / " + + std::to_string(mGameCount); + } + else { + gamelistInfoString += + ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount); + if (!(file->getSystem()->isCollection() && + file->getSystem()->getFullName() == "favorites")) + gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " + + std::to_string(mFavoritesGameCount); + } + + if (mIsFolder && infoAlign != ALIGN_RIGHT) + gamelistInfoString += " " + ViewController::FOLDER_CHAR; + + gamelistInfo->setValue(gamelistInfoString); + } + + if (mViewStyle == ViewController::DETAILED) { + // Fade in the game image. + auto func = [this](float t) { + mImageComponents[LegacyImage::MD_IMAGE]->setOpacity(static_cast( + glm::mix(static_cast(FADE_IN_START_OPACITY), 1.0f, t) * 255)); + }; + mImageComponents[LegacyImage::MD_IMAGE]->setAnimation( + new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false); + } + else if (mViewStyle == ViewController::VIDEO) { + // Fade in the static image. + auto func = [this](float t) { + mVideoComponents.front()->setOpacity(static_cast( + glm::mix(static_cast(FADE_IN_START_OPACITY), 1.0f, t) * 255)); + }; + mVideoComponents.front()->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, + nullptr, false); + } + + mTextComponents[LegacyText::MD_DESCRIPTION]->setText(file->metadata.get("desc")); + for (auto& container : mScrollableContainerComponents) + container->reset(); + + for (auto& rating : mRatingComponents) + rating->setValue(file->metadata.get("rating")); + + mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->setValue( + file->metadata.get("releasedate")); + mTextComponents[LegacyText::MD_DEVELOPER]->setValue(file->metadata.get("developer")); + mTextComponents[LegacyText::MD_PUBLISHER]->setValue(file->metadata.get("publisher")); + mTextComponents[LegacyText::MD_GENRE]->setValue(file->metadata.get("genre")); + mTextComponents[LegacyText::MD_PLAYERS]->setValue(file->metadata.get("players")); + + // Populate the badge slots based on game metadata. + std::vector badgeSlots; + for (auto& badgeComponent : mBadgeComponents) { + for (auto& badge : badgeComponent->getBadgeTypes()) { + BadgeComponent::BadgeInfo badgeInfo; + badgeInfo.badgeType = badge; + if (badge == "controller") { + if (file->metadata.get("controller").compare("") != 0) { + badgeInfo.gameController = file->metadata.get("controller"); + badgeSlots.push_back(badgeInfo); + } + } + else if (badge == "altemulator") { + if (file->metadata.get(badge).compare("") != 0) + badgeSlots.push_back(badgeInfo); + } + else { + if (file->metadata.get(badge).compare("true") == 0) + badgeSlots.push_back(badgeInfo); + } + } + badgeComponent->setBadges(badgeSlots); + } + + mTextComponents[LegacyText::MD_NAME]->setValue(file->metadata.get("name")); + + if (file->getType() == GAME) { + if (!hideMetaDataFields) { + mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setValue( + file->metadata.get("lastplayed")); + mTextComponents[LegacyText::MD_PLAYCOUNT]->setValue( + file->metadata.get("playcount")); + } + } + else if (file->getType() == FOLDER) { + if (!hideMetaDataFields) { + mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setValue( + file->metadata.get("lastplayed")); + mTextComponents[LegacyText::MD_LBL_PLAYCOUNT]->setVisible(false); + mTextComponents[LegacyText::MD_PLAYCOUNT]->setVisible(false); + } + } + + for (auto& text : mTextComponents) { + if (text->getValue() != "") + continue; + + std::string metadata = text->getMetadataField(); + if (metadata == "") + continue; + + if (metadata == "md_controller") { + std::string controller = + BadgeComponent::getDisplayName(file->metadata.get("controller")); + text->setValue(controller == "unknown" ? "" : controller); + continue; + } + + if (metadata == "md_name") + text->setValue(file->metadata.get("name")); + else if (metadata == "md_rating") + text->setValue(mRatingComponents.front()->getRatingValue()); + else if (metadata == "md_developer") + text->setValue(file->metadata.get("developer")); + else if (metadata == "md_publisher") + text->setValue(file->metadata.get("publisher")); + else if (metadata == "md_genre") + text->setValue(file->metadata.get("genre")); + else if (metadata == "md_players") + text->setValue(file->metadata.get("players")); + else if (metadata == "md_favorite") + text->setValue(file->metadata.get("favorite") == "true" ? "yes" : "no"); + else if (metadata == "md_completed") + text->setValue(file->metadata.get("completed") == "true" ? "yes" : "no"); + else if (metadata == "md_kidgame") + text->setValue(file->metadata.get("kidgame") == "true" ? "yes" : "no"); + else if (metadata == "md_broken") + text->setValue(file->metadata.get("broken") == "true" ? "yes" : "no"); + else if (metadata == "md_playcount") + text->setValue(file->metadata.get("playcount")); + else if (metadata == "md_altemulator") + text->setValue(file->metadata.get("altemulator")); + else + text->setValue(metadata); + } + + for (auto& date : mDateTimeComponents) { + std::string metadata = date->getMetadataField(); + if (metadata == "") + continue; + + if (metadata == "md_releasedate") { + date->setValue(file->metadata.get("releasedate")); + } + else if (metadata == "md_lastplayed") { + date->setValue(file->metadata.get("lastplayed")); + date->setDisplayRelative(true); + } + else { + date->setValue("19700101T000000"); + } + } + + fadingOut = false; + } + + std::vector comps; + + if (!mLegacyMode) { + 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()); + } + for (auto& badge : mBadgeComponents) { + if (badge->getScrollHide()) + comps.emplace_back(badge.get()); + } + for (auto& rating : mRatingComponents) { + if (rating->getScrollHide()) + comps.emplace_back(rating.get()); + } + } + + if (mLegacyMode) { + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::END; ++i) + comps.emplace_back(mTextComponents[i].get()); + comps.emplace_back(mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE].get()); + comps.emplace_back(mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED].get()); + comps.emplace_back(mTextComponents[LegacyText::MD_NAME].get()); + comps.emplace_back(mImageComponents[LegacyImage::MD_THUMBNAIL].get()); + comps.emplace_back(mImageComponents[LegacyImage::MD_MARQUEE].get()); + comps.emplace_back(mImageComponents[LegacyImage::MD_IMAGE].get()); + comps.push_back(mBadgeComponents.front().get()); + comps.push_back(mRatingComponents.front().get()); + } + + for (auto it = comps.cbegin(); it != comps.cend(); ++it) { + GuiComponent* comp = *it; + // An animation is playing, then animate if reverse != fadingOut. + // An animation is not playing, then animate if opacity != our target opacity. + if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) || + (!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) { + auto func = [comp](float t) { + comp->setOpacity(static_cast(glm::mix(0.0f, 1.0f, t) * 255)); + }; + comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut); + } + } +} + +void GamelistView::legacyUpdate(int deltaTime) +{ + if (ViewController::getInstance()->getGameLaunchTriggered() && + mImageComponents[LegacyImage::MD_IMAGE]->isAnimationPlaying(0)) + mImageComponents[LegacyImage::MD_IMAGE]->finishAnimation(0); + + if (mViewStyle == ViewController::VIDEO) { + if (!mVideoPlaying) + mVideoComponents.front()->onHide(); + else if (mVideoPlaying && !mVideoComponents.front()->isVideoPaused() && + !mWindow->isScreensaverActive()) + mVideoComponents.front()->onShow(); + + if (ViewController::getInstance()->getGameLaunchTriggered() && + mVideoComponents.front()->isAnimationPlaying(0)) + mVideoComponents.front()->finishAnimation(0); + } + + updateChildren(deltaTime); +} + +void GamelistView::legacyInitMDLabels() +{ + std::vector components; + + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DEVELOPER; ++i) + components.emplace_back(&*mTextComponents[i]); + + const unsigned int colCount {2}; + const unsigned int rowCount {static_cast(components.size() / 2)}; + + glm::vec3 start {mSize.x * 0.01f, mSize.y * 0.625f, 0.0f}; + + const float colSize {(mSize.x * 0.48f) / colCount}; + const float rowPadding {0.01f * mSize.y}; + + for (unsigned int i = 0; i < components.size(); ++i) { + const unsigned int row = i % rowCount; + glm::vec3 pos {}; + if (row == 0) { + pos = start + glm::vec3 {colSize * (i / rowCount), 0.0f, 0.0f}; + } + else { + // Work from the last component. + GuiComponent* lc {components[i - 1]}; + pos = lc->getPosition() + glm::vec3 {0.0f, lc->getSize().y + rowPadding, 0.0f}; + } + + components[i]->setFont(Font::get(FONT_SIZE_SMALL)); + components[i]->setPosition(pos); + // components[i]->setColor(0xFFFFFFFF); + components[i]->setDefaultZIndex(40.0f); + } +} + +void GamelistView::legacyInitMDValues() +{ + std::vector labels; + std::vector values; + + std::shared_ptr defaultFont {Font::get(FONT_SIZE_SMALL)}; + + for (size_t i = LegacyText::MD_LBL_RATING; i < LegacyText::MD_DEVELOPER; ++i) { + labels.emplace_back(&*mTextComponents[i]); + mTextComponents[i]->setFont(defaultFont); + // mTextComponents[i]->setColor(0xFFFFFFFF); + } + + mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->setFont(defaultFont); + // mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE]->setColor(0xFFFFFFFF); + mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setFont(defaultFont); + // mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED]->setColor(0xFFFFFFFF); + + values.emplace_back(mRatingComponents.front().get()); + values.emplace_back(mDateTimeComponents[LegacyDateTime::MD_RELEASEDATE].get()); + values.emplace_back(mTextComponents[LegacyText::MD_DEVELOPER].get()); + values.emplace_back(mTextComponents[LegacyText::MD_PUBLISHER].get()); + values.emplace_back(mTextComponents[LegacyText::MD_GENRE].get()); + values.emplace_back(mTextComponents[LegacyText::MD_PLAYERS].get()); + values.emplace_back(mDateTimeComponents[LegacyDateTime::MD_LASTPLAYED].get()); + values.emplace_back(mTextComponents[LegacyText::MD_PLAYCOUNT].get()); + + float bottom {0.0f}; + const float colSize {(mSize.x * 0.48f) / 2.0f}; + for (unsigned int i = 0; i < labels.size(); ++i) { + const float heightDiff = (labels[i]->getSize().y - values[i]->getSize().y) / 2.0f; + values[i]->setPosition(labels[i]->getPosition() + + glm::vec3 {labels[i]->getSize().x, heightDiff, 0.0f}); + values[i]->setSize(colSize - labels[i]->getSize().x, values[i]->getSize().y); + values[i]->setDefaultZIndex(40.0f); + + float testBot = values[i]->getPosition().y + values[i]->getSize().y; + + if (testBot > bottom) + bottom = testBot; + } + + // Default to off the screen for the following components. + mRatingComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f, + Renderer::getScreenHeight() * 2.0f); + + mScrollableContainerComponents.front()->setPosition(Renderer::getScreenWidth() * 2.0f, + Renderer::getScreenHeight() * 2.0f); + + for (auto& container : mScrollableContainerComponents) { + container->setPosition(container->getPosition().x, bottom + mSize.y * 0.01f); + container->setSize(container->getSize().x, mSize.y - container->getPosition().y); + } +} + +#endif // ES_APP_VIEWS_GAMELIST_LEGACY_H diff --git a/es-app/src/views/GamelistView.cpp b/es-app/src/views/GamelistView.cpp index c48332683..a70f10331 100644 --- a/es-app/src/views/GamelistView.cpp +++ b/es-app/src/views/GamelistView.cpp @@ -7,145 +7,34 @@ // #include "views/GamelistView.h" +#include "views/GamelistLegacy.h" #include "CollectionSystemsManager.h" #include "UIModeController.h" #include "animations/LambdaAnimation.h" -#define FADE_IN_START_OPACITY 0.5f -#define FADE_IN_TIME 325 +// #define FADE_IN_START_OPACITY 0.5f +// #define FADE_IN_TIME 325 -GamelistView::GamelistView(FileData* root) +GamelistView::GamelistView(FileData* root, bool legacyMode) : GamelistBase {root} + , mLegacyMode {legacyMode} , mViewStyle {ViewController::BASIC} - , mVideo {nullptr} { + // TEMPORARY + mLegacyMode = true; + mViewStyle = ViewController::getInstance()->getState().viewstyle; - mHeaderText.setText("Logo Text", false); - mHeaderText.setSize(mSize.x, 0.0f); - mHeaderText.setPosition(0.0f, 0.0f); - mHeaderText.setHorizontalAlignment(ALIGN_CENTER); - mHeaderText.setDefaultZIndex(50.0f); + if (mLegacyMode) + return; - mHeaderText.setText(mRoot->getSystem()->getFullName()); - - mHeaderImage.setResize(0.0f, mSize.y * 0.185f); - mHeaderImage.setOrigin(0.5f, 0.0f); - mHeaderImage.setPosition(mSize.x / 2.0f, 0.0f); - mHeaderImage.setDefaultZIndex(50.0f); - - mBackground.setResize(mSize.x, mSize.y); - mBackground.setDefaultZIndex(0.0f); - - addChild(&mHeaderText); - addChild(&mBackground); - - const float padding = 0.01f; - - if (mViewStyle == ViewController::VIDEO) { - // Create the video window. - mVideo = new VideoFFmpegComponent; - } + const float padding {0.01f}; mList.setPosition(mSize.x * (0.50f + padding), mList.getPosition().y); mList.setSize(mSize.x * (0.50f - padding), mList.getSize().y); mList.setAlignment(TextListComponent::ALIGN_LEFT); mList.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); }); - - // Thumbnail. - mThumbnail.setOrigin(0.5f, 0.5f); - mThumbnail.setPosition(2.0f, 2.0f); - mThumbnail.setVisible(false); - mThumbnail.setMaxSize(mSize.x * (0.25f - 2.0f * padding), mSize.y * 0.10f); - mThumbnail.setDefaultZIndex(25.0f); - addChild(&mThumbnail); - - // Marquee. - mMarquee.setOrigin(0.5f, 0.5f); - // Default to off the screen. - mMarquee.setPosition(2.0f, 2.0f); - mMarquee.setVisible(false); - mMarquee.setMaxSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.18f); - mMarquee.setDefaultZIndex(35.0f); - addChild(&mMarquee); - - // Image. - mImage.setOrigin(0.5f, 0.5f); - mImage.setPosition(mSize.x * 0.25f, mList.getPosition().y + mSize.y * 0.2125f); - mImage.setMaxSize(mSize.x * (0.50f - 2.0f * padding), mSize.y * 0.4f); - mImage.setDefaultZIndex(30.0f); - addChild(&mImage); - - if (mViewStyle == ViewController::VIDEO) { - // Video. - mVideo->setOrigin(0.5f, 0.5f); - mVideo->setPosition(mSize.x * 0.25f, mSize.y * 0.4f); - mVideo->setSize(mSize.x * (0.5f - 2.0f * padding), mSize.y * 0.4f); - mVideo->setDefaultZIndex(30.0f); - addChild(mVideo); - } - - // Metadata labels + values. - mLblRating.setText("Rating: ", false); - addChild(&mLblRating); - addChild(&mRating); - mLblReleaseDate.setText("Released: ", false); - addChild(&mLblReleaseDate); - addChild(&mReleaseDate); - mLblDeveloper.setText("Developer: ", false); - addChild(&mLblDeveloper); - addChild(&mDeveloper); - mLblPublisher.setText("Publisher: ", false); - addChild(&mLblPublisher); - addChild(&mPublisher); - mLblGenre.setText("Genre: ", false); - addChild(&mLblGenre); - addChild(&mGenre); - mLblPlayers.setText("Players: ", false); - addChild(&mLblPlayers); - addChild(&mPlayers); - mLblLastPlayed.setText("Last played: ", false); - addChild(&mLblLastPlayed); - mLastPlayed.setDisplayRelative(true); - addChild(&mLastPlayed); - mLblPlayCount.setText("Times played: ", false); - addChild(&mLblPlayCount); - addChild(&mPlayCount); - - // Badges. - addChild(&mBadges); - mBadges.setOrigin(0.5f, 0.5f); - mBadges.setPosition(mSize.x * 0.8f, mSize.y * 0.7f); - mBadges.setSize(mSize.x * 0.15f, mSize.y * 0.2f); - mBadges.setDefaultZIndex(50.0f); - - mName.setPosition(mSize.x, mSize.y); - mName.setDefaultZIndex(40.0f); - mName.setColor(0xAAAAAAFF); - mName.setFont(Font::get(FONT_SIZE_MEDIUM)); - mName.setHorizontalAlignment(ALIGN_CENTER); - addChild(&mName); - - mDescContainer.setPosition(mSize.x * padding, mSize.y * 0.65f); - mDescContainer.setSize(mSize.x * (0.50f - 2.0f * padding), - mSize.y - mDescContainer.getPosition().y); - mDescContainer.setAutoScroll(true); - mDescContainer.setDefaultZIndex(40.0f); - addChild(&mDescContainer); - - mDescription.setFont(Font::get(FONT_SIZE_SMALL)); - mDescription.setSize(mDescContainer.getSize().x, 0.0f); - mDescContainer.addChild(&mDescription); - - mGamelistInfo.setOrigin(0.5f, 0.5f); - mGamelistInfo.setFont(Font::get(FONT_SIZE_SMALL)); - mGamelistInfo.setDefaultZIndex(50.0f); - mGamelistInfo.setVisible(true); - addChild(&mGamelistInfo); - - initMDLabels(); - initMDValues(); } GamelistView::~GamelistView() @@ -156,9 +45,6 @@ GamelistView::~GamelistView() delete extra; } mThemeExtras.clear(); - - if (mViewStyle == ViewController::VIDEO && mVideo != nullptr) - delete mVideo; } void GamelistView::onFileChanged(FileData* file, bool reloadGamelist) @@ -190,15 +76,20 @@ void GamelistView::onShow() mLastUpdated = nullptr; GuiComponent::onShow(); - updateInfoPanel(); + if (mLegacyMode) + legacyUpdateInfoPanel(); + else + updateInfoPanel(); } void GamelistView::onThemeChanged(const std::shared_ptr& theme) { + if (mLegacyMode) { + legacyOnThemeChanged(theme); + return; + } + using namespace ThemeFlags; - mBackground.applyTheme(theme, getName(), "background", ALL); - mHeaderImage.applyTheme(theme, getName(), "logo", ALL); - mHeaderText.applyTheme(theme, getName(), "logoText", ALL); // Remove old theme extras. for (auto extra : mThemeExtras) { @@ -212,83 +103,18 @@ void GamelistView::onThemeChanged(const std::shared_ptr& theme) for (auto extra : mThemeExtras) addChild(extra); - if (mHeaderImage.hasImage()) { - removeChild(&mHeaderText); - addChild(&mHeaderImage); - } - else { - addChild(&mHeaderText); - removeChild(&mHeaderImage); - } - mList.applyTheme(theme, getName(), "gamelist", ALL); - mThumbnail.applyTheme(theme, getName(), "md_thumbnail", - 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); - - if (mViewStyle == ViewController::VIDEO) { - mVideo->applyTheme(theme, getName(), "md_video", - POSITION | ThemeFlags::SIZE | ThemeFlags::DELAY | Z_INDEX | ROTATION | - VISIBLE); - } - mName.applyTheme(theme, getName(), "md_name", ALL); - mBadges.applyTheme(theme, getName(), "md_badges", ALL); - - initMDLabels(); - std::vector labels {getMDLabels()}; - assert(labels.size() == 8); - std::vector lblElements = { - "md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher", - "md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"}; - - for (unsigned int i = 0; i < labels.size(); ++i) - labels[i]->applyTheme(theme, getName(), lblElements[i], ALL); - - initMDValues(); - std::vector values {getMDValues()}; - assert(values.size() == 8); - std::vector valElements = {"md_rating", "md_releasedate", "md_developer", - "md_publisher", "md_genre", "md_players", - "md_lastplayed", "md_playcount"}; - - for (unsigned int i = 0; i < values.size(); ++i) - values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT); - - mDescContainer.applyTheme(theme, getName(), "md_description", - POSITION | ThemeFlags::SIZE | Z_INDEX | VISIBLE); - mDescription.setSize(mDescContainer.getSize().x, 0.0f); - mDescription.applyTheme( - theme, getName(), "md_description", - ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION)); - - mGamelistInfo.applyTheme(theme, getName(), "gamelistInfo", ALL ^ ThemeFlags::TEXT); - // If there is no position defined in the theme for gamelistInfo, then hide it. - if (mGamelistInfo.getPosition() == glm::vec3 {}) - mGamelistInfo.setVisible(false); - else - mGamelistInfo.setVisible(true); + // TODO: Implement logic to populate component vectors. sortChildren(); } void GamelistView::update(int deltaTime) { - if (ViewController::getInstance()->getGameLaunchTriggered() && mImage.isAnimationPlaying(0)) - mImage.finishAnimation(0); - - if (mViewStyle == ViewController::VIDEO) { - if (!mVideoPlaying) - mVideo->onHide(); - else if (mVideoPlaying && !mVideo->isVideoPaused() && !mWindow->isScreensaverActive()) - mVideo->onShow(); - - if (ViewController::getInstance()->getGameLaunchTriggered() && - mVideo->isAnimationPlaying(0)) - mVideo->finishAnimation(0); + if (mLegacyMode) { + legacyUpdate(deltaTime); + return; } updateChildren(deltaTime); @@ -393,325 +219,5 @@ void GamelistView::updateInfoPanel() } } - // 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. - if (mList.isScrolling()) - if ((mLastUpdated && mLastUpdated->metadata.get("hidemetadata") == "true") || - (mLastUpdated->getSystem()->isCustomCollection() && - mLastUpdated->getPath() == mLastUpdated->getSystem()->getName())) - hideMetaDataFields = true; - - if (hideMetaDataFields || mViewStyle == ViewController::BASIC) { - mLblRating.setVisible(false); - mRating.setVisible(false); - mLblReleaseDate.setVisible(false); - mReleaseDate.setVisible(false); - mLblDeveloper.setVisible(false); - mDeveloper.setVisible(false); - mLblPublisher.setVisible(false); - mPublisher.setVisible(false); - mLblGenre.setVisible(false); - mGenre.setVisible(false); - mLblPlayers.setVisible(false); - mPlayers.setVisible(false); - mLblLastPlayed.setVisible(false); - mLastPlayed.setVisible(false); - mLblPlayCount.setVisible(false); - mPlayCount.setVisible(false); - mBadges.setVisible(false); - } - else { - mLblRating.setVisible(true); - mRating.setVisible(true); - mLblReleaseDate.setVisible(true); - mReleaseDate.setVisible(true); - mLblDeveloper.setVisible(true); - mDeveloper.setVisible(true); - mLblPublisher.setVisible(true); - mPublisher.setVisible(true); - mLblGenre.setVisible(true); - mGenre.setVisible(true); - mLblPlayers.setVisible(true); - mPlayers.setVisible(true); - mLblLastPlayed.setVisible(true); - mLastPlayed.setVisible(true); - mLblPlayCount.setVisible(true); - mPlayCount.setVisible(true); - mBadges.setVisible(true); - } - - bool fadingOut = false; - if (file == nullptr) { - 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) { - mThumbnail.setImage(mRandomGame->getThumbnailPath()); - mMarquee.setImage(mRandomGame->getMarqueePath(), false, true); - mImage.setImage(mRandomGame->getImagePath()); - if (mViewStyle == ViewController::VIDEO) { - mVideo->setImage(mRandomGame->getImagePath()); - // 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 video - // file) as the previously set video. That may happen when entering a folder - // with the same name as the first game file inside, or as in this case, when - // entering a custom collection. - mVideo->onHide(); - - if (!mVideo->setVideo(mRandomGame->getVideoPath())) - mVideo->setDefaultVideo(); - } - } - else { - mThumbnail.setImage(""); - mMarquee.setImage(""); - mImage.setImage(""); - if (mViewStyle == ViewController::VIDEO) { - mVideo->setImage(""); - mVideo->setVideo(""); - mVideo->setDefaultVideo(); - } - } - } - else { - mThumbnail.setImage(file->getThumbnailPath()); - mMarquee.setImage(file->getMarqueePath(), false, true); - mImage.setImage(file->getImagePath()); - if (mViewStyle == ViewController::VIDEO) { - mVideo->setImage(file->getImagePath()); - mVideo->onHide(); - - if (!mVideo->setVideo(file->getVideoPath())) - mVideo->setDefaultVideo(); - } - } - - 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. - std::string gamelistInfoString; - Alignment infoAlign = mGamelistInfo.getHorizontalAlignment(); - - if (mIsFolder && infoAlign == ALIGN_RIGHT) - gamelistInfoString = ViewController::FOLDER_CHAR + " "; - - if (mIsFiltered) { - if (mFilteredGameCountAll == mFilteredGameCount) - gamelistInfoString += ViewController::FILTER_CHAR + " " + - std::to_string(mFilteredGameCount) + " / " + - std::to_string(mGameCount); - else - gamelistInfoString += ViewController::FILTER_CHAR + " " + - std::to_string(mFilteredGameCount) + " + " + - std::to_string(mFilteredGameCountAll - mFilteredGameCount) + - " / " + std::to_string(mGameCount); - } - else { - gamelistInfoString += - ViewController::CONTROLLER_CHAR + " " + std::to_string(mGameCount); - if (!(file->getSystem()->isCollection() && - file->getSystem()->getFullName() == "favorites")) - gamelistInfoString += " " + ViewController::FAVORITE_CHAR + " " + - std::to_string(mFavoritesGameCount); - } - - if (mIsFolder && infoAlign != ALIGN_RIGHT) - gamelistInfoString += " " + ViewController::FOLDER_CHAR; - - mGamelistInfo.setValue(gamelistInfoString); - - if (mViewStyle == ViewController::DETAILED) { - // Fade in the game image. - auto func = [this](float t) { - mImage.setOpacity(static_cast( - glm::mix(static_cast(FADE_IN_START_OPACITY), 1.0f, t) * 255)); - }; - mImage.setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false); - } - else if (mViewStyle == ViewController::VIDEO) { - // Fade in the static image. - auto func = [this](float t) { - mVideo->setOpacity(static_cast( - glm::mix(static_cast(FADE_IN_START_OPACITY), 1.0f, t) * 255)); - }; - mVideo->setAnimation(new LambdaAnimation(func, FADE_IN_TIME), 0, nullptr, false); - } - - mDescription.setText(file->metadata.get("desc")); - mDescContainer.reset(); - - mRating.setValue(file->metadata.get("rating")); - mReleaseDate.setValue(file->metadata.get("releasedate")); - mDeveloper.setValue(file->metadata.get("developer")); - mPublisher.setValue(file->metadata.get("publisher")); - mGenre.setValue(file->metadata.get("genre")); - mPlayers.setValue(file->metadata.get("players")); - - // Populate the badge slots based on game metadata. - std::vector badgeSlots; - for (auto badge : mBadges.getBadgeTypes()) { - BadgeComponent::BadgeInfo badgeInfo; - badgeInfo.badgeType = badge; - if (badge == "controller") { - if (file->metadata.get("controller").compare("") != 0) { - badgeInfo.gameController = file->metadata.get("controller"); - badgeSlots.push_back(badgeInfo); - } - } - else if (badge == "altemulator") { - if (file->metadata.get(badge).compare("") != 0) - badgeSlots.push_back(badgeInfo); - } - else { - if (file->metadata.get(badge).compare("true") == 0) - badgeSlots.push_back(badgeInfo); - } - } - mBadges.setBadges(badgeSlots); - - mName.setValue(file->metadata.get("name")); - - if (file->getType() == GAME) { - if (!hideMetaDataFields) { - mLastPlayed.setValue(file->metadata.get("lastplayed")); - mPlayCount.setValue(file->metadata.get("playcount")); - } - } - else if (file->getType() == FOLDER) { - if (!hideMetaDataFields) { - mLastPlayed.setValue(file->metadata.get("lastplayed")); - mLblPlayCount.setVisible(false); - mPlayCount.setVisible(false); - } - } - - fadingOut = false; - } - - std::vector comps = getMDValues(); - comps.push_back(&mThumbnail); - comps.push_back(&mMarquee); - comps.push_back(&mImage); - comps.push_back(&mDescription); - comps.push_back(&mName); - comps.push_back(&mBadges); - std::vector labels = getMDLabels(); - comps.insert(comps.cend(), labels.cbegin(), labels.cend()); - - for (auto it = comps.cbegin(); it != comps.cend(); ++it) { - GuiComponent* comp = *it; - // An animation is playing, then animate if reverse != fadingOut. - // An animation is not playing, then animate if opacity != our target opacity. - if ((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) || - (!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255))) { - auto func = [comp](float t) { - comp->setOpacity(static_cast(glm::mix(0.0f, 1.0f, t) * 255)); - }; - comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut); - } - } -} - -void GamelistView::initMDLabels() -{ - std::vector components {getMDLabels()}; - - const unsigned int colCount {2}; - const unsigned int rowCount {static_cast(components.size() / 2)}; - - glm::vec3 start {mSize.x * 0.01f, mSize.y * 0.625f, 0.0f}; - - const float colSize {(mSize.x * 0.48f) / colCount}; - const float rowPadding {0.01f * mSize.y}; - - for (unsigned int i = 0; i < components.size(); ++i) { - const unsigned int row = i % rowCount; - glm::vec3 pos {}; - if (row == 0) { - pos = start + glm::vec3 {colSize * (i / rowCount), 0.0f, 0.0f}; - } - else { - // Work from the last component. - GuiComponent* lc {components[i - 1]}; - pos = lc->getPosition() + glm::vec3 {0.0f, lc->getSize().y + rowPadding, 0.0f}; - } - - components[i]->setFont(Font::get(FONT_SIZE_SMALL)); - components[i]->setPosition(pos); - components[i]->setDefaultZIndex(40.0f); - } -} - -void GamelistView::initMDValues() -{ - std::vector labels {getMDLabels()}; - std::vector values {getMDValues()}; - - std::shared_ptr defaultFont {Font::get(FONT_SIZE_SMALL)}; - mRating.setSize(defaultFont->getHeight() * 5.0f, static_cast(defaultFont->getHeight())); - mReleaseDate.setFont(defaultFont); - mDeveloper.setFont(defaultFont); - mPublisher.setFont(defaultFont); - mGenre.setFont(defaultFont); - mPlayers.setFont(defaultFont); - mLastPlayed.setFont(defaultFont); - mPlayCount.setFont(defaultFont); - - float bottom {0.0f}; - - const float colSize {(mSize.x * 0.48f) / 2.0f}; - for (unsigned int i = 0; i < labels.size(); ++i) { - const float heightDiff = (labels[i]->getSize().y - values[i]->getSize().y) / 2.0f; - values[i]->setPosition(labels[i]->getPosition() + - glm::vec3 {labels[i]->getSize().x, heightDiff, 0.0f}); - values[i]->setSize(colSize - labels[i]->getSize().x, values[i]->getSize().y); - values[i]->setDefaultZIndex(40.0f); - - float testBot = values[i]->getPosition().y + values[i]->getSize().y; - - if (testBot > bottom) - bottom = testBot; - } - - mDescContainer.setPosition(mDescContainer.getPosition().x, bottom + mSize.y * 0.01f); - mDescContainer.setSize(mDescContainer.getSize().x, mSize.y - mDescContainer.getPosition().y); -} - -std::vector GamelistView::getMDLabels() -{ - std::vector ret; - ret.push_back(&mLblRating); - ret.push_back(&mLblReleaseDate); - ret.push_back(&mLblDeveloper); - ret.push_back(&mLblPublisher); - ret.push_back(&mLblGenre); - ret.push_back(&mLblPlayers); - ret.push_back(&mLblLastPlayed); - ret.push_back(&mLblPlayCount); - return ret; -} - -std::vector GamelistView::getMDValues() -{ - std::vector ret; - ret.push_back(&mRating); - ret.push_back(&mReleaseDate); - ret.push_back(&mDeveloper); - ret.push_back(&mPublisher); - ret.push_back(&mGenre); - ret.push_back(&mPlayers); - ret.push_back(&mLastPlayed); - ret.push_back(&mPlayCount); - return ret; + // TODO: Implement gamelist logic. } diff --git a/es-app/src/views/GamelistView.h b/es-app/src/views/GamelistView.h index 13916eb8d..9a92343a3 100644 --- a/es-app/src/views/GamelistView.h +++ b/es-app/src/views/GamelistView.h @@ -17,7 +17,7 @@ class GamelistView : public GamelistBase { public: - GamelistView(FileData* root); + GamelistView(FileData* root, bool legacyMode = false); ~GamelistView(); // Called when a FileData* is added, has its metadata changed, or is removed. @@ -36,7 +36,6 @@ public: case ViewController::DETAILED: return "detailed"; case ViewController::BASIC: - return "basic"; default: return "basic"; } @@ -59,49 +58,61 @@ public: private: void updateInfoPanel(); - void initMDLabels(); - void initMDValues(); + // Legacy (backward compatibility) functions. + void legacyPopulateFields(); + void legacyOnThemeChanged(const std::shared_ptr& theme); + void legacyUpdateInfoPanel(); + void legacyUpdate(int deltaTime); + void legacyInitMDLabels(); + void legacyInitMDValues(); + bool mLegacyMode; ViewController::GamelistViewStyle mViewStyle; - std::vector getMDLabels(); - std::vector getMDValues(); - std::shared_ptr mTheme; std::vector mThemeExtras; - TextComponent mHeaderText; - ImageComponent mHeaderImage; - ImageComponent mBackground; + std::vector> mTextComponents; + std::vector> mDateTimeComponents; + std::vector> mImageComponents; + std::vector> mVideoComponents; + std::vector> mBadgeComponents; + std::vector> mRatingComponents; + std::vector> mScrollableContainerComponents; + std::vector> mGamelistInfoComponents; - ImageComponent mThumbnail; - ImageComponent mMarquee; - ImageComponent mImage; - VideoComponent* mVideo; + enum LegacyText { + LOGOTEXT = 0, + MD_LBL_RATING = 1, + MD_LBL_RELEASEDATE = 2, + MD_LBL_DEVELOPER = 3, + MD_LBL_PUBLISHER = 4, + MD_LBL_GENRE = 5, + MD_LBL_PLAYERS = 6, + MD_LBL_LASTPLAYED = 7, + MD_LBL_PLAYCOUNT = 8, + MD_DEVELOPER = 9, + MD_PUBLISHER = 10, + MD_GENRE = 11, + MD_PLAYERS = 12, + MD_PLAYCOUNT = 13, + MD_NAME = 14, + MD_DESCRIPTION = 15, + END + }; - TextComponent mLblRating; - TextComponent mLblReleaseDate; - TextComponent mLblDeveloper; - TextComponent mLblPublisher; - TextComponent mLblGenre; - TextComponent mLblPlayers; - TextComponent mLblLastPlayed; - TextComponent mLblPlayCount; + enum LegacyDateTime { + MD_RELEASEDATE = 0, // + MD_LASTPLAYED = 1 + }; - RatingComponent mRating; - DateTimeComponent mReleaseDate; - TextComponent mDeveloper; - TextComponent mPublisher; - TextComponent mGenre; - TextComponent mPlayers; - DateTimeComponent mLastPlayed; - TextComponent mPlayCount; - TextComponent mName; - BadgeComponent mBadges; - - ScrollableContainer mDescContainer; - TextComponent mDescription; - TextComponent mGamelistInfo; + enum LegacyImage { + LOGO = 0, // + BACKGROUND = 1, + MD_THUMBNAIL = 2, + MD_MARQUEE = 3, + MD_IMAGE = 4 + }; }; #endif // ES_APP_VIEWS_GAMELIST_VIEW_H