1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 19:27:35 +00:00

LibGUI: Add a AutoScroll timer to AbstractScrollableWidget

This commit adds a timer to AbstractScrollableWidget that can be used
when implementing automatic scrolling. By overriding
on_automatic_scrolling_timer_fired() we can calculate the scrolling
delta when dragging objects, and redraw as needed. A helper function,
automatic_scroll_delta_from_position() gives us a delta that
we can use to calculate speed and direction. By default
m_autoscroll_threshold is 20 pixels from the edge, and gives a linear
change in scroll delta.
This commit is contained in:
Marcus Nilsson 2021-09-16 19:00:09 +02:00 committed by Andreas Kling
parent 522119ab95
commit eec411c508
2 changed files with 47 additions and 0 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/Timer.h>
#include <LibGUI/AbstractScrollableWidget.h>
#include <LibGUI/Scrollbar.h>
@ -28,6 +29,12 @@ AbstractScrollableWidget::AbstractScrollableWidget()
m_corner_widget = add<Widget>();
m_corner_widget->set_fill_with_background_color(true);
m_automatic_scrolling_timer = add<Core::Timer>();
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();

View file

@ -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<Core::Timer> m_automatic_scrolling_timer;
bool m_active_scrolling_enabled { false };
int m_autoscroll_threshold { 20 };
};
}