From 8c1a06815927cc4fc6114cddc4a6bf96f613ed5e Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 13 Mar 2022 06:41:58 +0000 Subject: [PATCH] Allow dragging scroll bar for overscroll on Haiku * src/haiku_support.cc (class EmacsScrollBar): New fields `in_overscroll', `can_overscroll', `last_overscroll', `last_reported_overscroll_value' and `max_value'. (ValueChanged): Make very sure extraneous value are not generated. (MouseUp): Clear overscroll if enabled. (MouseMoved): If overscroll is enabled and dragging downwards fails to dislodge the maximum value, enable overscrolling. (BView_scroll_bar_update): New parameter `can_overscroll' * src/haiku_support.h: Update prototypes. * src/haikuterm.c (haiku_set_scroll_bar_thumb) (haiku_set_horizontal_scroll_bar_thumb): Adjust parameters to scroll bar update functions. (haiku_read_socket): Take ceiling of bar position if horizontal. --- src/haiku_support.cc | 126 +++++++++++++++++++++++++++++++++++++++---- src/haiku_support.h | 2 +- src/haikuterm.c | 11 ++-- 3 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/haiku_support.cc b/src/haiku_support.cc index 6b33245f64c..ecd93dd226a 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -1565,6 +1565,11 @@ public: /* True if button events should be passed to the parent. */ bool handle_button = false; + bool in_overscroll = false; + bool can_overscroll = false; + BPoint last_overscroll; + int last_reported_overscroll_value; + int max_value; EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p) : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ? @@ -1580,23 +1585,54 @@ public: void MessageReceived (BMessage *msg) { - int32 portion, range; + int32 portion, range, dragging, value; float proportion; if (msg->what == SCROLL_BAR_UPDATE) { - old_value = msg->GetInt32 ("emacs:units", 0); portion = msg->GetInt32 ("emacs:portion", 0); range = msg->GetInt32 ("emacs:range", 0); + dragging = msg->GetInt32 ("emacs:dragging", 0); proportion = (float) portion / range; + value = msg->GetInt32 ("emacs:units", 0); + can_overscroll = msg->GetBool ("emacs:overscroll", false); + value = std::max (0, value); - if (!msg->GetBool ("emacs:dragging", false)) + if (dragging != 1) { - /* Unlike on Motif, PORTION isn't included in the total - range of the scroll bar. */ - this->SetRange (0, range - portion); - this->SetValue (old_value); - this->SetProportion (proportion); + if (in_overscroll || dragging != -1) + { + /* Set the value to the smallest possible one. + Otherwise, the call to SetRange could lead to + spurious updates. */ + old_value = 0; + SetValue (0); + + /* Unlike on Motif, PORTION isn't included in the total + range of the scroll bar. */ + + SetRange (0, range - portion); + SetProportion (proportion); + max_value = range - portion; + + if (in_overscroll || value > max_value) + value = max_value; + + old_value = roundf (value); + SetValue (old_value); + } + else + { + value = Value (); + + old_value = 0; + SetValue (0); + SetRange (0, range - portion); + SetProportion (proportion); + old_value = value; + SetValue (value); + max_value = range - portion; + } } } @@ -1609,6 +1645,8 @@ public: struct haiku_scroll_bar_value_event rq; struct haiku_scroll_bar_part_event part; + new_value = Value (); + if (dragging) { if (new_value != old_value) @@ -1781,6 +1819,8 @@ public: struct haiku_scroll_bar_drag_event rq; BView *parent; + in_overscroll = false; + if (handle_button) { handle_button = false; @@ -1804,7 +1844,13 @@ public: MouseMoved (BPoint point, uint32 transit, const BMessage *msg) { struct haiku_menu_bar_left_event rq; + struct haiku_scroll_bar_value_event value_event; + int range, diff, value, trough_size; + BRect bounds; BPoint conv; + uint32 buttons; + + GetMouse (NULL, &buttons, false); if (transit == B_EXITED_VIEW) { @@ -1821,6 +1867,61 @@ public: } } + if (in_overscroll) + { + diff = point.y - last_overscroll.y; + + if (diff < 0) + { + in_overscroll = false; + goto allow; + } + + range = max_value; + bounds = Bounds (); + bounds.InsetBy (1.0, 1.0); + value = Value (); + trough_size = BE_RECT_HEIGHT (bounds); + trough_size -= BE_RECT_WIDTH (bounds) / 2; + if (info.double_arrows) + trough_size -= BE_RECT_WIDTH (bounds) / 2; + + value += ((double) range / trough_size) * diff * 2; + + if (value != last_reported_overscroll_value) + { + last_reported_overscroll_value = value; + last_overscroll = point; + + value_event.scroll_bar = this; + value_event.window = Window (); + value_event.position = value; + + haiku_write (SCROLL_BAR_VALUE_EVENT, &value_event); + return; + } + } + else if (can_overscroll && (buttons == B_PRIMARY_MOUSE_BUTTON)) + { + value = Value (); + + if (value >= max_value) + { + BScrollBar::MouseMoved (point, transit, msg); + + if (value == Value () && Proportion () < 1.0f) + { + in_overscroll = true; + last_overscroll = point; + last_reported_overscroll_value = value; + + MouseMoved (point, transit, msg); + return; + } + } + } + + allow: BScrollBar::MouseMoved (point, transit, msg); } }; @@ -2314,9 +2415,13 @@ BView_move_frame (void *view, int x, int y, int x1, int y1) vw->UnlockLooper (); } +/* DRAGGING can either be 0 (which means to update everything), 1 + (which means to update nothing), or -1 (which means to update only + the thumb size and range). */ + void BView_scroll_bar_update (void *sb, int portion, int whole, int position, - bool dragging) + int dragging, bool can_overscroll) { BScrollBar *bar = (BScrollBar *) sb; BMessage msg = BMessage (SCROLL_BAR_UPDATE); @@ -2324,7 +2429,8 @@ BView_scroll_bar_update (void *sb, int portion, int whole, int position, msg.AddInt32 ("emacs:range", whole); msg.AddInt32 ("emacs:units", position); msg.AddInt32 ("emacs:portion", portion); - msg.AddBool ("emacs:dragging", dragging); + msg.AddInt32 ("emacs:dragging", dragging); + msg.AddBool ("emacs:overscroll", can_overscroll); mr.SendMessage (&msg); } diff --git a/src/haiku_support.h b/src/haiku_support.h index e7c55d4d758..8b21fafad73 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -629,7 +629,7 @@ extern "C" extern void BView_scroll_bar_update (void *sb, int portion, int whole, int position, - bool dragging); + int dragging, bool can_overscroll); extern int BScrollBar_default_size (int horizontal_p); diff --git a/src/haikuterm.c b/src/haikuterm.c index cd0dcb08342..c98ab13e1a9 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -485,7 +485,10 @@ haiku_set_scroll_bar_thumb (struct scroll_bar *bar, int portion, } BView_scroll_bar_update (scroll_bar, lrint (size), - BE_SB_MAX, ceil (value), bar->dragging); + BE_SB_MAX, ceil (value), + (scroll_bar_adjust_thumb_portion_p + ? bar->dragging : bar->dragging ? -1 : 0), + !scroll_bar_adjust_thumb_portion_p); } static void @@ -505,7 +508,7 @@ haiku_set_horizontal_scroll_bar_thumb (struct scroll_bar *bar, int portion, bar->page_size = size; BView_scroll_bar_update (scroll_bar, lrint (size), BE_SB_MAX, - ceil (value), bar->dragging); + ceil (value), bar->dragging, false); } static struct scroll_bar * @@ -3282,8 +3285,8 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) if (bar->horizontal) { - portion = bar->total * ((float) b->position - / BE_SB_MAX); + portion = bar->total * ceil ((double) b->position + / BE_SB_MAX); whole = (bar->total * ((float) (BE_SB_MAX - bar->page_size) / BE_SB_MAX)); -- 2.39.5