From ae52489b6bb1fe2fc8cb9b09191707009d056e1b Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sat, 17 Dec 2022 22:20:29 +0100 Subject: [PATCH] Added support for up to two imageType values for CarouselComponent and GridComponent. --- es-app/src/views/GamelistView.cpp | 65 +---------- .../components/primary/CarouselComponent.h | 103 ++++++++++++++---- .../src/components/primary/GridComponent.h | 101 +++++++++++++---- 3 files changed, 160 insertions(+), 109 deletions(-) diff --git a/es-app/src/views/GamelistView.cpp b/es-app/src/views/GamelistView.cpp index 3d58985bf..2e39acc6a 100644 --- a/es-app/src/views/GamelistView.cpp +++ b/es-app/src/views/GamelistView.cpp @@ -155,51 +155,11 @@ void GamelistView::onThemeChanged(const std::shared_ptr& theme) if (element.second.type == "carousel") { if (mCarousel == nullptr) { mCarousel = std::make_unique>(); - if (element.second.has("imageType")) { - const std::string imageType {element.second.get("imageType")}; - if (imageType == "marquee" || imageType == "cover" || - imageType == "backcover" || imageType == "3dbox" || - imageType == "physicalmedia" || imageType == "screenshot" || - imageType == "titlescreen" || imageType == "miximage" || - imageType == "fanart" || imageType == "none") { - mCarousel->setImageType(imageType); - } - else { - LOG(LogWarning) << "GamelistView::onThemeChanged(): Invalid theme " - "configuration, carousel property \"imageType\" " - "for element \"" - << element.first.substr(9) << "\" defined as \"" - << imageType << "\""; - mCarousel->setImageType("marquee"); - } - } - else if (element.second.has("itemType")) { - // TEMPORARY: Backward compatiblity due to property name changes. - const std::string itemType {element.second.get("itemType")}; - if (itemType == "marquee" || itemType == "cover" || - itemType == "backcover" || itemType == "3dbox" || - itemType == "physicalmedia" || itemType == "screenshot" || - itemType == "titlescreen" || itemType == "miximage" || - itemType == "fanart" || itemType == "none") { - mCarousel->setImageType(itemType); - } - else { - LOG(LogWarning) << "GamelistView::onThemeChanged(): Invalid theme " - "configuration, carousel property \"itemType\" " - "for element \"" - << element.first.substr(9) << "\" defined as \"" - << itemType << "\""; - mCarousel->setImageType("marquee"); - } - } - else { - mCarousel->setImageType("marquee"); - } + if (element.second.has("defaultImage")) + mCarousel->setDefaultImage(element.second.get("defaultImage")); // TEMPORARY: Backward compatiblity due to property name changes. if (element.second.has("defaultItem")) mCarousel->setDefaultImage(element.second.get("defaultItem")); - if (element.second.has("defaultImage")) - mCarousel->setDefaultImage(element.second.get("defaultImage")); mPrimary = mCarousel.get(); } mPrimary->setCursorChangedCallback( @@ -211,27 +171,6 @@ void GamelistView::onThemeChanged(const std::shared_ptr& theme) if (element.second.type == "grid") { if (mGrid == nullptr) { mGrid = std::make_unique>(); - if (element.second.has("imageType")) { - const std::string imageType {element.second.get("imageType")}; - if (imageType == "marquee" || imageType == "cover" || - imageType == "backcover" || imageType == "3dbox" || - imageType == "physicalmedia" || imageType == "screenshot" || - imageType == "titlescreen" || imageType == "miximage" || - imageType == "fanart" || imageType == "none") { - mGrid->setImageType(imageType); - } - else { - LOG(LogWarning) << "GamelistView::onThemeChanged(): Invalid theme " - "configuration, grid property \"imageType\" " - "for element \"" - << element.first.substr(5) << "\" defined as \"" - << imageType << "\""; - mGrid->setImageType("marquee"); - } - } - else { - mGrid->setImageType("marquee"); - } if (element.second.has("defaultImage")) mGrid->setDefaultImage(element.second.get("defaultImage")); mPrimary = mGrid.get(); diff --git a/es-core/src/components/primary/CarouselComponent.h b/es-core/src/components/primary/CarouselComponent.h index bfb2db7f2..18566bd1f 100644 --- a/es-core/src/components/primary/CarouselComponent.h +++ b/es-core/src/components/primary/CarouselComponent.h @@ -61,8 +61,6 @@ public: Entry& getEntry(int index) { return mEntries.at(index); } void onDemandTextureLoad() override; const CarouselType getType() { return mType; } - const std::string& getImageType() { return mImageType; } - void setImageType(std::string imageType) { mImageType = imageType; } const std::string& getDefaultImage() { return mDefaultImage; } void setDefaultImage(std::string defaultImage) { mDefaultImage = defaultImage; } bool isScrolling() const override { return List::isScrolling(); } @@ -132,7 +130,7 @@ private: bool mLegacyMode; CarouselType mType; - std::string mImageType; + std::vector mImageTypes; std::string mDefaultImage; float mMaxItemCount; int mItemsBeforeCenter; @@ -399,6 +397,9 @@ void CarouselComponent::updateEntry(Entry& entry, const std::shared_ptr void CarouselComponent::onDemandTextureLoad() { if constexpr (std::is_same_v) { + if (mImageTypes.empty()) + mImageTypes.emplace_back("marquee"); + const int numEntries {size()}; const int center {getCursor()}; const bool isWheel {mType == CarouselType::VERTICAL_WHEEL || @@ -463,26 +464,31 @@ template void CarouselComponent::onDemandTextureLoad() if (entry.data.imagePath == "") { FileData* game {entry.object}; - if (mImageType == "" || mImageType == "marquee") - entry.data.imagePath = game->getMarqueePath(); - else if (mImageType == "cover") - entry.data.imagePath = game->getCoverPath(); - else if (mImageType == "backcover") - entry.data.imagePath = game->getBackCoverPath(); - else if (mImageType == "3dbox") - entry.data.imagePath = game->get3DBoxPath(); - else if (mImageType == "physicalmedia") - entry.data.imagePath = game->getPhysicalMediaPath(); - else if (mImageType == "screenshot") - entry.data.imagePath = game->getScreenshotPath(); - else if (mImageType == "titlescreen") - entry.data.imagePath = game->getTitleScreenPath(); - else if (mImageType == "miximage") - entry.data.imagePath = game->getMiximagePath(); - else if (mImageType == "fanart") - entry.data.imagePath = game->getFanArtPath(); - else if (mImageType == "none") // Display the game name as text. - return; + for (auto& imageType : mImageTypes) { + if (imageType == "marquee") + entry.data.imagePath = game->getMarqueePath(); + else if (imageType == "cover") + entry.data.imagePath = game->getCoverPath(); + else if (imageType == "backcover") + entry.data.imagePath = game->getBackCoverPath(); + else if (imageType == "3dbox") + entry.data.imagePath = game->get3DBoxPath(); + else if (imageType == "physicalmedia") + entry.data.imagePath = game->getPhysicalMediaPath(); + else if (imageType == "screenshot") + entry.data.imagePath = game->getScreenshotPath(); + else if (imageType == "titlescreen") + entry.data.imagePath = game->getTitleScreenPath(); + else if (imageType == "miximage") + entry.data.imagePath = game->getMiximagePath(); + else if (imageType == "fanart") + entry.data.imagePath = game->getFanArtPath(); + else if (imageType == "none") // Display the game name as text. + break; + + if (entry.data.imagePath != "") + break; + } if (entry.data.imagePath == "") entry.data.imagePath = entry.data.defaultImagePath; @@ -1033,6 +1039,57 @@ void CarouselComponent::applyTheme(const std::shared_ptr& theme, } } + // TEMPORARY: Support for itemType is for backward compatiblity due to property name changes. + if (mGamelistView && properties && (elem->has("imageType") || elem->has("itemType"))) { + const std::vector supportedImageTypes { + "marquee", "cover", "backcover", "3dbox", "physicalmedia", + "screenshot", "titlescreen", "miximage", "fanart", "none"}; + std::string imageTypesString; + + if (elem->has("imageType")) + imageTypesString = elem->get("imageType"); + else + imageTypesString = elem->get("itemType"); + + for (auto& character : imageTypesString) { + if (std::isspace(character)) + character = ','; + } + imageTypesString = Utils::String::replace(imageTypesString, ",,", ","); + mImageTypes = Utils::String::delimitedStringToVector(imageTypesString, ","); + + // Only allow two imageType entries due to performance reasons. + if (mImageTypes.size() > 2) + mImageTypes.erase(mImageTypes.begin() + 2, mImageTypes.end()); + + if (mImageTypes.empty()) { + LOG(LogWarning) + << "CarouselComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(9) << "\" contains no values"; + } + + for (std::string& type : mImageTypes) { + if (std::find(supportedImageTypes.cbegin(), supportedImageTypes.cend(), type) == + supportedImageTypes.cend()) { + LOG(LogWarning) + << "CarouselComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(9) << "\" defined as \"" << type << "\""; + mImageTypes.clear(); + break; + } + } + + if (mImageTypes.size() == 2 && mImageTypes.front() == mImageTypes.back()) { + LOG(LogError) + << "CarouselComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(9) << "\" contains duplicate values"; + mImageTypes.clear(); + } + } + if (elem->has("color")) { mCarouselColor = elem->get("color"); mCarouselColorEnd = mCarouselColor; diff --git a/es-core/src/components/primary/GridComponent.h b/es-core/src/components/primary/GridComponent.h index 0ee7b24df..0f2b483c9 100644 --- a/es-core/src/components/primary/GridComponent.h +++ b/es-core/src/components/primary/GridComponent.h @@ -63,8 +63,6 @@ public: { return mLetterCaseGroupedCollections; } - const std::string& getImageType() { return mImageType; } - void setImageType(std::string imageType) { mImageType = imageType; } const std::string& getDefaultImage() { return mDefaultImage; } void setDefaultImage(std::string defaultImage) { mDefaultImage = defaultImage; } bool input(InputConfig* config, Input input) override; @@ -134,7 +132,7 @@ private: float mHorizontalMargin; float mVerticalMargin; - std::string mImageType; + std::vector mImageTypes; std::string mDefaultImage; glm::vec2 mItemSize; float mItemScale; @@ -365,6 +363,9 @@ void GridComponent::updateEntry(Entry& entry, const std::shared_ptr void GridComponent::onDemandTextureLoad() { if constexpr (std::is_same_v) { + if (mImageTypes.empty()) + mImageTypes.emplace_back("marquee"); + const int visibleRows {static_cast(std::ceil(mVisibleRows))}; const int columnPos {mCursor % mColumns}; int loadItems {mColumns * visibleRows}; @@ -404,26 +405,31 @@ template void GridComponent::onDemandTextureLoad() if (entry.data.imagePath == "") { FileData* game {entry.object}; - if (mImageType == "" || mImageType == "marquee") - entry.data.imagePath = game->getMarqueePath(); - else if (mImageType == "cover") - entry.data.imagePath = game->getCoverPath(); - else if (mImageType == "backcover") - entry.data.imagePath = game->getBackCoverPath(); - else if (mImageType == "3dbox") - entry.data.imagePath = game->get3DBoxPath(); - else if (mImageType == "physicalmedia") - entry.data.imagePath = game->getPhysicalMediaPath(); - else if (mImageType == "screenshot") - entry.data.imagePath = game->getScreenshotPath(); - else if (mImageType == "titlescreen") - entry.data.imagePath = game->getTitleScreenPath(); - else if (mImageType == "miximage") - entry.data.imagePath = game->getMiximagePath(); - else if (mImageType == "fanart") - entry.data.imagePath = game->getFanArtPath(); - else if (mImageType == "none") // Display the game name as text. - return; + for (auto& imageType : mImageTypes) { + if (imageType == "marquee") + entry.data.imagePath = game->getMarqueePath(); + else if (imageType == "cover") + entry.data.imagePath = game->getCoverPath(); + else if (imageType == "backcover") + entry.data.imagePath = game->getBackCoverPath(); + else if (imageType == "3dbox") + entry.data.imagePath = game->get3DBoxPath(); + else if (imageType == "physicalmedia") + entry.data.imagePath = game->getPhysicalMediaPath(); + else if (imageType == "screenshot") + entry.data.imagePath = game->getScreenshotPath(); + else if (imageType == "titlescreen") + entry.data.imagePath = game->getTitleScreenPath(); + else if (imageType == "miximage") + entry.data.imagePath = game->getMiximagePath(); + else if (imageType == "fanart") + entry.data.imagePath = game->getFanArtPath(); + else if (imageType == "none") // Display the game name as text. + break; + + if (entry.data.imagePath != "") + break; + } if (entry.data.imagePath == "") entry.data.imagePath = entry.data.defaultImagePath; @@ -778,6 +784,55 @@ void GridComponent::applyTheme(const std::shared_ptr& theme, if (!elem) return; + // TEMPORARY: Support for itemType is for backward compatiblity due to property name changes. + if (mGamelistView && properties && (elem->has("imageType") || elem->has("itemType"))) { + const std::vector supportedImageTypes { + "marquee", "cover", "backcover", "3dbox", "physicalmedia", + "screenshot", "titlescreen", "miximage", "fanart", "none"}; + std::string imageTypesString; + + if (elem->has("imageType")) + imageTypesString = elem->get("imageType"); + else + imageTypesString = elem->get("itemType"); + + for (auto& character : imageTypesString) { + if (std::isspace(character)) + character = ','; + } + imageTypesString = Utils::String::replace(imageTypesString, ",,", ","); + mImageTypes = Utils::String::delimitedStringToVector(imageTypesString, ","); + + // Only allow two imageType entries due to performance reasons. + if (mImageTypes.size() > 2) + mImageTypes.erase(mImageTypes.begin() + 2, mImageTypes.end()); + + if (mImageTypes.empty()) { + LOG(LogWarning) << "GridComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(5) << "\" contains no values"; + } + + for (std::string& type : mImageTypes) { + if (std::find(supportedImageTypes.cbegin(), supportedImageTypes.cend(), type) == + supportedImageTypes.cend()) { + LOG(LogWarning) + << "GridComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(5) << "\" defined as \"" << type << "\""; + mImageTypes.clear(); + break; + } + } + + if (mImageTypes.size() == 2 && mImageTypes.front() == mImageTypes.back()) { + LOG(LogError) << "GridComponent: Invalid theme configuration, property \"imageType\" " + "for element \"" + << element.substr(5) << "\" contains duplicate values"; + mImageTypes.clear(); + } + } + mFractionalRows = (elem->has("fractionalRows") && elem->get("fractionalRows")); if (elem->has("itemSize")) {