ref: 02035753f817173a6861d1fc4bec437508cec42d
parent: 69f7e7f8f5890946f4625fc071eb3f8313b17238
author: Simon Tatham <anakin@pobox.com>
date: Tue Jun 7 13:57:50 EDT 2005
All the games in this collection have always defined their graphics in terms of a constant TILE_SIZE (or equivalent). Here's a surprisingly small patch which switches this constant into a run-time variable. The only observable behaviour change should be on Windows, which physically does not permit the creation of windows larger than the screen; if you try to create a puzzle (Net makes this plausible) large enough to encounter this restriction, the Windows front end should automatically re-adjust the puzzle's tile size so that it does fit within the available space. On GTK, I haven't done this, on the grounds that X _does_ permit windows larger than the screen, and many X window managers already provide the means to navigate around such a window. Gareth said he'd rather navigate around a huge Net window than have it shrunk to fit on one screen. I'm uncertain that this makes sense for all puzzles - Pattern in particular strikes me as something that might be better off shrunk to fit - so I may have to change policy later or make it configurable. On OS X, I also haven't done automatic shrinkage to fit on one screen, largely because I didn't have the courage to address the question of multiple monitors and what that means for the entire concept :-) [originally from svn r5913]
--- a/cube.c
+++ b/cube.c
@@ -157,7 +157,8 @@
enum { LEFT, RIGHT, UP, DOWN, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT };
-#define GRID_SCALE 48.0F
+#define PREFERRED_GRID_SCALE 48.0F
+#define GRID_SCALE (ds->gridscale)
#define ROLLTIME 0.13F
#define SQ(x) ( (x) * (x) )
@@ -1009,6 +1010,7 @@
}
struct game_drawstate {
+ float gridscale;
int ox, oy; /* pixel position of float origin */
};
@@ -1393,11 +1395,31 @@
return bb;
}
-static void game_size(game_params *params, int *x, int *y)
+#define XSIZE(bb, solid) \
+ ((int)(((bb).r - (bb).l + 2*(solid)->border) * GRID_SCALE))
+#define YSIZE(bb, solid) \
+ ((int)(((bb).d - (bb).u + 2*(solid)->border) * GRID_SCALE))
+
+static void game_size(game_params *params, game_drawstate *ds, int *x, int *y,
+ int expand)
{
struct bbox bb = find_bbox(params);
- *x = (int)((bb.r - bb.l + 2*solids[params->solid]->border) * GRID_SCALE);
- *y = (int)((bb.d - bb.u + 2*solids[params->solid]->border) * GRID_SCALE);
+ float gsx, gsy, gs;
+
+ gsx = *x / (bb.r - bb.l + 2*solids[params->solid]->border);
+ gsy = *y / (bb.d - bb.u + 2*solids[params->solid]->border);
+ gs = min(gsx, gsy);
+
+ if (expand)
+ ds->gridscale = gs;
+ else
+ ds->gridscale = min(gs, PREFERRED_GRID_SCALE);
+
+ ds->ox = (int)(-(bb.l - solids[params->solid]->border) * GRID_SCALE);
+ ds->oy = (int)(-(bb.u - solids[params->solid]->border) * GRID_SCALE);
+
+ *x = XSIZE(bb, solids[params->solid]);
+ *y = YSIZE(bb, solids[params->solid]);
}
static float *game_colours(frontend *fe, game_state *state, int *ncolours)
@@ -1421,10 +1443,8 @@
static game_drawstate *game_new_drawstate(game_state *state)
{
struct game_drawstate *ds = snew(struct game_drawstate);
- struct bbox bb = find_bbox(&state->params);
- ds->ox = (int)(-(bb.l - state->solid->border) * GRID_SCALE);
- ds->oy = (int)(-(bb.u - state->solid->border) * GRID_SCALE);
+ ds->ox = ds->oy = ds->gridscale = 0.0F;/* not decided yet */
return ds;
}
@@ -1435,8 +1455,8 @@
}
static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
- game_state *state, int dir, game_ui *ui,
- float animtime, float flashtime)
+ game_state *state, int dir, game_ui *ui,
+ float animtime, float flashtime)
{
int i, j;
struct bbox bb = find_bbox(&state->params);
@@ -1447,8 +1467,8 @@
game_state *newstate;
int square;
- draw_rect(fe, 0, 0, (int)((bb.r-bb.l+2.0F) * GRID_SCALE),
- (int)((bb.d-bb.u+2.0F) * GRID_SCALE), COL_BACKGROUND);
+ draw_rect(fe, 0, 0, XSIZE(bb, state->solid), YSIZE(bb, state->solid),
+ COL_BACKGROUND);
if (dir < 0) {
game_state *t;
@@ -1579,8 +1599,7 @@
}
sfree(poly);
- game_size(&state->params, &i, &j);
- draw_update(fe, 0, 0, i, j);
+ draw_update(fe, 0, 0, XSIZE(bb, state->solid), YSIZE(bb, state->solid));
/*
* Update the status bar.
--- a/fifteen.c
+++ b/fifteen.c
@@ -11,7 +11,8 @@
#include "puzzles.h"
-#define TILE_SIZE 48
+#define PREFERRED_TILE_SIZE 48
+#define TILE_SIZE (ds->tilesize)
#define BORDER (TILE_SIZE / 2)
#define HIGHLIGHT_WIDTH (TILE_SIZE / 20)
#define COORD(x) ( (x) * TILE_SIZE + BORDER )
@@ -456,6 +457,13 @@
{
}
+struct game_drawstate {
+ int started;
+ int w, h, bgcolour;
+ int *tiles;
+ int tilesize;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int gx, gy, dx, dy, ux, uy, up, p;
@@ -527,14 +535,23 @@
* Drawing routines.
*/
-struct game_drawstate {
- int started;
- int w, h, bgcolour;
- int *tiles;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times one more
+ * than the grid dimension (the border is half the width of the
+ * tiles).
+ */
+ tsx = *x / (params->w + 1);
+ tsy = *y / (params->h + 1);
+ ts = min(tsx, tsy);
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = TILE_SIZE * params->w + 2 * BORDER;
*y = TILE_SIZE * params->h + 2 * BORDER;
}
@@ -580,6 +597,7 @@
ds->h = state->h;
ds->bgcolour = COL_BACKGROUND;
ds->tiles = snewn(ds->w*ds->h, int);
+ ds->tilesize = 0; /* haven't decided yet */
for (i = 0; i < ds->w*ds->h; i++)
ds->tiles[i] = -1;
@@ -592,8 +610,8 @@
sfree(ds);
}
-static void draw_tile(frontend *fe, game_state *state, int x, int y,
- int tile, int flash_colour)
+static void draw_tile(frontend *fe, game_drawstate *ds, game_state *state,
+ int x, int y, int tile, int flash_colour)
{
if (tile == 0) {
draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE,
@@ -754,7 +772,7 @@
y = COORD(Y(state, i));
}
- draw_tile(fe, state, x, y, t, bgcolour);
+ draw_tile(fe, ds, state, x, y, t, bgcolour);
}
ds->tiles[i] = t0;
}
--- a/gtk.c
+++ b/gtk.c
@@ -79,6 +79,8 @@
void *paste_data;
int paste_data_len;
char *laststatus;
+ int pw, ph; /* pixmap size (w, h are area size) */
+ int ox, oy; /* offset of pixmap in drawing area */
};
void get_random_seed(void **randseed, int *randseedsize)
@@ -311,7 +313,7 @@
fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)],
fe->pixmap,
fe->bbox_l, fe->bbox_u,
- fe->bbox_l, fe->bbox_u,
+ fe->ox + fe->bbox_l, fe->oy + fe->bbox_u,
fe->bbox_r - fe->bbox_l, fe->bbox_d - fe->bbox_u);
}
}
@@ -397,7 +399,8 @@
if (event->type == GDK_BUTTON_RELEASE)
button += LEFT_RELEASE - LEFT_BUTTON;
- if (!midend_process_key(fe->me, event->x, event->y, button))
+ if (!midend_process_key(fe->me, event->x - fe->ox,
+ event->y - fe->oy, button))
gtk_widget_destroy(fe->window);
return TRUE;
@@ -421,7 +424,8 @@
else
return FALSE; /* don't even know what button! */
- if (!midend_process_key(fe->me, event->x, event->y, button))
+ if (!midend_process_key(fe->me, event->x - fe->ox,
+ event->y - fe->oy, button))
gtk_widget_destroy(fe->window);
return TRUE;
@@ -436,8 +440,8 @@
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
fe->pixmap,
+ event->area.x - fe->ox, event->area.y - fe->oy,
event->area.x, event->area.y,
- event->area.x, event->area.y,
event->area.width, event->area.height);
}
return TRUE;
@@ -463,15 +467,24 @@
{
frontend *fe = (frontend *)data;
GdkGC *gc;
+ int x, y;
if (fe->pixmap)
gdk_pixmap_unref(fe->pixmap);
- fe->pixmap = gdk_pixmap_new(widget->window, fe->w, fe->h, -1);
+ x = fe->w = event->width;
+ y = fe->h = event->height;
+ midend_size(fe->me, &x, &y, TRUE);
+ fe->pw = x;
+ fe->ph = y;
+ fe->ox = (fe->w - fe->pw) / 2;
+ fe->oy = (fe->h - fe->ph) / 2;
+ fe->pixmap = gdk_pixmap_new(widget->window, fe->pw, fe->ph, -1);
+
gc = gdk_gc_new(fe->area->window);
gdk_gc_set_foreground(gc, &fe->colours[0]);
- gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->w, fe->h);
+ gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->pw, fe->ph);
gdk_gc_unref(gc);
midend_force_redraw(fe->me);
@@ -816,6 +829,29 @@
gtk_widget_destroy(fe->window);
}
+static void get_size(frontend *fe, int *px, int *py)
+{
+ int x, y;
+
+ /*
+ * Currently I don't want to make the GTK port scale large
+ * puzzles to fit on the screen. This is because X does permit
+ * extremely large windows and many window managers provide a
+ * means of navigating round them, and the users I consulted
+ * before deciding said that they'd rather have enormous puzzle
+ * windows spanning multiple screen pages than have them
+ * shrunk. I could change my mind later or introduce
+ * configurability; this would be the place to do so, by
+ * replacing the initial values of x and y with the screen
+ * dimensions.
+ */
+ x = INT_MAX;
+ y = INT_MAX;
+ midend_size(fe->me, &x, &y, FALSE);
+ *px = x;
+ *py = y;
+}
+
static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
{
frontend *fe = (frontend *)data;
@@ -825,10 +861,11 @@
midend_set_params(fe->me, params);
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
- gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ get_size(fe, &x, &y);
fe->w = x;
fe->h = y;
+ gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ gtk_window_resize(GTK_WINDOW(fe->window), 1, 1);
}
GdkAtom compound_text_atom, utf8_string_atom;
@@ -969,10 +1006,11 @@
return;
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
- gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ get_size(fe, &x, &y);
fe->w = x;
fe->h = y;
+ gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ gtk_window_resize(GTK_WINDOW(fe->window), 1, 1);
}
static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
@@ -1201,12 +1239,12 @@
fe->statusbar = NULL;
fe->area = gtk_drawing_area_new();
- midend_size(fe->me, &x, &y);
+ get_size(fe, &x, &y);
gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
fe->w = x;
fe->h = y;
- gtk_box_pack_end(vbox, fe->area, FALSE, FALSE, 0);
+ gtk_box_pack_end(vbox, fe->area, TRUE, TRUE, 0);
fe->pixmap = NULL;
fe->fonts = NULL;
@@ -1245,6 +1283,9 @@
gtk_widget_show(fe->area);
gtk_widget_show(fe->window);
+
+ gdk_window_set_background(fe->area->window, &fe->colours[0]);
+ gdk_window_set_background(fe->window->window, &fe->colours[0]);
return fe;
}
--- a/midend.c
+++ b/midend.c
@@ -48,6 +48,8 @@
char *laststatus;
int pressed_mouse_button;
+
+ int winwidth, winheight;
};
#define ensure(me) do { \
@@ -90,6 +92,7 @@
me->laststatus = NULL;
me->timing = FALSE;
me->elapsed = 0.0F;
+ me->winwidth = me->winheight = 0;
sfree(randseed);
@@ -134,9 +137,11 @@
sfree(me);
}
-void midend_size(midend_data *me, int *x, int *y)
+void midend_size(midend_data *me, int *x, int *y, int expand)
{
- me->ourgame->size(me->params, x, y);
+ me->ourgame->size(me->params, me->drawstate, x, y, expand);
+ me->winwidth = *x;
+ me->winheight = *y;
}
void midend_set_params(midend_data *me, game_params *params)
@@ -155,11 +160,18 @@
deactivate_timer(me->frontend);
}
+static void midend_size_new_drawstate(midend_data *me)
+{
+ me->ourgame->size(me->params, me->drawstate, &me->winwidth, &me->winheight,
+ TRUE);
+}
+
void midend_force_redraw(midend_data *me)
{
if (me->drawstate)
me->ourgame->free_drawstate(me->drawstate);
me->drawstate = me->ourgame->new_drawstate(me->states[0].state);
+ midend_size_new_drawstate(me);
midend_redraw(me);
}
@@ -217,6 +229,7 @@
me->nstates++;
me->statepos = 1;
me->drawstate = me->ourgame->new_drawstate(me->states[0].state);
+ midend_size_new_drawstate(me);
me->elapsed = 0.0F;
midend_set_timer(me);
if (me->ui)
--- a/mines.c
+++ b/mines.c
@@ -25,10 +25,11 @@
NCOLOURS
};
-#define TILE_SIZE 20
+#define PREFERRED_TILE_SIZE 20
+#define TILE_SIZE (ds->tilesize)
#define BORDER (TILE_SIZE * 3 / 2)
-#define HIGHLIGHT_WIDTH 2
-#define OUTER_HIGHLIGHT_WIDTH 3
+#define HIGHLIGHT_WIDTH (TILE_SIZE / 10)
+#define OUTER_HIGHLIGHT_WIDTH (BORDER / 10)
#define COORD(x) ( (x) * TILE_SIZE + BORDER )
#define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
@@ -2480,6 +2481,21 @@
{
}
+struct game_drawstate {
+ int w, h, started, tilesize;
+ signed char *grid;
+ /*
+ * Items in this `grid' array have all the same values as in
+ * the game_state grid, and in addition:
+ *
+ * - -10 means the tile was drawn `specially' as a result of a
+ * flash, so it will always need redrawing.
+ *
+ * - -22 and -23 mean the tile is highlighted for a possible
+ * click.
+ */
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
@@ -2605,23 +2621,23 @@
* Drawing routines.
*/
-struct game_drawstate {
- int w, h, started;
- signed char *grid;
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
+{
+ int tsx, tsy, ts;
/*
- * Items in this `grid' array have all the same values as in
- * the game_state grid, and in addition:
- *
- * - -10 means the tile was drawn `specially' as a result of a
- * flash, so it will always need redrawing.
- *
- * - -22 and -23 mean the tile is highlighted for a possible
- * click.
+ * Each window dimension equals the tile size times 3 more than
+ * the grid dimension (the border is 3/2 the width of the
+ * tiles).
*/
-};
+ tsx = *x / (params->w + 3);
+ tsy = *y / (params->h + 3);
+ ts = min(tsx, tsy);
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
-static void game_size(game_params *params, int *x, int *y)
-{
*x = BORDER * 2 + TILE_SIZE * params->w;
*y = BORDER * 2 + TILE_SIZE * params->h;
}
@@ -2711,6 +2727,7 @@
ds->w = state->w;
ds->h = state->h;
ds->started = FALSE;
+ ds->tilesize = 0; /* not decided yet */
ds->grid = snewn(ds->w * ds->h, signed char);
memset(ds->grid, -99, ds->w * ds->h);
@@ -2724,7 +2741,8 @@
sfree(ds);
}
-static void draw_tile(frontend *fe, int x, int y, int v, int bg)
+static void draw_tile(frontend *fe, game_drawstate *ds,
+ int x, int y, int v, int bg)
{
if (v < 0) {
int coords[12];
@@ -2958,7 +2976,7 @@
v -= 20;
if (ds->grid[y*ds->w+x] != v || bg != COL_BACKGROUND) {
- draw_tile(fe, COORD(x), COORD(y), v, bg);
+ draw_tile(fe, ds, COORD(x), COORD(y), v, bg);
ds->grid[y*ds->w+x] = (bg == COL_BACKGROUND ? v : -10);
}
}
--- a/net.c
+++ b/net.c
@@ -43,7 +43,8 @@
#define COUNT(x) ( (((x) & 0x08) >> 3) + (((x) & 0x04) >> 2) + \
(((x) & 0x02) >> 1) + ((x) & 0x01) )
-#define TILE_SIZE 32
+#define PREFERRED_TILE_SIZE 32
+#define TILE_SIZE (ds->tilesize)
#define TILE_BORDER 1
#define WINDOW_OFFSET 16
@@ -1791,6 +1792,14 @@
{
}
+struct game_drawstate {
+ int started;
+ int width, height;
+ int org_x, org_y;
+ int tilesize;
+ unsigned char *visible;
+};
+
/* ----------------------------------------------------------------------
* Process a move.
*/
@@ -1977,13 +1986,6 @@
* Routines for drawing the game position on the screen.
*/
-struct game_drawstate {
- int started;
- int width, height;
- int org_x, org_y;
- unsigned char *visible;
-};
-
static game_drawstate *game_new_drawstate(game_state *state)
{
game_drawstate *ds = snew(game_drawstate);
@@ -1993,6 +1995,7 @@
ds->height = state->height;
ds->org_x = ds->org_y = -1;
ds->visible = snewn(state->width * state->height, unsigned char);
+ ds->tilesize = 0; /* undecided yet */
memset(ds->visible, 0xFF, state->width * state->height);
return ds;
@@ -2004,8 +2007,23 @@
sfree(ds);
}
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds, int *x, int *y,
+ int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times the grid
+ * dimension, plus TILE_BORDER, plus twice WINDOW_OFFSET.
+ */
+ tsx = (*x - 2*WINDOW_OFFSET - TILE_BORDER) / params->width;
+ tsy = (*y - 2*WINDOW_OFFSET - TILE_BORDER) / params->height;
+ ts = min(tsx, tsy);
+
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = WINDOW_OFFSET * 2 + TILE_SIZE * params->width + TILE_BORDER;
*y = WINDOW_OFFSET * 2 + TILE_SIZE * params->height + TILE_BORDER;
}
@@ -2092,8 +2110,8 @@
/*
* draw_barrier_corner() and draw_barrier() are passed physical coords
*/
-static void draw_barrier_corner(frontend *fe, int x, int y, int dx, int dy,
- int phase)
+static void draw_barrier_corner(frontend *fe, game_drawstate *ds,
+ int x, int y, int dx, int dy, int phase)
{
int bx = WINDOW_OFFSET + TILE_SIZE * x;
int by = WINDOW_OFFSET + TILE_SIZE * y;
@@ -2116,7 +2134,8 @@
}
}
-static void draw_barrier(frontend *fe, int x, int y, int dir, int phase)
+static void draw_barrier(frontend *fe, game_drawstate *ds,
+ int x, int y, int dir, int phase)
{
int bx = WINDOW_OFFSET + TILE_SIZE * x;
int by = WINDOW_OFFSET + TILE_SIZE * y;
@@ -2338,7 +2357,7 @@
* At least one barrier terminates here. Draw a
* corner.
*/
- draw_barrier_corner(fe, x, y,
+ draw_barrier_corner(fe, ds, x, y,
X(dir)+X(A(dir)), Y(dir)+Y(A(dir)),
phase);
}
@@ -2346,7 +2365,7 @@
for (dir = 1; dir < 0x10; dir <<= 1)
if (barrier(state, GX(x), GY(y)) & dir)
- draw_barrier(fe, x, y, dir, phase);
+ draw_barrier(fe, ds, x, y, dir, phase);
}
unclip(fe);
@@ -2388,19 +2407,19 @@
for (x = 0; x < ds->width; x++) {
if (x+1 < ds->width) {
if (barrier(state, GX(x), GY(0)) & R)
- draw_barrier_corner(fe, x, -1, +1, +1, phase);
+ draw_barrier_corner(fe, ds, x, -1, +1, +1, phase);
if (barrier(state, GX(x), GY(ds->height-1)) & R)
- draw_barrier_corner(fe, x, ds->height, +1, -1, phase);
+ draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase);
}
if (barrier(state, GX(x), GY(0)) & U) {
- draw_barrier_corner(fe, x, -1, -1, +1, phase);
- draw_barrier_corner(fe, x, -1, +1, +1, phase);
- draw_barrier(fe, x, -1, D, phase);
+ draw_barrier_corner(fe, ds, x, -1, -1, +1, phase);
+ draw_barrier_corner(fe, ds, x, -1, +1, +1, phase);
+ draw_barrier(fe, ds, x, -1, D, phase);
}
if (barrier(state, GX(x), GY(ds->height-1)) & D) {
- draw_barrier_corner(fe, x, ds->height, -1, -1, phase);
- draw_barrier_corner(fe, x, ds->height, +1, -1, phase);
- draw_barrier(fe, x, ds->height, U, phase);
+ draw_barrier_corner(fe, ds, x, ds->height, -1, -1, phase);
+ draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase);
+ draw_barrier(fe, ds, x, ds->height, U, phase);
}
}
@@ -2407,19 +2426,19 @@
for (y = 0; y < ds->height; y++) {
if (y+1 < ds->height) {
if (barrier(state, GX(0), GY(y)) & D)
- draw_barrier_corner(fe, -1, y, +1, +1, phase);
+ draw_barrier_corner(fe, ds, -1, y, +1, +1, phase);
if (barrier(state, GX(ds->width-1), GY(y)) & D)
- draw_barrier_corner(fe, ds->width, y, -1, +1, phase);
+ draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase);
}
if (barrier(state, GX(0), GY(y)) & L) {
- draw_barrier_corner(fe, -1, y, +1, -1, phase);
- draw_barrier_corner(fe, -1, y, +1, +1, phase);
- draw_barrier(fe, -1, y, R, phase);
+ draw_barrier_corner(fe, ds, -1, y, +1, -1, phase);
+ draw_barrier_corner(fe, ds, -1, y, +1, +1, phase);
+ draw_barrier(fe, ds, -1, y, R, phase);
}
if (barrier(state, GX(ds->width-1), GY(y)) & R) {
- draw_barrier_corner(fe, ds->width, y, -1, -1, phase);
- draw_barrier_corner(fe, ds->width, y, -1, +1, phase);
- draw_barrier(fe, ds->width, y, L, phase);
+ draw_barrier_corner(fe, ds, ds->width, y, -1, -1, phase);
+ draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase);
+ draw_barrier(fe, ds, ds->width, y, L, phase);
}
}
}
--- a/netslide.c
+++ b/netslide.c
@@ -52,7 +52,8 @@
#define COUNT(x) ( (((x) & 0x08) >> 3) + (((x) & 0x04) >> 2) + \
(((x) & 0x02) >> 1) + ((x) & 0x01) )
-#define TILE_SIZE 48
+#define PREFERRED_TILE_SIZE 48
+#define TILE_SIZE (ds->tilesize)
#define BORDER TILE_SIZE
#define TILE_BORDER 1
#define WINDOW_OFFSET 0
@@ -1050,6 +1051,13 @@
{
}
+struct game_drawstate {
+ int started;
+ int width, height;
+ int tilesize;
+ unsigned char *visible;
+};
+
static game_state *make_move(game_state *state, game_ui *ui,
game_drawstate *ds, int x, int y, int button)
{
@@ -1131,12 +1139,6 @@
* Routines for drawing the game position on the screen.
*/
-struct game_drawstate {
- int started;
- int width, height;
- unsigned char *visible;
-};
-
static game_drawstate *game_new_drawstate(game_state *state)
{
game_drawstate *ds = snew(game_drawstate);
@@ -1145,6 +1147,7 @@
ds->width = state->width;
ds->height = state->height;
ds->visible = snewn(state->width * state->height, unsigned char);
+ ds->tilesize = 0; /* not decided yet */
memset(ds->visible, 0xFF, state->width * state->height);
return ds;
@@ -1156,8 +1159,25 @@
sfree(ds);
}
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds, int *x, int *y,
+ int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times two more
+ * than the grid dimension (the border containing the arrows is
+ * the same width as the tiles), plus TILE_BORDER, plus twice
+ * WINDOW_OFFSET.
+ */
+ tsx = (*x - 2*WINDOW_OFFSET - TILE_BORDER) / (params->width + 2);
+ tsy = (*y - 2*WINDOW_OFFSET - TILE_BORDER) / (params->height + 2);
+ ts = min(tsx, tsy);
+
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * params->width + TILE_BORDER;
*y = BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * params->height + TILE_BORDER;
}
@@ -1248,7 +1268,8 @@
draw_rect(fe, mx, my, dx, dy, colour);
}
-static void draw_barrier_corner(frontend *fe, int x, int y, int dir, int phase)
+static void draw_barrier_corner(frontend *fe, game_drawstate *ds,
+ int x, int y, int dir, int phase)
{
int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x;
int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y;
@@ -1276,7 +1297,8 @@
}
}
-static void draw_barrier(frontend *fe, int x, int y, int dir, int phase)
+static void draw_barrier(frontend *fe, game_drawstate *ds,
+ int x, int y, int dir, int phase)
{
int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x;
int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y;
@@ -1294,8 +1316,8 @@
}
}
-static void draw_tile(frontend *fe, game_state *state, int x, int y, int tile,
- float xshift, float yshift)
+static void draw_tile(frontend *fe, game_drawstate *ds, game_state *state,
+ int x, int y, int tile, float xshift, float yshift)
{
int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x + (xshift * TILE_SIZE);
int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y + (yshift * TILE_SIZE);
@@ -1433,7 +1455,8 @@
draw_update(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
}
-static void draw_tile_barriers(frontend *fe, game_state *state, int x, int y)
+static void draw_tile_barriers(frontend *fe, game_drawstate *ds,
+ game_state *state, int x, int y)
{
int phase;
int dir;
@@ -1445,16 +1468,17 @@
for (phase = 0; phase < 2; phase++) {
for (dir = 1; dir < 0x10; dir <<= 1)
if (barrier(state, x, y) & (dir << 4))
- draw_barrier_corner(fe, x, y, dir << 4, phase);
+ draw_barrier_corner(fe, ds, x, y, dir << 4, phase);
for (dir = 1; dir < 0x10; dir <<= 1)
if (barrier(state, x, y) & dir)
- draw_barrier(fe, x, y, dir, phase);
+ draw_barrier(fe, ds, x, y, dir, phase);
}
draw_update(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
}
-static void draw_arrow(frontend *fe, int x, int y, int xdx, int xdy)
+static void draw_arrow(frontend *fe, game_drawstate *ds,
+ int x, int y, int xdx, int xdy)
{
int coords[14];
int ydy = -xdx, ydx = xdy;
@@ -1507,32 +1531,32 @@
for (x = 0; x < ds->width; x++) {
if (barrier(state, x, 0) & UL)
- draw_barrier_corner(fe, x, -1, LD, phase);
+ draw_barrier_corner(fe, ds, x, -1, LD, phase);
if (barrier(state, x, 0) & RU)
- draw_barrier_corner(fe, x, -1, DR, phase);
+ draw_barrier_corner(fe, ds, x, -1, DR, phase);
if (barrier(state, x, 0) & U)
- draw_barrier(fe, x, -1, D, phase);
+ draw_barrier(fe, ds, x, -1, D, phase);
if (barrier(state, x, ds->height-1) & DR)
- draw_barrier_corner(fe, x, ds->height, RU, phase);
+ draw_barrier_corner(fe, ds, x, ds->height, RU, phase);
if (barrier(state, x, ds->height-1) & LD)
- draw_barrier_corner(fe, x, ds->height, UL, phase);
+ draw_barrier_corner(fe, ds, x, ds->height, UL, phase);
if (barrier(state, x, ds->height-1) & D)
- draw_barrier(fe, x, ds->height, U, phase);
+ draw_barrier(fe, ds, x, ds->height, U, phase);
}
for (y = 0; y < ds->height; y++) {
if (barrier(state, 0, y) & UL)
- draw_barrier_corner(fe, -1, y, RU, phase);
+ draw_barrier_corner(fe, ds, -1, y, RU, phase);
if (barrier(state, 0, y) & LD)
- draw_barrier_corner(fe, -1, y, DR, phase);
+ draw_barrier_corner(fe, ds, -1, y, DR, phase);
if (barrier(state, 0, y) & L)
- draw_barrier(fe, -1, y, R, phase);
+ draw_barrier(fe, ds, -1, y, R, phase);
if (barrier(state, ds->width-1, y) & RU)
- draw_barrier_corner(fe, ds->width, y, UL, phase);
+ draw_barrier_corner(fe, ds, ds->width, y, UL, phase);
if (barrier(state, ds->width-1, y) & DR)
- draw_barrier_corner(fe, ds->width, y, LD, phase);
+ draw_barrier_corner(fe, ds, ds->width, y, LD, phase);
if (barrier(state, ds->width-1, y) & R)
- draw_barrier(fe, ds->width, y, L, phase);
+ draw_barrier(fe, ds, ds->width, y, L, phase);
}
}
@@ -1541,13 +1565,13 @@
*/
for (x = 0; x < ds->width; x++) {
if (x == state->cx) continue;
- draw_arrow(fe, x, 0, +1, 0);
- draw_arrow(fe, x+1, ds->height, -1, 0);
+ draw_arrow(fe, ds, x, 0, +1, 0);
+ draw_arrow(fe, ds, x+1, ds->height, -1, 0);
}
for (y = 0; y < ds->height; y++) {
if (y == state->cy) continue;
- draw_arrow(fe, ds->width, y, 0, +1);
- draw_arrow(fe, 0, y+1, 0, -1);
+ draw_arrow(fe, ds, ds->width, y, 0, +1);
+ draw_arrow(fe, ds, 0, y+1, 0, -1);
}
}
@@ -1627,15 +1651,15 @@
float xs = (y == state->last_move_row ? xshift : 0.0);
float ys = (x == state->last_move_col ? yshift : 0.0);
- draw_tile(fe, state, x, y, c, xs, ys);
+ draw_tile(fe, ds, state, x, y, c, xs, ys);
if (xs < 0 && x == 0)
- draw_tile(fe, state, state->width, y, c, xs, ys);
+ draw_tile(fe, ds, state, state->width, y, c, xs, ys);
else if (xs > 0 && x == state->width - 1)
- draw_tile(fe, state, -1, y, c, xs, ys);
+ draw_tile(fe, ds, state, -1, y, c, xs, ys);
else if (ys < 0 && y == 0)
- draw_tile(fe, state, x, state->height, c, xs, ys);
+ draw_tile(fe, ds, state, x, state->height, c, xs, ys);
else if (ys > 0 && y == state->height - 1)
- draw_tile(fe, state, x, -1, c, xs, ys);
+ draw_tile(fe, ds, state, x, -1, c, xs, ys);
if (x == state->last_move_col || y == state->last_move_row)
index(state, ds->visible, x, y) = 0xFF;
@@ -1646,7 +1670,7 @@
for (x = 0; x < ds->width; x++)
for (y = 0; y < ds->height; y++)
- draw_tile_barriers(fe, state, x, y);
+ draw_tile_barriers(fe, ds, state, x, y);
unclip(fe);
--- a/nullgame.c
+++ b/nullgame.c
@@ -147,6 +147,10 @@
{
}
+struct game_drawstate {
+ int FIXME;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
@@ -157,11 +161,8 @@
* Drawing routines.
*/
-struct game_drawstate {
- int FIXME;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
*x = *y = 200; /* FIXME */
}
--- a/osx.m
+++ b/osx.m
@@ -470,7 +470,8 @@
frame.origin.y = 0;
frame.origin.x = 0;
- midend_size(me, &w, &h);
+ w = h = INT_MAX;
+ midend_size(me, &w, &h, FALSE);
frame.size.width = w;
frame.size.height = h;
@@ -501,7 +502,8 @@
* initWithGame: simply call that one and pass it NULL.
*/
midend_new_game(me);
- midend_size(me, &w, &h);
+ w = h = INT_MAX;
+ midend_size(me, &w, &h, FALSE);
rect.size.width = w;
rect.size.height = h;
@@ -771,7 +773,8 @@
NSSize size = {0,0};
int w, h;
- midend_size(me, &w, &h);
+ w = h = INT_MAX;
+ midend_size(me, &w, &h, FALSE);
size.width = w;
size.height = h;
--- a/pattern.c
+++ b/pattern.c
@@ -20,15 +20,17 @@
NCOLOURS
};
-#define BORDER 18
+#define PREFERRED_TILE_SIZE 24
+#define TILE_SIZE (ds->tilesize)
+#define BORDER (3 * TILE_SIZE / 4)
#define TLBORDER(d) ( (d) / 5 + 2 )
-#define GUTTER 12
-#define TILE_SIZE 24
+#define GUTTER (TILE_SIZE / 2)
#define FROMCOORD(d, x) \
( ((x) - (BORDER + GUTTER + TILE_SIZE * TLBORDER(d))) / TILE_SIZE )
#define SIZE(d) (2*BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (d)))
+#define GETTILESIZE(d, w) (w / (2 + TLBORDER(d) + (d)))
#define TOCOORD(d, x) (BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (x)))
@@ -763,6 +765,13 @@
{
}
+struct game_drawstate {
+ int started;
+ int w, h;
+ int tilesize;
+ unsigned char *visible;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
game_state *ret;
@@ -895,14 +904,17 @@
* Drawing routines.
*/
-struct game_drawstate {
- int started;
- int w, h;
- unsigned char *visible;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
+ int ts;
+
+ ts = min(GETTILESIZE(params->w, *x), GETTILESIZE(params->h, *y));
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = SIZE(params->w);
*y = SIZE(params->h);
}
@@ -941,6 +953,7 @@
ds->w = state->w;
ds->h = state->h;
ds->visible = snewn(ds->w * ds->h, unsigned char);
+ ds->tilesize = 0; /* not decided yet */
memset(ds->visible, 255, ds->w * ds->h);
return ds;
@@ -975,8 +988,8 @@
}
static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
- game_state *state, int dir, game_ui *ui,
- float animtime, float flashtime)
+ game_state *state, int dir, game_ui *ui,
+ float animtime, float flashtime)
{
int i, j;
int x1, x2, y1, y2;
--- a/puzzles.h
+++ b/puzzles.h
@@ -151,7 +151,7 @@
midend_data *midend_new(frontend *fe, const game *ourgame);
void midend_free(midend_data *me);
void midend_set_params(midend_data *me, game_params *params);
-void midend_size(midend_data *me, int *x, int *y);
+void midend_size(midend_data *me, int *x, int *y, int expand);
void midend_new_game(midend_data *me);
void midend_restart_game(midend_data *me);
void midend_stop_anim(midend_data *me);
@@ -256,7 +256,8 @@
game_state *newstate);
game_state *(*make_move)(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button);
- void (*size)(game_params *params, int *x, int *y);
+ void (*size)(game_params *params, game_drawstate *ds, int *x, int *y,
+ int expand);
float *(*colours)(frontend *fe, game_state *state, int *ncolours);
game_drawstate *(*new_drawstate)(game_state *state);
void (*free_drawstate)(game_drawstate *ds);
--- a/rect.c
+++ b/rect.c
@@ -60,8 +60,9 @@
#define HRANGE(state,x,y) CRANGE(state,x,y,0,1)
#define VRANGE(state,x,y) CRANGE(state,x,y,1,0)
-#define TILE_SIZE 24
-#define BORDER 18
+#define PREFERRED_TILE_SIZE 24
+#define TILE_SIZE (ds->tilesize)
+#define BORDER (TILE_SIZE * 3 / 4)
#define CORNER_TOLERANCE 0.15F
#define CENTRE_TOLERANCE 0.15F
@@ -2188,6 +2189,12 @@
{
}
+struct game_drawstate {
+ int started;
+ int w, h, tilesize;
+ unsigned long *visible;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int xc, yc;
@@ -2292,14 +2299,23 @@
#define COLOUR(k) ( (k)==1 ? COL_LINE : COL_DRAG )
#define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) )
-struct game_drawstate {
- int started;
- int w, h;
- unsigned long *visible;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times 1.5 more
+ * than the grid dimension (the border is 3/4 the width of the
+ * tiles).
+ */
+ tsx = 2 * *x / (2 * params->w + 3);
+ tsy = 2 * *y / (2 * params->h + 3);
+ ts = min(tsx, tsy);
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = params->w * TILE_SIZE + 2*BORDER + 1;
*y = params->h * TILE_SIZE + 2*BORDER + 1;
}
@@ -2343,6 +2359,7 @@
ds->w = state->w;
ds->h = state->h;
ds->visible = snewn(ds->w * ds->h, unsigned long);
+ ds->tilesize = 0; /* not decided yet */
for (i = 0; i < ds->w * ds->h; i++)
ds->visible[i] = 0xFFFF;
@@ -2355,9 +2372,9 @@
sfree(ds);
}
-static void draw_tile(frontend *fe, game_state *state, int x, int y,
- unsigned char *hedge, unsigned char *vedge,
- unsigned char *corners, int correct)
+static void draw_tile(frontend *fe, game_drawstate *ds, game_state *state,
+ int x, int y, unsigned char *hedge, unsigned char *vedge,
+ unsigned char *corners, int correct)
{
int cx = COORD(x), cy = COORD(y);
char str[80];
@@ -2490,7 +2507,7 @@
c |= CORRECT;
if (index(ds,ds->visible,x,y) != c) {
- draw_tile(fe, state, x, y, hedge, vedge, corners,
+ draw_tile(fe, ds, state, x, y, hedge, vedge, corners,
(c & CORRECT) ? 1 : 0);
index(ds,ds->visible,x,y) = c;
}
--- a/sixteen.c
+++ b/sixteen.c
@@ -13,8 +13,9 @@
#include "puzzles.h"
-#define TILE_SIZE 48
-#define BORDER TILE_SIZE /* big border to fill with arrows */
+#define PREFERRED_TILE_SIZE 48
+#define TILE_SIZE (ds->tilesize)
+#define BORDER TILE_SIZE
#define HIGHLIGHT_WIDTH (TILE_SIZE / 20)
#define COORD(x) ( (x) * TILE_SIZE + BORDER )
#define FROMCOORD(x) ( ((x) - BORDER + 2*TILE_SIZE) / TILE_SIZE - 2 )
@@ -583,6 +584,13 @@
{
}
+struct game_drawstate {
+ int started;
+ int w, h, bgcolour;
+ int *tiles;
+ int tilesize;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button) {
int cx, cy;
@@ -645,14 +653,24 @@
* Drawing routines.
*/
-struct game_drawstate {
- int started;
- int w, h, bgcolour;
- int *tiles;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times two more
+ * than the grid dimension (the border is the same size as the
+ * tiles).
+ */
+ tsx = *x / (params->w + 2);
+ tsy = *y / (params->h + 2);
+ ts = min(tsx, tsy);
+
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = TILE_SIZE * params->w + 2 * BORDER;
*y = TILE_SIZE * params->h + 2 * BORDER;
}
@@ -698,6 +716,7 @@
ds->h = state->h;
ds->bgcolour = COL_BACKGROUND;
ds->tiles = snewn(ds->w*ds->h, int);
+ ds->tilesize = 0; /* haven't decided yet */
for (i = 0; i < ds->w*ds->h; i++)
ds->tiles[i] = -1;
@@ -710,7 +729,8 @@
sfree(ds);
}
-static void draw_tile(frontend *fe, game_state *state, int x, int y,
+static void draw_tile(frontend *fe, game_drawstate *ds,
+ game_state *state, int x, int y,
int tile, int flash_colour)
{
if (tile == 0) {
@@ -746,7 +766,8 @@
draw_update(fe, x, y, TILE_SIZE, TILE_SIZE);
}
-static void draw_arrow(frontend *fe, int x, int y, int xdx, int xdy)
+static void draw_arrow(frontend *fe, game_drawstate *ds,
+ int x, int y, int xdx, int xdy)
{
int coords[14];
int ydy = -xdx, ydx = xdy;
@@ -814,12 +835,12 @@
* Arrows for making moves.
*/
for (i = 0; i < state->w; i++) {
- draw_arrow(fe, COORD(i), COORD(0), +1, 0);
- draw_arrow(fe, COORD(i+1), COORD(state->h), -1, 0);
+ draw_arrow(fe, ds, COORD(i), COORD(0), +1, 0);
+ draw_arrow(fe, ds, COORD(i+1), COORD(state->h), -1, 0);
}
for (i = 0; i < state->h; i++) {
- draw_arrow(fe, COORD(state->w), COORD(i), 0, +1);
- draw_arrow(fe, COORD(0), COORD(i+1), 0, -1);
+ draw_arrow(fe, ds, COORD(state->w), COORD(i), 0, +1);
+ draw_arrow(fe, ds, COORD(0), COORD(i+1), 0, -1);
}
ds->started = TRUE;
@@ -917,9 +938,9 @@
x2 = y2 = -1;
}
- draw_tile(fe, state, x, y, t, bgcolour);
+ draw_tile(fe, ds, state, x, y, t, bgcolour);
if (x2 != -1 || y2 != -1)
- draw_tile(fe, state, x2, y2, t, bgcolour);
+ draw_tile(fe, ds, state, x2, y2, t, bgcolour);
}
ds->tiles[i] = t0;
}
--- a/solo.c
+++ b/solo.c
@@ -107,8 +107,9 @@
typedef unsigned char digit;
#define ORDER_MAX 255
-#define TILE_SIZE 32
-#define BORDER 18
+#define PREFERRED_TILE_SIZE 32
+#define TILE_SIZE (ds->tilesize)
+#define BORDER (TILE_SIZE / 2)
#define FLASH_TIME 0.4F
@@ -1869,6 +1870,17 @@
}
}
+struct game_drawstate {
+ int started;
+ int c, r, cr;
+ int tilesize;
+ digit *grid;
+ unsigned char *pencil;
+ unsigned char *hl;
+ /* This is scratch space used within a single call to game_redraw. */
+ int *entered_items;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
@@ -1972,25 +1984,23 @@
* Drawing routines.
*/
-struct game_drawstate {
- int started;
- int c, r, cr;
- digit *grid;
- unsigned char *pencil;
- unsigned char *hl;
- /* This is scratch space used within a single call to game_redraw. */
- int *entered_items;
-};
+#define SIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
+#define GETTILESIZE(cr, w) ( (w-1) / (cr+1) )
-#define XSIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
-#define YSIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
int c = params->c, r = params->r, cr = c*r;
+ int ts;
- *x = XSIZE(cr);
- *y = YSIZE(cr);
+ ts = min(GETTILESIZE(cr, *x), GETTILESIZE(cr, *y));
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
+ *x = SIZE(cr);
+ *y = SIZE(cr);
}
static float *game_colours(frontend *fe, game_state *state, int *ncolours)
@@ -2043,6 +2053,7 @@
ds->hl = snewn(cr*cr, unsigned char);
memset(ds->hl, 0, cr*cr);
ds->entered_items = snewn(cr*cr, int);
+ ds->tilesize = 0; /* not decided yet */
return ds;
}
@@ -2174,7 +2185,7 @@
* all games should start by drawing a big
* background-colour rectangle covering the whole window.
*/
- draw_rect(fe, 0, 0, XSIZE(cr), YSIZE(cr), COL_BACKGROUND);
+ draw_rect(fe, 0, 0, SIZE(cr), SIZE(cr), COL_BACKGROUND);
/*
* Draw the grid.
@@ -2240,7 +2251,7 @@
* Update the _entire_ grid if necessary.
*/
if (!ds->started) {
- draw_update(fe, 0, 0, XSIZE(cr), YSIZE(cr));
+ draw_update(fe, 0, 0, SIZE(cr), SIZE(cr));
ds->started = TRUE;
}
}
--- a/twiddle.c
+++ b/twiddle.c
@@ -14,7 +14,8 @@
#include "puzzles.h"
-#define TILE_SIZE 48
+#define PREFERRED_TILE_SIZE 48
+#define TILE_SIZE (ds->tilesize)
#define BORDER (TILE_SIZE / 2)
#define HIGHLIGHT_WIDTH (TILE_SIZE / 20)
#define COORD(x) ( (x) * TILE_SIZE + BORDER )
@@ -621,6 +622,13 @@
{
}
+struct game_drawstate {
+ int started;
+ int w, h, bgcolour;
+ int *grid;
+ int tilesize;
+};
+
static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
int x, int y, int button)
{
@@ -706,14 +714,23 @@
* Drawing routines.
*/
-struct game_drawstate {
- int started;
- int w, h, bgcolour;
- int *grid;
-};
-
-static void game_size(game_params *params, int *x, int *y)
+static void game_size(game_params *params, game_drawstate *ds,
+ int *x, int *y, int expand)
{
+ int tsx, tsy, ts;
+ /*
+ * Each window dimension equals the tile size times one more
+ * than the grid dimension (the border is half the width of the
+ * tiles).
+ */
+ tsx = *x / (params->w + 1);
+ tsy = *y / (params->h + 1);
+ ts = min(tsx, tsy);
+ if (expand)
+ ds->tilesize = ts;
+ else
+ ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
+
*x = TILE_SIZE * params->w + 2 * BORDER;
*y = TILE_SIZE * params->h + 2 * BORDER;
}
@@ -761,6 +778,7 @@
ds->h = state->h;
ds->bgcolour = COL_BACKGROUND;
ds->grid = snewn(ds->w*ds->h, int);
+ ds->tilesize = 0; /* haven't decided yet */
for (i = 0; i < ds->w*ds->h; i++)
ds->grid[i] = -1;
@@ -794,8 +812,9 @@
}
}
-static void draw_tile(frontend *fe, game_state *state, int x, int y,
- int tile, int flash_colour, struct rotation *rot)
+static void draw_tile(frontend *fe, game_drawstate *ds, game_state *state,
+ int x, int y, int tile, int flash_colour,
+ struct rotation *rot)
{
int coords[8];
char str[40];
@@ -1110,7 +1129,7 @@
ds->grid[i] != t || ds->grid[i] == -1 || t == -1) {
int x = COORD(tx), y = COORD(ty);
- draw_tile(fe, state, x, y, state->grid[i], bgcolour, rot);
+ draw_tile(fe, ds, state, x, y, state->grid[i], bgcolour, rot);
ds->grid[i] = t;
}
}
--- a/windows.c
+++ b/windows.c
@@ -19,6 +19,7 @@
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <limits.h>
#include <time.h>
#include "puzzles.h"
@@ -406,11 +407,57 @@
}
}
+static void check_window_size(frontend *fe, int *px, int *py)
+{
+ RECT r;
+ int x, y, sy;
+
+ if (fe->statusbar) {
+ RECT sr;
+ GetWindowRect(fe->statusbar, &sr);
+ sy = sr.bottom - sr.top;
+ } else {
+ sy = 0;
+ }
+
+ /*
+ * See if we actually got the window size we wanted, and adjust
+ * the puzzle size if not.
+ */
+ GetClientRect(fe->hwnd, &r);
+ x = r.right - r.left;
+ y = r.bottom - r.top - sy;
+ midend_size(fe->me, &x, &y, FALSE);
+ if (x != r.right - r.left || y != r.bottom - r.top) {
+ /*
+ * Resize the window, now we know what size we _really_
+ * want it to be.
+ */
+ r.left = r.top = 0;
+ r.right = x;
+ r.bottom = y + sy;
+ AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
+ (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED),
+ TRUE, 0);
+ SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ if (fe->statusbar) {
+ GetClientRect(fe->hwnd, &r);
+ SetWindowPos(fe->statusbar, NULL, 0, r.bottom-r.top-sy, r.right-r.left,
+ sy, SWP_NOZORDER);
+ }
+
+ *px = x;
+ *py = y;
+}
+
static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
{
frontend *fe;
int x, y;
- RECT r, sr;
+ RECT r;
HDC hdc;
fe = snew(frontend);
@@ -431,7 +478,6 @@
fe->inst = inst;
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
fe->timer = 0;
@@ -459,6 +505,9 @@
}
}
+ x = y = INT_MAX; /* find puzzle's preferred size */
+ midend_size(fe->me, &x, &y, FALSE);
+
r.left = r.top = 0;
r.right = x;
r.bottom = y;
@@ -473,6 +522,14 @@
r.right - r.left, r.bottom - r.top,
NULL, NULL, inst, NULL);
+ if (midend_wants_statusbar(fe->me))
+ fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, 0, 0, /* status bar does these */
+ fe->hwnd, NULL, inst, NULL);
+ else
+ fe->statusbar = NULL;
+
{
HMENU bar = CreateMenu();
HMENU menu = CreateMenu();
@@ -541,20 +598,7 @@
SetMenu(fe->hwnd, bar);
}
- if (midend_wants_statusbar(fe->me)) {
- fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh",
- WS_CHILD | WS_VISIBLE,
- 0, 0, 0, 0, /* status bar does these */
- fe->hwnd, NULL, inst, NULL);
- GetWindowRect(fe->statusbar, &sr);
- SetWindowPos(fe->hwnd, NULL, 0, 0,
- r.right - r.left, r.bottom - r.top + sr.bottom - sr.top,
- SWP_NOMOVE | SWP_NOZORDER);
- SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top,
- SWP_NOZORDER);
- } else {
- fe->statusbar = NULL;
- }
+ check_window_size(fe, &x, &y);
hdc = GetDC(fe->hwnd);
fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
@@ -1075,7 +1119,8 @@
int x, y;
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
+ x = y = INT_MAX;
+ midend_size(fe->me, &x, &y, FALSE);
r.left = r.top = 0;
r.right = x;
@@ -1094,6 +1139,9 @@
r.right - r.left,
r.bottom - r.top + sr.bottom - sr.top,
SWP_NOMOVE | SWP_NOZORDER);
+
+ check_window_size(fe, &x, &y);
+
if (fe->statusbar != NULL)
SetWindowPos(fe->statusbar, NULL, 0, y, x,
sr.bottom - sr.top, SWP_NOZORDER);