]> git.sur5r.net Git - glabels/blob - glabels2/src/print.c
2007-04-11 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / print.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 /*
4  *  (GLABELS) Label and Business Card Creation program for GNOME
5  *
6  *  print.c:  Print module
7  *
8  *  Copyright (C) 2001-2007  Jim Evins <evins@snaught.com>.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23  */
24 #include <config.h>
25
26 #include "print.h"
27
28 #include <glib/gi18n.h>
29 #include <math.h>
30 #include <time.h>
31 #include <ctype.h>
32
33 #include "label.h"
34 #include <libglabels/template.h>
35 #include "cairo-label-path.h"
36
37 #include "debug.h"
38
39 /*===========================================*/
40 /* Private macros and constants.             */
41 /*===========================================*/
42
43 #define TICK_OFFSET  2.25
44 #define TICK_LENGTH 18.0
45
46 /*=========================================================================*/
47 /* Private types.                                                          */
48 /*=========================================================================*/
49
50 typedef struct _PrintInfo {
51         cairo_t    *cr;
52
53         /* gLabels Template */
54         glTemplate *template;
55         gboolean    label_rotate_flag;
56
57         /* page size */
58         gdouble page_width;
59         gdouble page_height;
60
61 } PrintInfo;
62
63
64 /*=========================================================================*/
65 /* Private function prototypes.                                            */
66 /*=========================================================================*/
67 static PrintInfo *print_info_new              (cairo_t          *cr,
68                                                glLabel          *label);
69
70 static void       print_info_free             (PrintInfo       **pi);
71
72 static void       print_crop_marks            (PrintInfo        *pi);
73
74 static void       print_label                 (PrintInfo        *pi,
75                                                glLabel          *label,
76                                                gdouble           x,
77                                                gdouble           y,
78                                                glMergeRecord    *record,
79                                                gboolean          outline_flag,
80                                                gboolean          reverse_flag);
81
82
83 static void       draw_outline                (PrintInfo        *pi,
84                                                glLabel          *label);
85
86 static void       clip_to_outline             (PrintInfo        *pi,
87                                                glLabel          *label);
88
89
90 \f
91 /*****************************************************************************/
92 /* Print simple sheet (no merge data) command.                               */
93 /*****************************************************************************/
94 void
95 gl_print_simple_sheet (glLabel          *label,
96                        cairo_t          *cr,
97                        gint              page,
98                        gint              n_sheets,
99                        gint              first,
100                        gint              last,
101                        gboolean          outline_flag,
102                        gboolean          reverse_flag,
103                        gboolean          crop_marks_flag)
104 {
105         PrintInfo                 *pi;
106         const glTemplateLabelType *label_type;
107         gint                       i_label;
108         glTemplateOrigin          *origins;
109
110         gl_debug (DEBUG_PRINT, "START");
111
112         pi         = print_info_new (cr, label);
113
114         label_type = gl_template_get_first_label_type (pi->template);
115         origins = gl_template_get_origins (label_type);
116
117         if (crop_marks_flag) {
118                 print_crop_marks (pi);
119         }
120
121         for (i_label = first - 1; i_label < last; i_label++) {
122
123                 print_label (pi, label,
124                              origins[i_label].x, origins[i_label].y,
125                              NULL, outline_flag, reverse_flag);
126
127         }
128
129         g_free (origins);
130
131         print_info_free (&pi);
132
133         gl_debug (DEBUG_PRINT, "END");
134 }
135
136 /*****************************************************************************/
137 /* Print collated merge sheet command                                        */
138 /*****************************************************************************/
139 void
140 gl_print_collated_merge_sheet   (glLabel          *label,
141                                  cairo_t          *cr,
142                                  gint              page,
143                                  gint              n_copies,
144                                  gint              first,
145                                  gboolean          outline_flag,
146                                  gboolean          reverse_flag,
147                                  gboolean          crop_marks_flag,
148                                  glPrintState     *state)
149 {
150         glMerge                   *merge;
151         const GList               *record_list;
152         PrintInfo                 *pi;
153         const glTemplateLabelType *label_type;
154         gint                       i_label, n_labels_per_page, i_copy;
155         glMergeRecord             *record;
156         GList                     *p;
157         glTemplateOrigin          *origins;
158
159         gl_debug (DEBUG_PRINT, "START");
160
161         merge = gl_label_get_merge (label);
162         record_list = gl_merge_get_record_list (merge);
163
164         pi = print_info_new (cr, label);
165         label_type = gl_template_get_first_label_type (pi->template);
166
167         n_labels_per_page = gl_template_get_n_labels (label_type);
168         origins = gl_template_get_origins (label_type);
169
170         if (crop_marks_flag) {
171                 print_crop_marks (pi);
172         }
173
174         if (page == 0)
175         {
176                 state->i_copy  = 0;
177                 state->p_record = (GList *)record_list;
178
179                 i_label = first - 1;
180         }
181         else
182         {
183                 i_label = 0;
184         }
185
186
187         for ( p=(GList *)state->p_record; p!=NULL; p=p->next ) {
188                 record = (glMergeRecord *)p->data;
189                         
190                 if ( record->select_flag ) {
191                         for (i_copy = state->i_copy; i_copy < n_copies; i_copy++) {
192
193                                 print_label (pi, label,
194                                              origins[i_label].x,
195                                              origins[i_label].y,
196                                              record,
197                                              outline_flag, reverse_flag);
198
199                                 i_label++;
200                                 if (i_label == n_labels_per_page)
201                                 {
202                                         g_free (origins);
203                                         print_info_free (&pi);
204
205                                         state->i_copy = (i_copy+1) % n_copies;
206                                         if (state->i_copy == 0)
207                                         {
208                                                 state->p_record = p->next;
209                                         }
210                                         else
211                                         {
212                                                 state->p_record = p;
213                                         }
214                                         return;
215                                 }
216                         }
217                         state->i_copy = 0;
218                 }
219         }
220
221         g_free (origins);
222         print_info_free (&pi);
223
224         gl_debug (DEBUG_PRINT, "END");
225 }
226
227 /*****************************************************************************/
228 /* Print uncollated merge sheet command                                      */
229 /*****************************************************************************/
230 void
231 gl_print_uncollated_merge_sheet (glLabel          *label,
232                                  cairo_t          *cr,
233                                  gint              page,
234                                  gint              n_copies,
235                                  gint              first,
236                                  gboolean          outline_flag,
237                                  gboolean          reverse_flag,
238                                  gboolean          crop_marks_flag,
239                                  glPrintState     *state)
240 {
241         glMerge                   *merge;
242         const GList               *record_list;
243         PrintInfo                 *pi;
244         const glTemplateLabelType *label_type;
245         gint                       i_label, n_labels_per_page, i_copy;
246         glMergeRecord             *record;
247         GList                     *p;
248         glTemplateOrigin          *origins;
249
250         gl_debug (DEBUG_PRINT, "START");
251
252         merge = gl_label_get_merge (label);
253         record_list = gl_merge_get_record_list (merge);
254
255         pi = print_info_new (cr, label);
256         label_type = gl_template_get_first_label_type (pi->template);
257
258         n_labels_per_page = gl_template_get_n_labels (label_type);
259         origins = gl_template_get_origins (label_type);
260
261         if (crop_marks_flag) {
262                 print_crop_marks (pi);
263         }
264
265         if (page == 0)
266         {
267                 state->i_copy  = 0;
268                 state->p_record = (GList *)record_list;
269
270                 i_label = first - 1;
271         }
272         else
273         {
274                 i_label = 0;
275         }
276
277         for (i_copy = state->i_copy; i_copy < n_copies; i_copy++) {
278
279                 for ( p=state->p_record; p!=NULL; p=p->next ) {
280                         record = (glMergeRecord *)p->data;
281                         
282                         if ( record->select_flag ) {
283
284                                 print_label (pi, label,
285                                              origins[i_label].x,
286                                              origins[i_label].y,
287                                              record,
288                                              outline_flag, reverse_flag);
289
290                                 i_label++;
291                                 if (i_label == n_labels_per_page)
292                                 {
293                                         g_free (origins);
294                                         print_info_free (&pi);
295
296                                         state->p_record = p->next;
297                                         if (state->p_record == NULL)
298                                         {
299                                                 state->p_record = (GList *)record_list;
300                                                 state->i_copy = i_copy + 1;
301                                         }
302                                         else
303                                         {
304                                                 state->i_copy = i_copy;
305                                         }
306                                         return;
307                                 }
308                         }
309                 }
310                 state->p_record = (GList *)record_list;
311
312         }
313
314         g_free (origins);
315         print_info_free (&pi);
316
317         gl_debug (DEBUG_PRINT, "END");
318 }
319
320 /*---------------------------------------------------------------------------*/
321 /* PRIVATE.  new print info structure                                        */
322 /*---------------------------------------------------------------------------*/
323 static PrintInfo *
324 print_info_new (cairo_t          *cr,
325                 glLabel          *label)
326 {
327         PrintInfo            *pi = g_new0 (PrintInfo, 1);
328
329         gl_debug (DEBUG_PRINT, "START");
330
331         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
332
333         g_return_val_if_fail (label->template, NULL);
334         g_return_val_if_fail (label->template->page_size, NULL);
335         g_return_val_if_fail (label->template->page_width > 0, NULL);
336         g_return_val_if_fail (label->template->page_height > 0, NULL);
337
338         pi->cr = cr;
339
340         gl_debug (DEBUG_PRINT,
341                   "setting page size = \"%s\"", label->template->page_size);
342
343         pi->page_width  = label->template->page_width;
344         pi->page_height = label->template->page_height;
345
346         pi->template = label->template;
347         pi->label_rotate_flag = label->rotate_flag;
348
349         gl_debug (DEBUG_PRINT, "END");
350
351         return pi;
352 }
353
354 /*---------------------------------------------------------------------------*/
355 /* PRIVATE.  free print info structure                                       */
356 /*---------------------------------------------------------------------------*/
357 static void
358 print_info_free (PrintInfo **pi)
359 {
360         gl_debug (DEBUG_PRINT, "START");
361
362
363         g_free (*pi);
364         *pi = NULL;
365
366         gl_debug (DEBUG_PRINT, "END");
367 }
368
369 /*---------------------------------------------------------------------------*/
370 /* PRIVATE.  Print crop tick marks.                                          */
371 /*---------------------------------------------------------------------------*/
372 static void
373 print_crop_marks (PrintInfo *pi)
374 {
375         const glTemplateLabelType *label_type;
376         gdouble                    w, h, page_w, page_h;
377         GList                     *p;
378         glTemplateLayout          *layout;
379         gdouble                    xmin, ymin, xmax, ymax, dx, dy;
380         gdouble                    x1, y1, x2, y2, x3, y3, x4, y4;
381         gint                       ix, iy, nx, ny;
382
383         gl_debug (DEBUG_PRINT, "START");
384
385         label_type = gl_template_get_first_label_type (pi->template);
386
387         gl_template_get_label_size (label_type, &w, &h);
388
389         page_w = pi->page_width;
390         page_h = pi->page_height;
391
392         cairo_save (pi->cr);
393
394         cairo_set_source_rgba (pi->cr, 0.0, 0.0, 0.0, 1.0);
395         cairo_set_line_width  (pi->cr, 0.25);
396
397         for (p=label_type->layouts; p != NULL; p=p->next) {
398
399                 layout = (glTemplateLayout *)p->data;
400
401                 xmin = layout->x0;
402                 ymin = layout->y0;
403                 xmax = layout->x0 + layout->dx*(layout->nx - 1) + w;
404                 ymax = layout->y0 + layout->dy*(layout->ny - 1) + h;
405
406                 dx = layout->dx;
407                 dy = layout->dy;
408
409                 nx = layout->nx;
410                 ny = layout->ny;
411
412                 for (ix=0; ix < nx; ix++) {
413
414                         x1 = xmin + ix*dx;
415                         x2 = x1 + w;
416
417                         y1 = MAX((ymin - TICK_OFFSET), 0.0);
418                         y2 = MAX((y1 - TICK_LENGTH), 0.0);
419
420                         y3 = MIN((ymax + TICK_OFFSET), page_h);
421                         y4 = MIN((y3 + TICK_LENGTH), page_h);
422
423                         cairo_move_to (pi->cr, x1, y1);
424                         cairo_line_to (pi->cr, x1, y2);
425                         cairo_stroke  (pi->cr);
426
427                         cairo_move_to (pi->cr, x2, y1);
428                         cairo_line_to (pi->cr, x2, y2);
429                         cairo_stroke  (pi->cr);
430
431                         cairo_move_to (pi->cr, x1, y3);
432                         cairo_line_to (pi->cr, x1, y4);
433                         cairo_stroke  (pi->cr);
434
435                         cairo_move_to (pi->cr, x2, y3);
436                         cairo_line_to (pi->cr, x2, y4);
437                         cairo_stroke  (pi->cr);
438
439                 }
440
441                 for (iy=0; iy < ny; iy++) {
442
443                         y1 = ymin + iy*dy;
444                         y2 = y1 + h;
445
446                         x1 = MAX((xmin - TICK_OFFSET), 0.0);
447                         x2 = MAX((x1 - TICK_LENGTH), 0.0);
448
449                         x3 = MIN((xmax + TICK_OFFSET), page_w);
450                         x4 = MIN((x3 + TICK_LENGTH), page_w);
451
452                         cairo_move_to (pi->cr, x1, y1);
453                         cairo_line_to (pi->cr, x2, y1);
454                         cairo_stroke  (pi->cr);
455
456                         cairo_move_to (pi->cr, x1, y2);
457                         cairo_line_to (pi->cr, x2, y2);
458                         cairo_stroke  (pi->cr);
459
460                         cairo_move_to (pi->cr, x3, y1);
461                         cairo_line_to (pi->cr, x4, y1);
462                         cairo_stroke  (pi->cr);
463
464                         cairo_move_to (pi->cr, x3, y2);
465                         cairo_line_to (pi->cr, x4, y2);
466                         cairo_stroke  (pi->cr);
467
468                 }
469
470         }
471
472         cairo_restore (pi->cr);
473
474         gl_debug (DEBUG_PRINT, "END");
475 }
476
477 /*---------------------------------------------------------------------------*/
478 /* PRIVATE.  Print i'th label.                                               */
479 /*---------------------------------------------------------------------------*/
480 static void
481 print_label (PrintInfo     *pi,
482              glLabel       *label,
483              gdouble        x,
484              gdouble        y,
485              glMergeRecord *record,
486              gboolean       outline_flag,
487              gboolean       reverse_flag)
488 {
489         const glTemplateLabelType *label_type;
490         gdouble                    width, height;
491
492         gl_debug (DEBUG_PRINT, "START");
493
494         label_type = gl_template_get_first_label_type (pi->template);
495
496         gl_label_get_size (label, &width, &height);
497
498         cairo_save (pi->cr);
499
500         /* Transform coordinate system to be relative to upper corner */
501         /* of the current label */
502         cairo_translate (pi->cr, x, y);
503         if (label->rotate_flag) {
504                 gl_debug (DEBUG_PRINT, "Rotate flag set");
505                 cairo_rotate (pi->cr, -M_PI/2.0);
506                 cairo_translate (pi->cr, -width, 0.0);
507         }
508         if ( reverse_flag ) {
509                 cairo_translate (pi->cr, width, 0.0);
510                 cairo_scale (pi->cr, -1.0, 1.0);
511         }
512
513         clip_to_outline (pi, label);
514         gl_label_draw (label, pi->cr, FALSE, record);
515         if (outline_flag) {
516                 draw_outline (pi, label);
517         }
518
519         cairo_restore (pi->cr);
520
521         gl_debug (DEBUG_PRINT, "END");
522 }
523
524 /*---------------------------------------------------------------------------*/
525 /* PRIVATE.  Draw outline.                                                   */
526 /*---------------------------------------------------------------------------*/
527 static void
528 draw_outline (PrintInfo *pi,
529               glLabel   *label)
530 {
531         gl_debug (DEBUG_PRINT, "START");
532
533         cairo_save (pi->cr);
534
535         cairo_set_source_rgba (pi->cr, 0.0, 0.0, 0.0, 1.0);
536         cairo_set_line_width  (pi->cr, 0.25);
537
538         gl_cairo_label_path (pi->cr, label->template, FALSE, FALSE);
539
540         cairo_stroke (pi->cr);
541
542         cairo_restore (pi->cr);
543
544         gl_debug (DEBUG_PRINT, "END");
545 }
546
547 /*---------------------------------------------------------------------------*/
548 /* PRIVATE.  Clip to outline.                                                */
549 /*---------------------------------------------------------------------------*/
550 static void
551 clip_to_outline (PrintInfo *pi,
552                  glLabel   *label)
553 {
554         gl_debug (DEBUG_PRINT, "START");
555
556         gl_cairo_label_path (pi->cr, label->template, FALSE, TRUE);
557
558         cairo_set_fill_rule (pi->cr, CAIRO_FILL_RULE_EVEN_ODD);
559         cairo_clip (pi->cr);
560
561         gl_debug (DEBUG_PRINT, "END");
562 }
563