]> git.sur5r.net Git - glabels/blob - src/label-barcode.c
Refactored core barcode subsystem.
[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 #define GL_BARCODE_FONT_FAMILY      "Sans"
40
41
42 /*========================================================*/
43 /* Private types.                                         */
44 /*========================================================*/
45
46 struct _glLabelBarcodePrivate {
47
48         glTextNode          *text_node;
49         glLabelBarcodeStyle *style;
50         glColorNode         *color_node;
51
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         gl_label_barcode_style_free (lbc->priv->style);
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         glLabelBarcodeStyle *style;
149         glColorNode         *line_color_node;
150
151         lbc = g_object_new (gl_label_barcode_get_type(), NULL);
152
153         if (label != NULL)
154         {
155                 if ( checkpoint )
156                 {
157                         gl_label_checkpoint (label, _("Create barcode object"));
158                 }
159
160                 /* Default barcode style and properties. */
161                 style = gl_label_barcode_style_new ();
162                 gl_label_barcode_style_set_backend_id (style, gl_barcode_backends_backend_name_to_id (NULL));
163                 gl_label_barcode_style_set_style_id (style, gl_barcode_backends_style_name_to_id (style->backend_id, NULL));
164                 style->text_flag     = gl_barcode_backends_style_can_text (style->backend_id, style->id);
165                 style->checksum_flag = gl_barcode_backends_style_can_csum (style->backend_id, style->id);
166                 style->format_digits = gl_barcode_backends_style_get_prefered_n (style->backend_id, style->id);
167                 lbc->priv->style = style;
168
169                 line_color_node = gl_color_node_new_default ();
170                 line_color_node->color = gl_label_get_default_line_color(label);
171                 lbc->priv->color_node = line_color_node;
172
173                 gl_label_add_object (label, GL_LABEL_OBJECT (lbc));
174                 gl_label_object_set_parent (GL_LABEL_OBJECT (lbc), label);
175         }
176
177         return G_OBJECT (lbc);
178 }
179
180
181 /*****************************************************************************/
182 /* Copy object contents.                                                     */
183 /*****************************************************************************/
184 static void
185 copy (glLabelObject *dst_object,
186       glLabelObject *src_object)
187 {
188         glLabelBarcode      *lbc     = (glLabelBarcode *)src_object;
189         glLabelBarcode      *new_lbc = (glLabelBarcode *)dst_object;
190         glTextNode          *text_node;
191         glLabelBarcodeStyle *style;
192         glColorNode         *color_node;
193
194         gl_debug (DEBUG_LABEL, "START");
195
196         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
197         g_return_if_fail (new_lbc && GL_IS_LABEL_BARCODE (new_lbc));
198
199         text_node = gl_label_barcode_get_data (lbc);
200         style = gl_label_barcode_get_style (lbc);
201         color_node = get_line_color (src_object);
202
203         gl_label_barcode_set_data (new_lbc, text_node, FALSE);
204         gl_label_barcode_set_style (new_lbc, style, FALSE);
205         set_line_color (dst_object, color_node, FALSE);
206
207         gl_color_node_free (&color_node);
208         gl_text_node_free (&text_node);
209
210         gl_debug (DEBUG_LABEL, "END");
211 }
212
213
214 /*****************************************************************************/
215 /* Set object params.                                                        */
216 /*****************************************************************************/
217 void
218 gl_label_barcode_set_data (glLabelBarcode   *lbc,
219                            const glTextNode *text_node,
220                            gboolean          checkpoint)
221 {
222         glLabel *label;
223
224         gl_debug (DEBUG_LABEL, "START");
225
226         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
227
228         if (!gl_text_node_equal (lbc->priv->text_node, text_node))
229         {
230                 if ( checkpoint )
231                 {
232                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
233                         gl_label_checkpoint (label, _("Barcode data"));
234                 }
235                 
236                 gl_text_node_free (&lbc->priv->text_node);
237                 lbc->priv->text_node = gl_text_node_dup (text_node);
238
239                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
240         }
241
242         gl_debug (DEBUG_LABEL, "END");
243 }
244
245
246 void
247 gl_label_barcode_set_style (glLabelBarcode            *lbc,
248                             const glLabelBarcodeStyle *style,
249                             gboolean                   checkpoint)
250 {
251         glLabel *label;
252
253         gl_debug (DEBUG_LABEL, "START");
254
255         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
256
257         if ( !gl_label_barcode_style_is_equal (style, lbc->priv->style) )
258         {
259                 if ( checkpoint )
260                 {
261                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
262                         gl_label_checkpoint (label, _("Barcode property"));
263                 }
264
265                 gl_label_barcode_style_free (lbc->priv->style);
266                 lbc->priv->style = gl_label_barcode_style_dup (style);
267
268                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
269         }
270
271         gl_debug (DEBUG_LABEL, "END");
272 }
273
274
275 /*****************************************************************************/
276 /* Get object params.                                                        */
277 /*****************************************************************************/
278 glTextNode *
279 gl_label_barcode_get_data (glLabelBarcode *lbc)
280 {
281         g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
282
283         return gl_text_node_dup (lbc->priv->text_node);
284 }
285
286
287 glLabelBarcodeStyle *
288 gl_label_barcode_get_style (glLabelBarcode *lbc)
289 {
290         g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
291
292         return gl_label_barcode_style_dup (lbc->priv->style);
293 }
294
295
296 /*---------------------------------------------------------------------------*/
297 /* PRIVATE.  Get object size method.                                         */
298 /*---------------------------------------------------------------------------*/
299 static void
300 get_size (glLabelObject *object,
301           gdouble       *w,
302           gdouble       *h)
303 {
304         glLabelBarcode      *lbc = (glLabelBarcode *)object;
305         gchar               *data;
306         gdouble              w_parent, h_parent;
307         lglBarcode          *gbc;
308
309         gl_debug (DEBUG_LABEL, "START");
310
311         g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
312
313         gl_label_object_get_raw_size (object, &w_parent, &h_parent);
314
315         if (lbc->priv->text_node->field_flag) {
316                 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
317                                                                  lbc->priv->style->id,
318                                                                  lbc->priv->style->format_digits);
319         } else {
320                 data = gl_text_node_expand (lbc->priv->text_node, NULL);
321         }
322
323         gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
324                                                lbc->priv->style->id,
325                                                lbc->priv->style->text_flag,
326                                                lbc->priv->style->checksum_flag,
327                                                w_parent,
328                                                h_parent,
329                                                data);
330         g_free (data);
331
332         if ( gbc == NULL ) {
333                 /* Try again with default digits. */
334                 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
335                                                                  lbc->priv->style->id,
336                                                                  lbc->priv->style->format_digits);
337                 gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
338                                                        lbc->priv->style->id,
339                                                        lbc->priv->style->text_flag,
340                                                        lbc->priv->style->checksum_flag,
341                                                        w_parent,
342                                                        h_parent,
343                                                        data);
344                 g_free (data);
345         }
346
347         if ( gbc != NULL )
348         {
349                 *w = gbc->width;
350                 *h = gbc->height;
351         }
352         else
353         {
354                 /* If we still can't render, just set a default size. */
355                 *w = 144;
356                 *h = 72;
357         }
358
359         lgl_barcode_free (gbc);
360
361         gl_debug (DEBUG_LABEL, "END");
362 }
363
364
365 /*---------------------------------------------------------------------------*/
366 /* PRIVATE.  Set line color method.                                          */
367 /*---------------------------------------------------------------------------*/
368 static void
369 set_line_color (glLabelObject *object,
370                 glColorNode   *line_color_node,
371                 gboolean       checkpoint)
372 {
373         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
374         glLabel        *label;
375
376         g_return_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode));
377
378         if ( !gl_color_node_equal(lbarcode->priv->color_node, line_color_node) )
379         {
380                 if ( checkpoint )
381                 {
382                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbarcode));
383                         gl_label_checkpoint (label, _("Barcode data"));
384                 }
385
386                 gl_color_node_free (&(lbarcode->priv->color_node));
387                 lbarcode->priv->color_node = gl_color_node_dup (line_color_node);
388                 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbarcode));
389         }
390 }
391
392
393 /*---------------------------------------------------------------------------*/
394 /* PRIVATE.  Get line color method.                                          */
395 /*---------------------------------------------------------------------------*/
396 static glColorNode*
397 get_line_color (glLabelObject *object)
398 {
399         glLabelBarcode *lbarcode = (glLabelBarcode *)object;
400
401         g_return_val_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode), NULL);
402
403         return gl_color_node_dup (lbarcode->priv->color_node);
404 }
405
406
407 /*****************************************************************************/
408 /* Draw object method.                                                       */
409 /*****************************************************************************/
410 static void
411 draw_object (glLabelObject *object,
412              cairo_t       *cr,
413              gboolean       screen_flag,
414              glMergeRecord *record)
415 {
416         gdouble               x0, y0;
417         cairo_matrix_t        matrix;
418         lglBarcode           *gbc;
419         PangoLayout          *layout;
420         PangoFontDescription *desc;
421         gchar                *text;
422         glTextNode           *text_node;
423         glLabelBarcodeStyle  *style;
424         guint                 color;
425         glColorNode          *color_node;
426         gdouble               w, h;
427
428         gl_debug (DEBUG_LABEL, "START");
429
430         gl_label_object_get_position (object, &x0, &y0);
431         gl_label_object_get_matrix (object, &matrix);
432
433         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
434         style = gl_label_barcode_get_style (GL_LABEL_BARCODE (object));
435
436         color_node = gl_label_object_get_line_color (object);
437         color = gl_color_node_expand (color_node, record);
438         if (color_node->field_flag && screen_flag)
439         {
440                 color = GL_COLOR_MERGE_DEFAULT;
441         }
442
443         gl_label_object_get_size (object, &w, &h);
444
445         text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
446         text = gl_text_node_expand (text_node, record);
447         if (text_node->field_flag && screen_flag) {
448                 text = gl_barcode_backends_style_default_digits (style->backend_id, style->id, style->format_digits);
449         }
450
451         gbc = gl_barcode_backends_new_barcode (style->backend_id, style->id, style->text_flag, style->checksum_flag, w, h, text);
452
453         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
454
455         if (gbc == NULL) {
456
457                 layout = pango_cairo_create_layout (cr);
458
459                 desc = pango_font_description_new ();
460                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
461                 pango_font_description_set_size   (desc, 12 * PANGO_SCALE * FONT_SCALE);
462                 pango_layout_set_font_description (layout, desc);
463                 pango_font_description_free       (desc);
464
465                 if (text == NULL || *text == '\0')
466                 {
467                         pango_layout_set_text (layout, _("Barcode data empty"), -1);
468                 }
469                 else
470                 {
471                         pango_layout_set_text (layout, _("Invalid barcode data"), -1);
472                 }
473
474                 cairo_move_to (cr, 0, 0);
475                 pango_cairo_show_layout (cr, layout);
476
477                 g_object_unref (layout);
478
479         } else {
480
481                 lgl_barcode_render_to_cairo (gbc, cr);
482
483                 lgl_barcode_free (gbc);
484
485         }
486
487         g_free (text);
488         gl_text_node_free (&text_node);
489         gl_label_barcode_style_free (style);
490         gl_color_node_free (&color_node);
491
492         gl_debug (DEBUG_LABEL, "END");
493 }
494
495
496 /*****************************************************************************/
497 /* Is object at coordinates?                                                 */
498 /*****************************************************************************/
499 static gboolean
500 object_at (glLabelObject *object,
501            cairo_t       *cr,
502            gdouble        x,
503            gdouble        y)
504 {
505         gdouble           w, h;
506
507         gl_label_object_get_size (object, &w, &h);
508
509         cairo_new_path (cr);
510         cairo_rectangle (cr, 0.0, 0.0, w, h);
511
512         if (cairo_in_fill (cr, x, y))
513         {
514                 return TRUE;
515         }
516
517         return FALSE;
518 }
519
520
521 /*****************************************************************************/
522 /* Barcode style utilities.                                                  */
523 /*****************************************************************************/
524 glLabelBarcodeStyle *
525 gl_label_barcode_style_new (void)
526 {
527         return g_new0 (glLabelBarcodeStyle, 1);
528 }
529
530
531 glLabelBarcodeStyle *
532 gl_label_barcode_style_dup (const glLabelBarcodeStyle *style)
533 {
534         glLabelBarcodeStyle *style2;
535
536         style2 = gl_label_barcode_style_new ();
537
538         /* Shallow copy first. */
539         *style2 = *style;
540
541         /* Now go deep. */
542         style2->backend_id = g_strdup (style->backend_id);
543         style2->id         = g_strdup (style->id);
544
545         return style2;
546 }
547
548
549 void
550 gl_label_barcode_style_free (glLabelBarcodeStyle *style)
551 {
552         if ( style )
553         {
554                 g_free (style->backend_id);
555                 g_free (style->id);
556
557                 g_free (style);
558         }
559 }
560
561
562 gboolean
563 gl_label_barcode_style_is_equal (const glLabelBarcodeStyle *style1,
564                                  const glLabelBarcodeStyle *style2)
565 {
566
567         /* First take care of the case of either or both being NULL. */
568         if ( style1 == NULL )
569         {
570                 return ( style2 == NULL );
571         }
572         else
573         {
574                 if ( style2 == NULL )
575                 {
576                         return FALSE;
577                 }
578         }
579
580         /* Compare field by field, bail on first difference. */
581         if ( style1->text_flag != style2->text_flag )
582         {
583                 return FALSE;
584         }
585         if ( style1->checksum_flag != style2->checksum_flag )
586         {
587                 return FALSE;
588         }
589         if ( style1->format_digits != style2->format_digits )
590         {
591                 return FALSE;
592         }
593         if ( style1->backend_id && style2->backend_id )
594         {
595                 if ( strcmp (style1->backend_id, style2->backend_id) != 0 )
596                 {
597                         return FALSE;
598                 }
599         }
600         else
601         {
602                 if ( style1->backend_id != style2->backend_id )
603                 {
604                         return FALSE;
605                 }
606         }
607         if ( style1->id && style2->id )
608         {
609                 if ( strcmp (style1->id, style2->id) != 0 )
610                 {
611                         return FALSE;
612                 }
613         }
614         else
615         {
616                 if ( style1->id != style2->id )
617                 {
618                         return FALSE;
619                 }
620         }
621
622         /* Passed all tests. */
623         return TRUE;
624 }
625
626
627 void
628 gl_label_barcode_style_set_backend_id (glLabelBarcodeStyle *style,
629                                        const gchar         *backend_id)
630 {
631         style->backend_id = g_strdup (backend_id);
632 }
633
634
635 void
636 gl_label_barcode_style_set_style_id (glLabelBarcodeStyle *style,
637                                      const gchar         *id)
638 {
639         style->id = g_strdup (id);
640 }
641
642
643
644
645
646 /*
647  * Local Variables:       -- emacs
648  * mode: C                -- emacs
649  * c-basic-offset: 8      -- emacs
650  * tab-width: 8           -- emacs
651  * indent-tabs-mode: nil  -- emacs
652  * End:                   -- emacs
653  */