[gtk+] GtkGrid: make attaching more flexible
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] GtkGrid: make attaching more flexible
- Date: Sat, 3 Sep 2011 00:07:52 +0000 (UTC)
commit ef4690d511e051a75ec948fab00035e3f5007939
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Sep 2 20:04:06 2011 -0400
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 +++++++++++++++++++++++++-------------
gtk/tests/Makefile.am | 4 +
gtk/tests/grid.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 366 insertions(+), 65 deletions(-)
---
diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c
index cfb21f4..df6d74d 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);
diff --git a/gtk/tests/Makefile.am b/gtk/tests/Makefile.am
index 4b2d344..b4d224c 100644
--- a/gtk/tests/Makefile.am
+++ b/gtk/tests/Makefile.am
@@ -123,6 +123,10 @@ TEST_PROGS += entry
entry_SOURCES = entry.c
entry_LDADD = $(progs_ldadd)
+TEST_PROGS += grid
+grid_SOURCES = grid.c
+grid_LDADD = $(progs_ldadd)
+
EXTRA_DIST += \
file-chooser-test-dir/empty \
file-chooser-test-dir/text.txt
diff --git a/gtk/tests/grid.c b/gtk/tests/grid.c
new file mode 100644
index 0000000..90be1fd
--- /dev/null
+++ b/gtk/tests/grid.c
@@ -0,0 +1,238 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+/* test that attach_next_to picks the places
+ * we expect it to pick, when there is any choice
+ */
+static void
+test_attach (void)
+{
+ GtkGrid *g;
+ GtkWidget *child, *sibling, *z, *A, *B;
+ gint left, top, width, height;
+
+ g = (GtkGrid *)gtk_grid_new ();
+
+ child = gtk_label_new ("a");
+ gtk_grid_attach_next_to (g, child, NULL, GTK_POS_LEFT, 1, 1);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 0);
+ g_assert_cmpint (top, ==, 0);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 1);
+
+ sibling = child;
+ child = gtk_label_new ("b");
+ gtk_grid_attach_next_to (g, child, sibling, GTK_POS_RIGHT, 2, 2);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 1);
+ g_assert_cmpint (top, ==, 0);
+ g_assert_cmpint (width, ==, 2);
+ g_assert_cmpint (height, ==, 2);
+
+ /* this one should just be ignored */
+ z = gtk_label_new ("z");
+ gtk_grid_attach (g, z, 4, 4, 1, 1);
+
+ child = gtk_label_new ("c");
+ gtk_grid_attach_next_to (g, child, sibling, GTK_POS_BOTTOM, 3, 1);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 0);
+ g_assert_cmpint (top, ==, 1);
+ g_assert_cmpint (width, ==, 3);
+ g_assert_cmpint (height, ==, 1);
+
+ child = gtk_label_new ("u");
+ gtk_grid_attach_next_to (g, child, z, GTK_POS_LEFT, 2, 1);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 2);
+ g_assert_cmpint (top, ==, 4);
+ g_assert_cmpint (width, ==, 2);
+ g_assert_cmpint (height, ==, 1);
+
+ child = gtk_label_new ("v");
+ gtk_grid_attach_next_to (g, child, z, GTK_POS_RIGHT, 2, 1);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 5);
+ g_assert_cmpint (top, ==, 4);
+ g_assert_cmpint (width, ==, 2);
+ g_assert_cmpint (height, ==, 1);
+
+ child = gtk_label_new ("x");
+ gtk_grid_attach_next_to (g, child, z, GTK_POS_TOP, 1, 2);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 4);
+ g_assert_cmpint (top, ==, 2);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 2);
+
+ child = gtk_label_new ("x");
+ gtk_grid_attach_next_to (g, child, z, GTK_POS_TOP, 1, 2);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 4);
+ g_assert_cmpint (top, ==, 2);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 2);
+
+ child = gtk_label_new ("y");
+ gtk_grid_attach_next_to (g, child, z, GTK_POS_BOTTOM, 1, 2);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 4);
+ g_assert_cmpint (top, ==, 5);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 2);
+
+ A = gtk_label_new ("A");
+ gtk_grid_attach (g, A, 10, 10, 1, 1);
+ B = gtk_label_new ("B");
+ gtk_grid_attach (g, B, 10, 12, 1, 1);
+
+ child = gtk_label_new ("D");
+ gtk_grid_attach_next_to (g, child, A, GTK_POS_RIGHT, 1, 3);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 11);
+ g_assert_cmpint (top, ==, 10);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 3);
+}
+
+static void
+test_add (void)
+{
+ GtkGrid *g;
+ GtkWidget *child;
+ gint left, top, width, height;
+
+ g = (GtkGrid *)gtk_grid_new ();
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (g), GTK_ORIENTATION_HORIZONTAL);
+
+ child = gtk_label_new ("a");
+ gtk_container_add (GTK_CONTAINER (g), child);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 0);
+ g_assert_cmpint (top, ==, 0);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 1);
+
+ child = gtk_label_new ("b");
+ gtk_container_add (GTK_CONTAINER (g), child);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 1);
+ g_assert_cmpint (top, ==, 0);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 1);
+
+ child = gtk_label_new ("c");
+ gtk_container_add (GTK_CONTAINER (g), child);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 2);
+ g_assert_cmpint (top, ==, 0);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 1);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (g), GTK_ORIENTATION_VERTICAL);
+
+ child = gtk_label_new ("d");
+ gtk_container_add (GTK_CONTAINER (g), child);
+ gtk_container_child_get (GTK_CONTAINER (g), child,
+ "left-attach", &left,
+ "top-attach", &top,
+ "width", &width,
+ "height", &height,
+ NULL);
+ g_assert_cmpint (left, ==, 0);
+ g_assert_cmpint (top, ==, 1);
+ g_assert_cmpint (width, ==, 1);
+ g_assert_cmpint (height, ==, 1);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ gtk_test_init (&argc, &argv);
+
+ g_test_add_func ("/grid/attach", test_attach);
+ g_test_add_func ("/grid/add", test_add);
+
+ return g_test_run();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]