]> git.sur5r.net Git - glabels/blob - src/label-image.c
Imported Upstream version 2.2.8
[glabels] / src / label-image.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  label_image.c:  GLabels label image object
7  *
8  *  Copyright (C) 2001-2007  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24
25 #include "label-image.h"
26
27 #include <glib/gmem.h>
28 #include <glib/gstrfuncs.h>
29 #include <glib/gmessages.h>
30 #include <gdk/gdkcairo.h>
31
32 #include "pixmaps/checkerboard.xpm"
33
34 #include "debug.h"
35
36
37 #define MIN_IMAGE_SIZE 1.0
38
39
40 /*========================================================*/
41 /* Private types.                                         */
42 /*========================================================*/
43
44 struct _glLabelImagePrivate {
45         glTextNode       *filename;
46         GdkPixbuf        *pixbuf;
47 };
48
49 /*========================================================*/
50 /* Private globals.                                       */
51 /*========================================================*/
52
53 static GdkPixbuf *default_pixbuf = NULL;
54
55 /*========================================================*/
56 /* Private function prototypes.                           */
57 /*========================================================*/
58
59 static void gl_label_image_finalize      (GObject           *object);
60
61 static void copy                         (glLabelObject     *dst_object,
62                                           glLabelObject     *src_object);
63
64 static void set_size                      (glLabelObject      *object,
65                                            gdouble             w,
66                                            gdouble             h);
67
68 static void    draw_object               (glLabelObject     *object,
69                                           cairo_t           *cr,
70                                           gboolean           screen_flag,
71                                           glMergeRecord     *record);
72
73
74 \f
75 /*****************************************************************************/
76 /* Boilerplate object stuff.                                                 */
77 /*****************************************************************************/
78 G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
79
80 static void
81 gl_label_image_class_init (glLabelImageClass *class)
82 {
83         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
84         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
85
86         gl_label_image_parent_class = g_type_class_peek_parent (class);
87
88         label_object_class->copy           = copy;
89         label_object_class->set_size       = set_size;
90         label_object_class->draw_object    = draw_object;
91         label_object_class->draw_shadow    = NULL;
92
93         object_class->finalize = gl_label_image_finalize;
94 }
95
96 static void
97 gl_label_image_init (glLabelImage *limage)
98 {
99         GdkPixbuf *pixbuf;
100
101         if ( default_pixbuf == NULL ) {
102                 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
103                 default_pixbuf =
104                         gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
105                 g_object_unref (pixbuf);
106         }
107
108         limage->priv = g_new0 (glLabelImagePrivate, 1);
109
110         limage->priv->filename = g_new0 (glTextNode, 1);
111
112         limage->priv->pixbuf = default_pixbuf;
113 }
114
115 static void
116 gl_label_image_finalize (GObject *object)
117 {
118         glLabelObject *lobject = GL_LABEL_OBJECT (object);
119         glLabelImage  *limage  = GL_LABEL_IMAGE (object);;
120         GHashTable    *pixbuf_cache;
121
122         g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
123
124         if (!limage->priv->filename->field_flag) {
125                 pixbuf_cache = gl_label_get_pixbuf_cache (lobject->parent);
126                 gl_pixbuf_cache_remove_pixbuf (pixbuf_cache,
127                                                limage->priv->filename->data);
128         }
129         gl_text_node_free (&limage->priv->filename);
130         g_free (limage->priv);
131
132         G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
133 }
134
135 /*****************************************************************************/
136 /* NEW label "image" object.                                                 */
137 /*****************************************************************************/
138 GObject *
139 gl_label_image_new (glLabel *label)
140 {
141         glLabelImage *limage;
142
143         limage = g_object_new (gl_label_image_get_type(), NULL);
144
145         gl_label_object_set_parent (GL_LABEL_OBJECT(limage), label);
146
147         return G_OBJECT (limage);
148 }
149
150 /*****************************************************************************/
151 /* Copy object contents.                                                     */
152 /*****************************************************************************/
153 static void
154 copy (glLabelObject *dst_object,
155       glLabelObject *src_object)
156 {
157         glLabelImage     *limage     = (glLabelImage *)src_object;
158         glLabelImage     *new_limage = (glLabelImage *)dst_object;
159         glTextNode       *filename;
160         GdkPixbuf        *pixbuf;
161         GHashTable       *pixbuf_cache;
162
163         gl_debug (DEBUG_LABEL, "START");
164
165         g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
166         g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
167
168         filename = gl_label_image_get_filename (limage);
169
170         /* Make sure destination label has data suitably cached. */
171         if ( !filename->field_flag && (filename->data != NULL) ) {
172                 pixbuf = limage->priv->pixbuf;
173                 if ( pixbuf != default_pixbuf ) {
174                         pixbuf_cache = gl_label_get_pixbuf_cache (dst_object->parent);
175                         gl_pixbuf_cache_add_pixbuf (pixbuf_cache, filename->data, pixbuf);
176                 }
177         }
178
179         gl_label_image_set_filename (new_limage, filename);
180         gl_text_node_free (&filename);
181
182         gl_debug (DEBUG_LABEL, "END");
183 }
184
185
186 /*---------------------------------------------------------------------------*/
187 /* PRIVATE.  Set size method.                                                */
188 /*---------------------------------------------------------------------------*/
189 static void
190 set_size (glLabelObject *object,
191           gdouble        w,
192           gdouble        h)
193 {
194         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
195
196         if (w < MIN_IMAGE_SIZE)
197         {
198                 w = MIN_IMAGE_SIZE;
199         }
200
201         if (h < MIN_IMAGE_SIZE)
202         {
203                 h = MIN_IMAGE_SIZE;
204         }
205
206         GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h);
207 }
208
209
210 /*****************************************************************************/
211 /* Set object params.                                                        */
212 /*****************************************************************************/
213 void
214 gl_label_image_set_filename (glLabelImage *limage,
215                              glTextNode   *filename)
216 {
217         glTextNode  *old_filename;
218         GHashTable  *pixbuf_cache;
219         GdkPixbuf   *pixbuf;
220         gdouble      image_w, image_h, aspect_ratio, w, h;
221
222         gl_debug (DEBUG_LABEL, "START");
223
224         g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
225         g_return_if_fail (filename != NULL);
226
227         old_filename = limage->priv->filename;
228
229         /* If Unchanged don't do anything */
230         if ( gl_text_node_equal (filename, old_filename ) ) {
231                 return;
232         }
233
234         pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
235
236         /* Remove reference to previous pixbuf from cache, if needed. */
237         if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
238                 gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
239         }
240
241         /* Set new filename. */
242         limage->priv->filename = gl_text_node_dup(filename);
243         gl_text_node_free (&old_filename);
244
245         /* Now set the pixbuf. */
246         if ( filename->field_flag || (filename->data == NULL) ) {
247
248                 limage->priv->pixbuf = default_pixbuf;
249
250         } else {
251
252                 pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
253
254                 if (pixbuf != NULL) {
255                         limage->priv->pixbuf = pixbuf;
256                 } else {
257                         limage->priv->pixbuf = default_pixbuf;
258                 }
259         }
260
261         /* Treat current size as a bounding box, scale image to maintain aspect
262          * ratio while fitting it in this bounding box. */
263         image_w = gdk_pixbuf_get_width (limage->priv->pixbuf);
264         image_h = gdk_pixbuf_get_height (limage->priv->pixbuf);
265         aspect_ratio = image_h / image_w;
266         gl_label_object_get_size (GL_LABEL_OBJECT(limage), &w, &h);
267         if ( h > w*aspect_ratio ) {
268                 h = w * aspect_ratio;
269         } else {
270                 w = h / aspect_ratio;
271         }
272         gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h);
273
274         gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
275
276         gl_debug (DEBUG_LABEL, "END");
277 }
278
279
280 /*****************************************************************************/
281 /* Get object params.                                                        */
282 /*****************************************************************************/
283 glTextNode *
284 gl_label_image_get_filename (glLabelImage *limage)
285 {
286         g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
287
288         return gl_text_node_dup (limage->priv->filename);
289 }
290
291 const GdkPixbuf *
292 gl_label_image_get_pixbuf (glLabelImage  *limage,
293                            glMergeRecord *record)
294 {
295         g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
296
297         if ((record != NULL) && limage->priv->filename->field_flag) {
298
299                 GdkPixbuf   *pixbuf = NULL;
300                 gchar       *real_filename;
301
302                 /* Indirect filename, re-evaluate for given record. */
303
304                 real_filename = gl_merge_eval_key (record,
305                                                    limage->priv->filename->data);
306
307                 if (real_filename != NULL) {
308                         pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
309                 }
310                 if ( pixbuf != NULL ) {
311                         return pixbuf;
312                 } else {
313                         return default_pixbuf;
314                 }
315
316         }
317
318         return limage->priv->pixbuf;
319
320 }
321
322 /*****************************************************************************/
323 /* Draw object method.                                                       */
324 /*****************************************************************************/
325 static void
326 draw_object (glLabelObject *object,
327              cairo_t       *cr,
328              gboolean       screen_flag,
329              glMergeRecord *record)
330 {
331         gdouble          x0, y0;
332         gdouble          w, h;
333         const GdkPixbuf *pixbuf;
334         gint             image_w, image_h;
335
336         gl_debug (DEBUG_LABEL, "START");
337
338         gl_label_object_get_size (object, &w, &h);
339         gl_label_object_get_position (object, &x0, &y0);
340
341         pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE (object), record);
342         image_w = gdk_pixbuf_get_width (pixbuf);
343         image_h = gdk_pixbuf_get_height (pixbuf);
344
345         cairo_save (cr);
346
347         cairo_rectangle (cr, 0.0, 0.0, w, h);
348
349         cairo_scale (cr, w/image_w, h/image_h);
350         gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
351         cairo_fill (cr);
352
353         cairo_restore (cr);
354
355         gl_debug (DEBUG_LABEL, "END");
356 }
357
358
359