[libegg/spread-table-dnd] Make EggSpreadTableDnd override the ->build_segments_for_size vfunc and ->size_allocate vfunc.
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libegg/spread-table-dnd] Make EggSpreadTableDnd override the ->build_segments_for_size vfunc and ->size_allocate vfunc.
- Date: Mon, 11 Apr 2011 18:49:29 +0000 (UTC)
commit e54a8ad9116b524bc9ae9961c41900b60f60af27
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Mon Apr 11 14:45:03 2011 +0900
Make EggSpreadTableDnd override the ->build_segments_for_size vfunc and ->size_allocate vfunc.
Now EggSpreadTableDnd manages table configuration locking privately and
overrides size_allocate() to help avoid some flicker when dragging items
around in the same row.
libegg/spreadtable/eggspreadtablednd.c | 351 ++++++++++++++++++++++++++------
1 files changed, 287 insertions(+), 64 deletions(-)
---
diff --git a/libegg/spreadtable/eggspreadtablednd.c b/libegg/spreadtable/eggspreadtablednd.c
index 88e949e..ceb5156 100644
--- a/libegg/spreadtable/eggspreadtablednd.c
+++ b/libegg/spreadtable/eggspreadtablednd.c
@@ -38,6 +38,8 @@ static gboolean egg_spread_table_dnd_button_press (GtkWidget
GdkEventButton *event);
static gboolean egg_spread_table_dnd_button_release (GtkWidget *widget,
GdkEventButton *event);
+static void egg_spread_table_dnd_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
/* GtkWidgetClass drag-source */
static void egg_spread_table_dnd_drag_data_get (GtkWidget *widget,
@@ -69,13 +71,16 @@ static void egg_spread_table_dnd_drag_data_received (GtkWidget
guint time);
/* GtkContainerClass */
-static void egg_spread_table_dnd_remove (GtkContainer *container,
- GtkWidget *child);
+static void egg_spread_table_dnd_remove (GtkContainer *container,
+ GtkWidget *child);
/* EggSpreadTableClass */
-static void egg_spread_table_dnd_insert_child (EggSpreadTable *spread_table,
- GtkWidget *child,
- gint index);
+static void egg_spread_table_dnd_insert_child (EggSpreadTable *spread_table,
+ GtkWidget *child,
+ gint index);
+static gint egg_spread_table_dnd_build_segments (EggSpreadTable *table,
+ gint for_size,
+ gint **segments);
/* EggSpreadTableDndClass */
static gboolean egg_spread_table_dnd_drop_possible(EggSpreadTableDnd *table,
@@ -110,6 +115,12 @@ static gboolean boolean_handled_accumulator (GSignalInvocationHint *i
static gboolean drop_possible (EggSpreadTableDnd *spread_table,
GtkWidget *widget);
+static void adjust_line_segment (EggSpreadTableDnd *table,
+ gint segment,
+ gint offset);
+static void lock_table (EggSpreadTableDnd *spread_table);
+static void unlock_table (EggSpreadTableDnd *spread_table);
+
typedef struct {
EggSpreadTableDnd *table;
@@ -135,6 +146,10 @@ struct _EggSpreadTableDndPrivate {
gint pressed_button;
gint press_start_x;
gint press_start_y;
+
+ /* Caching and locking the child configuration */
+ gint *locked_config;
+
};
@@ -164,6 +179,7 @@ egg_spread_table_dnd_class_init (EggSpreadTableDndClass *class)
widget_class->button_press_event = egg_spread_table_dnd_button_press;
widget_class->button_release_event = egg_spread_table_dnd_button_release;
widget_class->motion_notify_event = egg_spread_table_dnd_motion;
+ widget_class->size_allocate = egg_spread_table_dnd_size_allocate;
/* Drag source */
widget_class->drag_data_get = egg_spread_table_dnd_drag_data_get;
@@ -176,7 +192,8 @@ egg_spread_table_dnd_class_init (EggSpreadTableDndClass *class)
container_class->remove = egg_spread_table_dnd_remove;
- spread_class->insert_child = egg_spread_table_dnd_insert_child;
+ spread_class->insert_child = egg_spread_table_dnd_insert_child;
+ spread_class->build_segments_for_size = egg_spread_table_dnd_build_segments;
class->widget_drop_possible = egg_spread_table_dnd_drop_possible;
@@ -335,6 +352,172 @@ egg_spread_table_dnd_button_release (GtkWidget *widget,
return TRUE;
}
+static void
+get_widget_size (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint for_size,
+ gint *min_size,
+ gint *nat_size)
+{
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (for_size < 0)
+ gtk_widget_get_preferred_width (widget, min_size, nat_size);
+ else
+ gtk_widget_get_preferred_width_for_height (widget, for_size, min_size, nat_size);
+ }
+ else
+ {
+ if (for_size < 0)
+ gtk_widget_get_preferred_height (widget, min_size, nat_size);
+ else
+ gtk_widget_get_preferred_height_for_width (widget, for_size, min_size, nat_size);
+ }
+}
+
+static void
+allocate_child (EggSpreadTableDnd *table,
+ GtkWidget *child,
+ gint item_offset,
+ gint line_offset,
+ gint item_size,
+ gint line_size)
+{
+ GtkAllocation widget_allocation;
+ GtkAllocation child_allocation;
+ GtkOrientation orientation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (table), &widget_allocation);
+ orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (table));
+
+ if (gtk_widget_get_has_window (GTK_WIDGET (table)))
+ {
+ widget_allocation.x = 0;
+ widget_allocation.y = 0;
+ }
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ child_allocation.x = widget_allocation.x + item_offset;
+ child_allocation.y = widget_allocation.y + line_offset;
+ child_allocation.width = item_size;
+ child_allocation.height = line_size;
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ child_allocation.x = widget_allocation.x + line_offset;
+ child_allocation.y = widget_allocation.y + item_offset;
+ child_allocation.width = line_size;
+ child_allocation.height = item_size;
+ }
+
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+get_spread_table_dimentions (EggSpreadTableDnd *spread_table,
+ gint *line_spacing,
+ gint *item_spacing,
+ gint *full_size,
+ gint *line_width)
+{
+ EggSpreadTable *table = EGG_SPREAD_TABLE (spread_table);
+ gint local_full_size, local_item_spacing, local_spacing;
+ gint lines = egg_spread_table_get_lines (table);
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (table), &allocation);
+
+ if (gtk_orientable_get_orientation (GTK_ORIENTABLE (table)) == GTK_ORIENTATION_VERTICAL)
+ {
+ local_full_size = allocation.width;
+ local_spacing = egg_spread_table_get_horizontal_spacing (table);
+ local_item_spacing = egg_spread_table_get_vertical_spacing (table);
+ }
+ else
+ {
+ local_full_size = allocation.height;
+ local_spacing = egg_spread_table_get_vertical_spacing (table);
+ local_item_spacing = egg_spread_table_get_horizontal_spacing (table);
+ }
+
+ if (full_size)
+ *full_size = local_full_size;
+ if (line_spacing)
+ *line_spacing = local_spacing;
+ if (item_spacing)
+ *item_spacing = local_item_spacing;
+
+ if (line_width)
+ *line_width = (local_full_size - (local_spacing * (lines -1))) / lines;
+}
+
+static void
+egg_spread_table_dnd_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EggSpreadTableDnd *table = EGG_SPREAD_TABLE_DND (widget);
+ GList *list, *children;
+ gint *segments = NULL;
+ gint full_thickness;
+ gint i, j;
+ gint line_offset, item_offset;
+ gint line_thickness;
+ gint line_spacing;
+ gint item_spacing;
+ gint placeholder_cnt = 0;
+ gint lines;
+ GtkWidgetClass *parent_parent_class;
+ GtkOrientation orientation;
+
+ /* Skip the EggSpreadTableClass allocator, chain up to it's parent to resize
+ * the GdkWindow properly */
+ parent_parent_class = g_type_class_peek_parent (egg_spread_table_dnd_parent_class);
+ parent_parent_class->size_allocate (widget, allocation);
+
+ get_spread_table_dimentions (table, &line_spacing, &item_spacing, &full_thickness, &line_thickness);
+ lines = egg_spread_table_get_lines (EGG_SPREAD_TABLE (table));
+ orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (table));
+
+ egg_spread_table_build_segments_for_size (EGG_SPREAD_TABLE (table), full_thickness, &segments);
+
+ children = gtk_container_get_children (GTK_CONTAINER (table));
+
+ for (list = children, line_offset = 0, i = 0; i < lines;
+ line_offset += line_thickness + line_spacing, i++)
+ {
+ /* Count the placeholders on each line */
+ placeholder_cnt = 0;
+
+ for (j = 0, item_offset = 0; list && j < segments[i]; list = list->next, j++)
+ {
+ GtkWidget *child = list->data;
+ gint child_size;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ get_widget_size (child, orientation, line_thickness, NULL, &child_size);
+
+ /* Stop allocating children on this line after 2 placeholders
+ * this avoids annoying flicker when moving a widget inside a single column */
+ if (placeholder_cnt >= 2)
+ continue;
+
+ if (placeholder_cnt < 2 && EGG_IS_PLACEHOLDER (child))
+ placeholder_cnt++;
+
+ allocate_child (table, child, item_offset, line_offset, child_size, line_thickness);
+
+ item_offset += child_size + item_spacing;
+ }
+ }
+
+ g_list_free (children);
+ g_free (segments);
+}
+
+
/*****************************************************
* GtkWidgetClass drag source *
*****************************************************/
@@ -380,27 +563,17 @@ get_child_line (EggSpreadTableDnd *table,
}
static void
-adjust_line_segment (EggSpreadTableDnd *spread_table,
- gint line,
- gint offset)
-{
- gint *segments;
-
- segments = egg_spread_table_get_segments (EGG_SPREAD_TABLE (spread_table));
- g_return_if_fail (segments[line] + offset >= 0);
- egg_spread_table_set_segment_length (EGG_SPREAD_TABLE (spread_table),
- line, segments[line] + offset);
- g_free (segments);
-}
-
-static void
placeholder_animated_out (GtkWidget *placeholder,
EggSpreadTableDnd *spread_table)
{
gint line = -1;
+ gboolean last_target = FALSE;
if (spread_table->priv->drop_target == placeholder)
- spread_table->priv->drop_target = NULL;
+ {
+ spread_table->priv->drop_target = NULL;
+ last_target = TRUE;
+ }
if (spread_table->priv->dragging)
line = get_child_line (spread_table, placeholder);
@@ -410,9 +583,9 @@ placeholder_animated_out (GtkWidget *placeholder,
/* Adjust line segment here manually since table may be locked */
if (spread_table->priv->dragging)
adjust_line_segment (spread_table, line, -1);
- else
+ else if (last_target)
/* Unlock the table after the drag is finished */
- egg_spread_table_unlock (EGG_SPREAD_TABLE (spread_table));
+ unlock_table (spread_table);
spread_table->priv->disappearing--;
}
@@ -443,39 +616,6 @@ egg_spread_table_dnd_drag_leave (GtkWidget *widget,
}
static void
-get_spread_table_dimentions (EggSpreadTableDnd *spread_table,
- gint *line_spacing,
- gint *full_size,
- gint *line_width)
-{
- EggSpreadTable *table = EGG_SPREAD_TABLE (spread_table);
- gint local_full_size, local_spacing;
- gint lines = egg_spread_table_get_lines (table);
- GtkAllocation allocation;
-
- gtk_widget_get_allocation (GTK_WIDGET (table), &allocation);
-
- if (gtk_orientable_get_orientation (GTK_ORIENTABLE (table)) == GTK_ORIENTATION_VERTICAL)
- {
- local_full_size = allocation.width;
- local_spacing = egg_spread_table_get_horizontal_spacing (table);
- }
- else
- {
- local_full_size = allocation.height;
- local_spacing = egg_spread_table_get_vertical_spacing (table);
- }
-
- if (full_size)
- *full_size = local_full_size;
- if (line_spacing)
- *line_spacing = local_spacing;
-
- if (line_width)
- *line_width = (local_full_size - (local_spacing * (lines -1))) / lines;
-}
-
-static void
get_placeholder_size (EggSpreadTableDnd *spread_table,
gint *width,
gint *height)
@@ -484,7 +624,7 @@ get_placeholder_size (EggSpreadTableDnd *spread_table,
gint line_width;
/* Calculate the size of the required placeholder based on the dimentions of the drag widget */
- get_spread_table_dimentions (spread_table, NULL, NULL, &line_width);
+ get_spread_table_dimentions (spread_table, NULL, NULL, NULL, &line_width);
if (orientation == GTK_ORIENTATION_VERTICAL)
{
@@ -528,7 +668,7 @@ egg_spread_table_dnd_drag_motion (GtkWidget *widget,
if (!drop_possible (spread_table, spread_table->priv->drag_data.child))
return FALSE;
- egg_spread_table_lock (EGG_SPREAD_TABLE (spread_table));
+ lock_table (spread_table);
spread_table->priv->dragging = TRUE;
/* Dont do anything until the currently drop target placeholder finishes animating in */
@@ -605,7 +745,7 @@ egg_spread_table_dnd_drag_drop (GtkWidget *widget,
/* Get the appropriate target index */
gtk_container_child_get (GTK_CONTAINER (spread_table),
- spread_table->priv->drop_target,
+ spread_table->priv->drop_target,
"position", &drop_index,
NULL);
@@ -618,9 +758,11 @@ egg_spread_table_dnd_drag_drop (GtkWidget *widget,
/* Ensure visibility */
gtk_widget_show (spread_table->priv->drag_data.child);
- /* Unlock the target spread table, any other spread table
- * should have been unlocked at drag_leave time */
- egg_spread_table_unlock (EGG_SPREAD_TABLE (spread_table));
+ /* Hide the drop target placeholder in the target spread table,
+ * it will be removed and the spread table unlocked after animating out
+ * (the placeholder started animating out at "drag-leave" time).
+ */
+ gtk_widget_hide (spread_table->priv->drop_target);
gtk_drag_finish (context, TRUE, TRUE, time_);
return TRUE;
@@ -703,6 +845,60 @@ egg_spread_table_dnd_insert_child (EggSpreadTable *spread_table,
}
}
+static gint
+egg_spread_table_dnd_build_segments (EggSpreadTable *table,
+ gint for_size,
+ gint **segments)
+{
+ EggSpreadTableDnd *dnd_table = EGG_SPREAD_TABLE_DND (table);
+ EggSpreadTableDndPrivate *priv = dnd_table->priv;
+ GList *l, *children;
+ gint line = 0, i = 0, lines;
+ gint largest_line = 0, line_size = 0, widget_size;
+ gint line_thickness;
+ gint spacing;
+ GtkOrientation orientation;
+
+ if (!priv->locked_config)
+ return EGG_SPREAD_TABLE_CLASS
+ (egg_spread_table_dnd_parent_class)->build_segments_for_size (table, for_size, segments);
+
+ get_spread_table_dimentions (dnd_table, NULL, &spacing, NULL, &line_thickness);
+
+ children = gtk_container_get_children (GTK_CONTAINER (table));
+ orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (table));
+ lines = egg_spread_table_get_lines (table);
+
+ for (l = children; l && line < lines; l = l->next)
+ {
+ GtkWidget *child = l->data;
+
+ if (!gtk_widget_get_visible (child))
+ continue;
+
+ get_widget_size (child, orientation, line_thickness, NULL, &widget_size);
+
+ line_size += widget_size;
+ if (i > 0)
+ line_size += spacing;
+
+ if (i++ >= priv->locked_config[line])
+ {
+ largest_line = MAX (largest_line, line_size);
+
+ line_size = 0;
+ i = 0;
+ line++;
+ }
+ }
+
+ if (segments)
+ *segments = g_memdup (priv->locked_config, lines * sizeof (gint));
+
+ return largest_line;
+}
+
+
/*****************************************************
* EggSpreadTableDndClass *
*****************************************************/
@@ -726,7 +922,7 @@ drag_begin (GtkWidget *widget,
gint drop_index;
/* Mark the spread table for an active drag */
- egg_spread_table_lock (EGG_SPREAD_TABLE (spread_table));
+ lock_table (spread_table);
spread_table->priv->dragging = TRUE;
/* Just assign a drag child, this is only important for
@@ -811,7 +1007,7 @@ get_index_at_position (EggSpreadTableDnd *spread_table,
lines = egg_spread_table_get_lines (table);
segments = egg_spread_table_get_segments (table);
- get_spread_table_dimentions (spread_table, &spacing, &full_size, &line_width);
+ get_spread_table_dimentions (spread_table, &spacing, NULL, &full_size, &line_width);
if (orientation == GTK_ORIENTATION_VERTICAL)
position = x;
@@ -958,6 +1154,33 @@ boolean_handled_accumulator (GSignalInvocationHint *ihint,
return continue_emission;
}
+static void
+adjust_line_segment (EggSpreadTableDnd *table,
+ gint segment,
+ gint offset)
+{
+ if (table->priv->locked_config)
+ table->priv->locked_config[segment] += offset;
+}
+
+static void
+lock_table (EggSpreadTableDnd *table)
+
+{
+ if (table->priv->locked_config == NULL)
+ table->priv->locked_config = egg_spread_table_get_segments (EGG_SPREAD_TABLE (table));
+}
+
+static void
+unlock_table (EggSpreadTableDnd *table)
+{
+
+ g_free (table->priv->locked_config);
+ table->priv->locked_config = NULL;
+
+ gtk_widget_queue_resize (GTK_WIDGET (table));
+}
+
/*****************************************************
* API *
*****************************************************/
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]