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