3 * Copyright (C) 2001-2009 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
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.
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.
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/>.
23 #include "label-barcode.h"
26 #include <glib/gi18n.h>
27 #include <pango/pangocairo.h>
28 #include "bc-backends.h"
32 /*========================================================*/
33 /* Private macros and constants. */
34 /*========================================================*/
36 #define FONT_SCALE (72.0/96.0)
37 #define PI 3.141592654
40 /*========================================================*/
42 /*========================================================*/
44 struct _glLabelBarcodePrivate {
46 glTextNode *text_node;
47 glLabelBarcodeStyle *style;
48 glColorNode *color_node;
53 /*========================================================*/
54 /* Private globals. */
55 /*========================================================*/
58 /*========================================================*/
59 /* Private function prototypes. */
60 /*========================================================*/
62 static void gl_label_barcode_finalize (GObject *object);
64 static void copy (glLabelObject *dst_object,
65 glLabelObject *src_object);
67 static void get_size (glLabelObject *object,
71 static void set_line_color (glLabelObject *object,
72 glColorNode *line_color,
75 static glColorNode *get_line_color (glLabelObject *object);
77 static void draw_object (glLabelObject *object,
80 glMergeRecord *record);
82 static gboolean object_at (glLabelObject *object,
88 /*****************************************************************************/
89 /* Boilerplate object stuff. */
90 /*****************************************************************************/
91 G_DEFINE_TYPE (glLabelBarcode, gl_label_barcode, GL_TYPE_LABEL_OBJECT);
95 gl_label_barcode_class_init (glLabelBarcodeClass *class)
97 GObjectClass *object_class = G_OBJECT_CLASS (class);
98 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
100 gl_label_barcode_parent_class = g_type_class_peek_parent (class);
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;
110 object_class->finalize = gl_label_barcode_finalize;
115 gl_label_barcode_init (glLabelBarcode *lbc)
117 lbc->priv = g_new0 (glLabelBarcodePrivate, 1);
118 lbc->priv->text_node = gl_text_node_new_from_text ("");
123 gl_label_barcode_finalize (GObject *object)
125 glLabelBarcode *lbc = GL_LABEL_BARCODE (object);
127 g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
129 gl_text_node_free (&lbc->priv->text_node);
130 gl_label_barcode_style_free (lbc->priv->style);
131 gl_color_node_free (&(lbc->priv->color_node));
134 G_OBJECT_CLASS (gl_label_barcode_parent_class)->finalize (object);
138 /*****************************************************************************/
139 /* NEW label "barcode" object. */
140 /*****************************************************************************/
142 gl_label_barcode_new (glLabel *label,
146 glLabelBarcodeStyle *style;
147 glColorNode *line_color_node;
149 lbc = g_object_new (gl_label_barcode_get_type(), NULL);
155 gl_label_checkpoint (label, _("Create barcode object"));
158 /* Default barcode style and properties. */
159 style = gl_label_barcode_style_new ();
160 gl_label_barcode_style_set_backend_id (style, gl_barcode_backends_backend_name_to_id (NULL));
161 gl_label_barcode_style_set_style_id (style, gl_barcode_backends_style_name_to_id (style->backend_id, NULL));
162 style->text_flag = gl_barcode_backends_style_can_text (style->backend_id, style->id);
163 style->checksum_flag = gl_barcode_backends_style_can_csum (style->backend_id, style->id);
164 style->format_digits = gl_barcode_backends_style_get_prefered_n (style->backend_id, style->id);
165 lbc->priv->style = style;
167 line_color_node = gl_color_node_new_default ();
168 line_color_node->color = gl_label_get_default_line_color(label);
169 lbc->priv->color_node = line_color_node;
171 gl_label_add_object (label, GL_LABEL_OBJECT (lbc));
172 gl_label_object_set_parent (GL_LABEL_OBJECT (lbc), label);
175 return G_OBJECT (lbc);
179 /*****************************************************************************/
180 /* Copy object contents. */
181 /*****************************************************************************/
183 copy (glLabelObject *dst_object,
184 glLabelObject *src_object)
186 glLabelBarcode *lbc = (glLabelBarcode *)src_object;
187 glLabelBarcode *new_lbc = (glLabelBarcode *)dst_object;
188 glTextNode *text_node;
189 glLabelBarcodeStyle *style;
190 glColorNode *color_node;
192 gl_debug (DEBUG_LABEL, "START");
194 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
195 g_return_if_fail (new_lbc && GL_IS_LABEL_BARCODE (new_lbc));
197 text_node = gl_label_barcode_get_data (lbc);
198 style = gl_label_barcode_get_style (lbc);
199 color_node = get_line_color (src_object);
201 gl_label_barcode_set_data (new_lbc, text_node, FALSE);
202 gl_label_barcode_set_style (new_lbc, style, FALSE);
203 set_line_color (dst_object, color_node, FALSE);
205 gl_color_node_free (&color_node);
206 gl_text_node_free (&text_node);
208 gl_debug (DEBUG_LABEL, "END");
212 /*****************************************************************************/
213 /* Set object params. */
214 /*****************************************************************************/
216 gl_label_barcode_set_data (glLabelBarcode *lbc,
217 const glTextNode *text_node,
222 gl_debug (DEBUG_LABEL, "START");
224 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
226 if (!gl_text_node_equal (lbc->priv->text_node, text_node))
230 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
231 gl_label_checkpoint (label, _("Barcode data"));
234 gl_text_node_free (&lbc->priv->text_node);
235 lbc->priv->text_node = gl_text_node_dup (text_node);
237 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
240 gl_debug (DEBUG_LABEL, "END");
245 gl_label_barcode_set_style (glLabelBarcode *lbc,
246 const glLabelBarcodeStyle *style,
251 gl_debug (DEBUG_LABEL, "START");
253 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
255 if ( !gl_label_barcode_style_is_equal (style, lbc->priv->style) )
259 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
260 gl_label_checkpoint (label, _("Barcode property"));
263 gl_label_barcode_style_free (lbc->priv->style);
264 lbc->priv->style = gl_label_barcode_style_dup (style);
266 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
269 gl_debug (DEBUG_LABEL, "END");
273 /*****************************************************************************/
274 /* Get object params. */
275 /*****************************************************************************/
277 gl_label_barcode_get_data (glLabelBarcode *lbc)
279 g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
281 return gl_text_node_dup (lbc->priv->text_node);
285 glLabelBarcodeStyle *
286 gl_label_barcode_get_style (glLabelBarcode *lbc)
288 g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
290 return gl_label_barcode_style_dup (lbc->priv->style);
294 /*---------------------------------------------------------------------------*/
295 /* PRIVATE. Get object size method. */
296 /*---------------------------------------------------------------------------*/
298 get_size (glLabelObject *object,
302 glLabelBarcode *lbc = (glLabelBarcode *)object;
304 gdouble w_parent, h_parent;
307 gl_debug (DEBUG_LABEL, "START");
309 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
311 gl_label_object_get_raw_size (object, &w_parent, &h_parent);
313 if (lbc->priv->text_node->field_flag) {
314 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
315 lbc->priv->style->id,
316 lbc->priv->style->format_digits);
318 data = gl_text_node_expand (lbc->priv->text_node, NULL);
321 gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
322 lbc->priv->style->id,
323 lbc->priv->style->text_flag,
324 lbc->priv->style->checksum_flag,
331 /* Try again with default digits. */
332 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
333 lbc->priv->style->id,
334 lbc->priv->style->format_digits);
335 gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
336 lbc->priv->style->id,
337 lbc->priv->style->text_flag,
338 lbc->priv->style->checksum_flag,
352 /* If we still can't render, just set a default size. */
357 gl_barcode_free (&gbc);
359 gl_debug (DEBUG_LABEL, "END");
363 /*---------------------------------------------------------------------------*/
364 /* PRIVATE. Set line color method. */
365 /*---------------------------------------------------------------------------*/
367 set_line_color (glLabelObject *object,
368 glColorNode *line_color_node,
371 glLabelBarcode *lbarcode = (glLabelBarcode *)object;
374 g_return_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode));
376 if ( !gl_color_node_equal(lbarcode->priv->color_node, line_color_node) )
380 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbarcode));
381 gl_label_checkpoint (label, _("Barcode data"));
384 gl_color_node_free (&(lbarcode->priv->color_node));
385 lbarcode->priv->color_node = gl_color_node_dup (line_color_node);
386 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbarcode));
391 /*---------------------------------------------------------------------------*/
392 /* PRIVATE. Get line color method. */
393 /*---------------------------------------------------------------------------*/
395 get_line_color (glLabelObject *object)
397 glLabelBarcode *lbarcode = (glLabelBarcode *)object;
399 g_return_val_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode), NULL);
401 return gl_color_node_dup (lbarcode->priv->color_node);
405 /*****************************************************************************/
406 /* Draw object method. */
407 /*****************************************************************************/
409 draw_object (glLabelObject *object,
411 gboolean screen_flag,
412 glMergeRecord *record)
415 cairo_matrix_t matrix;
417 glBarcodeShape *shape;
418 glBarcodeShapeLine *line;
419 glBarcodeShapeBox *box;
420 glBarcodeShapeRing *ring;
421 glBarcodeShapeHexagon *hexagon;
422 glBarcodeShapeChar *bchar;
423 glBarcodeShapeString *bstring;
425 gdouble x_offset, y_offset;
427 PangoFontDescription *desc;
428 gchar *text, *cstring;
429 glTextNode *text_node;
430 glLabelBarcodeStyle *style;
432 glColorNode *color_node;
435 gdouble layout_width;
437 gl_debug (DEBUG_LABEL, "START");
439 gl_label_object_get_position (object, &x0, &y0);
440 gl_label_object_get_matrix (object, &matrix);
442 text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
443 style = gl_label_barcode_get_style (GL_LABEL_BARCODE (object));
445 color_node = gl_label_object_get_line_color (object);
446 color = gl_color_node_expand (color_node, record);
447 if (color_node->field_flag && screen_flag)
449 color = GL_COLOR_MERGE_DEFAULT;
452 gl_label_object_get_size (object, &w, &h);
454 text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
455 text = gl_text_node_expand (text_node, record);
456 if (text_node->field_flag && screen_flag) {
457 text = gl_barcode_backends_style_default_digits (style->backend_id, style->id, style->format_digits);
460 gbc = gl_barcode_backends_new_barcode (style->backend_id, style->id, style->text_flag, style->checksum_flag, w, h, text);
462 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
466 layout = pango_cairo_create_layout (cr);
468 desc = pango_font_description_new ();
469 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
470 pango_font_description_set_size (desc, 12 * PANGO_SCALE * FONT_SCALE);
471 pango_layout_set_font_description (layout, desc);
472 pango_font_description_free (desc);
474 if (text == NULL || *text == '\0')
476 pango_layout_set_text (layout, _("Barcode data empty"), -1);
480 pango_layout_set_text (layout, _("Invalid barcode data"), -1);
483 cairo_move_to (cr, 0, 0);
484 pango_cairo_show_layout (cr, layout);
486 g_object_unref (layout);
490 for (p = gbc->shapes; p != NULL; p = p->next) {
491 shape = (glBarcodeShape *)p->data;
495 case GL_BARCODE_SHAPE_LINE:
496 line = (glBarcodeShapeLine *) shape;
498 cairo_move_to (cr, line->x, line->y);
499 cairo_line_to (cr, line->x, line->y + line->length);
500 cairo_set_line_width (cr, line->width);
505 case GL_BARCODE_SHAPE_BOX:
506 box = (glBarcodeShapeBox *) shape;
508 cairo_rectangle (cr, box->x, box->y, box->width, box->height);
513 case GL_BARCODE_SHAPE_CHAR:
514 bchar = (glBarcodeShapeChar *) shape;
516 layout = pango_cairo_create_layout (cr);
518 desc = pango_font_description_new ();
519 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
520 pango_font_description_set_size (desc, bchar->fsize * PANGO_SCALE * FONT_SCALE);
521 pango_layout_set_font_description (layout, desc);
522 pango_font_description_free (desc);
524 cstring = g_strdup_printf ("%c", bchar->c);
525 pango_layout_set_text (layout, cstring, -1);
528 y_offset = 0.2 * bchar->fsize;
530 cairo_move_to (cr, bchar->x, bchar->y-y_offset);
531 pango_cairo_show_layout (cr, layout);
533 g_object_unref (layout);
537 case GL_BARCODE_SHAPE_STRING:
538 bstring = (glBarcodeShapeString *) shape;
540 layout = pango_cairo_create_layout (cr);
542 desc = pango_font_description_new ();
543 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
544 pango_font_description_set_size (desc, bstring->fsize * PANGO_SCALE * FONT_SCALE);
545 pango_layout_set_font_description (layout, desc);
546 pango_font_description_free (desc);
548 pango_layout_set_text (layout, bstring->string, -1);
550 pango_layout_get_size (layout, &iw, &ih);
551 layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
553 x_offset = layout_width / 2.0;
554 y_offset = 0.2 * bstring->fsize;
556 cairo_move_to (cr, (bstring->x - x_offset), (bstring->y - y_offset));
557 pango_cairo_show_layout (cr, layout);
559 g_object_unref (layout);
563 case GL_BARCODE_SHAPE_RING:
564 ring = (glBarcodeShapeRing *) shape;
566 cairo_arc (cr, ring->x, ring->y, ring->radius, 0.0, 2 * PI);
567 cairo_set_line_width (cr, ring->line_width);
572 case GL_BARCODE_SHAPE_HEXAGON:
573 hexagon = (glBarcodeShapeHexagon *) shape;
575 cairo_move_to (cr, hexagon->x, hexagon->y);
576 cairo_line_to (cr, hexagon->x + 1.25, hexagon->y + 0.70);
577 cairo_line_to (cr, hexagon->x + 1.25, hexagon->y + 2.18);
578 cairo_line_to (cr, hexagon->x, hexagon->y + 2.89);
579 cairo_line_to (cr, hexagon->x - 1.25, hexagon->y + 2.18);
580 cairo_line_to (cr, hexagon->x - 1.25, hexagon->y + 0.70);
581 cairo_close_path (cr);
587 g_assert_not_reached ();
594 gl_barcode_free (&gbc);
599 gl_text_node_free (&text_node);
600 gl_label_barcode_style_free (style);
601 gl_color_node_free (&color_node);
603 gl_debug (DEBUG_LABEL, "END");
607 /*****************************************************************************/
608 /* Is object at coordinates? */
609 /*****************************************************************************/
611 object_at (glLabelObject *object,
618 gl_label_object_get_size (object, &w, &h);
621 cairo_rectangle (cr, 0.0, 0.0, w, h);
623 if (cairo_in_fill (cr, x, y))
632 /*****************************************************************************/
633 /* Barcode style utilities. */
634 /*****************************************************************************/
635 glLabelBarcodeStyle *
636 gl_label_barcode_style_new (void)
638 return g_new0 (glLabelBarcodeStyle, 1);
642 glLabelBarcodeStyle *
643 gl_label_barcode_style_dup (const glLabelBarcodeStyle *style)
645 glLabelBarcodeStyle *style2;
647 style2 = gl_label_barcode_style_new ();
649 /* Shallow copy first. */
653 style2->backend_id = g_strdup (style->backend_id);
654 style2->id = g_strdup (style->id);
661 gl_label_barcode_style_free (glLabelBarcodeStyle *style)
665 g_free (style->backend_id);
674 gl_label_barcode_style_is_equal (const glLabelBarcodeStyle *style1,
675 const glLabelBarcodeStyle *style2)
678 /* First take care of the case of either or both being NULL. */
679 if ( style1 == NULL )
681 return ( style2 == NULL );
685 if ( style2 == NULL )
691 /* Compare field by field, bail on first difference. */
692 if ( style1->text_flag != style2->text_flag )
696 if ( style1->checksum_flag != style2->checksum_flag )
700 if ( style1->format_digits != style2->format_digits )
704 if ( style1->backend_id && style2->backend_id )
706 if ( strcmp (style1->backend_id, style2->backend_id) != 0 )
713 if ( style1->backend_id != style2->backend_id )
718 if ( style1->id && style2->id )
720 if ( strcmp (style1->id, style2->id) != 0 )
727 if ( style1->id != style2->id )
733 /* Passed all tests. */
739 gl_label_barcode_style_set_backend_id (glLabelBarcodeStyle *style,
740 const gchar *backend_id)
742 style->backend_id = g_strdup (backend_id);
747 gl_label_barcode_style_set_style_id (glLabelBarcodeStyle *style,
750 style->id = g_strdup (id);
758 * Local Variables: -- emacs
760 * c-basic-offset: 8 -- emacs
761 * tab-width: 8 -- emacs
762 * indent-tabs-mode: nil -- emacs