summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-12-20 17:29:35 -0500
committerMatthias Clasen <mclasen@redhat.com>2020-05-30 20:01:14 -0400
commitbb06fffab1dcade95534ebed77adae2ede4c9526 (patch)
tree46c1c14d53fc21ac39919e63b0d4e84b9b3d46d8
parent94c5b00231cffc39770f577cc2a28e6dc6071692 (diff)
downloadgtk+-bb06fffab1dcade95534ebed77adae2ede4c9526.tar.gz
columnview: Interactive column reordering
Allow rearranging columns by dragging, in the same way the treeview does. We add the "dnd" style class to the header while it is dragged, and we move the header of the dragged column to the end of its parents children, so that it gets drawn on top.
-rw-r--r--gtk/gtkcolumnview.c130
1 files changed, 129 insertions, 1 deletions
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 19976614a0..1daabc6c5b 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -38,6 +38,7 @@
#include "gtkadjustment.h"
#include "gtkgesturedrag.h"
#include "gtkeventcontrollermotion.h"
+#include "gtkdragsource.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
@@ -221,6 +225,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;
}
@@ -579,6 +586,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,
@@ -587,6 +611,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++)
{
@@ -608,6 +634,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;
@@ -616,6 +643,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);
}
}
@@ -626,7 +667,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
@@ -641,6 +724,25 @@ update_column_resize (GtkColumnView *self,
}
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,
double offset_y,
@@ -648,11 +750,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