mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 15:41:30 -07:00
Add printing support for GTK.
Printing is only available in GTK versions >= 2.10. We can only embed the page setup dialog on GTK >= 2.18, so on a GTK version less than that, we must use a separate page setup dialog. In GTK, printing is usually done one page at a time, so also modify printing.c to allow printing of a single page at a time. Create a separate drawing API for drawing to the screen and for printing. Create a vtable for functions which need to be different depending on whether they were called from the printing or drawing API. When a function is called from the printing API, it is passed a separate instance of the frontend than if it were called from the drawing API. In that instance of the frontend, an appropriate vtable is available depending on whether it was called from the printing or drawing API. The low-level functions used for printing are enabled even if printing is not enabled. This is in case we ever need to use them for something other than printing with GTK. For example, using Cairo as a printing backend when printing from the command line. Enabling the low-level functions even when GTK printing is not available also allows them to be compiled under as many build settings as possible, and thus lowers the chance of undetected breakage. Move the definition of ROOT2 from ps.c to puzzles.h so other files can use it (gtk.c needs it for hatching). Also add myself to the copyright list. [Committer's note: by 'printing', this log message refers to the GTK GUI printing system, which handles selecting a printer, printing to a file, previewing and so on. The existing facility to generate printable puzzles in Postscript form by running the GTK binaries in command-line mode with the --print option is unaffected. -SGT]
This commit is contained in:

committed by
Simon Tatham

parent
0d77dfc415
commit
b443a84efe
280
printing.c
280
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;
|
||||
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);
|
||||
return 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++;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user