diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c index 6b725899e6..85fd2fcf1d 100644 --- a/gtk/gtkcolumnview.c +++ b/gtk/gtkcolumnview.c @@ -38,6 +38,7 @@ #include "gtkadjustment.h" #include "gtkgesturedrag.h" #include "gtkeventcontrollermotion.h" +#include "gtkdnd.h" /** * SECTION:gtkcolumnview @@ -71,8 +72,11 @@ struct _GtkColumnView GtkAdjustment *hadjustment; gboolean in_column_resize; + gboolean in_column_reorder; int drag_pos; int drag_x; + int drag_offset; + int drag_column_x; }; struct _GtkColumnViewClass @@ -220,6 +224,9 @@ gtk_column_view_allocate_columns (GtkColumnView *self, col_size = sizes[i].natural_size; gtk_column_view_column_allocate (column, x, col_size); + if (self->in_column_reorder && i == self->drag_pos) + gtk_column_view_column_set_header_position (column, self->drag_x); + x += col_size; } @@ -558,6 +565,23 @@ gtk_column_view_in_resize_rect (GtkColumnView *self, return graphene_rect_contains_point (&rect, &(graphene_point_t) { x, y}); } +static gboolean +gtk_column_view_in_header (GtkColumnView *self, + GtkColumnViewColumn *column, + double x, + double y) +{ + GtkWidget *header; + graphene_rect_t rect; + + header = gtk_column_view_column_get_header (column); + + if (!gtk_widget_compute_bounds (header, self->header, &rect)) + return FALSE; + + return graphene_rect_contains_point (&rect, &(graphene_point_t) { x, y}); +} + static void header_drag_begin (GtkGestureDrag *gesture, double start_x, @@ -566,6 +590,8 @@ header_drag_begin (GtkGestureDrag *gesture, { int i, n; + self->drag_pos = -1; + n = g_list_model_get_n_items (G_LIST_MODEL (self->columns)); for (i = 0; !self->in_column_resize && i < n; i++) { @@ -587,6 +613,7 @@ header_drag_begin (GtkGestureDrag *gesture, gtk_column_view_column_get_allocation (column, NULL, &size); gtk_column_view_column_set_fixed_width (column, size); + self->drag_pos = i; self->drag_x = start_x - size; self->in_column_resize = TRUE; @@ -595,6 +622,20 @@ header_drag_begin (GtkGestureDrag *gesture, break; } + if (gtk_column_view_column_get_reorderable (column) && + gtk_column_view_in_header (self, column, start_x, start_y)) + { + int pos; + + gtk_column_view_column_get_allocation (column, &pos, NULL); + + self->drag_pos = i; + self->drag_offset = start_x - pos; + + g_object_unref (column); + break; + } + g_object_unref (column); } } @@ -605,7 +646,49 @@ header_drag_end (GtkGestureDrag *gesture, double offset_y, GtkColumnView *self) { - self->in_column_resize = FALSE; + double start_x, x; + + gtk_gesture_drag_get_start_point (gesture, &start_x, NULL); + x = start_x + offset_x; + + if (self->in_column_resize) + { + self->in_column_resize = FALSE; + } + else if (self->in_column_reorder) + { + GtkColumnViewColumn *column; + GtkWidget *header; + int i; + + column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos); + header = gtk_column_view_column_get_header (column); + gtk_style_context_remove_class (gtk_widget_get_style_context (header), "dnd"); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++) + { + GtkColumnViewColumn *col = g_list_model_get_item (G_LIST_MODEL (self->columns), i); + + if (gtk_column_view_column_get_visible (col)) + { + int pos, size; + + gtk_column_view_column_get_allocation (col, &pos, &size); + if (pos <= x && x <= pos + size) + { + gtk_column_view_insert_column (self, i, column); + g_object_unref (col); + break; + } + } + + g_object_unref (col); + } + + g_object_unref (column); + + self->in_column_reorder = FALSE; + } } static void @@ -619,6 +702,25 @@ update_column_resize (GtkColumnView *self, g_object_unref (column); } +static void +update_column_reorder (GtkColumnView *self, + double x) +{ + GtkColumnViewColumn *column; + int width; + int size; + + column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos); + width = gtk_widget_get_allocated_width (GTK_WIDGET (self->header)); + gtk_column_view_column_get_allocation (column, NULL, &size); + + self->drag_x = CLAMP (x - self->drag_offset, 0, width - size); + + gtk_widget_queue_allocate (GTK_WIDGET (self)); + gtk_column_view_column_queue_resize (column); + g_object_unref (column); +} + static void header_drag_update (GtkGestureDrag *gesture, double offset_x, @@ -627,11 +729,37 @@ header_drag_update (GtkGestureDrag *gesture, { double start_x, x; + if (self->drag_pos == -1) + return; + + + if (!self->in_column_resize && !self->in_column_reorder) + { + if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0)) + { + GtkColumnViewColumn *column; + GtkWidget *header; + + column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos); + header = gtk_column_view_column_get_header (column); + + gtk_widget_insert_after (header, self->header, gtk_widget_get_last_child (self->header)); + gtk_style_context_add_class (gtk_widget_get_style_context (header), "dnd"); + + gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED); + self->in_column_reorder = TRUE; + + g_object_unref (column); + } + } + gtk_gesture_drag_get_start_point (gesture, &start_x, NULL); x = start_x + offset_x; if (self->in_column_resize) update_column_resize (self, x); + else if (self->in_column_reorder) + update_column_reorder (self, x); } static void