src/nautilus-cell-renderer-pixbuf-emblem.c (17235B) - raw
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2 *
3 * nautilus-cell-renderer-pixbuf-emblem.c: cell renderer which can render
4 * an emblem on top of a pixbuf (for use in FMListView and FMTreeView)
5 * Copyright (C) 2003 Juerg Billeter
6 *
7 * Mail Notification
8 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25 #include "nautilus-cell-renderer-pixbuf-emblem.h"
26
27 static void nautilus_cell_renderer_pixbuf_emblem_get_property (GObject *object,
28 guint param_id,
29 GValue *value,
30 GParamSpec *pspec);
31 static void nautilus_cell_renderer_pixbuf_emblem_set_property (GObject *object,
32 guint param_id,
33 const GValue *value,
34 GParamSpec *pspec);
35 static void nautilus_cell_renderer_pixbuf_emblem_init (NautilusCellRendererPixbufEmblem *cellpixbuf);
36 static void nautilus_cell_renderer_pixbuf_emblem_class_init (NautilusCellRendererPixbufEmblemClass *klass);
37 static void nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object);
38 static void nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
39 GtkWidget *widget);
40 static void nautilus_cell_renderer_pixbuf_emblem_get_size (GtkCellRenderer *cell,
41 GtkWidget *widget,
42 GdkRectangle *rectangle,
43 gint *x_offset,
44 gint *y_offset,
45 gint *width,
46 gint *height);
47 static void nautilus_cell_renderer_pixbuf_emblem_render (GtkCellRenderer *cell,
48 GdkWindow *window,
49 GtkWidget *widget,
50 GdkRectangle *background_area,
51 GdkRectangle *cell_area,
52 GdkRectangle *expose_area,
53 GtkCellRendererState flags);
54
55 enum {
56 PROP_ZERO,
57 PROP_PIXBUF,
58 PROP_PIXBUF_EXPANDER_OPEN,
59 PROP_PIXBUF_EXPANDER_CLOSED,
60 PROP_STOCK_ID,
61 PROP_STOCK_SIZE,
62 PROP_STOCK_DETAIL,
63 PROP_PIXBUF_EMBLEM
64 };
65
66 static gpointer parent_class;
67
68 #define CELLINFO_KEY "nautilus-cell-renderer-pixbuf-emblem-info"
69
70 typedef struct _NautilusCellRendererPixbufEmblemInfo NautilusCellRendererPixbufEmblemInfo;
71 struct _NautilusCellRendererPixbufEmblemInfo
72 {
73 gchar *stock_id;
74 GtkIconSize stock_size;
75 gchar *stock_detail;
76 };
77
78 GType
79 nautilus_cell_renderer_pixbuf_emblem_get_type (void)
80 {
81 static GType cell_pixbuf_type = 0;
82
83 if (!cell_pixbuf_type) {
84 static const GTypeInfo cell_pixbuf_info =
85 {
86 sizeof (NautilusCellRendererPixbufEmblemClass),
87 NULL, /* base_init */
88 NULL, /* base_finalize */
89 (GClassInitFunc) nautilus_cell_renderer_pixbuf_emblem_class_init,
90 NULL, /* class_finalize */
91 NULL, /* class_data */
92 sizeof (NautilusCellRendererPixbufEmblem),
93 0, /* n_preallocs */
94 (GInstanceInitFunc) nautilus_cell_renderer_pixbuf_emblem_init,
95 };
96
97 cell_pixbuf_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
98 "NautilusCellRendererPixbufEmblem",
99 &cell_pixbuf_info, 0);
100 }
101
102 return cell_pixbuf_type;
103 }
104
105 static void
106 nautilus_cell_renderer_pixbuf_emblem_init (NautilusCellRendererPixbufEmblem *cellpixbuf)
107 {
108 NautilusCellRendererPixbufEmblemInfo *cellinfo;
109
110 cellinfo = g_new0 (NautilusCellRendererPixbufEmblemInfo, 1);
111 cellinfo->stock_size = GTK_ICON_SIZE_MENU;
112 g_object_set_data (G_OBJECT (cellpixbuf), CELLINFO_KEY, cellinfo);
113 }
114
115 static void
116 nautilus_cell_renderer_pixbuf_emblem_class_init (NautilusCellRendererPixbufEmblemClass *klass)
117 {
118 GObjectClass *object_class = G_OBJECT_CLASS (klass);
119 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
120
121 parent_class = g_type_class_peek_parent (klass);
122
123 object_class->finalize = nautilus_cell_renderer_pixbuf_emblem_finalize;
124
125 object_class->get_property = nautilus_cell_renderer_pixbuf_emblem_get_property;
126 object_class->set_property = nautilus_cell_renderer_pixbuf_emblem_set_property;
127
128 cell_class->get_size = nautilus_cell_renderer_pixbuf_emblem_get_size;
129 cell_class->render = nautilus_cell_renderer_pixbuf_emblem_render;
130
131 g_object_class_install_property (object_class,
132 PROP_PIXBUF,
133 g_param_spec_object ("pixbuf",
134 "Pixbuf Object",
135 "The pixbuf to render",
136 GDK_TYPE_PIXBUF,
137 G_PARAM_READABLE |
138 G_PARAM_WRITABLE));
139
140 g_object_class_install_property (object_class,
141 PROP_PIXBUF_EXPANDER_OPEN,
142 g_param_spec_object ("pixbuf_expander_open",
143 "Pixbuf Expander Open",
144 "Pixbuf for open expander",
145 GDK_TYPE_PIXBUF,
146 G_PARAM_READABLE |
147 G_PARAM_WRITABLE));
148
149 g_object_class_install_property (object_class,
150 PROP_PIXBUF_EXPANDER_CLOSED,
151 g_param_spec_object ("pixbuf_expander_closed",
152 "Pixbuf Expander Closed",
153 "Pixbuf for closed expander",
154 GDK_TYPE_PIXBUF,
155 G_PARAM_READABLE |
156 G_PARAM_WRITABLE));
157
158 g_object_class_install_property (object_class,
159 PROP_STOCK_ID,
160 g_param_spec_string ("stock_id",
161 "Stock ID",
162 "The stock ID of the stock icon to render",
163 NULL,
164 G_PARAM_READWRITE));
165
166 g_object_class_install_property (object_class,
167 PROP_STOCK_SIZE,
168 g_param_spec_enum ("stock_size",
169 "Size",
170 "The size of the rendered icon",
171 GTK_TYPE_ICON_SIZE,
172 GTK_ICON_SIZE_MENU,
173 G_PARAM_READWRITE));
174
175 g_object_class_install_property (object_class,
176 PROP_STOCK_DETAIL,
177 g_param_spec_string ("stock_detail",
178 "Detail",
179 "Render detail to pass to the theme engine",
180 NULL,
181 G_PARAM_READWRITE));
182
183 g_object_class_install_property (object_class,
184 PROP_PIXBUF_EMBLEM,
185 g_param_spec_object ("pixbuf_emblem",
186 "Pixbuf Emblem Object",
187 "The emblem to overlay",
188 GDK_TYPE_PIXBUF,
189 G_PARAM_READABLE |
190 G_PARAM_WRITABLE));
191 }
192
193 static void
194 nautilus_cell_renderer_pixbuf_emblem_finalize (GObject *object)
195 {
196 NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
197 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
198
199 if (cellpixbuf->pixbuf && cellinfo->stock_id) {
200 g_object_unref (cellpixbuf->pixbuf);
201 }
202
203 if (cellinfo->stock_id) {
204 g_free (cellinfo->stock_id);
205 }
206
207 if (cellinfo->stock_detail) {
208 g_free (cellinfo->stock_detail);
209 }
210
211 g_free (cellinfo);
212 g_object_set_data (object, CELLINFO_KEY, NULL);
213
214 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
215 }
216
217 static void
218 nautilus_cell_renderer_pixbuf_emblem_get_property (GObject *object,
219 guint param_id,
220 GValue *value,
221 GParamSpec *pspec)
222 {
223 NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
224 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
225
226 switch (param_id)
227 {
228 case PROP_PIXBUF:
229 g_value_set_object (value,
230 cellpixbuf->pixbuf ? G_OBJECT (cellpixbuf->pixbuf) : NULL);
231 break;
232 case PROP_PIXBUF_EXPANDER_OPEN:
233 g_value_set_object (value,
234 cellpixbuf->pixbuf_expander_open ? G_OBJECT (cellpixbuf->pixbuf_expander_open) : NULL);
235 break;
236 case PROP_PIXBUF_EXPANDER_CLOSED:
237 g_value_set_object (value,
238 cellpixbuf->pixbuf_expander_closed ? G_OBJECT (cellpixbuf->pixbuf_expander_closed) : NULL);
239 break;
240 case PROP_STOCK_ID:
241 g_value_set_string (value, cellinfo->stock_id);
242 break;
243 case PROP_STOCK_SIZE:
244 g_value_set_enum (value, cellinfo->stock_size);
245 break;
246 case PROP_STOCK_DETAIL:
247 g_value_set_string (value, cellinfo->stock_detail);
248 break;
249 case PROP_PIXBUF_EMBLEM:
250 g_value_set_object (value,
251 cellpixbuf->pixbuf_emblem ? G_OBJECT (cellpixbuf->pixbuf_emblem) : NULL);
252 break;
253
254 default:
255 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
256 break;
257 }
258 }
259
260 static void
261 nautilus_cell_renderer_pixbuf_emblem_set_property (GObject *object,
262 guint param_id,
263 const GValue *value,
264 GParamSpec *pspec)
265 {
266 GdkPixbuf *pixbuf;
267 NautilusCellRendererPixbufEmblem *cellpixbuf = NAUTILUS_CELL_RENDERER_PIXBUF_EMBLEM (object);
268 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (object, CELLINFO_KEY);
269
270 switch (param_id)
271 {
272 case PROP_PIXBUF:
273 pixbuf = (GdkPixbuf*) g_value_get_object (value);
274 if (pixbuf) {
275 g_object_ref (pixbuf);
276 }
277 if (cellpixbuf->pixbuf) {
278 g_object_unref (cellpixbuf->pixbuf);
279 }
280 cellpixbuf->pixbuf = pixbuf;
281 break;
282 case PROP_PIXBUF_EXPANDER_OPEN:
283 pixbuf = (GdkPixbuf*) g_value_get_object (value);
284 if (pixbuf) {
285 g_object_ref (pixbuf);
286 }
287 if (cellpixbuf->pixbuf_expander_open) {
288 g_object_unref (cellpixbuf->pixbuf_expander_open);
289 }
290 cellpixbuf->pixbuf_expander_open = pixbuf;
291 break;
292 case PROP_PIXBUF_EXPANDER_CLOSED:
293 pixbuf = (GdkPixbuf*) g_value_get_object (value);
294 if (pixbuf) {
295 g_object_ref (pixbuf);
296 }
297 if (cellpixbuf->pixbuf_expander_closed) {
298 g_object_unref (cellpixbuf->pixbuf_expander_closed);
299 }
300 cellpixbuf->pixbuf_expander_closed = pixbuf;
301 break;
302 case PROP_STOCK_ID:
303 if (cellinfo->stock_id) {
304 g_free (cellinfo->stock_id);
305 }
306 cellinfo->stock_id = g_strdup (g_value_get_string (value));
307 break;
308 case PROP_STOCK_SIZE:
309 cellinfo->stock_size = g_value_get_enum (value);
310 break;
311 case PROP_STOCK_DETAIL:
312 if (cellinfo->stock_detail) {
313 g_free (cellinfo->stock_detail);
314 }
315 cellinfo->stock_detail = g_strdup (g_value_get_string (value));
316 break;
317 case PROP_PIXBUF_EMBLEM:
318 pixbuf = (GdkPixbuf *) g_value_get_object (value);
319 if (pixbuf) {
320 g_object_ref (pixbuf);
321 }
322 if (cellpixbuf->pixbuf_emblem) {
323 g_object_unref (cellpixbuf->pixbuf_emblem);
324 }
325 cellpixbuf->pixbuf_emblem = pixbuf;
326 break;
327
328 default:
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
330 break;
331 }
332 }
333
334 GtkCellRenderer *
335 nautilus_cell_renderer_pixbuf_emblem_new (void)
336 {
337 return g_object_new (NAUTILUS_TYPE_CELL_RENDERER_PIXBUF_EMBLEM, NULL);
338 }
339
340 static void
341 nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (NautilusCellRendererPixbufEmblem *cellpixbuf,
342 GtkWidget *widget)
343 {
344 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cellpixbuf), CELLINFO_KEY);
345
346 if (cellpixbuf->pixbuf) {
347 g_object_unref (cellpixbuf->pixbuf);
348 }
349
350 cellpixbuf->pixbuf = gtk_widget_render_icon (widget,
351 cellinfo->stock_id,
352 cellinfo->stock_size,
353 cellinfo->stock_detail);
354 }
355
356 static void
357 nautilus_cell_renderer_pixbuf_emblem_get_size (GtkCellRenderer *cell,
358 GtkWidget *widget,
359 GdkRectangle *cell_area,
360 gint *x_offset,
361 gint *y_offset,
362 gint *width,
363 gint *height)
364 {
365 NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
366 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
367 gint pixbuf_width = 0;
368 gint pixbuf_height = 0;
369 gint calc_width;
370 gint calc_height;
371
372 if (!cellpixbuf->pixbuf && cellinfo->stock_id)
373 nautilus_cell_renderer_pixbuf_emblem_create_stock_pixbuf (cellpixbuf, widget);
374
375 if (cellpixbuf->pixbuf) {
376 pixbuf_width = gdk_pixbuf_get_width (cellpixbuf->pixbuf);
377 pixbuf_height = gdk_pixbuf_get_height (cellpixbuf->pixbuf);
378 }
379 if (cellpixbuf->pixbuf_expander_open) {
380 pixbuf_width = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_open));
381 pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_open));
382 }
383 if (cellpixbuf->pixbuf_expander_closed) {
384 pixbuf_width = MAX (pixbuf_width, gdk_pixbuf_get_width (cellpixbuf->pixbuf_expander_closed));
385 pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellpixbuf->pixbuf_expander_closed));
386 }
387
388 calc_width = (gint) cell->xpad * 2 + pixbuf_width;
389 calc_height = (gint) cell->ypad * 2 + pixbuf_height;
390
391 if (x_offset) *x_offset = 0;
392 if (y_offset) *y_offset = 0;
393
394 if (cell_area && pixbuf_width > 0 && pixbuf_height > 0) {
395 if (x_offset) {
396 *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
397 1.0 - cell->xalign : cell->xalign) *
398 (cell_area->width - calc_width - 2 * cell->xpad));
399 *x_offset = MAX (*x_offset, 0) + cell->xpad;
400 }
401 if (y_offset) {
402 *y_offset = (cell->yalign *
403 (cell_area->height - calc_height - 2 * cell->ypad));
404 *y_offset = MAX (*y_offset, 0) + cell->ypad;
405 }
406 }
407
408 if (width)
409 *width = calc_width;
410
411 if (height)
412 *height = calc_height;
413 }
414
415 static void
416 nautilus_cell_renderer_pixbuf_emblem_render (GtkCellRenderer *cell,
417 GdkWindow *window,
418 GtkWidget *widget,
419 GdkRectangle *background_area,
420 GdkRectangle *cell_area,
421 GdkRectangle *expose_area,
422 GtkCellRendererState flags)
423
424 {
425 NautilusCellRendererPixbufEmblem *cellpixbuf = (NautilusCellRendererPixbufEmblem *) cell;
426 NautilusCellRendererPixbufEmblemInfo *cellinfo = g_object_get_data (G_OBJECT (cell), CELLINFO_KEY);
427 GdkPixbuf *pixbuf;
428 GdkRectangle pix_rect;
429 GdkRectangle pix_emblem_rect;
430 GdkRectangle draw_rect;
431 gboolean stock_pixbuf = FALSE;
432
433 pixbuf = cellpixbuf->pixbuf;
434 if (cell->is_expander) {
435 if (cell->is_expanded &&
436 cellpixbuf->pixbuf_expander_open != NULL) {
437 pixbuf = cellpixbuf->pixbuf_expander_open;
438 } else if (!cell->is_expanded &&
439 cellpixbuf->pixbuf_expander_closed != NULL) {
440 pixbuf = cellpixbuf->pixbuf_expander_closed;
441 }
442 }
443
444 if (!pixbuf && !cellinfo->stock_id) {
445 return;
446 } else if (!pixbuf && cellinfo->stock_id) {
447 stock_pixbuf = TRUE;
448 }
449
450 nautilus_cell_renderer_pixbuf_emblem_get_size (cell, widget, cell_area,
451 &pix_rect.x,
452 &pix_rect.y,
453 &pix_rect.width,
454 &pix_rect.height);
455
456 if (stock_pixbuf)
457 pixbuf = cellpixbuf->pixbuf;
458
459 pix_rect.x += cell_area->x;
460 pix_rect.y += cell_area->y;
461 pix_rect.width -= cell->xpad * 2;
462 pix_rect.height -= cell->ypad * 2;
463
464 if (gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) &&
465 gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
466 gdk_draw_pixbuf (window,
467 widget->style->black_gc,
468 pixbuf,
469 /* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */
470 draw_rect.x - pix_rect.x,
471 draw_rect.y - pix_rect.y,
472 draw_rect.x,
473 draw_rect.y,
474 draw_rect.width,
475 draw_rect.height,
476 GDK_RGB_DITHER_NORMAL,
477 0, 0);
478 }
479
480 if (cellpixbuf->pixbuf_emblem) {
481 pix_emblem_rect.width = gdk_pixbuf_get_width (cellpixbuf->pixbuf_emblem);
482 pix_emblem_rect.height = gdk_pixbuf_get_height (cellpixbuf->pixbuf_emblem);
483 pix_emblem_rect.x = pix_rect.x;
484 pix_emblem_rect.y = pix_rect.y + pix_rect.height - pix_emblem_rect.height;
485 if (gdk_rectangle_intersect (cell_area, &pix_emblem_rect, &draw_rect) &&
486 gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) {
487 gdk_draw_pixbuf (window,
488 widget->style->black_gc,
489 cellpixbuf->pixbuf_emblem,
490 /* pixbuf 0, 0 is at pix_emblem_rect.x, pix_emblem_rect.y */
491 draw_rect.x - pix_emblem_rect.x,
492 draw_rect.y - pix_emblem_rect.y,
493 draw_rect.x,
494 draw_rect.y,
495 draw_rect.width,
496 draw_rect.height,
497 GDK_RGB_DITHER_NORMAL,
498 0, 0);
499 }
500 }
501 }