mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
UI: Handle focus on page up/down.
This moves keyboard focus along with paging, but it also only responds to paging when already focused inside the scroll view.
This commit is contained in:
parent
8df188af2b
commit
b52a495b96
3 changed files with 102 additions and 8 deletions
|
@ -448,6 +448,7 @@ public:
|
|||
|
||||
// Fake RTTI
|
||||
virtual bool IsViewGroup() const { return false; }
|
||||
virtual bool ContainsSubview(const View *view) const { return false; }
|
||||
|
||||
Point GetFocusPosition(FocusDirection dir);
|
||||
|
||||
|
|
|
@ -57,6 +57,14 @@ void ViewGroup::RemoveSubview(View *view) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ViewGroup::ContainsSubview(const View *view) const {
|
||||
for (const View *subview : views_) {
|
||||
if (subview == view || subview->ContainsSubview(view))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewGroup::Clear() {
|
||||
std::lock_guard<std::mutex> guard(modifyLock_);
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
|
@ -444,11 +452,57 @@ NeighborResult ViewGroup::FindNeighbor(View *view, FocusDirection direction, Nei
|
|||
return result;
|
||||
}
|
||||
|
||||
case FOCUS_PREV_PAGE:
|
||||
case FOCUS_NEXT_PAGE:
|
||||
return FindScrollNeighbor(view, Point(INFINITY, INFINITY), direction, result);
|
||||
|
||||
default:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
float GetTargetScore(const Point &target, View *view) {
|
||||
if (!view->CanBeFocused())
|
||||
return 0.0f;
|
||||
if (view->IsEnabled() == false)
|
||||
return 0.0f;
|
||||
if (view->GetVisibility() != V_VISIBLE)
|
||||
return 0.0f;
|
||||
|
||||
Point viewPos = view->GetBounds().Center();
|
||||
float dx = viewPos.x - target.x;
|
||||
float dy = viewPos.y - target.y;
|
||||
|
||||
float distance = sqrtf(dx * dx + dy * dy);
|
||||
return 10.0f / std::max(1.0f, distance);
|
||||
}
|
||||
|
||||
NeighborResult ViewGroup::FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) {
|
||||
if (!IsEnabled())
|
||||
return best;
|
||||
if (GetVisibility() != V_VISIBLE)
|
||||
return best;
|
||||
|
||||
if (target.x < INFINITY && target.y < INFINITY) {
|
||||
for (auto v : views_) {
|
||||
// Note: we consider the origin itself, which might already be the best option.
|
||||
float score = GetTargetScore(target, v);
|
||||
if (score > best.score) {
|
||||
best.score = score;
|
||||
best.view = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto v : views_) {
|
||||
if (v->IsViewGroup()) {
|
||||
ViewGroup *vg = static_cast<ViewGroup *>(v);
|
||||
if (vg)
|
||||
best = vg->FindScrollNeighbor(view, target, direction, best);
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
// TODO: This code needs some cleanup/restructuring...
|
||||
void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
|
@ -792,12 +846,6 @@ bool ScrollView::Key(const KeyInput &input) {
|
|||
case NKCODE_EXT_MOUSEWHEEL_DOWN:
|
||||
ScrollRelative(250);
|
||||
break;
|
||||
case NKCODE_PAGE_DOWN:
|
||||
ScrollRelative((orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w) - 50);
|
||||
break;
|
||||
case NKCODE_PAGE_UP:
|
||||
ScrollRelative(-(orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w) + 50);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ViewGroup::Key(input);
|
||||
|
@ -903,6 +951,47 @@ bool ScrollView::SubviewFocused(View *view) {
|
|||
return true;
|
||||
}
|
||||
|
||||
NeighborResult ScrollView::FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) {
|
||||
if (ContainsSubview(view) && views_[0]->IsViewGroup()) {
|
||||
ViewGroup *vg = static_cast<ViewGroup *>(views_[0]);
|
||||
int found = -1;
|
||||
for (int i = 0, n = vg->GetNumSubviews(); i < n; ++i) {
|
||||
View *child = vg->GetViewByIndex(i);
|
||||
if (child == view || child->ContainsSubview(view)) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, the previously focused view is inside this.
|
||||
if (found != -1) {
|
||||
float mult = 0.0f;
|
||||
switch (direction) {
|
||||
case FOCUS_PREV_PAGE:
|
||||
mult = -1.0f;
|
||||
break;
|
||||
case FOCUS_NEXT_PAGE:
|
||||
mult = 1.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Okay, now where is our ideal target?
|
||||
Point targetPos = view->GetBounds().Center();
|
||||
if (orientation_ == ORIENT_VERTICAL)
|
||||
targetPos.y += mult * bounds_.h;
|
||||
else
|
||||
targetPos.x += mult * bounds_.x;
|
||||
|
||||
// Okay, which subview is closest to that?
|
||||
return vg->FindScrollNeighbor(view, targetPos, direction, best);
|
||||
}
|
||||
}
|
||||
|
||||
return ViewGroup::FindScrollNeighbor(view, target, direction, best);
|
||||
}
|
||||
|
||||
void ScrollView::PersistData(PersistStatus status, std::string anonId, PersistMap &storage) {
|
||||
ViewGroup::PersistData(status, anonId, storage);
|
||||
|
||||
|
|
|
@ -63,9 +63,11 @@ public:
|
|||
|
||||
// Assumes that layout has taken place.
|
||||
NeighborResult FindNeighbor(View *view, FocusDirection direction, NeighborResult best);
|
||||
virtual NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best);
|
||||
|
||||
virtual bool CanBeFocused() const override { return false; }
|
||||
virtual bool IsViewGroup() const override { return true; }
|
||||
bool CanBeFocused() const override { return false; }
|
||||
bool IsViewGroup() const override { return true; }
|
||||
bool ContainsSubview(const View *view) const override;
|
||||
|
||||
virtual void SetBG(const Drawable &bg) { bg_ = bg; }
|
||||
|
||||
|
@ -268,6 +270,8 @@ public:
|
|||
void PersistData(PersistStatus status, std::string anonId, PersistMap &storage) override;
|
||||
void SetVisibility(Visibility visibility) override;
|
||||
|
||||
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; }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue