forked from AuroraMiddleware/gtk
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.
This commit is contained in:
parent
11b4e0d4c0
commit
5d4893b3f0
@ -38,6 +38,7 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolumnview
|
||||
@ -73,8 +74,11 @@ struct _GtkColumnView
|
||||
gboolean reorderable;
|
||||
|
||||
gboolean in_column_resize;
|
||||
gboolean in_column_reorder;
|
||||
int drag_pos;
|
||||
int drag_x;
|
||||
int drag_offset;
|
||||
int drag_column_x;
|
||||
};
|
||||
|
||||
struct _GtkColumnViewClass
|
||||
@ -224,6 +228,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;
|
||||
}
|
||||
|
||||
@ -602,6 +609,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,
|
||||
@ -610,6 +634,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++)
|
||||
{
|
||||
@ -631,6 +657,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;
|
||||
@ -639,6 +666,20 @@ header_drag_begin (GtkGestureDrag *gesture,
|
||||
break;
|
||||
}
|
||||
|
||||
if (gtk_column_view_get_reorderable (self) &&
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -649,7 +690,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
|
||||
@ -663,6 +746,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,
|
||||
@ -671,11 +773,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
|
||||
|
Loading…
Reference in New Issue
Block a user