1 /* Copyright (c) 2007, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <glib/gi18n-lib.h>
33 #include <gtk/gtkwidget.h>
35 #include <modest-text-utils.h>
36 #include <modest-hbox-cell-renderer.h>
38 #define RENDERER_EXPAND_ATTRIBUTE "box-expand"
40 static GObjectClass *parent_class = NULL;
47 typedef struct _ModestHBoxCellRendererPrivate ModestHBoxCellRendererPrivate;
49 struct _ModestHBoxCellRendererPrivate
51 GList *renderers_list;
54 #define MODEST_HBOX_CELL_RENDERER_GET_PRIVATE(o) \
55 (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_HBOX_CELL_RENDERER, ModestHBoxCellRendererPrivate))
57 /* static guint signals[LAST_SIGNAL] = {0}; */
59 /* static functions: GObject */
60 static void modest_hbox_cell_renderer_instance_init (GTypeInstance *instance, gpointer g_class);
61 static void modest_hbox_cell_renderer_finalize (GObject *object);
62 static void modest_hbox_cell_renderer_class_init (ModestHBoxCellRendererClass *klass);
64 /* static functions: GtkCellRenderer */
65 static void modest_hbox_cell_renderer_get_size (GtkCellRenderer *cell,
67 GdkRectangle *rectangle,
72 static void modest_hbox_cell_renderer_render (GtkCellRenderer *cell,
75 GdkRectangle *background_area,
76 GdkRectangle *cell_area,
77 GdkRectangle *expose_area,
78 GtkCellRendererState flags);
82 * modest_hbox_cell_renderer_new:
84 * Return value: a new #ModestHBoxCellRenderer instance implemented for Gtk+
87 modest_hbox_cell_renderer_new (void)
89 ModestHBoxCellRenderer *self = g_object_new (MODEST_TYPE_HBOX_CELL_RENDERER, NULL);
91 return GTK_CELL_RENDERER (self);
95 modest_hbox_cell_renderer_instance_init (GTypeInstance *instance, gpointer g_class)
97 ModestHBoxCellRendererPrivate *priv = MODEST_HBOX_CELL_RENDERER_GET_PRIVATE (instance);
99 priv->renderers_list = NULL;
105 modest_hbox_cell_renderer_finalize (GObject *object)
107 ModestHBoxCellRendererPrivate *priv = MODEST_HBOX_CELL_RENDERER_GET_PRIVATE (object);
109 if (priv->renderers_list != NULL) {
110 g_list_foreach (priv->renderers_list, (GFunc) g_object_unref, NULL);
111 g_list_free (priv->renderers_list);
112 priv->renderers_list = NULL;
115 (*parent_class->finalize) (object);
121 modest_hbox_cell_renderer_class_init (ModestHBoxCellRendererClass *klass)
123 GObjectClass *object_class;
124 GtkCellRendererClass *renderer_class;
126 parent_class = g_type_class_peek_parent (klass);
127 object_class = (GObjectClass*) klass;
128 renderer_class = (GtkCellRendererClass*) klass;
130 object_class->finalize = modest_hbox_cell_renderer_finalize;
131 renderer_class->get_size = modest_hbox_cell_renderer_get_size;
132 renderer_class->render = modest_hbox_cell_renderer_render;
134 g_type_class_add_private (object_class, sizeof (ModestHBoxCellRendererPrivate));
140 modest_hbox_cell_renderer_get_type (void)
142 static GType type = 0;
144 if (G_UNLIKELY(type == 0))
146 static const GTypeInfo info =
148 sizeof (ModestHBoxCellRendererClass),
149 NULL, /* base_init */
150 NULL, /* base_finalize */
151 (GClassInitFunc) modest_hbox_cell_renderer_class_init, /* class_init */
152 NULL, /* class_finalize */
153 NULL, /* class_data */
154 sizeof (ModestHBoxCellRenderer),
156 modest_hbox_cell_renderer_instance_init /* instance_init */
159 type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
160 "ModestHBoxCellRenderer",
170 * modest_hbox_cell_renderer_append:
171 * @hbox_renderer: a #ModestHBoxCellRenderer
172 * @cell: a #GtkCellRenderer
174 * Appends @cell to the end of the list of renderers shown in @hbox_renderer
177 modest_hbox_cell_renderer_append (ModestHBoxCellRenderer *hbox_renderer,
178 GtkCellRenderer *cell,
181 ModestHBoxCellRendererPrivate *priv = MODEST_HBOX_CELL_RENDERER_GET_PRIVATE (hbox_renderer);
183 priv->renderers_list = g_list_append (priv->renderers_list, cell);
184 g_object_set_data (G_OBJECT (cell), RENDERER_EXPAND_ATTRIBUTE, GINT_TO_POINTER (expand));
186 #if GLIB_CHECK_VERSION(2, 10, 0) /* g_object_ref_sink() was added in glib 2.10: */
187 g_object_ref_sink (G_OBJECT (cell));
189 g_object_ref (G_OBJECT (cell));
190 gtk_object_sink (GTK_OBJECT (cell));
195 modest_hbox_cell_renderer_get_size (GtkCellRenderer *cell,
197 GdkRectangle *rectangle,
203 gint calc_width, calc_height;
204 gint full_width, full_height;
206 ModestHBoxCellRendererPrivate *priv = MODEST_HBOX_CELL_RENDERER_GET_PRIVATE (cell);
211 for (node = priv->renderers_list; node != NULL; node = g_list_next (node)) {
212 gint renderer_width, renderer_height;
213 GtkCellRenderer *renderer = (GtkCellRenderer *) node->data;
215 gtk_cell_renderer_get_size (renderer, widget, NULL, NULL, NULL,
216 &renderer_width, &renderer_height);
217 if ((renderer_width > 0)&&(renderer_height > 0)) {
218 calc_height = MAX (calc_height, renderer_height);
219 calc_width += renderer_width;
223 full_width = (gint) cell->xpad * 2 + calc_width;
224 full_height = (gint) cell->ypad * 2 + calc_height;
226 if (rectangle && calc_width > 0 && calc_height > 0) {
228 *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
229 (1.0 - cell->xalign) : cell->xalign) *
230 (rectangle->width - full_width));
231 *x_offset = MAX (*x_offset, 0);
234 *y_offset = ((cell->yalign) *
235 (rectangle->height - full_height));
236 *y_offset = MAX (*y_offset, 0);
248 *height = full_height;
252 modest_hbox_cell_renderer_render (GtkCellRenderer *cell,
255 GdkRectangle *background_area,
256 GdkRectangle *cell_area,
257 GdkRectangle *expose_area,
258 GtkCellRendererState flags)
260 ModestHBoxCellRendererPrivate *priv = MODEST_HBOX_CELL_RENDERER_GET_PRIVATE (cell);
261 gint nvis_children = 0;
262 gint nexpand_children = 0;
263 GtkTextDirection direction;
265 GtkCellRenderer *child;
269 direction = gtk_widget_get_direction (widget);
271 nexpand_children = 0;
273 /* first, retrieve the requisition of the children cell renderers */
274 modest_hbox_cell_renderer_get_size (cell, widget, NULL, NULL, NULL, &(req.width), &(req.height));
276 /* Counts visible and expandable children cell renderers */
277 for (node = priv->renderers_list; node != NULL; node = g_list_next (node)) {
278 gboolean visible, expand;
279 child = (GtkCellRenderer *) node->data;
280 g_object_get (G_OBJECT (child), "visible", &visible, NULL);
281 expand = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), RENDERER_EXPAND_ATTRIBUTE));
286 nexpand_children += 1;
290 if (nvis_children > 0) {
293 GdkRectangle child_alloc;
295 if (nexpand_children > 0) {
296 width = cell_area->width - req.width;
297 extra = width / nexpand_children;
303 g_object_get (cell, "xpad", &x_pad, "ypad", &y_pad, NULL);
304 x = cell_area->x + x_pad;
305 child_alloc.y = cell_area->y + y_pad;
306 child_alloc.height = MAX (1, cell_area->height - y_pad * 2);
308 for (node = priv->renderers_list; node != NULL; node = g_list_next (node)) {
309 gboolean visible, expand;
311 child = (GtkCellRenderer *) node->data;
312 g_object_get (G_OBJECT (child), "visible", &visible, NULL);
313 expand = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), RENDERER_EXPAND_ATTRIBUTE));
316 GtkRequisition child_req;
317 gint child_xpad, child_ypad;
318 GdkRectangle child_expose_area;
320 gtk_cell_renderer_get_size (child, widget, NULL, NULL, NULL, &(child_req.width), &(child_req.height));
321 g_object_get (child, "xpad", &child_xpad, "ypad", &child_ypad, NULL);
324 if (nexpand_children == 1)
325 child_req.width += width;
327 child_req.width += extra;
328 nexpand_children -= 1;
332 child_alloc.width = MAX (1, child_req.width);
335 if (direction == GTK_TEXT_DIR_RTL)
336 child_alloc.x = cell_area->x + cell_area->width - (child_alloc.x - cell_area->x) - child_alloc.width;
338 if (gdk_rectangle_intersect (&child_alloc, expose_area, &child_expose_area))
339 gtk_cell_renderer_render (child, window, widget, background_area, &child_alloc, &child_expose_area, flags);
340 x += child_req.width;