]> git.sur5r.net Git - glabels/blob - libglabels/lgl-template.c
Upload to unstable
[glabels] / libglabels / lgl-template.c
1 /*
2  *  lgl-template.c
3  *  Copyright (C) 2001-2010  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of libglabels.
6  *
7  *  libglabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  libglabels 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 Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with libglabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "lgl-template.h"
24
25 #include <glib/gi18n.h>
26 #include <glib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <math.h>
31
32 #include "libglabels-private.h"
33
34 #include "lgl-db.h"
35 #include "lgl-paper.h"
36
37 /*===========================================*/
38 /* Private macros and constants.             */
39 /*===========================================*/
40
41 /* Allowed error when comparing dimensions. (0.5pts ~= .007in ~= .2mm) */
42 #define EPSILON 0.5
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 categories, or frames associated with
77  * it.  See lgl_template_add_category() and lgl_template_add_frame() to add
78  * 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
93         template = g_new0 (lglTemplate,1);
94
95         template->brand       = g_strdup (brand);
96         template->part        = g_strdup (part);
97         template->description = g_strdup (description);
98         template->paper_id    = g_strdup (paper_id);
99         template->page_width  = page_width;
100         template->page_height = page_height;
101
102         return template;
103 }
104
105
106 /**
107  * lgl_template_new_from_equiv:
108  *   @brand:        Template brand
109  *   @part:         Template part name/number
110  *   @equiv_part:   Name of equivalent part to base template on
111  *
112  * Create a new template structure based on an existing template.  The
113  * created template will be a duplicate of the original template, except with
114  * the new part name/number.
115  *
116  * Returns: pointer to a newly allocated #lglTemplate structure.
117  *
118  */
119 lglTemplate *
120 lgl_template_new_from_equiv (const gchar          *brand,
121                              const gchar          *part,
122                              const gchar          *equiv_part)
123 {
124         lglTemplate      *template = NULL;
125
126         if ( lgl_db_does_template_exist (brand, equiv_part) )
127         {
128                 template = lgl_db_lookup_template_from_brand_part (brand, equiv_part);
129
130                 g_free (template->part);
131                 g_free (template->equiv_part);
132
133                 template->part       = g_strdup (part);
134                 template->equiv_part = g_strdup (equiv_part);
135         }
136         else
137         {
138                 g_message ("Equivalent part (\"%s\") for \"%s\", not previously defined.",
139                            equiv_part, part);
140         }
141
142         return template;
143 }
144
145
146 /**
147  * lgl_template_get_name:
148  *   @template:  Pointer to template structure to test
149  *
150  * This function returns the name of the given template.  The name is the concetenation
151  * of the brand and part name/number.
152  *
153  * Returns:  A pointer to a newly allocated name string.  Should be freed with g_free().
154  *
155  */
156 gchar *
157 lgl_template_get_name (const lglTemplate  *template)
158 {
159         g_return_val_if_fail (template, NULL);
160
161         return g_strdup_printf ("%s %s", template->brand, template->part);
162 }
163
164
165 /**
166  * lgl_template_do_templates_match:
167  *   @template1:  Pointer to 1st template structure to test
168  *   @template2:  Pointer to 2nd template structure to test
169  *
170  * This function tests if the given templates match.  This is a simple test that only tests
171  * the brand and part name/number. It does not test if they are actually identical.
172  *
173  * Returns:  TRUE if the two templates match.
174  *
175  */
176 gboolean
177 lgl_template_do_templates_match (const lglTemplate  *template1,
178                                  const lglTemplate  *template2)
179 {
180         g_return_val_if_fail (template1, FALSE);
181         g_return_val_if_fail (template2, FALSE);
182
183         return (UTF8_EQUAL (template1->brand, template2->brand) &&
184                 UTF8_EQUAL (template1->part, template2->part));
185 }
186
187
188 /**
189  * lgl_template_does_brand_match:
190  *   @template:  Pointer to template structure to test
191  *   @brand:     Brand string
192  *
193  * This function tests if the brand of the template matches the given brand.
194  *
195  * Returns:  TRUE if the template matches the given brand.
196  *
197  */
198 gboolean
199 lgl_template_does_brand_match (const lglTemplate  *template,
200                                const gchar        *brand)
201 {
202         g_return_val_if_fail (template, FALSE);
203
204         /* NULL matches everything. */
205         if (brand == NULL)
206         {
207                 return TRUE;
208         }
209
210         return UTF8_EQUAL (template->brand, brand);
211 }
212
213
214 /**
215  * lgl_template_does_page_size_match:
216  *   @template:  Pointer to template structure to test
217  *   @paper_id:  Page size ID string
218  *
219  * This function tests if the page size of the template matches the given ID.
220  *
221  * Returns:  TRUE if the template matches the given page size ID.
222  *
223  */
224 gboolean
225 lgl_template_does_page_size_match (const lglTemplate  *template,
226                                    const gchar        *paper_id)
227 {
228         g_return_val_if_fail (template, FALSE);
229
230         /* NULL matches everything. */
231         if (paper_id == NULL)
232         {
233                 return TRUE;
234         }
235
236         return ASCII_EQUAL(paper_id, template->paper_id);
237 }
238
239
240 /**
241  * lgl_template_does_category_match:
242  *   @template:     Pointer to template structure to test
243  *   @category_id:  Category ID string
244  *
245  * This function tests if the given template belongs to the given category ID.
246  *
247  * Returns:  TRUE if the template matches the given category ID.
248  *
249  */
250 gboolean
251 lgl_template_does_category_match  (const lglTemplate  *template,
252                                    const gchar        *category_id)
253 {
254         GList *p;
255
256         g_return_val_if_fail (template, FALSE);
257
258         /* NULL matches everything. */
259         if (category_id == NULL)
260         {
261                 return TRUE;
262         }
263
264         for ( p=template->category_ids; p != NULL; p=p->next )
265         {
266                 if (ASCII_EQUAL(category_id, p->data))
267                 {
268                         return TRUE;
269                 }
270         }
271
272         return FALSE;
273 }
274
275
276 /**
277  * lgl_template_are_templates_identical:
278  *   @template1:  Pointer to 1st template structure to test
279  *   @template2:  Pointer to 2nd template structure to test
280  *
281  * This function tests if the given templates have identical size and layout properties.
282  *
283  * Returns:  TRUE if the two templates are identical.
284  *
285  */
286 gboolean
287 lgl_template_are_templates_identical (const lglTemplate   *template1,
288                                       const lglTemplate   *template2)
289 {
290         lglTemplateFrame  *frame1;
291         lglTemplateFrame  *frame2;
292         GList             *p1;
293         GList             *p2;
294         lglTemplateLayout *layout1;
295         lglTemplateLayout *layout2;
296         gboolean           match_found;
297
298
299         if (!UTF8_EQUAL (template1->paper_id, template2->paper_id) ||
300             (template1->page_width  != template2->page_width)      ||
301             (template1->page_height != template2->page_height))
302         {
303                 return FALSE;
304         }
305
306         frame1 = (lglTemplateFrame *)template1->frames->data;
307         frame2 = (lglTemplateFrame *)template2->frames->data;
308
309         if ( frame1->shape != frame2->shape )
310         {
311                 return FALSE;
312         }
313
314         switch ( frame1->shape )
315         {
316
317         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
318                 if ( (fabs(frame1->rect.w - frame2->rect.w) > EPSILON) ||
319                      (fabs(frame1->rect.h - frame2->rect.h) > EPSILON) )
320                 {
321                         return FALSE;
322                 }
323                 break;
324
325         case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
326                 if ( (fabs(frame1->ellipse.w - frame2->ellipse.w) > EPSILON) ||
327                      (fabs(frame1->ellipse.h - frame2->ellipse.h) > EPSILON) )
328                 {
329                         return FALSE;
330                 }
331                 break;
332
333         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
334                 if ( fabs(frame1->round.r - frame2->round.r) > EPSILON )
335                 {
336                         return FALSE;
337                 }
338                 break;
339
340         case LGL_TEMPLATE_FRAME_SHAPE_CD:
341                 if ( (fabs(frame1->cd.r1 - frame2->cd.r1) > EPSILON) ||
342                      (fabs(frame1->cd.r2 - frame2->cd.r2) > EPSILON) )
343                 {
344                         return FALSE;
345                 }
346         }
347
348         for ( p1 = frame1->all.layouts; p1; p1 = p1->next )
349         {
350                 layout1 = (lglTemplateLayout *)p1->data;
351
352                 match_found = FALSE;
353                 for ( p2 = frame2->all.layouts; p2 && !match_found; p2 = p2->next )
354                 {
355                         layout2 = (lglTemplateLayout *)p2->data;
356
357                         if ( (layout1->nx == layout2->nx) &&
358                              (layout1->ny == layout2->ny) &&
359                              (fabs(layout1->x0 - layout2->x0) < EPSILON) &&
360                              (fabs(layout1->y0 - layout2->y0) < EPSILON) &&
361                              (fabs(layout1->dx - layout2->dx) < EPSILON) &&
362                              (fabs(layout1->dy - layout2->dy) < EPSILON) )
363                         {
364                                 match_found = TRUE;
365                         }
366
367                 }
368                 if ( !match_found )
369                 {
370                         return FALSE;
371                 }
372         }
373
374         return TRUE;
375 }
376
377
378 /**
379  * lgl_template_add_frame:
380  *   @template:  Pointer to template structure
381  *   @frame:     Pointer to frame structure
382  *
383  * This function adds the given frame structure to the template.  Once added,
384  * the frame structure belongs to the given template; do not attempt to free
385  * it.
386  *
387  * Note: Currently glabels only supports a single frame per template.
388  *
389  */
390 void
391 lgl_template_add_frame (lglTemplate      *template,
392                         lglTemplateFrame *frame)
393 {
394         g_return_if_fail (template);
395         g_return_if_fail (frame);
396
397         template->frames = g_list_append (template->frames, frame);
398 }
399
400  
401 /**
402  * lgl_template_add_category:
403  *   @template:     Pointer to template structure
404  *   @category_id:  Category ID string
405  *
406  * This function adds the given category ID to a templates category list.
407  *
408  */
409 void
410 lgl_template_add_category (lglTemplate         *template,
411                            const gchar         *category_id)
412 {
413         g_return_if_fail (template);
414         g_return_if_fail (category_id);
415
416         template->category_ids = g_list_append (template->category_ids,
417                                                 g_strdup (category_id));
418 }
419
420  
421 /**
422  * lgl_template_frame_rect_new:
423  *   @id:      ID of frame.  (This should currently always be "0").
424  *   @w:       width of frame in points.
425  *   @h:       height of frame in points.
426  *   @r:       radius of rounded corners in points.  (Should be 0 for square corners.)
427  *   @x_waste: Amount of overprint to allow in the horizontal direction.
428  *   @y_waste: Amount of overprint to allow in the vertical direction.
429  *
430  * This function creates a new template frame for a rectangular label or card.
431  *
432  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
433  *
434  */
435 lglTemplateFrame *
436 lgl_template_frame_rect_new  (const gchar         *id,
437                               gdouble              w,
438                               gdouble              h,
439                               gdouble              r,
440                               gdouble              x_waste,
441                               gdouble              y_waste)
442 {
443         lglTemplateFrame *frame;
444
445         frame = g_new0 (lglTemplateFrame, 1);
446
447         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_RECT;
448         frame->rect.id = g_strdup (id);
449
450         frame->rect.w = w;
451         frame->rect.h = h;
452         frame->rect.r = r;
453         frame->rect.x_waste = x_waste;
454         frame->rect.y_waste = y_waste;
455
456         return frame;
457 }
458
459
460 /**
461  * lgl_template_frame_ellipse_new:
462  *   @id:      ID of frame.  (This should currently always be "0").
463  *   @w:       width of frame in points.
464  *   @h:       height of frame in points.
465  *   @waste:   Amount of overprint to allow in points.
466  *
467  * This function creates a new template frame for an elliptical label or card.
468  *
469  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
470  *
471  */
472 lglTemplateFrame *
473 lgl_template_frame_ellipse_new  (const gchar         *id,
474                                  gdouble              w,
475                                  gdouble              h,
476                                  gdouble              waste)
477 {
478         lglTemplateFrame *frame;
479
480         frame = g_new0 (lglTemplateFrame, 1);
481
482         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE;
483         frame->ellipse.id = g_strdup (id);
484
485         frame->ellipse.w = w;
486         frame->ellipse.h = h;
487         frame->ellipse.waste = waste;
488
489         return frame;
490 }
491
492
493 /**
494  * lgl_template_frame_round_new:
495  *   @id:      ID of frame.  (This should currently always be "0").
496  *   @r:       radius of label in points.
497  *   @waste:   Amount of overprint to allow.
498  *
499  * This function creates a new template frame for a round label.
500  *
501  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
502  *
503  */
504 lglTemplateFrame *
505 lgl_template_frame_round_new (const gchar         *id,
506                               gdouble              r,
507                               gdouble              waste)
508 {
509         lglTemplateFrame *frame;
510
511         frame = g_new0 (lglTemplateFrame, 1);
512
513         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_ROUND;
514         frame->round.id = g_strdup (id);
515
516         frame->round.r = r;
517         frame->round.waste = waste;
518
519         return frame;
520 }
521
522                                                                                
523 /**
524  * lgl_template_frame_cd_new:
525  *   @id:      ID of frame.  (This should currently always be "0").
526  *   @r1:      outer radius of label in points.
527  *   @r2:      radius of center hole in points.
528  *   @w:       clip width of frame in points for business card CDs.  Should be 0 for no clipping.
529  *   @h:       clip height of frame in points for business card CDs.  Should be 0 for no clipping.
530  *   @waste:   Amount of overprint to allow.
531  *
532  * This function creates a new template frame for a CD/DVD label.
533  *
534  * Returns: Pointer to newly allocated #lglTemplateFrame structure.
535  *
536  */
537 lglTemplateFrame *
538 lgl_template_frame_cd_new (const gchar         *id,
539                            gdouble              r1,
540                            gdouble              r2,
541                            gdouble              w,
542                            gdouble              h,
543                            gdouble              waste)
544 {
545         lglTemplateFrame *frame;
546
547         frame = g_new0 (lglTemplateFrame, 1);
548
549         frame->shape = LGL_TEMPLATE_FRAME_SHAPE_CD;
550         frame->cd.id = g_strdup (id);
551
552         frame->cd.r1 = r1;
553         frame->cd.r2 = r2;
554         frame->cd.w  = w;
555         frame->cd.h  = h;
556         frame->cd.waste = waste;
557
558         return frame;
559 }
560
561
562 /**
563  * lgl_template_frame_get_size:
564  * @frame: #lglTemplateFrame structure to query
565  * @w: pointer to location to receive width of frame
566  * @h: pointer to location to receive height of frame
567  *
568  * Get size (width and height) of given #lglTemplateFrame in points.
569  *
570  */
571 void
572 lgl_template_frame_get_size (const lglTemplateFrame *frame,
573                              gdouble                *w,
574                              gdouble                *h)
575 {
576         g_return_if_fail (frame);
577
578         switch (frame->shape)
579         {
580         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
581                 *w = frame->rect.w;
582                 *h = frame->rect.h;
583                 break;
584         case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
585                 *w = frame->ellipse.w;
586                 *h = frame->ellipse.h;
587                 break;
588         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
589                 *w = 2.0 * frame->round.r;
590                 *h = 2.0 * frame->round.r;
591                 break;
592         case LGL_TEMPLATE_FRAME_SHAPE_CD:
593                 if (frame->cd.w == 0.0)
594                 {
595                         *w = 2.0 * frame->cd.r1;
596                 }
597                 else
598                 {
599                         *w = frame->cd.w;
600                 }
601                 if (frame->cd.h == 0.0)
602                 {
603                         *h = 2.0 * frame->cd.r1;
604                 }
605                 else
606                 {
607                         *h = frame->cd.h;
608                 }
609                 break;
610         default:
611                 *w = 0.0;
612                 *h = 0.0;
613                 break;
614         }
615 }
616
617
618 /**
619  * lgl_template_frame_get_n_labels:
620  * @frame: #lglTemplateFrame structure to query
621  *
622  * Get total number of labels per sheet corresponding to the given frame.
623  *
624  * Returns: number of labels per sheet.
625  *
626  */
627 gint
628 lgl_template_frame_get_n_labels (const lglTemplateFrame *frame)
629 {
630         gint               n_labels = 0;
631         GList             *p;
632         lglTemplateLayout *layout;
633
634         g_return_val_if_fail (frame, 0);
635
636         for ( p=frame->all.layouts; p != NULL; p=p->next )
637         {
638                 layout = (lglTemplateLayout *)p->data;
639
640                 n_labels += layout->nx * layout->ny;
641         }
642
643         return n_labels;
644 }
645
646
647 /**
648  * lgl_template_frame_get_layout_description
649  * @frame: #lglTemplateFrame structure to query
650  *
651  * Get a description of the label layout including number of labels per sheet.
652  *
653  * Returns: a newly allocation description string.
654  *
655  */
656 gchar *
657 lgl_template_frame_get_layout_description (const lglTemplateFrame *frame)
658 {
659         gint                    n_labels;
660         gchar                  *string;
661         lglTemplateLayout      *layout;
662
663         n_labels = lgl_template_frame_get_n_labels (frame);
664
665         if ( frame->all.layouts && (frame->all.layouts->next == NULL) )
666         {
667                 layout = (lglTemplateLayout *)frame->all.layouts->data;
668                 /*
669                  * Translators: 1st %d = number of labels across a page,
670                  *              2nd %d = number of labels down a page,
671                  *              3rd %d = total number of labels on a page (sheet).
672                  */
673                 string = g_strdup_printf (_("%d Ã— %d (%d per sheet)"), layout->nx, layout->ny, n_labels);
674         }
675         else
676         {
677                 /* Translators: %d is the total number of labels on a page (sheet). */
678                 string = g_strdup_printf (_("%d per sheet"), n_labels);
679         }
680
681         return string;
682 }
683
684
685 /**
686  * lgl_template_frame_get_size_description
687  * @frame: #lglTemplateFrame structure to query
688  * @units: #lglUnits
689  *
690  * Get a description of the label size.
691  *
692  * Returns: a newly allocation description string.
693  *
694  */
695 gchar *
696 lgl_template_frame_get_size_description (const lglTemplateFrame *frame,
697                                          lglUnits                units)
698 {
699         const gchar               *units_string;
700         gdouble                    units_per_point;
701         gchar                     *string = NULL;
702
703         units_string    = lgl_units_get_name (units);
704         units_per_point = lgl_units_get_units_per_point (units);
705
706         switch (frame->shape)
707         {
708
709         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
710                 if ( units == LGL_UNITS_INCH )
711                 {
712                         gchar *xstr, *ystr;
713
714                         xstr = lgl_str_format_fraction (frame->rect.w*units_per_point);
715                         ystr = lgl_str_format_fraction (frame->rect.h*units_per_point);
716                         string = g_strdup_printf ("%s Ã— %s %s",
717                                                   xstr, ystr, units_string);
718                         g_free (xstr);
719                         g_free (ystr);
720                 }
721                 else
722                 {
723                         string = g_strdup_printf ("%.5g Ã— %.5g %s",
724                                                   frame->rect.w*units_per_point,
725                                                   frame->rect.h*units_per_point,
726                                                   units_string);
727                 }
728                 break;
729
730         case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
731                 if ( units == LGL_UNITS_INCH )
732                 {
733                         gchar *xstr, *ystr;
734
735                         xstr = lgl_str_format_fraction (frame->ellipse.w*units_per_point);
736                         ystr = lgl_str_format_fraction (frame->ellipse.h*units_per_point);
737                         string = g_strdup_printf ("%s Ã— %s %s",
738                                                   xstr, ystr, units_string);
739                         g_free (xstr);
740                         g_free (ystr);
741                 }
742                 else
743                 {
744                         string = g_strdup_printf ("%.5g Ã— %.5g %s",
745                                                   frame->ellipse.w*units_per_point,
746                                                   frame->ellipse.h*units_per_point,
747                                                   units_string);
748                 }
749                 break;
750
751         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
752                 if ( units == LGL_UNITS_INCH )
753                 {
754                         gchar *dstr;
755
756                         dstr = lgl_str_format_fraction (2.0*frame->round.r*units_per_point);
757                         string = g_strdup_printf ("%s %s %s",
758                                                   dstr, units_string,
759                                                   _("diameter"));
760                         g_free (dstr);
761                 }
762                 else
763                 {
764                         string = g_strdup_printf ("%.5g %s %s",
765                                                   2.0*frame->round.r*units_per_point,
766                                                   units_string,
767                                                   _("diameter"));
768                 }
769                 break;
770
771         case LGL_TEMPLATE_FRAME_SHAPE_CD:
772                 if ( units == LGL_UNITS_INCH )
773                 {
774                         gchar *dstr;
775
776                         dstr = lgl_str_format_fraction (2.0*frame->cd.r1*units_per_point);
777                         string = g_strdup_printf ("%s %s %s",
778                                                   dstr, units_string,
779                                                   _("diameter"));
780                         g_free (dstr);
781                 }
782                 else
783                 {
784                         string = g_strdup_printf ("%.5g %s %s",
785                                                   2.0*frame->cd.r1*units_per_point,
786                                                   units_string,
787                                                   _("diameter"));
788                 }
789                 break;
790
791         default:
792                 break;
793
794         }
795
796         return string;
797 }
798
799
800 /**
801  * lgl_template_frame_get_origins:
802  * @frame: #lglTemplateFrame structure to query
803  *
804  * Get an array of label origins for the given frame.  These origins represent the
805  * upper left hand corner of each label on a page corresponding to the given frame.
806  * The origins will be ordered geometrically left to right and then top to bottom.
807  * The array should be freed using g_free().
808  *
809  * Returns: A newly allocated array of #lglTemplateOrigin structures.
810  *
811  */
812 lglTemplateOrigin *
813 lgl_template_frame_get_origins (const lglTemplateFrame *frame)
814 {
815         gint               i_label, n_labels, ix, iy;
816         lglTemplateOrigin *origins;
817         GList             *p;
818         lglTemplateLayout *layout;
819
820         g_return_val_if_fail (frame, NULL);
821
822         n_labels = lgl_template_frame_get_n_labels (frame);
823         origins = g_new0 (lglTemplateOrigin, n_labels);
824
825         i_label = 0;
826         for ( p=frame->all.layouts; p != NULL; p=p->next )
827         {
828                 layout = (lglTemplateLayout *)p->data;
829
830                 for (iy = 0; iy < layout->ny; iy++)
831                 {
832                         for (ix = 0; ix < layout->nx; ix++, i_label++)
833                         {
834                                 origins[i_label].x = ix*layout->dx + layout->x0;
835                                 origins[i_label].y = iy*layout->dy + layout->y0;
836                         }
837                 }
838         }
839
840         g_qsort_with_data (origins, n_labels, sizeof(lglTemplateOrigin),
841                            compare_origins, NULL);
842
843         return origins;
844 }
845
846
847 /**
848  * lgl_template_frame_add_layout:
849  *   @frame:  Pointer to template frame to add layout to.
850  *   @layout: Pointer to layout structure to add to frame.
851  *
852  * This function adds a layout structure to the given template frame.
853  *
854  */
855 void
856 lgl_template_frame_add_layout (lglTemplateFrame   *frame,
857                                lglTemplateLayout  *layout)
858 {
859         g_return_if_fail (frame);
860         g_return_if_fail (layout);
861
862         frame->all.layouts = g_list_append (frame->all.layouts, layout);
863 }
864  
865
866 /**
867  * lgl_template_frame_add_markup:
868  *   @frame:  Pointer to template frame to add markup to.
869  *   @markup: Pointer to markup structure to add to frame.
870  *
871  * This function adds a markup structure to the given template frame.
872  *
873  */
874 void
875 lgl_template_frame_add_markup (lglTemplateFrame   *frame,
876                                lglTemplateMarkup  *markup)
877 {
878         g_return_if_fail (frame);
879         g_return_if_fail (markup);
880
881         frame->all.markups = g_list_append (frame->all.markups, markup);
882 }
883  
884
885 /**
886  * lgl_template_layout_new:
887  *   @nx:  Number of labels across.
888  *   @ny:  Number of labels down.
889  *   @x0:  X coordinate of the top-left corner of the top-left label in the layout in points.
890  *   @y0:  Y coordinate of the top-left corner of the top-left label in the layout in points.
891  *   @dx:  Horizontal pitch in points.  This is the distance from left-edge to left-edge.
892  *   @dy:  Vertical pitch in points.  This is the distance from top-edge to top-edge.
893  *
894  * This function creates a new layout structure with the given parameters.
895  *
896  * Returns: a newly allocated #lglTemplateLayout structure.
897  *
898  */
899 lglTemplateLayout *
900 lgl_template_layout_new (gint    nx,
901                          gint    ny,
902                          gdouble x0,
903                          gdouble y0,
904                          gdouble dx,
905                          gdouble dy)
906 {
907         lglTemplateLayout *layout;
908
909         layout = g_new0 (lglTemplateLayout, 1);
910
911         layout->nx = nx;
912         layout->ny = ny;
913         layout->x0 = x0;
914         layout->y0 = y0;
915         layout->dx = dx;
916         layout->dy = dy;
917
918         return layout;
919 }
920
921
922 /**
923  * lgl_template_markup_margin_new:
924  *   @size: margin size in points.
925  *
926  * This function creates a new margin markup structure.
927  *
928  * Returns: a newly allocated #lglTemplateMarkup structure.
929  *
930  */
931 lglTemplateMarkup *
932 lgl_template_markup_margin_new (gdouble size)
933 {
934         lglTemplateMarkup *markup;
935
936         markup = g_new0 (lglTemplateMarkup, 1);
937
938         markup->type        = LGL_TEMPLATE_MARKUP_MARGIN;
939         markup->margin.size = size;
940
941         return markup;
942 }
943
944
945 /**
946  * lgl_template_markup_line_new:
947  *   @x1: x coordinate of first endpoint.
948  *   @y1: y coordinate of first endpoint.
949  *   @x2: x coordinate of second endpoint.
950  *   @y2: y coordinate of second endpoint.
951  *
952  * This function creates a new line markup structure.
953  *
954  * Returns: a newly allocated #lglTemplateMarkup structure.
955  *
956  */
957 lglTemplateMarkup *
958 lgl_template_markup_line_new (gdouble x1,
959                               gdouble y1,
960                               gdouble x2,
961                               gdouble y2)
962 {
963         lglTemplateMarkup *markup;
964
965         markup = g_new0 (lglTemplateMarkup, 1);
966
967         markup->type        = LGL_TEMPLATE_MARKUP_LINE;
968         markup->line.x1     = x1;
969         markup->line.y1     = y1;
970         markup->line.x2     = x2;
971         markup->line.y2     = y2;
972
973         return markup;
974 }
975
976
977 /**
978  * lgl_template_markup_circle_new:
979  *   @x0: x coordinate of center of circle.
980  *   @y0: y coordinate of center of circle.
981  *   @r:  radius of circle.
982  *
983  * This function creates a new circle markup structure.
984  *
985  * Returns: a newly allocated #lglTemplateMarkup structure.
986  *
987  */
988 lglTemplateMarkup *
989 lgl_template_markup_circle_new (gdouble x0,
990                                 gdouble y0,
991                                 gdouble r)
992 {
993         lglTemplateMarkup *markup;
994
995         markup = g_new0 (lglTemplateMarkup, 1);
996
997         markup->type        = LGL_TEMPLATE_MARKUP_CIRCLE;
998         markup->circle.x0   = x0;
999         markup->circle.y0   = y0;
1000         markup->circle.r    = r;
1001
1002         return markup;
1003 }
1004
1005
1006 /**
1007  * lgl_template_markup_rect_new:
1008  *   @x1: x coordinate of top-left corner of rectangle.
1009  *   @y1: y coordinate of top-left corner of rectangle.
1010  *   @w:  width of rectangle.
1011  *   @h:  height of rectangle.
1012  *   @r:  radius of rounded corner.
1013  *
1014  * This function creates a new rectangle markup structure.
1015  *
1016  * Returns: a newly allocated #lglTemplateMarkup structure.
1017  *
1018  */
1019 lglTemplateMarkup *
1020 lgl_template_markup_rect_new (gdouble x1,
1021                               gdouble y1,
1022                               gdouble w,
1023                               gdouble h,
1024                               gdouble r)
1025 {
1026         lglTemplateMarkup *markup;
1027
1028         markup = g_new0 (lglTemplateMarkup, 1);
1029
1030         markup->type        = LGL_TEMPLATE_MARKUP_RECT;
1031         markup->rect.x1     = x1;
1032         markup->rect.y1     = y1;
1033         markup->rect.w      = w;
1034         markup->rect.h      = h;
1035         markup->rect.r      = r;
1036
1037         return markup;
1038 }
1039
1040
1041 /**
1042  * lgl_template_markup_ellipse_new:
1043  *   @x1: x coordinate of top-left corner of ellipse.
1044  *   @y1: y coordinate of top-left corner of ellipse.
1045  *   @w:  width of ellipse.
1046  *   @h:  height of ellipse.
1047  *
1048  * This function creates a new ellipse markup structure.
1049  *
1050  * Returns: a newly allocated #lglTemplateMarkup structure.
1051  *
1052  */
1053 lglTemplateMarkup *
1054 lgl_template_markup_ellipse_new (gdouble x1,
1055                                  gdouble y1,
1056                                  gdouble w,
1057                                  gdouble h)
1058 {
1059         lglTemplateMarkup *markup;
1060
1061         markup = g_new0 (lglTemplateMarkup, 1);
1062
1063         markup->type        = LGL_TEMPLATE_MARKUP_ELLIPSE;
1064         markup->ellipse.x1     = x1;
1065         markup->ellipse.y1     = y1;
1066         markup->ellipse.w      = w;
1067         markup->ellipse.h      = h;
1068
1069         return markup;
1070 }
1071
1072
1073 /**
1074  * lgl_template_dup:
1075  *   @orig_template: Template to duplicate.
1076  *
1077  * This function duplicates a template structure.
1078  *
1079  * Returns:  a newly allocated #lglTemplate structure.
1080  *
1081  */
1082 lglTemplate *
1083 lgl_template_dup (const lglTemplate *orig_template)
1084 {
1085         lglTemplate         *template;
1086         GList               *p;
1087         lglTemplateFrame    *frame;
1088
1089         g_return_val_if_fail (orig_template, NULL);
1090
1091         template = lgl_template_new (orig_template->brand,
1092                                      orig_template->part,
1093                                      orig_template->description,
1094                                      orig_template->paper_id,
1095                                      orig_template->page_width,
1096                                      orig_template->page_height);
1097
1098         template->equiv_part  = g_strdup (orig_template->equiv_part);
1099         template->product_url = g_strdup (orig_template->product_url);
1100
1101
1102         for ( p=orig_template->category_ids; p != NULL; p=p->next )
1103         {
1104                 lgl_template_add_category (template, p->data);
1105         }
1106
1107         for ( p=orig_template->frames; p != NULL; p=p->next )
1108         {
1109                 frame = (lglTemplateFrame *)p->data;
1110
1111                 lgl_template_add_frame (template, lgl_template_frame_dup (frame));
1112         }
1113
1114         return template;
1115 }
1116
1117
1118 /**
1119  * lgl_template_free:
1120  *   @template: Template to free.
1121  *
1122  * This function frees all memory associated with given template structure.
1123  *
1124  */
1125 void
1126 lgl_template_free (lglTemplate *template)
1127 {
1128         GList            *p;
1129         lglTemplateFrame *frame;
1130
1131         if ( template != NULL )
1132         {
1133                 g_free (template->brand);
1134                 template->brand = NULL;
1135
1136                 g_free (template->part);
1137                 template->part = NULL;
1138
1139                 g_free (template->description);
1140                 template->description = NULL;
1141
1142                 g_free (template->paper_id);
1143                 template->paper_id = NULL;
1144
1145                 for ( p=template->category_ids; p != NULL; p=p->next )
1146                 {
1147                         g_free (p->data);
1148                         p->data = NULL;
1149                 }
1150                 g_list_free (template->category_ids);
1151                 template->category_ids = NULL;
1152
1153                 for ( p=template->frames; p != NULL; p=p->next )
1154                 {
1155                         frame = (lglTemplateFrame *)p->data;
1156
1157                         lgl_template_frame_free (frame);
1158                         p->data = NULL;
1159                 }
1160                 g_list_free (template->frames);
1161                 template->frames = NULL;
1162
1163                 g_free (template);
1164
1165         }
1166
1167 }
1168
1169
1170 /**
1171  * lgl_template_frame_dup:
1172  *   @orig_frame: Frame to duplicate.
1173  *
1174  * This function duplicates a template frame structure.
1175  *
1176  * Returns:  a newly allocated #lglTemplateFrame structure.
1177  *
1178  */
1179 lglTemplateFrame *
1180 lgl_template_frame_dup (const lglTemplateFrame *orig_frame)
1181 {
1182         lglTemplateFrame    *frame;
1183         GList               *p;
1184         lglTemplateLayout   *layout;
1185         lglTemplateMarkup   *markup;
1186
1187         g_return_val_if_fail (orig_frame, NULL);
1188
1189         switch (orig_frame->shape)
1190         {
1191
1192         case LGL_TEMPLATE_FRAME_SHAPE_RECT:
1193                 frame =
1194                         lgl_template_frame_rect_new (orig_frame->all.id,
1195                                                      orig_frame->rect.w,
1196                                                      orig_frame->rect.h,
1197                                                      orig_frame->rect.r,
1198                                                      orig_frame->rect.x_waste,
1199                                                      orig_frame->rect.y_waste);
1200                 break;
1201
1202         case LGL_TEMPLATE_FRAME_SHAPE_ELLIPSE:
1203                 frame =
1204                         lgl_template_frame_ellipse_new (orig_frame->all.id,
1205                                                         orig_frame->ellipse.w,
1206                                                         orig_frame->ellipse.h,
1207                                                         orig_frame->ellipse.waste);
1208                 break;
1209
1210         case LGL_TEMPLATE_FRAME_SHAPE_ROUND:
1211                 frame =
1212                         lgl_template_frame_round_new (orig_frame->all.id,
1213                                                       orig_frame->round.r,
1214                                                       orig_frame->round.waste);
1215                 break;
1216
1217         case LGL_TEMPLATE_FRAME_SHAPE_CD:
1218                 frame =
1219                         lgl_template_frame_cd_new (orig_frame->all.id,
1220                                                    orig_frame->cd.r1,
1221                                                    orig_frame->cd.r2,
1222                                                    orig_frame->cd.w,
1223                                                    orig_frame->cd.h,
1224                                                    orig_frame->cd.waste);
1225                 break;
1226
1227         default:
1228                 return NULL;
1229                 break;
1230         }
1231
1232         for ( p=orig_frame->all.layouts; p != NULL; p=p->next )
1233         {
1234                 layout = (lglTemplateLayout *)p->data;
1235
1236                 lgl_template_frame_add_layout (frame, lgl_template_layout_dup (layout));
1237         }
1238
1239         for ( p=orig_frame->all.markups; p != NULL; p=p->next )
1240         {
1241                 markup = (lglTemplateMarkup *)p->data;
1242
1243                 lgl_template_frame_add_markup (frame, lgl_template_markup_dup (markup));
1244         }
1245
1246         return frame;
1247 }
1248
1249
1250 /**
1251  * lgl_template_frame_free:
1252  *   @frame: Frame to free.
1253  *
1254  * This function frees all memory associated with given template frame structure.
1255  *
1256  */
1257 void
1258 lgl_template_frame_free (lglTemplateFrame *frame)
1259 {
1260         GList                *p;
1261         lglTemplateLayout    *layout;
1262         lglTemplateMarkup    *markup;
1263
1264         if ( frame != NULL )
1265         {
1266
1267                 g_free (frame->all.id);
1268                 frame->all.id = NULL;
1269
1270                 for ( p=frame->all.layouts; p != NULL; p=p->next )
1271                 {
1272                         layout = (lglTemplateLayout *)p->data;
1273
1274                         lgl_template_layout_free (layout);
1275                         p->data = NULL;
1276                 }
1277                 g_list_free (frame->all.layouts);
1278                 frame->all.layouts = NULL;
1279
1280                 for ( p=frame->all.markups; p != NULL; p=p->next )
1281                 {
1282                         markup = (lglTemplateMarkup *)p->data;
1283
1284                         lgl_template_markup_free (markup);
1285                         p->data = NULL;
1286                 }
1287                 g_list_free (frame->all.markups);
1288                 frame->all.markups = NULL;
1289
1290                 g_free (frame);
1291
1292         }
1293
1294 }
1295
1296
1297 /**
1298  * lgl_template_layout_dup:
1299  *   @orig_layout: Layout to duplicate.
1300  *
1301  * This function duplicates a template layout structure.
1302  *
1303  * Returns:  a newly allocated #lglTemplateLayout structure.
1304  *
1305  */
1306 lglTemplateLayout *
1307 lgl_template_layout_dup (const lglTemplateLayout *orig_layout)
1308 {
1309         lglTemplateLayout *layout;
1310
1311         g_return_val_if_fail (orig_layout, NULL);
1312
1313         layout = g_new0 (lglTemplateLayout, 1);
1314
1315         /* copy contents */
1316         *layout = *orig_layout;
1317
1318         return layout;
1319 }
1320
1321
1322 /**
1323  * lgl_template_layout_free:
1324  *   @layout: Layout to free.
1325  *
1326  * This function frees all memory associated with given template layout structure.
1327  *
1328  */
1329 void
1330 lgl_template_layout_free (lglTemplateLayout *layout)
1331 {
1332         g_free (layout);
1333 }
1334
1335
1336 /**
1337  * lgl_template_markup_dup:
1338  *   @orig_markup: Markup to duplicate.
1339  *
1340  * This function duplicates a template markup structure.
1341  *
1342  * Returns:  a newly allocated #lglTemplateMarkup structure.
1343  *
1344  */
1345 lglTemplateMarkup *
1346 lgl_template_markup_dup (const lglTemplateMarkup *orig_markup)
1347 {
1348         lglTemplateMarkup *markup;
1349
1350         g_return_val_if_fail (orig_markup, NULL);
1351
1352         markup = g_new0 (lglTemplateMarkup, 1);
1353
1354         *markup = *orig_markup;
1355
1356         return markup;
1357 }
1358
1359
1360 /**
1361  * lgl_template_markup_free:
1362  *   @markup: Markup to free.
1363  *
1364  * This function frees all memory associated with given template markup structure.
1365  *
1366  */
1367 void
1368 lgl_template_markup_free (lglTemplateMarkup *markup)
1369 {
1370         g_free (markup);
1371 }
1372
1373
1374 static gint
1375 compare_origins (gconstpointer a,
1376                  gconstpointer b,
1377                  gpointer      user_data)
1378 {
1379         const lglTemplateOrigin *a_origin = a, *b_origin = b;
1380
1381         if ( a_origin->y < b_origin->y )
1382         {
1383                 return -1;
1384         }
1385         else if ( a_origin->y > b_origin->y )
1386         {
1387                 return +1;
1388         }
1389         else
1390         {
1391                 if ( a_origin->x < b_origin->x )
1392                 {
1393                         return -1;
1394                 }
1395                 else if ( a_origin->x > b_origin->x )
1396                 {
1397                         return +1;
1398                 }
1399                 else
1400                 {
1401                         return 0; /* hopefully 2 labels won't have the same origin */
1402                 }
1403         }
1404 }
1405
1406
1407 /**
1408  * lgl_template_print:
1409  *   @template: template
1410  *
1411  * Print template details (for debugging purposes).
1412  *
1413  */
1414 void
1415 lgl_template_print (const lglTemplate *template)
1416 {
1417         g_print ("---- %s( TEMPLATE=%p ) ----\n", __FUNCTION__, template);
1418
1419         g_print("brand=\"%s\", part=\"%s\", description=\"%s\"\n",
1420                 template->brand, template->part, template->description);
1421
1422         g_print("paper_id=\"%s\", page_width=%g, page_height=%g\n",
1423                 template->paper_id, template->page_width, template->page_height);
1424
1425         g_print ("\n");
1426
1427 }
1428
1429
1430
1431 /*
1432  * Local Variables:       -- emacs
1433  * mode: C                -- emacs
1434  * c-basic-offset: 8      -- emacs
1435  * tab-width: 8           -- emacs
1436  * indent-tabs-mode: nil  -- emacs
1437  * End:                   -- emacs
1438  */