]> git.sur5r.net Git - glabels/blob - src/label-barcode.c
Add shadow property to image objects.
[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         glBarcodeShapeAlpha  *bchar;
428         GList                *p;
429         gdouble               y_offset;
430         PangoLayout          *layout;
431         PangoFontDescription *desc;
432         gchar                *text, *cstring;
433         glTextNode           *text_node;
434         gchar                *id;
435         gboolean              text_flag;
436         gboolean              checksum_flag;
437         guint                 color;
438         glColorNode          *color_node;
439         guint                 format_digits;
440         gdouble               w, h;
441
442         gl_debug (DEBUG_LABEL, "START");
443
444         gl_label_object_get_position (object, &x0, &y0);
445         gl_label_object_get_matrix (object, &matrix);
446
447         text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
448         gl_label_barcode_get_props (GL_LABEL_BARCODE (object),
449                                     &id, &text_flag, &checksum_flag, &format_digits);
450                                         
451         color_node = gl_label_object_get_line_color (object);
452         color = gl_color_node_expand (color_node, record);
453         if (color_node->field_flag && screen_flag)
454         {
455                 color = GL_COLOR_MERGE_DEFAULT;
456         }
457         gl_color_node_free (&color_node);
458         
459         gl_label_object_get_size (object, &w, &h);
460
461         text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
462         text = gl_text_node_expand (text_node, record);
463         if (text_node->field_flag && screen_flag) {
464                 text = gl_barcode_default_digits (id, format_digits);
465         }
466
467         gbc = gl_barcode_new (id, text_flag, checksum_flag, w, h, text);
468
469         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
470
471         if (gbc == NULL) {
472
473                 layout = pango_cairo_create_layout (cr);
474
475                 desc = pango_font_description_new ();
476                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
477                 pango_font_description_set_size   (desc, 12 * PANGO_SCALE * FONT_SCALE);
478                 pango_layout_set_font_description (layout, desc);
479                 pango_font_description_free       (desc);
480
481                 if (text == NULL || *text == '\0')
482                 {
483                         pango_layout_set_text (layout, _("Barcode data empty"), -1);
484                 }
485                 else
486                 {
487                         pango_layout_set_text (layout, _("Invalid barcode data"), -1);
488                 }
489
490                 cairo_move_to (cr, 0, 0);
491                 pango_cairo_show_layout (cr, layout);
492
493                 g_object_unref (layout);
494
495         } else {
496
497                 for (p = gbc->shapes; p != NULL; p = p->next) {
498                         shape = (glBarcodeShape *)p->data;
499                         switch (shape->type)
500                         {
501
502                         case GL_BARCODE_SHAPE_LINE:
503                                 line = (glBarcodeShapeLine *) shape;
504
505                                 cairo_move_to (cr, line->x, line->y);
506                                 cairo_line_to (cr, line->x, line->y + line->length);
507                                 cairo_set_line_width (cr, line->width);
508                                 cairo_stroke (cr);
509
510                                 break;
511
512                         case GL_BARCODE_SHAPE_ALPHA:
513                                 bchar = (glBarcodeShapeAlpha *) shape;
514
515                                 layout = pango_cairo_create_layout (cr);
516
517                                 desc = pango_font_description_new ();
518                                 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
519                                 pango_font_description_set_size   (desc, bchar->fsize * PANGO_SCALE * FONT_SCALE);
520                                 pango_layout_set_font_description (layout, desc);
521                                 pango_font_description_free       (desc);
522
523                                 cstring = g_strdup_printf ("%c", bchar->c);
524                                 pango_layout_set_text (layout, cstring, -1);
525                                 g_free (cstring);
526
527                                 y_offset = 0.2 * bchar->fsize;
528
529                                 cairo_move_to (cr, bchar->x, bchar->y-y_offset);
530                                 pango_cairo_show_layout (cr, layout);
531
532                                 g_object_unref (layout);
533
534                                 break;
535
536                         default:
537                                 g_assert_not_reached ();
538                                 break;
539
540                         }
541
542                 }
543
544                 gl_barcode_free (&gbc);
545
546         }
547
548         g_free (text);
549         gl_text_node_free (&text_node);
550         g_free (id);
551
552         gl_debug (DEBUG_LABEL, "END");
553 }
554
555
556 /*****************************************************************************/
557 /* Is object at coordinates?                                                 */
558 /*****************************************************************************/
559 static gboolean
560 object_at (glLabelObject *object,
561            cairo_t       *cr,
562            gdouble        x,
563            gdouble        y)
564 {
565         gdouble           w, h;
566
567         gl_label_object_get_size (object, &w, &h);
568
569         cairo_new_path (cr);
570         cairo_rectangle (cr, 0.0, 0.0, w, h);
571
572         if (cairo_in_fill (cr, x, y))
573         {
574                 return TRUE;
575         }
576
577         return FALSE;
578 }
579
580
581
582
583 /*
584  * Local Variables:       -- emacs
585  * mode: C                -- emacs
586  * c-basic-offset: 8      -- emacs
587  * tab-width: 8           -- emacs
588  * indent-tabs-mode: nil  -- emacs
589  * End:                   -- emacs
590  */