From fc78b408b2a7eca2fa2f1c024dce60e1059e752a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 27 Sep 2021 23:25:41 -0700 Subject: [PATCH 1/3] UI: Have scroll views directly remember their pos. Kinda like checkboxes, cleaner this way. --- Common/UI/ViewGroup.cpp | 8 +++----- Common/UI/ViewGroup.h | 12 ++++++++---- UI/CwCheatScreen.cpp | 3 +-- UI/MainScreen.cpp | 7 ++----- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index f73816c229..669a9200d9 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -1017,17 +1017,13 @@ void ScrollView::PersistData(PersistStatus status, std::string anonId, PersistMa void ScrollView::SetVisibility(Visibility visibility) { ViewGroup::SetVisibility(visibility); - if (visibility == V_GONE && !rememberPosition_) { + if (visibility == V_GONE && !rememberPos_) { // Since this is no longer shown, forget the scroll position. // For example, this happens when switching tabs. ScrollTo(0.0f); } } -float ScrollView::GetScrollPosition() { - return scrollPos_; -} - void ScrollView::ScrollTo(float newScrollPos) { scrollTarget_ = newScrollPos; scrollToTarget_ = true; @@ -1141,6 +1137,8 @@ void ScrollView::Update() { if (oldPos != scrollPos_) orientation_ == ORIENT_HORIZONTAL ? lastScrollPosX = scrollPos_ : lastScrollPosY = scrollPos_; + if (rememberPos_) + *rememberPos_ = scrollPos_; } void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) { diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 10ca2fbc09..aefad04c1b 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -262,8 +262,8 @@ public: // A scrollview usually contains just a single child - a linear layout or similar. class ScrollView : public ViewGroup { public: - ScrollView(Orientation orientation, LayoutParams *layoutParams = 0, bool rememberPosition = false) - : ViewGroup(layoutParams), orientation_(orientation), rememberPosition_(rememberPosition) {} + ScrollView(Orientation orientation, LayoutParams *layoutParams = 0) + : ViewGroup(layoutParams), orientation_(orientation) {} ~ScrollView(); void Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) override; @@ -277,10 +277,14 @@ public: void ScrollTo(float newScrollPos); void ScrollToBottom(); void ScrollRelative(float distance); - float GetScrollPosition(); bool CanScroll() const; void Update() override; + void RememberPosition(float *pos) { + rememberPos_ = pos; + ScrollTo(*pos); + } + // Get the last moved scroll view position static void GetLastScrollPosition(float &x, float &y); @@ -309,7 +313,7 @@ private: float pull_ = 0.0f; float lastViewSize_ = 0.0f; bool scrollToTopOnSizeChange_ = false; - bool rememberPosition_; + float *rememberPos_ = nullptr; static float lastScrollPosX; static float lastScrollPosY; diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index b5fde7d5f6..ba02587609 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -97,7 +97,7 @@ void CwCheatScreen::CreateViews() { rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 0.5f)); rightScroll_->SetTag("CwCheats"); rightScroll_->SetScrollToTop(false); - rightScroll_->ScrollTo(g_Config.fCwCheatScrollPosition); + rightScroll_->RememberPosition(&g_Config.fCwCheatScrollPosition); LinearLayout *rightColumn = new LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(200, FILL_PARENT, actionMenuMargins)); rightScroll_->Add(rightColumn); @@ -140,7 +140,6 @@ void CwCheatScreen::onFinish(DialogResult result) { if (MIPSComp::jit) { MIPSComp::jit->ClearCache(); } - g_Config.fCwCheatScrollPosition = rightScroll_->GetScrollPosition(); } UI::EventReturn CwCheatScreen::OnEnableAll(UI::EventParams ¶ms) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 1baa87abb1..43d7c8c77d 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1007,7 +1007,7 @@ void MainScreen::CreateViews() { Button *focusButton = nullptr; if (hasStorageAccess) { - scrollAllGames_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT), true); + scrollAllGames_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollAllGames_->SetTag("MainScreenAllGames"); ScrollView *scrollHomebrew = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); scrollHomebrew->SetTag("MainScreenHomebrew"); @@ -1026,7 +1026,7 @@ void MainScreen::CreateViews() { tabHolder_->AddTab(mm->T("Games"), scrollAllGames_); tabHolder_->AddTab(mm->T("Homebrew & Demos"), scrollHomebrew); - scrollAllGames_->ScrollTo(g_Config.fGameListScrollPosition); + scrollAllGames_->RememberPosition(&g_Config.fGameListScrollPosition); tabAllGames->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant); tabHomebrew->OnChoice.Handle(this, &MainScreen::OnGameSelectedInstant); @@ -1248,9 +1248,6 @@ void MainScreen::update() { RecreateViews(); lastVertical_ = vertical; } - if (scrollAllGames_) { - g_Config.fGameListScrollPosition = scrollAllGames_->GetScrollPosition(); - } } bool MainScreen::UseVerticalLayout() const { From 374569ce7ecd91b8864018326482a5b99213c63e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 27 Sep 2021 23:37:31 -0700 Subject: [PATCH 2/3] UI: Keep scroll position on async load. For the saved scroll position in the game list. --- Common/UI/ViewGroup.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 669a9200d9..312f12c1d9 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -800,15 +800,21 @@ void ScrollView::Layout() { switch (orientation_) { case ORIENT_HORIZONTAL: if (scrolled.w != lastViewSize_) { - ScrollTo(0.0f); + if (scrollToTopOnSizeChange_) + ScrollTo(0.0f); + else if (rememberPos_) + scrollPos_ = *rememberPos_; lastViewSize_ = scrolled.w; } scrolled.x = bounds_.x - layoutScrollPos_; scrolled.y = bounds_.y + margins.top; break; case ORIENT_VERTICAL: - if (scrolled.h != lastViewSize_ && scrollToTopOnSizeChange_) { - ScrollTo(0.0f); + if (scrolled.h != lastViewSize_) { + if (scrollToTopOnSizeChange_) + ScrollTo(0.0f); + else if (rememberPos_) + scrollPos_ = *rememberPos_; lastViewSize_ = scrolled.h; } scrolled.x = bounds_.x + margins.left; @@ -1137,8 +1143,11 @@ void ScrollView::Update() { if (oldPos != scrollPos_) orientation_ == ORIENT_HORIZONTAL ? lastScrollPosX = scrollPos_ : lastScrollPosY = scrollPos_; - if (rememberPos_) + + // We load some lists asynchronously, so don't update the position until it's loaded. + if (rememberPos_ && ClampedScrollPos(scrollPos_) != ClampedScrollPos(*rememberPos_)) { *rememberPos_ = scrollPos_; + } } void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) { From 931ba43216b8f5bd0578ad369ce6d5ca7587c8be Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 27 Sep 2021 23:39:33 -0700 Subject: [PATCH 3/3] UI: Remove scroll to top on size change. It wasn't actually used anywhere, and I don't see a reason for it now. --- Common/UI/ViewGroup.cpp | 8 ++------ Common/UI/ViewGroup.h | 4 ---- UI/ControlMappingScreen.cpp | 1 - UI/CwCheatScreen.cpp | 1 - 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 312f12c1d9..d3e1ad1b9e 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -800,9 +800,7 @@ void ScrollView::Layout() { switch (orientation_) { case ORIENT_HORIZONTAL: if (scrolled.w != lastViewSize_) { - if (scrollToTopOnSizeChange_) - ScrollTo(0.0f); - else if (rememberPos_) + if (rememberPos_) scrollPos_ = *rememberPos_; lastViewSize_ = scrolled.w; } @@ -811,9 +809,7 @@ void ScrollView::Layout() { break; case ORIENT_VERTICAL: if (scrolled.h != lastViewSize_) { - if (scrollToTopOnSizeChange_) - ScrollTo(0.0f); - else if (rememberPos_) + if (rememberPos_) scrollPos_ = *rememberPos_; lastViewSize_ = scrolled.h; } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index aefad04c1b..4dca68bb35 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -295,9 +295,6 @@ public: NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) override; - // Quick hack to prevent scrolling to top in some lists - void SetScrollToTop(bool t) { scrollToTopOnSizeChange_ = t; } - private: float ClampedScrollPos(float pos); @@ -312,7 +309,6 @@ private: float inertia_ = 0.0f; float pull_ = 0.0f; float lastViewSize_ = 0.0f; - bool scrollToTopOnSizeChange_ = false; float *rememberPos_ = nullptr; static float lastScrollPosX; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 1aee00dedd..a9edac12a9 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -250,7 +250,6 @@ void ControlMappingScreen::CreateViews() { rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)); rightScroll_->SetTag("ControlMapping"); - rightScroll_->SetScrollToTop(false); LinearLayout *rightColumn = new LinearLayoutList(ORIENT_VERTICAL); rightScroll_->Add(rightColumn); diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index ba02587609..0a1a1e85c3 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -96,7 +96,6 @@ void CwCheatScreen::CreateViews() { rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 0.5f)); rightScroll_->SetTag("CwCheats"); - rightScroll_->SetScrollToTop(false); rightScroll_->RememberPosition(&g_Config.fCwCheatScrollPosition); LinearLayout *rightColumn = new LinearLayoutList(ORIENT_VERTICAL, new LinearLayoutParams(200, FILL_PARENT, actionMenuMargins)); rightScroll_->Add(rightColumn);