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