]> git.sur5r.net Git - glabels/blob - glabels2/src/label-image.c
2009-09-22 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / 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.h>
26 #include <gdk/gdk.h>
27
28 #include "pixmaps/checkerboard.xpm"
29
30 #include "debug.h"
31
32
33 #define MIN_IMAGE_SIZE 1.0
34
35
36 /*========================================================*/
37 /* Private types.                                         */
38 /*========================================================*/
39
40 struct _glLabelImagePrivate {
41         glTextNode       *filename;
42         GdkPixbuf        *pixbuf;
43 };
44
45
46 /*========================================================*/
47 /* Private globals.                                       */
48 /*========================================================*/
49
50 static GdkPixbuf *default_pixbuf = NULL;
51
52
53 /*========================================================*/
54 /* Private function prototypes.                           */
55 /*========================================================*/
56
57 static void gl_label_image_finalize      (GObject           *object);
58
59 static void copy                         (glLabelObject     *dst_object,
60                                           glLabelObject     *src_object);
61
62 static void set_size                     (glLabelObject     *object,
63                                           gdouble            w,
64                                           gdouble            h);
65
66 static void draw_object                  (glLabelObject     *object,
67                                           cairo_t           *cr,
68                                           gboolean           screen_flag,
69                                           glMergeRecord     *record);
70
71
72 /*****************************************************************************/
73 /* Boilerplate object stuff.                                                 */
74 /*****************************************************************************/
75 G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
76
77
78 static void
79 gl_label_image_class_init (glLabelImageClass *class)
80 {
81         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
82         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
83
84         gl_label_image_parent_class = g_type_class_peek_parent (class);
85
86         label_object_class->copy           = copy;
87         label_object_class->set_size       = set_size;
88         label_object_class->draw_object    = draw_object;
89         label_object_class->draw_shadow    = NULL;
90
91         object_class->finalize = gl_label_image_finalize;
92 }
93
94
95 static void
96 gl_label_image_init (glLabelImage *limage)
97 {
98         GdkPixbuf *pixbuf;
99
100         if ( default_pixbuf == NULL ) {
101                 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
102                 default_pixbuf =
103                         gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
104                 g_object_unref (pixbuf);
105         }
106
107         limage->priv = g_new0 (glLabelImagePrivate, 1);
108
109         limage->priv->filename = g_new0 (glTextNode, 1);
110
111         limage->priv->pixbuf = default_pixbuf;
112 }
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 /*****************************************************************************/
137 /* NEW label "image" object.                                                 */
138 /*****************************************************************************/
139 GObject *
140 gl_label_image_new (glLabel *label)
141 {
142         glLabelImage *limage;
143
144         limage = g_object_new (gl_label_image_get_type(), NULL);
145
146         gl_label_object_set_parent (GL_LABEL_OBJECT(limage), label);
147
148         return G_OBJECT (limage);
149 }
150
151
152 /*****************************************************************************/
153 /* Copy object contents.                                                     */
154 /*****************************************************************************/
155 static void
156 copy (glLabelObject *dst_object,
157       glLabelObject *src_object)
158 {
159         glLabelImage     *limage     = (glLabelImage *)src_object;
160         glLabelImage     *new_limage = (glLabelImage *)dst_object;
161         glTextNode       *filename;
162         GdkPixbuf        *pixbuf;
163         GHashTable       *pixbuf_cache;
164
165         gl_debug (DEBUG_LABEL, "START");
166
167         g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
168         g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
169
170         filename = gl_label_image_get_filename (limage);
171
172         /* Make sure destination label has data suitably cached. */
173         if ( !filename->field_flag && (filename->data != NULL) ) {
174                 pixbuf = limage->priv->pixbuf;
175                 if ( pixbuf != default_pixbuf ) {
176                         pixbuf_cache = gl_label_get_pixbuf_cache (dst_object->parent);
177                         gl_pixbuf_cache_add_pixbuf (pixbuf_cache, filename->data, pixbuf);
178                 }
179         }
180
181         gl_label_image_set_filename (new_limage, filename);
182         gl_text_node_free (&filename);
183
184         gl_debug (DEBUG_LABEL, "END");
185 }
186
187
188 /*---------------------------------------------------------------------------*/
189 /* PRIVATE.  Set size method.                                                */
190 /*---------------------------------------------------------------------------*/
191 static void
192 set_size (glLabelObject *object,
193           gdouble        w,
194           gdouble        h)
195 {
196         g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
197
198         if (w < MIN_IMAGE_SIZE)
199         {
200                 w = MIN_IMAGE_SIZE;
201         }
202
203         if (h < MIN_IMAGE_SIZE)
204         {
205                 h = MIN_IMAGE_SIZE;
206         }
207
208         GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h);
209 }
210
211
212 /*****************************************************************************/
213 /* Set object params.                                                        */
214 /*****************************************************************************/
215 void
216 gl_label_image_set_filename (glLabelImage *limage,
217                              glTextNode   *filename)
218 {
219         glTextNode  *old_filename;
220         GHashTable  *pixbuf_cache;
221         GdkPixbuf   *pixbuf;
222         gdouble      image_w, image_h, aspect_ratio, w, h;
223
224         gl_debug (DEBUG_LABEL, "START");
225
226         g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
227         g_return_if_fail (filename != NULL);
228
229         old_filename = limage->priv->filename;
230
231         /* If Unchanged don't do anything */
232         if ( gl_text_node_equal (filename, old_filename ) ) {
233                 return;
234         }
235
236         pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
237
238         /* Remove reference to previous pixbuf from cache, if needed. */
239         if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
240                 gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
241         }
242
243         /* Set new filename. */
244         limage->priv->filename = gl_text_node_dup(filename);
245         gl_text_node_free (&old_filename);
246
247         /* Now set the pixbuf. */
248         if ( filename->field_flag || (filename->data == NULL) ) {
249
250                 limage->priv->pixbuf = default_pixbuf;
251
252         } else {
253
254                 pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
255
256                 if (pixbuf != NULL) {
257                         limage->priv->pixbuf = pixbuf;
258                 } else {
259                         limage->priv->pixbuf = default_pixbuf;
260                 }
261         }
262
263         /* Treat current size as a bounding box, scale image to maintain aspect
264          * ratio while fitting it in this bounding box. */
265         image_w = gdk_pixbuf_get_width (limage->priv->pixbuf);
266         image_h = gdk_pixbuf_get_height (limage->priv->pixbuf);
267         aspect_ratio = image_h / image_w;
268         gl_label_object_get_size (GL_LABEL_OBJECT(limage), &w, &h);
269         if ( h > w*aspect_ratio ) {
270                 h = w * aspect_ratio;
271         } else {
272                 w = h / aspect_ratio;
273         }
274         gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h);
275
276         gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
277
278         gl_debug (DEBUG_LABEL, "END");
279 }
280
281
282 /*****************************************************************************/
283 /* Get object params.                                                        */
284 /*****************************************************************************/
285 glTextNode *
286 gl_label_image_get_filename (glLabelImage *limage)
287 {
288         g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
289
290         return gl_text_node_dup (limage->priv->filename);
291 }
292
293
294 const GdkPixbuf *
295 gl_label_image_get_pixbuf (glLabelImage  *limage,
296                            glMergeRecord *record)
297 {
298         g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
299
300         if ((record != NULL) && limage->priv->filename->field_flag) {
301
302                 GdkPixbuf   *pixbuf = NULL;
303                 gchar       *real_filename;
304
305                 /* Indirect filename, re-evaluate for given record. */
306
307                 real_filename = gl_merge_eval_key (record,
308                                                    limage->priv->filename->data);
309
310                 if (real_filename != NULL) {
311                         pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
312                 }
313                 if ( pixbuf != NULL ) {
314                         return pixbuf;
315                 } else {
316                         return default_pixbuf;
317                 }
318
319         }
320
321         return limage->priv->pixbuf;
322
323 }
324
325
326 /*****************************************************************************/
327 /* Draw object method.                                                       */
328 /*****************************************************************************/
329 static void
330 draw_object (glLabelObject *object,
331              cairo_t       *cr,
332              gboolean       screen_flag,
333              glMergeRecord *record)
334 {
335         gdouble          x0, y0;
336         gdouble          w, h;
337         const GdkPixbuf *pixbuf;
338         gint             image_w, image_h;
339
340         gl_debug (DEBUG_LABEL, "START");
341
342         gl_label_object_get_size (object, &w, &h);
343         gl_label_object_get_position (object, &x0, &y0);
344
345         pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE (object), record);
346         image_w = gdk_pixbuf_get_width (pixbuf);
347         image_h = gdk_pixbuf_get_height (pixbuf);
348
349         cairo_save (cr);
350
351         cairo_rectangle (cr, 0.0, 0.0, w, h);
352
353         cairo_scale (cr, w/image_w, h/image_h);
354         gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
355         cairo_fill (cr);
356
357         cairo_restore (cr);
358
359         gl_debug (DEBUG_LABEL, "END");
360 }
361
362
363
364
365 /*
366  * Local Variables:       -- emacs
367  * mode: C                -- emacs
368  * c-basic-offset: 8      -- emacs
369  * tab-width: 8           -- emacs
370  * indent-tabs-mode: nil  -- emacs
371  * End:                   -- emacs
372  */