1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * label_image.c: GLabels label image object
8 * Copyright (C) 2001-2007 Jim Evins <evins@snaught.com>.
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.
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.
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
25 #include "label-image.h"
27 #include <glib/gmem.h>
28 #include <glib/gstrfuncs.h>
29 #include <glib/gmessages.h>
30 #include <gdk/gdkcairo.h>
32 #include "pixmaps/checkerboard.xpm"
37 #define MIN_IMAGE_SIZE 1.0
40 /*========================================================*/
42 /*========================================================*/
44 struct _glLabelImagePrivate {
49 /*========================================================*/
50 /* Private globals. */
51 /*========================================================*/
53 static GdkPixbuf *default_pixbuf = NULL;
55 /*========================================================*/
56 /* Private function prototypes. */
57 /*========================================================*/
59 static void gl_label_image_finalize (GObject *object);
61 static void copy (glLabelObject *dst_object,
62 glLabelObject *src_object);
64 static void set_size (glLabelObject *object,
68 static void draw_object (glLabelObject *object,
71 glMergeRecord *record);
75 /*****************************************************************************/
76 /* Boilerplate object stuff. */
77 /*****************************************************************************/
78 G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
81 gl_label_image_class_init (glLabelImageClass *class)
83 GObjectClass *object_class = G_OBJECT_CLASS (class);
84 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
86 gl_label_image_parent_class = g_type_class_peek_parent (class);
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;
93 object_class->finalize = gl_label_image_finalize;
97 gl_label_image_init (glLabelImage *limage)
101 if ( default_pixbuf == NULL ) {
102 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
104 gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
105 g_object_unref (pixbuf);
108 limage->priv = g_new0 (glLabelImagePrivate, 1);
110 limage->priv->filename = g_new0 (glTextNode, 1);
112 limage->priv->pixbuf = default_pixbuf;
116 gl_label_image_finalize (GObject *object)
118 glLabelObject *lobject = GL_LABEL_OBJECT (object);
119 glLabelImage *limage = GL_LABEL_IMAGE (object);;
120 GHashTable *pixbuf_cache;
122 g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
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);
129 gl_text_node_free (&limage->priv->filename);
130 g_free (limage->priv);
132 G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
135 /*****************************************************************************/
136 /* NEW label "image" object. */
137 /*****************************************************************************/
139 gl_label_image_new (glLabel *label)
141 glLabelImage *limage;
143 limage = g_object_new (gl_label_image_get_type(), NULL);
145 gl_label_object_set_parent (GL_LABEL_OBJECT(limage), label);
147 return G_OBJECT (limage);
150 /*****************************************************************************/
151 /* Copy object contents. */
152 /*****************************************************************************/
154 copy (glLabelObject *dst_object,
155 glLabelObject *src_object)
157 glLabelImage *limage = (glLabelImage *)src_object;
158 glLabelImage *new_limage = (glLabelImage *)dst_object;
159 glTextNode *filename;
161 GHashTable *pixbuf_cache;
163 gl_debug (DEBUG_LABEL, "START");
165 g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
166 g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
168 filename = gl_label_image_get_filename (limage);
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);
179 gl_label_image_set_filename (new_limage, filename);
180 gl_text_node_free (&filename);
182 gl_debug (DEBUG_LABEL, "END");
186 /*---------------------------------------------------------------------------*/
187 /* PRIVATE. Set size method. */
188 /*---------------------------------------------------------------------------*/
190 set_size (glLabelObject *object,
194 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
196 if (w < MIN_IMAGE_SIZE)
201 if (h < MIN_IMAGE_SIZE)
206 GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h);
210 /*****************************************************************************/
211 /* Set object params. */
212 /*****************************************************************************/
214 gl_label_image_set_filename (glLabelImage *limage,
215 glTextNode *filename)
217 glTextNode *old_filename;
218 GHashTable *pixbuf_cache;
220 gdouble image_w, image_h, aspect_ratio, w, h;
222 gl_debug (DEBUG_LABEL, "START");
224 g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
225 g_return_if_fail (filename != NULL);
227 old_filename = limage->priv->filename;
229 /* If Unchanged don't do anything */
230 if ( gl_text_node_equal (filename, old_filename ) ) {
234 pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
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);
241 /* Set new filename. */
242 limage->priv->filename = gl_text_node_dup(filename);
243 gl_text_node_free (&old_filename);
245 /* Now set the pixbuf. */
246 if ( filename->field_flag || (filename->data == NULL) ) {
248 limage->priv->pixbuf = default_pixbuf;
252 pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
254 if (pixbuf != NULL) {
255 limage->priv->pixbuf = pixbuf;
257 limage->priv->pixbuf = default_pixbuf;
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;
270 w = h / aspect_ratio;
272 gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h);
274 gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
276 gl_debug (DEBUG_LABEL, "END");
280 /*****************************************************************************/
281 /* Get object params. */
282 /*****************************************************************************/
284 gl_label_image_get_filename (glLabelImage *limage)
286 g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
288 return gl_text_node_dup (limage->priv->filename);
292 gl_label_image_get_pixbuf (glLabelImage *limage,
293 glMergeRecord *record)
295 g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
297 if ((record != NULL) && limage->priv->filename->field_flag) {
299 GdkPixbuf *pixbuf = NULL;
300 gchar *real_filename;
302 /* Indirect filename, re-evaluate for given record. */
304 real_filename = gl_merge_eval_key (record,
305 limage->priv->filename->data);
307 if (real_filename != NULL) {
308 pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
310 if ( pixbuf != NULL ) {
313 return default_pixbuf;
318 return limage->priv->pixbuf;
322 /*****************************************************************************/
323 /* Draw object method. */
324 /*****************************************************************************/
326 draw_object (glLabelObject *object,
328 gboolean screen_flag,
329 glMergeRecord *record)
333 const GdkPixbuf *pixbuf;
334 gint image_w, image_h;
336 gl_debug (DEBUG_LABEL, "START");
338 gl_label_object_get_size (object, &w, &h);
339 gl_label_object_get_position (object, &x0, &y0);
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);
347 cairo_rectangle (cr, 0.0, 0.0, w, h);
349 cairo_scale (cr, w/image_w, h/image_h);
350 gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
355 gl_debug (DEBUG_LABEL, "END");