]> git.sur5r.net Git - glabels/blob - libglabels/template.c
Imported Upstream version 2.2.8
[glabels] / libglabels / template.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (LIBGLABELS) Template library for GLABELS
5  *
6  *  template.c:  template module
7  *
8  *  Copyright (C) 2001-2006  Jim Evins <evins@snaught.com>.
9  *
10  *  This file is part of the LIBGLABELS library.
11  *
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.
16  *
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.
21  *
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,
25  *  MA 02111-1307, USA
26  */
27 #include <config.h>
28
29 #include "template.h"
30
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>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39
40 #include "libglabels-private.h"
41
42 #include "paper.h"
43
44 /*===========================================*/
45 /* Private types                             */
46 /*===========================================*/
47
48
49 /*===========================================*/
50 /* Private globals                           */
51 /*===========================================*/
52
53
54 /*===========================================*/
55 /* Local function prototypes                 */
56 /*===========================================*/
57
58 static gint         compare_origins              (gconstpointer           a,
59                                                   gconstpointer           b,
60                                                   gpointer                user_data);
61
62 /*===========================================*/
63 /* Functions.                                */
64 /*===========================================*/
65
66 /**
67  * lgl_template_new:
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"
74  *
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.
79  *
80  * Returns: pointer to a newly allocated #lglTemplate structure.
81  *
82  */
83 lglTemplate *
84 lgl_template_new (const gchar         *brand,
85                   const gchar         *part,
86                   const gchar         *description,
87                   const gchar         *paper_id,
88                   gdouble              page_width,
89                   gdouble              page_height)
90 {
91         lglTemplate      *template;
92         lglTemplateAlias *alias;
93
94         template = g_new0 (lglTemplate,1);
95
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;
102
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);
107
108         return template;
109 }
110
111
112 /**
113  * lgl_template_get_name:
114  *   @template:  Pointer to template structure to test
115  *
116  * This function returns the name of the given template.  The name is the concetenation
117  * of the brand and part name/number.
118  *
119  * Returns:  A pointer to a newly allocated name string.  Should be freed with g_free().
120  *
121  */
122 gchar *
123 lgl_template_get_name (const lglTemplate  *template)
124 {
125         g_return_val_if_fail (template, NULL);
126
127         return g_strdup_printf ("%s %s", template->brand, template->part);
128 }
129
130
131 /**
132  * lgl_template_do_templates_match:
133  *   @template1:  Pointer to 1st template structure to test
134  *   @template2:  Pointer to 2nd template structure to test
135  *
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.
138  *
139  * Returns:  TRUE if the two template matche.
140  *
141  */
142 gboolean
143 lgl_template_do_templates_match (const lglTemplate  *template1,
144                                  const lglTemplate  *template2)
145 {
146         g_return_val_if_fail (template1, FALSE);
147         g_return_val_if_fail (template2, FALSE);
148
149         return (UTF8_EQUAL (template1->brand, template2->brand) &&
150                 UTF8_EQUAL (template1->part, template2->part));
151 }
152
153
154 /**
155  * lgl_template_does_brand_match:
156  *   @template:  Pointer to template structure to test
157  *   @brand:     Brand string
158  *
159  * This function tests if the brand of the template matches the given brand.
160  *
161  * Returns:  TRUE if the template matches the given brand.
162  *
163  */
164 gboolean
165 lgl_template_does_brand_match (const lglTemplate  *template,
166                                const gchar        *brand)
167 {
168         g_return_val_if_fail (template, FALSE);
169
170         /* NULL matches everything. */
171         if (brand == NULL)
172         {
173                 return TRUE;
174         }
175
176         return UTF8_EQUAL (template->brand, brand);
177 }
178
179
180 /**
181  * lgl_template_does_page_size_match:
182  *   @template:  Pointer to template structure to test
183  *   @paper_id:  Page size ID string
184  *
185  * This function tests if the page size of the template matches the given ID.
186  *
187  * Returns:  TRUE if the template matches the given page size ID.
188  *
189  */
190 gboolean
191 lgl_template_does_page_size_match (const lglTemplate  *template,
192                                    const gchar        *paper_id)
193 {
194         g_return_val_if_fail (template, FALSE);
195
196         /* NULL matches everything. */
197         if (paper_id == NULL)
198         {
199                 return TRUE;
200         }
201
202         return ASCII_EQUAL(paper_id, template->paper_id);
203 }
204
205
206 /**
207  * lgl_template_does_category_match:
208  *   @template:     Pointer to template structure to test
209  *   @category_id:  Category ID string
210  *
211  * This function tests if the given template belongs to the given category ID.
212  *
213  * Returns:  TRUE if the template matches the given category ID.
214  *
215  */
216 gboolean
217 lgl_template_does_category_match  (const lglTemplate  *template,
218                                    const gchar        *category_id)
219 {
220         GList *p;
221
222         g_return_val_if_fail (template, FALSE);
223
224         /* NULL matches everything. */
225         if (category_id == NULL)
226         {
227                 return TRUE;
228         }
229
230         for ( p=template->category_ids; p != NULL; p=p->next )
231         {
232                 if (ASCII_EQUAL(category_id, p->data))
233                 {
234                         return TRUE;
235                 }
236         }
237
238         return FALSE;
239 }
240
241
242 /**
243  * lgl_template_alias_new:
244  *   @brand:        Alias brand
245  *   @part:         Alias part name/number
246  *
247  * Create a new template alias structure, with the given brand and part number.
248  *
249  * Returns: pointer to a newly allocated #lglTemplateAlias structure.
250  *
251  */
252 lglTemplateAlias *
253 lgl_template_alias_new (const gchar         *brand,
254                         const gchar         *part)
255 {
256         lglTemplateAlias *alias;
257
258         alias = g_new0 (lglTemplateAlias,1);
259
260         alias->brand       = g_strdup (brand);
261         alias->part        = g_strdup (part);
262
263         return alias;
264 }
265
266
267 /**
268  * lgl_template_add_alias:
269  *   @template:  Pointer to template structure
270  *   @alias:     Alias string
271  *
272  * This function adds the given alias to a templates list of aliases.
273  *
274  */
275 void
276 lgl_template_add_alias (lglTemplate         *template,
277                         lglTemplateAlias    *alias)
278 {
279         g_return_if_fail (template);
280         g_return_if_fail (alias);
281
282         template->aliases = g_list_append (template->aliases, alias);
283 }
284  
285
286 /**
287  * lgl_template_add_frame:
288  *   @template:  Pointer to template structure
289  *   @frame:     Pointer to frame structure
290  *
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
293  * it.
294  *
295  * Note: Currently glabels only supports a single frame per template.
296  *
297  */
298 void
299 lgl_template_add_frame (lglTemplate      *template,
300                         lglTemplateFrame *frame)
301 {
302         g_return_if_fail (template);
303         g_return_if_fail (frame);
304
305         template->frames = g_list_append (template->frames, frame);
306 }
307
308  
309 /**
310  * lgl_template_add_category:
311  *   @template:     Pointer to template structure
312  *   @category_id:  Category ID string
313  *
314  * This function adds the given category ID to a templates category list.
315  *
316  */
317 void
318 lgl_template_add_category (lglTemplate         *template,
319                            const gchar         *category_id)
320 {
321         g_return_if_fail (template);
322         g_return_if_fail (category_id);
323
324         template->category_ids = g_list_append (template->category_ids,
325                                                 g_strdup (category_id));
326 }
327
328  
329 /**
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.
337  *
338  * This function creates a new template frame for a rectangular label or card.
339  *
340  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
341  *
342  */
343 lglTemplateFrame *
344 lgl_template_frame_rect_new  (const gchar         *id,
345                               gdouble              w,
346                               gdouble              h,
347                               gdouble              r,
348                               gdouble              x_waste,
349                               gdouble              y_waste)
350 {
351         lglTemplateFrame *frame;
352
353         frame = g_new0 (lglTemplateFrame, 1);
354
355         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_RECT;
356         frame->rect.id = g_strdup (id);
357
358         frame->rect.w = w;
359         frame->rect.h = h;
360         frame->rect.r = r;
361         frame->rect.x_waste = x_waste;
362         frame->rect.y_waste = y_waste;
363
364         return frame;
365 }
366
367
368 /**
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.
373  *
374  * This function creates a new template frame for a round label.
375  *
376  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
377  *
378  */
379 lglTemplateFrame *
380 lgl_template_frame_round_new (const gchar         *id,
381                               gdouble              r,
382                               gdouble              waste)
383 {
384         lglTemplateFrame *frame;
385
386         frame = g_new0 (lglTemplateFrame, 1);
387
388         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ROUND;
389         frame->round.id = g_strdup (id);
390
391         frame->round.r = r;
392         frame->round.waste = waste;
393
394         return frame;
395 }
396
397                                                                                
398 /**
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.
406  *
407  * This function creates a new template frame for a CD/DVD label.
408  *
409  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
410  *
411  */
412 lglTemplateFrame *
413 lgl_template_frame_cd_new (const gchar         *id,
414                            gdouble              r1,
415                            gdouble              r2,
416                            gdouble              w,
417                            gdouble              h,
418                            gdouble              waste)
419 {
420         lglTemplateFrame *frame;
421
422         frame = g_new0 (lglTemplateFrame, 1);
423
424         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_CD;
425         frame->cd.id = g_strdup (id);
426
427         frame->cd.r1 = r1;
428         frame->cd.r2 = r2;
429         frame->cd.w  = w;
430         frame->cd.h  = h;
431         frame->cd.waste = waste;
432
433         return frame;
434 }
435
436
437 /**
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
442  *
443  * Get size (width and height) of given #lglTemplateFrame in points.
444  *
445  */
446 void
447 lgl_template_frame_get_size (const lglTemplateFrame *frame,
448                              gdouble                *w,
449                              gdouble                *h)
450 {
451         g_return_if_fail (frame);
452
453         switch (frame->shape) {
454         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
455                 *w = frame->rect.w;
456                 *h = frame->rect.h;
457                 break;
458         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
459                 *w = 2.0 * frame->round.r;
460                 *h = 2.0 * frame->round.r;
461                 break;
462         case LGL_TEMPLATE_FRAME_SHAPE_CD:
463                 if (frame->cd.w == 0.0) {
464                         *w = 2.0 * frame->cd.r1;
465                 } else {
466                         *w = frame->cd.w;
467                 }
468                 if (frame->cd.h == 0.0) {
469                         *h = 2.0 * frame->cd.r1;
470                 } else {
471                         *h = frame->cd.h;
472                 }
473                 break;
474         default:
475                 *w = 0.0;
476                 *h = 0.0;
477                 break;
478         }
479 }
480
481
482 /**
483  * lgl_template_frame_get_n_labels:
484  * @frame: #lglTemplateFrame structure to query
485  *
486  * Get total number of labels per sheet corresponding to the given frame.
487  *
488  * Returns: number of labels per sheet.
489  *
490  */
491 gint
492 lgl_template_frame_get_n_labels (const lglTemplateFrame *frame)
493 {
494         gint               n_labels = 0;
495         GList             *p;
496         lglTemplateLayout *layout;
497
498         g_return_val_if_fail (frame, 0);
499
500         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
501                 layout = (lglTemplateLayout *)p->data;
502
503                 n_labels += layout->nx * layout->ny;
504         }
505
506         return n_labels;
507 }
508
509
510 /**
511  * lgl_template_frame_get_origins:
512  * @frame: #lglTemplateFrame structure to query
513  *
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().
518  *
519  * Returns: A newly allocated array of #lglTemplateOrigin structures.
520  *
521  */
522 lglTemplateOrigin *
523 lgl_template_frame_get_origins (const lglTemplateFrame *frame)
524 {
525         gint               i_label, n_labels, ix, iy;
526         lglTemplateOrigin *origins;
527         GList             *p;
528         lglTemplateLayout *layout;
529
530         g_return_val_if_fail (frame, NULL);
531
532         n_labels = lgl_template_frame_get_n_labels (frame);
533         origins = g_new0 (lglTemplateOrigin, n_labels);
534
535         i_label = 0;
536         for ( p=frame->all.layouts; p != NULL; p=p->next ) {
537                 layout = (lglTemplateLayout *)p->data;
538
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;
543                         }
544                 }
545         }
546
547         g_qsort_with_data (origins, n_labels, sizeof(lglTemplateOrigin),
548                            compare_origins, NULL);
549
550         return origins;
551 }
552
553
554 /**
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.
558  *
559  * This function adds a layout structure to the given template frame.
560  *
561  */
562 void
563 lgl_template_frame_add_layout (lglTemplateFrame   *frame,
564                                lglTemplateLayout  *layout)
565 {
566         g_return_if_fail (frame);
567         g_return_if_fail (layout);
568
569         frame->all.layouts = g_list_append (frame->all.layouts, layout);
570 }
571  
572
573 /**
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.
577  *
578  * This function adds a markup structure to the given template frame.
579  *
580  */
581 void
582 lgl_template_frame_add_markup (lglTemplateFrame   *frame,
583                                lglTemplateMarkup  *markup)
584 {
585         g_return_if_fail (frame);
586         g_return_if_fail (markup);
587
588         frame->all.markups = g_list_append (frame->all.markups, markup);
589 }
590  
591
592 /**
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.
600  *
601  * This function creates a new layout structure with the given parameters.
602  *
603  * Returns: a newly allocated #lglTemplateLayout structure.
604  *
605  */
606 lglTemplateLayout *
607 lgl_template_layout_new (gint    nx,
608                          gint    ny,
609                          gdouble x0,
610                          gdouble y0,
611                          gdouble dx,
612                          gdouble dy)
613 {
614         lglTemplateLayout *layout;
615
616         layout = g_new0 (lglTemplateLayout, 1);
617
618         layout->nx = nx;
619         layout->ny = ny;
620         layout->x0 = x0;
621         layout->y0 = y0;
622         layout->dx = dx;
623         layout->dy = dy;
624
625         return layout;
626 }
627
628
629 /**
630  * lgl_template_markup_margin_new:
631  *   @size: margin size in points.
632  *
633  * This function creates a new margin markup structure.
634  *
635  * Returns: a newly allocated #lglTemplateMarkup structure.
636  *
637  */
638 lglTemplateMarkup *
639 lgl_template_markup_margin_new (gdouble size)
640 {
641         lglTemplateMarkup *markup;
642
643         markup = g_new0 (lglTemplateMarkup, 1);
644
645         markup->type        = LGL_TEMPLATE_MARKUP_MARGIN;
646         markup->margin.size = size;
647
648         return markup;
649 }
650
651
652 /**
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.
658  *
659  * This function creates a new line markup structure.
660  *
661  * Returns: a newly allocated #lglTemplateMarkup structure.
662  *
663  */
664 lglTemplateMarkup *
665 lgl_template_markup_line_new (gdouble x1,
666                               gdouble y1,
667                               gdouble x2,
668                               gdouble y2)
669 {
670         lglTemplateMarkup *markup;
671
672         markup = g_new0 (lglTemplateMarkup, 1);
673
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;
679
680         return markup;
681 }
682
683
684 /**
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.
689  *
690  * This function creates a new circle markup structure.
691  *
692  * Returns: a newly allocated #lglTemplateMarkup structure.
693  *
694  */
695 lglTemplateMarkup *
696 lgl_template_markup_circle_new (gdouble x0,
697                                 gdouble y0,
698                                 gdouble r)
699 {
700         lglTemplateMarkup *markup;
701
702         markup = g_new0 (lglTemplateMarkup, 1);
703
704         markup->type        = LGL_TEMPLATE_MARKUP_CIRCLE;
705         markup->circle.x0   = x0;
706         markup->circle.y0   = y0;
707         markup->circle.r    = r;
708
709         return markup;
710 }
711
712
713 /**
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.
720  *
721  * This function creates a new rectangle markup structure.
722  *
723  * Returns: a newly allocated #lglTemplateMarkup structure.
724  *
725  */
726 lglTemplateMarkup *
727 lgl_template_markup_rect_new (gdouble x1,
728                               gdouble y1,
729                               gdouble w,
730                               gdouble h,
731                               gdouble r)
732 {
733         lglTemplateMarkup *markup;
734
735         markup = g_new0 (lglTemplateMarkup, 1);
736
737         markup->type        = LGL_TEMPLATE_MARKUP_RECT;
738         markup->rect.x1     = x1;
739         markup->rect.y1     = y1;
740         markup->rect.w      = w;
741         markup->rect.h      = h;
742         markup->rect.r      = r;
743
744         return markup;
745 }
746
747
748 /**
749  * lgl_template_dup:
750  *   @orig_template: Template to duplicate.
751  *
752  * This function duplicates a template structure.
753  *
754  * Returns:  a newly allocated #lglTemplate structure.
755  *
756  */
757 lglTemplate *
758 lgl_template_dup (const lglTemplate *orig_template)
759 {
760         lglTemplate         *template;
761         lglTemplateAlias    *alias;
762         GList               *p;
763         lglTemplateFrame    *frame;
764
765         g_return_val_if_fail (orig_template, NULL);
766
767         template = lgl_template_new (orig_template->brand,
768                                      orig_template->part,
769                                      orig_template->description,
770                                      orig_template->paper_id,
771                                      orig_template->page_width,
772                                      orig_template->page_height);
773
774         for ( p=orig_template->aliases; p != NULL; p=p->next )
775         {
776                 alias = (lglTemplateAlias *)p->data;
777
778                 if ( !(UTF8_EQUAL (template->brand, alias->brand) &&
779                        UTF8_EQUAL (template->part, alias->part)) )
780                 {
781                         lgl_template_add_alias (template, lgl_template_alias_dup (alias));
782                 }
783
784         }
785
786         for ( p=orig_template->category_ids; p != NULL; p=p->next )
787         {
788                 lgl_template_add_category (template, p->data);
789         }
790
791         for ( p=orig_template->frames; p != NULL; p=p->next )
792         {
793                 frame = (lglTemplateFrame *)p->data;
794
795                 lgl_template_add_frame (template, lgl_template_frame_dup (frame));
796         }
797
798         return template;
799 }
800
801
802 /**
803  * lgl_template_free:
804  *   @template: Template to free.
805  *
806  * This function frees all memory associated with given template structure.
807  *
808  */
809 void
810 lgl_template_free (lglTemplate *template)
811 {
812         GList            *p;
813         lglTemplateFrame *frame;
814
815         if ( template != NULL ) {
816
817                 g_free (template->brand);
818                 template->brand = NULL;
819
820                 g_free (template->part);
821                 template->part = NULL;
822
823                 g_free (template->description);
824                 template->description = NULL;
825
826                 g_free (template->paper_id);
827                 template->paper_id = NULL;
828
829                 for ( p=template->aliases; p != NULL; p=p->next ) {
830
831                         lgl_template_alias_free (p->data);
832                         p->data = NULL;
833
834                 }
835                 g_list_free (template->aliases);
836                 template->aliases = NULL;
837
838                 for ( p=template->category_ids; p != NULL; p=p->next ) {
839
840                         g_free (p->data);
841                         p->data = NULL;
842
843                 }
844                 g_list_free (template->category_ids);
845                 template->category_ids = NULL;
846
847                 for ( p=template->frames; p != NULL; p=p->next ) {
848
849                         frame = (lglTemplateFrame *)p->data;
850
851                         lgl_template_frame_free (frame);
852                         p->data = NULL;
853                 }
854                 g_list_free (template->frames);
855                 template->frames = NULL;
856
857                 g_free (template);
858
859         }
860
861 }
862
863
864 /**
865  * lgl_template_alias_dup:
866  *   @orig_alias: Alias to duplicate.
867  *
868  * This function duplicates a template alias structure.
869  *
870  * Returns:  a newly allocated #lglTemplateAlias structure.
871  *
872  */
873 lglTemplateAlias *
874 lgl_template_alias_dup (const lglTemplateAlias *orig_alias)
875 {
876         g_return_val_if_fail (orig_alias, NULL);
877
878         return lgl_template_alias_new (orig_alias->brand, orig_alias->part);
879 }
880
881
882 /**
883  * lgl_template_alias_free:
884  *   @alias: Alias to free.
885  *
886  * This function frees all memory associated with given template alias structure.
887  *
888  */
889 void
890 lgl_template_alias_free (lglTemplateAlias *alias)
891 {
892
893         if ( alias != NULL )
894         {
895                 g_free (alias->brand);
896                 alias->brand = NULL;
897
898                 g_free (alias->part);
899                 alias->part = NULL;
900
901                 g_free (alias);
902         }
903 }
904
905
906 /**
907  * lgl_template_frame_dup:
908  *   @orig_frame: Frame to duplicate.
909  *
910  * This function duplicates a template frame structure.
911  *
912  * Returns:  a newly allocated #lglTemplateFrame structure.
913  *
914  */
915 lglTemplateFrame *
916 lgl_template_frame_dup (const lglTemplateFrame *orig_frame)
917 {
918         lglTemplateFrame    *frame;
919         GList               *p;
920         lglTemplateLayout   *layout;
921         lglTemplateMarkup   *markup;
922
923         g_return_val_if_fail (orig_frame, NULL);
924
925         switch (orig_frame->shape) {
926
927         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
928                 frame =
929                         lgl_template_frame_rect_new (orig_frame->all.id,
930                                                      orig_frame->rect.w,
931                                                      orig_frame->rect.h,
932                                                      orig_frame->rect.r,
933                                                      orig_frame->rect.x_waste,
934                                                      orig_frame->rect.y_waste);
935                 break;
936
937         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
938                 frame =
939                         lgl_template_frame_round_new (orig_frame->all.id,
940                                                       orig_frame->round.r,
941                                                       orig_frame->round.waste);
942                 break;
943
944         case LGL_TEMPLATE_FRAME_SHAPE_CD:
945                 frame =
946                         lgl_template_frame_cd_new (orig_frame->all.id,
947                                                    orig_frame->cd.r1,
948                                                    orig_frame->cd.r2,
949                                                    orig_frame->cd.w,
950                                                    orig_frame->cd.h,
951                                                    orig_frame->cd.waste);
952                 break;
953
954         default:
955                 return NULL;
956                 break;
957         }
958
959         for ( p=orig_frame->all.layouts; p != NULL; p=p->next ) {
960
961                 layout = (lglTemplateLayout *)p->data;
962
963                 lgl_template_frame_add_layout (frame, lgl_template_layout_dup (layout));
964         }
965
966         for ( p=orig_frame->all.markups; p != NULL; p=p->next ) {
967
968                 markup = (lglTemplateMarkup *)p->data;
969
970                 lgl_template_frame_add_markup (frame, lgl_template_markup_dup (markup));
971         }
972
973         return frame;
974 }
975
976
977 /**
978  * lgl_template_frame_free:
979  *   @frame: Frame to free.
980  *
981  * This function frees all memory associated with given template frame structure.
982  *
983  */
984 void
985 lgl_template_frame_free (lglTemplateFrame *frame)
986 {
987         GList                *p;
988         lglTemplateLayout    *layout;
989         lglTemplateMarkup    *markup;
990
991         if ( frame != NULL ) {
992
993                 g_free (frame->all.id);
994                 frame->all.id = NULL;
995
996                 for ( p=frame->all.layouts; p != NULL; p=p->next ) {
997
998                         layout = (lglTemplateLayout *)p->data;
999
1000                         lgl_template_layout_free (layout);
1001                         p->data = NULL;
1002                 }
1003                 g_list_free (frame->all.layouts);
1004                 frame->all.layouts = NULL;
1005
1006                 for ( p=frame->all.markups; p != NULL; p=p->next ) {
1007
1008                         markup = (lglTemplateMarkup *)p->data;
1009
1010                         lgl_template_markup_free (markup);
1011                         p->data = NULL;
1012                 }
1013                 g_list_free (frame->all.markups);
1014                 frame->all.markups = NULL;
1015
1016                 g_free (frame);
1017
1018         }
1019
1020 }
1021
1022
1023 /**
1024  * lgl_template_layout_dup:
1025  *   @orig_layout: Layout to duplicate.
1026  *
1027  * This function duplicates a template layout structure.
1028  *
1029  * Returns:  a newly allocated #lglTemplateLayout structure.
1030  *
1031  */
1032 lglTemplateLayout *
1033 lgl_template_layout_dup (const lglTemplateLayout *orig_layout)
1034 {
1035         lglTemplateLayout *layout;
1036
1037         g_return_val_if_fail (orig_layout, NULL);
1038
1039         layout = g_new0 (lglTemplateLayout, 1);
1040
1041         /* copy contents */
1042         *layout = *orig_layout;
1043
1044         return layout;
1045 }
1046
1047
1048 /**
1049  * lgl_template_layout_free:
1050  *   @layout: Layout to free.
1051  *
1052  * This function frees all memory associated with given template layout structure.
1053  *
1054  */
1055 void
1056 lgl_template_layout_free (lglTemplateLayout *layout)
1057 {
1058         g_free (layout);
1059 }
1060
1061
1062 /**
1063  * lgl_template_markup_dup:
1064  *   @orig_markup: Markup to duplicate.
1065  *
1066  * This function duplicates a template markup structure.
1067  *
1068  * Returns:  a newly allocated #lglTemplateMarkup structure.
1069  *
1070  */
1071 lglTemplateMarkup *
1072 lgl_template_markup_dup (const lglTemplateMarkup *orig_markup)
1073 {
1074         lglTemplateMarkup *markup;
1075
1076         g_return_val_if_fail (orig_markup, NULL);
1077
1078         markup = g_new0 (lglTemplateMarkup, 1);
1079
1080         *markup = *orig_markup;
1081
1082         return markup;
1083 }
1084
1085
1086 /**
1087  * lgl_template_markup_free:
1088  *   @markup: Markup to free.
1089  *
1090  * This function frees all memory associated with given template markup structure.
1091  *
1092  */
1093 void
1094 lgl_template_markup_free (lglTemplateMarkup *markup)
1095 {
1096         g_free (markup);
1097 }
1098
1099
1100 static gint
1101 compare_origins (gconstpointer a,
1102                  gconstpointer b,
1103                  gpointer      user_data)
1104 {
1105         const lglTemplateOrigin *a_origin = a, *b_origin = b;
1106
1107         if ( a_origin->y < b_origin->y ) {
1108                 return -1;
1109         } else if ( a_origin->y > b_origin->y ) {
1110                 return +1;
1111         } else {
1112                 if ( a_origin->x < b_origin->x ) {
1113                         return -1;
1114                 } else if ( a_origin->x > b_origin->x ) {
1115                         return +1;
1116                 } else {
1117                         return 0; /* hopefully 2 labels won't have the same origin */
1118                 }
1119         }
1120 }
1121