]> git.sur5r.net Git - glabels/blob - src/print.c
Imported Upstream version 2.2.8
[glabels] / 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 OUTLINE_RGB_ARGS          0.0,   0.0,   0.0
44
45 #define OUTLINE_WIDTH 0.25
46
47 #define TICK_OFFSET  2.25
48 #define TICK_LENGTH 18.0
49
50 /*=========================================================================*/
51 /* Private types.                                                          */
52 /*=========================================================================*/
53
54 typedef struct _PrintInfo {
55         cairo_t    *cr;
56
57         /* gLabels Template */
58         lglTemplate *template;
59         gboolean     label_rotate_flag;
60
61         /* page size */
62         gdouble page_width;
63         gdouble page_height;
64
65 } PrintInfo;
66
67
68 /*=========================================================================*/
69 /* Private function prototypes.                                            */
70 /*=========================================================================*/
71 static PrintInfo *print_info_new              (cairo_t          *cr,
72                                                glLabel          *label);
73
74 static void       print_info_free             (PrintInfo       **pi);
75
76 static void       print_crop_marks            (PrintInfo        *pi);
77
78 static void       print_label                 (PrintInfo        *pi,
79                                                glLabel          *label,
80                                                gdouble           x,
81                                                gdouble           y,
82                                                glMergeRecord    *record,
83                                                gboolean          outline_flag,
84                                                gboolean          reverse_flag);
85
86
87 static void       draw_outline                (PrintInfo        *pi,
88                                                glLabel          *label);
89
90 static void       clip_to_outline             (PrintInfo        *pi,
91                                                glLabel          *label);
92
93
94 \f
95 /*****************************************************************************/
96 /* Print simple sheet (no merge data) command.                               */
97 /*****************************************************************************/
98 void
99 gl_print_simple_sheet (glLabel          *label,
100                        cairo_t          *cr,
101                        gint              page,
102                        gint              n_sheets,
103                        gint              first,
104                        gint              last,
105                        gboolean          outline_flag,
106                        gboolean          reverse_flag,
107                        gboolean          crop_marks_flag)
108 {
109         PrintInfo              *pi;
110         const lglTemplateFrame *frame;
111         gint                    i_label;
112         lglTemplateOrigin      *origins;
113
114         gl_debug (DEBUG_PRINT, "START");
115
116         pi         = print_info_new (cr, label);
117
118         frame = (lglTemplateFrame *)pi->template->frames->data;
119         origins = lgl_template_frame_get_origins (frame);
120
121         if (crop_marks_flag) {
122                 print_crop_marks (pi);
123         }
124
125         for (i_label = first - 1; i_label < last; i_label++) {
126
127                 print_label (pi, label,
128                              origins[i_label].x, origins[i_label].y,
129                              NULL, outline_flag, reverse_flag);
130
131         }
132
133         g_free (origins);
134
135         print_info_free (&pi);
136
137         gl_debug (DEBUG_PRINT, "END");
138 }
139
140 /*****************************************************************************/
141 /* Print collated merge sheet command                                        */
142 /*****************************************************************************/
143 void
144 gl_print_collated_merge_sheet   (glLabel          *label,
145                                  cairo_t          *cr,
146                                  gint              page,
147                                  gint              n_copies,
148                                  gint              first,
149                                  gboolean          outline_flag,
150                                  gboolean          reverse_flag,
151                                  gboolean          crop_marks_flag,
152                                  glPrintState     *state)
153 {
154         glMerge                   *merge;
155         const GList               *record_list;
156         PrintInfo                 *pi;
157         const lglTemplateFrame    *frame;
158         gint                       i_label, n_labels_per_page, i_copy;
159         glMergeRecord             *record;
160         GList                     *p;
161         lglTemplateOrigin         *origins;
162
163         gl_debug (DEBUG_PRINT, "START");
164
165         merge = gl_label_get_merge (label);
166         record_list = gl_merge_get_record_list (merge);
167
168         pi = print_info_new (cr, label);
169         frame = (lglTemplateFrame *)pi->template->frames->data;
170
171         n_labels_per_page = lgl_template_frame_get_n_labels (frame);
172         origins = lgl_template_frame_get_origins (frame);
173
174         if (crop_marks_flag) {
175                 print_crop_marks (pi);
176         }
177
178         if (page == 0)
179         {
180                 state->i_copy  = 0;
181                 state->p_record = (GList *)record_list;
182
183                 i_label = first - 1;
184         }
185         else
186         {
187                 i_label = 0;
188         }
189
190
191         for ( p=(GList *)state->p_record; p!=NULL; p=p->next ) {
192                 record = (glMergeRecord *)p->data;
193                         
194                 if ( record->select_flag ) {
195                         for (i_copy = state->i_copy; i_copy < n_copies; i_copy++) {
196
197                                 print_label (pi, label,
198                                              origins[i_label].x,
199                                              origins[i_label].y,
200                                              record,
201                                              outline_flag, reverse_flag);
202
203                                 i_label++;
204                                 if (i_label == n_labels_per_page)
205                                 {
206                                         g_free (origins);
207                                         print_info_free (&pi);
208
209                                         state->i_copy = (i_copy+1) % n_copies;
210                                         if (state->i_copy == 0)
211                                         {
212                                                 state->p_record = p->next;
213                                         }
214                                         else
215                                         {
216                                                 state->p_record = p;
217                                         }
218                                         return;
219                                 }
220                         }
221                         state->i_copy = 0;
222                 }
223         }
224
225         g_free (origins);
226         print_info_free (&pi);
227
228         gl_debug (DEBUG_PRINT, "END");
229 }
230
231 /*****************************************************************************/
232 /* Print uncollated merge sheet command                                      */
233 /*****************************************************************************/
234 void
235 gl_print_uncollated_merge_sheet (glLabel          *label,
236                                  cairo_t          *cr,
237                                  gint              page,
238                                  gint              n_copies,
239                                  gint              first,
240                                  gboolean          outline_flag,
241                                  gboolean          reverse_flag,
242                                  gboolean          crop_marks_flag,
243                                  glPrintState     *state)
244 {
245         glMerge                   *merge;
246         const GList               *record_list;
247         PrintInfo                 *pi;
248         const lglTemplateFrame    *frame;
249         gint                       i_label, n_labels_per_page, i_copy;
250         glMergeRecord             *record;
251         GList                     *p;
252         lglTemplateOrigin         *origins;
253
254         gl_debug (DEBUG_PRINT, "START");
255
256         merge = gl_label_get_merge (label);
257         record_list = gl_merge_get_record_list (merge);
258
259         pi = print_info_new (cr, label);
260         frame = (lglTemplateFrame *)pi->template->frames->data;
261
262         n_labels_per_page = lgl_template_frame_get_n_labels (frame);
263         origins = lgl_template_frame_get_origins (frame);
264
265         if (crop_marks_flag) {
266                 print_crop_marks (pi);
267         }
268
269         if (page == 0)
270         {
271                 state->i_copy  = 0;
272                 state->p_record = (GList *)record_list;
273
274                 i_label = first - 1;
275         }
276         else
277         {
278                 i_label = 0;
279         }
280
281         for (i_copy = state->i_copy; i_copy < n_copies; i_copy++) {
282
283                 for ( p=state->p_record; p!=NULL; p=p->next ) {
284                         record = (glMergeRecord *)p->data;
285                         
286                         if ( record->select_flag ) {
287
288                                 print_label (pi, label,
289                                              origins[i_label].x,
290                                              origins[i_label].y,
291                                              record,
292                                              outline_flag, reverse_flag);
293
294                                 i_label++;
295                                 if (i_label == n_labels_per_page)
296                                 {
297                                         g_free (origins);
298                                         print_info_free (&pi);
299
300                                         state->p_record = p->next;
301                                         if (state->p_record == NULL)
302                                         {
303                                                 state->p_record = (GList *)record_list;
304                                                 state->i_copy = i_copy + 1;
305                                         }
306                                         else
307                                         {
308                                                 state->i_copy = i_copy;
309                                         }
310                                         return;
311                                 }
312                         }
313                 }
314                 state->p_record = (GList *)record_list;
315
316         }
317
318         g_free (origins);
319         print_info_free (&pi);
320
321         gl_debug (DEBUG_PRINT, "END");
322 }
323
324 /*---------------------------------------------------------------------------*/
325 /* PRIVATE.  new print info structure                                        */
326 /*---------------------------------------------------------------------------*/
327 static PrintInfo *
328 print_info_new (cairo_t          *cr,
329                 glLabel          *label)
330 {
331         PrintInfo            *pi = g_new0 (PrintInfo, 1);
332
333         gl_debug (DEBUG_PRINT, "START");
334
335         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
336
337         g_return_val_if_fail (label->template, NULL);
338         g_return_val_if_fail (label->template->paper_id, NULL);
339         g_return_val_if_fail (label->template->page_width > 0, NULL);
340         g_return_val_if_fail (label->template->page_height > 0, NULL);
341
342         pi->cr = cr;
343
344         gl_debug (DEBUG_PRINT,
345                   "setting page size = \"%s\"", label->template->paper_id);
346
347         pi->page_width  = label->template->page_width;
348         pi->page_height = label->template->page_height;
349
350         pi->template = label->template;
351         pi->label_rotate_flag = label->rotate_flag;
352
353         gl_debug (DEBUG_PRINT, "END");
354
355         return pi;
356 }
357
358 /*---------------------------------------------------------------------------*/
359 /* PRIVATE.  free print info structure                                       */
360 /*---------------------------------------------------------------------------*/
361 static void
362 print_info_free (PrintInfo **pi)
363 {
364         gl_debug (DEBUG_PRINT, "START");
365
366
367         g_free (*pi);
368         *pi = NULL;
369
370         gl_debug (DEBUG_PRINT, "END");
371 }
372
373 /*---------------------------------------------------------------------------*/
374 /* PRIVATE.  Print crop tick marks.                                          */
375 /*---------------------------------------------------------------------------*/
376 static void
377 print_crop_marks (PrintInfo *pi)
378 {
379         const lglTemplateFrame    *frame;
380         gdouble                    w, h, page_w, page_h;
381         GList                     *p;
382         lglTemplateLayout         *layout;
383         gdouble                    xmin, ymin, xmax, ymax, dx, dy;
384         gdouble                    x1, y1, x2, y2, x3, y3, x4, y4;
385         gint                       ix, iy, nx, ny;
386
387         gl_debug (DEBUG_PRINT, "START");
388
389         frame = (lglTemplateFrame *)pi->template->frames->data;
390
391         lgl_template_frame_get_size (frame, &w, &h);
392
393         page_w = pi->page_width;
394         page_h = pi->page_height;
395
396         cairo_save (pi->cr);
397
398         cairo_set_source_rgb (pi->cr, OUTLINE_RGB_ARGS);
399         cairo_set_line_width (pi->cr, OUTLINE_WIDTH);
400
401         for (p=frame->all.layouts; p != NULL; p=p->next) {
402
403                 layout = (lglTemplateLayout *)p->data;
404
405                 xmin = layout->x0;
406                 ymin = layout->y0;
407                 xmax = layout->x0 + layout->dx*(layout->nx - 1) + w;
408                 ymax = layout->y0 + layout->dy*(layout->ny - 1) + h;
409
410                 dx = layout->dx;
411                 dy = layout->dy;
412
413                 nx = layout->nx;
414                 ny = layout->ny;
415
416                 for (ix=0; ix < nx; ix++) {
417
418                         x1 = xmin + ix*dx;
419                         x2 = x1 + w;
420
421                         y1 = MAX((ymin - TICK_OFFSET), 0.0);
422                         y2 = MAX((y1 - TICK_LENGTH), 0.0);
423
424                         y3 = MIN((ymax + TICK_OFFSET), page_h);
425                         y4 = MIN((y3 + TICK_LENGTH), page_h);
426
427                         cairo_move_to (pi->cr, x1, y1);
428                         cairo_line_to (pi->cr, x1, y2);
429                         cairo_stroke  (pi->cr);
430
431                         cairo_move_to (pi->cr, x2, y1);
432                         cairo_line_to (pi->cr, x2, y2);
433                         cairo_stroke  (pi->cr);
434
435                         cairo_move_to (pi->cr, x1, y3);
436                         cairo_line_to (pi->cr, x1, y4);
437                         cairo_stroke  (pi->cr);
438
439                         cairo_move_to (pi->cr, x2, y3);
440                         cairo_line_to (pi->cr, x2, y4);
441                         cairo_stroke  (pi->cr);
442
443                 }
444
445                 for (iy=0; iy < ny; iy++) {
446
447                         y1 = ymin + iy*dy;
448                         y2 = y1 + h;
449
450                         x1 = MAX((xmin - TICK_OFFSET), 0.0);
451                         x2 = MAX((x1 - TICK_LENGTH), 0.0);
452
453                         x3 = MIN((xmax + TICK_OFFSET), page_w);
454                         x4 = MIN((x3 + TICK_LENGTH), page_w);
455
456                         cairo_move_to (pi->cr, x1, y1);
457                         cairo_line_to (pi->cr, x2, y1);
458                         cairo_stroke  (pi->cr);
459
460                         cairo_move_to (pi->cr, x1, y2);
461                         cairo_line_to (pi->cr, x2, y2);
462                         cairo_stroke  (pi->cr);
463
464                         cairo_move_to (pi->cr, x3, y1);
465                         cairo_line_to (pi->cr, x4, y1);
466                         cairo_stroke  (pi->cr);
467
468                         cairo_move_to (pi->cr, x3, y2);
469                         cairo_line_to (pi->cr, x4, y2);
470                         cairo_stroke  (pi->cr);
471
472                 }
473
474         }
475
476         cairo_restore (pi->cr);
477
478         gl_debug (DEBUG_PRINT, "END");
479 }
480
481 /*---------------------------------------------------------------------------*/
482 /* PRIVATE.  Print i'th label.                                               */
483 /*---------------------------------------------------------------------------*/
484 static void
485 print_label (PrintInfo     *pi,
486              glLabel       *label,
487              gdouble        x,
488              gdouble        y,
489              glMergeRecord *record,
490              gboolean       outline_flag,
491              gboolean       reverse_flag)
492 {
493         const lglTemplateFrame *frame;
494         gdouble                 width, height;
495
496         gl_debug (DEBUG_PRINT, "START");
497
498         frame = (lglTemplateFrame *)pi->template->frames->data;
499
500         gl_label_get_size (label, &width, &height);
501
502         cairo_save (pi->cr);
503
504         /* Transform coordinate system to be relative to upper corner */
505         /* of the current label */
506         cairo_translate (pi->cr, x, y);
507
508         clip_to_outline (pi, label);
509
510         cairo_save (pi->cr);
511
512         /* Special transformations. */
513         if (label->rotate_flag) {
514                 gl_debug (DEBUG_PRINT, "Rotate flag set");
515                 cairo_rotate (pi->cr, -M_PI/2.0);
516                 cairo_translate (pi->cr, -width, 0.0);
517         }
518         if ( reverse_flag ) {
519                 cairo_translate (pi->cr, width, 0.0);
520                 cairo_scale (pi->cr, -1.0, 1.0);
521         }
522
523         gl_label_draw (label, pi->cr, FALSE, record);
524
525         cairo_restore (pi->cr); /* From special transformations. */
526
527         if (outline_flag) {
528                 draw_outline (pi, label);
529         }
530
531         cairo_restore (pi->cr); /* From translation. */
532
533         gl_debug (DEBUG_PRINT, "END");
534 }
535
536 /*---------------------------------------------------------------------------*/
537 /* PRIVATE.  Draw outline.                                                   */
538 /*---------------------------------------------------------------------------*/
539 static void
540 draw_outline (PrintInfo *pi,
541               glLabel   *label)
542 {
543         gl_debug (DEBUG_PRINT, "START");
544
545         cairo_save (pi->cr);
546
547         cairo_set_source_rgb (pi->cr, OUTLINE_RGB_ARGS);
548         cairo_set_line_width (pi->cr, OUTLINE_WIDTH);
549
550         gl_cairo_label_path (pi->cr, label->template, FALSE, FALSE);
551
552         cairo_stroke (pi->cr);
553
554         cairo_restore (pi->cr);
555
556         gl_debug (DEBUG_PRINT, "END");
557 }
558
559 /*---------------------------------------------------------------------------*/
560 /* PRIVATE.  Clip to outline.                                                */
561 /*---------------------------------------------------------------------------*/
562 static void
563 clip_to_outline (PrintInfo *pi,
564                  glLabel   *label)
565 {
566         gl_debug (DEBUG_PRINT, "START");
567
568         gl_cairo_label_path (pi->cr, label->template, FALSE, TRUE);
569
570         cairo_set_fill_rule (pi->cr, CAIRO_FILL_RULE_EVEN_ODD);
571         cairo_clip (pi->cr);
572
573         gl_debug (DEBUG_PRINT, "END");
574 }
575