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