]> git.sur5r.net Git - glabels/blob - src/label-image.c
Imported Upstream version 3.0.0
[glabels] / src / label-image.c
1 /*
2  *  label-image.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "label-image.h"
24
25 #include <glib/gi18n.h>
26 #include <glib.h>
27 #include <gdk/gdk.h>
28 #include <librsvg/rsvg.h>
29 #include <librsvg/rsvg-cairo.h>
30
31 #include "pixbuf-util.h"
32 #include "file-util.h"
33 #include "pixmaps/checkerboard.xpm"
34
35 #include "debug.h"
36
37
38 #define MIN_IMAGE_SIZE 1.0
39
40
41 /*========================================================*/
42 /* Private types.                                         */
43 /*========================================================*/
44
45 typedef enum {
46         FILE_TYPE_NONE,
47         FILE_TYPE_PIXBUF,
48         FILE_TYPE_SVG
49 } FileType;
50
51
52 struct _glLabelImagePrivate {
53
54         glTextNode       *filename;
55
56         FileType          type;
57
58         GdkPixbuf        *pixbuf;
59         RsvgHandle       *svg_handle;
60 };
61
62
63 /*========================================================*/
64 /* Private globals.                                       */
65 /*========================================================*/
66
67 static GdkPixbuf *default_pixbuf = NULL;
68
69
70 /*========================================================*/
71 /* Private function prototypes.                           */
72 /*========================================================*/
73
74 static void gl_label_image_finalize      (GObject           *object);
75
76 static void copy                         (glLabelObject     *dst_object,
77                                           glLabelObject     *src_object);
78
79 static void set_size                     (glLabelObject     *object,
80                                           gdouble            w,
81                                           gdouble            h,
82                                           gboolean           checkpoint);
83
84 static void draw_object                  (glLabelObject     *object,
85                                           cairo_t           *cr,
86                                           gboolean           screen_flag,
87                                           glMergeRecord     *record);
88
89 static void draw_shadow                  (glLabelObject     *object,
90                                           cairo_t           *cr,
91                                           gboolean           screen_flag,
92                                           glMergeRecord     *record);
93
94 static gboolean object_at                (glLabelObject     *object,
95                                           cairo_t           *cr,
96                                           gdouble            x_pixels,
97                                           gdouble            y_pixels);
98
99
100 /*****************************************************************************/
101 /* Boilerplate object stuff.                                                 */
102 /*****************************************************************************/
103 G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT)
104
105
106 static void
107 gl_label_image_class_init (glLabelImageClass *class)
108 {
109         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
110         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
111         GdkPixbuf          *pixbuf;
112
113         gl_label_image_parent_class = g_type_class_peek_parent (class);
114
115         label_object_class->copy              = copy;
116         label_object_class->set_size          = set_size;
117         label_object_class->draw_object       = draw_object;
118         label_object_class->draw_shadow       = draw_shadow;
119         label_object_class->object_at         = object_at;
120
121         object_class->finalize = gl_label_image_finalize;
122
123         if ( default_pixbuf == NULL ) {
124                 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
125                 default_pixbuf =
126                         gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
127                 g_object_unref (pixbuf);
128         }
129 }
130
131
132 static void
133 gl_label_image_init (glLabelImage *this)
134 {
135         this->priv = g_new0 (glLabelImagePrivate, 1);
136
137         this->priv->filename = g_new0 (glTextNode, 1);
138
139         this->priv->type       = FILE_TYPE_NONE;
140         this->priv->pixbuf     = NULL;
141         this->priv->svg_handle = NULL;
142 }
143
144
145 static void
146 gl_label_image_finalize (GObject *object)
147 {
148         glLabelObject *lobject = GL_LABEL_OBJECT (object);
149         glLabelImage  *this  = GL_LABEL_IMAGE (object);
150         glLabel       *label;
151         GHashTable    *cache;
152
153         g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
154
155         if (!this->priv->filename->field_flag) {
156                 
157                 label = gl_label_object_get_parent (lobject);
158
159                 switch ( this->priv->type )
160                 {
161
162                 case FILE_TYPE_PIXBUF:
163                         cache = gl_label_get_pixbuf_cache (label);
164                         gl_pixbuf_cache_remove_pixbuf (cache, this->priv->filename->data);
165                         break;
166
167                 case FILE_TYPE_SVG:
168                         cache = gl_label_get_svg_cache (label);
169                         gl_svg_cache_remove_svg (cache, this->priv->filename->data);
170                         break;
171
172                 default:
173                         break;
174
175                 }
176
177         }
178         gl_text_node_free (&this->priv->filename);
179         g_free (this->priv);
180
181         G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
182 }
183
184
185 /*****************************************************************************/
186 /* NEW label "image" object.                                                 */
187 /*****************************************************************************/
188 GObject *
189 gl_label_image_new (glLabel *label,
190                     gboolean checkpoint)
191 {
192         glLabelImage *this;
193
194         this = g_object_new (gl_label_image_get_type(), NULL);
195
196         if (label != NULL)
197         {
198                 if ( checkpoint )
199                 {
200                         gl_label_checkpoint (label, _("Create image object"));
201                 }
202
203                 gl_label_add_object (label, GL_LABEL_OBJECT (this));
204                 gl_label_object_set_parent (GL_LABEL_OBJECT (this), label);
205         }
206
207         return G_OBJECT (this);
208 }
209
210
211 /*****************************************************************************/
212 /* Copy object contents.                                                     */
213 /*****************************************************************************/
214 static void
215 copy (glLabelObject *dst_object,
216       glLabelObject *src_object)
217 {
218         glLabelImage     *src_limage = (glLabelImage *)src_object;
219         glLabelImage     *new_limage = (glLabelImage *)dst_object;
220         glTextNode       *filename;
221         GdkPixbuf        *pixbuf;
222         gchar            *contents;
223         glLabel          *src_label, *dst_label;
224         GHashTable       *cache;
225
226         gl_debug (DEBUG_LABEL, "START");
227
228         g_return_if_fail (src_limage && GL_IS_LABEL_IMAGE (src_limage));
229         g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
230
231         filename = gl_label_image_get_filename (src_limage);
232
233         /* Make sure destination label has data suitably cached. */
234         if ( !filename->field_flag && (src_limage->priv->type != FILE_TYPE_NONE) )
235         {
236                 src_label = gl_label_object_get_parent (src_object);
237                 dst_label = gl_label_object_get_parent (dst_object);
238
239                 switch ( src_limage->priv->type )
240                 {
241
242                 case FILE_TYPE_PIXBUF:
243                         pixbuf = src_limage->priv->pixbuf;
244                         if ( pixbuf != NULL ) {
245                                 cache = gl_label_get_pixbuf_cache (dst_label);
246                                 gl_pixbuf_cache_add_pixbuf (cache, filename->data, pixbuf);
247                         }
248                         break;
249
250                 case FILE_TYPE_SVG:
251                         cache = gl_label_get_svg_cache (src_label);
252                         contents = gl_svg_cache_get_contents (cache, filename->data);
253                         if ( contents != NULL ) {
254                                 cache = gl_label_get_svg_cache (dst_label);
255                                 gl_svg_cache_add_svg (cache, filename->data, contents);
256                                 g_free (contents);
257                         }
258                         break;
259
260                 default:
261                         break;
262
263                 }
264         }
265
266         gl_label_image_set_filename (new_limage, filename, FALSE);
267         gl_text_node_free (&filename);
268
269         gl_debug (DEBUG_LABEL, "END");
270 }
271
272
273 /*---------------------------------------------------------------------------*/
274 /* PRIVATE.  Set size method.                                                */
275 /*---------------------------------------------------------------------------*/
276 static void
277 set_size (glLabelObject *object,
278           gdouble        w,
279           gdouble        h,
280           gboolean       checkpoint)
281 {
282         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
283
284         if (w < MIN_IMAGE_SIZE)
285         {
286                 w = MIN_IMAGE_SIZE;
287         }
288
289         if (h < MIN_IMAGE_SIZE)
290         {
291                 h = MIN_IMAGE_SIZE;
292         }
293
294         GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h, checkpoint);
295 }
296
297
298 /*****************************************************************************/
299 /* Set object params.                                                        */
300 /*****************************************************************************/
301 void
302 gl_label_image_set_filename (glLabelImage *this,
303                              glTextNode   *filename,
304                              gboolean      checkpoint)
305 {
306         glTextNode        *old_filename;
307         glLabel           *label;
308         GHashTable        *pixbuf_cache;
309         GHashTable        *svg_cache;
310         GdkPixbuf         *pixbuf;
311         RsvgHandle        *svg_handle;
312         RsvgDimensionData  svg_dim;
313         gdouble            image_w, image_h, aspect_ratio, w, h;
314
315         gl_debug (DEBUG_LABEL, "START");
316
317         g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
318         g_return_if_fail (filename != NULL);
319
320         old_filename = this->priv->filename;
321
322         /* If Unchanged don't do anything */
323         if ( gl_text_node_equal (filename, old_filename ) ) {
324                 return;
325         }
326
327         label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
328         pixbuf_cache = gl_label_get_pixbuf_cache (label);
329         svg_cache    = gl_label_get_svg_cache (label);
330
331         if ( checkpoint )
332         {
333                 gl_label_checkpoint (label, _("Set image"));
334         }
335
336         /* Set new filename. */
337         this->priv->filename = gl_text_node_dup(filename);
338
339         /* Remove reference to previous item. */
340         switch (this->priv->type)
341         {
342
343         case FILE_TYPE_PIXBUF:
344                 if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
345                         gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
346                 }
347                 break;
348
349         case FILE_TYPE_SVG:
350                 if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
351                         gl_svg_cache_remove_svg (svg_cache, old_filename->data);
352                 }
353                 break;
354
355         default:
356                 break;
357
358         }
359
360         gl_text_node_free (&old_filename);
361
362
363         /* Now set the new file type and the pixbuf or svg_handle. */
364         if ( !filename->field_flag && (filename->data != NULL) )
365         {
366
367                 if ( gl_file_util_is_extension (filename->data, ".svg") )
368                 {
369                         svg_handle = gl_svg_cache_get_handle (svg_cache, filename->data);
370
371                         if (svg_handle != NULL)
372                         {
373                                 this->priv->type       = FILE_TYPE_SVG;
374                                 this->priv->pixbuf     = NULL;
375                                 this->priv->svg_handle = svg_handle;
376                         }
377                         else
378                         {
379                                 this->priv->type       = FILE_TYPE_NONE;
380                                 this->priv->pixbuf     = NULL;
381                                 this->priv->svg_handle = NULL;
382                         }
383
384                 }
385                 else
386                 {
387
388                         pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
389
390                         if (pixbuf != NULL)
391                         {
392                                 this->priv->type       = FILE_TYPE_PIXBUF;
393                                 this->priv->pixbuf     = pixbuf;
394                                 this->priv->svg_handle = NULL;
395                         }
396                         else
397                         {
398                                 this->priv->type       = FILE_TYPE_NONE;
399                                 this->priv->pixbuf     = NULL;
400                                 this->priv->svg_handle = NULL;
401                         }
402
403                 }
404         }
405         else
406         {
407                 this->priv->type       = FILE_TYPE_NONE;
408                 this->priv->pixbuf     = NULL;
409                 this->priv->svg_handle = NULL;
410         }
411
412
413         /* Treat current size as a bounding box, scale image to maintain aspect
414          * ratio while fitting it in this bounding box. */
415         switch (this->priv->type)
416         {
417
418         case FILE_TYPE_PIXBUF:
419                 image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
420                 image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
421                 break;
422
423         case FILE_TYPE_SVG:
424                 rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
425                 image_w = svg_dim.width;
426                 image_h = svg_dim.height;
427                 break;
428
429         default:
430                 image_w = gdk_pixbuf_get_width (default_pixbuf);
431                 image_h = gdk_pixbuf_get_height (default_pixbuf);
432                 break;
433
434         }
435         aspect_ratio = image_h / image_w;
436         gl_label_object_get_size (GL_LABEL_OBJECT(this), &w, &h);
437         if ( h > w*aspect_ratio ) {
438                 h = w * aspect_ratio;
439         } else {
440                 w = h / aspect_ratio;
441         }
442         gl_label_object_set_size (GL_LABEL_OBJECT(this), w, h, FALSE);
443
444         gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
445
446         gl_debug (DEBUG_LABEL, "END");
447 }
448
449
450 void
451 gl_label_image_set_pixbuf (glLabelImage  *this,
452                            GdkPixbuf     *pixbuf,
453                            gboolean       checkpoint)
454 {
455         glTextNode  *old_filename;
456         glLabel     *label;
457         GHashTable  *pixbuf_cache;
458         GHashTable  *svg_cache;
459         gchar       *cs;
460         gchar       *name;
461         gdouble      image_w, image_h;
462
463         gl_debug (DEBUG_LABEL, "START");
464
465         g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
466         g_return_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf));
467
468         old_filename = this->priv->filename;
469
470         label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
471
472         if ( checkpoint )
473         {
474                 gl_label_checkpoint (label, _("Set image"));
475         }
476
477         pixbuf_cache = gl_label_get_pixbuf_cache (label);
478         svg_cache = gl_label_get_svg_cache (label);
479
480         /* Remove reference to previous item. */
481         switch (this->priv->type)
482         {
483
484         case FILE_TYPE_PIXBUF:
485                 if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
486                         gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
487                 }
488                 break;
489
490         case FILE_TYPE_SVG:
491                 if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
492                         gl_svg_cache_remove_svg (svg_cache, old_filename->data);
493                 }
494                 break;
495
496         default:
497                 break;
498
499         }
500
501         /* Set new filename. */
502         cs = g_compute_checksum_for_data (G_CHECKSUM_MD5,
503                                           gdk_pixbuf_get_pixels (pixbuf),
504                                           gdk_pixbuf_get_rowstride (pixbuf)*gdk_pixbuf_get_height (pixbuf));
505         name = g_strdup_printf ("%s.bitmap", cs);
506         this->priv->filename = gl_text_node_new_from_text(name);
507         gl_text_node_free (&old_filename);
508
509         this->priv->pixbuf = g_object_ref (pixbuf);
510         gl_pixbuf_cache_add_pixbuf (pixbuf_cache, name, pixbuf);
511
512         g_free (cs);
513         g_free (name);
514
515         this->priv->type       = FILE_TYPE_PIXBUF;
516         this->priv->svg_handle = NULL;
517
518         image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
519         image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
520         gl_label_object_set_size (GL_LABEL_OBJECT(this), image_w, image_h, FALSE);
521
522         gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
523
524         gl_debug (DEBUG_LABEL, "END");
525 }
526
527
528 /*****************************************************************************/
529 /* Get object params.                                                        */
530 /*****************************************************************************/
531 GdkPixbuf *
532 gl_label_image_get_pixbuf (glLabelImage  *this,
533                            glMergeRecord *record)
534 {
535         g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
536
537         if ((record != NULL) && this->priv->filename->field_flag)
538         {
539
540                 GdkPixbuf   *pixbuf = NULL;
541                 gchar       *real_filename;
542
543                 /* Indirect filename, re-evaluate for given record. */
544
545                 real_filename = gl_merge_eval_key (record,
546                                                    this->priv->filename->data);
547
548                 if (real_filename != NULL)
549                 {
550                         pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
551                 }
552                 return pixbuf;
553         }
554
555         if ( this->priv->type == FILE_TYPE_PIXBUF )
556         {
557                 return g_object_ref (this->priv->pixbuf);
558         }
559         else
560         {
561                 return NULL;
562         }
563 }
564
565
566 RsvgHandle *
567 gl_label_image_get_svg_handle (glLabelImage  *this,
568                                glMergeRecord *record)
569 {
570         g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
571
572         if ((record != NULL) && this->priv->filename->field_flag)
573         {
574
575                 RsvgHandle  *svg_handle = NULL;
576                 gchar       *real_filename;
577
578                 /* Indirect filename, re-evaluate for given record. */
579
580                 real_filename = gl_merge_eval_key (record,
581                                                    this->priv->filename->data);
582
583                 if (real_filename != NULL)
584                 {
585                         if ( gl_file_util_is_extension (real_filename, ".svg") )
586                         {
587                                 svg_handle = rsvg_handle_new_from_file (real_filename, NULL);
588                         }
589                 }
590                 return svg_handle;
591         }
592
593         if ( this->priv->type == FILE_TYPE_SVG )
594         {
595                 return g_object_ref (this->priv->svg_handle);
596         }
597         else
598         {
599                 return NULL;
600         }
601 }
602
603
604 static FileType
605 get_type (glLabelImage  *this,
606           glMergeRecord *record)
607 {
608         g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), FALSE);
609
610         if ((record != NULL) && this->priv->filename->field_flag)
611         {
612                 gchar       *real_filename;
613
614                 real_filename = gl_merge_eval_key (record,
615                                                    this->priv->filename->data);
616
617                 if ( gl_file_util_is_extension (real_filename, ".svg") )
618                 {
619                         return FILE_TYPE_SVG;
620                 }
621                 else
622                 {
623                         /* Assume a pixbuf compat file.  If not, queries for
624                            pixbufs should return NULL and do the right thing. */
625                         return FILE_TYPE_PIXBUF;
626                 }
627         }
628         else
629         {
630                 return (this->priv->type);
631         }
632 }
633
634
635 glTextNode *
636 gl_label_image_get_filename (glLabelImage *this)
637 {
638         g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
639
640         return gl_text_node_dup (this->priv->filename);
641 }
642
643
644 void
645 gl_label_image_get_base_size (glLabelImage *this,
646                               gdouble      *w,
647                               gdouble      *h)
648 {
649         RsvgDimensionData  svg_dim;
650
651         g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
652         g_return_if_fail (w != NULL);
653         g_return_if_fail (h != NULL);
654
655         switch (this->priv->type)
656         {
657
658         case FILE_TYPE_PIXBUF:
659                 *w = gdk_pixbuf_get_width (this->priv->pixbuf);
660                 *h = gdk_pixbuf_get_height (this->priv->pixbuf);
661                 break;
662
663         case FILE_TYPE_SVG:
664                 rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
665                 *w = svg_dim.width;
666                 *h = svg_dim.height;
667                 break;
668
669         default:
670                 *w = gdk_pixbuf_get_width (default_pixbuf);
671                 *h = gdk_pixbuf_get_height (default_pixbuf);
672                 break;
673
674         }
675 }
676
677
678 /*****************************************************************************/
679 /* Draw object method.                                                       */
680 /*****************************************************************************/
681 static void
682 draw_object (glLabelObject *object,
683              cairo_t       *cr,
684              gboolean       screen_flag,
685              glMergeRecord *record)
686 {
687         glLabelImage      *this = GL_LABEL_IMAGE (object);
688         gdouble            w, h;
689         gdouble            image_w, image_h;
690         GdkPixbuf         *pixbuf;
691         RsvgHandle        *svg_handle;
692         RsvgDimensionData  svg_dim;
693
694         gl_debug (DEBUG_LABEL, "START");
695
696         gl_label_object_get_size (object, &w, &h);
697
698         cairo_save (cr);
699
700         switch (get_type (this, record))
701         {
702
703         case FILE_TYPE_PIXBUF:
704                 pixbuf = gl_label_image_get_pixbuf (this, record);
705                 if ( pixbuf )
706                 {
707                         image_w = gdk_pixbuf_get_width (pixbuf);
708                         image_h = gdk_pixbuf_get_height (pixbuf);
709                         cairo_rectangle (cr, 0.0, 0.0, w, h);
710                         cairo_scale (cr, w/image_w, h/image_h);
711                         gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
712                         cairo_fill (cr);
713                         g_object_unref (pixbuf);
714                 }
715                 break;
716
717         case FILE_TYPE_SVG:
718                 svg_handle = gl_label_image_get_svg_handle (this, record);
719                 if ( svg_handle )
720                 {
721                         rsvg_handle_get_dimensions (svg_handle, &svg_dim);
722                         cairo_scale (cr, w/svg_dim.width, h/svg_dim.height);
723                         rsvg_handle_render_cairo (svg_handle, cr);
724                 }
725                 break;
726
727         default:
728                 cairo_rectangle (cr, 0.0, 0.0, w, h);
729                 image_w = gdk_pixbuf_get_width (default_pixbuf);
730                 image_h = gdk_pixbuf_get_height (default_pixbuf);
731                 cairo_scale (cr, w/image_w, h/image_h);
732                 gdk_cairo_set_source_pixbuf (cr, default_pixbuf, 0, 0);
733                 cairo_fill (cr);
734                 break;
735
736         }
737
738         cairo_restore (cr);
739
740         gl_debug (DEBUG_LABEL, "END");
741 }
742
743
744 /*****************************************************************************/
745 /* Draw shadow method.                                                       */
746 /*****************************************************************************/
747 static void
748 draw_shadow (glLabelObject *object,
749              cairo_t       *cr,
750              gboolean       screen_flag,
751              glMergeRecord *record)
752 {
753         glLabelImage    *this = GL_LABEL_IMAGE (object);
754         gdouble          w, h;
755         GdkPixbuf       *pixbuf;
756         GdkPixbuf       *shadow_pixbuf;
757         gdouble          image_w, image_h;
758         glColorNode     *shadow_color_node;
759         guint            shadow_color;
760         gdouble          shadow_opacity;
761
762         gl_debug (DEBUG_LABEL, "START");
763
764         gl_label_object_get_size (object, &w, &h);
765
766         shadow_color_node = gl_label_object_get_shadow_color (object);
767         shadow_color = gl_color_node_expand (shadow_color_node, record);
768         if (shadow_color_node->field_flag && screen_flag)
769         {
770                 shadow_color = GL_COLOR_SHADOW_MERGE_DEFAULT;
771         }
772         shadow_opacity = gl_label_object_get_shadow_opacity (object);
773
774         cairo_save (cr);
775
776         switch (get_type (this, record))
777         {
778
779         case FILE_TYPE_PIXBUF:
780                 pixbuf = gl_label_image_get_pixbuf (this, record);
781                 if ( pixbuf )
782                 {
783                         image_w = gdk_pixbuf_get_width (pixbuf);
784                         image_h = gdk_pixbuf_get_height (pixbuf);
785
786                         shadow_pixbuf = gl_pixbuf_util_create_shadow_pixbuf (pixbuf,
787                                                                              shadow_color, shadow_opacity);
788                         cairo_rectangle (cr, 0.0, 0.0, w, h);
789                         cairo_scale (cr, w/image_w, h/image_h);
790                         gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)shadow_pixbuf, 0, 0);
791                         cairo_fill (cr);
792
793                         g_object_unref (G_OBJECT (shadow_pixbuf));
794                         g_object_unref (G_OBJECT (pixbuf));
795                 }
796                 break;
797
798         case FILE_TYPE_SVG:
799                 /* FIXME: no shadow support, yet. */
800                 break;
801
802         default:
803                 shadow_color = gl_color_set_opacity (shadow_color, shadow_opacity);
804
805                 cairo_rectangle (cr, 0.0, 0.0, w, h);
806                 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (shadow_color));
807                 cairo_fill (cr);
808                 break;
809         }
810
811         cairo_restore (cr);
812
813         gl_debug (DEBUG_LABEL, "END");
814 }
815
816
817 /*****************************************************************************/
818 /* Is object at coordinates?                                                 */
819 /*****************************************************************************/
820 static gboolean
821 object_at (glLabelObject *object,
822            cairo_t       *cr,
823            gdouble        x,
824            gdouble        y)
825 {
826         gdouble           w, h;
827
828         gl_label_object_get_size (object, &w, &h);
829
830         cairo_new_path (cr);
831         cairo_rectangle (cr, 0.0, 0.0, w, h);
832
833         if (cairo_in_fill (cr, x, y))
834         {
835                 return TRUE;
836         }
837
838         return FALSE;
839 }
840
841
842
843
844 /*
845  * Local Variables:       -- emacs
846  * mode: C                -- emacs
847  * c-basic-offset: 8      -- emacs
848  * tab-width: 8           -- emacs
849  * indent-tabs-mode: nil  -- emacs
850  * End:                   -- emacs
851  */