mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 17:55:08 +00:00
LibGUI: Implement automatic scrolling in AbstractView
This adds automatic scrolling when dragging items in TreeViews and other widgets that inherit from AbstractView when the overloaded accepts_drag() returns true. This is implemented in FileSystemModel to allow directories and files to be dragged.
This commit is contained in:
parent
53cfc6ec9f
commit
d660e86d13
6 changed files with 45 additions and 7 deletions
|
@ -52,7 +52,7 @@ public:
|
||||||
void scroll_to_bottom();
|
void scroll_to_bottom();
|
||||||
|
|
||||||
void set_automatic_scrolling_timer(bool active);
|
void set_automatic_scrolling_timer(bool active);
|
||||||
Gfx::IntPoint automatic_scroll_delta_from_position(const Gfx::IntPoint&) const;
|
virtual Gfx::IntPoint automatic_scroll_delta_from_position(const Gfx::IntPoint&) const;
|
||||||
|
|
||||||
int width_occupied_by_vertical_scrollbar() const;
|
int width_occupied_by_vertical_scrollbar() const;
|
||||||
int height_occupied_by_horizontal_scrollbar() const;
|
int height_occupied_by_horizontal_scrollbar() const;
|
||||||
|
@ -75,6 +75,7 @@ protected:
|
||||||
void set_content_size(const Gfx::IntSize&);
|
void set_content_size(const Gfx::IntSize&);
|
||||||
void set_size_occupied_by_fixed_elements(const Gfx::IntSize&);
|
void set_size_occupied_by_fixed_elements(const Gfx::IntSize&);
|
||||||
virtual void on_automatic_scrolling_timer_fired() {};
|
virtual void on_automatic_scrolling_timer_fired() {};
|
||||||
|
int autoscroll_threshold() const { return m_autoscroll_threshold; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class AbstractScrollableWidgetScrollbar final : public Scrollbar {
|
class AbstractScrollableWidgetScrollbar final : public Scrollbar {
|
||||||
|
|
|
@ -460,4 +460,14 @@ bool AbstractTableView::is_navigation(GUI::KeyEvent& event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx::IntPoint AbstractTableView::automatic_scroll_delta_from_position(const Gfx::IntPoint& pos) const
|
||||||
|
{
|
||||||
|
if (pos.y() > column_header().height() + autoscroll_threshold())
|
||||||
|
return AbstractScrollableWidget::automatic_scroll_delta_from_position(pos);
|
||||||
|
|
||||||
|
Gfx::IntPoint position_excluding_header = { pos.x(), pos.y() - column_header().height() };
|
||||||
|
return AbstractScrollableWidget::automatic_scroll_delta_from_position(position_excluding_header);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,8 @@ protected:
|
||||||
|
|
||||||
void move_cursor_relative(int vertical_steps, int horizontal_steps, SelectionUpdate);
|
void move_cursor_relative(int vertical_steps, int horizontal_steps, SelectionUpdate);
|
||||||
|
|
||||||
|
virtual Gfx::IntPoint automatic_scroll_delta_from_position(const Gfx::IntPoint& pos) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void layout_headers();
|
void layout_headers();
|
||||||
bool is_navigation(GUI::KeyEvent&);
|
bool is_navigation(GUI::KeyEvent&);
|
||||||
|
|
|
@ -335,6 +335,8 @@ void AbstractView::mouseup_event(MouseEvent& event)
|
||||||
if (!model())
|
if (!model())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
set_automatic_scrolling_timer(false);
|
||||||
|
|
||||||
if (m_might_drag) {
|
if (m_might_drag) {
|
||||||
// We were unsure about unselecting items other than the current one
|
// We were unsure about unselecting items other than the current one
|
||||||
// in mousedown_event(), because we could be seeing a start of a drag.
|
// in mousedown_event(), because we could be seeing a start of a drag.
|
||||||
|
@ -759,13 +761,19 @@ void AbstractView::drag_move_event(DragEvent& event)
|
||||||
{
|
{
|
||||||
if (!model())
|
if (!model())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto index = index_at_event_position(event.position());
|
auto index = index_at_event_position(event.position());
|
||||||
ModelIndex new_drop_candidate_index;
|
ModelIndex new_drop_candidate_index;
|
||||||
if (index.is_valid()) {
|
bool acceptable = model()->accepts_drag(index, event.mime_types());
|
||||||
bool acceptable = model()->accepts_drag(index, event.mime_types());
|
|
||||||
if (acceptable)
|
if (acceptable && index.is_valid())
|
||||||
new_drop_candidate_index = index;
|
new_drop_candidate_index = index;
|
||||||
|
|
||||||
|
if (acceptable) {
|
||||||
|
m_automatic_scroll_delta = automatic_scroll_delta_from_position(event.position());
|
||||||
|
set_automatic_scrolling_timer(!m_automatic_scroll_delta.is_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_drop_candidate_index != new_drop_candidate_index) {
|
if (m_drop_candidate_index != new_drop_candidate_index) {
|
||||||
m_drop_candidate_index = new_drop_candidate_index;
|
m_drop_candidate_index = new_drop_candidate_index;
|
||||||
update();
|
update();
|
||||||
|
@ -780,6 +788,17 @@ void AbstractView::drag_leave_event(Event&)
|
||||||
m_drop_candidate_index = {};
|
m_drop_candidate_index = {};
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_automatic_scrolling_timer(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractView::on_automatic_scrolling_timer_fired()
|
||||||
|
{
|
||||||
|
if (m_automatic_scroll_delta.is_null())
|
||||||
|
return;
|
||||||
|
|
||||||
|
vertical_scrollbar().set_value(vertical_scrollbar().value() + m_automatic_scroll_delta.y());
|
||||||
|
horizontal_scrollbar().set_value(horizontal_scrollbar().value() + m_automatic_scroll_delta.x());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,8 @@ protected:
|
||||||
virtual void hide_event(HideEvent&) override;
|
virtual void hide_event(HideEvent&) override;
|
||||||
virtual void focusin_event(FocusEvent&) override;
|
virtual void focusin_event(FocusEvent&) override;
|
||||||
|
|
||||||
|
virtual void on_automatic_scrolling_timer_fired() override;
|
||||||
|
|
||||||
virtual void clear_selection();
|
virtual void clear_selection();
|
||||||
virtual void set_selection(ModelIndex const&);
|
virtual void set_selection(ModelIndex const&);
|
||||||
virtual void set_selection_start_index(ModelIndex const&);
|
virtual void set_selection_start_index(ModelIndex const&);
|
||||||
|
@ -202,6 +204,8 @@ private:
|
||||||
bool m_is_dragging { false };
|
bool m_is_dragging { false };
|
||||||
bool m_draw_item_text_with_shadow { false };
|
bool m_draw_item_text_with_shadow { false };
|
||||||
bool m_suppress_update_on_selection_change { false };
|
bool m_suppress_update_on_selection_change { false };
|
||||||
|
|
||||||
|
Gfx::IntPoint m_automatic_scroll_delta {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -711,10 +711,12 @@ String FileSystemModel::column_name(int column) const
|
||||||
|
|
||||||
bool FileSystemModel::accepts_drag(ModelIndex const& index, Vector<String> const& mime_types) const
|
bool FileSystemModel::accepts_drag(ModelIndex const& index, Vector<String> const& mime_types) const
|
||||||
{
|
{
|
||||||
if (!index.is_valid())
|
|
||||||
return false;
|
|
||||||
if (!mime_types.contains_slow("text/uri-list"))
|
if (!mime_types.contains_slow("text/uri-list"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!index.is_valid())
|
||||||
|
return true;
|
||||||
|
|
||||||
auto& node = this->node(index);
|
auto& node = this->node(index);
|
||||||
return node.is_directory();
|
return node.is_directory();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue