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