]> git.sur5r.net Git - glabels/blob - glabels2/src/label-barcode.c
2007-09-14 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / label-barcode.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_barcode.c:  GLabels label text 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-barcode.h"
26
27 #include <glib/gi18n.h>
28 #include <glib/gmem.h>
29 #include <glib/gstrfuncs.h>
30 #include <glib/gmessages.h>
31 #include <cairo.h>
32 #include <pango/pangocairo.h>
33
34 #include "debug.h"
35
36 /*========================================================*/
37 /* Private macros and constants.                          */
38 /*========================================================*/
39
40 #define FONT_SCALE (72.0/96.0)
41
42 /*========================================================*/
43 /* Private types.                                         */
44 /*========================================================*/
45
46 struct _glLabelBarcodePrivate {
47         glTextNode     *text_node;
48         gchar          *id;
49         glColorNode    *color_node;
50         gboolean        text_flag;
51         gboolean        checksum_flag;
52         guint           format_digits;
53 };
54
55 /*========================================================*/
56 /* Private globals.                                       */
57 /*========================================================*/
58
59 /*========================================================*/
60 /* Private function prototypes.                           */
61 /*========================================================*/
62
63 static void  gl_label_barcode_finalize      (GObject             *object);
64
65 static void  copy                           (glLabelObject       *dst_object,
66                                              glLabelObject       *src_object);
67
68 static void  get_size                       (glLabelObject       *object,
69                                              gdouble             *w,
70                                              gdouble             *h);
71
72 static void  set_line_color                 (glLabelObject       *object,
73                                              glColorNode         *line_color);
74
75 static glColorNode *get_line_color          (glLabelObject       *object);
76
77 static void    draw_object                (glLabelObject     *object,
78                                            cairo_t           *cr,
79                                            gboolean           screen_flag,
80                                            glMergeRecord     *record);
81
82
83 \f
84 /*****************************************************************************/
85 /* Boilerplate object stuff.                                                 */
86 /*****************************************************************************/
87 G_DEFINE_TYPE (glLabelBarcode, gl_label_barcode, GL_TYPE_LABEL_OBJECT);
88
89 static void
90 gl_label_barcode_class_init (glLabelBarcodeClass *class)
91 {
92         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
93         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
94
95         gl_label_barcode_parent_class = g_type_class_peek_parent (class);
96
97         label_object_class->copy           = copy;
98         label_object_class->get_size       = get_size;
99         label_object_class->set_line_color = set_line_color;
100         label_object_class->get_line_color = get_line_color;
101         label_object_class->draw_object    = draw_object;
102         label_object_class->draw_shadow    = NULL;
103
104         object_class->finalize = gl_label_barcode_finalize;
105 }
106
107 static void
108 gl_label_barcode_init (glLabelBarcode *lbc)
109 {
110         lbc->priv = g_new0 (glLabelBarcodePrivate, 1);
111         lbc->priv->color_node = gl_color_node_new_default ();
112         lbc->priv->text_node  = gl_text_node_new_from_text ("");
113 }
114
115 static void
116 gl_label_barcode_finalize (GObject *object)
117 {
118         glLabelBarcode *lbc = GL_LABEL_BARCODE (object);
119
120         g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
121
122         gl_text_node_free (&lbc->priv->text_node);
123         g_free (lbc->priv->id);
124         gl_color_node_free (&(lbc->priv->color_node));
125         g_free (lbc->priv);
126
127         G_OBJECT_CLASS (gl_label_barcode_parent_class)->finalize (object);
128 }
129
130 /*****************************************************************************/
131 /* NEW label "barcode" object.                                               */
132 /*****************************************************************************/
133 GObject *
134 gl_label_barcode_new (glLabel *label)
135 {
136         glLabelBarcode *lbc;
137
138         lbc = g_object_new (gl_label_barcode_get_type(), NULL);
139
140         gl_label_object_set_parent (GL_LABEL_OBJECT(lbc), label);
141
142         return G_OBJECT (lbc);
143 }
144
145 /*****************************************************************************/
146 /* Copy object contents.                                                     */
147 /*****************************************************************************/
148 static void
149 copy (glLabelObject *dst_object,
150       glLabelObject *src_object)
151 {
152         glLabelBarcode      *lbc     = (glLabelBarcode *)src_object;
153         glLabelBarcode      *new_lbc = (glLabelBarcode *)dst_object;
154         glTextNode          *text_node;
155         gchar               *id;
156         gboolean             text_flag;
157         gboolean             checksum_flag;
158         glColorNode         *color_node;
159         guint                format_digits;
160
161         gl_debug (DEBUG_LABEL, "START");
162
163         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
164         g_return_if_fail (new_lbc && GL_IS_LABEL_BARCODE (new_lbc));
165
166         text_node = gl_label_barcode_get_data (lbc);
167         gl_label_barcode_get_props (lbc, &id, &text_flag, &checksum_flag, &format_digits);
168         color_node = get_line_color (src_object);
169
170         gl_label_barcode_set_data (new_lbc, text_node);
171         gl_label_barcode_set_props (new_lbc, id, text_flag, checksum_flag, format_digits);
172         set_line_color (dst_object, color_node);
173
174         gl_color_node_free (&color_node);
175         gl_text_node_free (&text_node);
176         g_free (id);
177
178         gl_debug (DEBUG_LABEL, "END");
179 }
180
181
182 /*****************************************************************************/
183 /* Set object params.                                                        */
184 /*****************************************************************************/
185 void
186 gl_label_barcode_set_data (glLabelBarcode *lbc,
187                            glTextNode     *text_node)
188 {
189         gl_debug (DEBUG_LABEL, "START");
190
191         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
192
193         if (!gl_text_node_equal (lbc->priv->text_node, text_node)) {
194
195                 gl_text_node_free (&lbc->priv->text_node);
196                 lbc->priv->text_node = gl_text_node_dup (text_node);
197
198                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
199
200         }
201
202         gl_debug (DEBUG_LABEL, "END");
203 }
204
205 void
206 gl_label_barcode_set_props (glLabelBarcode *lbc,
207                             gchar          *id,
208                             gboolean        text_flag,
209                             gboolean        checksum_flag,
210                             guint           format_digits)
211 {
212         gl_debug (DEBUG_LABEL, "START");
213
214         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
215
216         if ( ((lbc->priv->id == NULL) && (id != NULL))
217              || (g_strcasecmp (lbc->priv->id, id) != 0)
218              || (lbc->priv->text_flag != text_flag)
219              || (lbc->priv->checksum_flag != checksum_flag)
220              || (lbc->priv->format_digits != format_digits)) {
221
222                 lbc->priv->id               = g_strdup (id);
223                 lbc->priv->text_flag        = text_flag;
224                 lbc->priv->checksum_flag    = checksum_flag;
225                 lbc->priv->format_digits    = format_digits;
226
227                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
228
229         }
230
231         gl_debug (DEBUG_LABEL, "END");
232 }
233
234
235 /*****************************************************************************/
236 /* Get object params.                                                        */
237 /*****************************************************************************/
238 glTextNode *
239 gl_label_barcode_get_data (glLabelBarcode *lbc)
240 {
241         g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
242
243         return gl_text_node_dup (lbc->priv->text_node);
244 }
245
246 void
247 gl_label_barcode_get_props (glLabelBarcode *lbc,
248                             gchar          **id,
249                             gboolean       *text_flag,
250                             gboolean       *checksum_flag,
251                             guint          *format_digits)
252 {
253         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
254
255         *id               = g_strdup (lbc->priv->id);
256         *text_flag        = lbc->priv->text_flag;
257         *checksum_flag    = lbc->priv->checksum_flag;
258         *format_digits    = lbc->priv->format_digits;
259 }
260
261 /*---------------------------------------------------------------------------*/
262 /* PRIVATE.  Get object size method.                                         */
263 /*---------------------------------------------------------------------------*/
264 static void
265 get_size (glLabelObject *object,
266           gdouble       *w,
267           gdouble       *h)
268 {
269         glLabelBarcode      *lbc = (glLabelBarcode *)object;
270         gchar               *data;
271         gdouble              w_parent, h_parent;
272         glBarcode           *gbc;
273
274         gl_debug (DEBUG_LABEL, "START");
275
276         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
277
278         gl_label_object_get_raw_size (object, &w_parent, &h_parent);
279
280         if (lbc->priv->text_node->field_flag) {
281                 data = gl_barcode_default_digits (lbc->priv->id,
282                                                   lbc->priv->format_digits);
283         } else {
284                 data = gl_text_node_expand (lbc->priv->text_node, NULL);
285         }
286
287         gbc = gl_barcode_new (lbc->priv->id,
288                               lbc->priv->text_flag,
289                               lbc->priv->checksum_flag,
290                               w_parent,
291                               h_parent,
292                               data);
293
294         if ( gbc == NULL ) {
295                 /* Try again with default digits. */
296                 data = gl_barcode_default_digits (lbc->priv->id,
297                                                   lbc->priv->format_digits);
298                 gbc = gl_barcode_new (lbc->priv->id,
299                                       lbc->priv->text_flag,
300                                       lbc->priv->checksum_flag,
301                                       w_parent,
302                                       h_parent,
303                                       data);
304         }
305
306         *w = gbc->width;
307         *h = gbc->height;
308
309         gl_barcode_free (&gbc);
310         g_free (data);
311
312         gl_debug (DEBUG_LABEL, "END");
313 }
314
315 /*---------------------------------------------------------------------------*/
316 /* PRIVATE.  Set line color method.                                          */
317 /*---------------------------------------------------------------------------*/
318 static void
319 set_line_color (glLabelObject *object,
320                 glColorNode   *line_color_node)
321 {
322         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
323
324         g_return_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode));
325
326         if ( !gl_color_node_equal(lbarcode->priv->color_node, line_color_node) ) {
327                 
328                 gl_color_node_free (&(lbarcode->priv->color_node));
329                 lbarcode->priv->color_node = gl_color_node_dup (line_color_node);
330                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbarcode));
331         }
332 }
333
334 /*---------------------------------------------------------------------------*/
335 /* PRIVATE.  Get line color method.                                          */
336 /*---------------------------------------------------------------------------*/
337 static glColorNode*
338 get_line_color (glLabelObject *object)
339 {
340         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
341
342         g_return_val_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode), NULL);
343
344         return gl_color_node_dup (lbarcode->priv->color_node);
345 }
346
347 /*****************************************************************************/
348 /* Draw object method.                                                       */
349 /*****************************************************************************/
350 static void
351 draw_object (glLabelObject *object,
352              cairo_t       *cr,
353              gboolean       screen_flag,
354              glMergeRecord *record)
355 {
356         gdouble             x0, y0;
357         cairo_matrix_t      matrix;
358         glBarcode          *gbc;
359         glBarcodeLine      *line;
360         glBarcodeChar      *bchar;
361         GList              *li;
362         gdouble             y_offset;
363         PangoLayout        *layout;
364         PangoFontDescription *desc;
365         gchar              *text, *cstring;
366         glTextNode         *text_node;
367         gchar              *id;
368         gboolean            text_flag;
369         gboolean            checksum_flag;
370         guint               color;
371         glColorNode        *color_node;
372         guint               format_digits;
373         gdouble             w, h;
374
375         gl_debug (DEBUG_LABEL, "START");
376
377         gl_label_object_get_position (object, &x0, &y0);
378         gl_label_object_get_matrix (object, &matrix);
379
380         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
381         gl_label_barcode_get_props (GL_LABEL_BARCODE (object),
382                                     &id, &text_flag, &checksum_flag, &format_digits);
383                                         
384         color_node = gl_label_object_get_line_color (object);
385         color = gl_color_node_expand (color_node, record);
386         if (color_node->field_flag && screen_flag)
387         {
388                 color = GL_COLOR_MERGE_DEFAULT;
389         }
390         gl_color_node_free (&color_node);
391         
392         gl_label_object_get_size (object, &w, &h);
393
394         text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
395         text = gl_text_node_expand (text_node, record);
396         if (text_node->field_flag && screen_flag) {
397                 text = gl_barcode_default_digits (id, format_digits);
398         }
399
400         gbc = gl_barcode_new (id, text_flag, checksum_flag, w, h, text);
401
402         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
403
404         if (gbc == NULL) {
405
406                 layout = pango_cairo_create_layout (cr);
407
408                 desc = pango_font_description_new ();
409                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
410                 pango_font_description_set_size   (desc, 12 * PANGO_SCALE * FONT_SCALE);
411                 pango_layout_set_font_description (layout, desc);
412                 pango_font_description_free       (desc);
413
414                 if (text == NULL || *text == '\0')
415                 {
416                         pango_layout_set_text (layout, _("Barcode data empty"), -1);
417                 }
418                 else
419                 {
420                         pango_layout_set_text (layout, _("Invalid barcode data"), -1);
421                 }
422
423                 pango_cairo_show_layout (cr, layout);
424
425                 g_object_unref (layout);
426
427         } else {
428
429                 for (li = gbc->lines; li != NULL; li = li->next) {
430                         line = (glBarcodeLine *) li->data;
431
432                         cairo_move_to (cr, line->x, line->y);
433                         cairo_line_to (cr, line->x, line->y + line->length);
434                         cairo_set_line_width (cr, line->width);
435                         cairo_stroke (cr);
436                 }
437
438                 for (li = gbc->chars; li != NULL; li = li->next) {
439                         bchar = (glBarcodeChar *) li->data;
440
441                         layout = pango_cairo_create_layout (cr);
442
443                         desc = pango_font_description_new ();
444                         pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
445                         pango_font_description_set_size   (desc, bchar->fsize * PANGO_SCALE * FONT_SCALE);
446                         pango_layout_set_font_description (layout, desc);
447                         pango_font_description_free       (desc);
448
449                         cstring = g_strdup_printf ("%c", bchar->c);
450                         pango_layout_set_text (layout, cstring, -1);
451                         g_free (cstring);
452
453                         y_offset = 0.2 * bchar->fsize;
454
455                         cairo_move_to (cr, bchar->x, bchar->y-y_offset);
456                         pango_cairo_show_layout (cr, layout);
457
458                         g_object_unref (layout);
459
460                 }
461
462                 gl_barcode_free (&gbc);
463
464         }
465
466         g_free (text);
467         gl_text_node_free (&text_node);
468         g_free (id);
469
470         gl_debug (DEBUG_LABEL, "END");
471 }
472