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