summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/printing.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2017-04-29 18:21:56 -0400
committerFranklin Wei <git@fwei.tk>2017-04-29 18:24:42 -0400
commit881746789a489fad85aae8317555f73dbe261556 (patch)
treecec2946362c4698c8db3c10f3242ef546c2c22dd /apps/plugins/puzzles/src/printing.c
parent03dd4b92be7dcd5c8ab06da3810887060e06abd5 (diff)
downloadrockbox-881746789a489fad85aae8317555f73dbe261556.zip
rockbox-881746789a489fad85aae8317555f73dbe261556.tar.gz
rockbox-881746789a489fad85aae8317555f73dbe261556.tar.bz2
rockbox-881746789a489fad85aae8317555f73dbe261556.tar.xz
puzzles: refactor and resync with upstream
This brings puzzles up-to-date with upstream revision 2d333750272c3967cfd5cd3677572cddeaad5932, though certain changes made by me, including cursor-only Untangle and some compilation fixes remain. Upstream code has been moved to its separate subdirectory and future syncs can be done by simply copying over the new sources. Change-Id: Ia6506ca5f78c3627165ea6791d38db414ace0804
Diffstat (limited to 'apps/plugins/puzzles/src/printing.c')
-rw-r--r--apps/plugins/puzzles/src/printing.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/apps/plugins/puzzles/src/printing.c b/apps/plugins/puzzles/src/printing.c
new file mode 100644
index 0000000..e921a4d
--- /dev/null
+++ b/apps/plugins/puzzles/src/printing.c
@@ -0,0 +1,247 @@
+/*
+ * printing.c: Cross-platform printing manager. Handles document
+ * setup and layout.
+ */
+
+#include "puzzles.h"
+
+struct puzzle {
+ const game *game;
+ game_params *par;
+ game_state *st;
+ game_state *st2;
+};
+
+struct document {
+ int pw, ph;
+ int npuzzles;
+ struct puzzle *puzzles;
+ int puzzlesize;
+ int got_solns;
+ float *colwid, *rowht;
+ float userscale;
+};
+
+/*
+ * Create a new print document. pw and ph are the layout
+ * parameters: they state how many puzzles will be printed across
+ * the page, and down the page.
+ */
+document *document_new(int pw, int ph, float userscale)
+{
+ document *doc = snew(document);
+
+ doc->pw = pw;
+ doc->ph = ph;
+ doc->puzzles = NULL;
+ doc->puzzlesize = doc->npuzzles = 0;
+ doc->got_solns = FALSE;
+
+ doc->colwid = snewn(pw, float);
+ doc->rowht = snewn(ph, float);
+
+ doc->userscale = userscale;
+
+ return doc;
+}
+
+/*
+ * Free a document structure, whether it's been printed or not.
+ */
+void document_free(document *doc)
+{
+ int i;
+
+ for (i = 0; i < doc->npuzzles; i++) {
+ doc->puzzles[i].game->free_params(doc->puzzles[i].par);
+ doc->puzzles[i].game->free_game(doc->puzzles[i].st);
+ if (doc->puzzles[i].st2)
+ doc->puzzles[i].game->free_game(doc->puzzles[i].st2);
+ }
+
+ sfree(doc->colwid);
+ sfree(doc->rowht);
+
+ sfree(doc->puzzles);
+ sfree(doc);
+}
+
+/*
+ * Called from midend.c to add a puzzle to be printed. Provides a
+ * game_params (for initial layout computation), a game_state, and
+ * optionally a second game_state to be printed in parallel on
+ * another sheet (typically the solution to the first game_state).
+ */
+void document_add_puzzle(document *doc, const game *game, game_params *par,
+ game_state *st, game_state *st2)
+{
+ if (doc->npuzzles >= doc->puzzlesize) {
+ doc->puzzlesize += 32;
+ doc->puzzles = sresize(doc->puzzles, doc->puzzlesize, struct puzzle);
+ }
+ doc->puzzles[doc->npuzzles].game = game;
+ doc->puzzles[doc->npuzzles].par = par;
+ doc->puzzles[doc->npuzzles].st = st;
+ doc->puzzles[doc->npuzzles].st2 = st2;
+ doc->npuzzles++;
+ if (st2)
+ doc->got_solns = TRUE;
+}
+
+static void get_puzzle_size(document *doc, struct puzzle *pz,
+ float *w, float *h, float *scale)
+{
+ float ww, hh, ourscale;
+
+ /* Get the preferred size of the game, in mm. */
+ pz->game->print_size(pz->par, &ww, &hh);
+
+ /* Adjust for user-supplied scale factor. */
+ ourscale = doc->userscale;
+
+ /*
+ * FIXME: scale it down here if it's too big for the page size.
+ * Rather than do complicated things involving scaling all
+ * columns down in proportion, the simplest approach seems to
+ * me to be to scale down until the game fits within one evenly
+ * divided cell of the page (i.e. width/pw by height/ph).
+ *
+ * In order to do this step we need the page size available.
+ */
+
+ *scale = ourscale;
+ *w = ww * ourscale;
+ *h = hh * ourscale;
+}
+
+/*
+ * Having accumulated a load of puzzles, actually do the printing.
+ */
+void document_print(document *doc, drawing *dr)
+{
+ int ppp; /* puzzles per page */
+ int pages, passes;
+ int page, pass;
+ int pageno;
+
+ 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++;
+ }
+ }
+
+ print_end_doc(dr);
+}