diff --git a/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp b/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp index 3f9430427c..6ca74f6834 100644 --- a/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp +++ b/Userland/Libraries/LibGUI/AbstractScrollableWidget.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include @@ -28,6 +29,12 @@ AbstractScrollableWidget::AbstractScrollableWidget() m_corner_widget = add(); m_corner_widget->set_fill_with_background_color(true); + + m_automatic_scrolling_timer = add(); + m_automatic_scrolling_timer->set_interval(50); + m_automatic_scrolling_timer->on_timeout = [this] { + on_automatic_scrolling_timer_fired(); + }; } AbstractScrollableWidget::~AbstractScrollableWidget() @@ -214,6 +221,38 @@ void AbstractScrollableWidget::scroll_to_bottom() scroll_into_view({ 0, content_height(), 0, 0 }, Orientation::Vertical); } +void AbstractScrollableWidget::set_automatic_scrolling_timer(bool active) +{ + if (active == m_active_scrolling_enabled) + return; + + m_active_scrolling_enabled = active; + + if (active) { + on_automatic_scrolling_timer_fired(); + m_automatic_scrolling_timer->start(); + } else { + m_automatic_scrolling_timer->stop(); + } +} + +Gfx::IntPoint AbstractScrollableWidget::automatic_scroll_delta_from_position(const Gfx::IntPoint& pos) const +{ + Gfx::IntPoint delta { 0, 0 }; + + if (pos.y() < m_autoscroll_threshold) + delta.set_y(clamp(-(m_autoscroll_threshold - pos.y()), -m_autoscroll_threshold, 0)); + else if (pos.y() > height() - m_autoscroll_threshold) + delta.set_y(clamp(m_autoscroll_threshold - (height() - pos.y()), 0, m_autoscroll_threshold)); + + if (pos.x() < m_autoscroll_threshold) + delta.set_x(clamp(-(m_autoscroll_threshold - pos.x()), -m_autoscroll_threshold, 0)); + else if (pos.x() > width() - m_autoscroll_threshold) + delta.set_x(clamp(m_autoscroll_threshold - (width() - pos.x()), 0, m_autoscroll_threshold)); + + return delta; +} + Gfx::IntRect AbstractScrollableWidget::widget_inner_rect() const { auto rect = frame_inner_rect(); diff --git a/Userland/Libraries/LibGUI/AbstractScrollableWidget.h b/Userland/Libraries/LibGUI/AbstractScrollableWidget.h index 11d8c234a3..4f977b3f31 100644 --- a/Userland/Libraries/LibGUI/AbstractScrollableWidget.h +++ b/Userland/Libraries/LibGUI/AbstractScrollableWidget.h @@ -51,6 +51,9 @@ public: void scroll_to_top(); void scroll_to_bottom(); + void set_automatic_scrolling_timer(bool active); + Gfx::IntPoint automatic_scroll_delta_from_position(const Gfx::IntPoint&) const; + int width_occupied_by_vertical_scrollbar() const; int height_occupied_by_horizontal_scrollbar() const; @@ -71,6 +74,7 @@ protected: virtual void did_scroll() { } void set_content_size(const Gfx::IntSize&); void set_size_occupied_by_fixed_elements(const Gfx::IntSize&); + virtual void on_automatic_scrolling_timer_fired() {}; private: class AbstractScrollableWidgetScrollbar final : public Scrollbar { @@ -103,6 +107,10 @@ private: Gfx::IntSize m_size_occupied_by_fixed_elements; bool m_scrollbars_enabled { true }; bool m_should_hide_unnecessary_scrollbars { false }; + + RefPtr m_automatic_scrolling_timer; + bool m_active_scrolling_enabled { false }; + int m_autoscroll_threshold { 20 }; }; }