3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
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.
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.
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/>.
23 #include "label-image.h"
28 #include "pixmaps/checkerboard.xpm"
33 #define MIN_IMAGE_SIZE 1.0
36 /*========================================================*/
38 /*========================================================*/
40 struct _glLabelImagePrivate {
46 /*========================================================*/
47 /* Private globals. */
48 /*========================================================*/
50 static GdkPixbuf *default_pixbuf = NULL;
53 /*========================================================*/
54 /* Private function prototypes. */
55 /*========================================================*/
57 static void gl_label_image_finalize (GObject *object);
59 static void copy (glLabelObject *dst_object,
60 glLabelObject *src_object);
62 static void set_size (glLabelObject *object,
66 static void draw_object (glLabelObject *object,
69 glMergeRecord *record);
72 /*****************************************************************************/
73 /* Boilerplate object stuff. */
74 /*****************************************************************************/
75 G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
79 gl_label_image_class_init (glLabelImageClass *class)
81 GObjectClass *object_class = G_OBJECT_CLASS (class);
82 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
84 gl_label_image_parent_class = g_type_class_peek_parent (class);
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;
91 object_class->finalize = gl_label_image_finalize;
96 gl_label_image_init (glLabelImage *limage)
100 if ( default_pixbuf == NULL ) {
101 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
103 gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
104 g_object_unref (pixbuf);
107 limage->priv = g_new0 (glLabelImagePrivate, 1);
109 limage->priv->filename = g_new0 (glTextNode, 1);
111 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);
136 /*****************************************************************************/
137 /* NEW label "image" object. */
138 /*****************************************************************************/
140 gl_label_image_new (glLabel *label)
142 glLabelImage *limage;
144 limage = g_object_new (gl_label_image_get_type(), NULL);
146 gl_label_object_set_parent (GL_LABEL_OBJECT(limage), label);
148 return G_OBJECT (limage);
152 /*****************************************************************************/
153 /* Copy object contents. */
154 /*****************************************************************************/
156 copy (glLabelObject *dst_object,
157 glLabelObject *src_object)
159 glLabelImage *limage = (glLabelImage *)src_object;
160 glLabelImage *new_limage = (glLabelImage *)dst_object;
161 glTextNode *filename;
163 GHashTable *pixbuf_cache;
165 gl_debug (DEBUG_LABEL, "START");
167 g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
168 g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
170 filename = gl_label_image_get_filename (limage);
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);
181 gl_label_image_set_filename (new_limage, filename);
182 gl_text_node_free (&filename);
184 gl_debug (DEBUG_LABEL, "END");
188 /*---------------------------------------------------------------------------*/
189 /* PRIVATE. Set size method. */
190 /*---------------------------------------------------------------------------*/
192 set_size (glLabelObject *object,
196 g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
198 if (w < MIN_IMAGE_SIZE)
203 if (h < MIN_IMAGE_SIZE)
208 GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h);
212 /*****************************************************************************/
213 /* Set object params. */
214 /*****************************************************************************/
216 gl_label_image_set_filename (glLabelImage *limage,
217 glTextNode *filename)
219 glTextNode *old_filename;
220 GHashTable *pixbuf_cache;
222 gdouble image_w, image_h, aspect_ratio, w, h;
224 gl_debug (DEBUG_LABEL, "START");
226 g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
227 g_return_if_fail (filename != NULL);
229 old_filename = limage->priv->filename;
231 /* If Unchanged don't do anything */
232 if ( gl_text_node_equal (filename, old_filename ) ) {
236 pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
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);
243 /* Set new filename. */
244 limage->priv->filename = gl_text_node_dup(filename);
245 gl_text_node_free (&old_filename);
247 /* Now set the pixbuf. */
248 if ( filename->field_flag || (filename->data == NULL) ) {
250 limage->priv->pixbuf = default_pixbuf;
254 pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
256 if (pixbuf != NULL) {
257 limage->priv->pixbuf = pixbuf;
259 limage->priv->pixbuf = default_pixbuf;
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;
272 w = h / aspect_ratio;
274 gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h);
276 gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
278 gl_debug (DEBUG_LABEL, "END");
282 /*****************************************************************************/
283 /* Get object params. */
284 /*****************************************************************************/
286 gl_label_image_get_filename (glLabelImage *limage)
288 g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
290 return gl_text_node_dup (limage->priv->filename);
295 gl_label_image_get_pixbuf (glLabelImage *limage,
296 glMergeRecord *record)
298 g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
300 if ((record != NULL) && limage->priv->filename->field_flag) {
302 GdkPixbuf *pixbuf = NULL;
303 gchar *real_filename;
305 /* Indirect filename, re-evaluate for given record. */
307 real_filename = gl_merge_eval_key (record,
308 limage->priv->filename->data);
310 if (real_filename != NULL) {
311 pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
313 if ( pixbuf != NULL ) {
316 return default_pixbuf;
321 return limage->priv->pixbuf;
326 /*****************************************************************************/
327 /* Draw object method. */
328 /*****************************************************************************/
330 draw_object (glLabelObject *object,
332 gboolean screen_flag,
333 glMergeRecord *record)
337 const GdkPixbuf *pixbuf;
338 gint image_w, image_h;
340 gl_debug (DEBUG_LABEL, "START");
342 gl_label_object_get_size (object, &w, &h);
343 gl_label_object_get_position (object, &x0, &y0);
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);
351 cairo_rectangle (cr, 0.0, 0.0, w, h);
353 cairo_scale (cr, w/image_w, h/image_h);
354 gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
359 gl_debug (DEBUG_LABEL, "END");
366 * Local Variables: -- emacs
368 * c-basic-offset: 8 -- emacs
369 * tab-width: 8 -- emacs
370 * indent-tabs-mode: nil -- emacs