From 843468dbf8a2f7c1542823aff70a121a543a1e2c Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 21 Apr 2025 08:29:51 -0400 Subject: [PATCH] LibWeb: Enlarge scrollbars that are interacting with the mouse When a scrollbar is not interacting with the mouse, we now draw the scrollbar slightly slimmer. When the mouse enters the space occupied by the scrollbar, we enlarge it for easier mouse interactivity. --- Libraries/LibWeb/Painting/PaintableBox.cpp | 65 +++++++++++++++++++--- Libraries/LibWeb/Painting/PaintableBox.h | 4 ++ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index 56723d8325d..864beb73e34 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -357,7 +358,8 @@ bool PaintableBox::could_be_scrolled_by_wheel_event() const return could_be_scrolled_by_wheel_event(ScrollDirection::Horizontal) || could_be_scrolled_by_wheel_event(ScrollDirection::Vertical); } -static constexpr CSSPixels scrollbar_thumb_thickness = 8; +static constexpr CSSPixels SCROLLBAR_THUMB_NORMAL_THICKNESS = 5; +static constexpr CSSPixels SCROLLBAR_THUMB_WIDENED_THICKNESS = 10; Optional PaintableBox::scroll_thumb_rect(ScrollDirection direction) const { @@ -401,7 +403,13 @@ Optional PaintableBox::compute_scrollbar_data(Scrol if (scroll_overflow_size == 0) return {}; - auto scrollbar_rect_length = is_horizontal ? scrollport_size - scrollbar_thumb_thickness : scrollport_size; + auto thickness = [&]() { + if (is_horizontal) + return m_draw_enlarged_horizontal_scrollbar ? SCROLLBAR_THUMB_WIDENED_THICKNESS : SCROLLBAR_THUMB_NORMAL_THICKNESS; + return m_draw_enlarged_vertical_scrollbar ? SCROLLBAR_THUMB_WIDENED_THICKNESS : SCROLLBAR_THUMB_NORMAL_THICKNESS; + }(); + + auto scrollbar_rect_length = is_horizontal ? scrollport_size - thickness : scrollport_size; auto min_thumb_length = min(scrollbar_rect_length, 24); auto thumb_length = max(scrollbar_rect_length * (scrollport_size / scroll_overflow_size), min_thumb_length); @@ -411,9 +419,9 @@ Optional PaintableBox::compute_scrollbar_data(Scrol scroll_size = (scrollbar_rect_length - thumb_length) / (scroll_overflow_size - scrollport_size); CSSPixelRect rect; if (is_horizontal) - rect = { padding_rect.left(), padding_rect.bottom() - scrollbar_thumb_thickness, thumb_length, scrollbar_thumb_thickness }; + rect = { padding_rect.left(), padding_rect.bottom() - thickness, thumb_length, thickness }; else - rect = { padding_rect.right() - scrollbar_thumb_thickness, padding_rect.top(), scrollbar_thumb_thickness, thumb_length }; + rect = { padding_rect.right() - thickness, padding_rect.top(), thickness, thumb_length }; return PaintableBox::ScrollbarData { rect, scroll_size }; } @@ -953,9 +961,37 @@ Paintable::DispatchEventOfSameName PaintableBox::handle_mousemove(Badge= scrollbar_data->thumb_rect.top(); + return position.x() >= scrollbar_data->thumb_rect.left(); +} + bool PaintableBox::handle_mousewheel(Badge, CSSPixelPoint, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y) { // if none of the axes we scrolled with can be accepted by this element, don't handle scroll. @@ -979,12 +1015,25 @@ Layout::NodeWithStyleAndBoxModelMetrics& PaintableWithLines::layout_node_with_st TraversalDecision PaintableBox::hit_test_scrollbars(CSSPixelPoint position, Function const& callback) const { - auto vertical_scroll_thumb_rect = scroll_thumb_rect(ScrollDirection::Vertical); - if (vertical_scroll_thumb_rect.has_value() && vertical_scroll_thumb_rect.value().contains(position)) + // FIXME: This const_cast is not great, but this method is invoked from overrides of virtual const methods. + auto& self = const_cast(*this); + + if (self.scrollbar_contains_mouse_position(ScrollDirection::Horizontal, position)) return callback(HitTestResult { const_cast(*this) }); - auto horizontal_scroll_thumb_rect = scroll_thumb_rect(ScrollDirection::Horizontal); - if (horizontal_scroll_thumb_rect.has_value() && horizontal_scroll_thumb_rect.value().contains(position)) + + if (m_draw_enlarged_horizontal_scrollbar) { + self.m_draw_enlarged_horizontal_scrollbar = false; + self.set_needs_display(); + } + + if (self.scrollbar_contains_mouse_position(ScrollDirection::Vertical, position)) return callback(HitTestResult { const_cast(*this) }); + + if (m_draw_enlarged_vertical_scrollbar) { + self.m_draw_enlarged_vertical_scrollbar = false; + self.set_needs_display(); + } + return TraversalDecision::Continue; } diff --git a/Libraries/LibWeb/Painting/PaintableBox.h b/Libraries/LibWeb/Painting/PaintableBox.h index ae2be9a4687..11c589b259e 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Libraries/LibWeb/Painting/PaintableBox.h @@ -278,6 +278,8 @@ private: virtual DispatchEventOfSameName handle_mouseup(Badge, CSSPixelPoint, unsigned button, unsigned modifiers) override; virtual DispatchEventOfSameName handle_mousemove(Badge, CSSPixelPoint, unsigned buttons, unsigned modifiers) override; + bool scrollbar_contains_mouse_position(ScrollDirection, CSSPixelPoint); + OwnPtr m_stacking_context; Optional m_overflow_data; @@ -304,6 +306,8 @@ private: Optional m_last_mouse_tracking_position; Optional m_scroll_thumb_dragging_direction; + bool m_draw_enlarged_horizontal_scrollbar { false }; + bool m_draw_enlarged_vertical_scrollbar { false }; ResolvedBackground m_resolved_background;