]> git.sur5r.net Git - glabels/blob - src/label-barcode.c
Allow user selection of barcode backend.
[glabels] / 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 #include "bc-backends.h"
29
30 #include "debug.h"
31
32 /*========================================================*/
33 /* Private macros and constants.                          */
34 /*========================================================*/
35
36 #define FONT_SCALE (72.0/96.0)
37 #define PI 3.141592654
38
39
40 /*========================================================*/
41 /* Private types.                                         */
42 /*========================================================*/
43
44 struct _glLabelBarcodePrivate {
45         glTextNode     *text_node;
46         gchar          *backend_id;
47         gchar          *id;
48         glColorNode    *color_node;
49         gboolean        text_flag;
50         gboolean        checksum_flag;
51         guint           format_digits;
52 };
53
54
55 /*========================================================*/
56 /* Private globals.                                       */
57 /*========================================================*/
58
59
60 /*========================================================*/
61 /* Private function prototypes.                           */
62 /*========================================================*/
63
64 static void  gl_label_barcode_finalize      (GObject             *object);
65
66 static void  copy                           (glLabelObject       *dst_object,
67                                              glLabelObject       *src_object);
68
69 static void  get_size                       (glLabelObject       *object,
70                                              gdouble             *w,
71                                              gdouble             *h);
72
73 static void  set_line_color                 (glLabelObject       *object,
74                                              glColorNode         *line_color,
75                                              gboolean             checkpoint);
76
77 static glColorNode *get_line_color          (glLabelObject       *object);
78
79 static void     draw_object                 (glLabelObject       *object,
80                                              cairo_t             *cr,
81                                              gboolean             screen_flag,
82                                              glMergeRecord       *record);
83
84 static gboolean object_at                   (glLabelObject       *object,
85                                              cairo_t             *cr,
86                                              gdouble              x_pixels,
87                                              gdouble              y_pixels);
88
89
90 /*****************************************************************************/
91 /* Boilerplate object stuff.                                                 */
92 /*****************************************************************************/
93 G_DEFINE_TYPE (glLabelBarcode, gl_label_barcode, GL_TYPE_LABEL_OBJECT);
94
95
96 static void
97 gl_label_barcode_class_init (glLabelBarcodeClass *class)
98 {
99         GObjectClass       *object_class       = G_OBJECT_CLASS (class);
100         glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
101
102         gl_label_barcode_parent_class = g_type_class_peek_parent (class);
103
104         label_object_class->copy           = copy;
105         label_object_class->get_size       = get_size;
106         label_object_class->set_line_color = set_line_color;
107         label_object_class->get_line_color = get_line_color;
108         label_object_class->draw_object    = draw_object;
109         label_object_class->draw_shadow    = NULL;
110         label_object_class->object_at      = object_at;
111
112         object_class->finalize = gl_label_barcode_finalize;
113 }
114
115
116 static void
117 gl_label_barcode_init (glLabelBarcode *lbc)
118 {
119         lbc->priv = g_new0 (glLabelBarcodePrivate, 1);
120         lbc->priv->text_node  = gl_text_node_new_from_text ("");
121 }
122
123
124 static void
125 gl_label_barcode_finalize (GObject *object)
126 {
127         glLabelBarcode *lbc = GL_LABEL_BARCODE (object);
128
129         g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
130
131         gl_text_node_free (&lbc->priv->text_node);
132         g_free (lbc->priv->id);
133         gl_color_node_free (&(lbc->priv->color_node));
134         g_free (lbc->priv);
135
136         G_OBJECT_CLASS (gl_label_barcode_parent_class)->finalize (object);
137 }
138
139
140 /*****************************************************************************/
141 /* NEW label "barcode" object.                                               */
142 /*****************************************************************************/
143 GObject *
144 gl_label_barcode_new (glLabel *label,
145                       gboolean checkpoint)
146 {
147         glLabelBarcode      *lbc;
148         glColorNode         *line_color_node;
149
150         lbc = g_object_new (gl_label_barcode_get_type(), NULL);
151
152         if (label != NULL)
153         {
154                 if ( checkpoint )
155                 {
156                         gl_label_checkpoint (label, _("Create barcode object"));
157                 }
158
159                 /* Default barcode style and properties. */
160                 lbc->priv->backend_id = g_strdup (gl_barcode_backends_backend_name_to_id (NULL));
161                 lbc->priv->id         = g_strdup (gl_barcode_backends_style_name_to_id (lbc->priv->backend_id,
162                                                                                         NULL));
163                 lbc->priv->text_flag     = gl_barcode_backends_style_can_text (lbc->priv->backend_id,
164                                                                                lbc->priv->id);
165                 lbc->priv->checksum_flag = gl_barcode_backends_style_can_csum (lbc->priv->backend_id,
166                                                                                lbc->priv->id);
167                 lbc->priv->format_digits = gl_barcode_backends_style_get_prefered_n (lbc->priv->backend_id,
168                                                                                      lbc->priv->id);
169
170                 line_color_node = gl_color_node_new_default ();
171                 line_color_node->color = gl_label_get_default_line_color(label);
172
173                 lbc->priv->color_node = line_color_node;
174
175                 gl_label_add_object (label, GL_LABEL_OBJECT (lbc));
176                 gl_label_object_set_parent (GL_LABEL_OBJECT (lbc), label);
177         }
178
179         return G_OBJECT (lbc);
180 }
181
182
183 /*****************************************************************************/
184 /* Copy object contents.                                                     */
185 /*****************************************************************************/
186 static void
187 copy (glLabelObject *dst_object,
188       glLabelObject *src_object)
189 {
190         glLabelBarcode      *lbc     = (glLabelBarcode *)src_object;
191         glLabelBarcode      *new_lbc = (glLabelBarcode *)dst_object;
192         glTextNode          *text_node;
193         gchar               *backend_id;
194         gchar               *id;
195         gboolean             text_flag;
196         gboolean             checksum_flag;
197         glColorNode         *color_node;
198         guint                format_digits;
199
200         gl_debug (DEBUG_LABEL, "START");
201
202         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
203         g_return_if_fail (new_lbc && GL_IS_LABEL_BARCODE (new_lbc));
204
205         text_node = gl_label_barcode_get_data (lbc);
206         gl_label_barcode_get_props (lbc, &backend_id, &id, &text_flag, &checksum_flag, &format_digits);
207         color_node = get_line_color (src_object);
208
209         gl_label_barcode_set_data (new_lbc, text_node, FALSE);
210         gl_label_barcode_set_props (new_lbc, backend_id, id, text_flag, checksum_flag, format_digits, FALSE);
211         set_line_color (dst_object, color_node, FALSE);
212
213         gl_color_node_free (&color_node);
214         gl_text_node_free (&text_node);
215         g_free (backend_id);
216         g_free (id);
217
218         gl_debug (DEBUG_LABEL, "END");
219 }
220
221
222 /*****************************************************************************/
223 /* Set object params.                                                        */
224 /*****************************************************************************/
225 void
226 gl_label_barcode_set_data (glLabelBarcode *lbc,
227                            glTextNode     *text_node,
228                            gboolean        checkpoint)
229 {
230         glLabel *label;
231
232         gl_debug (DEBUG_LABEL, "START");
233
234         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
235
236         if (!gl_text_node_equal (lbc->priv->text_node, text_node))
237         {
238                 if ( checkpoint )
239                 {
240                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
241                         gl_label_checkpoint (label, _("Barcode data"));
242                 }
243                 
244                 gl_text_node_free (&lbc->priv->text_node);
245                 lbc->priv->text_node = gl_text_node_dup (text_node);
246
247                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
248         }
249
250         gl_debug (DEBUG_LABEL, "END");
251 }
252
253
254 void
255 gl_label_barcode_set_props (glLabelBarcode *lbc,
256                             gchar          *backend_id,
257                             gchar          *id,
258                             gboolean        text_flag,
259                             gboolean        checksum_flag,
260                             guint           format_digits,
261                             gboolean        checkpoint)
262 {
263         glLabel *label;
264
265         gl_debug (DEBUG_LABEL, "START");
266
267         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
268
269         if ( ((lbc->priv->backend_id == NULL) && (backend_id != NULL))
270              || ((lbc->priv->id == NULL) && (id != NULL))
271              || ((lbc->priv->backend_id != NULL) && (backend_id != NULL) && (g_ascii_strcasecmp (lbc->priv->backend_id, backend_id) != 0))
272              || ((lbc->priv->id != NULL) && (id != NULL) && (g_ascii_strcasecmp (lbc->priv->id, id) != 0))
273              || (lbc->priv->text_flag != text_flag)
274              || (lbc->priv->checksum_flag != checksum_flag)
275              || (lbc->priv->format_digits != format_digits))
276         {
277                 if ( checkpoint )
278                 {
279                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
280                         gl_label_checkpoint (label, _("Barcode property"));
281                 }
282
283                 lbc->priv->backend_id       = g_strdup (backend_id);
284                 lbc->priv->id               = g_strdup (id);
285                 lbc->priv->text_flag        = text_flag;
286                 lbc->priv->checksum_flag    = checksum_flag;
287                 lbc->priv->format_digits    = format_digits;
288
289                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
290         }
291
292         gl_debug (DEBUG_LABEL, "END");
293 }
294
295
296 /*****************************************************************************/
297 /* Get object params.                                                        */
298 /*****************************************************************************/
299 glTextNode *
300 gl_label_barcode_get_data (glLabelBarcode *lbc)
301 {
302         g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
303
304         return gl_text_node_dup (lbc->priv->text_node);
305 }
306
307
308 void
309 gl_label_barcode_get_props (glLabelBarcode *lbc,
310                             gchar          **backend_id,
311                             gchar          **id,
312                             gboolean       *text_flag,
313                             gboolean       *checksum_flag,
314                             guint          *format_digits)
315 {
316         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
317
318         *backend_id       = g_strdup (lbc->priv->backend_id);
319         *id               = g_strdup (lbc->priv->id);
320         *text_flag        = lbc->priv->text_flag;
321         *checksum_flag    = lbc->priv->checksum_flag;
322         *format_digits    = lbc->priv->format_digits;
323 }
324
325
326 /*---------------------------------------------------------------------------*/
327 /* PRIVATE.  Get object size method.                                         */
328 /*---------------------------------------------------------------------------*/
329 static void
330 get_size (glLabelObject *object,
331           gdouble       *w,
332           gdouble       *h)
333 {
334         glLabelBarcode      *lbc = (glLabelBarcode *)object;
335         gchar               *data;
336         gdouble              w_parent, h_parent;
337         glBarcode           *gbc;
338
339         gl_debug (DEBUG_LABEL, "START");
340
341         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
342
343         gl_label_object_get_raw_size (object, &w_parent, &h_parent);
344
345         if (lbc->priv->text_node->field_flag) {
346                 data = gl_barcode_backends_style_default_digits (lbc->priv->backend_id,
347                                                                  lbc->priv->id,
348                                                                  lbc->priv->format_digits);
349         } else {
350                 data = gl_text_node_expand (lbc->priv->text_node, NULL);
351         }
352
353         gbc = gl_barcode_backends_new_barcode (lbc->priv->backend_id,
354                                                lbc->priv->id,
355                                                lbc->priv->text_flag,
356                                                lbc->priv->checksum_flag,
357                                                w_parent,
358                                                h_parent,
359                                                data);
360         g_free (data);
361
362         if ( gbc == NULL ) {
363                 /* Try again with default digits. */
364                 data = gl_barcode_backends_style_default_digits (lbc->priv->backend_id,
365                                                                  lbc->priv->id,
366                                                                  lbc->priv->format_digits);
367                 gbc = gl_barcode_backends_new_barcode (lbc->priv->backend_id,
368                                                        lbc->priv->id,
369                                                        lbc->priv->text_flag,
370                                                        lbc->priv->checksum_flag,
371                                                        w_parent,
372                                                        h_parent,
373                                                        data);
374                 g_free (data);
375         }
376
377         if ( gbc != NULL )
378         {
379                 *w = gbc->width;
380                 *h = gbc->height;
381         }
382         else
383         {
384                 /* If we still can't render, just set a default size. */
385                 *w = 144;
386                 *h = 72;
387         }
388
389         gl_barcode_free (&gbc);
390
391         gl_debug (DEBUG_LABEL, "END");
392 }
393
394
395 /*---------------------------------------------------------------------------*/
396 /* PRIVATE.  Set line color method.                                          */
397 /*---------------------------------------------------------------------------*/
398 static void
399 set_line_color (glLabelObject *object,
400                 glColorNode   *line_color_node,
401                 gboolean       checkpoint)
402 {
403         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
404         glLabel        *label;
405
406         g_return_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode));
407
408         if ( !gl_color_node_equal(lbarcode->priv->color_node, line_color_node) )
409         {
410                 if ( checkpoint )
411                 {
412                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbarcode));
413                         gl_label_checkpoint (label, _("Barcode data"));
414                 }
415
416                 gl_color_node_free (&(lbarcode->priv->color_node));
417                 lbarcode->priv->color_node = gl_color_node_dup (line_color_node);
418                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbarcode));
419         }
420 }
421
422
423 /*---------------------------------------------------------------------------*/
424 /* PRIVATE.  Get line color method.                                          */
425 /*---------------------------------------------------------------------------*/
426 static glColorNode*
427 get_line_color (glLabelObject *object)
428 {
429         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
430
431         g_return_val_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode), NULL);
432
433         return gl_color_node_dup (lbarcode->priv->color_node);
434 }
435
436
437 /*****************************************************************************/
438 /* Draw object method.                                                       */
439 /*****************************************************************************/
440 static void
441 draw_object (glLabelObject *object,
442              cairo_t       *cr,
443              gboolean       screen_flag,
444              glMergeRecord *record)
445 {
446         gdouble               x0, y0;
447         cairo_matrix_t        matrix;
448         glBarcode            *gbc;
449         glBarcodeShape       *shape;
450         glBarcodeShapeLine   *line;
451         glBarcodeShapeBox    *box;
452         glBarcodeShapeRing   *ring;
453         glBarcodeShapeHexagon *hexagon;
454         glBarcodeShapeChar   *bchar;
455         glBarcodeShapeString *bstring;
456         GList                *p;
457         gdouble               x_offset, y_offset;
458         PangoLayout          *layout;
459         PangoFontDescription *desc;
460         gchar                *text, *cstring;
461         glTextNode           *text_node;
462         gchar                *backend_id;
463         gchar                *id;
464         gboolean              text_flag;
465         gboolean              checksum_flag;
466         guint                 color;
467         glColorNode          *color_node;
468         guint                 format_digits;
469         gdouble               w, h;
470         gint                  iw, ih;
471         gdouble               layout_width;
472
473         gl_debug (DEBUG_LABEL, "START");
474
475         gl_label_object_get_position (object, &x0, &y0);
476         gl_label_object_get_matrix (object, &matrix);
477
478         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
479         gl_label_barcode_get_props (GL_LABEL_BARCODE (object),
480                                     &backend_id, &id, &text_flag, &checksum_flag, &format_digits);
481
482         color_node = gl_label_object_get_line_color (object);
483         color = gl_color_node_expand (color_node, record);
484         if (color_node->field_flag && screen_flag)
485         {
486                 color = GL_COLOR_MERGE_DEFAULT;
487         }
488         gl_color_node_free (&color_node);
489
490         gl_label_object_get_size (object, &w, &h);
491
492         text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
493         text = gl_text_node_expand (text_node, record);
494         if (text_node->field_flag && screen_flag) {
495                 text = gl_barcode_backends_style_default_digits (backend_id, id, format_digits);
496         }
497
498         gbc = gl_barcode_backends_new_barcode (backend_id, id, text_flag, checksum_flag, w, h, text);
499
500         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
501
502         if (gbc == NULL) {
503
504                 layout = pango_cairo_create_layout (cr);
505
506                 desc = pango_font_description_new ();
507                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
508                 pango_font_description_set_size   (desc, 12 * PANGO_SCALE * FONT_SCALE);
509                 pango_layout_set_font_description (layout, desc);
510                 pango_font_description_free       (desc);
511
512                 if (text == NULL || *text == '\0')
513                 {
514                         pango_layout_set_text (layout, _("Barcode data empty"), -1);
515                 }
516                 else
517                 {
518                         pango_layout_set_text (layout, _("Invalid barcode data"), -1);
519                 }
520
521                 cairo_move_to (cr, 0, 0);
522                 pango_cairo_show_layout (cr, layout);
523
524                 g_object_unref (layout);
525
526         } else {
527
528                 for (p = gbc->shapes; p != NULL; p = p->next) {
529                         shape = (glBarcodeShape *)p->data;
530                         switch (shape->type)
531                         {
532
533                         case GL_BARCODE_SHAPE_LINE:
534                                 line = (glBarcodeShapeLine *) shape;
535
536                                 cairo_move_to (cr, line->x, line->y);
537                                 cairo_line_to (cr, line->x, line->y + line->length);
538                                 cairo_set_line_width (cr, line->width);
539                                 cairo_stroke (cr);
540
541                                 break;
542
543                         case GL_BARCODE_SHAPE_BOX:
544                                 box = (glBarcodeShapeBox *) shape;
545
546                                 cairo_rectangle (cr, box->x, box->y, box->width, box->height);
547                                 cairo_fill (cr);
548
549                                 break;
550
551                         case GL_BARCODE_SHAPE_CHAR:
552                                 bchar = (glBarcodeShapeChar *) shape;
553
554                                 layout = pango_cairo_create_layout (cr);
555
556                                 desc = pango_font_description_new ();
557                                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
558                                 pango_font_description_set_size   (desc, bchar->fsize * PANGO_SCALE * FONT_SCALE);
559                                 pango_layout_set_font_description (layout, desc);
560                                 pango_font_description_free       (desc);
561
562                                 cstring = g_strdup_printf ("%c", bchar->c);
563                                 pango_layout_set_text (layout, cstring, -1);
564                                 g_free (cstring);
565
566                                 y_offset = 0.2 * bchar->fsize;
567
568                                 cairo_move_to (cr, bchar->x, bchar->y-y_offset);
569                                 pango_cairo_show_layout (cr, layout);
570
571                                 g_object_unref (layout);
572
573                                 break;
574
575                         case GL_BARCODE_SHAPE_STRING:
576                                 bstring = (glBarcodeShapeString *) shape;
577
578                                 layout = pango_cairo_create_layout (cr);
579
580                                 desc = pango_font_description_new ();
581                                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
582                                 pango_font_description_set_size   (desc, bstring->fsize * PANGO_SCALE * FONT_SCALE);
583                                 pango_layout_set_font_description (layout, desc);
584                                 pango_font_description_free       (desc);
585
586                                 pango_layout_set_text (layout, bstring->string, -1);
587
588                                 pango_layout_get_size (layout, &iw, &ih);
589                                 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
590
591                                 x_offset = layout_width / 2.0;
592                                 y_offset = 0.2 * bstring->fsize;
593
594                                 cairo_move_to (cr, (bstring->x - x_offset), (bstring->y - y_offset));
595                                 pango_cairo_show_layout (cr, layout);
596
597                                 g_object_unref (layout);
598
599                                 break;
600
601                         case GL_BARCODE_SHAPE_RING:
602                                 ring = (glBarcodeShapeRing *) shape;
603
604                                 cairo_arc (cr, ring->x, ring->y, ring->radius, 0.0, 2 * PI);
605                                 cairo_set_line_width (cr, ring->line_width);
606                                 cairo_stroke (cr);
607
608                                 break;
609
610                         case GL_BARCODE_SHAPE_HEXAGON:
611                                 hexagon = (glBarcodeShapeHexagon *) shape;
612
613                                 cairo_move_to (cr, hexagon->x, hexagon->y);
614                                 cairo_line_to (cr, hexagon->x + 1.25, hexagon->y + 0.70);
615                                 cairo_line_to (cr, hexagon->x + 1.25, hexagon->y + 2.18);
616                                 cairo_line_to (cr, hexagon->x, hexagon->y + 2.89);
617                                 cairo_line_to (cr, hexagon->x - 1.25, hexagon->y + 2.18);
618                                 cairo_line_to (cr, hexagon->x - 1.25, hexagon->y + 0.70);
619                                 cairo_close_path (cr);
620                                 cairo_fill (cr);
621
622                                 break;
623
624                         default:
625                                 g_assert_not_reached ();
626                                 break;
627
628                         }
629
630                 }
631
632                 gl_barcode_free (&gbc);
633
634         }
635
636         g_free (text);
637         gl_text_node_free (&text_node);
638         g_free (backend_id);
639         g_free (id);
640
641         gl_debug (DEBUG_LABEL, "END");
642 }
643
644
645 /*****************************************************************************/
646 /* Is object at coordinates?                                                 */
647 /*****************************************************************************/
648 static gboolean
649 object_at (glLabelObject *object,
650            cairo_t       *cr,
651            gdouble        x,
652            gdouble        y)
653 {
654         gdouble           w, h;
655
656         gl_label_object_get_size (object, &w, &h);
657
658         cairo_new_path (cr);
659         cairo_rectangle (cr, 0.0, 0.0, w, h);
660
661         if (cairo_in_fill (cr, x, y))
662         {
663                 return TRUE;
664         }
665
666         return FALSE;
667 }
668
669
670
671
672 /*
673  * Local Variables:       -- emacs
674  * mode: C                -- emacs
675  * c-basic-offset: 8      -- emacs
676  * tab-width: 8           -- emacs
677  * indent-tabs-mode: nil  -- emacs
678  * End:                   -- emacs
679  */