diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 9b816f2767..ba8a9ef1bf 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; } } } @@ -793,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: @@ -801,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: @@ -810,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; } @@ -913,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; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 8e0471643b..31f7fe761d 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" @@ -45,10 +46,10 @@ 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_; } + private: void Refresh(); @@ -67,30 +68,22 @@ 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_; }; -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(); } -void SingleControlMapper::Update() { - if (refresh_) { - refresh_ = false; - Refresh(); - host->UpdateUI(); - } -} - void SingleControlMapper::Refresh() { - bool hasFocus = UI::GetFocusedView() == this; Clear(); auto mc = GetI18NCategory("MappableControls"); @@ -117,17 +110,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 +130,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); } @@ -162,30 +153,31 @@ 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) { 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; - ctrlScreen_->KeyMapped(pspKey_); - // After this, we do not exist any more. So the refresh_ = true is probably irrelevant. } UI::EventReturn SingleControlMapper::OnReplace(UI::EventParams ¶ms) { @@ -221,7 +213,11 @@ 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(); + else + SetFocus(); return UI::EVENT_DONE; } @@ -260,8 +256,9 @@ 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); } @@ -314,13 +311,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; @@ -1007,6 +997,7 @@ public: MockPSP(UI::LayoutParams *layoutParams = nullptr); void SelectButton(int btn); + void FocusButton(int btn); float GetPopupOffset(); UI::Event ButtonClick; @@ -1053,6 +1044,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) @@ -1162,8 +1159,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_]; @@ -1177,6 +1179,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); 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: