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