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