New mechanism for automatic generation of the puzzle screenshots on

the web, which I hope will also end up being extended to generate
both Windows and X icons for each individual puzzle. The mechanism
is: for each puzzle there's a save file in the `icons' subdirectory
showing a game state which I think is a decent illustration of the
puzzle, and then there's a nasty set of scripts which runs each
puzzle binary, loads that save file, grabs a screenshot using xwd,
and munges it into shape.

In order to support this I've added two new options (--redo and
--windowid) to all the GTK puzzles, which I don't expect ever to be
used outside the icons makefile. I've also added two more options
(--load and --id) which force a GTK puzzle to treat its command-line
option as a save file or as a game ID respectively (the previous
behaviour was always to guess, and sometimes it guessed wrong).

[originally from svn r7014]
This commit is contained in:
Simon Tatham
2006-12-26 16:47:28 +00:00
parent ff7d2559ee
commit d55ad9fc42
31 changed files with 1238 additions and 20 deletions

128
gtk.c
View File

@ -1451,7 +1451,9 @@ static void add_menu_separator(GtkContainer *cont)
gtk_widget_show(menuitem);
}
static frontend *new_window(char *arg, char **error)
enum { ARG_EITHER, ARG_SAVE, ARG_ID }; /* for argtype */
static frontend *new_window(char *arg, int argtype, char **error)
{
frontend *fe;
GtkBox *vbox;
@ -1468,30 +1470,53 @@ static frontend *new_window(char *arg, char **error)
if (arg) {
char *err;
FILE *fp;
errbuf[0] = '\0';
/*
* Try treating the argument as a game ID.
*/
err = midend_game_id(fe->me, arg);
if (!err) {
/*
* It's a valid game ID.
*/
midend_new_game(fe->me);
} else {
FILE *fp = fopen(arg, "r");
switch (argtype) {
case ARG_ID:
err = midend_game_id(fe->me, arg);
if (!err)
midend_new_game(fe->me);
else
sprintf(errbuf, "Invalid game ID: %.800s", err);
break;
case ARG_SAVE:
fp = fopen(arg, "r");
if (!fp) {
sprintf(errbuf, "Supplied argument is neither a game ID (%.400s)"
" nor a save file (%.400s)", err, strerror(errno));
sprintf(errbuf, "Error opening file: %.800s", strerror(errno));
} else {
err = midend_deserialise(fe->me, savefile_read, fp);
if (err)
sprintf(errbuf, "%.800s", err);
sprintf(errbuf, "Invalid save file: %.800s", err);
fclose(fp);
}
}
break;
default /*case ARG_EITHER*/:
/*
* First try treating the argument as a game ID.
*/
err = midend_game_id(fe->me, arg);
if (!err) {
/*
* It's a valid game ID.
*/
midend_new_game(fe->me);
} else {
FILE *fp = fopen(arg, "r");
if (!fp) {
sprintf(errbuf, "Supplied argument is neither a game ID (%.400s)"
" nor a save file (%.400s)", err, strerror(errno));
} else {
err = midend_deserialise(fe->me, savefile_read, fp);
if (err)
sprintf(errbuf, "%.800s", err);
fclose(fp);
}
}
break;
}
if (*errbuf) {
*error = dupstr(errbuf);
midend_free(fe->me);
@ -1755,7 +1780,10 @@ int main(int argc, char **argv)
int ngenerate = 0, print = FALSE, px = 1, py = 1;
int soln = FALSE, colour = FALSE;
float scale = 1.0F;
float redo_proportion = 0.0F;
char *arg = NULL;
int argtype = ARG_EITHER;
int output_window_id = FALSE;
int doing_opts = TRUE;
int ac = argc;
char **av = argv;
@ -1826,6 +1854,42 @@ int main(int argc, char **argv)
pname);
return 1;
}
} else if (doing_opts && !strcmp(p, "--redo")) {
/*
* This is an internal option which I don't expect
* users to have any particular use for. The effect of
* --redo is that once the game has been loaded and
* initialised, the next move in the redo chain is
* replayed, and the game screen is redrawn part way
* through the making of the move. This is only
* meaningful if there _is_ a next move in the redo
* chain, which means in turn that this option is only
* useful if you're also passing a save file on the
* command line.
*
* This option is used by the script which generates
* the puzzle icons and website screenshots, and I
* don't imagine it's useful for anything else.
* (Unless, I suppose, users don't like my screenshots
* and want to generate their own in the same way for
* some repackaged version of the puzzles.)
*/
if (--ac > 0) {
redo_proportion = atof(*++av);
} else {
fprintf(stderr, "%s: no argument supplied to '--redo'\n",
pname);
return 1;
}
} else if (doing_opts && !strcmp(p, "--windowid")) {
/*
* Another internal option for the icon building
* script. This causes the window ID of the central
* drawing area (i.e. not including the menu bar or
* status bar) to be printed on standard output once
* the window has been drawn.
*/
output_window_id = TRUE;
} else if (doing_opts && (!strcmp(p, "--with-solutions") ||
!strcmp(p, "--with-solution") ||
!strcmp(p, "--with-solns") ||
@ -1842,6 +1906,10 @@ int main(int argc, char **argv)
return 1;
}
colour = TRUE;
} else if (doing_opts && !strcmp(p, "--load")) {
argtype = ARG_SAVE;
} else if (doing_opts && !strcmp(p, "--game")) {
argtype = ARG_ID;
} else if (doing_opts && !strcmp(p, "--")) {
doing_opts = FALSE;
} else if (!doing_opts || p[0] != '-') {
@ -1971,14 +2039,40 @@ int main(int argc, char **argv)
return 0;
} else {
frontend *fe;
gtk_init(&argc, &argv);
if (!new_window(argc > 1 ? argv[1] : NULL, &error)) {
fe = new_window(arg, argtype, &error);
if (!fe) {
fprintf(stderr, "%s: %s\n", pname, error);
return 1;
}
if (output_window_id) {
/*
* Some puzzles will not redraw their entire area if
* given a partially completed animation, which means
* we must redraw now and _then_ redraw again after
* freezing the move timer.
*/
midend_force_redraw(fe->me);
}
if (redo_proportion) {
/* Start a redo. */
midend_process_key(fe->me, 0, 0, 'r');
/* And freeze the timer at the specified position. */
midend_freeze_timer(fe->me, redo_proportion);
}
if (output_window_id) {
midend_redraw(fe->me);
printf("%p\n", (void *)GDK_WINDOW_XWINDOW(fe->area->window));
fflush(stdout);
}
gtk_main();
}