From f8b7346b8d751e5313e6f62fdb709ed1033f2650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Jul 2023 17:34:56 +0200 Subject: [PATCH 1/2] Make the achievement lists collapsible on the main achievements screen --- Common/UI/View.cpp | 39 ++++++++++++++++++++++++++++++++++ Common/UI/View.h | 11 +++++++++- Common/UI/ViewGroup.cpp | 13 ++++++++++++ Common/UI/ViewGroup.h | 9 +++++++- Core/RetroAchievements.h | 3 +++ UI/RetroAchievementScreens.cpp | 18 ++++++++++------ 6 files changed, 85 insertions(+), 8 deletions(-) diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index 30824c9be1..ab9697cff2 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -612,6 +612,45 @@ std::string ItemHeader::DescribeText() const { return ApplySafeSubstitutions(u->T("%1 heading"), text_); } +CollapsibleHeader::CollapsibleHeader(bool *toggle, const std::string &text, LayoutParams *layoutParams) + : CheckBox(toggle, text, "", layoutParams) { + layoutParams_->width = FILL_PARENT; + layoutParams_->height = 40; +} + +void CollapsibleHeader::Draw(UIContext &dc) { + Style style = dc.theme->itemStyle; + if (HasFocus()) style = dc.theme->itemFocusedStyle; + if (down_) style = dc.theme->itemDownStyle; + if (!IsEnabled()) style = dc.theme->itemDisabledStyle; + + DrawBG(dc, style); + + float xoff = 37.0f; + + dc.SetFontStyle(dc.theme->uiFontSmall); + dc.DrawText(text_.c_str(), bounds_.x + 4 + xoff, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER); + dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y2() - 2, bounds_.x2(), bounds_.y2(), dc.theme->headerStyle.fgColor); + dc.Draw()->DrawImageRotated(ImageID("I_ARROW"), bounds_.x + 20.0f, bounds_.y + 20.0f, 1.0f, *toggle_ ? -M_PI / 2 : M_PI); +} + +void CollapsibleHeader::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const { + Bounds bounds(0, 0, layoutParams_->width, layoutParams_->height); + if (bounds.w < 0) { + // If there's no size, let's grow as big as we want. + bounds.w = horiz.size == 0 ? MAX_ITEM_SIZE : horiz.size; + } + if (bounds.h < 0) { + bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size; + } + ApplyBoundsBySpec(bounds, horiz, vert); + dc.MeasureTextRect(dc.theme->uiFontSmall, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, ALIGN_LEFT | ALIGN_VCENTER); +} + +void CollapsibleHeader::GetContentDimensions(const UIContext &dc, float &w, float &h) const { + View::GetContentDimensions(dc, w, h); +} + void BorderView::Draw(UIContext &dc) { Color color = 0xFFFFFFFF; if (style_ == BorderStyle::HEADER_FG) diff --git a/Common/UI/View.h b/Common/UI/View.h index f520d9aab1..2f06ad1438 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -857,7 +857,8 @@ public: //allow external agents to toggle the checkbox virtual void Toggle(); virtual bool Toggled() const; -private: + +protected: float CalculateTextScale(const UIContext &dc, float availWidth) const; bool *toggle_; @@ -866,6 +867,14 @@ private: ImageID imageID_; }; +class CollapsibleHeader : public CheckBox { +public: + CollapsibleHeader(bool *toggle, const std::string &text, LayoutParams *layoutParams = nullptr); + void Draw(UIContext &dc) override; + void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override; + void GetContentDimensions(const UIContext &dc, float &w, float &h) const override; +}; + class BitCheckBox : public CheckBox { public: BitCheckBox(uint32_t *bitfield, uint32_t bit, const std::string &text, const std::string &smallText = "", LayoutParams *layoutParams = nullptr) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f1360cf0bd..f2e03d81bc 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1180,4 +1180,17 @@ StickyChoice *ChoiceStrip::Choice(int index) { return nullptr; } +CollapsibleSection::CollapsibleSection(const std::string &title, LayoutParams *layoutParams) : LinearLayout(ORIENT_VERTICAL, layoutParams) { + CollapsibleHeader *heading = new CollapsibleHeader(&open_, title); + views_.push_back(heading); + heading->OnClick.Add([=](UI::EventParams &) { + // Change the visibility of all children except the first one. + // Later maybe try something more ambitious. + for (size_t i = 1; i < views_.size(); i++) { + views_[i]->SetVisibility(open_ ? V_VISIBLE : V_GONE); + } + return UI::EVENT_DONE; + }); +} + } // namespace UI diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 53ffc3089b..2f014ac48b 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -290,7 +290,6 @@ private: bool topTabs_ = false; }; - class TabHolder : public LinearLayout { public: TabHolder(Orientation orientation, float stripSize, LayoutParams *layoutParams = 0); @@ -325,4 +324,12 @@ private: std::vector tabTweens_; }; +class CollapsibleSection : public LinearLayout { +public: + CollapsibleSection(const std::string &title, LayoutParams *layoutParams = nullptr); + +private: + bool open_ = true; +}; + } // namespace UI diff --git a/Core/RetroAchievements.h b/Core/RetroAchievements.h index 140cbf39d2..5e524cc79a 100644 --- a/Core/RetroAchievements.h +++ b/Core/RetroAchievements.h @@ -56,6 +56,9 @@ bool IsActive(); // Returns true if unofficial achievements are enabled. bool UnofficialEnabled(); +// Returns true if encore-mode is active. +bool EncoreModeActive(); + // Returns true if the emulator should hold off on executing game code, such as during game identification. bool IsBlockingExecution(); diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 93e155f487..bcadfa16c1 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -11,6 +11,7 @@ #include "UI/RetroAchievementScreens.h" #include "UI/BackgroundAudio.h" +#include "UI/OnScreenDisplay.h" static inline const char *DeNull(const char *ptr) { return ptr ? ptr : ""; @@ -115,18 +116,23 @@ void RetroAchievementsListScreen::CreateAchievementsTab(UI::ViewGroup *achieveme achievements->Add(new GameAchievementSummaryView()); - achievements->Add(new ItemHeader(ac->T("Unlocked achievements"))); + CollapsibleSection *unlocked = new CollapsibleSection(ac->T("Unlocked achievements")); for (auto &achievement : unlockedAchievements) { - achievements->Add(new AchievementView(achievement)); + unlocked->Add(new AchievementView(achievement)); } - achievements->Add(new ItemHeader(ac->T("Locked achievements"))); + achievements->Add(unlocked); + + CollapsibleSection *locked = new CollapsibleSection(ac->T("Locked achievements")); for (auto &achievement : lockedAchievements) { - achievements->Add(new AchievementView(achievement)); + locked->Add(new AchievementView(achievement)); } - achievements->Add(new ItemHeader(ac->T("Other achievements"))); + achievements->Add(locked); + + CollapsibleSection *other = new CollapsibleSection(ac->T("Other achievements")); for (auto &achievement : otherAchievements) { - achievements->Add(new AchievementView(achievement)); + other->Add(new AchievementView(achievement)); } + achievements->Add(other); } void RetroAchievementsListScreen::CreateLeaderboardsTab(UI::ViewGroup *viewGroup) { From 7eb1bfe1aa691b3c8b52aea671e0f449bb226895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 16 Jul 2023 18:23:43 +0200 Subject: [PATCH 2/2] Spacing default 0.0 in collapsible sections, set spacing for achievements a little higher --- Common/UI/ViewGroup.cpp | 2 ++ UI/RetroAchievementScreens.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f2e03d81bc..757192fab8 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1181,6 +1181,8 @@ StickyChoice *ChoiceStrip::Choice(int index) { } CollapsibleSection::CollapsibleSection(const std::string &title, LayoutParams *layoutParams) : LinearLayout(ORIENT_VERTICAL, layoutParams) { + SetSpacing(0.0f); + CollapsibleHeader *heading = new CollapsibleHeader(&open_, title); views_.push_back(heading); heading->OnClick.Add([=](UI::EventParams &) { diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index bcadfa16c1..e8a3a4fa48 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -116,19 +116,22 @@ void RetroAchievementsListScreen::CreateAchievementsTab(UI::ViewGroup *achieveme achievements->Add(new GameAchievementSummaryView()); - CollapsibleSection *unlocked = new CollapsibleSection(ac->T("Unlocked achievements")); + CollapsibleSection *unlocked = new CollapsibleSection(StringFromFormat("%s (%d)", ac->T("Unlocked achievements"), (int)unlockedAchievements.size())); + unlocked->SetSpacing(2.0f); for (auto &achievement : unlockedAchievements) { unlocked->Add(new AchievementView(achievement)); } achievements->Add(unlocked); - CollapsibleSection *locked = new CollapsibleSection(ac->T("Locked achievements")); + CollapsibleSection *locked = new CollapsibleSection(StringFromFormat("%s (%d)", ac->T("Locked achievements"), (int)lockedAchievements.size())); + unlocked->SetSpacing(2.0f); for (auto &achievement : lockedAchievements) { locked->Add(new AchievementView(achievement)); } achievements->Add(locked); - CollapsibleSection *other = new CollapsibleSection(ac->T("Other achievements")); + CollapsibleSection *other = new CollapsibleSection(StringFromFormat("%s (%d)", ac->T("Other achievements"), (int)otherAchievements.size())); + unlocked->SetSpacing(2.0f); for (auto &achievement : otherAchievements) { other->Add(new AchievementView(achievement)); }