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