Jelajahi Sumber

LibGUI: Let ScrollableWidget handle the wheel events of its ScrollBars

Route the ScrollBar's wheel event to the ScrollableWidget so it can
handle it itself. This allows it to handle it consistently (e.g.
speed) when the cursor is hovering the scroll bars rather than the
widget's contents.

Fixes #5419
Tom 4 tahun lalu
induk
melakukan
a0cbb9068b

+ 3 - 2
Userland/Libraries/LibGUI/ScrollBar.h

@@ -31,7 +31,7 @@
 
 namespace GUI {
 
-class ScrollBar final : public AbstractSlider {
+class ScrollBar : public AbstractSlider {
     C_OBJECT(ScrollBar);
 
 public:
@@ -49,7 +49,7 @@ public:
         Scrubber,
     };
 
-private:
+protected:
     explicit ScrollBar(Gfx::Orientation = Gfx::Orientation::Vertical);
 
     virtual void paint_event(PaintEvent&) override;
@@ -60,6 +60,7 @@ private:
     virtual void leave_event(Core::Event&) override;
     virtual void change_event(Event&) override;
 
+private:
     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(); }

+ 9 - 4
Userland/Libraries/LibGUI/ScrollableWidget.cpp

@@ -31,14 +31,14 @@ namespace GUI {
 
 ScrollableWidget::ScrollableWidget()
 {
-    m_vertical_scrollbar = add<ScrollBar>(Orientation::Vertical);
+    m_vertical_scrollbar = add<ScrollableWidgetScrollBar>(*this, Orientation::Vertical);
     m_vertical_scrollbar->set_step(4);
     m_vertical_scrollbar->on_change = [this](int) {
         did_scroll();
         update();
     };
 
-    m_horizontal_scrollbar = add<ScrollBar>(Orientation::Horizontal);
+    m_horizontal_scrollbar = add<ScrollableWidgetScrollBar>(*this, Orientation::Horizontal);
     m_horizontal_scrollbar->set_step(4);
     m_horizontal_scrollbar->set_page_step(30);
     m_horizontal_scrollbar->on_change = [this](int) {
@@ -54,20 +54,25 @@ ScrollableWidget::~ScrollableWidget()
 {
 }
 
-void ScrollableWidget::mousewheel_event(MouseEvent& event)
+void ScrollableWidget::handle_wheel_event(MouseEvent& event, Widget& event_source)
 {
     if (!m_scrollbars_enabled) {
         event.ignore();
         return;
     }
     // FIXME: The wheel delta multiplier should probably come from... somewhere?
-    if (event.shift()) {
+    if (event.shift() || &event_source == m_horizontal_scrollbar.ptr()) {
         horizontal_scrollbar().set_value(horizontal_scrollbar().value() + event.wheel_delta() * 60);
     } else {
         vertical_scrollbar().set_value(vertical_scrollbar().value() + event.wheel_delta() * 20);
     }
 }
 
+void ScrollableWidget::mousewheel_event(MouseEvent& event)
+{
+    handle_wheel_event(event, *this);
+}
+
 void ScrollableWidget::custom_layout()
 {
     auto inner_rect = frame_inner_rect_for_size(size());

+ 24 - 2
Userland/Libraries/LibGUI/ScrollableWidget.h

@@ -27,6 +27,7 @@
 #pragma once
 
 #include <LibGUI/Frame.h>
+#include <LibGUI/ScrollBar.h>
 
 namespace GUI {
 
@@ -91,10 +92,31 @@ protected:
     void set_size_occupied_by_fixed_elements(const Gfx::IntSize&);
 
 private:
+    class ScrollableWidgetScrollBar final : public ScrollBar {
+        C_OBJECT(ScrollableWidgetScrollBar);
+
+    protected:
+        explicit ScrollableWidgetScrollBar(ScrollableWidget& owner, Gfx::Orientation orientation)
+            : ScrollBar(orientation)
+            , m_owner(owner)
+        {
+        }
+
+        virtual void mousewheel_event(MouseEvent& event) override
+        {
+            m_owner.handle_wheel_event(event, *this);
+        }
+
+    private:
+        ScrollableWidget& m_owner;
+    };
+    friend class ScrollableWidgetScrollBar;
+
     void update_scrollbar_ranges();
+    void handle_wheel_event(MouseEvent&, Widget&);
 
-    RefPtr<ScrollBar> m_vertical_scrollbar;
-    RefPtr<ScrollBar> m_horizontal_scrollbar;
+    RefPtr<ScrollableWidgetScrollBar> m_vertical_scrollbar;
+    RefPtr<ScrollableWidgetScrollBar> m_horizontal_scrollbar;
     RefPtr<Widget> m_corner_widget;
     Gfx::IntSize m_content_size;
     Gfx::IntSize m_size_occupied_by_fixed_elements;