Revert "FIXME: this can be rather slow and blocks until the size is known"
[geeqie.git] / src / cellrenderericon.cc
1 /*
2  * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "main.h"
21 #include "cellrenderericon.h"
22
23 #define FIXED_ICON_SIZE_MAX 512
24
25
26 static void gqv_cell_renderer_icon_get_property(GObject         *object,
27                                                 guint           param_id,
28                                                 GValue          *value,
29                                                 GParamSpec      *pspec);
30 static void gqv_cell_renderer_icon_set_property(GObject         *object,
31                                                 guint           param_id,
32                                                 const GValue    *value,
33                                                 GParamSpec      *pspec);
34 static void gqv_cell_renderer_icon_init_wrapper(void *, void *);
35 static void gqv_cell_renderer_icon_init(GQvCellRendererIcon *celltext);
36 static void gqv_cell_renderer_icon_class_init_wrapper(void *, void *);
37 static void gqv_cell_renderer_icon_class_init(GQvCellRendererIconClass *icon_class);
38 static void gqv_cell_renderer_icon_finalize(GObject *object);
39 static void gqv_cell_renderer_icon_get_size(GtkCellRenderer    *cell,
40                                             GtkWidget          *widget,
41                                             const GdkRectangle *rectangle,
42                                             gint               *x_offset,
43                                             gint               *y_offset,
44                                             gint               *width,
45                                             gint               *height);
46
47 static void gqv_cell_renderer_icon_render(GtkCellRenderer *cell,
48                                            cairo_t *cr,
49                                            GtkWidget *widget,
50                                            const GdkRectangle *background_area,
51                                            const GdkRectangle *cell_area,
52                                            GtkCellRendererState flags);
53
54 static gboolean gqv_cell_renderer_icon_activate(GtkCellRenderer      *cell,
55                                                 GdkEvent             *event,
56                                                 GtkWidget            *widget,
57                                                 const gchar          *path,
58                                                 const GdkRectangle   *background_area,
59                                                 const GdkRectangle   *cell_area,
60                                                 GtkCellRendererState  flags);
61 enum {
62   TOGGLED,
63   LAST_SIGNAL
64 };
65
66 enum {
67         PROP_ZERO,
68         PROP_PIXBUF,
69         PROP_TEXT,
70         PROP_BACKGROUND_GDK,
71         PROP_FOREGROUND_GDK,
72         PROP_FOCUSED,
73         PROP_FIXED_WIDTH,
74         PROP_FIXED_HEIGHT,
75
76         PROP_BACKGROUND_SET,
77         PROP_FOREGROUND_SET,
78         PROP_SHOW_TEXT,
79         PROP_SHOW_MARKS,
80         PROP_NUM_MARKS,
81         PROP_MARKS,
82         PROP_TOGGLED
83 };
84
85 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
86
87 static gpointer parent_class;
88
89 GType
90 gqv_cell_renderer_icon_get_type(void)
91 {
92         static GType cell_icon_type = 0;
93
94         if (!cell_icon_type)
95                 {
96                 static const GTypeInfo cell_icon_info =
97                         {
98                         sizeof(GQvCellRendererIconClass), /* class_size */
99                         NULL,           /* base_init */
100                         NULL,           /* base_finalize */
101                         (GClassInitFunc) gqv_cell_renderer_icon_class_init_wrapper, /* class_init */
102                         NULL,           /* class_finalize */
103                         NULL,           /* class_data */
104                         sizeof(GQvCellRendererIcon), /* instance_size */
105                         0,              /* n_preallocs */
106                         (GInstanceInitFunc) gqv_cell_renderer_icon_init_wrapper, /* instance_init */
107                         NULL,           /* value_table */
108                         };
109
110                 cell_icon_type = g_type_register_static(GTK_TYPE_CELL_RENDERER,
111                                                         "GQvCellRendererIcon",
112                                                         &cell_icon_info, GTypeFlags(0));
113                 }
114
115         return cell_icon_type;
116 }
117
118 static void
119 gqv_cell_renderer_icon_init_wrapper(void *data, void *UNUSED(user_data))
120 {
121         gqv_cell_renderer_icon_init(static_cast<GQvCellRendererIcon *>(data));
122 }
123
124 static void
125 gqv_cell_renderer_icon_init(GQvCellRendererIcon *cellicon)
126 {
127         g_object_set(G_OBJECT(cellicon), "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
128         gtk_cell_renderer_set_padding(GTK_CELL_RENDERER(cellicon), 2, 2);
129 }
130
131 static void
132 gqv_cell_renderer_icon_class_init_wrapper(void *data, void *UNUSED(user_data))
133 {
134         gqv_cell_renderer_icon_class_init(static_cast<GQvCellRendererIconClass *>(data));
135 }
136
137 static void
138 gqv_cell_renderer_icon_class_init(GQvCellRendererIconClass *icon_class)
139 {
140         GObjectClass *object_class = G_OBJECT_CLASS(icon_class);
141         GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(icon_class);
142
143         parent_class = g_type_class_peek_parent(icon_class);
144
145         object_class->finalize = gqv_cell_renderer_icon_finalize;
146
147         object_class->get_property = gqv_cell_renderer_icon_get_property;
148         object_class->set_property = gqv_cell_renderer_icon_set_property;
149
150         cell_class->get_size = gqv_cell_renderer_icon_get_size;
151         cell_class->render = gqv_cell_renderer_icon_render;
152         cell_class->activate = gqv_cell_renderer_icon_activate;
153
154         g_object_class_install_property(object_class,
155                                         PROP_PIXBUF,
156                                         g_param_spec_object("pixbuf",
157                                                         "Pixbuf Object",
158                                                         "The pixbuf to render",
159                                                         GDK_TYPE_PIXBUF,
160                                                         G_PARAM_READWRITE));
161
162         g_object_class_install_property(object_class,
163                                         PROP_TEXT,
164                                         g_param_spec_string("text",
165                                                         "Text",
166                                                         "Text to render",
167                                                         NULL,
168                                                         G_PARAM_READWRITE));
169
170         g_object_class_install_property(object_class,
171                                         PROP_BACKGROUND_GDK,
172                                         g_param_spec_boxed("background_gdk",
173                                                         "Background color",
174                                                         "Background color as a GdkColor",
175                                                         GDK_TYPE_COLOR,
176                                                         G_PARAM_READWRITE));
177
178         g_object_class_install_property(object_class,
179                                         PROP_FOREGROUND_GDK,
180                                         g_param_spec_boxed("foreground_gdk",
181                                                         "Foreground color",
182                                                         "Foreground color as a GdkColor",
183                                                         GDK_TYPE_COLOR,
184                                                         G_PARAM_READWRITE));
185
186         g_object_class_install_property(object_class,
187                                         PROP_FOCUSED,
188                                         g_param_spec_boolean("has_focus",
189                                                         "Focus",
190                                                         "Draw focus indicator",
191                                                         FALSE,
192                                                         G_PARAM_READWRITE));
193
194         g_object_class_install_property(object_class,
195                                         PROP_FIXED_WIDTH,
196                                         g_param_spec_int("fixed_width",
197                                                         "Fixed width",
198                                                         "Width of cell",
199                                                         -1, FIXED_ICON_SIZE_MAX,
200                                                         -1,
201                                                         G_PARAM_READWRITE));
202
203         g_object_class_install_property(object_class,
204                                         PROP_FIXED_HEIGHT,
205                                         g_param_spec_int("fixed_height",
206                                                         "Fixed height",
207                                                         "Height of icon excluding text",
208                                                         -1, FIXED_ICON_SIZE_MAX,
209                                                         -1,
210                                                         G_PARAM_READWRITE));
211
212         g_object_class_install_property(object_class,
213                                         PROP_BACKGROUND_SET,
214                                         g_param_spec_boolean("background_set",
215                                                         "Background set",
216                                                         "Whether this tag affects the background color",
217                                                         FALSE,
218                                                         G_PARAM_READWRITE));
219
220         g_object_class_install_property(object_class,
221                                         PROP_FOREGROUND_SET,
222                                         g_param_spec_boolean("foreground_set",
223                                                         "Foreground set",
224                                                         "Whether this tag affects the foreground color",
225                                                         FALSE,
226                                                         G_PARAM_READWRITE));
227
228         g_object_class_install_property(object_class,
229                                         PROP_SHOW_TEXT,
230                                         g_param_spec_boolean("show_text",
231                                                         "Show text",
232                                                         "Whether the text is displayed",
233                                                         TRUE,
234                                                         G_PARAM_READWRITE));
235
236         g_object_class_install_property(object_class,
237                                         PROP_SHOW_MARKS,
238                                         g_param_spec_boolean("show_marks",
239                                                         "Show marks",
240                                                         "Whether the marks are displayed",
241                                                         TRUE,
242                                                         G_PARAM_READWRITE));
243
244         g_object_class_install_property(object_class,
245                                         PROP_NUM_MARKS,
246                                         g_param_spec_int("num_marks",
247                                                         "Number of marks",
248                                                         "Number of marks",
249                                                         0, 32,
250                                                         6,
251                                                         G_PARAM_READWRITE));
252
253         g_object_class_install_property(object_class,
254                                         PROP_MARKS,
255                                         g_param_spec_uint("marks",
256                                                         "Marks",
257                                                         "Marks bit array",
258                                                         0, 0xffffffff,
259                                                         0,
260                                                         G_PARAM_READWRITE));
261
262         g_object_class_install_property(object_class,
263                                         PROP_TOGGLED,
264                                         g_param_spec_uint("toggled_mark",
265                                                         "Toggled mark",
266                                                         "Toggled mark",
267                                                         0, 32,
268                                                         0,
269                                                         G_PARAM_READWRITE));
270         toggle_cell_signals[TOGGLED] =
271                 g_signal_new("toggled",
272                 G_OBJECT_CLASS_TYPE (object_class),
273                 G_SIGNAL_RUN_LAST,
274                 G_STRUCT_OFFSET (GQvCellRendererIconClass, toggled),
275                 NULL, NULL,
276                 g_cclosure_marshal_VOID__STRING,
277                 G_TYPE_NONE, 1,
278                 G_TYPE_STRING);
279
280 }
281
282 static void
283 gqv_cell_renderer_icon_finalize(GObject *object)
284 {
285         GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
286
287         if (cellicon->pixbuf) g_object_unref(cellicon->pixbuf);
288
289         g_free(cellicon->text);
290
291         (*(G_OBJECT_CLASS(parent_class))->finalize)(object);
292 }
293
294 static void
295 gqv_cell_renderer_icon_get_property(GObject     *object,
296                                     guint       param_id,
297                                     GValue      *value,
298                                     GParamSpec  *pspec)
299 {
300         GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
301
302         switch (param_id)
303         {
304         case PROP_PIXBUF:
305                 g_value_set_object(value, cellicon->pixbuf ? G_OBJECT(cellicon->pixbuf) : NULL);
306                 break;
307         case PROP_TEXT:
308                 g_value_set_string(value, cellicon->text);
309                 break;
310         case PROP_BACKGROUND_GDK:
311                 {
312                 GdkColor color;
313
314                 color.red = cellicon->background.red;
315                 color.green = cellicon->background.green;
316                 color.blue = cellicon->background.blue;
317
318                 g_value_set_boxed(value, &color);
319                 }
320                 break;
321         case PROP_FOREGROUND_GDK:
322                 {
323                 GdkColor color;
324
325                 color.red = cellicon->foreground.red;
326                 color.green = cellicon->foreground.green;
327                 color.blue = cellicon->foreground.blue;
328
329                 g_value_set_boxed(value, &color);
330                 }
331                 break;
332         case PROP_FOCUSED:
333                 g_value_set_boolean(value, cellicon->focused);
334                 break;
335         case PROP_FIXED_WIDTH:
336                 g_value_set_int(value, cellicon->fixed_width);
337                 break;
338         case PROP_FIXED_HEIGHT:
339                 g_value_set_int(value, cellicon->fixed_height);
340                 break;
341         case PROP_BACKGROUND_SET:
342                 g_value_set_boolean(value, cellicon->background_set);
343                 break;
344         case PROP_FOREGROUND_SET:
345                 g_value_set_boolean(value, cellicon->foreground_set);
346                 break;
347         case PROP_SHOW_TEXT:
348                 g_value_set_boolean(value, cellicon->show_text);
349                 break;
350         case PROP_SHOW_MARKS:
351                 g_value_set_boolean(value, cellicon->show_marks);
352                 break;
353         case PROP_NUM_MARKS:
354                 g_value_set_int(value, cellicon->num_marks);
355                 break;
356         case PROP_MARKS:
357                 g_value_set_uint(value, cellicon->marks);
358                 break;
359         case PROP_TOGGLED:
360                 g_value_set_uint(value, cellicon->toggled_mark);
361                 break;
362         default:
363                 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
364                 break;
365         }
366 }
367
368 static void
369 set_bg_color(GQvCellRendererIcon *cellicon,
370              GdkColor             *color)
371 {
372         if (color)
373                 {
374                 if (!cellicon->background_set)
375                         {
376                         cellicon->background_set = TRUE;
377                         g_object_notify(G_OBJECT(cellicon), "background_set");
378                         }
379
380                 cellicon->background.red = color->red;
381                 cellicon->background.green = color->green;
382                 cellicon->background.blue = color->blue;
383                 }
384         else
385                 {
386                 if (cellicon->background_set)
387                         {
388                         cellicon->background_set = FALSE;
389                         g_object_notify(G_OBJECT(cellicon), "background_set");
390                         }
391                 }
392 }
393
394 static void set_fg_color(GQvCellRendererIcon *cellicon,
395                          GdkColor             *color)
396 {
397         if (color)
398                 {
399                 if (!cellicon->foreground_set)
400                         {
401                         cellicon->foreground_set = TRUE;
402                         g_object_notify(G_OBJECT(cellicon), "foreground_set");
403                         }
404
405                 cellicon->foreground.red = color->red;
406                 cellicon->foreground.green = color->green;
407                 cellicon->foreground.blue = color->blue;
408                 }
409         else
410                 {
411                 if (cellicon->foreground_set)
412                         {
413                         cellicon->foreground_set = FALSE;
414                         g_object_notify(G_OBJECT(cellicon), "foreground_set");
415                         }
416                 }
417 }
418
419 static void
420 gqv_cell_renderer_icon_set_property(GObject             *object,
421                                     guint               param_id,
422                                     const GValue        *value,
423                                     GParamSpec          *pspec)
424 {
425         GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
426
427         switch (param_id)
428         {
429         case PROP_PIXBUF:
430                 {
431                 GdkPixbuf *pixbuf;
432
433                 pixbuf = (GdkPixbuf *) g_value_get_object(value);
434                 if (pixbuf) g_object_ref(pixbuf);
435                 if (cellicon->pixbuf) g_object_unref(cellicon->pixbuf);
436                 cellicon->pixbuf = pixbuf;
437                 }
438                 break;
439         case PROP_TEXT:
440                 {
441                 gchar *text;
442
443                 text = cellicon->text;
444                 cellicon->text = g_strdup(g_value_get_string(value));
445                 g_free(text);
446
447                 g_object_notify(object, "text");
448                 }
449                 break;
450         case PROP_BACKGROUND_GDK:
451                 set_bg_color(cellicon, static_cast<GdkColor *>(g_value_get_boxed(value)));
452                 break;
453         case PROP_FOREGROUND_GDK:
454                 set_fg_color(cellicon, static_cast<GdkColor *>(g_value_get_boxed(value)));
455                 break;
456         case PROP_FOCUSED:
457                 cellicon->focused = g_value_get_boolean(value);
458                 break;
459         case PROP_FIXED_WIDTH:
460                 cellicon->fixed_width = g_value_get_int(value);
461                 break;
462         case PROP_FIXED_HEIGHT:
463                 cellicon->fixed_height = g_value_get_int(value);
464                 break;
465         case PROP_BACKGROUND_SET:
466                 cellicon->background_set = g_value_get_boolean(value);
467                 break;
468         case PROP_FOREGROUND_SET:
469                 cellicon->foreground_set = g_value_get_boolean(value);
470                 break;
471         case PROP_SHOW_TEXT:
472                 cellicon->show_text = g_value_get_boolean(value);
473                 break;
474         case PROP_SHOW_MARKS:
475                 cellicon->show_marks = g_value_get_boolean(value);
476                 break;
477         case PROP_NUM_MARKS:
478                 cellicon->num_marks = g_value_get_int(value);
479                 break;
480         case PROP_MARKS:
481                 cellicon->marks = g_value_get_uint(value);
482                 break;
483         default:
484                 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
485                 break;
486         }
487 }
488
489 static PangoLayout *
490 gqv_cell_renderer_icon_get_layout(GQvCellRendererIcon *cellicon, GtkWidget *widget, gboolean will_render)
491 {
492         PangoLayout *layout;
493         gint width;
494
495         width = (cellicon->fixed_width > 0) ? cellicon->fixed_width * PANGO_SCALE : -1;
496
497         layout = gtk_widget_create_pango_layout(widget, cellicon->text);
498         pango_layout_set_width(layout, width);
499         pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
500         pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
501
502         if (will_render)
503                 {
504                 PangoAttrList *attr_list;
505
506                 attr_list = pango_attr_list_new();
507
508                 if (cellicon->foreground_set)
509                         {
510                         PangoColor color;
511                         PangoAttribute *attr;
512
513                         color = cellicon->foreground;
514
515                         attr = pango_attr_foreground_new(color.red, color.green, color.blue);
516
517                         attr->start_index = 0;
518                         attr->end_index = G_MAXINT;
519                         pango_attr_list_insert(attr_list, attr);
520                         }
521
522                 pango_layout_set_attributes(layout, attr_list);
523                 pango_attr_list_unref(attr_list);
524                 }
525
526         return layout;
527 }
528
529 /**
530  * gqv_cell_renderer_icon_new:
531  *
532  * Creates a new #GQvCellRendererIcon. Adjust rendering
533  * parameters using object properties. Object properties can be set
534  * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
535  * can bind a property to a value in a #GtkTreeModel. For example, you
536  * can bind the "pixbuf" property on the cell renderer to a pixbuf value
537  * in the model, thus rendering a different image in each row of the
538  * #GtkTreeView.
539  *
540  * Return value: the new cell renderer
541  **/
542 GtkCellRenderer *
543 gqv_cell_renderer_icon_new(void)
544 {
545         return static_cast<GtkCellRenderer *>(g_object_new(GQV_TYPE_CELL_RENDERER_ICON, NULL));
546 }
547
548 static void gqv_cell_renderer_icon_get_size(GtkCellRenderer    *cell,
549                                             GtkWidget          *widget,
550                                             const GdkRectangle *cell_area,
551                                             gint               *x_offset,
552                                             gint               *y_offset,
553                                             gint               *width,
554                                             gint               *height)
555 {
556         GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell;
557         gint calc_width;
558         gint calc_height;
559         gint xpad, ypad;
560         gfloat xalign, yalign;
561
562         gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
563         gtk_cell_renderer_get_alignment(cell, &xalign, &yalign);
564
565         if (cellicon->fixed_width > 0)
566                 {
567                 calc_width = cellicon->fixed_width;
568                 }
569         else
570                 {
571                 calc_width = (cellicon->pixbuf) ? gdk_pixbuf_get_width(cellicon->pixbuf) : 0;
572                 }
573
574         if (cellicon->fixed_height > 0)
575                 {
576                 calc_height = cellicon->fixed_height;
577                 }
578         else
579                 {
580                 calc_height = (cellicon->pixbuf) ? gdk_pixbuf_get_height(cellicon->pixbuf) : 0;
581                 }
582
583         if (cellicon->show_text && cellicon->text)
584                 {
585                 PangoLayout *layout;
586                 PangoRectangle rect;
587
588                 layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, FALSE);
589                 pango_layout_get_pixel_extents(layout, NULL, &rect);
590                 g_object_unref(layout);
591
592                 calc_width = MAX(calc_width, rect.width);
593                 calc_height += rect.height;
594                 }
595
596         if (cellicon->show_marks)
597                 {
598                 calc_height += TOGGLE_SPACING;
599                 calc_width = MAX(calc_width, TOGGLE_SPACING * cellicon->num_marks);
600                 }
601
602         calc_width += xpad * 2;
603         calc_height += ypad * 2;
604
605         if (x_offset) *x_offset = 0;
606         if (y_offset) *y_offset = 0;
607
608         if (cell_area && calc_width > 0 && calc_height > 0)
609                 {
610                 if (x_offset)
611                         {
612                         *x_offset = (xalign * (cell_area->width - calc_width - 2 * xpad));
613                         *x_offset = MAX(*x_offset, 0) + xpad;
614                         }
615                 if (y_offset)
616                         {
617                         *y_offset = (yalign * (cell_area->height - calc_height - 2 * ypad));
618                         *y_offset = MAX(*y_offset, 0) + ypad;
619                         }
620                 }
621
622         if (width) *width = calc_width;
623         if (height) *height = calc_height;
624 }
625
626 static void gqv_cell_renderer_icon_render(GtkCellRenderer *cell,
627                                            cairo_t *cr,
628                                            GtkWidget *widget,
629                                            const GdkRectangle *UNUSED(background_area),
630                                            const GdkRectangle *cell_area,
631                                            GtkCellRendererState flags)
632
633 {
634         GtkStyleContext *context = gtk_widget_get_style_context(widget);
635         GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell;
636         GdkPixbuf *pixbuf;
637         const gchar *text;
638         GdkRectangle cell_rect;
639         GtkStateFlags state;
640         gint xpad, ypad;
641
642
643         pixbuf = cellicon->pixbuf;
644         text = cellicon->text;
645         if (!pixbuf && !text)
646                 {
647                 return;
648                 }
649
650         gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
651
652         gqv_cell_renderer_icon_get_size(cell, widget, cell_area,
653                                         &cell_rect.x, &cell_rect.y,
654                                         &cell_rect.width, &cell_rect.height);
655
656         cell_rect.x += xpad;
657         cell_rect.y += ypad;
658         cell_rect.width -= xpad * 2;
659         cell_rect.height -= ypad * 2;
660
661         if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
662                 {
663                 if (gtk_widget_has_focus(widget))
664                         state = GTK_STATE_FLAG_SELECTED;
665                 else
666                         state = GTK_STATE_FLAG_ACTIVE;
667                 }
668         else
669                 {
670                 if (gtk_widget_get_state(widget) == GTK_STATE_INSENSITIVE)
671                         state = GTK_STATE_FLAG_INSENSITIVE;
672                 else
673                         state = GTK_STATE_FLAG_NORMAL;
674                 }
675         gtk_style_context_set_state(context, state);
676
677         if (pixbuf)
678                 {
679                 GdkRectangle pix_rect;
680                 GdkRectangle draw_rect;
681
682                 pix_rect.width = gdk_pixbuf_get_width(pixbuf);
683                 pix_rect.height = gdk_pixbuf_get_height(pixbuf);
684
685                 pix_rect.x = cell_area->x + (cell_area->width - pix_rect.width) / 2;
686
687                 if (cellicon->fixed_height > 0)
688                         {
689                         pix_rect.y = cell_area->y + ypad + (cellicon->fixed_height - pix_rect.height) / 2;
690                         }
691                 else
692                         {
693                         pix_rect.y = cell_area->y + cell_rect.y;
694                         }
695
696                 if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect))
697                         {
698                         gdk_cairo_set_source_pixbuf(cr, pixbuf, pix_rect.x, pix_rect.y);
699                         cairo_rectangle (cr,
700                                         draw_rect.x,
701                                         draw_rect.y,
702                                         draw_rect.width,
703                                         draw_rect.height);
704
705                         cairo_fill (cr);
706                         }
707                 }
708
709         if (cellicon->show_text && text)
710                 {
711                 PangoLayout *layout;
712                 PangoRectangle text_rect;
713                 GdkRectangle pix_rect;
714                 GdkRectangle draw_rect;
715                 layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, TRUE);
716                 pango_layout_get_pixel_extents(layout, NULL, &text_rect);
717
718                 pix_rect.width = text_rect.width;
719                 pix_rect.height = text_rect.height;
720                 pix_rect.x = cell_area->x + xpad + (cell_rect.width - text_rect.width + 1) / 2;
721                 pix_rect.y = cell_area->y + ypad + (cell_rect.height - text_rect.height);
722
723                 if (cellicon->show_marks)
724                         {
725                         pix_rect.y -= TOGGLE_SPACING;
726                         }
727
728                 if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect))
729                         {
730                         gtk_render_layout(context, cr, pix_rect.x - text_rect.x, pix_rect.y, layout);
731                         }
732                 g_object_unref(layout);
733                 }
734
735         if (cellicon->show_marks)
736                 {
737                 GdkRectangle pix_rect;
738                 GdkRectangle draw_rect;
739                 gint i;
740
741                 pix_rect.width = TOGGLE_SPACING * cellicon->num_marks;
742                 pix_rect.height = TOGGLE_SPACING;
743                 pix_rect.x = cell_area->x + xpad + (cell_rect.width - pix_rect.width + 1) / 2 + (TOGGLE_SPACING - TOGGLE_WIDTH) / 2;
744                 pix_rect.y = cell_area->y + ypad + (cell_rect.height - pix_rect.height) + (TOGGLE_SPACING - TOGGLE_WIDTH) / 2;
745
746                 if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect))
747                         {
748                         for (i = 0; i < cellicon->num_marks; i++)
749                                 {
750                                 state = static_cast<GtkStateFlags>(state & ~GTK_STATE_FLAG_CHECKED);
751
752                                 if ((cellicon->marks & (1 << i)))
753                                         state = static_cast<GtkStateFlags>(state | GTK_STATE_FLAG_CHECKED);
754                                 cairo_save (cr);
755
756                                 cairo_rectangle(cr,
757                                                 pix_rect.x + i * TOGGLE_SPACING + (TOGGLE_WIDTH - TOGGLE_SPACING) / 2,
758                                                 pix_rect.y,
759                                                 TOGGLE_WIDTH, TOGGLE_WIDTH);
760                                 cairo_clip (cr);
761
762                                 gtk_style_context_save(context);
763                                 gtk_style_context_set_state(context, state);
764
765                                 gtk_style_context_add_class(context, GTK_STYLE_CLASS_CHECK);
766
767                                 gtk_style_context_add_class(context, "marks");
768                                 GtkStyleProvider *provider;
769                                 provider = (GtkStyleProvider *)gtk_css_provider_new();
770                                 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
771                                                 ".marks {\n"
772                                                 "border-color: #808080;\n"
773                                                 "border-style: solid;\n"
774                                                 "border-width: 1px;\n"
775                                                 "border-radius: 0px;\n"
776                                                 "}\n"
777                                                 ,-1, NULL);
778                                 gtk_style_context_add_provider(context, provider,
779                                                         GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
780
781                                 if (state & GTK_STATE_FLAG_CHECKED)
782                                         {
783                                         gtk_render_check(context, cr,
784                                                 pix_rect.x + i * TOGGLE_SPACING + (TOGGLE_WIDTH - TOGGLE_SPACING) / 2,
785                                                 pix_rect.y,
786                                                 TOGGLE_WIDTH, TOGGLE_WIDTH);
787                                         }
788                                 gtk_render_frame(context, cr,
789                                          pix_rect.x + i * TOGGLE_SPACING + (TOGGLE_WIDTH - TOGGLE_SPACING) / 2,
790                                          pix_rect.y,
791                                          TOGGLE_WIDTH, TOGGLE_WIDTH);
792
793                                 if (cellicon->focused && gtk_widget_has_focus(widget))
794                                         {
795                                         gtk_render_focus(context, cr,
796                                                 pix_rect.x + i * TOGGLE_SPACING + (TOGGLE_WIDTH - TOGGLE_SPACING) / 2,
797                                                 pix_rect.y, TOGGLE_WIDTH, TOGGLE_WIDTH);
798                                         }
799                                 gtk_style_context_restore(context);
800                                 cairo_restore(cr);
801                                 gtk_style_context_remove_provider(context, provider);
802                                 g_object_unref(provider);
803                                 }
804                         }
805                 }
806 }
807
808 static gboolean gqv_cell_renderer_icon_activate(GtkCellRenderer      *cell,
809                                                 GdkEvent             *event,
810                                                 GtkWidget            *widget,
811                                                 const gchar          *path,
812                                                 const GdkRectangle   *UNUSED(background_area),
813                                                 const GdkRectangle   *cell_area,
814                                                 GtkCellRendererState  UNUSED(flags))
815 {
816         GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell;
817         GdkEventButton *bevent = &event->button;
818
819         if (cellicon->show_marks &&
820             event->type == GDK_BUTTON_PRESS &&
821             !(bevent->state & GDK_SHIFT_MASK ) &&
822             !(bevent->state & GDK_CONTROL_MASK ))
823                 {
824                 GdkRectangle rect;
825                 GdkRectangle cell_rect;
826                 gint i;
827                 gint xpad, ypad;
828
829                 gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
830
831                 gqv_cell_renderer_icon_get_size(cell, widget, cell_area,
832                                                 &cell_rect.x, &cell_rect.y,
833                                                 &cell_rect.width, &cell_rect.height);
834
835                 cell_rect.x += xpad;
836                 cell_rect.y += ypad;
837                 cell_rect.width -= xpad * 2;
838                 cell_rect.height -= ypad * 2;
839
840                 rect.width = TOGGLE_WIDTH;
841                 rect.height = TOGGLE_WIDTH;
842                 rect.y = cell_area->y + ypad + (cell_rect.height - TOGGLE_SPACING) + (TOGGLE_SPACING - TOGGLE_WIDTH) / 2;
843                 for (i = 0; i < cellicon->num_marks; i++)
844                         {
845                         rect.x = cell_area->x + xpad + (cell_rect.width - TOGGLE_SPACING * cellicon->num_marks + 1) / 2 + i * TOGGLE_SPACING;
846
847                         if (bevent->x >= rect.x && bevent->x < rect.x + rect.width &&
848                             bevent->y >= rect.y && bevent->y < rect.y + rect.height)
849                                 {
850                                 cellicon->toggled_mark = i;
851                                 g_signal_emit(cell, toggle_cell_signals[TOGGLED], 0, path);
852                                 break;
853                                 }
854                         }
855                 }
856         return FALSE;
857 }
858 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */