diff options
author | Tristan Van Berkom <tristan.van.berkom@gmail.com> | 2010-08-18 19:36:51 -0400 |
---|---|---|
committer | Tristan Van Berkom <tristan.van.berkom@gmail.com> | 2010-08-18 20:01:28 -0400 |
commit | e2a82c70b4cb8f59451f8b00dfce33a4f23ff998 (patch) | |
tree | c9a2579f4a86d67293498b9c0aa1f4c75fb5dd39 /gtk | |
parent | fa565f3a3e1d459591dd9068e80767420c58fd8b (diff) | |
download | gtk+-e2a82c70b4cb8f59451f8b00dfce33a4f23ff998.tar.gz |
Added/Implemented GtkCellSizeRequestIface
This patch adds height-for-width geometry management
for cell renderers while still responding to the old
gtk_cell_renderer_get_size() apis with virtual return values
(obtained by soliciting the new height-for-width cell renderer
apis).
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkcellrenderer.c | 234 | ||||
-rw-r--r-- | gtk/gtkcellrenderer.h | 8 | ||||
-rw-r--r-- | gtk/gtkcellrenderertext.c | 225 | ||||
-rw-r--r-- | gtk/gtkcellsizerequest.c | 335 | ||||
-rw-r--r-- | gtk/gtkcellsizerequest.h | 92 |
5 files changed, 835 insertions, 59 deletions
diff --git a/gtk/gtkcellrenderer.c b/gtk/gtkcellrenderer.c index 17744e8ee8..8c940f24d7 100644 --- a/gtk/gtkcellrenderer.c +++ b/gtk/gtkcellrenderer.c @@ -19,12 +19,15 @@ #include "config.h" #include "gtkcellrenderer.h" +#include "gtkcellsizerequest.h" #include "gtkintl.h" #include "gtkmarshalers.h" #include "gtkprivate.h" #include "gtktreeprivate.h" +static void gtk_cell_renderer_init (GtkCellRenderer *cell); +static void gtk_cell_renderer_class_init (GtkCellRendererClass *class); static void gtk_cell_renderer_get_property (GObject *object, guint param_id, GValue *value, @@ -36,6 +39,28 @@ static void gtk_cell_renderer_set_property (GObject *object, static void set_cell_bg_color (GtkCellRenderer *cell, GdkColor *color); +/* Fallback GtkCellSizeRequest implementation to use remaining ->get_size() implementations */ +static void gtk_cell_renderer_cell_size_request_init (GtkCellSizeRequestIface *iface); +static void gtk_cell_renderer_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_cell_renderer_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_cell_renderer_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); +static void gtk_cell_renderer_get_width_for_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); + + struct _GtkCellRendererPriv { @@ -86,9 +111,50 @@ enum { LAST_SIGNAL }; -static guint cell_renderer_signals[LAST_SIGNAL] = { 0 }; +static guint cell_renderer_signals[LAST_SIGNAL] = { 0 }; + + +/* Do a manual _get_type() here to avoid a deadlock implementing + * the interface which we are a prerequisite of. + */ +GType +gtk_cell_renderer_get_type (void) +{ + static GType cell_renderer_type = 0; + + if (G_UNLIKELY (cell_renderer_type == 0)) + { + const GTypeInfo cell_renderer_info = + { + sizeof (GtkCellRendererClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gtk_cell_renderer_class_init, + NULL, /* class_finalize */ + NULL, /* class_init */ + sizeof (GtkCellRenderer), + 0, /* n_preallocs */ + (GInstanceInitFunc) gtk_cell_renderer_init, + NULL, /* value_table */ + }; + + const GInterfaceInfo cell_size_request_info = + { + (GInterfaceInitFunc) gtk_cell_renderer_cell_size_request_init, + (GInterfaceFinalizeFunc) NULL, + NULL /* interface data */ + }; + + cell_renderer_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkCellRenderer", + &cell_renderer_info, G_TYPE_FLAG_ABSTRACT); + + g_type_add_interface_static (cell_renderer_type, GTK_TYPE_CELL_SIZE_REQUEST, + &cell_size_request_info) ; + } + + return cell_renderer_type; +} -G_DEFINE_ABSTRACT_TYPE (GtkCellRenderer, gtk_cell_renderer, GTK_TYPE_OBJECT) static void gtk_cell_renderer_init (GtkCellRenderer *cell) @@ -514,6 +580,9 @@ set_cell_bg_color (GtkCellRenderer *cell, * * Please note that the values set in @width and @height, as well as those * in @x_offset and @y_offset are inclusive of the xpad and ypad properties. + * + * + * Deprecated: 3.0: Use gtk_cell_size_request_get_size() instead. **/ void gtk_cell_renderer_get_size (GtkCellRenderer *cell, @@ -524,33 +593,22 @@ gtk_cell_renderer_get_size (GtkCellRenderer *cell, gint *width, gint *height) { - GtkCellRendererPriv *priv; - gint *real_width = width; - gint *real_height = height; + GtkRequisition request; g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); - g_return_if_fail (GTK_CELL_RENDERER_GET_CLASS (cell)->get_size != NULL); - priv = cell->priv; + gtk_cell_size_request_get_size (GTK_CELL_SIZE_REQUEST (cell), + widget, &request, NULL); - if (width && priv->width != -1) - { - real_width = NULL; - *width = priv->width; - } - if (height && priv->height != -1) - { - real_height = NULL; - *height = priv->height; - } + if (width) + *width = request.width; + + if (height) + *height = request.height; - GTK_CELL_RENDERER_GET_CLASS (cell)->get_size (cell, - widget, - (GdkRectangle *) cell_area, - x_offset, - y_offset, - real_width, - real_height); + if (cell_area) + _gtk_cell_renderer_calc_offset (cell, cell_area, gtk_widget_get_direction (widget), + request.width, request.height, x_offset, y_offset); } /** @@ -1035,3 +1093,131 @@ gtk_cell_renderer_stop_editing (GtkCellRenderer *cell, g_signal_emit (cell, cell_renderer_signals[EDITING_CANCELED], 0); } } + +static void +gtk_cell_renderer_cell_size_request_init (GtkCellSizeRequestIface *iface) +{ + iface->get_width = gtk_cell_renderer_get_width; + iface->get_height = gtk_cell_renderer_get_height; + + iface->get_width_for_height = gtk_cell_renderer_get_width_for_height; + iface->get_height_for_width = gtk_cell_renderer_get_height_for_width; +} + +static void +gtk_cell_renderer_get_desired_size (GtkCellSizeRequest *cell, + GtkWidget *widget, + GtkOrientation orientation, + gint *minimum_size, + gint *natural_size) +{ + GtkRequisition min_req; + + /* Fallback on the old API to get the size. */ + if (GTK_CELL_RENDERER_GET_CLASS (cell)->get_size) + GTK_CELL_RENDERER_GET_CLASS (cell)->get_size (GTK_CELL_RENDERER (cell), widget, NULL, NULL, NULL, + &min_req.width, &min_req.height); + else + { + min_req.width = 0; + min_req.height = 0; + } + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (minimum_size) + *minimum_size = min_req.width; + + if (natural_size) + *natural_size = min_req.width; + } + else + { + if (minimum_size) + *minimum_size = min_req.height; + + if (natural_size) + *natural_size = min_req.height; + } +} + +static void +gtk_cell_renderer_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gtk_cell_renderer_get_desired_size (cell, widget, GTK_ORIENTATION_HORIZONTAL, + minimum_size, natural_size); +} + +static void +gtk_cell_renderer_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gtk_cell_renderer_get_desired_size (cell, widget, GTK_ORIENTATION_VERTICAL, + minimum_size, natural_size); +} + + +static void +gtk_cell_renderer_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height) +{ + /* Fall back on the height reported from ->get_size() */ + gtk_cell_size_request_get_height (cell, widget, minimum_height, natural_height); +} + +static void +gtk_cell_renderer_get_width_for_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width) +{ + /* Fall back on the width reported from ->get_size() */ + gtk_cell_size_request_get_width (cell, widget, minimum_width, natural_width); +} + +/* An internal convenience function for some containers to peek at the + * cell alignment in a target allocation (used to draw focus and align + * cells in the icon view). + * + * Note this is only a trivial 'align * (allocation - request)' operation. + */ +void +_gtk_cell_renderer_calc_offset (GtkCellRenderer *cell, + const GdkRectangle *cell_area, + GtkTextDirection direction, + gint width, + gint height, + gint *x_offset, + gint *y_offset) +{ + GtkCellRendererPriv *priv; + + g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); + g_return_if_fail (cell_area != NULL); + g_return_if_fail (x_offset || y_offset); + + priv = cell->priv; + + if (x_offset) + { + *x_offset = (((direction == GTK_TEXT_DIR_RTL) ? + (1.0 - priv->xalign) : priv->xalign) * + (cell_area->width - width)); + *x_offset = MAX (*x_offset, 0); + } + if (y_offset) + { + *y_offset = (priv->yalign * + (cell_area->height - height)); + *y_offset = MAX (*y_offset, 0); + } +} diff --git a/gtk/gtkcellrenderer.h b/gtk/gtkcellrenderer.h index 9e3dff8ff8..fac5b8daf9 100644 --- a/gtk/gtkcellrenderer.h +++ b/gtk/gtkcellrenderer.h @@ -174,6 +174,14 @@ void gtk_cell_renderer_stop_editing (GtkCellRenderer *cell, gboolean canceled); +void _gtk_cell_renderer_calc_offset (GtkCellRenderer *cell, + const GdkRectangle *cell_area, + GtkTextDirection direction, + gint width, + gint height, + gint *x_offset, + gint *y_offset); + G_END_DECLS #endif /* __GTK_CELL_RENDERER_H__ */ diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c index 435bb3dfd4..f55a2b0d6b 100644 --- a/gtk/gtkcellrenderertext.c +++ b/gtk/gtkcellrenderertext.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include "gtkcellrenderertext.h" #include "gtkeditable.h" +#include "gtkcellsizerequest.h" #include "gtkentry.h" #include "gtkmarshalers.h" #include "gtkintl.h" @@ -38,13 +39,6 @@ static void gtk_cell_renderer_text_set_property (GObject *obje guint param_id, const GValue *value, GParamSpec *pspec); -static void gtk_cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); static void gtk_cell_renderer_text_render (GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, @@ -61,6 +55,21 @@ static GtkCellEditable *gtk_cell_renderer_text_start_editing (GtkCellRenderer GdkRectangle *cell_area, GtkCellRendererState flags); +static void gtk_cell_renderer_text_cell_size_request_init (GtkCellSizeRequestIface *iface); +static void gtk_cell_renderer_text_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimal_size, + gint *natural_size); +static void gtk_cell_renderer_text_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimal_size, + gint *natural_size); +static void gtk_cell_renderer_text_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); + enum { EDITED, LAST_SIGNAL @@ -169,7 +178,9 @@ struct _GtkCellRendererTextPriv gulong entry_menu_popdown_timeout; }; -G_DEFINE_TYPE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER) +G_DEFINE_TYPE_WITH_CODE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER, + G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_SIZE_REQUEST, + gtk_cell_renderer_text_cell_size_request_init)) static void gtk_cell_renderer_text_init (GtkCellRendererText *celltext) @@ -206,7 +217,6 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) object_class->get_property = gtk_cell_renderer_text_get_property; object_class->set_property = gtk_cell_renderer_text_set_property; - cell_class->get_size = gtk_cell_renderer_text_get_size; cell_class->render = gtk_cell_renderer_text_render; cell_class->start_editing = gtk_cell_renderer_text_start_editing; @@ -479,7 +489,7 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class) /** * GtkCellRendererText:wrap-width: * - * Specifies the width at which the text is wrapped. The wrap-mode property can + * Specifies the minimum width at which the text is wrapped. The wrap-mode property can * be used to influence at what character positions the line breaks can be placed. * Setting wrap-width to -1 turns wrapping off. * @@ -1382,16 +1392,19 @@ add_attr (PangoAttrList *attr_list, static PangoLayout* get_layout (GtkCellRendererText *celltext, GtkWidget *widget, - gboolean will_render, + GdkRectangle *cell_area, GtkCellRendererState flags) { GtkCellRendererTextPriv *priv = celltext->priv; PangoAttrList *attr_list; PangoLayout *layout; PangoUnderline uline; + gint xpad; layout = gtk_widget_create_pango_layout (widget, priv->text); + gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (celltext), &xpad, NULL); + if (priv->extra_attrs) attr_list = pango_attr_list_copy (priv->extra_attrs); else @@ -1399,7 +1412,7 @@ get_layout (GtkCellRendererText *celltext, pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph); - if (will_render) + if (cell_area) { /* Add options that affect appearance but not size */ @@ -1460,6 +1473,11 @@ get_layout (GtkCellRendererText *celltext, if (priv->rise_set) add_attr (attr_list, pango_attr_rise_new (priv->rise)); + /* Now apply the attributes as they will effect the outcome + * of pango_layout_get_extents() */ + pango_layout_set_attributes (layout, attr_list); + pango_attr_list_unref (attr_list); + if (priv->ellipsize_set) pango_layout_set_ellipsize (layout, priv->ellipsize); else @@ -1467,7 +1485,20 @@ get_layout (GtkCellRendererText *celltext, if (priv->wrap_width != -1) { - pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE); + PangoRectangle rect; + gint width, text_width; + + pango_layout_get_extents (layout, NULL, &rect); + text_width = rect.width; + + if (cell_area) + width = (cell_area->width - xpad * 2) * PANGO_SCALE; + else + width = priv->wrap_width * PANGO_SCALE; + + width = MIN (width, text_width); + + pango_layout_set_width (layout, width); pango_layout_set_wrap (layout, priv->wrap_mode); } else @@ -1489,14 +1520,11 @@ get_layout (GtkCellRendererText *celltext, pango_layout_set_alignment (layout, align); } - - pango_layout_set_attributes (layout, attr_list); - - pango_attr_list_unref (attr_list); return layout; } + static void get_size (GtkCellRenderer *cell, GtkWidget *widget, @@ -1559,7 +1587,7 @@ get_size (GtkCellRenderer *cell, if (layout) g_object_ref (layout); else - layout = get_layout (celltext, widget, FALSE, 0); + layout = get_layout (celltext, widget, NULL, 0); pango_layout_get_pixel_extents (layout, NULL, &rect); @@ -1620,20 +1648,6 @@ get_size (GtkCellRenderer *cell, g_object_unref (layout); } - -static void -gtk_cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - GdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - get_size (cell, widget, cell_area, NULL, - x_offset, y_offset, width, height); -} - static void gtk_cell_renderer_text_render (GtkCellRenderer *cell, GdkDrawable *window, @@ -1648,11 +1662,11 @@ gtk_cell_renderer_text_render (GtkCellRenderer *cell, GtkCellRendererTextPriv *priv = celltext->priv; PangoLayout *layout; GtkStateType state; - gint x_offset; - gint y_offset; + gint x_offset = 0; + gint y_offset = 0; gint xpad, ypad; - layout = get_layout (celltext, widget, TRUE, flags); + layout = get_layout (celltext, widget, cell_area, flags); get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL); if (!gtk_cell_renderer_get_sensitive (cell)) @@ -1965,3 +1979,144 @@ gtk_cell_renderer_text_set_fixed_height_from_font (GtkCellRendererText *renderer priv->calc_fixed_height = TRUE; } } + +static void +gtk_cell_renderer_text_cell_size_request_init (GtkCellSizeRequestIface *iface) +{ + iface->get_width = gtk_cell_renderer_text_get_width; + iface->get_height = gtk_cell_renderer_text_get_height; + iface->get_height_for_width = gtk_cell_renderer_text_get_height_for_width; +} + +static void +gtk_cell_renderer_text_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + GtkCellRendererTextPriv *priv; + GtkCellRendererText *celltext; + PangoLayout *layout; + PangoContext *context; + PangoFontMetrics *metrics; + PangoRectangle rect; + gint char_width, digit_width, char_pixels, text_width, ellipsize_chars, guess_width, xpad; + gint min_width; + + /* "width-chars" Hard-coded minimum width: + * - minimum size should be MAX (width-chars, strlen ("...")); + * - natural size should be MAX (width-chars, strlen (label->text)); + * + * "wrap-width" User specified natural wrap width + * - minimum size should be MAX (width-chars, 0) + * - natural size should be MIN (wrap-width, strlen (label->text)) + */ + + celltext = GTK_CELL_RENDERER_TEXT (cell); + priv = celltext->priv; + + gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (cell), &xpad, NULL); + + layout = get_layout (celltext, widget, NULL, 0); + + /* Get the layout with the text possibly wrapping at wrap_width */ + pango_layout_get_pixel_extents (layout, NULL, &rect); + guess_width = rect.width; + + /* Fetch the length of the complete unwrapped text */ + pango_layout_set_width (layout, -1); + pango_layout_get_extents (layout, NULL, &rect); + text_width = rect.width; + + /* Fetch the average size of a charachter */ + context = pango_layout_get_context (layout); + metrics = pango_context_get_metrics (context, widget->style->font_desc, + pango_context_get_language (context)); + + char_width = pango_font_metrics_get_approximate_char_width (metrics); + digit_width = pango_font_metrics_get_approximate_digit_width (metrics); + char_pixels = MAX (char_width, digit_width); + + pango_font_metrics_unref (metrics); + g_object_unref (layout); + + /* enforce minimum width for ellipsized labels at ~3 chars */ + if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) + ellipsize_chars = 3; + else + ellipsize_chars = 0; + + if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->width_chars > 0) + min_width = + xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, ellipsize_chars)); + /* If no width-chars set, minimum for wrapping text will be the wrap-width */ + else if (priv->wrap_width > -1) + min_width = xpad * 2 + rect.x + priv->wrap_width; + else + min_width = xpad * 2 + rect.x + guess_width; + + if (minimum_size) + *minimum_size = min_width; + + if (natural_size) + { + /* Control the max wrap width here possibly (add max-width-chars ?) */ + *natural_size = xpad * 2 + + MAX ((PANGO_PIXELS (char_width) * priv->width_chars), PANGO_PIXELS (text_width)); + + *natural_size = MAX (*natural_size, min_width); + } +} + +static void +gtk_cell_renderer_text_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height) +{ + GtkCellRendererTextPriv *priv; + GtkCellRendererText *celltext; + PangoLayout *layout; + gint text_height, xpad, ypad; + + + celltext = GTK_CELL_RENDERER_TEXT (cell); + priv = celltext->priv; + + gtk_cell_renderer_get_padding (GTK_CELL_RENDERER (cell), &xpad, &ypad); + + layout = get_layout (celltext, widget, FALSE, 0); + + pango_layout_set_width (layout, (width - xpad * 2) * PANGO_SCALE); + pango_layout_get_pixel_size (layout, NULL, &text_height); + + if (minimum_height) + *minimum_height = text_height + ypad * 2; + + if (natural_height) + *natural_height = text_height + ypad * 2; + + g_object_unref (layout); +} + +static void +gtk_cell_renderer_text_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gint min_width; + + /* Thankfully cell renderers dont rotate, so they only have to do + * height-for-width and not the opposite. Here we have only to return + * the height for the base minimum width of the renderer. + * + * Note this code path wont be followed by GtkTreeView which is + * height-for-width specifically. + */ + gtk_cell_size_request_get_width (cell, widget, &min_width, NULL); + gtk_cell_renderer_text_get_height_for_width (cell, widget, min_width, + minimum_size, natural_size); +} + diff --git a/gtk/gtkcellsizerequest.c b/gtk/gtkcellsizerequest.c new file mode 100644 index 0000000000..a09c45e250 --- /dev/null +++ b/gtk/gtkcellsizerequest.c @@ -0,0 +1,335 @@ +/* gtkcellsizerequest.c + * Copyright (C) 2010 Openismus GmbH + * + * Author: + * Tristan Van Berkom <tristan.van.berkom@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include <config.h> +#include "gtkcellrenderer.h" +#include "gtkcellsizerequest.h" +#include "gtkintl.h" + + +#define DEBUG_CELL_SIZE_REQUEST 0 + +GType +gtk_cell_size_request_get_type (void) +{ + static GType cell_size_request_type = 0; + + if (G_UNLIKELY(!cell_size_request_type)) + { + cell_size_request_type = + g_type_register_static_simple (G_TYPE_INTERFACE, I_("GtkCellSizeRequest"), + sizeof (GtkCellSizeRequestIface), + NULL, 0, NULL, 0); + + g_type_interface_add_prerequisite (cell_size_request_type, GTK_TYPE_CELL_RENDERER); + } + return cell_size_request_type; +} + +/** + * gtk_cell_size_request_get_request_mode: + * @cell: a #GtkCellSizeRequest instance + * + * Gets whether the cell renderer prefers a height-for-width layout + * or a width-for-height layout. + * + * Returns: The #GtkSizeRequestMode preferred by this renderer. + * + * Since: 3.0 + */ +GtkSizeRequestMode +gtk_cell_size_request_get_request_mode (GtkCellSizeRequest *cell) +{ + GtkCellSizeRequestIface *iface; + + g_return_val_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell), FALSE); + + iface = GTK_CELL_SIZE_REQUEST_GET_IFACE (cell); + if (iface->get_request_mode) + return iface->get_request_mode (cell); + + /* By default cell renderers are height-for-width. */ + return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH; +} + +/** + * gtk_cell_size_request_get_width: + * @cell: a #GtkCellSizeRequest instance + * @widget: the #GtkWidget this cell will be rendering to + * @minimum_size: location to store the minimum size, or %NULL + * @natural_size: location to store the natural size, or %NULL + * + * Retreives a renderer's natural size when rendered to @widget. + * + * Since: 3.0 + */ +void +gtk_cell_size_request_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + GtkCellSizeRequestIface *iface; + gint width; + + g_return_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (NULL != minimum_size || NULL != natural_size); + + gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), &width, NULL); + + if (width < 0) + { + iface = GTK_CELL_SIZE_REQUEST_GET_IFACE (cell); + iface->get_width (cell, widget, minimum_size, natural_size); + } + else + { + if (minimum_size) + *minimum_size = width; + if (natural_size) + *natural_size = width; + } + +#if DEBUG_CELL_SIZE_REQUEST + g_message ("%s returning minimum width: %d and natural width: %d", + G_OBJECT_TYPE_NAME (cell), + minimum_size ? *minimum_size : 20000, + natural_size ? *natural_size : 20000); +#endif +} + + +/** + * gtk_cell_size_request_get_height: + * @cell: a #GtkCellSizeRequest instance + * @widget: the #GtkWidget this cell will be rendering to + * @minimum_size: location to store the minimum size, or %NULL + * @natural_size: location to store the natural size, or %NULL + * + * Retreives a renderer's natural size when rendered to @widget. + * + * Since: 3.0 + */ +void +gtk_cell_size_request_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + GtkCellSizeRequestIface *iface; + gint height; + + g_return_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (NULL != minimum_size || NULL != natural_size); + + gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), NULL, &height); + + if (height < 0) + { + iface = GTK_CELL_SIZE_REQUEST_GET_IFACE (cell); + iface->get_height (cell, widget, minimum_size, natural_size); + } + else + { + if (minimum_size) + *minimum_size = height; + if (natural_size) + *natural_size = height; + } + +#if DEBUG_CELL_SIZE_REQUEST + g_message ("%s returning minimum height: %d and natural height: %d", + G_OBJECT_TYPE_NAME (cell), + minimum_size ? *minimum_size : 20000, + natural_size ? *natural_size : 20000); +#endif +} + + +/** + * gtk_cell_size_request_get_width_for_height: + * @cell: a #GtkCellSizeRequest instance + * @widget: the #GtkWidget this cell will be rendering to + * @height: the size which is available for allocation + * @minimum_width: location for storing the minimum size, or %NULL + * @natural_width: location for storing the preferred size, or %NULL + * + * Retreives a cell renderers's minimum and natural width if it were rendered to + * @widget with the specified @height. + * + * Since: 3.0 + */ +void +gtk_cell_size_request_get_width_for_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width) +{ + GtkCellSizeRequestIface *iface; + gint width; + + g_return_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (NULL != minimum_width || NULL != natural_width); + + gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), &width, NULL); + + if (width < 0) + { + iface = GTK_CELL_SIZE_REQUEST_GET_IFACE (cell); + iface->get_width_for_height (cell, widget, height, minimum_width, natural_width); + } + else + { + if (minimum_width) + *minimum_width = width; + if (natural_width) + *natural_width = width; + } + +#if DEBUG_CELL_SIZE_REQUEST + g_message ("%s width for height: %d is minimum %d and natural: %d", + G_OBJECT_TYPE_NAME (cell), height, + minimum_width ? *minimum_width : 20000, + natural_width ? *natural_width : 20000); +#endif +} + +/** + * gtk_cell_size_request_get_height_for_width: + * @cell: a #GtkCellSizeRequest instance + * @widget: the #GtkWidget this cell will be rendering to + * @width: the size which is available for allocation + * @minimum_height: location for storing the minimum size, or %NULL + * @natural_height: location for storing the preferred size, or %NULL + * + * Retreives a cell renderers's minimum and natural height if it were rendered to + * @widget with the specified @width. + * + * Since: 3.0 + */ +void +gtk_cell_size_request_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height) +{ + GtkCellSizeRequestIface *iface; + gint height; + + g_return_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (NULL != minimum_height || NULL != natural_height); + + gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), NULL, &height); + + if (height < 0) + { + iface = GTK_CELL_SIZE_REQUEST_GET_IFACE (cell); + iface->get_height_for_width (cell, widget, width, minimum_height, natural_height); + } + else + { + if (minimum_height) + *minimum_height = height; + if (natural_height) + *natural_height = height; + } + +#if DEBUG_CELL_SIZE_REQUEST + g_message ("%s height for width: %d is minimum %d and natural: %d", + G_OBJECT_TYPE_NAME (cell), width, + minimum_height ? *minimum_height : 20000, + natural_height ? *natural_height : 20000); +#endif +} + +/** + * gtk_cell_size_request_get_size: + * @cell: a #GtkCellSizeRequest instance + * @widget: the #GtkWidget this cell will be rendering to + * @request_natural: Whether to base the contextual request off of the + * base natural or the base minimum + * @minimum_size: (out) (allow-none): location for storing the minimum size, or %NULL + * @natural_size: (out) (allow-none): location for storing the natural size, or %NULL + * + * Retrieves the minimum and natural size of a cell taking + * into account the widget's preference for height-for-width management. + * + * If request_natural is specified, the non-contextual natural value will + * be used to make the contextual request; otherwise the minimum will be used. + * + * Since: 3.0 + */ +void +gtk_cell_size_request_get_size (GtkCellSizeRequest *cell, + GtkWidget *widget, + GtkRequisition *minimum_size, + GtkRequisition *natural_size) +{ + gint min_width, nat_width; + gint min_height, nat_height; + + g_return_if_fail (GTK_IS_CELL_SIZE_REQUEST (cell)); + + if (gtk_cell_size_request_get_request_mode (cell) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH) + { + gtk_cell_size_request_get_width (cell, widget, &min_width, &nat_width); + + if (minimum_size) + { + minimum_size->width = min_width; + gtk_cell_size_request_get_height_for_width (cell, widget, min_width, + &minimum_size->height, NULL); + } + + if (natural_size) + { + natural_size->width = nat_width; + gtk_cell_size_request_get_height_for_width (cell, widget, nat_width, + NULL, &natural_size->height); + } + } + else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */ + { + gtk_cell_size_request_get_height (cell, widget, &min_height, &nat_height); + + if (minimum_size) + { + minimum_size->height = min_height; + gtk_cell_size_request_get_width_for_height (cell, widget, min_height, + &minimum_size->width, NULL); + } + + if (natural_size) + { + natural_size->height = nat_height; + gtk_cell_size_request_get_width_for_height (cell, widget, nat_height, + NULL, &natural_size->width); + } + } +} diff --git a/gtk/gtkcellsizerequest.h b/gtk/gtkcellsizerequest.h new file mode 100644 index 0000000000..c69fce893a --- /dev/null +++ b/gtk/gtkcellsizerequest.h @@ -0,0 +1,92 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2010 Openismus GmbH + * + * Author: + * Tristan Van Berkom <tristan.van.berkom@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_CELL_SIZE_REQUEST_H__ +#define __GTK_CELL_SIZE_REQUEST_H__ + +#include <gtk/gtkwidget.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_CELL_SIZE_REQUEST (gtk_cell_size_request_get_type ()) +#define GTK_CELL_SIZE_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_SIZE_REQUEST, GtkCellSizeRequest)) +#define GTK_CELL_SIZE_REQUEST_CLASS(klass) ((GtkCellSizeRequestIface*)g_type_interface_peek ((klass), GTK_TYPE_CELL_SIZE_REQUEST)) +#define GTK_IS_CELL_SIZE_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_SIZE_REQUEST)) +#define GTK_CELL_SIZE_REQUEST_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_CELL_SIZE_REQUEST, GtkCellSizeRequestIface)) + +typedef struct _GtkCellSizeRequest GtkCellSizeRequest; +typedef struct _GtkCellSizeRequestIface GtkCellSizeRequestIface; + +struct _GtkCellSizeRequestIface +{ + GTypeInterface g_iface; + + /* virtual table */ + GtkSizeRequestMode (* get_request_mode) (GtkCellSizeRequest *cell); + void (* get_width) (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); + void (* get_height_for_width) (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); + void (* get_height) (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); + void (* get_width_for_height) (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); +}; + +GType gtk_cell_size_request_get_type (void) G_GNUC_CONST; +GtkSizeRequestMode gtk_cell_size_request_get_request_mode (GtkCellSizeRequest *cell); +void gtk_cell_size_request_get_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +void gtk_cell_size_request_get_height_for_width (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); +void gtk_cell_size_request_get_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +void gtk_cell_size_request_get_width_for_height (GtkCellSizeRequest *cell, + GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); +void gtk_cell_size_request_get_size (GtkCellSizeRequest *cell, + GtkWidget *widget, + GtkRequisition *minimum_size, + GtkRequisition *natural_size); + +G_END_DECLS + +#endif /* __GTK_CELL_SIZE_REQUEST_H__ */ |