[gtk+/native-layout] Fixed height-for-width implementation for combobox/cellview
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/native-layout] Fixed height-for-width implementation for combobox/cellview
- Date: Tue, 17 Aug 2010 05:37:20 +0000 (UTC)
commit 94f7cf03476bb1634783ab219e391e1eea83656d
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Tue Aug 17 01:33:11 2010 -0400
Fixed height-for-width implementation for combobox/cellview
Now the combo box requests height-for-width properly taking
into account all of its cells at request/allocation time.
Note an implementation of menu-items is needed to get the
the combo's drop-down menu to condense to a proper (smaller)
height when given enough width.
gtk/gtkcellview.c | 417 ++++++++++++++++++++++++++++++++++-------------------
gtk/gtkcellview.h | 9 +-
gtk/gtkcombobox.c | 355 +++++++++++++++++++++++++++++++--------------
3 files changed, 519 insertions(+), 262 deletions(-)
---
diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c
index 0bc91b5..12b4efd 100644
--- a/gtk/gtkcellview.c
+++ b/gtk/gtkcellview.c
@@ -128,6 +128,14 @@ static void gtk_cell_view_get_width (GtkSizeRequest
static void gtk_cell_view_get_height (GtkSizeRequest *widget,
gint *minimum_size,
gint *natural_size);
+static void gtk_cell_view_get_width_for_height (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_cell_view_get_height_for_width (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size);
static GtkBuildableIface *parent_buildable_iface;
@@ -329,20 +337,27 @@ gtk_cell_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkCellView *cellview;
- GList *i;
- gint nexpand_cells = 0;
- gint requested_width = 0;
- gint natural_width = 0;
- gint available, natural, extra;
+ GtkRequestedSize *sizes;
+ GArray *array;
+ GList *list;
+ gint nexpand_cells = 0;
+ gint avail_width = 0;
+ gint extra_per_cell, extra_extra, i;
+ gboolean first_cell = TRUE;
widget->allocation = *allocation;
cellview = GTK_CELL_VIEW (widget);
+ avail_width = allocation->width;
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
/* checking how much extra space we have */
- for (i = cellview->priv->cell_list; i; i = i->next)
+ for (list = cellview->priv->cell_list; list; list = list->next)
{
- GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+ GtkRequestedSize requested;
if (!gtk_cell_renderer_get_visible (info->cell))
continue;
@@ -350,41 +365,54 @@ gtk_cell_view_size_allocate (GtkWidget *widget,
if (info->expand)
nexpand_cells++;
- requested_width += info->requested_width;
- natural_width += info->natural_width - info->requested_width;
+ requested.data = info;
+ requested.minimum_size = info->requested_width;
+ requested.natural_size = info->natural_width;
+ g_array_append_val (array, requested);
+
+ if (!first_cell)
+ avail_width -= cellview->priv->spacing;
+
+ avail_width -= requested.minimum_size;
+
+ first_cell = FALSE;
}
- available = MAX (0, widget->allocation.width - requested_width);
- natural = MIN (available, natural_width);
- available -= natural;
+ sizes = (GtkRequestedSize *)array->data;
+ avail_width = gtk_distribute_natural_allocation (MAX (0, avail_width), array->len, sizes);
+ /* Deal with any expand space... */
if (nexpand_cells > 0)
- extra = available / nexpand_cells;
+ {
+ extra_per_cell = avail_width / nexpand_cells;
+ extra_extra = avail_width % nexpand_cells;
+ }
else
- extra = 0;
+ /* Everything just left-aligned if no cells expand */
+ extra_per_cell = extra_extra = 0;
- for (i = cellview->priv->cell_list; i; i = i->next)
+ for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
{
- GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
if (!gtk_cell_renderer_get_visible (info->cell))
continue;
- info->real_width = info->requested_width;
-
- if (natural_width > 0)
- info->real_width += natural * (info->natural_width - info->requested_width) / natural_width;
+ info->real_width = sizes[i].minimum_size;
if (info->expand)
{
- if (nexpand_cells == 1)
- info->real_width += available;
- else
- info->real_width += extra;
+ info->real_width += extra_per_cell;
- nexpand_cells -= 1;
- available -= extra;
- }
+ if (extra_extra)
+ {
+ info->real_width++;
+ extra_extra--;
+ }
+ }
+
+ /* increment index into sizes for visible children */
+ i++;
}
}
@@ -392,12 +420,13 @@ static gboolean
gtk_cell_view_expose (GtkWidget *widget,
GdkEventExpose *event)
{
- GList *i;
+ GList *list;
GtkCellView *cellview;
GdkRectangle area;
GtkCellRendererState state;
gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
-
+ GtkPackType packing;
+
cellview = GTK_CELL_VIEW (widget);
if (!gtk_widget_is_drawable (widget))
@@ -428,7 +457,6 @@ gtk_cell_view_expose (GtkWidget *widget,
area = widget->allocation;
/* we draw on our very own window, initialize x and y to zero */
- area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0);
area.y = widget->allocation.y;
if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
@@ -438,55 +466,44 @@ gtk_cell_view_expose (GtkWidget *widget,
else
state = 0;
- /* PACK_START */
- for (i = cellview->priv->cell_list; i; i = i->next)
+ for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
{
- GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
-
- if (info->pack == GTK_PACK_END)
- continue;
+ if (packing == GTK_PACK_START)
+ area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0);
+ else
+ area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);
- if (!gtk_cell_renderer_get_visible (info->cell))
- continue;
-
- area.width = info->real_width;
- if (rtl)
- area.x -= area.width;
+ for (list = cellview->priv->cell_list; list; list = list->next)
+ {
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
- gtk_cell_renderer_render (info->cell,
- event->window,
- widget,
- /* FIXME! */
- &area, &area, &event->area, state);
+ if (info->pack != packing)
+ continue;
- if (!rtl)
- area.x += info->real_width;
- }
+ if (!gtk_cell_renderer_get_visible (info->cell))
+ continue;
- area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);
+ area.width = info->real_width;
- /* PACK_END */
- for (i = cellview->priv->cell_list; i; i = i->next)
- {
- GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+ if ((packing == GTK_PACK_START && rtl) ||
+ (packing == GTK_PACK_END && !rtl))
+ area.x -= area.width;
- if (info->pack == GTK_PACK_START)
- continue;
+ gtk_cell_renderer_render (info->cell,
+ event->window,
+ widget,
+ /* FIXME! */
+ &area, &area, &event->area, state);
- if (!gtk_cell_renderer_get_visible (info->cell))
- continue;
-
- area.width = info->real_width;
- if (!rtl)
- area.x -= area.width;
-
- gtk_cell_renderer_render (info->cell,
- widget->window,
- widget,
- /* FIXME ! */
- &area, &area, &event->area, state);
- if (rtl)
- area.x += info->real_width;
+ if ((packing == GTK_PACK_START && !rtl) ||
+ (packing == GTK_PACK_END && rtl))
+ {
+ area.x += area.width;
+ area.x += cellview->priv->spacing;
+ }
+ else
+ area.x -= cellview->priv->spacing;
+ }
}
return FALSE;
@@ -980,7 +997,7 @@ gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
* Since: 2.6
*
* Deprecated: 3.0: Use gtk_cell_view_get_desired_width_of_row() and
- * gtk_cell_view_get_desired_height_of_row() instead.
+ * gtk_cell_view_get_desired_height_for_width_of_row() instead.
*/
gboolean
gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
@@ -992,8 +1009,9 @@ gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
+ /* Return the minimum height for the minimum width */
gtk_cell_view_get_desired_width_of_row (cell_view, path, &req.width, NULL);
- gtk_cell_view_get_desired_height_of_row (cell_view, path, &req.height, NULL);
+ gtk_cell_view_get_desired_height_for_width_of_row (cell_view, path, req.width, &req.height, NULL);
if (requisition)
*requisition = req;
@@ -1002,35 +1020,6 @@ gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
}
-
-static void
-gtk_cell_view_get_desired_size_of_row (GtkCellView *cell_view,
- GtkTreePath *path,
- GtkOrientation orientation,
- gint *minimum_size,
- gint *natural_size)
-{
- GtkTreeRowReference *tmp;
-
- tmp = cell_view->priv->displayed_row;
- cell_view->priv->displayed_row =
- gtk_tree_row_reference_new (cell_view->priv->model, path);
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- gtk_cell_view_get_width (GTK_SIZE_REQUEST (cell_view), minimum_size, natural_size);
- else
- gtk_cell_view_get_height (GTK_SIZE_REQUEST (cell_view), minimum_size, natural_size);
-
- gtk_tree_row_reference_free (cell_view->priv->displayed_row);
- cell_view->priv->displayed_row = tmp;
-
- /* Restore active size */
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- gtk_cell_view_get_width (GTK_SIZE_REQUEST (cell_view), NULL, NULL);
- else
- gtk_cell_view_get_height (GTK_SIZE_REQUEST (cell_view), NULL, NULL);
-}
-
/**
* gtk_cell_view_get_desired_width_of_row:
* @cell_view: a #GtkCellView
@@ -1049,37 +1038,65 @@ gtk_cell_view_get_desired_width_of_row (GtkCellView *cell_view,
gint *minimum_size,
gint *natural_size)
{
+ GtkTreeRowReference *tmp;
+
g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
g_return_if_fail (path != NULL);
g_return_if_fail (minimum_size != NULL || natural_size != NULL);
- gtk_cell_view_get_desired_size_of_row (cell_view, path, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+ tmp = cell_view->priv->displayed_row;
+ cell_view->priv->displayed_row =
+ gtk_tree_row_reference_new (cell_view->priv->model, path);
+
+ gtk_cell_view_get_width (GTK_SIZE_REQUEST (cell_view), minimum_size, natural_size);
+
+ gtk_tree_row_reference_free (cell_view->priv->displayed_row);
+ cell_view->priv->displayed_row = tmp;
+
+ /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
+ gtk_cell_view_get_width (GTK_SIZE_REQUEST (cell_view), NULL, NULL);
}
/**
- * gtk_cell_view_get_desired_height_of_row:
+ * gtk_cell_view_get_desired_height_for_width_of_row:
* @cell_view: a #GtkCellView
* @path: a #GtkTreePath
- * @minimum_size: location to store the minimum size
- * @natural_size: location to store the natural size
+ * @avail_size: available width
+ * @minimum_size: location to store the minimum height
+ * @natural_size: location to store the natural height
*
* Sets @minimum_size and @natural_size to the height desired by @cell_view
- * to display the model row pointed to by @path.
+ * if it were allocated a width of @avail_size to display the model row
+ * pointed to by @path.
*
* Since: 3.0
*/
void
-gtk_cell_view_get_desired_height_of_row (GtkCellView *cell_view,
- GtkTreePath *path,
- gint *minimum_size,
- gint *natural_size)
+gtk_cell_view_get_desired_height_for_width_of_row (GtkCellView *cell_view,
+ GtkTreePath *path,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size)
{
+ GtkTreeRowReference *tmp;
+
g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
g_return_if_fail (path != NULL);
g_return_if_fail (minimum_size != NULL || natural_size != NULL);
- gtk_cell_view_get_desired_size_of_row (cell_view, path, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+ tmp = cell_view->priv->displayed_row;
+ cell_view->priv->displayed_row =
+ gtk_tree_row_reference_new (cell_view->priv->model, path);
+
+ /* Then get the collective height_for_width based on the cached values */
+ gtk_cell_view_get_height_for_width (GTK_SIZE_REQUEST (cell_view), avail_size, minimum_size, natural_size);
+
+ gtk_tree_row_reference_free (cell_view->priv->displayed_row);
+ cell_view->priv->displayed_row = tmp;
+
+ /* Restore active size (this will restore the cellrenderer info->width/requested_width's) */
+ gtk_cell_view_get_width (GTK_SIZE_REQUEST (cell_view), NULL, NULL);
}
/**
@@ -1174,17 +1191,18 @@ gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
static void
gtk_cell_view_size_request_init (GtkSizeRequestIface *iface)
{
- iface->get_width = gtk_cell_view_get_width;
- iface->get_height = gtk_cell_view_get_height;
+ iface->get_width = gtk_cell_view_get_width;
+ iface->get_height = gtk_cell_view_get_height;
+ iface->get_width_for_height = gtk_cell_view_get_width_for_height;
+ iface->get_height_for_width = gtk_cell_view_get_height_for_width;
}
static void
-gtk_cell_view_get_size (GtkSizeRequest *widget,
- GtkOrientation orientation,
- gint *minimum_size,
- gint *natural_size)
+gtk_cell_view_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
{
- GList *i;
+ GList *list;
gint cell_min, cell_nat;
gboolean first_cell = TRUE;
GtkCellView *cellview = GTK_CELL_VIEW (widget);
@@ -1195,37 +1213,28 @@ gtk_cell_view_get_size (GtkSizeRequest *widget,
if (cellview->priv->displayed_row)
gtk_cell_view_set_cell_data (cellview);
- for (i = cellview->priv->cell_list; i; i = i->next)
+ for (list = cellview->priv->cell_list; list; list = list->next)
{
- GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
if (gtk_cell_renderer_get_visible (info->cell))
{
- if (!first_cell && orientation == GTK_ORIENTATION_HORIZONTAL)
+ if (!first_cell)
{
minimum += cellview->priv->spacing;
natural += cellview->priv->spacing;
}
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- gtk_cell_size_request_get_width (GTK_CELL_SIZE_REQUEST (info->cell),
- GTK_WIDGET (cellview), &cell_min, &cell_nat);
-
- info->requested_width = cell_min;
- info->natural_width = cell_nat;
+ gtk_cell_size_request_get_width (GTK_CELL_SIZE_REQUEST (info->cell),
+ GTK_WIDGET (cellview), &cell_min, &cell_nat);
+
+ info->requested_width = cell_min;
+ info->natural_width = cell_nat;
+
+ minimum += info->requested_width;
+ natural += info->natural_width;
- minimum += info->requested_width;
- natural += info->natural_width;
- }
- else
- {
- gtk_cell_size_request_get_height (GTK_CELL_SIZE_REQUEST (info->cell),
- GTK_WIDGET (cellview), &cell_min, &cell_nat);
- minimum = MAX (minimum, cell_min);
- natural = MAX (natural, cell_nat);
- }
first_cell = FALSE;
}
}
@@ -1237,18 +1246,134 @@ gtk_cell_view_get_size (GtkSizeRequest *widget,
*natural_size = natural;
}
-static void
-gtk_cell_view_get_width (GtkSizeRequest *widget,
+static void
+gtk_cell_view_get_height (GtkSizeRequest *widget,
gint *minimum_size,
gint *natural_size)
{
- gtk_cell_view_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+ gint minimum_width;
+
+ /* CellViews only need to respond to height-for-width mode (cellview is pretty much
+ * an implementation detail of GtkComboBox) */
+ gtk_cell_view_get_width (widget, &minimum_width, NULL);
+ gtk_cell_view_get_height_for_width (widget, minimum_width, minimum_size, natural_size);
}
static void
-gtk_cell_view_get_height (GtkSizeRequest *widget,
- gint *minimum_size,
- gint *natural_size)
+gtk_cell_view_get_width_for_height (GtkSizeRequest *widget,
+ gint for_size,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ /* CellViews only need to respond to height-for-width mode (cellview is pretty much
+ * an implementation detail of GtkComboBox) */
+ gtk_cell_view_get_width (widget, minimum_size, natural_size);
+}
+
+static void
+gtk_cell_view_get_height_for_width (GtkSizeRequest *widget,
+ gint for_size,
+ gint *minimum_size,
+ gint *natural_size)
{
- gtk_cell_view_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+ GtkCellView *cellview = GTK_CELL_VIEW (widget);
+ GList *list;
+ GtkRequestedSize *sizes;
+ GArray *array;
+ gint minimum, natural, avail_size;
+ gboolean first_cell = TRUE;
+ gint n_expand_cells = 0;
+ gint extra_per_cell, extra_extra, i;
+
+ minimum = natural = 0;
+ avail_size = for_size;
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
+ if (cellview->priv->displayed_row)
+ gtk_cell_view_set_cell_data (cellview);
+
+ /* First allocate the right width to all cells */
+ for (list = cellview->priv->cell_list; list; list = list->next)
+ {
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+
+ if (gtk_cell_renderer_get_visible (info->cell))
+ {
+ GtkRequestedSize requested;
+
+ gtk_cell_size_request_get_width (GTK_CELL_SIZE_REQUEST (info->cell),
+ GTK_WIDGET (cellview),
+ &requested.minimum_size,
+ &requested.natural_size);
+
+ requested.data = info;
+ g_array_append_val (array, requested);
+
+ avail_size -= requested.minimum_size;
+
+ if (!first_cell)
+ avail_size -= cellview->priv->spacing;
+
+ first_cell = FALSE;
+
+ if (info->expand)
+ n_expand_cells++;
+ }
+ }
+
+ sizes = (GtkRequestedSize *)array->data;
+ avail_size = gtk_distribute_natural_allocation (MAX (0, avail_size), array->len, sizes);
+
+ /* Deal with any expand space... */
+ if (n_expand_cells > 0)
+ {
+ extra_per_cell = avail_size / n_expand_cells;
+ extra_extra = avail_size % n_expand_cells;
+ }
+ else
+ /* Everything just left-aligned if no cells expand */
+ extra_per_cell = extra_extra = 0;
+
+ /* Now get the height for the real width of each cell */
+ for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
+ {
+ GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
+ gint cell_minimum, cell_natural;
+
+ if (gtk_cell_renderer_get_visible (info->cell))
+ {
+ gint cell_width = sizes[i].minimum_size;
+
+ g_assert (sizes[i].data == info);
+
+ if (info->expand)
+ {
+ cell_width += extra_per_cell;
+ if (extra_extra)
+ {
+ cell_width++;
+ extra_extra--;
+ }
+ }
+
+ /* Get the height for the real width of this cell */
+ gtk_cell_size_request_get_height_for_width (GTK_CELL_SIZE_REQUEST (info->cell),
+ GTK_WIDGET (widget),
+ cell_width, &cell_minimum, &cell_natural);
+
+ minimum = MAX (minimum, cell_minimum);
+ natural = MAX (natural, cell_natural);
+
+ /* increment sizes[] index for visible cells */
+ i++;
+ }
+ }
+
+ g_array_free (array, TRUE);
+
+ if (minimum_size)
+ *minimum_size = minimum;
+ if (natural_size)
+ *natural_size = natural;
}
diff --git a/gtk/gtkcellview.h b/gtk/gtkcellview.h
index 84dc4e5..cb6b269 100644
--- a/gtk/gtkcellview.h
+++ b/gtk/gtkcellview.h
@@ -76,10 +76,11 @@ void gtk_cell_view_get_desired_width_of_row(GtkCellView *cell_v
GtkTreePath *path,
gint *minimum_size,
gint *natural_size);
-void gtk_cell_view_get_desired_height_of_row(GtkCellView *cell_view,
- GtkTreePath *path,
- gint *minimum_size,
- gint *natural_size);
+void gtk_cell_view_get_desired_height_for_width_of_row(GtkCellView *cell_view,
+ GtkTreePath *path,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size);
void gtk_cell_view_set_background_color (GtkCellView *cell_view,
const GdkColor *color);
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 1034265..7ebcfb9 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -108,8 +108,8 @@ struct _GtkComboBoxPrivate
guint scroll_timer;
guint resize_idle_id;
- GtkRequisition minimum_size;
- GtkRequisition natural_size;
+ gint minimum_width;
+ gint natural_width;
GSList *cells;
@@ -474,6 +474,14 @@ static void gtk_combo_box_get_width (GtkSizeRequest
static void gtk_combo_box_get_height (GtkSizeRequest *widget,
gint *minimum_size,
gint *natural_size);
+static void gtk_combo_box_get_width_for_height (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_combo_box_get_height_for_width (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size);
G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
@@ -947,8 +955,8 @@ gtk_combo_box_init (GtkComboBox *combo_box)
_gtk_bin_set_child (GTK_BIN (combo_box), priv->cell_view);
gtk_widget_show (priv->cell_view);
- memset (&priv->minimum_size, 0x0, sizeof (GtkRequisition));
- memset (&priv->natural_size, 0x0, sizeof (GtkRequisition));
+ priv->minimum_width = 0;
+ priv->natural_width = 0;
priv->wrap_width = 0;
@@ -3591,14 +3599,14 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model,
width = gtk_combo_box_calc_requested_width (combo_box, path);
- if (width > priv->minimum_size.width)
+ if (width > priv->minimum_width)
{
if (priv->cell_view)
{
gtk_widget_set_size_request (priv->cell_view, width, -1);
gtk_widget_queue_resize (priv->cell_view);
}
- priv->minimum_size.width = width;
+ priv->minimum_width = width;
}
}
@@ -4108,14 +4116,14 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model,
width = gtk_combo_box_calc_requested_width (combo_box, path);
- if (width > priv->minimum_size.width)
+ if (width > priv->minimum_width)
{
if (priv->cell_view)
{
gtk_widget_set_size_request (priv->cell_view, width, -1);
gtk_widget_queue_resize (priv->cell_view);
}
- priv->minimum_size.width = width;
+ priv->minimum_width = width;
}
}
@@ -5923,8 +5931,10 @@ gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
static void
gtk_combo_box_size_request_init (GtkSizeRequestIface *iface)
{
- iface->get_width = gtk_combo_box_get_width;
- iface->get_height = gtk_combo_box_get_height;
+ iface->get_width = gtk_combo_box_get_width;
+ iface->get_height = gtk_combo_box_get_height;
+ iface->get_height_for_width = gtk_combo_box_get_height_for_width;
+ iface->get_width_for_height = gtk_combo_box_get_width_for_height;
}
static void
@@ -5938,34 +5948,20 @@ gtk_combo_box_remeasure (GtkComboBox *combo_box)
!gtk_tree_model_get_iter_first (priv->model, &iter))
return;
- memset (&priv->minimum_size, 0x0, sizeof (GtkRequisition));
- memset (&priv->natural_size, 0x0, sizeof (GtkRequisition));
+ priv->minimum_width = priv->natural_width = 0;
path = gtk_tree_path_new_from_indices (0, -1);
do
{
- GtkRequisition req, nat_req;
+ gint row_min = 0, row_nat = 0;
if (priv->cell_view)
- {
- /* XXX FIXME: Currently still not doing height-for-width in cell renderers here */
- gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view),
- path, &req.width, &nat_req.width);
- gtk_cell_view_get_desired_height_of_row (GTK_CELL_VIEW (priv->cell_view),
- path, &req.height, &nat_req.height);
- }
- else
- {
- memset (&req, 0x0, sizeof (GtkRequisition));
- memset (&nat_req, 0x0, sizeof (GtkRequisition));
- }
-
- priv->minimum_size.width = MAX (priv->minimum_size.width, req.width);
- priv->minimum_size.height = MAX (priv->minimum_size.height, req.height);
+ gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view),
+ path, &row_min, &row_nat);
- priv->natural_size.width = MAX (priv->natural_size.width, nat_req.width);
- priv->natural_size.height = MAX (priv->natural_size.height, nat_req.height);
+ priv->minimum_width = MAX (priv->minimum_width, row_min);
+ priv->natural_width = MAX (priv->natural_width, row_nat);
gtk_tree_path_next (path);
}
@@ -5975,35 +5971,80 @@ gtk_combo_box_remeasure (GtkComboBox *combo_box)
}
-/* XXX TODO: Split this up into 2 orientations so as
- * to properly support height-for-width/width-for-height here
- *
- */
static void
-gtk_combo_box_get_size (GtkSizeRequest *widget,
- GtkRequisition *minimum_size,
- GtkRequisition *natural_size)
+gtk_combo_box_measure_height_for_width (GtkComboBox *combo_box,
+ gint avail_width,
+ gint *min_height,
+ gint *nat_height)
+{
+ GtkWidget *child;
+ GtkComboBoxPrivate *priv = combo_box->priv;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gint child_min, child_nat;
+
+ child = gtk_bin_get_child (GTK_BIN (combo_box));
+
+ gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child), avail_width,
+ &child_min, &child_nat);
+
+ if (!priv->model ||
+ !gtk_tree_model_get_iter_first (priv->model, &iter))
+ goto out;
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+
+ do
+ {
+ gint row_min = 0, row_nat = 0;
+
+ if (priv->cell_view)
+ gtk_cell_view_get_desired_height_for_width_of_row (GTK_CELL_VIEW (priv->cell_view),
+ path, avail_width,
+ &row_min, &row_nat);
+
+ child_min = MAX (child_min, row_min);
+ child_nat = MAX (child_nat, row_nat);
+
+ gtk_tree_path_next (path);
+ }
+ while (gtk_tree_model_iter_next (priv->model, &iter));
+
+ gtk_tree_path_free (path);
+
+ out:
+
+ if (min_height)
+ *min_height = child_min;
+ if (nat_height)
+ *nat_height = child_nat;
+}
+
+
+static void
+gtk_combo_box_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
GtkComboBoxPrivate *priv = combo_box->priv;
gint focus_width, focus_pad;
gint font_size, arrow_size;
- GtkRequisition bin_req, bin_nat_req;
PangoContext *context;
PangoFontMetrics *metrics;
PangoFontDescription *font_desc;
GtkWidget *child;
+ gint minimum_width, natural_width;
+ gint child_min, child_nat;
child = gtk_bin_get_child (GTK_BIN (widget));
/* common */
- gtk_size_request_get_size (GTK_SIZE_REQUEST (child), &bin_req, &bin_nat_req);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
gtk_combo_box_remeasure (combo_box);
- bin_req.width = MAX (bin_req.width, priv->minimum_size.width);
- bin_req.height = MAX (bin_req.height, priv->minimum_size.height);
- bin_nat_req.width = MAX (bin_nat_req.width, priv->natural_size.width);
- bin_nat_req.height = MAX (bin_nat_req.height, priv->natural_size.height);
+ child_min = MAX (child_min, priv->minimum_width);
+ child_nat = MAX (child_nat, priv->natural_width);
gtk_widget_style_get (GTK_WIDGET (widget),
"focus-line-width", &focus_width,
@@ -6029,109 +6070,74 @@ gtk_combo_box_get_size (GtkSizeRequest *widget,
if (priv->cell_view)
{
- GtkRequisition button_req, sep_req, arrow_req;
- gint border_width, xthickness, ythickness, xpad, ypad;
+ gint sep_width, arrow_width;
+ gint border_width, xthickness, xpad;
- gtk_widget_size_request (priv->button, &button_req);
border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
- xthickness = priv->button->style->xthickness;
- ythickness = priv->button->style->ythickness;
-
- xpad = 2*(border_width + xthickness + focus_width + focus_pad);
- ypad = 2*(border_width + ythickness + focus_width + focus_pad);
-
- gtk_widget_size_request (priv->separator, &sep_req);
- gtk_widget_size_request (priv->arrow, &arrow_req);
+ xthickness = priv->button->style->xthickness;
- minimum_size->width = bin_req.width + sep_req.width + arrow_req.width;
- minimum_size->height = MAX (sep_req.height, arrow_req.height);
- minimum_size->height = MAX (minimum_size->height, bin_req.height);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->separator), &sep_width, NULL);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->arrow), &arrow_width, NULL);
- natural_size->width = bin_nat_req.width + sep_req.width + arrow_req.width;
- natural_size->height = MAX (minimum_size->height, bin_nat_req.height);
+ xpad = 2*(border_width + xthickness + focus_width + focus_pad);
- minimum_size->width += xpad;
- minimum_size->height += ypad;
- natural_size->width += xpad;
- natural_size->height += ypad;
+ minimum_width = child_min + sep_width + arrow_width + xpad;
+ natural_width = child_nat + sep_width + arrow_width + xpad;
}
else
{
- GtkRequisition but_req, but_nat_req;
-
- gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->button),
- &but_req, &but_nat_req);
+ gint but_width, but_nat_width;
- minimum_size->width = bin_req.width + but_req.width;
- minimum_size->height = MAX (bin_req.height, but_req.height);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button),
+ &but_width, &but_nat_width);
- natural_size->width = bin_nat_req.width + but_nat_req.width;
- natural_size->height = MAX (bin_nat_req.height, but_nat_req.height);
+ minimum_width = child_min + but_width;
+ natural_width = child_nat + but_nat_width;
}
}
else
{
/* list mode */
- GtkRequisition button_req, button_nat_req, frame_req;
+ gint button_width, button_nat_width;
/* sample + frame */
- *minimum_size = bin_req;
- *natural_size = bin_nat_req;
+ minimum_width = child_min;
+ natural_width = child_nat;
- minimum_size->width += 2 * focus_width;
- natural_size->width += 2 * focus_width;
+ minimum_width += 2 * focus_width;
+ natural_width += 2 * focus_width;
if (priv->cell_view_frame)
{
- gtk_widget_size_request (priv->cell_view_frame, &frame_req);
if (priv->has_frame)
{
gint border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
- gint xpad = 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
- gint ypad = 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
+ gint xpad = 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
- minimum_size->width += xpad;
- minimum_size->height += ypad;
- natural_size->width += xpad;
- natural_size->height += ypad;
+ minimum_width += xpad;
+ natural_width += xpad;
}
}
/* the button */
- gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->button),
- &button_req, &button_nat_req);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button),
+ &button_width, &button_nat_width);
- minimum_size->width += button_req.width;
- minimum_size->height = MAX (minimum_size->height, button_req.height);
-
- natural_size->width += button_nat_req.width;
- natural_size->height = MAX (natural_size->height, button_nat_req.height);
+ minimum_width += button_width;
+ natural_width += button_nat_width;
}
if (GTK_SHADOW_NONE != priv->shadow_type)
{
- minimum_size->width += 2 * GTK_WIDGET (widget)->style->xthickness;
- minimum_size->height += 2 * GTK_WIDGET (widget)->style->ythickness;
-
- natural_size->width += 2 * GTK_WIDGET (widget)->style->xthickness;
- natural_size->height += 2 * GTK_WIDGET (widget)->style->ythickness;
+ minimum_width += 2 * GTK_WIDGET (widget)->style->xthickness;
+ natural_width += 2 * GTK_WIDGET (widget)->style->xthickness;
}
-}
-
-static void
-gtk_combo_box_get_width (GtkSizeRequest *widget,
- gint *minimum_size,
- gint *natural_size)
-{
- GtkRequisition minimum, natural;
-
- gtk_combo_box_get_size (widget, &minimum, &natural);
if (minimum_size)
- *minimum_size = minimum.width;
+ *minimum_size = minimum_width;
if (natural_size)
- *natural_size = natural.width;
+ *natural_size = natural_width;
}
static void
@@ -6139,14 +6145,139 @@ gtk_combo_box_get_height (GtkSizeRequest *widget,
gint *minimum_size,
gint *natural_size)
{
- GtkRequisition minimum, natural;
+ gint min_width;
+
+ /* Combo box is height-for-width only
+ * (so we always just reserve enough height for the minimum width) */
+ gtk_size_request_get_width (widget, &min_width, NULL);
+ gtk_size_request_get_height_for_width (widget, min_width, minimum_size, natural_size);
+}
+
+static void
+gtk_combo_box_get_width_for_height (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ /* Combo box is height-for-width only
+ * (so we assume we always reserved enough height for the minimum width) */
+ gtk_size_request_get_width (widget, minimum_size, natural_size);
+}
+
+
+static void
+gtk_combo_box_get_height_for_width (GtkSizeRequest *widget,
+ gint avail_size,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+ GtkComboBoxPrivate *priv = combo_box->priv;
+ gint focus_width, focus_pad;
+ gint min_height, nat_height;
+ gint size;
+
+ gtk_widget_style_get (GTK_WIDGET (widget),
+ "focus-line-width", &focus_width,
+ "focus-padding", &focus_pad,
+ NULL);
+
+ size = avail_size;
- gtk_combo_box_get_size (widget, &minimum, &natural);
+ if (GTK_SHADOW_NONE != priv->shadow_type)
+ size -= GTK_WIDGET (widget)->style->xthickness;
+
+ if (!priv->tree_view)
+ {
+ /* menu mode */
+ if (priv->cell_view)
+ {
+ /* calculate x/y padding and separator/arrow size */
+ gint sep_width, arrow_width, sep_height, arrow_height;
+ gint border_width, xthickness, ythickness, xpad, ypad;
+
+ border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
+ xthickness = priv->button->style->xthickness;
+ ythickness = priv->button->style->ythickness;
+
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->separator), &sep_width, NULL);
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->arrow), &arrow_width, NULL);
+ gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->separator),
+ sep_width, &sep_height, NULL);
+ gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->arrow),
+ arrow_width, &arrow_height, NULL);
+
+ xpad = 2*(border_width + xthickness + focus_width + focus_pad);
+ ypad = 2*(border_width + ythickness + focus_width + focus_pad);
+
+ size -= sep_width + arrow_width + xpad;
+
+ gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height);
+
+ arrow_height = MAX (arrow_height, sep_height);
+ min_height = MAX (min_height, arrow_height);
+ nat_height = MAX (nat_height, arrow_height);
+
+ min_height += ypad;
+ nat_height += ypad;
+ }
+ else
+ {
+ /* there is a custom child widget inside (no priv->cell_view) */
+ gint but_width, but_height;
+
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button), &but_width, NULL);
+ gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->button),
+ but_width, &but_height, NULL);
+
+ size -= but_width;
+
+ gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height);
+
+ min_height = MAX (min_height, but_height);
+ nat_height = MAX (nat_height, but_height);
+ }
+ }
+ else
+ {
+ /* list mode */
+ gint but_width, but_height;
+ gint xpad = 0, ypad = 0;
+
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button), &but_width, NULL);
+ gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (priv->button),
+ but_width, &but_height, NULL);
+
+ if (priv->cell_view_frame && priv->has_frame)
+ {
+ gint border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
+
+ xpad = 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
+ ypad = 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
+ }
+
+ size -= but_width;
+ size -= 2 * focus_width;
+ size -= xpad;
+
+ gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height);
+
+ min_height = MAX (min_height, but_height);
+ nat_height = MAX (nat_height, but_height);
+
+ min_height += ypad;
+ nat_height += ypad;
+ }
+
+ if (GTK_SHADOW_NONE != priv->shadow_type)
+ {
+ min_height += 2 * GTK_WIDGET (widget)->style->ythickness;
+ nat_height += 2 * GTK_WIDGET (widget)->style->ythickness;
+ }
if (minimum_size)
- *minimum_size = minimum.height;
+ *minimum_size = min_height;
if (natural_size)
- *natural_size = natural.height;
+ *natural_size = nat_height;
}
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]