All the games in this collection have always defined their graphics

in terms of a constant TILE_SIZE (or equivalent). Here's a
surprisingly small patch which switches this constant into a
run-time variable.

The only observable behaviour change should be on Windows, which
physically does not permit the creation of windows larger than the
screen; if you try to create a puzzle (Net makes this plausible)
large enough to encounter this restriction, the Windows front end
should automatically re-adjust the puzzle's tile size so that it
does fit within the available space.

On GTK, I haven't done this, on the grounds that X _does_ permit
windows larger than the screen, and many X window managers already
provide the means to navigate around such a window. Gareth said he'd
rather navigate around a huge Net window than have it shrunk to fit
on one screen. I'm uncertain that this makes sense for all puzzles -
Pattern in particular strikes me as something that might be better
off shrunk to fit - so I may have to change policy later or make it
configurable.

On OS X, I also haven't done automatic shrinkage to fit on one
screen, largely because I didn't have the courage to address the
question of multiple monitors and what that means for the entire
concept :-)

[originally from svn r5913]
This commit is contained in:
Simon Tatham
2005-06-07 17:57:50 +00:00
parent 69f7e7f8f5
commit 02035753f8
16 changed files with 512 additions and 226 deletions

45
cube.c
View File

@ -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.

View File

@ -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;
}

65
gtk.c
View File

@ -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;
}

View File

@ -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)

60
mines.c
View File

@ -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;
/*
* 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 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 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);
*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);
}
}

79
net.c
View File

@ -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);
}
}
}

View 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);

View 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 */
}

9
osx.m
View File

@ -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;

View File

@ -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;

View File

@ -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);

43
rect.c
View File

@ -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;
}

View File

@ -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;
}

49
solo.c
View File

@ -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;
*x = XSIZE(cr);
*y = YSIZE(cr);
ts = min(GETTILESIZE(cr, *x), GETTILESIZE(cr, *y));
if (expand)
ds->tilesize = ts;
else
ds->tilesize = min(ts, PREFERRED_TILE_SIZE);
*x = SIZE(cr);
*y = SIZE(cr);
}
static float *game_colours(frontend *fe, game_state *state, int *ncolours)
@ -2043,6 +2053,7 @@ 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;
}
}

View File

@ -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;
}
}

View File

@ -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);