chiark / gitweb /
All the games in this collection have always defined their graphics
authorSimon Tatham <anakin@pobox.com>
Tue, 7 Jun 2005 17:57:50 +0000 (17:57 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 7 Jun 2005 17:57:50 +0000 (17:57 +0000)
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]

16 files changed:
cube.c
fifteen.c
gtk.c
midend.c
mines.c
net.c
netslide.c
nullgame.c
osx.m
pattern.c
puzzles.h
rect.c
sixteen.c
solo.c
twiddle.c
windows.c

diff --git a/cube.c b/cube.c
index ffefa2f17e20950d5b75dcad1df99ced6809113d..e1c28658580ca081e8fcfd98956c23bbed16e716 100644 (file)
--- 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.
index a6402c9a912f4754e8790391fc4d07376415ccfa..226de305cf6500e55fb024e931bbdab2cbffe793 100644 (file)
--- 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 7483a98eea4bc9f5fcb87f753af79ca8d7aaa0cb..91d44d6c53bb657998ab3a8ec23f9773d6cbcedf 100644 (file)
--- 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;
 }
 
index d8960a7b6eea2e50aa249d5253976b2f8c0e0dd6..f4eeb6160b8651645a5c26f63a1a975956b4706a 100644 (file)
--- 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 286f76d614b387f0234c0bca75db7cd5fce4bd69..01415176d88688fa846e03f52bdc6574b2f31395 100644 (file)
--- 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 fe9b846af6b5118e71ca08d74b4490b19d974400..614371962f70031b53329bf37507dc3dc96e0e04 100644 (file)
--- 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);
                 }
             }
         }
index e6751fe66048bde237e1f04d14dee47a54cc82dd..22517f48d0853cd1f3aa051dac3daa1642e24f48 100644 (file)
@@ -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);
 
index 3bcfe4633b1347880d0141472bc3906d493b485d..92bdf32a6d2523a8547dd2a3302855d31ec6a7e9 100644 (file)
@@ -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 039f0813e1a1e36222b950e8992bb76bf21fdbee..7b6789d5a94c6a79bbc7b7913461ba9fac175e31 100644 (file)
--- 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;
 
index dd8626ab2d79534c192be8170aa7291bc170f013..523374d6727a84ac06be2e40217874757ea8340a 100644 (file)
--- 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;
index 1451f12fd18fc4650346367ced6befe107582da0..ecb574bbd6c1be53849637ea142da12628addbbe 100644 (file)
--- 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 c040efaa78552a0921076f3393c9a6de12c2c452..f0e5e79f1427bd959b34cb36f518276d8dd1e942 100644 (file)
--- 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;
            }
index 9a347fa9153bab0d2f9b544d671cc630c4409ea8..1aec630250ff90c80f0c78f601522066d9a23194 100644 (file)
--- 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 922f748e84957a809be11a001093aeefa2cb31b8..2f8ec23b51460d06ea8590e0591ea6f976e01f37 100644 (file)
--- 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;
     }
 }
index b5548793e9c5479a537746b0f9d03315a88f9483..8388f4764cec320da2df303cba70db8970edd7d9 100644 (file)
--- 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;
         }
     }
index be1f17cb8a5fd2de04b8fe9fc3d693c567e405cf..30d223d6279d94922026908c2dddaf94f56e14c9 100644 (file)
--- 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 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);