1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (LIBGLABELS) Template library for GLABELS
6 * template.c: template module
8 * Copyright (C) 2001-2006 Jim Evins <evins@snaught.com>.
10 * This file is part of the LIBGLABELS library.
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
31 #include <glib/gi18n.h>
32 #include <glib/gmem.h>
33 #include <glib/gstrfuncs.h>
34 #include <glib/gqsort.h>
35 #include <glib/gmessages.h>
38 #include <sys/types.h>
40 #include "libglabels-private.h"
44 /*===========================================*/
46 /*===========================================*/
49 /*===========================================*/
51 /*===========================================*/
54 /*===========================================*/
55 /* Local function prototypes */
56 /*===========================================*/
58 static gint compare_origins (gconstpointer a,
62 /*===========================================*/
64 /*===========================================*/
68 * @brand: Template brand
69 * @part: Template part name/number
70 * @description: Template descriptions
71 * @paper_id: Page size id
72 * @page_width: Page width in points, set to zero unless paper_id="Other"
73 * @page_height: Page height in points, set to zero unless paper_id="Other"
75 * Create a new template structure, with the given top-level attributes. The
76 * created template will have no initial aliases, categories, or frames
77 * associated with it. See lgl_template_add_alias(), lgl_template_add_category(),
78 * and lgl_template_add_frame() to add these.
80 * Returns: pointer to a newly allocated #lglTemplate structure.
84 lgl_template_new (const gchar *brand,
86 const gchar *description,
87 const gchar *paper_id,
91 lglTemplate *template;
92 lglTemplateAlias *alias;
94 template = g_new0 (lglTemplate,1);
96 template->brand = g_strdup (brand);
97 template->part = g_strdup (part);
98 template->description = g_strdup (description);
99 template->paper_id = g_strdup (paper_id);
100 template->page_width = page_width;
101 template->page_height = page_height;
103 /* Always include primary name in alias list. */
104 template->aliases = NULL;
105 alias = lgl_template_alias_new (brand, part);
106 lgl_template_add_alias (template, alias);
113 * lgl_template_get_name:
114 * @template: Pointer to template structure to test
116 * This function returns the name of the given template. The name is the concetenation
117 * of the brand and part name/number.
119 * Returns: A pointer to a newly allocated name string. Should be freed with g_free().
123 lgl_template_get_name (const lglTemplate *template)
125 g_return_val_if_fail (template, NULL);
127 return g_strdup_printf ("%s %s", template->brand, template->part);
132 * lgl_template_do_templates_match:
133 * @template1: Pointer to 1st template structure to test
134 * @template2: Pointer to 2nd template structure to test
136 * This function tests if the given templates match. This is a simple test that only tests
137 * the brand and part name/number. It does not test if they are actually identical.
139 * Returns: TRUE if the two template matche.
143 lgl_template_do_templates_match (const lglTemplate *template1,
144 const lglTemplate *template2)
146 g_return_val_if_fail (template1, FALSE);
147 g_return_val_if_fail (template2, FALSE);
149 return (UTF8_EQUAL (template1->brand, template2->brand) &&
150 UTF8_EQUAL (template1->part, template2->part));
155 * lgl_template_does_brand_match:
156 * @template: Pointer to template structure to test
157 * @brand: Brand string
159 * This function tests if the brand of the template matches the given brand.
161 * Returns: TRUE if the template matches the given brand.
165 lgl_template_does_brand_match (const lglTemplate *template,
168 g_return_val_if_fail (template, FALSE);
170 /* NULL matches everything. */
176 return UTF8_EQUAL (template->brand, brand);
181 * lgl_template_does_page_size_match:
182 * @template: Pointer to template structure to test
183 * @paper_id: Page size ID string
185 * This function tests if the page size of the template matches the given ID.
187 * Returns: TRUE if the template matches the given page size ID.
191 lgl_template_does_page_size_match (const lglTemplate *template,
192 const gchar *paper_id)
194 g_return_val_if_fail (template, FALSE);
196 /* NULL matches everything. */
197 if (paper_id == NULL)
202 return ASCII_EQUAL(paper_id, template->paper_id);
207 * lgl_template_does_category_match:
208 * @template: Pointer to template structure to test
209 * @category_id: Category ID string
211 * This function tests if the given template belongs to the given category ID.
213 * Returns: TRUE if the template matches the given category ID.
217 lgl_template_does_category_match (const lglTemplate *template,
218 const gchar *category_id)
222 g_return_val_if_fail (template, FALSE);
224 /* NULL matches everything. */
225 if (category_id == NULL)
230 for ( p=template->category_ids; p != NULL; p=p->next )
232 if (ASCII_EQUAL(category_id, p->data))
243 * lgl_template_alias_new:
244 * @brand: Alias brand
245 * @part: Alias part name/number
247 * Create a new template alias structure, with the given brand and part number.
249 * Returns: pointer to a newly allocated #lglTemplateAlias structure.
253 lgl_template_alias_new (const gchar *brand,
256 lglTemplateAlias *alias;
258 alias = g_new0 (lglTemplateAlias,1);
260 alias->brand = g_strdup (brand);
261 alias->part = g_strdup (part);
268 * lgl_template_add_alias:
269 * @template: Pointer to template structure
270 * @alias: Alias string
272 * This function adds the given alias to a templates list of aliases.
276 lgl_template_add_alias (lglTemplate *template,
277 lglTemplateAlias *alias)
279 g_return_if_fail (template);
280 g_return_if_fail (alias);
282 template->aliases = g_list_append (template->aliases, alias);
287 * lgl_template_add_frame:
288 * @template: Pointer to template structure
289 * @frame: Pointer to frame structure
291 * This function adds the given frame structure to the template. Once added,
292 * the frame structure belongs to the given template; do not attempt to free
295 * Note: Currently glabels only supports a single frame per template.
299 lgl_template_add_frame (lglTemplate *template,
300 lglTemplateFrame *frame)
302 g_return_if_fail (template);
303 g_return_if_fail (frame);
305 template->frames = g_list_append (template->frames, frame);
310 * lgl_template_add_category:
311 * @template: Pointer to template structure
312 * @category_id: Category ID string
314 * This function adds the given category ID to a templates category list.
318 lgl_template_add_category (lglTemplate *template,
319 const gchar *category_id)
321 g_return_if_fail (template);
322 g_return_if_fail (category_id);
324 template->category_ids = g_list_append (template->category_ids,
325 g_strdup (category_id));
330 * lgl_template_frame_rect_new:
331 * @id: ID of frame. (This should currently always be "0").
332 * @w: width of frame in points.
333 * @h: height of frame in points.
334 * @r: radius of rounded corners in points. (Should be 0 for square corners.)
335 * @x_waste: Amount of overprint to allow in the horizontal direction.
336 * @y_waste: Amount of overprint to allow in the vertical direction.
338 * This function creates a new template frame for a rectangular label or card.
340 * Returns: Pointer to newly allocated #lglTemplateFrame structure.
344 lgl_template_frame_rect_new (const gchar *id,
351 lglTemplateFrame *frame;
353 frame = g_new0 (lglTemplateFrame, 1);
355 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_RECT;
356 frame->rect.id = g_strdup (id);
361 frame->rect.x_waste = x_waste;
362 frame->rect.y_waste = y_waste;
369 * lgl_template_frame_round_new:
370 * @id: ID of frame. (This should currently always be "0").
371 * @r: radius of label in points.
372 * @waste: Amount of overprint to allow.
374 * This function creates a new template frame for a round label.
376 * Returns: Pointer to newly allocated #lglTemplateFrame structure.
380 lgl_template_frame_round_new (const gchar *id,
384 lglTemplateFrame *frame;
386 frame = g_new0 (lglTemplateFrame, 1);
388 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ROUND;
389 frame->round.id = g_strdup (id);
392 frame->round.waste = waste;
399 * lgl_template_frame_cd_new:
400 * @id: ID of frame. (This should currently always be "0").
401 * @r1: outer radius of label in points.
402 * @r2: radius of center hole in points.
403 * @w: clip width of frame in points for business card CDs. Should be 0 for no clipping.
404 * @h: clip height of frame in points for business card CDs. Should be 0 for no clipping.
405 * @waste: Amount of overprint to allow.
407 * This function creates a new template frame for a CD/DVD label.
409 * Returns: Pointer to newly allocated #lglTemplateFrame structure.
413 lgl_template_frame_cd_new (const gchar *id,
420 lglTemplateFrame *frame;
422 frame = g_new0 (lglTemplateFrame, 1);
424 frame->shape = LGL_TEMPLATE_FRAME_SHAPE_CD;
425 frame->cd.id = g_strdup (id);
431 frame->cd.waste = waste;
438 * lgl_template_frame_get_size:
439 * @frame: #lglTemplateFrame structure to query
440 * @w: pointer to location to receive width of frame
441 * @h: pointer to location to receive height of frame
443 * Get size (width and height) of given #lglTemplateFrame in points.
447 lgl_template_frame_get_size (const lglTemplateFrame *frame,
451 g_return_if_fail (frame);
453 switch (frame->shape) {
454 case LGL_TEMPLATE_FRAME_SHAPE_RECT:
458 case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
459 *w = 2.0 * frame->round.r;
460 *h = 2.0 * frame->round.r;
462 case LGL_TEMPLATE_FRAME_SHAPE_CD:
463 if (frame->cd.w == 0.0) {
464 *w = 2.0 * frame->cd.r1;
468 if (frame->cd.h == 0.0) {
469 *h = 2.0 * frame->cd.r1;
483 * lgl_template_frame_get_n_labels:
484 * @frame: #lglTemplateFrame structure to query
486 * Get total number of labels per sheet corresponding to the given frame.
488 * Returns: number of labels per sheet.
492 lgl_template_frame_get_n_labels (const lglTemplateFrame *frame)
496 lglTemplateLayout *layout;
498 g_return_val_if_fail (frame, 0);
500 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
501 layout = (lglTemplateLayout *)p->data;
503 n_labels += layout->nx * layout->ny;
511 * lgl_template_frame_get_origins:
512 * @frame: #lglTemplateFrame structure to query
514 * Get an array of label origins for the given frame. These origins represent the
515 * upper left hand corner of each label on a page corresponding to the given frame.
516 * The origins will be ordered geometrically left to right and then top to bottom.
517 * The array should be freed using g_free().
519 * Returns: A newly allocated array of #lglTemplateOrigin structures.
523 lgl_template_frame_get_origins (const lglTemplateFrame *frame)
525 gint i_label, n_labels, ix, iy;
526 lglTemplateOrigin *origins;
528 lglTemplateLayout *layout;
530 g_return_val_if_fail (frame, NULL);
532 n_labels = lgl_template_frame_get_n_labels (frame);
533 origins = g_new0 (lglTemplateOrigin, n_labels);
536 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
537 layout = (lglTemplateLayout *)p->data;
539 for (iy = 0; iy < layout->ny; iy++) {
540 for (ix = 0; ix < layout->nx; ix++, i_label++) {
541 origins[i_label].x = ix*layout->dx + layout->x0;
542 origins[i_label].y = iy*layout->dy + layout->y0;
547 g_qsort_with_data (origins, n_labels, sizeof(lglTemplateOrigin),
548 compare_origins, NULL);
555 * lgl_template_frame_add_layout:
556 * @frame: Pointer to template frame to add layout to.
557 * @layout: Pointer to layout structure to add to frame.
559 * This function adds a layout structure to the given template frame.
563 lgl_template_frame_add_layout (lglTemplateFrame *frame,
564 lglTemplateLayout *layout)
566 g_return_if_fail (frame);
567 g_return_if_fail (layout);
569 frame->all.layouts = g_list_append (frame->all.layouts, layout);
574 * lgl_template_frame_add_markup:
575 * @frame: Pointer to template frame to add markup to.
576 * @markup: Pointer to markup structure to add to frame.
578 * This function adds a markup structure to the given template frame.
582 lgl_template_frame_add_markup (lglTemplateFrame *frame,
583 lglTemplateMarkup *markup)
585 g_return_if_fail (frame);
586 g_return_if_fail (markup);
588 frame->all.markups = g_list_append (frame->all.markups, markup);
593 * lgl_template_layout_new:
594 * @nx: Number of labels across.
595 * @ny: Number of labels down.
596 * @x0: X coordinate of the top-left corner of the top-left label in the layout in points.
597 * @y0: Y coordinate of the top-left corner of the top-left label in the layout in points.
598 * @dx: Horizontal pitch in points. This is the distance from left-edge to left-edge.
599 * @dy: Vertical pitch in points. This is the distance from top-edge to top-edge.
601 * This function creates a new layout structure with the given parameters.
603 * Returns: a newly allocated #lglTemplateLayout structure.
607 lgl_template_layout_new (gint nx,
614 lglTemplateLayout *layout;
616 layout = g_new0 (lglTemplateLayout, 1);
630 * lgl_template_markup_margin_new:
631 * @size: margin size in points.
633 * This function creates a new margin markup structure.
635 * Returns: a newly allocated #lglTemplateMarkup structure.
639 lgl_template_markup_margin_new (gdouble size)
641 lglTemplateMarkup *markup;
643 markup = g_new0 (lglTemplateMarkup, 1);
645 markup->type = LGL_TEMPLATE_MARKUP_MARGIN;
646 markup->margin.size = size;
653 * lgl_template_markup_line_new:
654 * @x1: x coordinate of first endpoint.
655 * @y1: y coordinate of first endpoint.
656 * @x2: x coordinate of second endpoint.
657 * @y2: y coordinate of second endpoint.
659 * This function creates a new line markup structure.
661 * Returns: a newly allocated #lglTemplateMarkup structure.
665 lgl_template_markup_line_new (gdouble x1,
670 lglTemplateMarkup *markup;
672 markup = g_new0 (lglTemplateMarkup, 1);
674 markup->type = LGL_TEMPLATE_MARKUP_LINE;
675 markup->line.x1 = x1;
676 markup->line.y1 = y1;
677 markup->line.x2 = x2;
678 markup->line.y2 = y2;
685 * lgl_template_markup_circle_new:
686 * @x0: x coordinate of center of circle.
687 * @y0: y coordinate of center of circle.
688 * @r: radius of circle.
690 * This function creates a new circle markup structure.
692 * Returns: a newly allocated #lglTemplateMarkup structure.
696 lgl_template_markup_circle_new (gdouble x0,
700 lglTemplateMarkup *markup;
702 markup = g_new0 (lglTemplateMarkup, 1);
704 markup->type = LGL_TEMPLATE_MARKUP_CIRCLE;
705 markup->circle.x0 = x0;
706 markup->circle.y0 = y0;
707 markup->circle.r = r;
714 * lgl_template_markup_rect_new:
715 * @x1: x coordinate of top-left corner of rectangle.
716 * @y1: y coordinate of top-left corner of rectangle.
717 * @w: width of rectangle.
718 * @h: height of rectangle.
719 * @r: radius of rounded corner.
721 * This function creates a new rectangle markup structure.
723 * Returns: a newly allocated #lglTemplateMarkup structure.
727 lgl_template_markup_rect_new (gdouble x1,
733 lglTemplateMarkup *markup;
735 markup = g_new0 (lglTemplateMarkup, 1);
737 markup->type = LGL_TEMPLATE_MARKUP_RECT;
738 markup->rect.x1 = x1;
739 markup->rect.y1 = y1;
750 * @orig_template: Template to duplicate.
752 * This function duplicates a template structure.
754 * Returns: a newly allocated #lglTemplate structure.
758 lgl_template_dup (const lglTemplate *orig_template)
760 lglTemplate *template;
761 lglTemplateAlias *alias;
763 lglTemplateFrame *frame;
765 g_return_val_if_fail (orig_template, NULL);
767 template = lgl_template_new (orig_template->brand,
769 orig_template->description,
770 orig_template->paper_id,
771 orig_template->page_width,
772 orig_template->page_height);
774 for ( p=orig_template->aliases; p != NULL; p=p->next )
776 alias = (lglTemplateAlias *)p->data;
778 if ( !(UTF8_EQUAL (template->brand, alias->brand) &&
779 UTF8_EQUAL (template->part, alias->part)) )
781 lgl_template_add_alias (template, lgl_template_alias_dup (alias));
786 for ( p=orig_template->category_ids; p != NULL; p=p->next )
788 lgl_template_add_category (template, p->data);
791 for ( p=orig_template->frames; p != NULL; p=p->next )
793 frame = (lglTemplateFrame *)p->data;
795 lgl_template_add_frame (template, lgl_template_frame_dup (frame));
804 * @template: Template to free.
806 * This function frees all memory associated with given template structure.
810 lgl_template_free (lglTemplate *template)
813 lglTemplateFrame *frame;
815 if ( template != NULL ) {
817 g_free (template->brand);
818 template->brand = NULL;
820 g_free (template->part);
821 template->part = NULL;
823 g_free (template->description);
824 template->description = NULL;
826 g_free (template->paper_id);
827 template->paper_id = NULL;
829 for ( p=template->aliases; p != NULL; p=p->next ) {
831 lgl_template_alias_free (p->data);
835 g_list_free (template->aliases);
836 template->aliases = NULL;
838 for ( p=template->category_ids; p != NULL; p=p->next ) {
844 g_list_free (template->category_ids);
845 template->category_ids = NULL;
847 for ( p=template->frames; p != NULL; p=p->next ) {
849 frame = (lglTemplateFrame *)p->data;
851 lgl_template_frame_free (frame);
854 g_list_free (template->frames);
855 template->frames = NULL;
865 * lgl_template_alias_dup:
866 * @orig_alias: Alias to duplicate.
868 * This function duplicates a template alias structure.
870 * Returns: a newly allocated #lglTemplateAlias structure.
874 lgl_template_alias_dup (const lglTemplateAlias *orig_alias)
876 g_return_val_if_fail (orig_alias, NULL);
878 return lgl_template_alias_new (orig_alias->brand, orig_alias->part);
883 * lgl_template_alias_free:
884 * @alias: Alias to free.
886 * This function frees all memory associated with given template alias structure.
890 lgl_template_alias_free (lglTemplateAlias *alias)
895 g_free (alias->brand);
898 g_free (alias->part);
907 * lgl_template_frame_dup:
908 * @orig_frame: Frame to duplicate.
910 * This function duplicates a template frame structure.
912 * Returns: a newly allocated #lglTemplateFrame structure.
916 lgl_template_frame_dup (const lglTemplateFrame *orig_frame)
918 lglTemplateFrame *frame;
920 lglTemplateLayout *layout;
921 lglTemplateMarkup *markup;
923 g_return_val_if_fail (orig_frame, NULL);
925 switch (orig_frame->shape) {
927 case LGL_TEMPLATE_FRAME_SHAPE_RECT:
929 lgl_template_frame_rect_new (orig_frame->all.id,
933 orig_frame->rect.x_waste,
934 orig_frame->rect.y_waste);
937 case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
939 lgl_template_frame_round_new (orig_frame->all.id,
941 orig_frame->round.waste);
944 case LGL_TEMPLATE_FRAME_SHAPE_CD:
946 lgl_template_frame_cd_new (orig_frame->all.id,
951 orig_frame->cd.waste);
959 for ( p=orig_frame->all.layouts; p != NULL; p=p->next ) {
961 layout = (lglTemplateLayout *)p->data;
963 lgl_template_frame_add_layout (frame, lgl_template_layout_dup (layout));
966 for ( p=orig_frame->all.markups; p != NULL; p=p->next ) {
968 markup = (lglTemplateMarkup *)p->data;
970 lgl_template_frame_add_markup (frame, lgl_template_markup_dup (markup));
978 * lgl_template_frame_free:
979 * @frame: Frame to free.
981 * This function frees all memory associated with given template frame structure.
985 lgl_template_frame_free (lglTemplateFrame *frame)
988 lglTemplateLayout *layout;
989 lglTemplateMarkup *markup;
991 if ( frame != NULL ) {
993 g_free (frame->all.id);
994 frame->all.id = NULL;
996 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
998 layout = (lglTemplateLayout *)p->data;
1000 lgl_template_layout_free (layout);
1003 g_list_free (frame->all.layouts);
1004 frame->all.layouts = NULL;
1006 for ( p=frame->all.markups; p != NULL; p=p->next ) {
1008 markup = (lglTemplateMarkup *)p->data;
1010 lgl_template_markup_free (markup);
1013 g_list_free (frame->all.markups);
1014 frame->all.markups = NULL;
1024 * lgl_template_layout_dup:
1025 * @orig_layout: Layout to duplicate.
1027 * This function duplicates a template layout structure.
1029 * Returns: a newly allocated #lglTemplateLayout structure.
1033 lgl_template_layout_dup (const lglTemplateLayout *orig_layout)
1035 lglTemplateLayout *layout;
1037 g_return_val_if_fail (orig_layout, NULL);
1039 layout = g_new0 (lglTemplateLayout, 1);
1042 *layout = *orig_layout;
1049 * lgl_template_layout_free:
1050 * @layout: Layout to free.
1052 * This function frees all memory associated with given template layout structure.
1056 lgl_template_layout_free (lglTemplateLayout *layout)
1063 * lgl_template_markup_dup:
1064 * @orig_markup: Markup to duplicate.
1066 * This function duplicates a template markup structure.
1068 * Returns: a newly allocated #lglTemplateMarkup structure.
1072 lgl_template_markup_dup (const lglTemplateMarkup *orig_markup)
1074 lglTemplateMarkup *markup;
1076 g_return_val_if_fail (orig_markup, NULL);
1078 markup = g_new0 (lglTemplateMarkup, 1);
1080 *markup = *orig_markup;
1087 * lgl_template_markup_free:
1088 * @markup: Markup to free.
1090 * This function frees all memory associated with given template markup structure.
1094 lgl_template_markup_free (lglTemplateMarkup *markup)
1101 compare_origins (gconstpointer a,
1105 const lglTemplateOrigin *a_origin = a, *b_origin = b;
1107 if ( a_origin->y < b_origin->y ) {
1109 } else if ( a_origin->y > b_origin->y ) {
1112 if ( a_origin->x < b_origin->x ) {
1114 } else if ( a_origin->x > b_origin->x ) {
1117 return 0; /* hopefully 2 labels won't have the same origin */