Bläddra i källkod

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.
Marcus Nilsson 3 år sedan
förälder
incheckning
d660e86d13

+ 2 - 1
Userland/Libraries/LibGUI/AbstractScrollableWidget.h

@@ -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 {

+ 10 - 0
Userland/Libraries/LibGUI/AbstractTableView.cpp

@@ -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);
+}
+
 }
 }

+ 2 - 0
Userland/Libraries/LibGUI/AbstractTableView.h

@@ -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&);

+ 23 - 4
Userland/Libraries/LibGUI/AbstractView.cpp

@@ -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());
-        if (acceptable)
-            new_drop_candidate_index = index;
+    bool acceptable = model()->accepts_drag(index, event.mime_types());
+
+    if (acceptable && index.is_valid())
+        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());
 }
 }
 
 
 }
 }

+ 4 - 0
Userland/Libraries/LibGUI/AbstractView.h

@@ -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 {};
 };
 };
 
 
 }
 }

+ 4 - 2
Userland/Libraries/LibGUI/FileSystemModel.cpp

@@ -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();
 }
 }