[gtk+/grid-widget] Implement height-for-width in GtkGrid
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/grid-widget] Implement height-for-width in GtkGrid
- Date: Sun, 10 Oct 2010 05:19:27 +0000 (UTC)
commit 9c80c9353404778f59325c86ba6e557ff5dfbb0f
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Oct 10 01:14:53 2010 -0400
Implement height-for-width in GtkGrid
gtk/gtkgrid.c | 498 +++++++++++++++++++++++++++++++++++----------------------
1 files changed, 308 insertions(+), 190 deletions(-)
---
diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c
index 8386a3d..957e20e 100644
--- a/gtk/gtkgrid.c
+++ b/gtk/gtkgrid.c
@@ -1,6 +1,6 @@
/* TODO
- * - wfh
* - magic expand
+ * - infinite span
*/
/* GTK - The GIMP Toolkit
@@ -28,6 +28,7 @@
#include "gtkgrid.h"
#include "gtkorientable.h"
+#include "gtksizerequest.h"
#include "gtkprivate.h"
#include "gtkintl.h"
@@ -415,8 +416,8 @@ gtk_grid_init (GtkGrid *grid)
priv->children = NULL;
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
- init_lines (ROWS(priv));
- init_lines (COLUMNS(priv));
+ init_lines (ROWS (priv));
+ init_lines (COLUMNS (priv));
}
static void grid_attach (GtkGrid *grid,
@@ -512,12 +513,13 @@ gtk_grid_child_type (GtkContainer *container)
}
static void
-gtk_grid_allocate_lines (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_ensure_lines (GtkGrid *grid,
+ GtkOrientation orientation)
{
GtkGridPrivate *priv = grid->priv;
GtkGridLines *lines;
- GtkGridChild *grid_child;
+ GtkGridChild *child;
+ GtkGridChildAttach *attach;
GList *list;
gint min, max;
@@ -530,10 +532,11 @@ gtk_grid_allocate_lines (GtkGrid *grid,
max = G_MININT;
for (list = priv->children; list; list = list->next)
{
- grid_child = list->data;
+ child = list->data;
+ attach = &child->attach[orientation];
- min = MIN (min, grid_child->attach[orientation].pos);
- max = MAX (max, grid_child->attach[orientation].pos + grid_child->attach[orientation].span);
+ min = MIN (min, attach->pos);
+ max = MAX (max, attach->pos + attach->span);
}
lines->min = min;
@@ -541,12 +544,12 @@ gtk_grid_allocate_lines (GtkGrid *grid,
lines->lines = g_new (GtkGridLine, max - min);
}
-/* set requisitions to 0, mark rows/cols as expand
- * if they have a non-spanning exanding child
+/* set line sizes to 0, mark lines as expand
+ * if they have a non-spanning expanding child
*/
static void
-gtk_grid_size_request_init (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_request_init (GtkGrid *grid,
+ GtkOrientation orientation)
{
GtkGridPrivate *priv = grid->priv;
GtkGridChild *child;
@@ -574,32 +577,36 @@ gtk_grid_size_request_init (GtkGrid *grid,
}
}
-static void
-get_preferred_size (GtkWidget *widget,
- GtkOrientation orientation,
- gint *minimum,
- gint *natural)
+static gint
+compute_allocation_for_span (GtkGrid *grid,
+ GtkOrientation orientation,
+ GtkGridChild *child)
{
- GtkRequisition minimum_req;
- GtkRequisition natural_req;
+ GtkGridPrivate *priv = grid->priv;
+ GtkGridLines *lines;
+ GtkGridLine *line;
+ GtkGridChildAttach *attach;
+ gint size;
+ gint i;
- gtk_widget_get_preferred_size (widget, &minimum_req, &natural_req);
+ lines = &priv->lines[orientation];
+ attach = &child->attach[orientation];
- if (minimum)
- *minimum = orientation == GTK_ORIENTATION_HORIZONTAL
- ? minimum_req.width
- : minimum_req.height;
+ size = (attach->span - 1) * lines->spacing;
+ for (i = 0; i < attach->span; i++)
+ {
+ line = &lines->lines[attach->pos - lines->min + i];
+ size += line->allocation;
+ }
- if (natural)
- *natural = orientation == GTK_ORIENTATION_HORIZONTAL
- ? natural_req.width
- : natural_req.height;
+ return size;
}
/* set requisition to max of non-spanning children */
static void
-gtk_grid_size_request_pass1 (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_request_non_spanning (GtkGrid *grid,
+ GtkOrientation orientation,
+ gboolean for_size)
{
GtkGridPrivate *priv = grid->priv;
GtkGridChild *child;
@@ -609,6 +616,7 @@ gtk_grid_size_request_pass1 (GtkGrid *grid,
GList *list;
gint minimum;
gint natural;
+ gint size;
lines = &priv->lines[orientation];
@@ -623,7 +631,25 @@ gtk_grid_size_request_pass1 (GtkGrid *grid,
if (attach->span != 1)
continue;
- get_preferred_size (child->widget, orientation, &minimum, &natural);
+ if (for_size)
+ {
+ size = compute_allocation_for_span (grid, 1 - orientation, child);
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_get_preferred_width_for_height (child->widget,
+ size,
+ &minimum, &natural);
+ else
+ gtk_widget_get_preferred_height_for_width (child->widget,
+ size,
+ &minimum, &natural);
+ }
+ else
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_get_preferred_width (child->widget, &minimum, &natural);
+ else
+ gtk_widget_get_preferred_height (child->widget, &minimum, &natural);
+ }
line = &lines->lines[attach->pos - lines->min];
line->minimum = MAX (line->minimum, minimum);
@@ -633,8 +659,8 @@ gtk_grid_size_request_pass1 (GtkGrid *grid,
/* force homogeneous sizes */
static void
-gtk_grid_size_request_pass2 (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_request_homogeneous (GtkGrid *grid,
+ GtkOrientation orientation)
{
GtkGridPrivate *priv = grid->priv;
GtkGridLines *lines;
@@ -664,8 +690,9 @@ gtk_grid_size_request_pass2 (GtkGrid *grid,
/* deal with spanning children */
static void
-gtk_grid_size_request_pass3 (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_request_spanning (GtkGrid *grid,
+ GtkOrientation orientation,
+ gboolean for_size)
{
GtkGridPrivate *priv = grid->priv;
GList *list;
@@ -684,6 +711,7 @@ gtk_grid_size_request_pass3 (GtkGrid *grid,
gboolean force;
gint i;
gint extra;
+ gint size;
lines = &priv->lines[orientation];
@@ -710,7 +738,25 @@ gtk_grid_size_request_pass3 (GtkGrid *grid,
span_expand += 1;
}
- get_preferred_size (child->widget, orientation, &child_minimum, &child_natural);
+ if (for_size)
+ {
+ size = compute_allocation_for_span (grid, 1 - orientation, child);
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_get_preferred_width_for_height (child->widget,
+ size,
+ &child_minimum, &child_natural);
+ else
+ gtk_widget_get_preferred_height_for_width (child->widget,
+ size,
+ &child_minimum, &child_natural);
+ }
+ else
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_get_preferred_width (child->widget, &child_minimum, &child_natural);
+ else
+ gtk_widget_get_preferred_height (child->widget, &child_minimum, &child_natural);
+ }
/* If we need to request more space for this child to fill
* its requisition, then divide up the needed space amongst the
@@ -764,91 +810,12 @@ gtk_grid_size_request_pass3 (GtkGrid *grid,
}
}
-static void
-gtk_grid_get_size (GtkGrid *grid,
- GtkOrientation orientation,
- gint *minimum_size,
- gint *natural_size)
-{
- GtkGridPrivate *priv = grid->priv;
- GtkGridLines *lines;
- gint i;
- gint minimum, natural;
-
- gtk_grid_allocate_lines (grid, orientation);
-
- gtk_grid_size_request_init (grid, orientation);
- gtk_grid_size_request_pass1 (grid, orientation);
- gtk_grid_size_request_pass2 (grid, orientation);
- gtk_grid_size_request_pass3 (grid, orientation);
- gtk_grid_size_request_pass2 (grid, orientation);
-
- lines = &priv->lines[orientation];
-
- minimum = (lines->max - lines->min - 1) * lines->spacing;
- natural = (lines->max - lines->min - 1) * lines->spacing;
-
- for (i = 0; i < lines->max - lines->min; i++)
- {
- minimum += lines->lines[i].minimum;
- natural += lines->lines[i].natural;
- }
-
- if (minimum_size)
- *minimum_size = minimum;
-
- if (natural_size)
- *natural_size = natural;
-}
-
-static void
-gtk_grid_get_preferred_width (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- gtk_grid_get_size (GTK_GRID (widget),
- GTK_ORIENTATION_HORIZONTAL,
- minimum,
- natural);
-}
-
-static void
-gtk_grid_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- gtk_grid_get_size (GTK_GRID (widget),
- GTK_ORIENTATION_VERTICAL,
- minimum,
- natural);
-}
-
-#if 0
-static void
-gtk_grid_get_preferred_width_for_height (GtkWidget *widget,
- gint height,
- gint *minimum,
- gint *natural)
-{
- GtkGrid *grid = GTK_GRID (widget);
- GtkGridPrivate *priv = grid->priv;
-}
-
-static void
-gtk_grid_get_preferred_height_for_width (GtkWidget *widget,
- gint width,
- gint *minimum,
- gint *natural)
-{
- GtkGrid *grid = GTK_GRID (widget);
- GtkGridPrivate *priv = grid->priv;
-}
-#endif
-
/* find empty and expanding lines */
static void
-gtk_grid_size_allocate_init (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_compute_expand (GtkGrid *grid,
+ GtkOrientation orientation,
+ gint *nonempty_lines,
+ gint *expand_lines)
{
GtkGridPrivate *priv = grid->priv;
GtkGridChild *child;
@@ -858,14 +825,13 @@ gtk_grid_size_allocate_init (GtkGrid *grid,
GtkGridLines *lines;
GtkGridLine *line;
gboolean has_expand;
-
- gtk_grid_allocate_lines (grid, orientation);
+ gint expand;
+ gint empty;
lines = &priv->lines[orientation];
for (i = 0; i < lines->max - lines->min; i++)
{
- lines->lines[i].allocation = lines->lines[i].minimum;
lines->lines[i].need_expand = FALSE;
lines->lines[i].expand = FALSE;
lines->lines[i].empty = TRUE;
@@ -918,94 +884,248 @@ gtk_grid_size_allocate_init (GtkGrid *grid,
}
}
+ empty = 0;
+ expand = 0;
for (i = 0; i < lines->max - lines->min; i++)
{
- if (lines->lines[i].need_expand)
- lines->lines[i].expand = TRUE;
+ line = &lines->lines[i];
+
+ if (line->need_expand)
+ line->expand = TRUE;
+
+ if (line->empty)
+ empty += 1;
+
+ if (line->expand)
+ expand += 1;
}
+
+ if (nonempty_lines)
+ *nonempty_lines = lines->max - lines->min - empty;
+
+ if (expand_lines)
+ *expand_lines = expand;
}
-/* distribute space over lines */
static void
-gtk_grid_size_allocate_pass1 (GtkGrid *grid,
- GtkOrientation orientation)
+gtk_grid_request_sum (GtkGrid *grid,
+ GtkOrientation orientation,
+ gint *minimum,
+ gint *natural)
{
GtkGridPrivate *priv = grid->priv;
- GtkAllocation allocation;
- gint extra;
+ GtkGridLines *lines;
gint i;
- gint nonempty, expand;
+ gint min, nat;
+ gint nonempty;
+
+ gtk_grid_compute_expand (grid, orientation, &nonempty, NULL);
+
+ lines = &priv->lines[orientation];
+
+ min = (nonempty - 1) * lines->spacing;
+ nat = (nonempty - 1) * lines->spacing;
+
+ for (i = 0; i < lines->max - lines->min; i++)
+ {
+ min += lines->lines[i].minimum;
+ nat += lines->lines[i].natural;
+ }
+
+ if (minimum)
+ *minimum = min;
+
+ if (natural)
+ *natural = nat;
+}
+
+static void
+gtk_grid_request_lines (GtkGrid *grid,
+ GtkOrientation orientation,
+ gboolean for_size)
+{
+ gtk_grid_ensure_lines (grid, orientation);
+
+ gtk_grid_request_init (grid, orientation);
+ gtk_grid_request_non_spanning (grid, orientation, for_size);
+ gtk_grid_request_homogeneous (grid, orientation);
+ gtk_grid_request_spanning (grid, orientation, for_size);
+ gtk_grid_request_homogeneous (grid, orientation);
+}
+
+static void
+gtk_grid_get_size (GtkGrid *grid,
+ GtkOrientation orientation,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_grid_request_lines (grid, orientation, FALSE);
+ gtk_grid_request_sum (grid, orientation, minimum, natural);
+}
+
+static void
+gtk_grid_allocate_lines (GtkGrid *grid,
+ GtkOrientation orientation,
+ gint total_size)
+{
+ GtkGridPrivate *priv = grid->priv;
GtkGridLines *lines;
+ GtkGridLine *line;
+ gint nonempty;
+ gint expand;
+ gint i, j;
+ GtkRequestedSize *sizes;
+ gint extra;
+ gint rest;
gint size;
- gint alloc_size;
- if (priv->children == NULL)
- return;
-
- gtk_widget_get_allocation (GTK_WIDGET (grid), &allocation);
+ gtk_grid_compute_expand (grid, orientation, &nonempty, &expand);
lines = &priv->lines[orientation];
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- alloc_size = allocation.width;
- else
- alloc_size = allocation.height;
+
+ size = total_size - (nonempty - 1) * lines->spacing;
if (lines->homogeneous)
{
- nonempty = 0;
- expand = 0;
+ extra = size / nonempty;
+ rest = size % nonempty;
+
for (i = 0; i < lines->max - lines->min; i++)
{
- if (!lines->lines[i].empty)
- nonempty += 1;
- if (lines->lines[i].expand)
- expand += 1;
- }
+ line = &lines->lines[i];
+ if (line->empty)
+ continue;
- size = alloc_size - (nonempty - 1) * lines->spacing;
- if (expand > 0)
- {
- for (i = 0; i < lines->max - lines->min; i++)
+ line->allocation = extra;
+ if (rest > 0)
{
- extra = size / (lines->max - lines->min - i);
- lines->lines[i].allocation = MAX (1, extra);
- size -= extra;
+ line->allocation += 1;
+ rest -= 1;
}
}
}
else
{
- size = 0;
- expand = 0;
- nonempty = 0;
+ sizes = g_newa (GtkRequestedSize, nonempty);
+
+ j = 0;
for (i = 0; i < lines->max - lines->min; i++)
{
- size += lines->lines[i].minimum;
- if (!lines->lines[i].empty)
- nonempty += 1;
- if (lines->lines[i].expand)
- expand += 1;
+ line = &lines->lines[i];
+ if (line->empty)
+ continue;
+
+ size -= line->minimum;
+
+ sizes[j].minimum_size = line->minimum;
+ sizes[j].natural_size = line->natural;
+ sizes[j].data = line;
+ j++;
+ }
+
+ size = gtk_distribute_natural_allocation (MAX (0, size), nonempty, sizes);
+
+ if (expand > 0)
+ {
+ extra = size / expand;
+ rest = size % expand;
+ }
+ else
+ {
+ extra = 0;
+ rest = 0;
}
- size += (nonempty - 1) * lines->spacing;
- if (size < alloc_size && expand > 0)
+ j = 0;
+ for (i = 0; i < lines->max - lines->min; i++)
{
- size = alloc_size - size;
- for (i = 0; i < lines->max - lines->min; i++)
+ line = &lines->lines[i];
+ if (line->empty)
+ continue;
+
+ g_assert (line == sizes[j].data);
+
+ line->allocation = sizes[j].minimum_size;
+ if (line->expand)
{
- if (lines->lines[i].expand)
+ line->allocation += extra;
+ if (rest > 0)
{
- extra = size / expand;
- lines->lines[i].allocation += extra;
- size -= extra;
- expand -= 1;
+ line->allocation += 1;
+ rest -= 1;
}
}
+
+ j++;
}
}
}
static void
+gtk_grid_get_size_for_orientation (GtkGrid *grid,
+ GtkOrientation orientation,
+ gint size,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_grid_request_lines (grid, 1 - orientation, FALSE);
+ gtk_grid_allocate_lines (grid, 1 - orientation, size);
+ gtk_grid_request_lines (grid, orientation, TRUE);
+ gtk_grid_request_sum (grid, orientation, minimum, natural);
+}
+
+static void
+gtk_grid_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_grid_get_size (GTK_GRID (widget), GTK_ORIENTATION_HORIZONTAL, minimum, natural);
+}
+
+static void
+gtk_grid_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_grid_get_size (GTK_GRID (widget), GTK_ORIENTATION_VERTICAL, minimum, natural);
+}
+
+static GtkSizeRequestMode
+gtk_grid_get_request_mode (GtkWidget *widget)
+{
+ GtkGridPrivate *priv = GTK_GRID (widget)->priv;
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+ else
+ return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+}
+
+static void
+gtk_grid_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum,
+ gint *natural)
+{
+ if (gtk_grid_get_request_mode (GTK_GRID (widget)) != GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT)
+ gtk_grid_get_preferred_height (widget, &height, NULL);
+
+ gtk_grid_get_size_for_orientation (GTK_GRID (widget), GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
+}
+
+static void
+gtk_grid_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural)
+{
+ if (gtk_grid_get_request_mode (GTK_GRID (widget)) != GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
+ gtk_grid_get_preferred_width (widget, &width, NULL);
+
+ gtk_grid_get_size_for_orientation (GTK_GRID (widget), GTK_ORIENTATION_VERTICAL, width, minimum, natural);
+}
+
+static void
allocate_child (GtkGrid *grid,
GtkOrientation orientation,
GtkGridChild *child,
@@ -1037,9 +1157,8 @@ allocate_child (GtkGrid *grid,
}
}
-/* allocate children */
static void
-gtk_grid_size_allocate_pass2 (GtkGrid *grid)
+gtk_grid_allocate_children (GtkGrid *grid)
{
GtkGridPrivate *priv = grid->priv;
GList *list;
@@ -1074,25 +1193,26 @@ gtk_grid_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkGrid *grid = GTK_GRID (widget);
+ GtkGridPrivate *priv = grid->priv;
gtk_widget_set_allocation (widget, allocation);
- gtk_grid_size_allocate_init (grid, GTK_ORIENTATION_HORIZONTAL);
- gtk_grid_size_allocate_init (grid, GTK_ORIENTATION_VERTICAL);
- gtk_grid_size_allocate_pass1 (grid, GTK_ORIENTATION_HORIZONTAL);
- gtk_grid_size_allocate_pass1 (grid, GTK_ORIENTATION_VERTICAL);
- gtk_grid_size_allocate_pass2 (grid);
-}
-
-static GtkSizeRequestMode
-gtk_grid_get_request_mode (GtkWidget *widget)
-{
- GtkGridPrivate *priv = GTK_GRID (widget)->priv;
-
- if (priv->orientation == GTK_ORIENTATION_VERTICAL)
- return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_grid_request_lines (grid, GTK_ORIENTATION_VERTICAL, FALSE);
+ gtk_grid_allocate_lines (grid, GTK_ORIENTATION_VERTICAL, allocation->height);
+ gtk_grid_request_lines (grid, GTK_ORIENTATION_HORIZONTAL, TRUE);
+ gtk_grid_allocate_lines (grid, GTK_ORIENTATION_HORIZONTAL, allocation->width);
+ }
else
- return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+ {
+ gtk_grid_request_lines (grid, GTK_ORIENTATION_HORIZONTAL, FALSE);
+ gtk_grid_allocate_lines (grid, GTK_ORIENTATION_HORIZONTAL, allocation->width);
+ gtk_grid_request_lines (grid, GTK_ORIENTATION_VERTICAL, TRUE);
+ gtk_grid_allocate_lines (grid, GTK_ORIENTATION_VERTICAL, allocation->height);
+ }
+
+ gtk_grid_allocate_children (grid);
}
static void
@@ -1110,10 +1230,8 @@ gtk_grid_class_init (GtkGridClass *class)
widget_class->get_preferred_width = gtk_grid_get_preferred_width;
widget_class->get_preferred_height = gtk_grid_get_preferred_height;
widget_class->get_request_mode = gtk_grid_get_request_mode;
-#if 0
widget_class->get_preferred_width_for_height = gtk_grid_get_preferred_width_for_height;
widget_class->get_preferred_height_for_width = gtk_grid_get_preferred_height_for_width;
-#endif
container_class->add = gtk_grid_add;
container_class->remove = gtk_grid_remove;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]