Added a new gameOverridePath property to the image element to enable per-game static image overrides

Also fixed an issue where the default image element property could be used even if no imageType entries were defined
This commit is contained in:
Leon Styhre 2023-04-10 20:16:19 +02:00
parent 5030d45525
commit 1697508393
5 changed files with 97 additions and 49 deletions

View file

@ -670,9 +670,8 @@ void GamelistView::updateView(const CursorState& state)
} }
} }
else { else {
for (auto& image : mImageComponents) { for (auto& image : mImageComponents)
setGameImage(file, image.get()); setGameImage(file, image.get());
}
for (auto& video : mVideoComponents) { for (auto& video : mVideoComponents) {
setGameImage(file, video.get()); setGameImage(file, video.get());
@ -1018,74 +1017,79 @@ void GamelistView::setGameImage(FileData* file, GuiComponent* comp)
path = file->getImagePath(); path = file->getImagePath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "miximage") { else if (imageType == "miximage") {
path = file->getMiximagePath(); path = file->getMiximagePath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "marquee") { else if (imageType == "marquee") {
path = file->getMarqueePath(); path = file->getMarqueePath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "screenshot") { else if (imageType == "screenshot") {
path = file->getScreenshotPath(); path = file->getScreenshotPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "titlescreen") { else if (imageType == "titlescreen") {
path = file->getTitleScreenPath(); path = file->getTitleScreenPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "cover") { else if (imageType == "cover") {
path = file->getCoverPath(); path = file->getCoverPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "backcover") { else if (imageType == "backcover") {
path = file->getBackCoverPath(); path = file->getBackCoverPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "3dbox") { else if (imageType == "3dbox") {
path = file->get3DBoxPath(); path = file->get3DBoxPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "physicalmedia") { else if (imageType == "physicalmedia") {
path = file->getPhysicalMediaPath(); path = file->getPhysicalMediaPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
else if (imageType == "fanart") { else if (imageType == "fanart") {
path = file->getFanArtPath(); path = file->getFanArtPath();
if (path != "") { if (path != "") {
comp->setImage(path); comp->setImage(path);
break; return;
} }
} }
} }
// This is needed so the default image is set if no game media was found. // This is needed so the default image is set if no game media was found.
if (path == "" && (comp->getThemeImageTypes().size() > 0 || comp->getDefaultImage() != "")) if (path == "" && (comp->getThemeImageTypes().size() > 0 || comp->getDefaultImage() != "")) {
comp->setImage(""); comp->setImage("");
return;
}
// Sets per-game overrides of static images using the game file basename.
comp->setGameOverrideImage(Utils::FileSystem::getStem(file->getPath()), file->getSystemName());
} }

View file

@ -279,6 +279,7 @@ public:
const std::string& getThemeGameSelector() const { return mThemeGameSelector; } const std::string& getThemeGameSelector() const { return mThemeGameSelector; }
const unsigned int getThemeGameSelectorEntry() const { return mThemeGameSelectorEntry; } const unsigned int getThemeGameSelectorEntry() const { return mThemeGameSelectorEntry; }
virtual const std::string getDefaultImage() const { return ""; } virtual const std::string getDefaultImage() const { return ""; }
virtual void setGameOverrideImage(const std::string& basename, const std::string& system) {}
const float getThemeOpacity() const { return mThemeOpacity; } const float getThemeOpacity() const { return mThemeOpacity; }
virtual std::shared_ptr<Font> getFont() const { return nullptr; } virtual std::shared_ptr<Font> getFont() const { return nullptr; }

View file

@ -299,6 +299,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
{"flipHorizontal", BOOLEAN}, {"flipHorizontal", BOOLEAN},
{"flipVertical", BOOLEAN}, {"flipVertical", BOOLEAN},
{"path", PATH}, {"path", PATH},
{"gameOverridePath", PATH},
{"default", PATH}, {"default", PATH},
{"imageType", STRING}, {"imageType", STRING},
{"metadataElement", BOOLEAN}, {"metadataElement", BOOLEAN},

View file

@ -128,6 +128,25 @@ void ImageComponent::setImage(const std::shared_ptr<TextureResource>& texture, b
resize(); resize();
} }
void ImageComponent::setGameOverrideImage(const std::string& basename, const std::string& system)
{
if (mGameOverridePath == "")
return;
if (!Utils::FileSystem::exists(mGameOverridePath + system))
return;
const std::string imageFilePath {mGameOverridePath + system + "/" + basename};
for (auto& extension : sSupportedOverrideExtensions) {
if (Utils::FileSystem::exists(imageFilePath + extension)) {
setImage(imageFilePath + extension);
return;
}
}
setImage(mGameOverrideOriginalPath);
}
void ImageComponent::setResize(const float width, const float height) void ImageComponent::setResize(const float width, const float height)
{ {
mTargetSize = glm::vec2 {width, height}; mTargetSize = glm::vec2 {width, height};
@ -494,7 +513,45 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
} }
} }
if (elem->has("default")) if (properties && elem->has("imageType")) {
std::string imageTypes {elem->get<std::string>("imageType")};
for (auto& character : imageTypes) {
if (std::isspace(character))
character = ',';
}
imageTypes = Utils::String::replace(imageTypes, ",,", ",");
mThemeImageTypes = Utils::String::delimitedStringToVector(imageTypes, ",");
if (mThemeImageTypes.empty()) {
LOG(LogError) << "ImageComponent: Invalid theme configuration, property \"imageType\" "
"for element \""
<< element.substr(6) << "\" contains no values";
}
for (std::string& type : mThemeImageTypes) {
if (std::find(sSupportedImageTypes.cbegin(), sSupportedImageTypes.cend(), type) ==
sSupportedImageTypes.cend()) {
LOG(LogError)
<< "ImageComponent: Invalid theme configuration, property \"imageType\" "
"for element \""
<< element.substr(6) << "\" defined as \"" << type << "\"";
mThemeImageTypes.clear();
break;
}
}
std::vector<std::string> sortedTypes {mThemeImageTypes};
std::stable_sort(sortedTypes.begin(), sortedTypes.end());
if (std::adjacent_find(sortedTypes.begin(), sortedTypes.end()) != sortedTypes.end()) {
LOG(LogError) << "ImageComponent: Invalid theme configuration, property \"imageType\" "
"for element \""
<< element.substr(6) << "\" contains duplicate values";
mThemeImageTypes.clear();
}
}
if (!mThemeImageTypes.empty() && elem->has("default"))
setDefaultImage(elem->get<std::string>("default")); setDefaultImage(elem->get<std::string>("default"));
bool tile {elem->has("tile") && elem->get<bool>("tile")}; bool tile {elem->has("tile") && elem->get<bool>("tile")};
@ -567,42 +624,20 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (tile && updateAlignment) if (tile && updateAlignment)
updateVertices(); updateVertices();
if (properties && elem->has("imageType")) { // Per-game overrides of static images using the game file's basename. It's by design not
std::string imageTypes {elem->get<std::string>("imageType")}; // possible to override scraped media.
for (auto& character : imageTypes) { if (mThemeImageTypes.empty() && elem->has("gameOverridePath")) {
if (std::isspace(character)) mGameOverridePath = elem->get<std::string>("gameOverridePath");
character = ','; #if defined(_WIN64)
} mBasenamePath = Utils::String::replace(mGameOverridePath, "\\", "/");
imageTypes = Utils::String::replace(imageTypes, ",,", ","); #endif
mThemeImageTypes = Utils::String::delimitedStringToVector(imageTypes, ","); if (mGameOverridePath.back() != '/')
mGameOverridePath.push_back('/');
if (mThemeImageTypes.empty()) { if (elem->has("path"))
LOG(LogError) << "ImageComponent: Invalid theme configuration, property \"imageType\" " mGameOverrideOriginalPath = elem->get<std::string>("path");
"for element \"" else
<< element.substr(6) << "\" contains no values"; mGameOverrideOriginalPath = "";
}
for (std::string& type : mThemeImageTypes) {
if (std::find(sSupportedImageTypes.cbegin(), sSupportedImageTypes.cend(), type) ==
sSupportedImageTypes.cend()) {
LOG(LogError)
<< "ImageComponent: Invalid theme configuration, property \"imageType\" "
"for element \""
<< element.substr(6) << "\" defined as \"" << type << "\"";
mThemeImageTypes.clear();
break;
}
}
std::vector<std::string> sortedTypes {mThemeImageTypes};
std::stable_sort(sortedTypes.begin(), sortedTypes.end());
if (std::adjacent_find(sortedTypes.begin(), sortedTypes.end()) != sortedTypes.end()) {
LOG(LogError) << "ImageComponent: Invalid theme configuration, property \"imageType\" "
"for element \""
<< element.substr(6) << "\" contains duplicate values";
mThemeImageTypes.clear();
}
} }
if (elem->has("metadataElement") && elem->get<bool>("metadataElement")) if (elem->has("metadataElement") && elem->get<bool>("metadataElement"))

View file

@ -30,6 +30,9 @@ public:
// Use an already existing texture. // Use an already existing texture.
void setImage(const std::shared_ptr<TextureResource>& texture, bool resizeTexture = true); void setImage(const std::shared_ptr<TextureResource>& texture, bool resizeTexture = true);
// Sets per-game overrides of static images using the game file basename.
void setGameOverrideImage(const std::string& basename, const std::string& system) override;
void setDynamic(bool state) { mDynamic = state; } void setDynamic(bool state) { mDynamic = state; }
void onSizeChanged() override { updateVertices(); } void onSizeChanged() override { updateVertices(); }
@ -143,7 +146,11 @@ private:
bool mColorGradientHorizontal; bool mColorGradientHorizontal;
std::string mDefaultPath; std::string mDefaultPath;
std::string mGameOverridePath;
std::string mGameOverrideOriginalPath;
static inline std::vector<std::string> sSupportedOverrideExtensions {".jpg", ".png", ".gif",
".svg"};
static inline std::vector<std::string> sSupportedImageTypes { static inline std::vector<std::string> sSupportedImageTypes {
"image", "miximage", "marquee", "screenshot", "titlescreen", "image", "miximage", "marquee", "screenshot", "titlescreen",
"cover", "backcover", "3dbox", "physicalmedia", "fanart"}; "cover", "backcover", "3dbox", "physicalmedia", "fanart"};