From ef4690d511e051a75ec948fab00035e3f5007939 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 2 Sep 2011 20:04:06 -0400 Subject: GtkGrid: make attaching more flexible Allow to attach children at either end of row/column 0. Proposed by Alex Larsson. https://bugzilla.gnome.org/show_bug.cgi?id=657793 --- gtk/gtkgrid.c | 189 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 65 deletions(-) (limited to 'gtk/gtkgrid.c') diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c index cfb21f41ba..df6d74daec 100644 --- a/gtk/gtkgrid.c +++ b/gtk/gtkgrid.c @@ -363,41 +363,93 @@ gtk_grid_init (GtkGrid *grid) priv->linedata[1].homogeneous = FALSE; } -static void grid_attach (GtkGrid *grid, - GtkWidget *child, - gint left, - gint top, - gint width, - gint height); - static void -gtk_grid_add (GtkContainer *container, - GtkWidget *child) +grid_attach (GtkGrid *grid, + GtkWidget *widget, + gint left, + gint top, + gint width, + gint height) +{ + GtkGridPrivate *priv = grid->priv; + GtkGridChild *child; + + child = g_slice_new (GtkGridChild); + child->widget = widget; + CHILD_LEFT (child) = left; + CHILD_TOP (child) = top; + CHILD_WIDTH (child) = width; + CHILD_HEIGHT (child) = height; + + priv->children = g_list_prepend (priv->children, child); + + gtk_widget_set_parent (widget, GTK_WIDGET (grid)); +} + +/* Find the position 'touching' existing + * children. @orientation and @max determine + * from which direction to approach (horizontal + * + max = right, vertical + !max = top, etc). + * @op_pos, @op_span determine the rows/columns + * in which the touching has to happen. + */ +static gint +find_attach_position (GtkGrid *grid, + GtkOrientation orientation, + gint op_pos, + gint op_span, + gboolean max) { - GtkGrid *grid = GTK_GRID (container); GtkGridPrivate *priv = grid->priv; GtkGridChild *grid_child; GtkGridChildAttach *attach; GtkGridChildAttach *opposite; GList *list; gint pos; + gboolean hit; + + if (max) + pos = -G_MAXINT; + else + pos = G_MAXINT; + + hit = FALSE; - pos = 0; for (list = priv->children; list; list = list->next) { grid_child = list->data; - attach = &grid_child->attach[priv->orientation]; - opposite = &grid_child->attach[1 - priv->orientation]; + attach = &grid_child->attach[orientation]; + opposite = &grid_child->attach[1 - orientation]; + + /* check if the ranges overlap */ + if (opposite->pos <= op_pos + op_span && op_pos <= opposite->pos + opposite->span) + { + hit = TRUE; - if (opposite->pos <= 0 && opposite->pos + opposite->span > 0) - pos = MAX (pos, attach->pos + attach->span); + if (max) + pos = MAX (pos, attach->pos + attach->span); + else + pos = MIN (pos, attach->pos); + } } - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - grid_attach (grid, child, pos, 0, 1, 1); - else - grid_attach (grid, child, 0, pos, 1, 1); + if (!hit) + pos = 0; + + return pos; +} + +static void +gtk_grid_add (GtkContainer *container, + GtkWidget *child) +{ + GtkGrid *grid = GTK_GRID (container); + GtkGridPrivate *priv = grid->priv; + gint pos[2] = { 0, 0 }; + + pos[priv->orientation] = find_attach_position (grid, priv->orientation, 0, 1, TRUE); + grid_attach (grid, child, pos[0], pos[1], 1, 1); } static void @@ -1365,29 +1417,6 @@ gtk_grid_new (void) return g_object_new (GTK_TYPE_GRID, NULL); } -static void -grid_attach (GtkGrid *grid, - GtkWidget *widget, - gint left, - gint top, - gint width, - gint height) -{ - GtkGridPrivate *priv = grid->priv; - GtkGridChild *child; - - child = g_slice_new (GtkGridChild); - child->widget = widget; - CHILD_LEFT (child) = left; - CHILD_TOP (child) = top; - CHILD_WIDTH (child) = width; - CHILD_HEIGHT (child) = height; - - priv->children = g_list_prepend (priv->children, child); - - gtk_widget_set_parent (widget, GTK_WIDGET (grid)); -} - /** * gtk_grid_attach: * @grid: a #GtkGrid @@ -1424,7 +1453,8 @@ gtk_grid_attach (GtkGrid *grid, * gtk_grid_attach_next_to: * @grid: a #GtkGrid * @child: the widget to add - * @sibling: the child of @grid that @child will be placed next to + * @sibling (allow-none): the child of @grid that @child will be placed + * next to, or %NULL to place @child at the beginning or end * @side: the side of @sibling that @child is positioned next to * @width: the number of columns that @child will span * @height: the number of rows that @child will span @@ -1432,7 +1462,9 @@ gtk_grid_attach (GtkGrid *grid, * Adds a widget to the grid. * * The widget is placed next to @sibling, on the side determined by - * @side. + * @side. When @sibling is %NULL, the widget is placed in row (for + * left or right placement) or column 0 (for top or bottom placement), + * at the end indicated by @side. */ void gtk_grid_attach_next_to (GtkGrid *grid, @@ -1448,32 +1480,59 @@ gtk_grid_attach_next_to (GtkGrid *grid, g_return_if_fail (GTK_IS_GRID (grid)); g_return_if_fail (GTK_IS_WIDGET (child)); g_return_if_fail (gtk_widget_get_parent (child) == NULL); - g_return_if_fail (gtk_widget_get_parent (sibling) == (GtkWidget*)grid); + g_return_if_fail (sibling == NULL || gtk_widget_get_parent (sibling) == (GtkWidget*)grid); g_return_if_fail (width > 0); g_return_if_fail (height > 0); - grid_sibling = find_grid_child (grid, sibling); + if (sibling) + { + grid_sibling = find_grid_child (grid, sibling); - switch (side) + switch (side) + { + case GTK_POS_LEFT: + left = CHILD_LEFT (grid_sibling) - width; + top = CHILD_TOP (grid_sibling); + break; + case GTK_POS_RIGHT: + left = CHILD_LEFT (grid_sibling) + CHILD_WIDTH (grid_sibling); + top = CHILD_TOP (grid_sibling); + break; + case GTK_POS_TOP: + left = CHILD_LEFT (grid_sibling); + top = CHILD_TOP (grid_sibling) - height; + break; + case GTK_POS_BOTTOM: + left = CHILD_LEFT (grid_sibling); + top = CHILD_TOP (grid_sibling) + CHILD_HEIGHT (grid_sibling); + break; + default: + g_assert_not_reached (); + } + } + else { - case GTK_POS_LEFT: - left = CHILD_LEFT (grid_sibling) - width; - top = CHILD_TOP (grid_sibling); - break; - case GTK_POS_RIGHT: - left = CHILD_LEFT (grid_sibling) + CHILD_WIDTH (grid_sibling); - top = CHILD_TOP (grid_sibling); - break; - case GTK_POS_TOP: - left = CHILD_LEFT (grid_sibling); - top = CHILD_TOP (grid_sibling) - height; - break; - case GTK_POS_BOTTOM: - left = CHILD_LEFT (grid_sibling); - top = CHILD_TOP (grid_sibling) + CHILD_HEIGHT (grid_sibling); - break; - default: - g_assert_not_reached (); + switch (side) + { + case GTK_POS_LEFT: + left = find_attach_position (grid, GTK_ORIENTATION_HORIZONTAL, 0, height, TRUE); + top = 0; + break; + case GTK_POS_RIGHT: + left = find_attach_position (grid, GTK_ORIENTATION_HORIZONTAL, 0, height, FALSE); + top = 0; + break; + case GTK_POS_TOP: + left = 0; + top = find_attach_position (grid, GTK_ORIENTATION_VERTICAL, 0, width, TRUE); + break; + case GTK_POS_BOTTOM: + left = 0; + top = find_attach_position (grid, GTK_ORIENTATION_VERTICAL, 0, width, FALSE); + break; + default: + g_assert_not_reached (); + } } grid_attach (grid, child, left, top, width, height); -- cgit v1.2.1