From 23770a19adea81df984787e428c47f9164f7e321 Mon Sep 17 00:00:00 2001 From: Andre Date: Sun, 15 Feb 2026 16:08:58 -0500 Subject: [PATCH] added a "type" attribute to the reloadableGlobalHiscores tag. Valid values are qr, table, both. This enables the QR code to be shown in isolation. When value is "qr", the QR code takes up the entire space allocated for the component. Also, exposed qrDelaySec qrFadeSec attribuates in the tag. These were coded (and defaulted) previously, but not exposed at the tag level. --- .../Component/ReloadableGlobalHiscores.cpp | 136 +++++++++++------- .../Component/ReloadableGlobalHiscores.h | 14 +- RetroFE/Source/Graphics/PageBuilder.cpp | 7 +- 3 files changed, 106 insertions(+), 51 deletions(-) diff --git a/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.cpp b/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.cpp index 15f201e9..967eaa8f 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.cpp +++ b/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.cpp @@ -39,7 +39,10 @@ ReloadableGlobalHiscores::ReloadableGlobalHiscores( int displayOffset, FontManager* font, float baseColumnPadding, - float baseRowPadding) + float baseRowPadding, + std::string renderType, + float qrDelaySec, + float qrFadeSec) : Component(p) , fontInst_(font) , textFormat_(std::move(textFormat)) @@ -81,7 +84,29 @@ ReloadableGlobalHiscores::ReloadableGlobalHiscores( , qrDelaySec_(2.0f) , qrFadeSec_(1.0f) , qrPlacement_(QrPlacement::TopLeft) - , qrMarginPx_(8) { + , qrMarginPx_(8) + , renderMode_(RenderMode::Both) + , renderTable_(true) + , renderQr_(true) { + + const std::string mode = Utils::toLower(Utils::trimEnds(renderType)); + if (mode == "qr") { + renderMode_ = RenderMode::QrOnly; + renderTable_ = false; + renderQr_ = true; + } + else if (mode == "table") { + renderMode_ = RenderMode::TableOnly; + renderTable_ = true; + renderQr_ = false; + } + + if (std::isfinite(qrDelaySec) && qrDelaySec >= 0.0f) { + qrDelaySec_ = qrDelaySec; + } + if (std::isfinite(qrFadeSec) && qrFadeSec >= 0.0f) { + qrFadeSec_ = qrFadeSec; + } } ReloadableGlobalHiscores::~ReloadableGlobalHiscores() { @@ -1167,59 +1192,62 @@ void ReloadableGlobalHiscores::reloadTexture() { return; } + std::vector qrTextures(Nvisible, nullptr); + std::vector> qrSizes(Nvisible, { 0,0 }); + // --- Resolve the list of QR IDs for the selected game --- - std::vector gameIds; - if (!selectedItem->iscoredId.empty()) { - Utils::listToVector(selectedItem->iscoredId, gameIds, ','); - } + if (renderQr_) { + std::vector gameIds; + if (!selectedItem->iscoredId.empty()) { + Utils::listToVector(selectedItem->iscoredId, gameIds, ','); + } - // Check QR cache validity by IDs - bool qrCacheValid = (cachedQrGameIds_.size() == gameIds.size()); - if (qrCacheValid) { - for (size_t i = 0; i < gameIds.size(); ++i) { - if (i >= cachedQrGameIds_.size() || cachedQrGameIds_[i] != gameIds[i]) { - qrCacheValid = false; break; + // Check QR cache validity by IDs + bool qrCacheValid = (cachedQrGameIds_.size() == gameIds.size()); + if (qrCacheValid) { + for (size_t i = 0; i < gameIds.size(); ++i) { + if (i >= cachedQrGameIds_.size() || cachedQrGameIds_[i] != gameIds[i]) { + qrCacheValid = false; break; + } } } - } - - // (Re)load QR textures only if IDs changed - if (!qrCacheValid) { - for (SDL_Texture* tex : cachedQrTextures_) if (tex) SDL_DestroyTexture(tex); - cachedQrTextures_.clear(); - cachedQrSizes_.clear(); - cachedQrGameIds_.clear(); - cachedQrTextures_.resize(gameIds.size(), nullptr); - cachedQrSizes_.resize(gameIds.size(), { 0,0 }); - - for (size_t i = 0; i < gameIds.size(); ++i) { - if (gameIds[i].empty()) continue; - const std::string path = Configuration::absolutePath + "/iScored/qr/" + gameIds[i] + ".png"; - if (SDL_Surface* surf = IMG_Load(path.c_str())) { - if (SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf)) { - SDL_SetTextureScaleMode(tex, SDL_ScaleModeNearest); - SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); // set once - cachedQrTextures_[i] = tex; - cachedQrSizes_[i] = { surf->w, surf->h }; + // (Re)load QR textures only if IDs changed + if (!qrCacheValid) { + for (SDL_Texture* tex : cachedQrTextures_) if (tex) SDL_DestroyTexture(tex); + cachedQrTextures_.clear(); + cachedQrSizes_.clear(); + cachedQrGameIds_.clear(); + + cachedQrTextures_.resize(gameIds.size(), nullptr); + cachedQrSizes_.resize(gameIds.size(), { 0,0 }); + + for (size_t i = 0; i < gameIds.size(); ++i) { + if (gameIds[i].empty()) continue; + const std::string path = Configuration::absolutePath + "/iScored/qr/" + gameIds[i] + ".png"; + if (SDL_Surface* surf = IMG_Load(path.c_str())) { + if (SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf)) { + SDL_SetTextureScaleMode(tex, SDL_ScaleModeNearest); + SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); // set once + cachedQrTextures_[i] = tex; + cachedQrSizes_[i] = { surf->w, surf->h }; + } + SDL_FreeSurface(surf); } - SDL_FreeSurface(surf); } - } - cachedQrGameIds_ = gameIds; - // IDs changed → sizes likely changed somewhere; mark all dirty - for (auto& L : cachedTableLayouts_) L.qrDstDirty = true; - } + cachedQrGameIds_ = gameIds; + // IDs changed → sizes likely changed somewhere; mark all dirty + for (auto& L : cachedTableLayouts_) L.qrDstDirty = true; + } - // Map cached QR textures/sizes to the visible range - std::vector qrTextures(Nvisible, nullptr); - std::vector> qrSizes(Nvisible, { 0,0 }); - for (int t = 0; t < Nvisible; ++t) { - const int gi = startIdx + t; - if (gi < (int)cachedQrTextures_.size()) { - qrTextures[t] = cachedQrTextures_[gi]; - qrSizes[t] = cachedQrSizes_[gi]; + // Map cached QR textures/sizes to the visible range + for (int t = 0; t < Nvisible; ++t) { + const int gi = startIdx + t; + if (gi < (int)cachedQrTextures_.size()) { + qrTextures[t] = cachedQrTextures_[gi]; + qrSizes[t] = cachedQrSizes_[gi]; + } } } @@ -1515,7 +1543,17 @@ void ReloadableGlobalHiscores::reloadTexture() { L.qrDstDirty = true; // size change → re-place } if (L.qrDstDirty) { - L.qrDst = placeQrInPanel(L.panelRect, L.qrSrcW, L.qrSrcH); + if (renderMode_ == RenderMode::QrOnly) { + L.qrDst = { + 0.0f, + 0.0f, + static_cast(compositeW), + static_cast(compositeH) + }; + } + else { + L.qrDst = placeQrInPanel(L.panelRect, L.qrSrcW, L.qrSrcH); + } L.qrDstDirty = false; } } @@ -1538,12 +1576,12 @@ void ReloadableGlobalHiscores::reloadTexture() { SDL_RenderClear(renderer); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); - if (tableTexture_) { + if (renderTable_ && tableTexture_) { SDL_RenderCopy(renderer, tableTexture_, nullptr, nullptr); } // Add QRs on top (if QR phase allows) - if (qrPhase_ == QrPhase::FadingIn || qrPhase_ == QrPhase::Visible) { + if (renderQr_ && (qrPhase_ == QrPhase::FadingIn || qrPhase_ == QrPhase::Visible)) { float qrAlphaF = 1.0f; if (qrPhase_ == QrPhase::FadingIn && qrFadeSec_ > 0.f) { qrAlphaF = std::clamp(qrT_ / qrFadeSec_, 0.f, 1.f); diff --git a/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.h b/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.h index 75a6dfc4..4f12d28a 100644 --- a/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.h +++ b/RetroFE/Source/Graphics/Component/ReloadableGlobalHiscores.h @@ -32,7 +32,10 @@ class ReloadableGlobalHiscores : public Component { ReloadableGlobalHiscores(Configuration& config, std::string textFormat, Page& p, int displayOffset, FontManager* font, - float baseColumnPadding, float baseRowPadding); + float baseColumnPadding, float baseRowPadding, + std::string renderType, + float qrDelaySec, + float qrFadeSec); ~ReloadableGlobalHiscores() override; bool update(float dt) override; @@ -72,6 +75,12 @@ class ReloadableGlobalHiscores : public Component { LeftMiddle }; + enum class RenderMode { + Both, + QrOnly, + TableOnly + }; + // Per-table layout cache struct struct TableLayout { @@ -202,6 +211,9 @@ class ReloadableGlobalHiscores : public Component { // --- QR configuration --- QrPlacement qrPlacement_; // where to place QR codes int qrMarginPx_; // margin between QR and panel + RenderMode renderMode_; // both/table-only/qr-only + bool renderTable_; + bool renderQr_; // Layout cache (populated in Stage 1, reused in Stage 2) std::vector cachedTableLayouts_; diff --git a/RetroFE/Source/Graphics/PageBuilder.cpp b/RetroFE/Source/Graphics/PageBuilder.cpp index 3065b26d..8199e584 100644 --- a/RetroFE/Source/Graphics/PageBuilder.cpp +++ b/RetroFE/Source/Graphics/PageBuilder.cpp @@ -775,6 +775,8 @@ void PageBuilder::loadReloadableImages(const xml_node<>* layout, const std::stri xml_attribute<> const* locationXml = componentXml->first_attribute("location"); xml_attribute<> const* baseColumnPaddingXml = componentXml->first_attribute("baseColumnPadding"); xml_attribute<> const* baseRowPaddingXml = componentXml->first_attribute("baseRowPadding"); + xml_attribute<> const* qrDelaySecXml = componentXml->first_attribute("qrDelaySec"); + xml_attribute<> const* qrFadeSecXml = componentXml->first_attribute("qrFadeSec"); xml_attribute<> const* maxRowsXml = componentXml->first_attribute("maxRows"); xml_attribute<> const* excludedColumnsXml = componentXml->first_attribute("excludedColumns"); @@ -878,12 +880,15 @@ void PageBuilder::loadReloadableImages(const xml_node<>* layout, const std::stri else if (tagName == "reloadableGlobalHiscores") { FontManager* font = addFont(componentXml, nullptr, cMonitor); std::string textFormat = textFormatXml ? textFormatXml->value() : ""; + std::string renderType = type ? type->value() : ""; float baseColumnPadding = baseColumnPaddingXml ? Utils::convertFloat(baseColumnPaddingXml->value()) : 1.5f; float baseRowPadding = baseRowPaddingXml ? Utils::convertFloat(baseRowPaddingXml->value()) : 0.5f; + float qrDelaySec = qrDelaySecXml ? Utils::convertFloat(qrDelaySecXml->value()) : 2.0f; + float qrFadeSec = qrFadeSecXml ? Utils::convertFloat(qrFadeSecXml->value()) : 1.0f; std::string excludedColumns = excludedColumnsXml ? excludedColumnsXml->value() : ""; c = new ReloadableGlobalHiscores(config_, textFormat, *page, selectedOffset, - font, baseColumnPadding, baseRowPadding); + font, baseColumnPadding, baseRowPadding, renderType, qrDelaySec, qrFadeSec); } else if (tagName == "musicPlayer") {