From 48d577014ae2af09ba044a546276de9d26ba2428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 31 Jul 2023 23:13:52 +0200 Subject: [PATCH] Refactor the on-screen display to be more customizable --- Common/System/OSD.cpp | 73 +++------ Common/System/OSD.h | 30 ++-- Core/Config.cpp | 1 + Core/Config.h | 11 -- UI/DevScreens.cpp | 5 + UI/DevScreens.h | 2 + UI/EmuScreen.cpp | 2 +- UI/OnScreenDisplay.cpp | 290 ++++++++++++++++++++------------- UI/RetroAchievementScreens.cpp | 2 +- 9 files changed, 226 insertions(+), 190 deletions(-) diff --git a/Common/System/OSD.cpp b/Common/System/OSD.cpp index e8cf697b27..3eaddce71d 100644 --- a/Common/System/OSD.cpp +++ b/Common/System/OSD.cpp @@ -21,22 +21,6 @@ void OnScreenDisplay::Update() { iter++; } } - - for (auto iter = sideEntries_.begin(); iter != sideEntries_.end(); ) { - if (now >= iter->endTime) { - iter = sideEntries_.erase(iter); - } else { - iter++; - } - } - - for (auto iter = bars_.begin(); iter != bars_.end(); ) { - if (now >= iter->endTime) { - iter = bars_.erase(iter); - } else { - iter++; - } - } } std::vector OnScreenDisplay::Entries() { @@ -44,16 +28,6 @@ std::vector OnScreenDisplay::Entries() { return entries_; // makes a copy. } -std::vector OnScreenDisplay::SideEntries() { - std::lock_guard guard(mutex_); - return sideEntries_; // makes a copy. -} - -std::vector OnScreenDisplay::ProgressBars() { - std::lock_guard guard(mutex_); - return bars_; // makes a copy. -} - void OnScreenDisplay::NudgeSidebar() { sideBarShowTime_ = time_now_d(); } @@ -89,7 +63,7 @@ void OnScreenDisplay::Show(OSDType type, const std::string &text, const std::str std::lock_guard guard(mutex_); if (id) { for (auto iter = entries_.begin(); iter != entries_.end(); ++iter) { - if (iter->id && !strcmp(iter->id, id)) { + if (iter->id == id) { Entry msg = *iter; msg.endTime = now + duration_s; msg.text = text; @@ -111,7 +85,9 @@ void OnScreenDisplay::Show(OSDType type, const std::string &text, const std::str msg.startTime = now; msg.endTime = now + duration_s; msg.type = type; - msg.id = id; + if (id) { + msg.id = id; + } entries_.insert(entries_.begin(), msg); } @@ -132,7 +108,7 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) { double now = time_now_d(); // There can only be one of these at a time. - for (auto &entry : sideEntries_) { + for (auto &entry : entries_) { if (entry.type == OSDType::ACHIEVEMENT_PROGRESS) { if (!show) { // Hide and eventually delete it. @@ -158,13 +134,13 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) { entry.type = OSDType::ACHIEVEMENT_PROGRESS; entry.startTime = now; entry.endTime = now + forever_s; - sideEntries_.insert(sideEntries_.begin(), entry); + entries_.insert(entries_.begin(), entry); } void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) { double now = time_now_d(); - for (auto &entry : sideEntries_) { + for (auto &entry : entries_) { if (entry.numericID == achievementID && entry.type == OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR && !show) { // Hide and eventually delete it. entry.endTime = now + (double)FadeoutTime(); @@ -184,13 +160,13 @@ void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) { entry.type = OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR; entry.startTime = now; entry.endTime = now + forever_s; - sideEntries_.insert(sideEntries_.begin(), entry); + entries_.insert(entries_.begin(), entry); } void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const char *trackerText, bool show) { // show=true is used both for create and update. double now = time_now_d(); - for (auto &entry : sideEntries_) { + for (auto &entry : entries_) { if (entry.numericID == leaderboardTrackerID && entry.type == OSDType::LEADERBOARD_TRACKER) { if (show) { // Just an update. @@ -218,7 +194,7 @@ void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const cha if (trackerText) { entry.text = trackerText; } - sideEntries_.insert(sideEntries_.begin(), entry); + entries_.insert(entries_.begin(), entry); } void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) { @@ -235,32 +211,33 @@ void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, floa bool found = false; std::lock_guard guard(mutex_); - for (auto &bar : bars_) { - if (bar.id == id) { + for (auto &bar : entries_) { + if (bar.type == OSDType::PROGRESS_BAR && bar.id == id) { bar.minValue = minValue; bar.maxValue = maxValue; bar.progress = progress; - bar.message = message; + bar.text = message; bar.endTime = now + 60.0; // Nudge the progress bar to keep it shown. return; } } - ProgressBar bar; + Entry bar; bar.id = id; - bar.message = std::move(message); + bar.type = OSDType::PROGRESS_BAR; + bar.text = std::move(message); bar.minValue = minValue; bar.maxValue = maxValue; bar.progress = progress; bar.startTime = now + delay; bar.endTime = now + 60.0; // Show the progress bar for 60 seconds, then fade it out. - bars_.push_back(bar); + entries_.push_back(bar); } void OnScreenDisplay::RemoveProgressBar(std::string id, bool success, float delay_s) { std::lock_guard guard(mutex_); - for (auto iter = bars_.begin(); iter != bars_.end(); iter++) { - if (iter->id == id) { + for (auto iter = entries_.begin(); iter != entries_.end(); iter++) { + if (iter->type == OSDType::PROGRESS_BAR && iter->id == id) { if (success) { // Quickly shoot up to max, if we weren't there. if (iter->maxValue != 0.0f) { @@ -293,16 +270,4 @@ void OnScreenDisplay::ClearAchievementStuff() { break; } } - for (auto &iter : sideEntries_) { - switch (iter.type) { - case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR: - case OSDType::ACHIEVEMENT_UNLOCKED: - case OSDType::ACHIEVEMENT_PROGRESS: - case OSDType::LEADERBOARD_TRACKER: - iter.endTime = now; - break; - default: - break; - } - } } diff --git a/Common/System/OSD.h b/Common/System/OSD.h index cecf0cae79..221502be7f 100644 --- a/Common/System/OSD.h +++ b/Common/System/OSD.h @@ -21,6 +21,22 @@ enum class OSDType { ACHIEVEMENT_CHALLENGE_INDICATOR, // Achievement icon ONLY, no auto-hide LEADERBOARD_TRACKER, + + PROGRESS_BAR, + + VALUE_COUNT, +}; + +enum class ScreenEdgePosition { + BOTTOM_LEFT = 0, + BOTTOM_CENTER = 1, + BOTTOM_RIGHT = 2, + TOP_LEFT = 3, + TOP_CENTER = 4, + TOP_RIGHT = 5, + CENTER_LEFT = 6, + CENTER_RIGHT = 7, + VALUE_COUNT, }; // Data holder for on-screen messages. @@ -67,31 +83,23 @@ public: std::string text2; std::string iconName; int numericID; - const char *id; + std::string id; double startTime; double endTime; - }; - struct ProgressBar { - std::string id; - std::string message; + // Progress-bar-only data: float minValue; float maxValue; float progress; - double startTime; - double endTime; }; std::vector Entries(); - std::vector SideEntries(); - std::vector ProgressBars(); + static float FadeinTime() { return 0.1f; } static float FadeoutTime() { return 0.25f; } private: std::vector entries_; - std::vector sideEntries_; - std::vector bars_; std::mutex mutex_; double sideBarShowTime_ = 0.0; diff --git a/Core/Config.cpp b/Core/Config.cpp index e322f6dbcf..2fec57c37e 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -47,6 +47,7 @@ #include "Common/Thread/ThreadUtil.h" #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/VR/PPSSPPVR.h" +#include "Common/System/OSD.h" #include "Core/Config.h" #include "Core/ConfigSettings.h" #include "Core/ConfigValues.h" diff --git a/Core/Config.h b/Core/Config.h index d6af7aeffb..7f35c13c78 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -29,17 +29,6 @@ extern const char *PPSSPP_GIT_VERSION; -enum class ScreenEdgePosition { - BOTTOM_LEFT = 0, - BOTTOM_CENTER = 1, - BOTOM_RIGHT = 2, - TOP_LEFT = 3, - TOP_CENTER = 4, - TOP_RIGHT = 5, - CENTER_LEFT = 6, - CENTER_RIGHT = 7, -}; - namespace http { class Request; class RequestManager; diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index a9d1bce918..79b197c59e 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -459,6 +459,11 @@ const char *GetCompilerABI() { #endif } +void SystemInfoScreen::update() { + TabbedUIDialogScreenWithGameBackground::update(); + g_OSD.NudgeSidebar(); +} + void SystemInfoScreen::CreateTabs() { using namespace Draw; using namespace UI; diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 743b83af08..fdf2964574 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -113,6 +113,8 @@ public: void CreateTabs() override; + void update() override; + protected: bool ShowSearchControls() const override { return false; } }; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 8e87463697..46d59e5038 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -897,7 +897,7 @@ static UI::AnchorLayoutParams *AnchorInCorner(const Bounds &bounds, int corner, switch ((ScreenEdgePosition)g_Config.iChatButtonPosition) { case ScreenEdgePosition::BOTTOM_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, NONE, NONE, yOffset, true); case ScreenEdgePosition::BOTTOM_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), NONE, NONE, yOffset, true); - case ScreenEdgePosition::BOTOM_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true); + case ScreenEdgePosition::BOTTOM_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true); case ScreenEdgePosition::TOP_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, yOffset, NONE, NONE, true); case ScreenEdgePosition::TOP_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), yOffset, NONE, NONE, true); case ScreenEdgePosition::TOP_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, yOffset, xOffset, NONE, true); diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index a8bc84c441..75802023a5 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -156,12 +156,12 @@ static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, B } } -static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::ProgressBar &bar, float *width, float *height) { +static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::Entry &bar, float *width, float *height) { *height = 36; *width = 450.0f; } -static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressBar &entry, Bounds bounds, int align, float alpha) { +static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, int align, float alpha) { uint32_t foreGround = whiteAlpha(alpha); dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha); @@ -197,7 +197,7 @@ static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressB dc.SetFontStyle(dc.theme->uiFont); dc.SetFontScale(1.0f, 1.0f); - dc.DrawTextShadowRect(entry.message.c_str(), bounds, colorAlpha(0xFFFFFFFF, alpha), (align & FLAG_DYNAMIC_ASCII) | ALIGN_CENTER); + dc.DrawTextShadowRect(entry.text.c_str(), bounds, colorAlpha(0xFFFFFFFF, alpha), (align & FLAG_DYNAMIC_ASCII) | ALIGN_CENTER); } static void MeasureLeaderboardTracker(UIContext &dc, const std::string &text, float *width, float *height) { @@ -226,143 +226,209 @@ void OnScreenMessagesView::Draw(UIContext &dc) { double now = time_now_d(); - float y = 10.0f; + const float padding = 5.0f; + const float fadeinCoef = 1.0f / OnScreenDisplay::FadeinTime(); const float fadeoutCoef = 1.0f / OnScreenDisplay::FadeoutTime(); float sidebarAlpha = g_OSD.SidebarAlpha(); - if (sidebarAlpha > 0.0f) { - // Draw side entries. Top entries should apply on top of them if there's a collision, so drawing - // these first makes sense. - const std::vector sideEntries = g_OSD.SideEntries(); - for (auto &entry : sideEntries) { - float tw, th; + struct LayoutEdge { + float height; + float maxWidth; + float alpha; + }; - const rc_client_achievement_t *achievement = nullptr; - AchievementRenderStyle style; + struct MeasuredEntry { + float w; + float h; + float h1; + float alpha; + int align; + int align2; + AchievementRenderStyle style; + }; - switch (entry.type) { - case OSDType::ACHIEVEMENT_PROGRESS: - { - achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); - if (!achievement) - continue; - style = AchievementRenderStyle::PROGRESS_INDICATOR; - MeasureAchievement(dc, achievement, style, &tw, &th); - break; - } - case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR: - { - achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); - if (!achievement) - continue; - style = AchievementRenderStyle::CHALLENGE_INDICATOR; - MeasureAchievement(dc, achievement, style, &tw, &th); - break; - } - case OSDType::LEADERBOARD_TRACKER: - { - MeasureLeaderboardTracker(dc, entry.text, &tw, &th); - break; - } - default: - continue; - } - Bounds b(10.0f, y, tw, th); - // We don't multiply in sidebarAlpha here because it shouldn't drive the below animation. - float alpha = Clamp((float)(entry.endTime - now) * fadeoutCoef, 0.0f, 1.0f); - // OK, render the thing. - - switch (entry.type) { - case OSDType::ACHIEVEMENT_PROGRESS: - case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR: - { - RenderAchievement(dc, achievement, style, b, alpha * sidebarAlpha, entry.startTime, now, false); - break; - } - case OSDType::LEADERBOARD_TRACKER: - RenderLeaderboardTracker(dc, b, entry.text, alpha * sidebarAlpha); - break; - default: - continue; - } - - y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations. - } - } - - y = 10.0f; - - // Draw the progress bars. - const std::vector bars = g_OSD.ProgressBars(); - for (auto &bar : bars) { - float tw, th; - MeasureOSDProgressBar(dc, bar, &tw, &th); - Bounds b(0.0f, y, tw, th); - b.x = (bounds_.w - b.w) * 0.5f; - - float enterAlpha = saturatef((float)(now - bar.startTime) * 4.0f); - float leaveAlpha = saturatef((float)(bar.endTime - now) * 4.0f); - float alpha = std::min(enterAlpha, leaveAlpha); - RenderOSDProgressBar(dc, bar, b, 0, alpha); - y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations. - } - - // Draw the rest of the top-center messages. + // Grab all the entries. Makes a copy so we can release the lock ASAP. const std::vector entries = g_OSD.Entries(); - for (const auto &entry : entries) { - dc.SetFontScale(1.0f, 1.0f); - // Messages that are wider than the screen are left-aligned instead of centered. - int align = 0; + std::vector measuredEntries; + measuredEntries.resize(entries.size()); + + // Indexed by the enum ScreenEdgePosition. + LayoutEdge edges[(size_t)ScreenEdgePosition::VALUE_COUNT]{}; + for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) { + edges[i].alpha = sidebarAlpha; + } + edges[(size_t)ScreenEdgePosition::TOP_CENTER].alpha = 1.0f; + + ScreenEdgePosition typeEdges[(size_t)OSDType::VALUE_COUNT]{}; + // Default to top. + for (int i = 0; i < (size_t)OSDType::VALUE_COUNT; i++) { + typeEdges[i] = ScreenEdgePosition::TOP_CENTER; + } + + // TODO: Add ability to override these with g_Config settings. + typeEdges[(size_t)OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR] = ScreenEdgePosition::TOP_LEFT; + typeEdges[(size_t)OSDType::ACHIEVEMENT_PROGRESS] = ScreenEdgePosition::TOP_LEFT; + typeEdges[(size_t)OSDType::LEADERBOARD_TRACKER] = ScreenEdgePosition::TOP_LEFT; + + dc.SetFontScale(1.0f, 1.0f); + + // First pass: Measure all the sides. + for (size_t i = 0; i < entries.size(); i++) { + const auto &entry = entries[i]; + auto &measuredEntry = measuredEntries[i]; + + ScreenEdgePosition pos = typeEdges[(size_t)entry.type]; + + measuredEntry.align = 0; + measuredEntry.align2 = 0; // If we have newlines, we may be looking at ASCII debug output. But let's verify. - if (entry.text.find('\n') != 0) { + if (entry.text.find('\n') != std::string::npos) { if (!UTF8StringHasNonASCII(entry.text.c_str())) - align |= FLAG_DYNAMIC_ASCII; + measuredEntry.align |= FLAG_DYNAMIC_ASCII; + } + if (entry.text2.find('\n') != std::string::npos) { + if (!UTF8StringHasNonASCII(entry.text2.c_str())) + measuredEntry.align2 |= FLAG_DYNAMIC_ASCII; } - - float tw, th = 0.0f, h1 = 0.0f; switch (entry.type) { + case OSDType::ACHIEVEMENT_PROGRESS: + { + const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); + if (!achievement) + continue; + measuredEntry.style = AchievementRenderStyle::PROGRESS_INDICATOR; + MeasureAchievement(dc, achievement, measuredEntry.style, &measuredEntry.w, &measuredEntry.h); + break; + } + case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR: + { + const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); + if (!achievement) + continue; + measuredEntry.style = AchievementRenderStyle::CHALLENGE_INDICATOR; + MeasureAchievement(dc, achievement, measuredEntry.style, &measuredEntry.w, &measuredEntry.h); + break; + } + case OSDType::LEADERBOARD_TRACKER: + { + MeasureLeaderboardTracker(dc, entry.text, &measuredEntry.w, &measuredEntry.h); + break; + } case OSDType::ACHIEVEMENT_UNLOCKED: { const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); - if (achievement) { - MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &tw, &th); - h1 = th; - } - tw = 550.0f; + if (!achievement) + continue; + measuredEntry.style = AchievementRenderStyle::UNLOCKED; + MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &measuredEntry.w, &measuredEntry.h); + measuredEntry.h1 = measuredEntry.h; + measuredEntry.w = 550.0f; break; } + case OSDType::PROGRESS_BAR: + MeasureOSDProgressBar(dc, entry, &measuredEntry.w, &measuredEntry.h); + break; default: - MeasureOSDEntry(dc, entry, align, &tw, &th, &h1); + MeasureOSDEntry(dc, entry, measuredEntry.align, &measuredEntry.w, &measuredEntry.h, &measuredEntry.h1); break; } - Bounds b(0.0f, y, tw, th); + float enterAlpha = saturatef((float)(now - entry.startTime) * fadeoutCoef); + float leaveAlpha = saturatef((float)(entry.endTime - now) * fadeoutCoef); + float alpha = std::min(enterAlpha, leaveAlpha); + measuredEntry.alpha = alpha; - if (tw > bounds_.w) { - // Left-aligned - b.x = 2; - } else { - // Centered - b.x = (bounds_.w - b.w) * 0.5f; + edges[(size_t)pos].height += (measuredEntry.h + 4.0f) * alpha; + edges[(size_t)pos].maxWidth = std::max(edges[(size_t)pos].maxWidth, measuredEntry.w); + } + + // Now, perform layout for all 8 edges. + for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) { + if (edges[i].height == 0.0f) { + // Nothing on this side, ignore it entirely. + continue; } - // Scale down if height doesn't fit. - float scale = 1.0f; - if (th > bounds_.h - y) { - // Scale down! - scale = std::max(0.15f, (bounds_.h - y) / th); - dc.SetFontScale(scale, scale); - b.w *= scale; - b.h *= scale; + // First, compute the start position. + float y = padding; + int horizAdj = 0; + int vertAdj = 0; + switch ((ScreenEdgePosition)i) { + case ScreenEdgePosition::TOP_LEFT: horizAdj = -1; vertAdj = -1; break; + case ScreenEdgePosition::CENTER_LEFT: horizAdj = -1; break; + case ScreenEdgePosition::BOTTOM_LEFT: horizAdj = -1; vertAdj = 1; break; + case ScreenEdgePosition::TOP_RIGHT: horizAdj = 1; vertAdj = -1; break; + case ScreenEdgePosition::CENTER_RIGHT: horizAdj = 1; break; + case ScreenEdgePosition::BOTTOM_RIGHT: horizAdj = 1; vertAdj = 1; break; + case ScreenEdgePosition::TOP_CENTER: vertAdj = -1; break; + case ScreenEdgePosition::BOTTOM_CENTER: vertAdj = 1; break; + default: break; } - float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f); - RenderOSDEntry(dc, entry, b, h1, align, alpha); - y += (b.h * scale + 4.0f) * alpha; // including alpha here gets us smooth animations. + if (vertAdj == 0) { + // Center vertically + y = (bounds_.h - edges[i].height) * 0.5f; + } else if (vertAdj == 1) { + y = (bounds_.h - edges[i].height); + } + + // Then, loop through the entries and those belonging here, get rendered here. + for (size_t j = 0; j < (size_t)entries.size(); j++) { + auto &entry = entries[j]; + if (typeEdges[(size_t)entry.type] != (ScreenEdgePosition)i) { // yes, i + continue; + } + auto &measuredEntry = measuredEntries[j]; + float alpha = measuredEntry.alpha * edges[i].alpha; + + Bounds b(padding, y, measuredEntry.w, measuredEntry.h); + + if (horizAdj == 0) { + // Centered + b.x = (bounds_.w - b.w) * 0.5f; + } else if (horizAdj == 1) { + // Right-aligned + b.x = bounds_.w - (b.w + padding); + } + + switch (entry.type) { + case OSDType::ACHIEVEMENT_PROGRESS: + case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR: + { + const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID); + RenderAchievement(dc, achievement, measuredEntry.style, b, alpha, entry.startTime, now, false); + break; + } + case OSDType::LEADERBOARD_TRACKER: + RenderLeaderboardTracker(dc, b, entry.text, alpha); + break; + case OSDType::PROGRESS_BAR: + RenderOSDProgressBar(dc, entry, b, 0, alpha); + break; + default: + { + // Scale down if height doesn't fit. + float scale = 1.0f; + if (measuredEntry.h > bounds_.h - y) { + // Scale down! + scale = std::max(0.15f, (bounds_.h - y) / measuredEntry.h); + dc.SetFontScale(scale, scale); + b.w *= scale; + b.h *= scale; + } + + float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f); + RenderOSDEntry(dc, entry, b, measuredEntry.h1, measuredEntry.align, alpha); + break; + } + } + + y += (measuredEntry.h + 4.0f) * measuredEntry.alpha; + } } } diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 8bc67c8d44..a1f3931e8e 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -275,7 +275,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup) using namespace UI; if (!g_Config.bAchievementsEnable) { - viewGroup->Add(new TextView(ac->T("Achievements are disabled"))); + viewGroup->Add(new NoticeView(NoticeLevel::INFO, ac->T("Achievements are disabled"), "", new LinearLayoutParams(Margins(5)))); } else if (Achievements::IsLoggedIn()) { const rc_client_user_t *info = rc_client_get_user_info(Achievements::GetClient());