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 *
lgl_template_new(const gchar * brand,const gchar * part,const gchar * description,const gchar * paper_id,gdouble page_width,gdouble page_height)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 *
lgl_template_new_from_equiv(const gchar * brand,const gchar * part,const gchar * equiv_part)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 *
lgl_template_get_name(const lglTemplate * template)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
lgl_template_do_templates_match(const lglTemplate * template1,const lglTemplate * template2)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
lgl_template_does_brand_match(const lglTemplate * template,const gchar * brand)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
lgl_template_does_page_size_match(const lglTemplate * template,const gchar * paper_id)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
lgl_template_does_category_match(const lglTemplate * template,const gchar * category_id)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
lgl_template_are_templates_identical(const lglTemplate * template1,const lglTemplate * template2)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
lgl_template_add_frame(lglTemplate * template,lglTemplateFrame * frame)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
lgl_template_add_category(lglTemplate * template,const gchar * category_id)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 *
lgl_template_frame_rect_new(const gchar * id,gdouble w,gdouble h,gdouble r,gdouble x_waste,gdouble y_waste)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 *
lgl_template_frame_ellipse_new(const gchar * id,gdouble w,gdouble h,gdouble waste)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 *
lgl_template_frame_round_new(const gchar * id,gdouble r,gdouble waste)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 *
lgl_template_frame_cd_new(const gchar * id,gdouble r1,gdouble r2,gdouble w,gdouble h,gdouble waste)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
lgl_template_frame_get_size(const lglTemplateFrame * frame,gdouble * w,gdouble * h)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
lgl_template_frame_get_n_labels(const lglTemplateFrame * frame)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 *
lgl_template_frame_get_layout_description(const lglTemplateFrame * frame)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 *
lgl_template_frame_get_size_description(const lglTemplateFrame * frame,lglUnits units)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 *
lgl_template_frame_get_origins(const lglTemplateFrame * frame)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
lgl_template_frame_add_layout(lglTemplateFrame * frame,lglTemplateLayout * layout)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
lgl_template_frame_add_markup(lglTemplateFrame * frame,lglTemplateMarkup * markup)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 *
lgl_template_layout_new(gint nx,gint ny,gdouble x0,gdouble y0,gdouble dx,gdouble dy)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 *
lgl_template_markup_margin_new(gdouble size)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 *
lgl_template_markup_line_new(gdouble x1,gdouble y1,gdouble x2,gdouble y2)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 *
lgl_template_markup_circle_new(gdouble x0,gdouble y0,gdouble r)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 *
lgl_template_markup_rect_new(gdouble x1,gdouble y1,gdouble w,gdouble h,gdouble r)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 *
lgl_template_markup_ellipse_new(gdouble x1,gdouble y1,gdouble w,gdouble h)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 *
lgl_template_dup(const lglTemplate * orig_template)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
lgl_template_free(lglTemplate * template)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 *
lgl_template_frame_dup(const lglTemplateFrame * orig_frame)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
lgl_template_frame_free(lglTemplateFrame * frame)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 *
lgl_template_layout_dup(const lglTemplateLayout * orig_layout)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
lgl_template_layout_free(lglTemplateLayout * layout)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 *
lgl_template_markup_dup(const lglTemplateMarkup * orig_markup)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
lgl_template_markup_free(lglTemplateMarkup * markup)1368 lgl_template_markup_free (lglTemplateMarkup *markup)
1369 {
1370 g_free (markup);
1371 }
1372
1373
1374 static gint
compare_origins(gconstpointer a,gconstpointer b,gpointer user_data)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
lgl_template_print(const lglTemplate * template)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 */
1439