From 6ba08fbcb9eacfaea5e0438a3240d3df0c734709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Aug 2023 16:32:39 +0200 Subject: [PATCH] Allow using atlas icons other than the presets in OSD messages. --- Common/StringUtils.h | 8 ++++++ UI/DevScreens.cpp | 5 ++++ UI/OnScreenDisplay.cpp | 56 ++++++++++++++++++++++++++---------------- 3 files changed, 48 insertions(+), 21 deletions(-) diff --git a/Common/StringUtils.h b/Common/StringUtils.h index 945a37de94..c7cd21cc26 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -35,6 +35,14 @@ std::string IndentString(const std::string &str, const std::string &sep, bool sk // Other simple string utilities. +// Optimized for string constants. +inline bool startsWith(const std::string &str, const char *key) { + size_t keyLen = strlen(key); + if (str.size() < keyLen) + return false; + return !memcmp(str.data(), key, keyLen); +} + inline bool startsWith(const std::string &str, const std::string &what) { if (str.size() < what.size()) return false; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 10d1e3ea19..ee9a39f8ab 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -492,6 +492,7 @@ void SystemInfoScreen::CreateTabs() { auto di = GetI18NCategory(I18NCat::DIALOG); auto si = GetI18NCategory(I18NCat::SYSINFO); + auto sy = GetI18NCategory(I18NCat::SYSTEM); auto gr = GetI18NCategory(I18NCat::GRAPHICS); TabHolder *tabHolder = new TabHolder(ORIENT_VERTICAL, 225, new AnchorLayoutParams(10, 0, 10, 0, false)); @@ -875,6 +876,10 @@ void SystemInfoScreen::CreateTabs() { g_OSD.Show(OSDType::MESSAGE_SUCCESS, "Success"); return UI::EVENT_DONE; }); + internals->Add(new Choice(sy->T("RetroAchievements")))->OnClick.Add([&](UI::EventParams &) { + g_OSD.Show(OSDType::MESSAGE_WARNING, "RetroAchievements warning", "", "I_RETROACHIEVEMENTS_LOGO"); + return UI::EVENT_DONE; + }); internals->Add(new ItemHeader(si->T("Progress tests"))); internals->Add(new Choice(si->T("30%")))->OnClick.Add([&](UI::EventParams &) { g_OSD.SetProgressBar("testprogress", "Test Progress", 1, 100, 30, 0.0f); diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 0302515a3c..2258ba6cc4 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -71,22 +71,27 @@ static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::str *height += 5.0f + height2; } - float iconSize = 0.0f; - - if (!iconName.empty()) { + float iconW = 0.0f; + float iconH = 0.0f; + if (!iconName.empty() && !startsWith(iconName, "I_")) { // Check for atlas image. Bit hacky, but we choose prefixes for icon IDs anyway in a way that this is safe. // Normal entry but with a cached icon. int iconWidth, iconHeight; if (g_iconCache.GetDimensions(iconName, &iconWidth, &iconHeight)) { *width += 5.0f + iconWidth; - iconSize = iconWidth + 5.0f; + iconW = iconWidth; + iconH = iconHeight; + } + } else { + ImageID iconID = iconName.empty() ? GetOSDIcon(level) : ImageID(iconName.c_str()); + if (iconID.isValid()) { + dc.Draw()->GetAtlas()->measureImage(iconID, &iconW, &iconH); } - } else if (!GetOSDIcon(level).isInvalid()) { - // Atlas icon. - iconSize = g_atlasIconSize + 5.0f; } - *width += iconSize + 12.0f; - *height = std::max(*height, iconSize + 5.0f); + iconW += 5.0f; + + *width += iconW + 12.0f; + *height = std::max(*height, iconH + 5.0f); } // Align only matters here for the ASCII-only flag. @@ -109,29 +114,38 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha); dc.FillRect(background, bounds); - ImageID iconID = GetOSDIcon(level); - - float iconSize = 0.0f; - if (!iconName.empty()) { + float iconW = 0.0f; + float iconH = 0.0f; + if (!iconName.empty() && !startsWith(iconName, "I_")) { dc.Flush(); // Normal entry but with a cached icon. Draw::Texture *texture = g_iconCache.BindIconTexture(&dc, iconName); if (texture) { - iconSize = texture->Width(); - dc.Draw()->DrawTexRect(Bounds(bounds.x + 2.5f, bounds.y + 2.5f, iconSize, iconSize), 0.0f, 0.0f, 1.0f, 1.0f, foreGround); + iconW = texture->Width(); + iconH = texture->Height(); + dc.Draw()->DrawTexRect(Bounds(bounds.x + 2.5f, bounds.y + 2.5f, iconW, iconH), 0.0f, 0.0f, 1.0f, 1.0f, foreGround); dc.Flush(); dc.RebindTexture(); } dc.Begin(); - } else if (iconID.isValid()) { - // Atlas icon. - dc.DrawImageVGradient(iconID, foreGround, foreGround, Bounds(bounds.x + 2.5f, bounds.y + 2.5f, g_atlasIconSize, g_atlasIconSize)); - iconSize = g_atlasIconSize; + } else { + ImageID iconID = iconName.empty() ? GetOSDIcon(level) : ImageID(iconName.c_str()); + if (iconID.isValid()) { + // Atlas icon. + dc.Draw()->GetAtlas()->measureImage(iconID, &iconW, &iconH); + Bounds iconBounds = Bounds(bounds.x + 2.5f, bounds.y + 2.5f, iconW, iconH); + if (!iconName.empty()) { + // If it's not a preset OSD icon, give it some background to blend in. The RA icon for example + // easily melts into the orange of warnings otherwise. + dc.FillRect(UI::Drawable(0x50000000), iconBounds.Expand(2.0f)); + } + dc.DrawImageVGradient(iconID, foreGround, foreGround, Bounds(bounds.x + 2.5f, bounds.y + 2.5f, iconW, iconH)); + } } // Make room - bounds.x += iconSize + 5.0f; - bounds.w -= iconSize + 5.0f; + bounds.x += iconW + 5.0f; + bounds.w -= iconW + 5.0f; dc.DrawTextShadowRect(text.c_str(), bounds.Inset(0.0f, 1.0f, 0.0f, 0.0f), foreGround, (align & FLAG_DYNAMIC_ASCII));