]> git.sur5r.net Git - glabels/blob - glabels2/src/print.c
2009-09-22 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / src / print.c
1 /*
2  *  print.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU 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  *  gLabels 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 General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include "print.h"
24
25 #include <glib/gi18n.h>
26 #include <math.h>
27 #include <time.h>
28 #include <ctype.h>
29
30 #include <libglabels/libglabels.h>
31 #include "label.h"
32 #include "cairo-label-path.h"
33
34 #include "debug.h"
35
36
37 /*===========================================*/
38 /* Private macros and constants.             */
39 /*===========================================*/
40
41 #define OUTLINE_RGB_ARGS          0.0,   0.0,   0.0
42
43 #define OUTLINE_WIDTH 0.25
44
45 #define TICK_OFFSET  2.25
46 #define TICK_LENGTH 18.0
47
48
49 /*=========================================================================*/
50 /* Private types.                                                          */
51 /*=========================================================================*/
52
53 typedef struct _PrintInfo {
54         cairo_t    *cr;
55
56         /* gLabels Template */
57         lglTemplate *template;
58         gboolean     label_rotate_flag;
59
60         /* page size */
61         gdouble page_width;
62         gdouble page_height;
63
64 } PrintInfo;
65
66
67 /*=========================================================================*/
68 /* Private function prototypes.                                            */
69 /*=========================================================================*/
70 static PrintInfo *print_info_new              (cairo_t          *cr,
71                                                glLabel          *label);
72
73 static void       print_info_free             (PrintInfo       **pi);
74
75 static void       print_crop_marks            (PrintInfo        *pi);
76
77 static void       print_label                 (PrintInfo        *pi,
78                                                glLabel          *label,
79                                                gdouble           x,
80                                                gdouble           y,
81                                                glMergeRecord    *record,
82                                                gboolean          outline_flag,
83                                                gboolean          reverse_flag);
84
85
86 static void       draw_outline                (PrintInfo        *pi,
87                                                glLabel          *label);
88
89 static void       clip_to_outline             (PrintInfo        *pi,
90                                                glLabel          *label);
91
92
93 /*****************************************************************************/
94 /* Print simple sheet (no merge data) command.                               */
95 /*****************************************************************************/
96 void
97 gl_print_simple_sheet (glLabel          *label,
98                        cairo_t          *cr,
99                        gint              page,
100                        gint              n_sheets,
101                        gint              first,
102                        gint              last,
103                        gboolean          outline_flag,
104                        gboolean          reverse_flag,
105                        gboolean          crop_marks_flag)
106 {
107         PrintInfo              *pi;
108         const lglTemplateFrame *frame;
109         gint                    i_label;
110         lglTemplateOrigin      *origins;
111
112         gl_debug (DEBUG_PRINT, "START");
113
114         pi         = print_info_new (cr, label);
115
116         frame = (lglTemplateFrame *)pi->template->frames->data;
117         origins = lgl_template_frame_get_origins (frame);
118
119         if (crop_marks_flag) {
120                 print_crop_marks (pi);
121         }
122
123         for (i_label = first - 1; i_label < last; i_label++) {
124
125                 print_label (pi, label,
126                              origins[i_label].x, origins[i_label].y,
127                              NULL, outline_flag, reverse_flag);
128
129         }
130
131         g_free (origins);
132
133         print_info_free (&pi);
134
135         gl_debug (DEBUG_PRINT, "END");
136 }
137
138
139 /*****************************************************************************/
140 /* Print collated merge sheet command                                        */
141 /*****************************************************************************/
142 void
143 gl_print_collated_merge_sheet   (glLabel          *label,
144                                  cairo_t          *cr,
145                                  gint              page,
146                                  gint              n_copies,
147                                  gint              first,
148                                  gboolean          outline_flag,
149                                  gboolean          reverse_flag,
150                                  gboolean          crop_marks_flag,
151                                  glPrintState     *state)
152 {
153         glMerge                   *merge;
154         const GList               *record_list;
155         PrintInfo                 *pi;
156         const lglTemplateFrame    *frame;
157         gint                       i_label, n_labels_per_page, i_copy;
158         glMergeRecord             *record;
159         GList                     *p;
160         lglTemplateOrigin         *origins;
161
162         gl_debug (DEBUG_PRINT, "START");
163
164         merge = gl_label_get_merge (label);
165         record_list = gl_merge_get_record_list (merge);
166
167         pi = print_info_new (cr, label);
168         frame = (lglTemplateFrame *)pi->template->frames->data;
169
170         n_labels_per_page = lgl_template_frame_get_n_labels (frame);
171         origins = lgl_template_frame_get_origins (frame);
172
173         if (crop_marks_flag) {
174                 print_crop_marks (pi);
175         }
176
177         if (page == 0)
178         {
179                 state->i_copy  = 0;
180                 state->p_record = (GList *)record_list;
181
182                 i_label = first - 1;
183         }
184         else
185         {
186                 i_label = 0;
187         }
188
189
190         for ( p=(GList *)state->p_record; p!=NULL; p=p->next ) {
191                 record = (glMergeRecord *)p->data;
192                         
193                 if ( record->select_flag ) {
194                         for (i_copy = state->i_copy; i_copy < n_copies; i_copy++) {
195
196                                 print_label (pi, label,
197                                              origins[i_label].x,
198                                              origins[i_label].y,
199                                              record,
200                                              outline_flag, reverse_flag);
201
202                                 i_label++;
203                                 if (i_label == n_labels_per_page)
204                                 {
205                                         g_free (origins);
206                                         print_info_free (&pi);
207
208                                         state->i_copy = (i_copy+1) % n_copies;
209                                         if (state->i_copy == 0)
210                                         {
211                                                 state->p_record = p->next;
212                                         }
213                                         else
214                                         {
215                                                 state->p_record = p;
216                                         }
217                                         return;
218                                 }
219                         }
220                         state->i_copy = 0;
221                 }
222         }
223
224         g_free (origins);
225         print_info_free (&pi);
226
227         gl_debug (DEBUG_PRINT, "END");
228 }
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 /*---------------------------------------------------------------------------*/
326 /* PRIVATE.  new print info structure                                        */
327 /*---------------------------------------------------------------------------*/
328 static PrintInfo *
329 print_info_new (cairo_t          *cr,
330                 glLabel          *label)
331 {
332         PrintInfo            *pi = g_new0 (PrintInfo, 1);
333
334         gl_debug (DEBUG_PRINT, "START");
335
336         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
337
338         g_return_val_if_fail (label->template, NULL);
339         g_return_val_if_fail (label->template->paper_id, NULL);
340         g_return_val_if_fail (label->template->page_width > 0, NULL);
341         g_return_val_if_fail (label->template->page_height > 0, NULL);
342
343         pi->cr = cr;
344
345         gl_debug (DEBUG_PRINT,
346                   "setting page size = \"%s\"", label->template->paper_id);
347
348         pi->page_width  = label->template->page_width;
349         pi->page_height = label->template->page_height;
350
351         pi->template = label->template;
352         pi->label_rotate_flag = label->rotate_flag;
353
354         gl_debug (DEBUG_PRINT, "END");
355
356         return pi;
357 }
358
359
360 /*---------------------------------------------------------------------------*/
361 /* PRIVATE.  free print info structure                                       */
362 /*---------------------------------------------------------------------------*/
363 static void
364 print_info_free (PrintInfo **pi)
365 {
366         gl_debug (DEBUG_PRINT, "START");
367
368
369         g_free (*pi);
370         *pi = NULL;
371
372         gl_debug (DEBUG_PRINT, "END");
373 }
374
375
376 /*---------------------------------------------------------------------------*/
377 /* PRIVATE.  Print crop tick marks.                                          */
378 /*---------------------------------------------------------------------------*/
379 static void
380 print_crop_marks (PrintInfo *pi)
381 {
382         const lglTemplateFrame    *frame;
383         gdouble                    w, h, page_w, page_h;
384         GList                     *p;
385         lglTemplateLayout         *layout;
386         gdouble                    xmin, ymin, xmax, ymax, dx, dy;
387         gdouble                    x1, y1, x2, y2, x3, y3, x4, y4;
388         gint                       ix, iy, nx, ny;
389
390         gl_debug (DEBUG_PRINT, "START");
391
392         frame = (lglTemplateFrame *)pi->template->frames->data;
393
394         lgl_template_frame_get_size (frame, &w, &h);
395
396         page_w = pi->page_width;
397         page_h = pi->page_height;
398
399         cairo_save (pi->cr);
400
401         cairo_set_source_rgb (pi->cr, OUTLINE_RGB_ARGS);
402         cairo_set_line_width (pi->cr, OUTLINE_WIDTH);
403
404         for (p=frame->all.layouts; p != NULL; p=p->next) {
405
406                 layout = (lglTemplateLayout *)p->data;
407
408                 xmin = layout->x0;
409                 ymin = layout->y0;
410                 xmax = layout->x0 + layout->dx*(layout->nx - 1) + w;
411                 ymax = layout->y0 + layout->dy*(layout->ny - 1) + h;
412
413                 dx = layout->dx;
414                 dy = layout->dy;
415
416                 nx = layout->nx;
417                 ny = layout->ny;
418
419                 for (ix=0; ix < nx; ix++) {
420
421                         x1 = xmin + ix*dx;
422                         x2 = x1 + w;
423
424                         y1 = MAX((ymin - TICK_OFFSET), 0.0);
425                         y2 = MAX((y1 - TICK_LENGTH), 0.0);
426
427                         y3 = MIN((ymax + TICK_OFFSET), page_h);
428                         y4 = MIN((y3 + TICK_LENGTH), page_h);
429
430                         cairo_move_to (pi->cr, x1, y1);
431                         cairo_line_to (pi->cr, x1, y2);
432                         cairo_stroke  (pi->cr);
433
434                         cairo_move_to (pi->cr, x2, y1);
435                         cairo_line_to (pi->cr, x2, y2);
436                         cairo_stroke  (pi->cr);
437
438                         cairo_move_to (pi->cr, x1, y3);
439                         cairo_line_to (pi->cr, x1, y4);
440                         cairo_stroke  (pi->cr);
441
442                         cairo_move_to (pi->cr, x2, y3);
443                         cairo_line_to (pi->cr, x2, y4);
444                         cairo_stroke  (pi->cr);
445
446                 }
447
448                 for (iy=0; iy < ny; iy++) {
449
450                         y1 = ymin + iy*dy;
451                         y2 = y1 + h;
452
453                         x1 = MAX((xmin - TICK_OFFSET), 0.0);
454                         x2 = MAX((x1 - TICK_LENGTH), 0.0);
455
456                         x3 = MIN((xmax + TICK_OFFSET), page_w);
457                         x4 = MIN((x3 + TICK_LENGTH), page_w);
458
459                         cairo_move_to (pi->cr, x1, y1);
460                         cairo_line_to (pi->cr, x2, y1);
461                         cairo_stroke  (pi->cr);
462
463                         cairo_move_to (pi->cr, x1, y2);
464                         cairo_line_to (pi->cr, x2, y2);
465                         cairo_stroke  (pi->cr);
466
467                         cairo_move_to (pi->cr, x3, y1);
468                         cairo_line_to (pi->cr, x4, y1);
469                         cairo_stroke  (pi->cr);
470
471                         cairo_move_to (pi->cr, x3, y2);
472                         cairo_line_to (pi->cr, x4, y2);
473                         cairo_stroke  (pi->cr);
474
475                 }
476
477         }
478
479         cairo_restore (pi->cr);
480
481         gl_debug (DEBUG_PRINT, "END");
482 }
483
484
485 /*---------------------------------------------------------------------------*/
486 /* PRIVATE.  Print i'th label.                                               */
487 /*---------------------------------------------------------------------------*/
488 static void
489 print_label (PrintInfo     *pi,
490              glLabel       *label,
491              gdouble        x,
492              gdouble        y,
493              glMergeRecord *record,
494              gboolean       outline_flag,
495              gboolean       reverse_flag)
496 {
497         const lglTemplateFrame *frame;
498         gdouble                 width, height;
499
500         gl_debug (DEBUG_PRINT, "START");
501
502         frame = (lglTemplateFrame *)pi->template->frames->data;
503
504         gl_label_get_size (label, &width, &height);
505
506         cairo_save (pi->cr);
507
508         /* Transform coordinate system to be relative to upper corner */
509         /* of the current label */
510         cairo_translate (pi->cr, x, y);
511
512         clip_to_outline (pi, label);
513
514         cairo_save (pi->cr);
515
516         /* Special transformations. */
517         if (label->rotate_flag) {
518                 gl_debug (DEBUG_PRINT, "Rotate flag set");
519                 cairo_rotate (pi->cr, -M_PI/2.0);
520                 cairo_translate (pi->cr, -width, 0.0);
521         }
522         if ( reverse_flag ) {
523                 cairo_translate (pi->cr, width, 0.0);
524                 cairo_scale (pi->cr, -1.0, 1.0);
525         }
526
527         gl_label_draw (label, pi->cr, FALSE, record);
528
529         cairo_restore (pi->cr); /* From special transformations. */
530
531         if (outline_flag) {
532                 draw_outline (pi, label);
533         }
534
535         cairo_restore (pi->cr); /* From translation. */
536
537         gl_debug (DEBUG_PRINT, "END");
538 }
539
540
541 /*---------------------------------------------------------------------------*/
542 /* PRIVATE.  Draw outline.                                                   */
543 /*---------------------------------------------------------------------------*/
544 static void
545 draw_outline (PrintInfo *pi,
546               glLabel   *label)
547 {
548         gl_debug (DEBUG_PRINT, "START");
549
550         cairo_save (pi->cr);
551
552         cairo_set_source_rgb (pi->cr, OUTLINE_RGB_ARGS);
553         cairo_set_line_width (pi->cr, OUTLINE_WIDTH);
554
555         gl_cairo_label_path (pi->cr, label->template, FALSE, FALSE);
556
557         cairo_stroke (pi->cr);
558
559         cairo_restore (pi->cr);
560
561         gl_debug (DEBUG_PRINT, "END");
562 }
563
564
565 /*---------------------------------------------------------------------------*/
566 /* PRIVATE.  Clip to outline.                                                */
567 /*---------------------------------------------------------------------------*/
568 static void
569 clip_to_outline (PrintInfo *pi,
570                  glLabel   *label)
571 {
572         gl_debug (DEBUG_PRINT, "START");
573
574         gl_cairo_label_path (pi->cr, label->template, FALSE, TRUE);
575
576         cairo_set_fill_rule (pi->cr, CAIRO_FILL_RULE_EVEN_ODD);
577         cairo_clip (pi->cr);
578
579         gl_debug (DEBUG_PRINT, "END");
580 }
581
582
583
584
585
586 /*
587  * Local Variables:       -- emacs
588  * mode: C                -- emacs
589  * c-basic-offset: 8      -- emacs
590  * tab-width: 8           -- emacs
591  * indent-tabs-mode: nil  -- emacs
592  * End:                   -- emacs
593  */