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 }