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