From 7a29a8bd4808402bd6c29e73658fa907e6971ed0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 16:39:14 -0700 Subject: [PATCH 1/6] UI: Handle WRAP_CONTENT in flexible scroll views. If the scroll view had weight, it'd grow to the max size always. Now it still fits to the container, if that's what it's set to. --- Common/UI/ViewGroup.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 9b816f2767..fbff1e3f6c 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -756,6 +756,8 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver } views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v); MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight(), vert, &measuredHeight_); + if (layoutParams_->width == WRAP_CONTENT) + MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_); } else { MeasureSpec h = MeasureSpec(AT_MOST, measuredWidth_ - margins.horiz()); if (measuredWidth_ == 0.0f && (horiz.type == UNSPECIFIED || layoutParams_->width == WRAP_CONTENT)) { @@ -763,16 +765,16 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver } views_[0]->Measure(dc, h, MeasureSpec(UNSPECIFIED, measuredHeight_)); MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_); + if (layoutParams_->height == WRAP_CONTENT) + MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight(), vert, &measuredHeight_); } if (orientation_ == ORIENT_VERTICAL && vert.type != EXACTLY) { - if (measuredHeight_ < views_[0]->GetMeasuredHeight() && layoutParams_->height < 0.0f) { - measuredHeight_ = views_[0]->GetMeasuredHeight(); - } - if (measuredHeight_ < views_[0]->GetBounds().h && layoutParams_->height < 0.0f) { - measuredHeight_ = views_[0]->GetBounds().h; - } - if (vert.type == AT_MOST && measuredHeight_ > vert.size) { - measuredHeight_ = vert.size; + float bestHeight = std::max(views_[0]->GetMeasuredHeight(), views_[0]->GetBounds().h); + if (vert.type == AT_MOST) + bestHeight = std::min(bestHeight, vert.size); + + if (measuredHeight_ < bestHeight && layoutParams_->height < 0.0f) { + measuredHeight_ = bestHeight; } } } From 6378cb1693af7771662bb34fd2f9018bd5f2ef3a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 16:43:15 -0700 Subject: [PATCH 2/6] UI: Fix focus persistence in control mapping. Trying to reset focus from the parent was just complicating things. We persist the focus state when recreating views. --- UI/ControlMappingScreen.cpp | 16 ++++------------ UI/ControlMappingScreen.h | 1 - 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 8e0471643b..a827d9d409 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -33,6 +33,7 @@ #include "Common/Data/Text/I18n.h" #include "Common/Input/KeyCodes.h" #include "Common/Input/InputState.h" +#include "Common/StringUtils.h" #include "Common/System/Display.h" #include "Common/System/System.h" #include "Core/KeyMap.h" @@ -90,7 +91,6 @@ void SingleControlMapper::Update() { } void SingleControlMapper::Refresh() { - bool hasFocus = UI::GetFocusedView() == this; Clear(); auto mc = GetI18NCategory("MappableControls"); @@ -162,9 +162,6 @@ void SingleControlMapper::Refresh() { Choice *c = rightColumn->Add(new Choice("", new LinearLayoutParams(FILL_PARENT, itemH))); c->OnClick.Handle(this, &SingleControlMapper::OnAdd); } - - if (hasFocus) - this->SetFocus(); } void SingleControlMapper::MappedCallback(KeyDef kdf) { @@ -184,7 +181,7 @@ void SingleControlMapper::MappedCallback(KeyDef kdf) { } g_Config.bMapMouse = false; refresh_ = true; - ctrlScreen_->KeyMapped(pspKey_); + SetFocus(); // After this, we do not exist any more. So the refresh_ = true is probably irrelevant. } @@ -222,6 +219,7 @@ UI::EventReturn SingleControlMapper::OnDelete(UI::EventParams ¶ms) { KeyMap::g_controllerMap[pspKey_].erase(KeyMap::g_controllerMap[pspKey_].begin() + index); KeyMap::g_controllerMapGeneration++; refresh_ = true; + SetFocus(); return UI::EVENT_DONE; } @@ -262,6 +260,7 @@ void ControlMappingScreen::CreateViews() { SingleControlMapper *mapper = rightColumn->Add( new SingleControlMapper(this, mappableKeys[i].key, mappableKeys[i].name, screenManager(), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); + mapper->SetTag(StringFromFormat("KeyMap%s", mappableKeys[i].name)); mappers_.push_back(mapper); } @@ -314,13 +313,6 @@ void ControlMappingScreen::dialogFinished(const Screen *dialog, DialogResult res } } -void ControlMappingScreen::KeyMapped(int pspkey) { // Notification to let us refocus the same one after recreating views. - for (size_t i = 0; i < mappers_.size(); i++) { - if (mappers_[i]->GetPspKey() == pspkey) - SetFocusedView(mappers_[i]); - } -} - void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h index 496fab41f3..393fb1f18c 100644 --- a/UI/ControlMappingScreen.h +++ b/UI/ControlMappingScreen.h @@ -35,7 +35,6 @@ class SingleControlMapper; class ControlMappingScreen : public UIDialogScreenWithBackground { public: ControlMappingScreen() {} - void KeyMapped(int pspkey); // Notification to let us refocus the same one after recreating views. std::string tag() const override { return "control mapping"; } protected: From 7bb58ce5a01bc2388b6fe22a1f92ff50e4af0577 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 16:59:55 -0700 Subject: [PATCH 3/6] UI: Refocus better on control mapping change. This is less awkward, since it keeps you closer to where you were before. --- UI/ControlMappingScreen.cpp | 54 ++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index a827d9d409..3645747dba 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -46,7 +46,7 @@ class SingleControlMapper : public UI::LinearLayout { public: - SingleControlMapper(ControlMappingScreen *ctrlScreen, int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams = 0); + SingleControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams = nullptr); void Update() override; int GetPspKey() const { return pspKey_; } @@ -68,17 +68,19 @@ private: ADD, }; - ControlMappingScreen *ctrlScreen_; - Action action_; + UI::Choice *addButton_ = nullptr; + UI::Choice *replaceAllButton_ = nullptr; + std::vector rows_; + Action action_ = NONE; int actionIndex_; int pspKey_; std::string keyName_; ScreenManager *scrm_; - bool refresh_; + bool refresh_ = false; }; -SingleControlMapper::SingleControlMapper(ControlMappingScreen *ctrlScreen, int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) - : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), ctrlScreen_(ctrlScreen), action_(NONE), pspKey_(pspKey), keyName_(keyName), scrm_(scrm), refresh_(false) { +SingleControlMapper::SingleControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) + : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), pspKey_(pspKey), keyName_(keyName), scrm_(scrm) { Refresh(); } @@ -117,17 +119,16 @@ void SingleControlMapper::Refresh() { auto iter = keyImages.find(keyName_); // First, look among images. if (iter != keyImages.end()) { - Choice *c = root->Add(new Choice(iter->second, new LinearLayoutParams(leftColumnWidth, itemH))); - c->OnClick.Handle(this, &SingleControlMapper::OnReplaceAll); + replaceAllButton_ = new Choice(iter->second, new LinearLayoutParams(leftColumnWidth, itemH)); } else { // No image? Let's translate. - Choice *c = new Choice(mc->T(keyName_.c_str()), new LinearLayoutParams(leftColumnWidth, itemH)); - c->SetCentered(true); - root->Add(c)->OnClick.Handle(this, &SingleControlMapper::OnReplaceAll); + replaceAllButton_ = new Choice(mc->T(keyName_.c_str()), new LinearLayoutParams(leftColumnWidth, itemH)); + replaceAllButton_->SetCentered(true); } + root->Add(replaceAllButton_)->OnClick.Handle(this, &SingleControlMapper::OnReplaceAll); - Choice *p = root->Add(new Choice(" + ", new LayoutParams(WRAP_CONTENT, itemH))); - p->OnClick.Handle(this, &SingleControlMapper::OnAdd); + addButton_ = root->Add(new Choice(" + ", new LayoutParams(WRAP_CONTENT, itemH))); + addButton_->OnClick.Handle(this, &SingleControlMapper::OnAdd); if (g_Config.bMouseControl) { Choice *p = root->Add(new Choice("M", new LayoutParams(WRAP_CONTENT, itemH))); p->OnClick.Handle(this, &SingleControlMapper::OnAddMouse); @@ -138,22 +139,21 @@ void SingleControlMapper::Refresh() { std::vector mappings; KeyMap::KeyFromPspButton(pspKey_, &mappings, false); + rows_.empty(); for (size_t i = 0; i < mappings.size(); i++) { std::string deviceName = GetDeviceName(mappings[i].deviceId); std::string keyName = KeyMap::GetKeyOrAxisName(mappings[i].keyCode); LinearLayout *row = rightColumn->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); row->SetSpacing(1.0f); - - char tagbuf[16]; - sprintf(tagbuf, "%d", (int)i); + rows_.push_back(row); Choice *c = row->Add(new Choice(deviceName + "." + keyName, new LinearLayoutParams(FILL_PARENT, itemH, 1.0f))); - c->SetTag(tagbuf); + c->SetTag(StringFromFormat("%d_Change%d", (int)i, pspKey_)); c->OnClick.Handle(this, &SingleControlMapper::OnReplace); Choice *d = row->Add(new Choice(" X ", new LayoutParams(WRAP_CONTENT, itemH))); - d->SetTag(tagbuf); + d->SetTag(StringFromFormat("%d_Del%d", (int)i, pspKey_)); d->OnClick.Handle(this, &SingleControlMapper::OnDelete); } @@ -168,20 +168,26 @@ void SingleControlMapper::MappedCallback(KeyDef kdf) { switch (action_) { case ADD: KeyMap::SetKeyMapping(pspKey_, kdf, false); + addButton_->SetFocus(); break; case REPLACEALL: KeyMap::SetKeyMapping(pspKey_, kdf, true); + replaceAllButton_->SetFocus(); break; case REPLACEONE: KeyMap::g_controllerMap[pspKey_][actionIndex_] = kdf; KeyMap::g_controllerMapGeneration++; + if (actionIndex_ < rows_.size()) + rows_[actionIndex_]->SetFocus(); + else + SetFocus(); break; default: - ; + SetFocus(); + break; } g_Config.bMapMouse = false; refresh_ = true; - SetFocus(); // After this, we do not exist any more. So the refresh_ = true is probably irrelevant. } @@ -219,7 +225,11 @@ UI::EventReturn SingleControlMapper::OnDelete(UI::EventParams ¶ms) { KeyMap::g_controllerMap[pspKey_].erase(KeyMap::g_controllerMap[pspKey_].begin() + index); KeyMap::g_controllerMapGeneration++; refresh_ = true; - SetFocus(); + + if (index + 1 < rows_.size()) + rows_[index]->SetFocus(); + else + SetFocus(); return UI::EVENT_DONE; } @@ -258,7 +268,7 @@ void ControlMappingScreen::CreateViews() { std::vector mappableKeys = KeyMap::GetMappableKeys(); for (size_t i = 0; i < mappableKeys.size(); i++) { SingleControlMapper *mapper = rightColumn->Add( - new SingleControlMapper(this, mappableKeys[i].key, mappableKeys[i].name, screenManager(), + new SingleControlMapper(mappableKeys[i].key, mappableKeys[i].name, screenManager(), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT))); mapper->SetTag(StringFromFormat("KeyMap%s", mappableKeys[i].name)); mappers_.push_back(mapper); From 6e4708733cc4ec08670e9ae40f476562eb80fb47 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 17:08:27 -0700 Subject: [PATCH 4/6] UI: Restore focus on PSP view as well. --- UI/ControlMappingScreen.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 3645747dba..3f09c61bdc 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -1009,6 +1009,7 @@ public: MockPSP(UI::LayoutParams *layoutParams = nullptr); void SelectButton(int btn); + void FocusButton(int btn); float GetPopupOffset(); UI::Event ButtonClick; @@ -1055,6 +1056,12 @@ void MockPSP::SelectButton(int btn) { selectedButton_ = btn; } +void MockPSP::FocusButton(int btn) { + MockButton *view = buttons_[selectedButton_]; + if (view) + view->SetFocus(); +} + float MockPSP::GetPopupOffset() { MockButton *view = buttons_[selectedButton_]; if (!view) @@ -1164,8 +1171,13 @@ void VisualMappingScreen::HandleKeyMapping(KeyDef key) { nextKey_ = VIRTKEY_AXIS_X_MIN; else if (nextKey_ == VIRTKEY_AXIS_X_MIN) nextKey_ = VIRTKEY_AXIS_X_MAX; - else + else { + if (nextKey_ == VIRTKEY_AXIS_X_MAX) + psp_->FocusButton(VIRTKEY_AXIS_Y_MAX); + else + psp_->FocusButton(nextKey_); nextKey_ = 0; + } } else if ((size_t)bindAll_ + 1 < bindAllOrder.size()) { bindAll_++; nextKey_ = bindAllOrder[bindAll_]; @@ -1179,6 +1191,9 @@ void VisualMappingScreen::dialogFinished(const Screen *dialog, DialogResult resu if (result == DR_YES && nextKey_ != 0) { MapNext(); } else { + // This means they canceled. + if (nextKey_ != 0) + psp_->FocusButton(nextKey_); nextKey_ = 0; bindAll_ = -1; psp_->SelectButton(0); From 01edd695c86e022999937016c7a9f4be0dc6a067 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 17:14:08 -0700 Subject: [PATCH 5/6] UI: Fix refocus on no control change. There's no reason to refresh, and since the views are different without PersistData being called, it breaks the focus. Refreshing now handled via the generation value. --- UI/ControlMappingScreen.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 3f09c61bdc..31f7fe761d 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -48,8 +48,8 @@ class SingleControlMapper : public UI::LinearLayout { public: SingleControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams = nullptr); - void Update() override; int GetPspKey() const { return pspKey_; } + private: void Refresh(); @@ -76,7 +76,6 @@ private: int pspKey_; std::string keyName_; ScreenManager *scrm_; - bool refresh_ = false; }; SingleControlMapper::SingleControlMapper(int pspKey, std::string keyName, ScreenManager *scrm, UI::LinearLayoutParams *layoutParams) @@ -84,14 +83,6 @@ SingleControlMapper::SingleControlMapper(int pspKey, std::string keyName, Screen Refresh(); } -void SingleControlMapper::Update() { - if (refresh_) { - refresh_ = false; - Refresh(); - host->UpdateUI(); - } -} - void SingleControlMapper::Refresh() { Clear(); auto mc = GetI18NCategory("MappableControls"); @@ -187,8 +178,6 @@ void SingleControlMapper::MappedCallback(KeyDef kdf) { break; } g_Config.bMapMouse = false; - refresh_ = true; - // After this, we do not exist any more. So the refresh_ = true is probably irrelevant. } UI::EventReturn SingleControlMapper::OnReplace(UI::EventParams ¶ms) { @@ -224,7 +213,6 @@ UI::EventReturn SingleControlMapper::OnDelete(UI::EventParams ¶ms) { int index = atoi(params.v->Tag().c_str()); KeyMap::g_controllerMap[pspKey_].erase(KeyMap::g_controllerMap[pspKey_].begin() + index); KeyMap::g_controllerMapGeneration++; - refresh_ = true; if (index + 1 < rows_.size()) rows_[index]->SetFocus(); From e9ebd86439ae03edc41537a95d6c1e34ff9bc2a9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Aug 2021 17:35:58 -0700 Subject: [PATCH 6/6] UI: Fix scrollview focus scroll before relayout. Need to use the position of the bounds as of last layout, not the new desired position. --- Common/UI/ViewGroup.cpp | 32 +++++++++++++++++--------------- Common/UI/ViewGroup.h | 1 + 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index fbff1e3f6c..ba8a9ef1bf 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -795,7 +795,7 @@ void ScrollView::Layout() { scrolled.w = views_[0]->GetMeasuredWidth() - margins.horiz(); scrolled.h = views_[0]->GetMeasuredHeight() - margins.vert(); - float layoutScrollPos = ClampedScrollPos(scrollPos_); + layoutScrollPos_ = ClampedScrollPos(scrollPos_); switch (orientation_) { case ORIENT_HORIZONTAL: @@ -803,7 +803,7 @@ void ScrollView::Layout() { ScrollTo(0.0f); lastViewSize_ = scrolled.w; } - scrolled.x = bounds_.x - layoutScrollPos; + scrolled.x = bounds_.x - layoutScrollPos_; scrolled.y = bounds_.y + margins.top; break; case ORIENT_VERTICAL: @@ -812,7 +812,7 @@ void ScrollView::Layout() { lastViewSize_ = scrolled.h; } scrolled.x = bounds_.x + margins.left; - scrolled.y = bounds_.y - layoutScrollPos; + scrolled.y = bounds_.y - layoutScrollPos_; break; } @@ -915,25 +915,27 @@ bool ScrollView::SubviewFocused(View *view) { const float overscroll = std::min(view->GetBounds().h / 1.5f, GetBounds().h / 4.0f); float pos = ClampedScrollPos(scrollPos_); + float visibleSize = orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w; + float visibleEnd = scrollPos_ + visibleSize; + + float viewStart, viewEnd; switch (orientation_) { case ORIENT_HORIZONTAL: - if (vBounds.x2() > bounds_.x2()) { - ScrollTo(pos + vBounds.x2() - bounds_.x2() + overscroll); - } - if (vBounds.x < bounds_.x) { - ScrollTo(pos + (vBounds.x - bounds_.x) - overscroll); - } + viewStart = layoutScrollPos_ + vBounds.x - bounds_.x; + viewEnd = layoutScrollPos_ + vBounds.x2() - bounds_.x; break; case ORIENT_VERTICAL: - if (vBounds.y2() > bounds_.y2()) { - ScrollTo(pos + vBounds.y2() - bounds_.y2() + overscroll); - } - if (vBounds.y < bounds_.y) { - ScrollTo(pos + (vBounds.y - bounds_.y) - overscroll); - } + viewStart = layoutScrollPos_ + vBounds.y - bounds_.y; + viewEnd = layoutScrollPos_ + vBounds.y2() - bounds_.y; break; } + if (viewEnd > visibleEnd) { + ScrollTo(viewEnd - visibleSize + overscroll); + } else if (viewStart < pos) { + ScrollTo(viewStart - overscroll); + } + return true; } diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 3460cd7886..ad21b08a0f 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -300,6 +300,7 @@ private: float scrollTarget_ = 0.0f; int scrollTouchId_ = -1; bool scrollToTarget_ = false; + float layoutScrollPos_ = 0.0f; float inertia_ = 0.0f; float pull_ = 0.0f; float lastViewSize_ = 0.0f;