From 86363ffe6e8b9f437ee42a3c18dbc0de97cdbdf5 Mon Sep 17 00:00:00 2001 From: FrHun <28605587+frhun@users.noreply.github.com> Date: Tue, 2 Nov 2021 12:01:18 +0100 Subject: [PATCH] LibGUI: Add visual clue to Scrollbar gutter This adds a visual clue to scrolling by clicking on the Scrollbar gutter. This gives the user a hint that scrolling will continue in the direction of the darkened gutter, until the mouse is released. It is inspired by very similar behavior on old windows. --- Userland/Libraries/LibGUI/Scrollbar.cpp | 40 +++++++++++++++++++++++-- Userland/Libraries/LibGUI/Scrollbar.h | 7 +++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibGUI/Scrollbar.cpp b/Userland/Libraries/LibGUI/Scrollbar.cpp index df8bab1687..b6c108a196 100644 --- a/Userland/Libraries/LibGUI/Scrollbar.cpp +++ b/Userland/Libraries/LibGUI/Scrollbar.cpp @@ -174,6 +174,30 @@ void Scrollbar::paint_event(PaintEvent& event) hovered_component_for_painting = Component::None; painter.fill_rect_with_dither_pattern(rect(), palette().button().lightened(1.3f), palette().button()); + if (gutter_click_state != GutterClickState::NotPressed && has_scrubber() && hovered_component_for_painting == Component::Gutter) { + VERIFY(!scrubber_rect().is_null()); + Gfx::IntRect rect_to_fill = rect(); + if (orientation() == Orientation::Vertical) { + if (gutter_click_state == GutterClickState::BeforeScrubber) { + rect_to_fill.set_top(decrement_button_rect().bottom()); + rect_to_fill.set_bottom(scrubber_rect().top()); + } else { + VERIFY(gutter_click_state == GutterClickState::AfterScrubber); + rect_to_fill.set_top(scrubber_rect().bottom()); + rect_to_fill.set_bottom(increment_button_rect().top()); + } + } else { + if (gutter_click_state == GutterClickState::BeforeScrubber) { + rect_to_fill.set_left(decrement_button_rect().right()); + rect_to_fill.set_right(scrubber_rect().left()); + } else { + VERIFY(gutter_click_state == GutterClickState::AfterScrubber); + rect_to_fill.set_left(scrubber_rect().right()); + rect_to_fill.set_right(increment_button_rect().left()); + } + } + painter.fill_rect_with_dither_pattern(rect_to_fill, palette().button(), palette().button().lightened(0.77f)); + } bool decrement_pressed = (m_pressed_component == Component::DecrementButton) && (m_pressed_component == m_hovered_component); bool increment_pressed = (m_pressed_component == Component::IncrementButton) && (m_pressed_component == m_hovered_component); @@ -213,9 +237,15 @@ void Scrollbar::on_automatic_scrolling_timer_fired() } if (m_pressed_component == Component::Gutter && component_at_position(m_last_mouse_position) == Component::Gutter) { scroll_by_page(m_last_mouse_position); - m_hovered_component = component_at_position(m_last_mouse_position); + if (m_hovered_component != component_at_position(m_last_mouse_position)) { + m_hovered_component = component_at_position(m_last_mouse_position); + if (m_hovered_component != Component::Gutter) + gutter_click_state = GutterClickState::NotPressed; + update(); + } return; } + gutter_click_state = GutterClickState::NotPressed; } void Scrollbar::mousedown_event(MouseEvent& event) @@ -286,6 +316,7 @@ void Scrollbar::set_automatic_scrolling_active(bool active, Component pressed_co m_automatic_scrolling_timer->start(); } else { m_automatic_scrolling_timer->stop(); + gutter_click_state = GutterClickState::NotPressed; } } @@ -296,10 +327,13 @@ void Scrollbar::scroll_by_page(const Gfx::IntPoint& click_position) float rel_scrubber_size = unclamped_scrubber_size() / available; float page_increment = range_size * rel_scrubber_size; - if (click_position.primary_offset_for_orientation(orientation()) < scrubber_rect().primary_offset_for_orientation(orientation())) + if (click_position.primary_offset_for_orientation(orientation()) < scrubber_rect().primary_offset_for_orientation(orientation())) { + gutter_click_state = GutterClickState::BeforeScrubber; set_value(value() - page_increment); - else + } else { + gutter_click_state = GutterClickState::AfterScrubber; set_value(value() + page_increment); + } } void Scrollbar::scroll_to_position(const Gfx::IntPoint& click_position) diff --git a/Userland/Libraries/LibGUI/Scrollbar.h b/Userland/Libraries/LibGUI/Scrollbar.h index 4e46264db5..a7330c45e1 100644 --- a/Userland/Libraries/LibGUI/Scrollbar.h +++ b/Userland/Libraries/LibGUI/Scrollbar.h @@ -41,6 +41,13 @@ protected: virtual void change_event(Event&) override; private: + enum class GutterClickState { + NotPressed, + BeforeScrubber, + AfterScrubber, + } gutter_click_state + = GutterClickState::NotPressed; + int default_button_size() const { return 16; } int button_size() const { return length(orientation()) <= (default_button_size() * 2) ? length(orientation()) / 2 : default_button_size(); } int button_width() const { return orientation() == Orientation::Vertical ? width() : button_size(); }