aboutsummaryrefslogtreecommitdiff
path: root/printing.c
diff options
context:
space:
mode:
Diffstat (limited to 'printing.c')
-rw-r--r--printing.c278
1 files changed, 162 insertions, 116 deletions
diff --git a/printing.c b/printing.c
index 98fdd84..3f0810a 100644
--- a/printing.c
+++ b/printing.c
@@ -3,6 +3,8 @@
* setup and layout.
*/
+#include <assert.h>
+
#include "puzzles.h"
struct puzzle {
@@ -115,133 +117,177 @@ static void get_puzzle_size(document *doc, struct puzzle *pz,
}
/*
- * Having accumulated a load of puzzles, actually do the printing.
+ * Calculate the the number of pages for a document.
*/
-void document_print(document *doc, drawing *dr)
+int document_npages(document *doc)
{
int ppp; /* puzzles per page */
int pages, passes;
+
+ ppp = doc->pw * doc->ph;
+ pages = (doc->npuzzles + ppp - 1) / ppp;
+ passes = (doc->got_solns ? 2 : 1);
+
+ return pages * passes;
+}
+
+/*
+ * Begin a document.
+ */
+void document_begin(document *doc, drawing *dr)
+{
+ print_begin_doc(dr, document_npages(doc));
+}
+
+/*
+ * End a document.
+ */
+void document_end(document *doc, drawing *dr)
+{
+ print_end_doc(dr);
+}
+
+/*
+ * Print a single page of a document.
+ */
+void document_print_page(document *doc, drawing *dr, int page_nr)
+{
+ int ppp; /* puzzles per page */
+ int pages;
int page, pass;
int pageno;
+ int i, n, offset;
+ float colsum, rowsum;
ppp = doc->pw * doc->ph;
pages = (doc->npuzzles + ppp - 1) / ppp;
- passes = (doc->got_solns ? 2 : 1);
- print_begin_doc(dr, pages * passes);
-
- pageno = 1;
- for (pass = 0; pass < passes; pass++) {
- for (page = 0; page < pages; page++) {
- int i, n, offset;
- float colsum, rowsum;
-
- print_begin_page(dr, pageno);
-
- offset = page * ppp;
- n = min(ppp, doc->npuzzles - offset);
-
- for (i = 0; i < doc->pw; i++)
- doc->colwid[i] = 0;
- for (i = 0; i < doc->ph; i++)
- doc->rowht[i] = 0;
-
- /*
- * Lay the page out by computing all the puzzle sizes.
- */
- for (i = 0; i < n; i++) {
- struct puzzle *pz = doc->puzzles + offset + i;
- int x = i % doc->pw, y = i / doc->pw;
- float w, h, scale;
-
- get_puzzle_size(doc, pz, &w, &h, &scale);
-
- /* Update the maximum width/height of this column. */
- doc->colwid[x] = max(doc->colwid[x], w);
- doc->rowht[y] = max(doc->rowht[y], h);
- }
-
- /*
- * Add up the maximum column/row widths to get the
- * total amount of space used up by puzzles on the
- * page. We will use this to compute gutter widths.
- */
- colsum = 0.0;
- for (i = 0; i < doc->pw; i++)
- colsum += doc->colwid[i];
- rowsum = 0.0;
- for (i = 0; i < doc->ph; i++)
- rowsum += doc->rowht[i];
-
- /*
- * Now do the printing.
- */
- for (i = 0; i < n; i++) {
- struct puzzle *pz = doc->puzzles + offset + i;
- int x = i % doc->pw, y = i / doc->pw, j;
- float w, h, scale, xm, xc, ym, yc;
- int pixw, pixh, tilesize;
-
- if (pass == 1 && !pz->st2)
- continue; /* nothing to do */
-
- /*
- * The total amount of gutter space is the page
- * width minus colsum. This is divided into pw+1
- * gutters, so the amount of horizontal gutter
- * space appearing to the left of this puzzle
- * column is
- *
- * (width-colsum) * (x+1)/(pw+1)
- * = width * (x+1)/(pw+1) - (colsum * (x+1)/(pw+1))
- */
- xm = (float)(x+1) / (doc->pw + 1);
- xc = -xm * colsum;
- /* And similarly for y. */
- ym = (float)(y+1) / (doc->ph + 1);
- yc = -ym * rowsum;
-
- /*
- * However, the amount of space to the left of this
- * puzzle isn't just gutter space: we must also
- * count the widths of all the previous columns.
- */
- for (j = 0; j < x; j++)
- xc += doc->colwid[j];
- /* And similarly for rows. */
- for (j = 0; j < y; j++)
- yc += doc->rowht[j];
-
- /*
- * Now we adjust for this _specific_ puzzle, which
- * means centring it within the cell we've just
- * computed.
- */
- get_puzzle_size(doc, pz, &w, &h, &scale);
- xc += (doc->colwid[x] - w) / 2;
- yc += (doc->rowht[y] - h) / 2;
-
- /*
- * And now we know where and how big we want to
- * print the puzzle, just go ahead and do so. For
- * the moment I'll pick a standard pixel tile size
- * of 512.
- *
- * (FIXME: would it be better to pick this value
- * with reference to the printer resolution? Or
- * permit each game to choose its own?)
- */
- tilesize = 512;
- pz->game->compute_size(pz->par, tilesize, &pixw, &pixh);
- print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale);
- pz->game->print(dr, pass == 0 ? pz->st : pz->st2, tilesize);
- print_end_puzzle(dr);
- }
-
- print_end_page(dr, pageno);
- pageno++;
- }
+ /* Get the current page, pass, and pageno based on page_nr. */
+ if (page_nr < pages) {
+ page = page_nr;
+ pass = 0;
+ }
+ else {
+ assert(doc->got_solns);
+ page = page_nr - pages;
+ pass = 1;
}
+ pageno = page_nr + 1;
+
+ offset = page * ppp;
+ n = min(ppp, doc->npuzzles - offset);
+
+ print_begin_page(dr, pageno);
+ for (i = 0; i < doc->pw; i++)
+ doc->colwid[i] = 0;
+ for (i = 0; i < doc->ph; i++)
+ doc->rowht[i] = 0;
+
+ /*
+ * Lay the page out by computing all the puzzle sizes.
+ */
+ for (i = 0; i < n; i++) {
+ struct puzzle *pz = doc->puzzles + offset + i;
+ int x = i % doc->pw, y = i / doc->pw;
+ float w, h, scale;
+
+ get_puzzle_size(doc, pz, &w, &h, &scale);
+
+ /* Update the maximum width/height of this column. */
+ doc->colwid[x] = max(doc->colwid[x], w);
+ doc->rowht[y] = max(doc->rowht[y], h);
+ }
+
+ /*
+ * Add up the maximum column/row widths to get the
+ * total amount of space used up by puzzles on the
+ * page. We will use this to compute gutter widths.
+ */
+ colsum = 0.0;
+ for (i = 0; i < doc->pw; i++)
+ colsum += doc->colwid[i];
+ rowsum = 0.0;
+ for (i = 0; i < doc->ph; i++)
+ rowsum += doc->rowht[i];
+
+ /*
+ * Now do the printing.
+ */
+ for (i = 0; i < n; i++) {
+ struct puzzle *pz = doc->puzzles + offset + i;
+ int x = i % doc->pw, y = i / doc->pw, j;
+ float w, h, scale, xm, xc, ym, yc;
+ int pixw, pixh, tilesize;
+
+ if (pass == 1 && !pz->st2)
+ continue; /* nothing to do */
+
+ /*
+ * The total amount of gutter space is the page
+ * width minus colsum. This is divided into pw+1
+ * gutters, so the amount of horizontal gutter
+ * space appearing to the left of this puzzle
+ * column is
+ *
+ * (width-colsum) * (x+1)/(pw+1)
+ * = width * (x+1)/(pw+1) - (colsum * (x+1)/(pw+1))
+ */
+ xm = (float)(x+1) / (doc->pw + 1);
+ xc = -xm * colsum;
+ /* And similarly for y. */
+ ym = (float)(y+1) / (doc->ph + 1);
+ yc = -ym * rowsum;
+
+ /*
+ * However, the amount of space to the left of this
+ * puzzle isn't just gutter space: we must also
+ * count the widths of all the previous columns.
+ */
+ for (j = 0; j < x; j++)
+ xc += doc->colwid[j];
+ /* And similarly for rows. */
+ for (j = 0; j < y; j++)
+ yc += doc->rowht[j];
+
+ /*
+ * Now we adjust for this _specific_ puzzle, which
+ * means centring it within the cell we've just
+ * computed.
+ */
+ get_puzzle_size(doc, pz, &w, &h, &scale);
+ xc += (doc->colwid[x] - w) / 2;
+ yc += (doc->rowht[y] - h) / 2;
+
+ /*
+ * And now we know where and how big we want to
+ * print the puzzle, just go ahead and do so. For
+ * the moment I'll pick a standard pixel tile size
+ * of 512.
+ *
+ * (FIXME: would it be better to pick this value
+ * with reference to the printer resolution? Or
+ * permit each game to choose its own?)
+ */
+ tilesize = 512;
+ pz->game->compute_size(pz->par, tilesize, &pixw, &pixh);
+ print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale);
+ pz->game->print(dr, pass == 0 ? pz->st : pz->st2, tilesize);
+ print_end_puzzle(dr);
+ }
+
+ print_end_page(dr, pageno);
+}
+
+/*
+ * Having accumulated a load of puzzles, actually do the printing.
+ */
+void document_print(document *doc, drawing *dr)
+{
+ int page, pages;
+ pages = document_npages(doc);
+ print_begin_doc(dr, pages);
+ for (page = 0; page < pages; page++)
+ document_print_page(doc, dr, page);
print_end_doc(dr);
}