From 1e3e152de7cc491b63c5e351b5f603d307182b07 Mon Sep 17 00:00:00 2001 From: simon Date: Tue, 7 Jun 2005 17:57:50 +0000 Subject: [PATCH] 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 :-) git-svn-id: svn://svn.tartarus.org/sgt/puzzles@5913 cda61777-01e9-0310-a592-d414129be87e --- cube.c | 45 ++++++++++++++++++++-------- fifteen.c | 40 ++++++++++++++++++------- gtk.c | 65 ++++++++++++++++++++++++++++++++-------- midend.c | 17 +++++++++-- mines.c | 56 ++++++++++++++++++++++------------ net.c | 79 +++++++++++++++++++++++++++++------------------- netslide.c | 100 ++++++++++++++++++++++++++++++++++++++----------------------- nullgame.c | 11 +++---- osx.m | 9 ++++-- pattern.c | 37 +++++++++++++++-------- puzzles.h | 5 ++-- rect.c | 43 ++++++++++++++++++-------- sixteen.c | 55 +++++++++++++++++++++++----------- solo.c | 49 ++++++++++++++++++------------ twiddle.c | 41 ++++++++++++++++++------- windows.c | 82 +++++++++++++++++++++++++++++++++++++++----------- 16 files changed, 510 insertions(+), 224 deletions(-) diff --git a/cube.c b/cube.c index ffefa2f..e1c2865 100644 --- a/cube.c +++ b/cube.c @@ -157,7 +157,8 @@ enum { 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, } struct game_drawstate { + float gridscale; int ox, oy; /* pixel position of float origin */ }; @@ -1393,11 +1395,31 @@ static struct bbox find_bbox(game_params *params) 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 float *game_colours(frontend *fe, game_state *state, int *ncolours) 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_free_drawstate(game_drawstate *ds) } 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, } 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. diff --git a/fifteen.c b/fifteen.c index a6402c9..226de30 100644 --- 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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; } diff --git a/gtk.c b/gtk.c index 7483a98..91d44d6 100644 --- a/gtk.c +++ b/gtk.c @@ -79,6 +79,8 @@ struct frontend { 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 @@ void end_draw(frontend *fe) 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 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event, 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 @@ static gint motion_event(GtkWidget *widget, GdkEventMotion *event, 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,7 +440,7 @@ static gint expose_area(GtkWidget *widget, GdkEventExpose *event, gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], fe->pixmap, - event->area.x, event->area.y, + event->area.x - fe->ox, event->area.y - fe->oy, event->area.x, event->area.y, event->area.width, event->area.height); } @@ -463,15 +467,24 @@ static gint configure_area(GtkWidget *widget, { 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 @@ static void menu_key_event(GtkMenuItem *menuitem, gpointer data) 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 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) 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 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data) 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 @@ static frontend *new_window(char *game_id, char **error) 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; @@ -1246,6 +1284,9 @@ static frontend *new_window(char *game_id, char **error) 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; } diff --git a/midend.c b/midend.c index d8960a7..f4eeb61 100644 --- a/midend.c +++ b/midend.c @@ -48,6 +48,8 @@ struct midend_data { char *laststatus; int pressed_mouse_button; + + int winwidth, winheight; }; #define ensure(me) do { \ @@ -90,6 +92,7 @@ midend_data *midend_new(frontend *fe, const game *ourgame) me->laststatus = NULL; me->timing = FALSE; me->elapsed = 0.0F; + me->winwidth = me->winheight = 0; sfree(randseed); @@ -134,9 +137,11 @@ void midend_free(midend_data *me) 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 @@ static void midend_set_timer(midend_data *me) 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 @@ void midend_new_game(midend_data *me) 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) diff --git a/mines.c b/mines.c index 286f76d..0141517 100644 --- a/mines.c +++ b/mines.c @@ -25,10 +25,11 @@ enum { 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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); } } diff --git a/net.c b/net.c index fe9b846..6143719 100644 --- 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *state, game_ui *ui, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2, /* * 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_corner(frontend *fe, int x, int y, int dx, int dy, } } -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 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * 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 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, 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,38 +2407,38 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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); } } 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); } } } diff --git a/netslide.c b/netslide.c index e6751fe..22517f4 100644 --- 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *state, game_ui *ui, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2, 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_corner(frontend *fe, int x, int y, int dir, int phase) } } -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_barrier(frontend *fe, int x, int y, int dir, int phase) } } -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 @@ static void draw_tile(frontend *fe, game_state *state, int x, int y, int tile, 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 @@ static void draw_tile_barriers(frontend *fe, game_state *state, int x, int y) 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, */ 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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); diff --git a/nullgame.c b/nullgame.c index 3bcfe46..92bdf32 100644 --- a/nullgame.c +++ b/nullgame.c @@ -147,6 +147,10 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 */ } diff --git a/osx.m b/osx.m index 039f081..7b6789d 100644 --- a/osx.m +++ b/osx.m @@ -470,7 +470,8 @@ struct frontend { 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 @@ struct frontend { * 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 @@ struct frontend { 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; diff --git a/pattern.c b/pattern.c index dd8626a..523374d 100644 --- a/pattern.c +++ b/pattern.c @@ -20,15 +20,17 @@ enum { 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 grid_square(frontend *fe, game_drawstate *ds, } 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; diff --git a/puzzles.h b/puzzles.h index 1451f12..ecb574b 100644 --- a/puzzles.h +++ b/puzzles.h @@ -151,7 +151,7 @@ void get_random_seed(void **randseed, int *randseedsize); 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 @@ struct game { 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); diff --git a/rect.c b/rect.c index c040efa..f0e5e79 100644 --- a/rect.c +++ b/rect.c @@ -60,8 +60,9 @@ struct game_params { #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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, #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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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; } diff --git a/sixteen.c b/sixteen.c index 9a347fa..1aec630 100644 --- 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_free_drawstate(game_drawstate *ds) 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 @@ static void draw_tile(frontend *fe, game_state *state, int x, int y, 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, * 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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; } diff --git a/solo.c b/solo.c index 922f748..2f8ec23 100644 --- a/solo.c +++ b/solo.c @@ -107,8 +107,9 @@ int solver_show_working; 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, } } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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; + + ts = min(GETTILESIZE(cr, *x), GETTILESIZE(cr, *y)); + if (expand) + ds->tilesize = ts; + else + ds->tilesize = min(ts, PREFERRED_TILE_SIZE); - *x = XSIZE(cr); - *y = YSIZE(cr); + *x = SIZE(cr); + *y = SIZE(cr); } static float *game_colours(frontend *fe, game_state *state, int *ncolours) @@ -2043,6 +2053,7 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, * 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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, * 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; } } diff --git a/twiddle.c b/twiddle.c index b554879..8388f47 100644 --- 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 @@ static void game_changed_state(game_ui *ui, game_state *oldstate, { } +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 @@ static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, * 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 @@ static game_drawstate *game_new_drawstate(game_state *state) 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 rotate(int *xy, struct rotation *rot) } } -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 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, 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; } } diff --git a/windows.c b/windows.c index be1f17c..30d223d 100644 --- a/windows.c +++ b/windows.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "puzzles.h" @@ -406,11 +407,57 @@ static void find_help_file(frontend *fe) } } +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 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) fe->inst = inst; midend_new_game(fe->me); - midend_size(fe->me, &x, &y); fe->timer = 0; @@ -459,6 +505,9 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) } } + 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 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) 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 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) 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 @@ static void new_game_type(frontend *fe) 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 @@ static void new_game_type(frontend *fe) 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); -- 2.11.0