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
39 #define GL_BARCODE_FONT_FAMILY "Sans"
41 #define HANDLE_OUTLINE_RGBA_ARGS 0.5, 0.5, 0.5, 0.75
42 #define HANDLE_OUTLINE_WIDTH_PIXELS 2.0
44 #define SELECTION_SLOP_PIXELS 4.0
47 /*========================================================*/
49 /*========================================================*/
51 struct _glLabelBarcodePrivate {
53 glTextNode *text_node;
54 glLabelBarcodeStyle *style;
55 glColorNode *color_node;
57 /* Cached info. Only regenerate when text_node,
58 * style, or raw size changed */
59 lglBarcode *display_gbc;
65 /*========================================================*/
66 /* Private globals. */
67 /*========================================================*/
70 /*========================================================*/
71 /* Private function prototypes. */
72 /*========================================================*/
74 static void gl_label_barcode_finalize (GObject *object);
76 static void copy (glLabelObject *dst_object,
77 glLabelObject *src_object);
79 static void update_barcode (glLabelBarcode *lbc);
81 static void set_size (glLabelObject *object,
86 static void get_size (glLabelObject *object,
90 static void set_line_color (glLabelObject *object,
91 glColorNode *line_color,
94 static glColorNode *get_line_color (glLabelObject *object);
96 static void draw_object (glLabelObject *object,
99 glMergeRecord *record);
101 static gboolean object_at (glLabelObject *object,
106 static void draw_handles (glLabelObject *object,
109 static void create_alt_msg_path (cairo_t *cr,
113 /*****************************************************************************/
114 /* Boilerplate object stuff. */
115 /*****************************************************************************/
116 G_DEFINE_TYPE (glLabelBarcode, gl_label_barcode, GL_TYPE_LABEL_OBJECT)
120 gl_label_barcode_class_init (glLabelBarcodeClass *class)
122 GObjectClass *object_class = G_OBJECT_CLASS (class);
123 glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
125 gl_label_barcode_parent_class = g_type_class_peek_parent (class);
127 label_object_class->copy = copy;
128 label_object_class->set_size = set_size;
129 label_object_class->get_size = get_size;
130 label_object_class->set_line_color = set_line_color;
131 label_object_class->get_line_color = get_line_color;
132 label_object_class->draw_object = draw_object;
133 label_object_class->draw_shadow = NULL;
134 label_object_class->object_at = object_at;
135 label_object_class->draw_handles = draw_handles;
137 object_class->finalize = gl_label_barcode_finalize;
142 gl_label_barcode_init (glLabelBarcode *lbc)
144 lbc->priv = g_new0 (glLabelBarcodePrivate, 1);
145 lbc->priv->text_node = gl_text_node_new_from_text ("");
150 gl_label_barcode_finalize (GObject *object)
152 glLabelBarcode *lbc = GL_LABEL_BARCODE (object);
154 g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
156 gl_text_node_free (&lbc->priv->text_node);
157 gl_label_barcode_style_free (lbc->priv->style);
158 gl_color_node_free (&(lbc->priv->color_node));
159 lgl_barcode_free (lbc->priv->display_gbc);
162 G_OBJECT_CLASS (gl_label_barcode_parent_class)->finalize (object);
166 /*****************************************************************************/
167 /* NEW label "barcode" object. */
168 /*****************************************************************************/
170 gl_label_barcode_new (glLabel *label,
174 glLabelBarcodeStyle *style;
175 glColorNode *line_color_node;
177 lbc = g_object_new (gl_label_barcode_get_type(), NULL);
183 gl_label_checkpoint (label, _("Create barcode object"));
186 /* Default barcode style and properties. */
187 style = gl_label_barcode_style_new ();
188 gl_label_barcode_style_set_backend_id (style, gl_barcode_backends_backend_name_to_id (NULL));
189 gl_label_barcode_style_set_style_id (style, gl_barcode_backends_style_name_to_id (style->backend_id, NULL));
190 style->text_flag = gl_barcode_backends_style_can_text (style->backend_id, style->id);
191 style->checksum_flag = gl_barcode_backends_style_can_csum (style->backend_id, style->id);
192 style->format_digits = gl_barcode_backends_style_get_prefered_n (style->backend_id, style->id);
193 lbc->priv->style = style;
194 update_barcode (lbc);
196 line_color_node = gl_color_node_new_default ();
197 line_color_node->color = gl_label_get_default_line_color(label);
198 lbc->priv->color_node = line_color_node;
200 gl_label_add_object (label, GL_LABEL_OBJECT (lbc));
201 gl_label_object_set_parent (GL_LABEL_OBJECT (lbc), label);
204 return G_OBJECT (lbc);
208 /*****************************************************************************/
209 /* Copy object contents. */
210 /*****************************************************************************/
212 copy (glLabelObject *dst_object,
213 glLabelObject *src_object)
215 glLabelBarcode *lbc = (glLabelBarcode *)src_object;
216 glLabelBarcode *new_lbc = (glLabelBarcode *)dst_object;
217 glTextNode *text_node;
218 glLabelBarcodeStyle *style;
219 glColorNode *color_node;
221 gl_debug (DEBUG_LABEL, "START");
223 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
224 g_return_if_fail (new_lbc && GL_IS_LABEL_BARCODE (new_lbc));
226 text_node = gl_label_barcode_get_data (lbc);
227 style = gl_label_barcode_get_style (lbc);
228 color_node = get_line_color (src_object);
230 new_lbc->priv->text_node = text_node;
231 new_lbc->priv->style = style;
232 new_lbc->priv->color_node = color_node;
234 update_barcode (new_lbc);
236 gl_debug (DEBUG_LABEL, "END");
240 /*****************************************************************************/
241 /* Set object params. */
242 /*****************************************************************************/
244 gl_label_barcode_set_data (glLabelBarcode *lbc,
245 const glTextNode *text_node,
250 gl_debug (DEBUG_LABEL, "START");
252 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
254 if (!gl_text_node_equal (lbc->priv->text_node, text_node))
258 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
259 gl_label_checkpoint (label, _("Barcode data"));
262 gl_text_node_free (&lbc->priv->text_node);
263 lbc->priv->text_node = gl_text_node_dup (text_node);
265 update_barcode (lbc);
267 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
270 gl_debug (DEBUG_LABEL, "END");
275 gl_label_barcode_set_style (glLabelBarcode *lbc,
276 const glLabelBarcodeStyle *style,
281 gl_debug (DEBUG_LABEL, "START");
283 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
285 if ( !gl_label_barcode_style_is_equal (style, lbc->priv->style) )
289 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbc));
290 gl_label_checkpoint (label, _("Barcode property"));
293 gl_label_barcode_style_free (lbc->priv->style);
294 lbc->priv->style = gl_label_barcode_style_dup (style);
296 update_barcode (lbc);
298 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbc));
301 gl_debug (DEBUG_LABEL, "END");
305 /*****************************************************************************/
306 /* Get object params. */
307 /*****************************************************************************/
309 gl_label_barcode_get_data (glLabelBarcode *lbc)
311 g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
313 return gl_text_node_dup (lbc->priv->text_node);
317 glLabelBarcodeStyle *
318 gl_label_barcode_get_style (glLabelBarcode *lbc)
320 g_return_val_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc), NULL);
322 return gl_label_barcode_style_dup (lbc->priv->style);
326 /*---------------------------------------------------------------------------*/
327 /* PRIVATE. Update cached lglBarcode. */
328 /*---------------------------------------------------------------------------*/
330 update_barcode (glLabelBarcode *lbc)
332 gdouble w_raw, h_raw;
335 gl_debug (DEBUG_LABEL, "START");
337 g_return_if_fail (lbc && GL_IS_LABEL_BARCODE (lbc));
339 gl_label_object_get_raw_size (GL_LABEL_OBJECT (lbc), &w_raw, &h_raw);
341 lgl_barcode_free (lbc->priv->display_gbc);
343 if (lbc->priv->text_node->field_flag)
345 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
346 lbc->priv->style->id,
347 lbc->priv->style->format_digits);
351 data = gl_text_node_expand (lbc->priv->text_node, NULL);
354 lbc->priv->display_gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
355 lbc->priv->style->id,
356 lbc->priv->style->text_flag,
357 lbc->priv->style->checksum_flag,
363 if ( lbc->priv->display_gbc == NULL )
367 /* Try again with default digits, but don't save -- just extract size. */
368 data = gl_barcode_backends_style_default_digits (lbc->priv->style->backend_id,
369 lbc->priv->style->id,
370 lbc->priv->style->format_digits);
371 gbc = gl_barcode_backends_new_barcode (lbc->priv->style->backend_id,
372 lbc->priv->style->id,
373 lbc->priv->style->text_flag,
374 lbc->priv->style->checksum_flag,
382 lbc->priv->w = gbc->width;
383 lbc->priv->h = gbc->height;
387 /* If we still can't render, just set a default size. */
392 lgl_barcode_free (gbc);
396 lbc->priv->w = lbc->priv->display_gbc->width;
397 lbc->priv->h = lbc->priv->display_gbc->height;
400 gl_debug (DEBUG_LABEL, "END");
404 /*---------------------------------------------------------------------------*/
405 /* PRIVATE. Set object size method. */
406 /*---------------------------------------------------------------------------*/
408 set_size (glLabelObject *object,
413 gl_debug (DEBUG_LABEL, "START");
415 g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
417 gl_label_object_set_raw_size (object, w, h, checkpoint);
418 update_barcode (GL_LABEL_BARCODE (object));
420 gl_debug (DEBUG_LABEL, "END");
424 /*---------------------------------------------------------------------------*/
425 /* PRIVATE. Get object size method. */
426 /*---------------------------------------------------------------------------*/
428 get_size (glLabelObject *object,
432 gl_debug (DEBUG_LABEL, "START");
434 g_return_if_fail (object && GL_IS_LABEL_BARCODE (object));
436 *w = GL_LABEL_BARCODE (object)->priv->w;
437 *h = GL_LABEL_BARCODE (object)->priv->h;
439 gl_debug (DEBUG_LABEL, "END");
443 /*---------------------------------------------------------------------------*/
444 /* PRIVATE. Set line color method. */
445 /*---------------------------------------------------------------------------*/
447 set_line_color (glLabelObject *object,
448 glColorNode *line_color_node,
451 glLabelBarcode *lbarcode = (glLabelBarcode *)object;
454 g_return_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode));
456 if ( !gl_color_node_equal(lbarcode->priv->color_node, line_color_node) )
460 label = gl_label_object_get_parent (GL_LABEL_OBJECT (lbarcode));
461 gl_label_checkpoint (label, _("Barcode data"));
464 gl_color_node_free (&(lbarcode->priv->color_node));
465 lbarcode->priv->color_node = gl_color_node_dup (line_color_node);
466 gl_label_object_emit_changed (GL_LABEL_OBJECT(lbarcode));
471 /*---------------------------------------------------------------------------*/
472 /* PRIVATE. Get line color method. */
473 /*---------------------------------------------------------------------------*/
475 get_line_color (glLabelObject *object)
477 glLabelBarcode *lbarcode = (glLabelBarcode *)object;
479 g_return_val_if_fail (lbarcode && GL_IS_LABEL_BARCODE (lbarcode), NULL);
481 return gl_color_node_dup (lbarcode->priv->color_node);
485 /*****************************************************************************/
486 /* Draw object method. */
487 /*****************************************************************************/
489 draw_object (glLabelObject *object,
491 gboolean screen_flag,
492 glMergeRecord *record)
494 glLabelBarcode *lbc = (glLabelBarcode *)object;
496 cairo_matrix_t matrix;
499 glTextNode *text_node;
500 glLabelBarcodeStyle *style;
502 glColorNode *color_node;
505 gl_debug (DEBUG_LABEL, "START");
507 gl_label_object_get_position (object, &x0, &y0);
508 gl_label_object_get_matrix (object, &matrix);
510 text_node = gl_label_barcode_get_data (GL_LABEL_BARCODE (object));
511 style = gl_label_barcode_get_style (GL_LABEL_BARCODE (object));
513 color_node = gl_label_object_get_line_color (object);
514 color = gl_color_node_expand (color_node, record);
515 if (color_node->field_flag && screen_flag)
517 color = GL_COLOR_MERGE_DEFAULT;
520 cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
522 if (text_node->field_flag && !screen_flag) {
524 gl_label_object_get_raw_size (object, &w, &h);
526 text = gl_text_node_expand (text_node, record);
527 gbc = gl_barcode_backends_new_barcode (style->backend_id, style->id, style->text_flag, style->checksum_flag, w, h, text);
532 lgl_barcode_render_to_cairo (gbc, cr);
533 lgl_barcode_free (gbc);
540 if (lbc->priv->display_gbc == NULL)
542 create_alt_msg_path (cr, text_node->data);
547 lgl_barcode_render_to_cairo (lbc->priv->display_gbc, cr);
552 gl_text_node_free (&text_node);
553 gl_label_barcode_style_free (style);
554 gl_color_node_free (&color_node);
556 gl_debug (DEBUG_LABEL, "END");
560 /*****************************************************************************/
561 /* Is object at coordinates? */
562 /*****************************************************************************/
564 object_at (glLabelObject *object,
569 glLabelBarcode *lbc = (glLabelBarcode *)object;
571 glTextNode *text_node;
572 gdouble scale_x, scale_y;
574 gl_label_object_get_size (object, &w, &h);
576 if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
579 text_node = gl_label_barcode_get_data(GL_LABEL_BARCODE(object));
581 if ( lbc->priv->display_gbc == NULL )
583 create_alt_msg_path (cr, text_node->data);
587 lgl_barcode_render_to_cairo_path (lbc->priv->display_gbc, cr);
590 if (cairo_in_fill (cr, x, y))
598 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
600 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
602 if (cairo_in_stroke (cr, x, y))
608 if (gl_label_object_is_selected (object))
611 cairo_rectangle (cr, 0, 0, w, h);
615 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
617 cairo_set_line_width (cr, (HANDLE_OUTLINE_WIDTH_PIXELS + 2*SELECTION_SLOP_PIXELS)*scale_x);
619 if (cairo_in_stroke (cr, x, y))
631 /*****************************************************************************/
632 /* Draw barcode style handles. */
633 /*****************************************************************************/
635 draw_handles (glLabelObject *object,
639 gdouble scale_x, scale_y;
640 gdouble dashes[2] = { 2, 2 };
642 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
646 cairo_rectangle (cr, 0, 0, w, h);
650 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
651 cairo_scale (cr, scale_x, scale_y);
653 cairo_set_dash (cr, dashes, 2, 0);
654 cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
655 cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
660 gl_label_object_draw_handles_box (object, cr);
664 /*****************************************************************************/
665 /* Create a cairo path with apropos message. */
666 /*****************************************************************************/
668 create_alt_msg_path (cairo_t *cr,
672 PangoFontDescription *desc;
674 layout = pango_cairo_create_layout (cr);
676 desc = pango_font_description_new ();
677 pango_font_description_set_family (desc, GL_BARCODE_FONT_FAMILY);
678 pango_font_description_set_size (desc, 12 * PANGO_SCALE * FONT_SCALE);
679 pango_layout_set_font_description (layout, desc);
680 pango_font_description_free (desc);
682 if (text == NULL || *text == '\0')
684 pango_layout_set_text (layout, _("Barcode data empty"), -1);
688 pango_layout_set_text (layout, _("Invalid barcode data"), -1);
691 cairo_move_to (cr, 0, 0);
692 pango_cairo_layout_path (cr, layout);
694 g_object_unref (layout);
698 /*****************************************************************************/
699 /* Barcode style utilities. */
700 /*****************************************************************************/
701 glLabelBarcodeStyle *
702 gl_label_barcode_style_new (void)
704 return g_new0 (glLabelBarcodeStyle, 1);
708 glLabelBarcodeStyle *
709 gl_label_barcode_style_dup (const glLabelBarcodeStyle *style)
711 glLabelBarcodeStyle *style2;
713 style2 = gl_label_barcode_style_new ();
715 /* Shallow copy first. */
719 style2->backend_id = g_strdup (style->backend_id);
720 style2->id = g_strdup (style->id);
727 gl_label_barcode_style_free (glLabelBarcodeStyle *style)
731 g_free (style->backend_id);
740 gl_label_barcode_style_is_equal (const glLabelBarcodeStyle *style1,
741 const glLabelBarcodeStyle *style2)
744 /* First take care of the case of either or both being NULL. */
745 if ( style1 == NULL )
747 return ( style2 == NULL );
751 if ( style2 == NULL )
757 /* Compare field by field, bail on first difference. */
758 if ( style1->text_flag != style2->text_flag )
762 if ( style1->checksum_flag != style2->checksum_flag )
766 if ( style1->format_digits != style2->format_digits )
770 if ( style1->backend_id && style2->backend_id )
772 if ( strcmp (style1->backend_id, style2->backend_id) != 0 )
779 if ( style1->backend_id != style2->backend_id )
784 if ( style1->id && style2->id )
786 if ( strcmp (style1->id, style2->id) != 0 )
793 if ( style1->id != style2->id )
799 /* Passed all tests. */
805 gl_label_barcode_style_set_backend_id (glLabelBarcodeStyle *style,
806 const gchar *backend_id)
808 style->backend_id = g_strdup (backend_id);
813 gl_label_barcode_style_set_style_id (glLabelBarcodeStyle *style,
816 style->id = g_strdup (id);
824 * Local Variables: -- emacs
826 * c-basic-offset: 8 -- emacs
827 * tab-width: 8 -- emacs
828 * indent-tabs-mode: nil -- emacs