diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp index 6099071dbe..a7d4a4edd8 100644 --- a/Common/System/Request.cpp +++ b/Common/System/Request.cpp @@ -87,6 +87,19 @@ void OnScreenDisplay::Show(OSDType type, const std::string &text, const std::str entries_.insert(entries_.begin(), msg); } +void OnScreenDisplay::ShowAchievementUnlocked(int achievementID) { + double now = time_now_d(); + + double duration_s = 5.0; + + Entry msg; + msg.numericID = achievementID; + msg.type = OSDType::ACHIEVEMENT_UNLOCKED; + msg.startTime = now; + msg.endTime = now + duration_s; + entries_.insert(entries_.begin(), msg); +} + void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) { // TODO: translate "on" and "off"? Or just get rid of this whole thing? Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s); diff --git a/Common/System/System.h b/Common/System/System.h index 96753b8271..d493d5cb84 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -223,6 +223,9 @@ enum class OSDType { MESSAGE_ERROR, MESSAGE_ERROR_DUMP, // displays lots of text (after the first line), small size MESSAGE_FILE_LINK, + + ACHIEVEMENT_UNLOCKED, + // PROGRESS_BAR, // PROGRESS_INDETERMINATE, }; @@ -235,6 +238,8 @@ public: Show(type, text, "", duration_s, id); } void Show(OSDType type, const std::string &text, const std::string &text2, float duration_s = 0.0f, const char *id = nullptr); + void ShowAchievementUnlocked(int achievementID); + void ShowOnOff(const std::string &message, bool on, float duration_s = 0.0f); bool IsEmpty() const { return entries_.empty(); } // Shortcut to skip rendering. @@ -251,9 +256,11 @@ public: OSDType type; std::string text; std::string text2; + std::string iconName; + int numericID; const char *id; + double startTime; double endTime; - double duration; }; struct ProgressBar { diff --git a/UI/DevScreens.h b/UI/DevScreens.h index 29f4f926c9..776c6bb8e8 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -114,7 +114,7 @@ public: void CreateTabs() override; protected: - bool ShowSearchControls() override { return false; } + bool ShowSearchControls() const override { return false; } }; class AddressPromptScreen : public PopupScreen { diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index dcf68d2778..70300e2705 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -8,6 +8,8 @@ #include "Common/Render/TextureAtlas.h" #include "Common/Render/DrawBuffer.h" #include "Common/Math/math_util.h" +#include "Common/UI/IconCache.h" +#include "UI/RetroAchievementScreens.h" #include "Common/UI/Context.h" #include "Common/System/System.h" @@ -44,6 +46,14 @@ static const float extraTextScale = 0.7f; // Align only matters here for the ASCII-only flag. static void MeasureOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, int align, float *width, float *height, float *height1) { + if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) { + const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID); + MeasureAchievement(dc, *achievement, width, height); + *width = 400.0f; + *height1 = *height; + return; + } + dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, entry.text.c_str(), width, height, align); *height1 = *height; @@ -63,6 +73,12 @@ static void MeasureOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, } static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, float height1, int align, float alpha) { + if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) { + const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID); + RenderAchievement(dc, *achievement, AchievementRenderStyle::UNLOCKED, bounds, alpha); + return; + } + UI::Drawable background = UI::Drawable(colorAlpha(GetOSDBackgroundColor(entry.type), alpha)); uint32_t foreGround = whiteAlpha(alpha); diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index c74638dae3..76977cd9e4 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -115,28 +115,22 @@ void RetroAchievementsSettingsScreen::CreateSettingsTab(UI::ViewGroup *viewGroup // viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficialTestMode, ac->T("Unofficial Test Mode"))); } -void MeasureAchievement(const Achievements::Achievement &achievement, float *w, float *h) { +void MeasureAchievement(const UIContext &dc, const Achievements::Achievement &achievement, float *w, float *h) { *w = 0.0f; *h = 60.0f; } -void MeasureGameAchievementSummary(int gameID, float *w, float *h) { +void MeasureGameAchievementSummary(const UIContext &dc, int gameID, float *w, float *h) { *w = 0.0f; *h = 60.0f; } - -// Render style references: - -// https://www.trueachievements.com/achievement-meme-maker - - // Graphical -void RenderAchievement(UIContext &dc, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float opacity) { +void RenderAchievement(UIContext &dc, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha) { using namespace UI; UI::Drawable background = achievement.locked ? dc.theme->popupStyle.background : dc.theme->itemStyle.background; - background.color = colorAlpha(background.color, opacity); + background.color = colorAlpha(background.color, alpha); float iconSpace = 64.0f; dc.Flush(); @@ -168,11 +162,11 @@ void RenderAchievement(UIContext &dc, const Achievements::Achievement &achieveme dc.RebindTexture(); } -void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bounds, float opacity) { +void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bounds, float alpha) { using namespace UI; UI::Drawable background = dc.theme->itemStyle.background; - background.color = colorAlpha(background.color, opacity); + background.color = colorAlpha(background.color, alpha); float iconSpace = 64.0f; dc.Flush(); @@ -207,7 +201,14 @@ void AchievementView::Draw(UIContext &dc) { } void AchievementView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - MeasureAchievement(achievement_, &w, &h); + MeasureAchievement(dc, achievement_, &w, &h); +} + +void AchievementView::Click() { + // In debug builds, clicking achievements will show them being unlocked (which may be a lie). +#ifdef _DEBUG + g_OSD.ShowAchievementUnlocked(achievement_.id); +#endif } void GameAchievementSummaryView::Draw(UIContext &dc) { @@ -215,5 +216,5 @@ void GameAchievementSummaryView::Draw(UIContext &dc) { } void GameAchievementSummaryView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { - MeasureGameAchievementSummary(gameID_, &w, &h); + MeasureGameAchievementSummary(dc, gameID_, &w, &h); } diff --git a/UI/RetroAchievementScreens.h b/UI/RetroAchievementScreens.h index b7d419e880..ddb94160e0 100644 --- a/UI/RetroAchievementScreens.h +++ b/UI/RetroAchievementScreens.h @@ -24,6 +24,9 @@ public: void CreateTabs() override; void sendMessage(const char *message, const char *value) override; +protected: + bool ShowSearchControls() const override { return false; } + private: void CreateAccountTab(UI::ViewGroup *viewGroup); void CreateSettingsTab(UI::ViewGroup *viewGroup); @@ -36,15 +39,16 @@ enum class AchievementRenderStyle { UNLOCKED, }; -void MeasureAchievement(const Achievements::Achievement &achievement, float *w, float *h); -void RenderAchievement(UIContext &context, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float time_s); -void MeasureGameAchievementSummary(int gameID, float *w, float *h); +void MeasureAchievement(const UIContext &dc, const Achievements::Achievement &achievement, float *w, float *h); +void RenderAchievement(UIContext &dc, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha); +void MeasureGameAchievementSummary(const UIContext &dc, int gameID, float *w, float *h); +void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bounds, float alpha); - -class AchievementView : public UI::Item { +class AchievementView : public UI::ClickableItem { public: - AchievementView(const Achievements::Achievement &achievement, UI::LayoutParams *layoutParams = nullptr) : UI::Item(layoutParams), achievement_(achievement) {} + AchievementView(const Achievements::Achievement &achievement, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), achievement_(achievement) {} + void Click() override; void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; private: diff --git a/UI/RetroAchievements.cpp b/UI/RetroAchievements.cpp index 248ff32207..74a3342c3d 100644 --- a/UI/RetroAchievements.cpp +++ b/UI/RetroAchievements.cpp @@ -113,6 +113,10 @@ void OSDAddNotification(float duration_s, const std::string &title, const std::s g_OSD.Show(OSDType::MESSAGE_INFO, title); } +void OSDAddAchievementUnlockedNotification(unsigned int achievementId) { + g_OSD.ShowAchievementUnlocked(achievementId); +} + void OSDOpenBackgroundProgressDialog(const char *str_id, std::string message, s32 min, s32 max, s32 value) { NOTICE_LOG(ACHIEVEMENTS, "Progress dialog opened: %s %s", str_id, message.c_str()); g_OSD.SetProgressBar(str_id, std::move(message), min, max, value); diff --git a/UI/TabbedDialogScreen.h b/UI/TabbedDialogScreen.h index 1f6258f9f8..cc0c3e80e5 100644 --- a/UI/TabbedDialogScreen.h +++ b/UI/TabbedDialogScreen.h @@ -18,7 +18,7 @@ protected: // Load data and define your tabs here. virtual void PreCreateViews() {} virtual void CreateTabs() = 0; - virtual bool ShowSearchControls() { return true; } + virtual bool ShowSearchControls() const { return true; } void RecreateViews() override; void sendMessage(const char *message, const char *value) override;