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