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 {
for (auto& image : mImageComponents) {
for (auto& image : mImageComponents)
setGameImage(file, image.get());
}
for (auto& video : mVideoComponents) {
setGameImage(file, video.get());
@ -1018,74 +1017,79 @@ void GamelistView::setGameImage(FileData* file, GuiComponent* comp)
path = file->getImagePath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "miximage") {
path = file->getMiximagePath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "marquee") {
path = file->getMarqueePath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "screenshot") {
path = file->getScreenshotPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "titlescreen") {
path = file->getTitleScreenPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "cover") {
path = file->getCoverPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "backcover") {
path = file->getBackCoverPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "3dbox") {
path = file->get3DBoxPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "physicalmedia") {
path = file->getPhysicalMediaPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
else if (imageType == "fanart") {
path = file->getFanArtPath();
if (path != "") {
comp->setImage(path);
break;
return;
}
}
}
// 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("");
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 unsigned int getThemeGameSelectorEntry() const { return mThemeGameSelectorEntry; }
virtual const std::string getDefaultImage() const { return ""; }
virtual void setGameOverrideImage(const std::string& basename, const std::string& system) {}
const float getThemeOpacity() const { return mThemeOpacity; }
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},
{"flipVertical", BOOLEAN},
{"path", PATH},
{"gameOverridePath", PATH},
{"default", PATH},
{"imageType", STRING},
{"metadataElement", BOOLEAN},

View file

@ -128,6 +128,25 @@ void ImageComponent::setImage(const std::shared_ptr<TextureResource>& texture, b
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)
{
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"));
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)
updateVertices();
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, ",");
// Per-game overrides of static images using the game file's basename. It's by design not
// possible to override scraped media.
if (mThemeImageTypes.empty() && elem->has("gameOverridePath")) {
mGameOverridePath = elem->get<std::string>("gameOverridePath");
#if defined(_WIN64)
mBasenamePath = Utils::String::replace(mGameOverridePath, "\\", "/");
#endif
if (mGameOverridePath.back() != '/')
mGameOverridePath.push_back('/');
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 (elem->has("path"))
mGameOverrideOriginalPath = elem->get<std::string>("path");
else
mGameOverrideOriginalPath = "";
}
if (elem->has("metadataElement") && elem->get<bool>("metadataElement"))

View file

@ -30,6 +30,9 @@ public:
// Use an already existing texture.
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 onSizeChanged() override { updateVertices(); }
@ -143,7 +146,11 @@ private:
bool mColorGradientHorizontal;
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 {
"image", "miximage", "marquee", "screenshot", "titlescreen",
"cover", "backcover", "3dbox", "physicalmedia", "fanart"};