Skip to content

Commit

Permalink
Merge pull request #16785 from hrydgard/scrollview-dragbar
Browse files Browse the repository at this point in the history
UI: Make vertical scrollbars directly draggable
  • Loading branch information
hrydgard committed Jan 11, 2023
2 parents 725f9ad + 69ff11f commit eeca797
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 17 deletions.
86 changes: 69 additions & 17 deletions Common/UI/ScrollView.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Common/UI/Context.h"
#include "Common/UI/ScrollView.h"
#include "Common/Data/Text/I18n.h"
#include "Common/Log.h"

namespace UI {

Expand Down Expand Up @@ -134,7 +135,15 @@ const float friction = 0.92f;
const float stop_threshold = 0.1f;

bool ScrollView::Touch(const TouchInput &input) {
if ((input.flags & TOUCH_DOWN) && scrollTouchId_ == -1) {
if ((input.flags & TOUCH_DOWN) && scrollTouchId_ == -1 && bounds_.Contains(input.x, input.y)) {
if (orientation_ == ORIENT_VERTICAL) {
Bob bob = ComputeBob();
float internalY = input.y - bounds_.y;
draggingBob_ = internalY >= bob.offset && internalY <= bob.offset + bob.size && input.x >= bounds_.x2() - 20.0f;
barDragStart_ = bob.offset;
barDragOffset_ = internalY - bob.offset;
}

scrollStart_ = scrollPos_;
inertia_ = 0.0f;
scrollTouchId_ = input.id;
Expand All @@ -148,17 +157,35 @@ bool ScrollView::Touch(const TouchInput &input) {
inertia_ = info[1];
}
scrollTouchId_ = -1;
draggingBob_ = false;
}

TouchInput input2;
if (CanScroll()) {
input2 = gesture_.Update(input, bounds_);
float info[4];
if (input.id == scrollTouchId_ && gesture_.GetGestureInfo(gesture, input.id, info) && !(input.flags & TOUCH_DOWN)) {
float pos = scrollStart_ - info[0];
scrollPos_ = pos;
scrollTarget_ = pos;
if (draggingBob_) {
input2 = input;
// Skip the gesture, do calculations directly.
// Might switch to the gesture later.
Bob bob = ComputeBob();
float internalY = input.y - bounds_.y;

float bobPos = internalY - barDragOffset_;
float bobDragMax = bounds_.h - bob.size;

float newScrollPos = Clamp(bobPos / bobDragMax, 0.0f, 1.0f) * bob.scrollMax;

scrollPos_ = newScrollPos;
scrollTarget_ = newScrollPos;
scrollToTarget_ = false;
} else {
input2 = gesture_.Update(input, bounds_);
float info[4];
if (input.id == scrollTouchId_ && gesture_.GetGestureInfo(gesture, input.id, info) && !(input.flags & TOUCH_DOWN)) {
float pos = scrollStart_ - info[0];
scrollPos_ = pos;
scrollTarget_ = pos;
scrollToTarget_ = false;
}
}
} else {
input2 = input;
Expand All @@ -173,6 +200,22 @@ bool ScrollView::Touch(const TouchInput &input) {
}
}

ScrollView::Bob ScrollView::ComputeBob() const {
Bob bob{};
float childHeight = std::max(0.01f, views_[0]->GetBounds().h);
float scrollMax = std::max(0.0f, childHeight - bounds_.h);
float ratio = bounds_.h / childHeight;

if (ratio < 1.0f && scrollMax > 0.0f) {
bob.show = true;
bob.thickness = draggingBob_ ? 15.0f : 5.0f;
bob.size = ratio * bounds_.h;
bob.offset = (HardClampedScrollPos(scrollPos_) / scrollMax) * (bounds_.h - bob.size);
bob.scrollMax = scrollMax;
}
return bob;
}

void ScrollView::Draw(UIContext &dc) {
if (!views_.size()) {
ViewGroup::Draw(dc);
Expand All @@ -187,18 +230,16 @@ void ScrollView::Draw(UIContext &dc) {
views_[0]->Draw(dc);
dc.PopScissor();

float childHeight = views_[0]->GetBounds().h;
float scrollMax = std::max(0.0f, childHeight - bounds_.h);

float ratio = bounds_.h / std::max(0.01f, views_[0]->GetBounds().h);
// Vertical scroll bob. We don't support a horizontal yet.
if (orientation_ != ORIENT_VERTICAL) {
return;
}

float bobWidth = 5;
if (ratio < 1.0f && scrollMax > 0.0f) {
float bobHeight = ratio * bounds_.h;
float bobOffset = (ClampedScrollPos(scrollPos_) / scrollMax) * (bounds_.h - bobHeight);
Bob bob = ComputeBob();

Bounds bob(bounds_.x2() - bobWidth, bounds_.y + bobOffset, bobWidth, bobHeight);
dc.FillRect(Drawable(0x80FFFFFF), bob);
if (bob.show) {
Bounds bobBounds(bounds_.x2() - bob.thickness, bounds_.y + bob.offset, bob.thickness, bob.size);
dc.FillRect(Drawable(0x80FFFFFF), bobBounds);
}
}

Expand Down Expand Up @@ -331,6 +372,16 @@ void ScrollView::ScrollRelative(float distance) {
scrollToTarget_ = true;
}

float ScrollView::HardClampedScrollPos(float pos) const {
if (!views_.size() || bounds_.h == 0.0f) {
return 0.0f;
}
float childSize = orientation_ == ORIENT_VERTICAL ? views_[0]->GetBounds().h : views_[0]->GetBounds().w;
float containerSize = (orientation_ == ORIENT_VERTICAL ? bounds_.h : bounds_.w);
float scrollMax = std::max(0.0f, childSize - containerSize);
return Clamp(pos, 0.0f, scrollMax);
}

float ScrollView::ClampedScrollPos(float pos) {
if (!views_.size() || bounds_.h == 0.0f) {
return 0.0f;
Expand All @@ -342,6 +393,7 @@ float ScrollView::ClampedScrollPos(float pos) {

Gesture gesture = orientation_ == ORIENT_VERTICAL ? GESTURE_DRAG_VERTICAL : GESTURE_DRAG_HORIZONTAL;

// TODO: Not all of this is properly orientation independent.
if (scrollTouchId_ >= 0 && gesture_.IsGestureActive(gesture, scrollTouchId_) && bounds_.h > 0.0f) {
float maxPull = bounds_.h * 0.1f;
if (pos < 0.0f) {
Expand Down
18 changes: 18 additions & 0 deletions Common/UI/ScrollView.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,22 @@ class ScrollView : public ViewGroup {
NeighborResult FindScrollNeighbor(View *view, const Point &target, FocusDirection direction, NeighborResult best) override;

private:
float HardClampedScrollPos(float pos) const;

// TODO: Don't adjust pull_ within this!
float ClampedScrollPos(float pos);

// The "bob" is the draggable thingy on a scroll bar. Don't know a better name for it.
struct Bob {
bool show;
float thickness;
float size;
float offset;
float scrollMax;
};

Bob ComputeBob() const;

GestureDetector gesture_;
Orientation orientation_;
float scrollPos_ = 0.0f;
Expand All @@ -62,6 +76,10 @@ class ScrollView : public ViewGroup {
float lastViewSize_ = 0.0f;
float *rememberPos_ = nullptr;
bool alignOpposite_ = false;
bool draggingBob_ = false;

float barDragStart_ = 0.0f;
float barDragOffset_ = 0.0f;

static float lastScrollPosX;
static float lastScrollPosY;
Expand Down

0 comments on commit eeca797

Please sign in to comment.