mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-29 06:51:10 +00:00
Added height-for-width management for GtkComboBox/GtkCellView
now GtkComboBox (and GtkCellView) request and allocate children/cells in a height-for-width manner.
This commit is contained in:
parent
9f762fe86c
commit
9c26bd525f
@ -24,6 +24,8 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkcellrenderertext.h"
|
||||
#include "gtkcellrendererpixbuf.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkcellsizerequest.h"
|
||||
#include "gtkprivate.h"
|
||||
#include <gobject/gmarshal.h>
|
||||
#include "gtkbuildable.h"
|
||||
@ -35,6 +37,7 @@ struct _GtkCellViewCellInfo
|
||||
GtkCellRenderer *cell;
|
||||
|
||||
gint requested_width;
|
||||
gint natural_width;
|
||||
gint real_width;
|
||||
guint expand : 1;
|
||||
guint pack : 1;
|
||||
@ -68,8 +71,6 @@ static void gtk_cell_view_set_property (GObject *obj
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_cell_view_finalize (GObject *object);
|
||||
static void gtk_cell_view_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition);
|
||||
static void gtk_cell_view_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static gboolean gtk_cell_view_expose (GtkWidget *widget,
|
||||
@ -120,6 +121,22 @@ static void gtk_cell_view_buildable_custom_tag_end (GtkBuildable
|
||||
const gchar *tagname,
|
||||
gpointer *data);
|
||||
|
||||
static void gtk_cell_view_size_request_init (GtkSizeRequestIface *iface);
|
||||
static void gtk_cell_view_get_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
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;
|
||||
|
||||
|
||||
@ -136,7 +153,10 @@ G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
|
||||
gtk_cell_view_cell_layout_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
||||
gtk_cell_view_buildable_init))
|
||||
gtk_cell_view_buildable_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
|
||||
gtk_cell_view_size_request_init))
|
||||
|
||||
|
||||
static void
|
||||
gtk_cell_view_class_init (GtkCellViewClass *klass)
|
||||
@ -150,7 +170,6 @@ gtk_cell_view_class_init (GtkCellViewClass *klass)
|
||||
|
||||
widget_class->expose_event = gtk_cell_view_expose;
|
||||
widget_class->size_allocate = gtk_cell_view_size_allocate;
|
||||
widget_class->size_request = gtk_cell_view_size_request;
|
||||
|
||||
/* properties */
|
||||
g_object_class_install_property (gobject_class,
|
||||
@ -313,100 +332,110 @@ gtk_cell_view_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_cell_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_view_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition)
|
||||
{
|
||||
GList *i;
|
||||
gboolean first_cell = TRUE;
|
||||
GtkCellView *cellview;
|
||||
|
||||
cellview = GTK_CELL_VIEW (widget);
|
||||
|
||||
requisition->width = 0;
|
||||
requisition->height = 0;
|
||||
|
||||
if (cellview->priv->displayed_row)
|
||||
gtk_cell_view_set_cell_data (cellview);
|
||||
|
||||
for (i = cellview->priv->cell_list; i; i = i->next)
|
||||
{
|
||||
gint width, height;
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
|
||||
|
||||
if (!gtk_cell_renderer_get_visible (info->cell))
|
||||
continue;
|
||||
|
||||
if (!first_cell)
|
||||
requisition->width += cellview->priv->spacing;
|
||||
|
||||
gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
|
||||
&width, &height);
|
||||
|
||||
info->requested_width = width;
|
||||
requisition->width += width;
|
||||
requisition->height = MAX (requisition->height, height);
|
||||
|
||||
first_cell = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_view_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation)
|
||||
{
|
||||
GList *i;
|
||||
gint expand_cell_count = 0;
|
||||
gint full_requested_width = 0;
|
||||
gint extra_space;
|
||||
GtkCellView *cellview;
|
||||
GtkCellView *cellview;
|
||||
GtkRequestedSize *sizes;
|
||||
GList *list;
|
||||
gint n_visible_cells, n_expand_cells;
|
||||
gint avail_width = 0;
|
||||
gint extra_per_cell, extra_extra, i;
|
||||
gboolean first_cell = TRUE;
|
||||
|
||||
widget->allocation = *allocation;
|
||||
|
||||
cellview = GTK_CELL_VIEW (widget);
|
||||
|
||||
/* checking how much extra space we have */
|
||||
for (i = cellview->priv->cell_list; i; i = i->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
|
||||
avail_width = allocation->width;
|
||||
|
||||
if (!gtk_cell_renderer_get_visible (info->cell))
|
||||
continue;
|
||||
/* Count visible/expand children */
|
||||
for (n_visible_cells = 0, n_expand_cells = 0, list = cellview->priv->cell_list;
|
||||
list; list = list->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
|
||||
|
||||
n_visible_cells++;
|
||||
|
||||
if (info->expand)
|
||||
expand_cell_count++;
|
||||
|
||||
full_requested_width += info->requested_width;
|
||||
n_expand_cells++;
|
||||
}
|
||||
|
||||
extra_space = widget->allocation.width - full_requested_width;
|
||||
if (extra_space < 0)
|
||||
extra_space = 0;
|
||||
else if (extra_space > 0 && expand_cell_count > 0)
|
||||
extra_space /= expand_cell_count;
|
||||
sizes = g_new0 (GtkRequestedSize, n_visible_cells);
|
||||
|
||||
for (i = cellview->priv->cell_list; i; i = i->next)
|
||||
/* checking how much extra space we have */
|
||||
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 +
|
||||
(info->expand ? extra_space : 0);
|
||||
sizes[i].data = info;
|
||||
sizes[i].minimum_size = info->requested_width;
|
||||
sizes[i].natural_size = info->natural_width;
|
||||
|
||||
if (!first_cell)
|
||||
avail_width -= cellview->priv->spacing;
|
||||
|
||||
avail_width -= sizes[i].minimum_size;
|
||||
|
||||
first_cell = FALSE;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
avail_width = gtk_distribute_natural_allocation (MAX (0, avail_width), n_visible_cells, sizes);
|
||||
|
||||
/* Deal with any expand space... */
|
||||
if (n_expand_cells > 0)
|
||||
{
|
||||
extra_per_cell = avail_width / n_expand_cells;
|
||||
extra_extra = avail_width % n_expand_cells;
|
||||
}
|
||||
else
|
||||
/* Everything just left-aligned if no cells expand */
|
||||
extra_per_cell = extra_extra = 0;
|
||||
|
||||
for (i = 0, list = cellview->priv->cell_list; list; list = list->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
|
||||
|
||||
if (!gtk_cell_renderer_get_visible (info->cell))
|
||||
continue;
|
||||
|
||||
info->real_width = sizes[i].minimum_size;
|
||||
|
||||
if (info->expand)
|
||||
{
|
||||
info->real_width += extra_per_cell;
|
||||
|
||||
if (extra_extra)
|
||||
{
|
||||
info->real_width++;
|
||||
extra_extra--;
|
||||
}
|
||||
}
|
||||
|
||||
/* increment index into sizes for visible children */
|
||||
i++;
|
||||
}
|
||||
|
||||
g_free (sizes);
|
||||
}
|
||||
|
||||
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))
|
||||
@ -437,7 +466,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)
|
||||
@ -447,55 +475,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 (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 (info->pack == GTK_PACK_END)
|
||||
continue;
|
||||
for (list = cellview->priv->cell_list; list; list = list->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
|
||||
|
||||
if (!gtk_cell_renderer_get_visible (info->cell))
|
||||
continue;
|
||||
if (info->pack != packing)
|
||||
continue;
|
||||
|
||||
area.width = info->real_width;
|
||||
if (rtl)
|
||||
area.x -= area.width;
|
||||
if (!gtk_cell_renderer_get_visible (info->cell))
|
||||
continue;
|
||||
|
||||
gtk_cell_renderer_render (info->cell,
|
||||
event->window,
|
||||
widget,
|
||||
/* FIXME! */
|
||||
&area, &area, &event->area, state);
|
||||
area.width = info->real_width;
|
||||
|
||||
if (!rtl)
|
||||
area.x += info->real_width;
|
||||
}
|
||||
if ((packing == GTK_PACK_START && rtl) ||
|
||||
(packing == GTK_PACK_END && !rtl))
|
||||
area.x -= area.width;
|
||||
|
||||
area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);
|
||||
gtk_cell_renderer_render (info->cell,
|
||||
event->window,
|
||||
widget,
|
||||
/* FIXME! */
|
||||
&area, &area, &event->area, state);
|
||||
|
||||
/* PACK_END */
|
||||
for (i = cellview->priv->cell_list; i; i = i->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
|
||||
|
||||
if (info->pack == GTK_PACK_START)
|
||||
continue;
|
||||
|
||||
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;
|
||||
@ -584,6 +601,8 @@ gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout,
|
||||
info->pack = GTK_PACK_START;
|
||||
|
||||
cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (cellview));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -604,6 +623,8 @@ gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout,
|
||||
info->pack = GTK_PACK_END;
|
||||
|
||||
cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (cellview));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -983,32 +1004,108 @@ gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
|
||||
* Return value: %TRUE
|
||||
*
|
||||
* Since: 2.6
|
||||
*
|
||||
* Deprecated: 3.0: Use gtk_cell_view_get_desired_width_of_row() and
|
||||
* gtk_cell_view_get_desired_height_for_width_of_row() instead.
|
||||
*/
|
||||
gboolean
|
||||
gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
|
||||
GtkTreePath *path,
|
||||
GtkRequisition *requisition)
|
||||
{
|
||||
GtkTreeRowReference *tmp;
|
||||
GtkRequisition req;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
|
||||
g_return_val_if_fail (path != NULL, FALSE);
|
||||
g_return_val_if_fail (requisition != 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_for_width_of_row (cell_view, path, req.width, &req.height, NULL);
|
||||
|
||||
if (requisition)
|
||||
*requisition = req;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_cell_view_get_desired_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
|
||||
*
|
||||
* Sets @minimum_size and @natural_size to the width desired by @cell_view
|
||||
* to display the model row pointed to by @path.
|
||||
*
|
||||
* Since: 3.0
|
||||
*/
|
||||
void
|
||||
gtk_cell_view_get_desired_width_of_row (GtkCellView *cell_view,
|
||||
GtkTreePath *path,
|
||||
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);
|
||||
|
||||
tmp = cell_view->priv->displayed_row;
|
||||
cell_view->priv->displayed_row =
|
||||
gtk_tree_row_reference_new (cell_view->priv->model, path);
|
||||
|
||||
gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition);
|
||||
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 actual size info */
|
||||
gtk_cell_view_size_request (GTK_WIDGET (cell_view), &req);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
/**
|
||||
* gtk_cell_view_get_desired_height_for_width_of_row:
|
||||
* @cell_view: a #GtkCellView
|
||||
* @path: a #GtkTreePath
|
||||
* @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
|
||||
* 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_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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1099,3 +1196,193 @@ gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
|
||||
parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
|
||||
data);
|
||||
}
|
||||
|
||||
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_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_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
GList *list;
|
||||
gint cell_min, cell_nat;
|
||||
gboolean first_cell = TRUE;
|
||||
GtkCellView *cellview = GTK_CELL_VIEW (widget);
|
||||
gint minimum, natural;
|
||||
|
||||
minimum = natural = 0;
|
||||
|
||||
if (cellview->priv->displayed_row)
|
||||
gtk_cell_view_set_cell_data (cellview);
|
||||
|
||||
for (list = cellview->priv->cell_list; list; list = list->next)
|
||||
{
|
||||
GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
|
||||
|
||||
if (gtk_cell_renderer_get_visible (info->cell))
|
||||
{
|
||||
|
||||
if (!first_cell)
|
||||
{
|
||||
minimum += cellview->priv->spacing;
|
||||
natural += cellview->priv->spacing;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
first_cell = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = minimum;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = natural;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_view_get_height (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *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_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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -69,6 +69,18 @@ GtkTreePath *gtk_cell_view_get_displayed_row (GtkCellView *cell_v
|
||||
gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
|
||||
GtkTreePath *path,
|
||||
GtkRequisition *requisition);
|
||||
gboolean gtk_cell_view_get_size_of_row (GtkCellView *cell_view,
|
||||
GtkTreePath *path,
|
||||
GtkRequisition *requisition);
|
||||
void gtk_cell_view_get_desired_width_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);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "gtktreeselection.h"
|
||||
#include "gtkvseparator.h"
|
||||
#include "gtkwindow.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
@ -107,8 +108,9 @@ struct _GtkComboBoxPrivate
|
||||
guint scroll_timer;
|
||||
guint resize_idle_id;
|
||||
|
||||
gint width;
|
||||
gint height;
|
||||
gint minimum_width;
|
||||
gint natural_width;
|
||||
|
||||
GSList *cells;
|
||||
|
||||
guint popup_in_progress : 1;
|
||||
@ -272,14 +274,12 @@ static void gtk_combo_box_menu_position (GtkMenu *menu,
|
||||
gint *push_in,
|
||||
gpointer user_data);
|
||||
|
||||
static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
|
||||
GtkTreePath *path);
|
||||
static void gtk_combo_box_update_requested_width(GtkComboBox *combo_box,
|
||||
GtkTreePath *path);
|
||||
static void gtk_combo_box_remeasure (GtkComboBox *combo_box);
|
||||
|
||||
static void gtk_combo_box_unset_model (GtkComboBox *combo_box);
|
||||
|
||||
static void gtk_combo_box_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition);
|
||||
static void gtk_combo_box_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation);
|
||||
static void gtk_combo_box_forall (GtkContainer *container,
|
||||
@ -464,8 +464,24 @@ static void gtk_combo_box_buildable_custom_tag_end (GtkBuildable *bui
|
||||
gpointer *data);
|
||||
|
||||
/* GtkCellEditable method implementations */
|
||||
static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
|
||||
GdkEvent *event);
|
||||
static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable,
|
||||
GdkEvent *event);
|
||||
|
||||
static void gtk_combo_box_size_request_init (GtkSizeRequestIface *iface);
|
||||
static void gtk_combo_box_get_width (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size);
|
||||
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,
|
||||
@ -474,7 +490,9 @@ G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
|
||||
gtk_combo_box_cell_editable_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
||||
gtk_combo_box_buildable_init))
|
||||
gtk_combo_box_buildable_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
|
||||
gtk_combo_box_size_request_init))
|
||||
|
||||
|
||||
/* common */
|
||||
@ -496,7 +514,6 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
|
||||
|
||||
widget_class = (GtkWidgetClass *)klass;
|
||||
widget_class->size_allocate = gtk_combo_box_size_allocate;
|
||||
widget_class->size_request = gtk_combo_box_size_request;
|
||||
widget_class->expose_event = gtk_combo_box_expose_event;
|
||||
widget_class->scroll_event = gtk_combo_box_scroll_event;
|
||||
widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
|
||||
@ -938,8 +955,9 @@ gtk_combo_box_init (GtkComboBox *combo_box)
|
||||
_gtk_bin_set_child (GTK_BIN (combo_box), priv->cell_view);
|
||||
gtk_widget_show (priv->cell_view);
|
||||
|
||||
priv->width = 0;
|
||||
priv->height = 0;
|
||||
priv->minimum_width = 0;
|
||||
priv->natural_width = 0;
|
||||
|
||||
priv->wrap_width = 0;
|
||||
|
||||
priv->active = -1;
|
||||
@ -1543,23 +1561,37 @@ gtk_combo_box_menu_position_over (GtkMenu *menu,
|
||||
gboolean *push_in,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkComboBox *combo_box;
|
||||
GtkWidget *active;
|
||||
GtkWidget *child;
|
||||
GtkWidget *widget;
|
||||
GtkRequisition requisition;
|
||||
GList *children;
|
||||
gint screen_width;
|
||||
gint menu_xpos;
|
||||
gint menu_ypos;
|
||||
gint menu_width;
|
||||
GtkComboBox *combo_box;
|
||||
GtkWidget *active;
|
||||
GtkWidget *child;
|
||||
GtkWidget *widget;
|
||||
GtkRequisition requisition;
|
||||
GList *children;
|
||||
guint horizontal_padding, border_width;
|
||||
gint screen_width;
|
||||
gint menu_item_avail_width;
|
||||
gint min_item_height;
|
||||
gint menu_xpos;
|
||||
gint menu_ypos;
|
||||
gint menu_width;
|
||||
|
||||
combo_box = GTK_COMBO_BOX (user_data);
|
||||
widget = GTK_WIDGET (combo_box);
|
||||
|
||||
gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition);
|
||||
gtk_widget_style_get (GTK_WIDGET (menu),
|
||||
"horizontal-padding", &horizontal_padding,
|
||||
NULL);
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
|
||||
|
||||
/* Get the minimum height for minimum width of the menu */
|
||||
gtk_size_request_get_size (GTK_SIZE_REQUEST (menu), &requisition, NULL);
|
||||
menu_width = requisition.width;
|
||||
|
||||
/* Get the size for the height-for-width menu-item requests */
|
||||
menu_item_avail_width =
|
||||
menu_width - (border_width + horizontal_padding + widget->style->xthickness) * 2;
|
||||
|
||||
active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget));
|
||||
|
||||
menu_xpos = widget->allocation.x;
|
||||
@ -1567,8 +1599,9 @@ gtk_combo_box_menu_position_over (GtkMenu *menu,
|
||||
|
||||
if (active != NULL)
|
||||
{
|
||||
gtk_widget_get_child_requisition (active, &requisition);
|
||||
menu_ypos -= requisition.height / 2;
|
||||
gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (active),
|
||||
menu_item_avail_width, &min_item_height, NULL);
|
||||
menu_ypos -= min_item_height / 2;
|
||||
}
|
||||
|
||||
children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children;
|
||||
@ -1581,8 +1614,9 @@ gtk_combo_box_menu_position_over (GtkMenu *menu,
|
||||
|
||||
if (gtk_widget_get_visible (child))
|
||||
{
|
||||
gtk_widget_get_child_requisition (child, &requisition);
|
||||
menu_ypos -= requisition.height;
|
||||
gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child),
|
||||
menu_item_avail_width, &min_item_height, NULL);
|
||||
menu_ypos -= min_item_height;
|
||||
}
|
||||
|
||||
children = children->next;
|
||||
@ -1830,8 +1864,7 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
GtkTreePath *path;
|
||||
gint active_item;
|
||||
GtkRequisition requisition;
|
||||
gint width;
|
||||
gint width, min_width;
|
||||
|
||||
update_menu_sensitivity (combo_box, priv->popup_widget);
|
||||
|
||||
@ -1853,10 +1886,10 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box,
|
||||
{
|
||||
width = GTK_WIDGET (combo_box)->allocation.width;
|
||||
gtk_widget_set_size_request (priv->popup_widget, -1, -1);
|
||||
gtk_widget_size_request (priv->popup_widget, &requisition);
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->popup_widget), &min_width, NULL);
|
||||
|
||||
gtk_widget_set_size_request (priv->popup_widget,
|
||||
MAX (width, requisition.width), -1);
|
||||
MAX (width, min_width), -1);
|
||||
}
|
||||
|
||||
gtk_menu_popup (GTK_MENU (priv->popup_widget),
|
||||
@ -2093,13 +2126,12 @@ gtk_combo_box_popdown (GtkComboBox *combo_box)
|
||||
priv->grab_keyboard = NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
|
||||
GtkTreePath *path)
|
||||
static void
|
||||
gtk_combo_box_update_requested_width (GtkComboBox *combo_box,
|
||||
GtkTreePath *path)
|
||||
{
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
gint padding;
|
||||
GtkRequisition req;
|
||||
gint padding, min_width, nat_width;
|
||||
|
||||
if (priv->cell_view)
|
||||
gtk_widget_style_get (priv->cell_view,
|
||||
@ -2112,168 +2144,24 @@ gtk_combo_box_calc_requested_width (GtkComboBox *combo_box,
|
||||
padding += BONUS_PADDING;
|
||||
|
||||
if (priv->cell_view)
|
||||
gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view),
|
||||
path, &req);
|
||||
gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view),
|
||||
path, &min_width, &nat_width);
|
||||
else
|
||||
req.width = 0;
|
||||
min_width = nat_width = 0;
|
||||
|
||||
return req.width + padding;
|
||||
}
|
||||
min_width += padding;
|
||||
nat_width += padding;
|
||||
|
||||
static void
|
||||
gtk_combo_box_remeasure (GtkComboBox *combo_box)
|
||||
{
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
|
||||
if (!priv->model ||
|
||||
!gtk_tree_model_get_iter_first (priv->model, &iter))
|
||||
return;
|
||||
|
||||
priv->width = 0;
|
||||
priv->height = 0;
|
||||
|
||||
path = gtk_tree_path_new_from_indices (0, -1);
|
||||
|
||||
do
|
||||
if (min_width > priv->minimum_width || nat_width > priv->natural_width)
|
||||
{
|
||||
GtkRequisition req;
|
||||
priv->minimum_width = MAX (priv->minimum_width, min_width);
|
||||
priv->natural_width = MAX (priv->natural_width, nat_width);
|
||||
|
||||
if (priv->cell_view)
|
||||
gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view),
|
||||
path, &req);
|
||||
else
|
||||
{
|
||||
req.width = 0;
|
||||
req.height = 0;
|
||||
}
|
||||
|
||||
priv->width = MAX (priv->width, req.width);
|
||||
priv->height = MAX (priv->height, req.height);
|
||||
|
||||
gtk_tree_path_next (path);
|
||||
}
|
||||
while (gtk_tree_model_iter_next (priv->model, &iter));
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_combo_box_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition)
|
||||
{
|
||||
gint width, height;
|
||||
gint focus_width, focus_pad;
|
||||
gint font_size;
|
||||
gint arrow_size;
|
||||
guint border_width;
|
||||
GtkRequisition bin_req;
|
||||
PangoContext *context;
|
||||
PangoFontMetrics *metrics;
|
||||
PangoFontDescription *font_desc;
|
||||
|
||||
GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
|
||||
/* common */
|
||||
gtk_widget_size_request (gtk_bin_get_child (GTK_BIN (widget)), &bin_req);
|
||||
gtk_combo_box_remeasure (combo_box);
|
||||
bin_req.width = MAX (bin_req.width, priv->width);
|
||||
bin_req.height = MAX (bin_req.height, priv->height);
|
||||
|
||||
gtk_widget_style_get (GTK_WIDGET (widget),
|
||||
"focus-line-width", &focus_width,
|
||||
"focus-padding", &focus_pad,
|
||||
"arrow-size", &arrow_size,
|
||||
NULL);
|
||||
|
||||
font_desc = gtk_bin_get_child (GTK_BIN (widget))->style->font_desc;
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
metrics = pango_context_get_metrics (context, font_desc,
|
||||
pango_context_get_language (context));
|
||||
font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||
pango_font_metrics_get_descent (metrics));
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
arrow_size = MAX (arrow_size, font_size);
|
||||
|
||||
gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
|
||||
|
||||
if (!priv->tree_view)
|
||||
{
|
||||
/* menu mode */
|
||||
|
||||
if (priv->cell_view)
|
||||
{
|
||||
GtkRequisition button_req, sep_req, arrow_req;
|
||||
gint xthickness, ythickness;
|
||||
|
||||
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;
|
||||
|
||||
bin_req.width = MAX (bin_req.width, priv->width);
|
||||
bin_req.height = MAX (bin_req.height, priv->height);
|
||||
|
||||
gtk_widget_size_request (priv->separator, &sep_req);
|
||||
gtk_widget_size_request (priv->arrow, &arrow_req);
|
||||
|
||||
height = MAX (sep_req.height, arrow_req.height);
|
||||
height = MAX (height, bin_req.height);
|
||||
|
||||
width = bin_req.width + sep_req.width + arrow_req.width;
|
||||
|
||||
height += 2*(border_width + ythickness + focus_width + focus_pad);
|
||||
width += 2*(border_width + xthickness + focus_width + focus_pad);
|
||||
|
||||
requisition->width = width;
|
||||
requisition->height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkRequisition but_req;
|
||||
|
||||
gtk_widget_size_request (priv->button, &but_req);
|
||||
|
||||
requisition->width = bin_req.width + but_req.width;
|
||||
requisition->height = MAX (bin_req.height, but_req.height);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* list mode */
|
||||
GtkRequisition button_req, frame_req;
|
||||
|
||||
/* sample + frame */
|
||||
*requisition = bin_req;
|
||||
|
||||
requisition->width += 2 * focus_width;
|
||||
|
||||
if (priv->cell_view_frame)
|
||||
{
|
||||
gtk_widget_size_request (priv->cell_view_frame, &frame_req);
|
||||
if (priv->has_frame)
|
||||
{
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame));
|
||||
|
||||
requisition->width += 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->xthickness);
|
||||
requisition->height += 2 * (border_width + GTK_WIDGET (priv->cell_view_frame)->style->ythickness);
|
||||
}
|
||||
}
|
||||
|
||||
/* the button */
|
||||
gtk_widget_size_request (priv->button, &button_req);
|
||||
|
||||
requisition->height = MAX (requisition->height, button_req.height);
|
||||
requisition->width += button_req.width;
|
||||
}
|
||||
|
||||
if (GTK_SHADOW_NONE != priv->shadow_type)
|
||||
{
|
||||
requisition->height += 2 * widget->style->ythickness;
|
||||
requisition->width += 2 * widget->style->xthickness;
|
||||
{
|
||||
gtk_widget_set_size_request (priv->cell_view, min_width, -1);
|
||||
gtk_widget_queue_resize (priv->cell_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2395,19 +2283,19 @@ gtk_combo_box_size_allocate (GtkWidget *widget,
|
||||
|
||||
if (gtk_widget_get_visible (priv->popup_widget))
|
||||
{
|
||||
gint width;
|
||||
GtkRequisition requisition;
|
||||
gint width, min_width;
|
||||
|
||||
/* Warning here, without the check in the position func */
|
||||
gtk_menu_reposition (GTK_MENU (priv->popup_widget));
|
||||
if (priv->wrap_width == 0)
|
||||
{
|
||||
width = GTK_WIDGET (combo_box)->allocation.width;
|
||||
gtk_widget_set_size_request (priv->popup_widget, -1, -1);
|
||||
gtk_widget_size_request (priv->popup_widget, &requisition);
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->popup_widget), &min_width, NULL);
|
||||
gtk_widget_set_size_request (priv->popup_widget,
|
||||
MAX (width, requisition.width), -1);
|
||||
MAX (width, min_width), -1);
|
||||
}
|
||||
|
||||
/* reposition the menu after giving it a new width */
|
||||
gtk_menu_reposition (GTK_MENU (priv->popup_widget));
|
||||
}
|
||||
|
||||
child.width = MAX (1, child.width);
|
||||
@ -3691,7 +3579,6 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model,
|
||||
GtkComboBox *combo_box = GTK_COMBO_BOX (user_data);
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
GtkWidget *item;
|
||||
gint width;
|
||||
gboolean is_separator;
|
||||
|
||||
if (!priv->popup_widget)
|
||||
@ -3736,17 +3623,7 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model,
|
||||
gtk_combo_box_relayout_item (combo_box, item, iter, pitem);
|
||||
}
|
||||
|
||||
width = gtk_combo_box_calc_requested_width (combo_box, path);
|
||||
|
||||
if (width > priv->width)
|
||||
{
|
||||
if (priv->cell_view)
|
||||
{
|
||||
gtk_widget_set_size_request (priv->cell_view, width, -1);
|
||||
gtk_widget_queue_resize (priv->cell_view);
|
||||
}
|
||||
priv->width = width;
|
||||
}
|
||||
gtk_combo_box_update_requested_width (combo_box, path);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4250,20 +4127,8 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model,
|
||||
gpointer data)
|
||||
{
|
||||
GtkComboBox *combo_box = GTK_COMBO_BOX (data);
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
gint width;
|
||||
|
||||
width = gtk_combo_box_calc_requested_width (combo_box, path);
|
||||
|
||||
if (width > priv->width)
|
||||
{
|
||||
if (priv->cell_view)
|
||||
{
|
||||
gtk_widget_set_size_request (priv->cell_view, width, -1);
|
||||
gtk_widget_queue_resize (priv->cell_view);
|
||||
}
|
||||
priv->width = width;
|
||||
}
|
||||
gtk_combo_box_update_requested_width (combo_box, path);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4316,8 +4181,11 @@ gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout,
|
||||
priv->cells = g_slist_append (priv->cells, info);
|
||||
|
||||
if (priv->cell_view)
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view),
|
||||
cell, expand);
|
||||
{
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view),
|
||||
cell, expand);
|
||||
|
||||
}
|
||||
|
||||
if (priv->column)
|
||||
gtk_tree_view_column_pack_start (priv->column, cell, expand);
|
||||
@ -6062,3 +5930,358 @@ gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable,
|
||||
parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
|
||||
data);
|
||||
}
|
||||
|
||||
|
||||
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_height_for_width = gtk_combo_box_get_height_for_width;
|
||||
iface->get_width_for_height = gtk_combo_box_get_width_for_height;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_combo_box_remeasure (GtkComboBox *combo_box)
|
||||
{
|
||||
GtkComboBoxPrivate *priv = combo_box->priv;
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
|
||||
if (!priv->model ||
|
||||
!gtk_tree_model_get_iter_first (priv->model, &iter))
|
||||
return;
|
||||
|
||||
priv->minimum_width = priv->natural_width = 0;
|
||||
|
||||
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_width_of_row (GTK_CELL_VIEW (priv->cell_view),
|
||||
path, &row_min, &row_nat);
|
||||
|
||||
priv->minimum_width = MAX (priv->minimum_width, row_min);
|
||||
priv->natural_width = MAX (priv->natural_width, row_nat);
|
||||
|
||||
gtk_tree_path_next (path);
|
||||
}
|
||||
while (gtk_tree_model_iter_next (priv->model, &iter));
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
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;
|
||||
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_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat);
|
||||
gtk_combo_box_remeasure (combo_box);
|
||||
|
||||
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,
|
||||
"focus-padding", &focus_pad,
|
||||
"arrow-size", &arrow_size,
|
||||
NULL);
|
||||
|
||||
font_desc = child->style->font_desc;
|
||||
context = gtk_widget_get_pango_context (GTK_WIDGET (widget));
|
||||
metrics = pango_context_get_metrics (context, font_desc,
|
||||
pango_context_get_language (context));
|
||||
font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
||||
pango_font_metrics_get_descent (metrics));
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
arrow_size = MAX (arrow_size, font_size);
|
||||
|
||||
gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size);
|
||||
|
||||
if (!priv->tree_view)
|
||||
{
|
||||
/* menu mode */
|
||||
|
||||
if (priv->cell_view)
|
||||
{
|
||||
gint sep_width, arrow_width;
|
||||
gint border_width, xthickness, xpad;
|
||||
|
||||
border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box));
|
||||
xthickness = priv->button->style->xthickness;
|
||||
|
||||
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);
|
||||
|
||||
xpad = 2*(border_width + xthickness + focus_width + focus_pad);
|
||||
|
||||
minimum_width = child_min + sep_width + arrow_width + xpad;
|
||||
natural_width = child_nat + sep_width + arrow_width + xpad;
|
||||
}
|
||||
else
|
||||
{
|
||||
gint but_width, but_nat_width;
|
||||
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button),
|
||||
&but_width, &but_nat_width);
|
||||
|
||||
minimum_width = child_min + but_width;
|
||||
natural_width = child_nat + but_nat_width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* list mode */
|
||||
gint button_width, button_nat_width;
|
||||
|
||||
/* sample + frame */
|
||||
minimum_width = child_min;
|
||||
natural_width = child_nat;
|
||||
|
||||
minimum_width += 2 * focus_width;
|
||||
natural_width += 2 * focus_width;
|
||||
|
||||
if (priv->cell_view_frame)
|
||||
{
|
||||
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);
|
||||
|
||||
minimum_width += xpad;
|
||||
natural_width += xpad;
|
||||
}
|
||||
}
|
||||
|
||||
/* the button */
|
||||
gtk_size_request_get_width (GTK_SIZE_REQUEST (priv->button),
|
||||
&button_width, &button_nat_width);
|
||||
|
||||
minimum_width += button_width;
|
||||
natural_width += button_nat_width;
|
||||
}
|
||||
|
||||
if (GTK_SHADOW_NONE != priv->shadow_type)
|
||||
{
|
||||
minimum_width += 2 * GTK_WIDGET (widget)->style->xthickness;
|
||||
natural_width += 2 * GTK_WIDGET (widget)->style->xthickness;
|
||||
}
|
||||
|
||||
if (minimum_size)
|
||||
*minimum_size = minimum_width;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = natural_width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_combo_box_get_height (GtkSizeRequest *widget,
|
||||
gint *minimum_size,
|
||||
gint *natural_size)
|
||||
{
|
||||
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;
|
||||
|
||||
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 = min_height;
|
||||
|
||||
if (natural_size)
|
||||
*natural_size = nat_height;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user