2 * printing.c: Cross-platform printing manager. Handles document
18 struct puzzle
*puzzles
;
21 float *colwid
, *rowht
;
26 * Create a new print document. pw and ph are the layout
27 * parameters: they state how many puzzles will be printed across
28 * the page, and down the page.
30 document
*document_new(int pw
, int ph
, float userscale
)
32 document
*doc
= snew(document
);
37 doc
->puzzlesize
= doc
->npuzzles
= 0;
38 doc
->got_solns
= FALSE
;
40 doc
->colwid
= snewn(pw
, float);
41 doc
->rowht
= snewn(ph
, float);
43 doc
->userscale
= userscale
;
49 * Free a document structure, whether it's been printed or not.
51 void document_free(document
*doc
)
55 for (i
= 0; i
< doc
->npuzzles
; i
++) {
56 doc
->puzzles
[i
].game
->free_params(doc
->puzzles
[i
].par
);
57 doc
->puzzles
[i
].game
->free_game(doc
->puzzles
[i
].st
);
58 if (doc
->puzzles
[i
].st2
)
59 doc
->puzzles
[i
].game
->free_game(doc
->puzzles
[i
].st2
);
70 * Called from midend.c to add a puzzle to be printed. Provides a
71 * game_params (for initial layout computation), a game_state, and
72 * optionally a second game_state to be printed in parallel on
73 * another sheet (typically the solution to the first game_state).
75 void document_add_puzzle(document
*doc
, const game
*game
, game_params
*par
,
76 game_state
*st
, game_state
*st2
)
78 if (doc
->npuzzles
>= doc
->puzzlesize
) {
79 doc
->puzzlesize
+= 32;
80 doc
->puzzles
= sresize(doc
->puzzles
, doc
->puzzlesize
, struct puzzle
);
82 doc
->puzzles
[doc
->npuzzles
].game
= game
;
83 doc
->puzzles
[doc
->npuzzles
].par
= par
;
84 doc
->puzzles
[doc
->npuzzles
].st
= st
;
85 doc
->puzzles
[doc
->npuzzles
].st2
= st2
;
88 doc
->got_solns
= TRUE
;
91 static void get_puzzle_size(document
*doc
, struct puzzle
*pz
,
92 float *w
, float *h
, float *scale
)
94 float ww
, hh
, ourscale
;
96 /* Get the preferred size of the game, in mm. */
97 pz
->game
->print_size(pz
->par
, &ww
, &hh
);
99 /* Adjust for user-supplied scale factor. */
100 ourscale
= doc
->userscale
;
103 * FIXME: scale it down here if it's too big for the page size.
104 * Rather than do complicated things involving scaling all
105 * columns down in proportion, the simplest approach seems to
106 * me to be to scale down until the game fits within one evenly
107 * divided cell of the page (i.e. width/pw by height/ph).
109 * In order to do this step we need the page size available.
118 * Having accumulated a load of puzzles, actually do the printing.
120 void document_print(document
*doc
, drawing
*dr
)
122 int ppp
; /* puzzles per page */
127 ppp
= doc
->pw
* doc
->ph
;
128 pages
= (doc
->npuzzles
+ ppp
- 1) / ppp
;
129 passes
= (doc
->got_solns
? 2 : 1);
131 print_begin_doc(dr
, pages
* passes
);
134 for (pass
= 0; pass
< passes
; pass
++) {
135 for (page
= 0; page
< pages
; page
++) {
137 float colsum
, rowsum
;
139 print_begin_page(dr
, pageno
);
142 n
= min(ppp
, doc
->npuzzles
- offset
);
144 for (i
= 0; i
< doc
->pw
; i
++)
146 for (i
= 0; i
< doc
->ph
; i
++)
150 * Lay the page out by computing all the puzzle sizes.
152 for (i
= 0; i
< n
; i
++) {
153 struct puzzle
*pz
= doc
->puzzles
+ offset
+ i
;
154 int x
= i
% doc
->pw
, y
= i
/ doc
->pw
;
157 get_puzzle_size(doc
, pz
, &w
, &h
, &scale
);
159 /* Update the maximum width/height of this column. */
160 doc
->colwid
[x
] = max(doc
->colwid
[x
], w
);
161 doc
->rowht
[y
] = max(doc
->rowht
[y
], h
);
165 * Add up the maximum column/row widths to get the
166 * total amount of space used up by puzzles on the
167 * page. We will use this to compute gutter widths.
170 for (i
= 0; i
< doc
->pw
; i
++)
171 colsum
+= doc
->colwid
[i
];
173 for (i
= 0; i
< doc
->ph
; i
++)
174 rowsum
+= doc
->rowht
[i
];
177 * Now do the printing.
179 for (i
= 0; i
< n
; i
++) {
180 struct puzzle
*pz
= doc
->puzzles
+ offset
+ i
;
181 int x
= i
% doc
->pw
, y
= i
/ doc
->pw
, j
;
182 float w
, h
, scale
, xm
, xc
, ym
, yc
;
183 int pixw
, pixh
, tilesize
;
185 if (pass
== 1 && !pz
->st2
)
186 continue; /* nothing to do */
189 * The total amount of gutter space is the page
190 * width minus colsum. This is divided into pw+1
191 * gutters, so the amount of horizontal gutter
192 * space appearing to the left of this puzzle
195 * (width-colsum) * (x+1)/(pw+1)
196 * = width * (x+1)/(pw+1) - (colsum * (x+1)/(pw+1))
198 xm
= (float)(x
+1) / (doc
->pw
+ 1);
200 /* And similarly for y. */
201 ym
= (float)(y
+1) / (doc
->ph
+ 1);
205 * However, the amount of space to the left of this
206 * puzzle isn't just gutter space: we must also
207 * count the widths of all the previous columns.
209 for (j
= 0; j
< x
; j
++)
210 xc
+= doc
->colwid
[j
];
211 /* And similarly for rows. */
212 for (j
= 0; j
< y
; j
++)
216 * Now we adjust for this _specific_ puzzle, which
217 * means centring it within the cell we've just
220 get_puzzle_size(doc
, pz
, &w
, &h
, &scale
);
221 xc
+= (doc
->colwid
[x
] - w
) / 2;
222 yc
+= (doc
->rowht
[y
] - h
) / 2;
225 * And now we know where and how big we want to
226 * print the puzzle, just go ahead and do so. For
227 * the moment I'll pick a standard pixel tile size
230 * (FIXME: would it be better to pick this value
231 * with reference to the printer resolution? Or
232 * permit each game to choose its own?)
235 pz
->game
->compute_size(pz
->par
, tilesize
, &pixw
, &pixh
);
236 print_begin_puzzle(dr
, xm
, xc
, ym
, yc
, pixw
, pixh
, w
, scale
);
237 pz
->game
->print(dr
, pass
== 0 ? pz
->st
: pz
->st2
, tilesize
);
238 print_end_puzzle(dr
);
241 print_end_page(dr
, pageno
);