mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Add a menu bar, in both Windows and GTK. In particular, game modules
are now expected to provide a list of `presets' (game_params plus a name) which are selectable from the menu. This means I can play both Octahedron and Cube without recompiling in between :-) While I'm here, also enabled a Cygwin makefile, which Just Worked. [originally from svn r4158]
This commit is contained in:
1
Recipe
1
Recipe
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
!makefile gtk Makefile
|
!makefile gtk Makefile
|
||||||
!makefile vc Makefile.vc
|
!makefile vc Makefile.vc
|
||||||
|
!makefile cygwin Makefile.cyg
|
||||||
|
|
||||||
WINDOWS = windows user32.lib gdi32.lib
|
WINDOWS = windows user32.lib gdi32.lib
|
||||||
COMMON = midend malloc
|
COMMON = midend malloc
|
||||||
|
64
cube.c
64
cube.c
@ -21,6 +21,7 @@ struct solid {
|
|||||||
int faces[MAXFACES * MAXORDER]; /* order*nfaces point indices */
|
int faces[MAXFACES * MAXORDER]; /* order*nfaces point indices */
|
||||||
float normals[MAXFACES * 3]; /* 3*npoints vector components */
|
float normals[MAXFACES * 3]; /* 3*npoints vector components */
|
||||||
float shear; /* isometric shear for nice drawing */
|
float shear; /* isometric shear for nice drawing */
|
||||||
|
float border; /* border required around arena */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct solid tetrahedron = {
|
static const struct solid tetrahedron = {
|
||||||
@ -41,7 +42,7 @@ static const struct solid tetrahedron = {
|
|||||||
0.816496580928, -0.471404520791, 0.333333333334,
|
0.816496580928, -0.471404520791, 0.333333333334,
|
||||||
0.0, 0.0, -1.0,
|
0.0, 0.0, -1.0,
|
||||||
},
|
},
|
||||||
0.0
|
0.0, 0.3
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct solid cube = {
|
static const struct solid cube = {
|
||||||
@ -57,7 +58,7 @@ static const struct solid cube = {
|
|||||||
{
|
{
|
||||||
-1,0,0, 0,0,+1, +1,0,0, 0,0,-1, 0,-1,0, 0,+1,0
|
-1,0,0, 0,0,+1, +1,0,0, 0,0,-1, 0,-1,0, 0,+1,0
|
||||||
},
|
},
|
||||||
0.3
|
0.3, 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct solid octahedron = {
|
static const struct solid octahedron = {
|
||||||
@ -84,7 +85,7 @@ static const struct solid octahedron = {
|
|||||||
0.816496580928, -0.471404520791, -0.333333333334,
|
0.816496580928, -0.471404520791, -0.333333333334,
|
||||||
0.816496580928, 0.471404520791, 0.333333333334,
|
0.816496580928, 0.471404520791, 0.333333333334,
|
||||||
},
|
},
|
||||||
0.0
|
0.0, 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct solid icosahedron = {
|
static const struct solid icosahedron = {
|
||||||
@ -132,7 +133,7 @@ static const struct solid icosahedron = {
|
|||||||
-0.57735026919, -0.333333333334, -0.745355992501,
|
-0.57735026919, -0.333333333334, -0.745355992501,
|
||||||
0.57735026919, -0.333333333334, -0.745355992501,
|
0.57735026919, -0.333333333334, -0.745355992501,
|
||||||
},
|
},
|
||||||
0.0
|
0.0, 0.8
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -216,11 +217,58 @@ game_params *default_params(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int game_fetch_preset(int i, char **name, game_params **params)
|
||||||
|
{
|
||||||
|
game_params *ret = snew(game_params);
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
str = "Cube";
|
||||||
|
ret->solid = CUBE;
|
||||||
|
ret->d1 = 4;
|
||||||
|
ret->d2 = 4;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
str = "Tetrahedron";
|
||||||
|
ret->solid = TETRAHEDRON;
|
||||||
|
ret->d1 = 2;
|
||||||
|
ret->d2 = 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
str = "Octahedron";
|
||||||
|
ret->solid = OCTAHEDRON;
|
||||||
|
ret->d1 = 2;
|
||||||
|
ret->d2 = 2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
str = "Icosahedron";
|
||||||
|
ret->solid = ICOSAHEDRON;
|
||||||
|
ret->d1 = 3;
|
||||||
|
ret->d2 = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sfree(ret);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*name = dupstr(str);
|
||||||
|
*params = ret;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void free_params(game_params *params)
|
void free_params(game_params *params)
|
||||||
{
|
{
|
||||||
sfree(params);
|
sfree(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game_params *dup_params(game_params *params)
|
||||||
|
{
|
||||||
|
game_params *ret = snew(game_params);
|
||||||
|
*ret = *params; /* structure copy */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void enum_grid_squares(game_params *params,
|
static void enum_grid_squares(game_params *params,
|
||||||
void (*callback)(void *, struct grid_square *),
|
void (*callback)(void *, struct grid_square *),
|
||||||
void *ctx)
|
void *ctx)
|
||||||
@ -1083,8 +1131,8 @@ static struct bbox find_bbox(game_params *params)
|
|||||||
void game_size(game_params *params, int *x, int *y)
|
void game_size(game_params *params, int *x, int *y)
|
||||||
{
|
{
|
||||||
struct bbox bb = find_bbox(params);
|
struct bbox bb = find_bbox(params);
|
||||||
*x = (bb.r - bb.l + 2) * GRID_SCALE;
|
*x = (bb.r - bb.l + 2*solids[params->solid]->border) * GRID_SCALE;
|
||||||
*y = (bb.d - bb.u + 2) * GRID_SCALE;
|
*y = (bb.d - bb.u + 2*solids[params->solid]->border) * GRID_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
float *game_colours(frontend *fe, game_state *state, int *ncolours)
|
float *game_colours(frontend *fe, game_state *state, int *ncolours)
|
||||||
@ -1110,8 +1158,8 @@ game_drawstate *game_new_drawstate(game_state *state)
|
|||||||
struct game_drawstate *ds = snew(struct game_drawstate);
|
struct game_drawstate *ds = snew(struct game_drawstate);
|
||||||
struct bbox bb = find_bbox(&state->params);
|
struct bbox bb = find_bbox(&state->params);
|
||||||
|
|
||||||
ds->ox = -(bb.l - 1) * GRID_SCALE;
|
ds->ox = -(bb.l - state->solid->border) * GRID_SCALE;
|
||||||
ds->oy = -(bb.u - 1) * GRID_SCALE;
|
ds->oy = -(bb.u - state->solid->border) * GRID_SCALE;
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
102
gtk.c
102
gtk.c
@ -206,6 +206,9 @@ static gint configure_area(GtkWidget *widget,
|
|||||||
frontend *fe = (frontend *)data;
|
frontend *fe = (frontend *)data;
|
||||||
GdkGC *gc;
|
GdkGC *gc;
|
||||||
|
|
||||||
|
if (fe->pixmap)
|
||||||
|
gdk_pixmap_unref(fe->pixmap);
|
||||||
|
|
||||||
fe->pixmap = gdk_pixmap_new(widget->window, fe->w, fe->h, -1);
|
fe->pixmap = gdk_pixmap_new(widget->window, fe->w, fe->h, -1);
|
||||||
|
|
||||||
gc = gdk_gc_new(fe->area->window);
|
gc = gdk_gc_new(fe->area->window);
|
||||||
@ -239,10 +242,56 @@ void activate_timer(frontend *fe)
|
|||||||
fe->timer_active = TRUE;
|
fe->timer_active = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void menu_key_event(GtkMenuItem *menuitem, gpointer data)
|
||||||
|
{
|
||||||
|
frontend *fe = (frontend *)data;
|
||||||
|
int key = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem),
|
||||||
|
"user-data"));
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, key))
|
||||||
|
gtk_widget_destroy(fe->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
|
||||||
|
{
|
||||||
|
frontend *fe = (frontend *)data;
|
||||||
|
game_params *params =
|
||||||
|
(game_params *)gtk_object_get_data(GTK_OBJECT(menuitem), "user-data");
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
midend_set_params(fe->me, params);
|
||||||
|
midend_new_game(fe->me, NULL);
|
||||||
|
midend_size(fe->me, &x, &y);
|
||||||
|
gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
|
||||||
|
fe->w = x;
|
||||||
|
fe->h = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont,
|
||||||
|
char *text, int key)
|
||||||
|
{
|
||||||
|
GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
|
||||||
|
gtk_container_add(cont, menuitem);
|
||||||
|
gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
|
||||||
|
GINT_TO_POINTER(key));
|
||||||
|
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
|
||||||
|
GTK_SIGNAL_FUNC(menu_key_event), fe);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
return menuitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_menu_separator(GtkContainer *cont)
|
||||||
|
{
|
||||||
|
GtkWidget *menuitem = gtk_menu_item_new();
|
||||||
|
gtk_container_add(cont, menuitem);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
}
|
||||||
|
|
||||||
static frontend *new_window(void)
|
static frontend *new_window(void)
|
||||||
{
|
{
|
||||||
frontend *fe;
|
frontend *fe;
|
||||||
int x, y;
|
GtkBox *vbox;
|
||||||
|
GtkWidget *menubar, *menu, *menuitem;
|
||||||
|
int x, y, n;
|
||||||
|
|
||||||
fe = snew(frontend);
|
fe = snew(frontend);
|
||||||
|
|
||||||
@ -255,6 +304,55 @@ static frontend *new_window(void)
|
|||||||
#else
|
#else
|
||||||
gtk_window_set_policy(GTK_WINDOW(fe->window), FALSE, FALSE, TRUE);
|
gtk_window_set_policy(GTK_WINDOW(fe->window), FALSE, FALSE, TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
vbox = GTK_BOX(gtk_vbox_new(FALSE, 0));
|
||||||
|
gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox));
|
||||||
|
gtk_widget_show(GTK_WIDGET(vbox));
|
||||||
|
|
||||||
|
menubar = gtk_menu_bar_new();
|
||||||
|
gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show(menubar);
|
||||||
|
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Game");
|
||||||
|
gtk_container_add(GTK_CONTAINER(menubar), menuitem);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
|
||||||
|
menu = gtk_menu_new();
|
||||||
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
|
||||||
|
|
||||||
|
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "New", 'n');
|
||||||
|
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Restart", 'r');
|
||||||
|
|
||||||
|
if ((n = midend_num_presets(fe->me)) > 0) {
|
||||||
|
GtkWidget *submenu;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Type");
|
||||||
|
gtk_container_add(GTK_CONTAINER(menu), menuitem);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
|
||||||
|
submenu = gtk_menu_new();
|
||||||
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
char *name;
|
||||||
|
game_params *params;
|
||||||
|
|
||||||
|
midend_fetch_preset(fe->me, i, &name, ¶ms);
|
||||||
|
|
||||||
|
menuitem = gtk_menu_item_new_with_label(name);
|
||||||
|
gtk_container_add(GTK_CONTAINER(submenu), menuitem);
|
||||||
|
gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", params);
|
||||||
|
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
|
||||||
|
GTK_SIGNAL_FUNC(menu_preset_event), fe);
|
||||||
|
gtk_widget_show(menuitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_menu_separator(GTK_CONTAINER(menu));
|
||||||
|
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Undo", 'u');
|
||||||
|
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", '\x12');
|
||||||
|
add_menu_separator(GTK_CONTAINER(menu));
|
||||||
|
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q');
|
||||||
|
|
||||||
{
|
{
|
||||||
int i, ncolours;
|
int i, ncolours;
|
||||||
@ -288,7 +386,7 @@ static frontend *new_window(void)
|
|||||||
fe->w = x;
|
fe->w = x;
|
||||||
fe->h = y;
|
fe->h = y;
|
||||||
|
|
||||||
gtk_container_add(GTK_CONTAINER(fe->window), fe->area);
|
gtk_box_pack_end(vbox, fe->area, FALSE, FALSE, 0);
|
||||||
|
|
||||||
fe->pixmap = NULL;
|
fe->pixmap = NULL;
|
||||||
|
|
||||||
|
42
midend.c
42
midend.c
@ -14,6 +14,11 @@ struct midend_data {
|
|||||||
frontend *frontend;
|
frontend *frontend;
|
||||||
char *seed;
|
char *seed;
|
||||||
int nstates, statesize, statepos;
|
int nstates, statesize, statepos;
|
||||||
|
|
||||||
|
game_params **presets;
|
||||||
|
char **preset_names;
|
||||||
|
int npresets, presetsize;
|
||||||
|
|
||||||
game_params *params;
|
game_params *params;
|
||||||
game_state **states;
|
game_state **states;
|
||||||
game_drawstate *drawstate;
|
game_drawstate *drawstate;
|
||||||
@ -39,6 +44,9 @@ midend_data *midend_new(frontend *frontend)
|
|||||||
me->seed = NULL;
|
me->seed = NULL;
|
||||||
me->drawstate = NULL;
|
me->drawstate = NULL;
|
||||||
me->oldstate = NULL;
|
me->oldstate = NULL;
|
||||||
|
me->presets = NULL;
|
||||||
|
me->preset_names = NULL;
|
||||||
|
me->npresets = me->presetsize = 0;
|
||||||
|
|
||||||
return me;
|
return me;
|
||||||
}
|
}
|
||||||
@ -59,7 +67,7 @@ void midend_size(midend_data *me, int *x, int *y)
|
|||||||
void midend_set_params(midend_data *me, game_params *params)
|
void midend_set_params(midend_data *me, game_params *params)
|
||||||
{
|
{
|
||||||
free_params(me->params);
|
free_params(me->params);
|
||||||
me->params = params;
|
me->params = dup_params(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void midend_new_game(midend_data *me, char *seed)
|
void midend_new_game(midend_data *me, char *seed)
|
||||||
@ -227,3 +235,35 @@ float *midend_colours(midend_data *me, int *ncolours)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int midend_num_presets(midend_data *me)
|
||||||
|
{
|
||||||
|
if (!me->npresets) {
|
||||||
|
char *name;
|
||||||
|
game_params *preset;
|
||||||
|
|
||||||
|
while (game_fetch_preset(me->npresets, &name, &preset)) {
|
||||||
|
if (me->presetsize <= me->npresets) {
|
||||||
|
me->presetsize = me->npresets + 10;
|
||||||
|
me->presets = sresize(me->presets, me->presetsize,
|
||||||
|
game_params *);
|
||||||
|
me->preset_names = sresize(me->preset_names, me->presetsize,
|
||||||
|
char *);
|
||||||
|
}
|
||||||
|
|
||||||
|
me->presets[me->npresets] = preset;
|
||||||
|
me->preset_names[me->npresets] = name;
|
||||||
|
me->npresets++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return me->npresets;
|
||||||
|
}
|
||||||
|
|
||||||
|
void midend_fetch_preset(midend_data *me, int n,
|
||||||
|
char **name, game_params **params)
|
||||||
|
{
|
||||||
|
assert(n >= 0 && n < me->npresets);
|
||||||
|
*name = me->preset_names[n];
|
||||||
|
*params = me->presets[n];
|
||||||
|
}
|
||||||
|
59
net.c
59
net.c
@ -126,19 +126,60 @@ game_params *default_params(void)
|
|||||||
{
|
{
|
||||||
game_params *ret = snew(game_params);
|
game_params *ret = snew(game_params);
|
||||||
|
|
||||||
ret->width = 11;
|
ret->width = 5;
|
||||||
ret->height = 11;
|
ret->height = 5;
|
||||||
ret->wrapping = TRUE;
|
ret->wrapping = FALSE;
|
||||||
ret->barrier_probability = 0.1;
|
ret->barrier_probability = 0.0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int game_fetch_preset(int i, char **name, game_params **params)
|
||||||
|
{
|
||||||
|
game_params *ret;
|
||||||
|
char str[80];
|
||||||
|
static const struct { int x, y, wrap; } values[] = {
|
||||||
|
{5, 5, FALSE},
|
||||||
|
{7, 7, FALSE},
|
||||||
|
{9, 9, FALSE},
|
||||||
|
{11, 11, FALSE},
|
||||||
|
{13, 11, FALSE},
|
||||||
|
{5, 5, TRUE},
|
||||||
|
{7, 7, TRUE},
|
||||||
|
{9, 9, TRUE},
|
||||||
|
{11, 11, TRUE},
|
||||||
|
{13, 11, TRUE},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i < 0 || i >= lenof(values))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ret = snew(game_params);
|
||||||
|
ret->width = values[i].x;
|
||||||
|
ret->height = values[i].y;
|
||||||
|
ret->wrapping = values[i].wrap;
|
||||||
|
ret->barrier_probability = 0.0;
|
||||||
|
|
||||||
|
sprintf(str, "%dx%d%s", ret->width, ret->height,
|
||||||
|
ret->wrapping ? " wrapping" : "");
|
||||||
|
|
||||||
|
*name = dupstr(str);
|
||||||
|
*params = ret;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
void free_params(game_params *params)
|
void free_params(game_params *params)
|
||||||
{
|
{
|
||||||
sfree(params);
|
sfree(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game_params *dup_params(game_params *params)
|
||||||
|
{
|
||||||
|
game_params *ret = snew(game_params);
|
||||||
|
*ret = *params; /* structure copy */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Randomly select a new game seed.
|
* Randomly select a new game seed.
|
||||||
*/
|
*/
|
||||||
@ -480,27 +521,27 @@ game_state *new_game(game_params *params, char *seed)
|
|||||||
|
|
||||||
x1 = x + X(dir), y1 = y + Y(dir);
|
x1 = x + X(dir), y1 = y + Y(dir);
|
||||||
if (x1 >= 0 && x1 < state->width &&
|
if (x1 >= 0 && x1 < state->width &&
|
||||||
y1 >= 0 && y1 < state->width &&
|
y1 >= 0 && y1 < state->height &&
|
||||||
(barrier(state, x1, y1) & dir2))
|
(barrier(state, x1, y1) & dir2))
|
||||||
corner = TRUE;
|
corner = TRUE;
|
||||||
|
|
||||||
x2 = x + X(dir2), y2 = y + Y(dir2);
|
x2 = x + X(dir2), y2 = y + Y(dir2);
|
||||||
if (x2 >= 0 && x2 < state->width &&
|
if (x2 >= 0 && x2 < state->width &&
|
||||||
y2 >= 0 && y2 < state->width &&
|
y2 >= 0 && y2 < state->height &&
|
||||||
(barrier(state, x2, y2) & dir))
|
(barrier(state, x2, y2) & dir))
|
||||||
corner = TRUE;
|
corner = TRUE;
|
||||||
|
|
||||||
if (corner) {
|
if (corner) {
|
||||||
barrier(state, x, y) |= (dir << 4);
|
barrier(state, x, y) |= (dir << 4);
|
||||||
if (x1 >= 0 && x1 < state->width &&
|
if (x1 >= 0 && x1 < state->width &&
|
||||||
y1 >= 0 && y1 < state->width)
|
y1 >= 0 && y1 < state->height)
|
||||||
barrier(state, x1, y1) |= (A(dir) << 4);
|
barrier(state, x1, y1) |= (A(dir) << 4);
|
||||||
if (x2 >= 0 && x2 < state->width &&
|
if (x2 >= 0 && x2 < state->width &&
|
||||||
y2 >= 0 && y2 < state->width)
|
y2 >= 0 && y2 < state->height)
|
||||||
barrier(state, x2, y2) |= (C(dir) << 4);
|
barrier(state, x2, y2) |= (C(dir) << 4);
|
||||||
x3 = x + X(dir) + X(dir2), y3 = y + Y(dir) + Y(dir2);
|
x3 = x + X(dir) + X(dir2), y3 = y + Y(dir) + Y(dir2);
|
||||||
if (x3 >= 0 && x3 < state->width &&
|
if (x3 >= 0 && x3 < state->width &&
|
||||||
y3 >= 0 && y3 < state->width)
|
y3 >= 0 && y3 < state->height)
|
||||||
barrier(state, x3, y3) |= (F(dir) << 4);
|
barrier(state, x3, y3) |= (F(dir) << 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,9 @@ int midend_process_key(midend_data *me, int x, int y, int button);
|
|||||||
void midend_redraw(midend_data *me);
|
void midend_redraw(midend_data *me);
|
||||||
float *midend_colours(midend_data *me, int *ncolours);
|
float *midend_colours(midend_data *me, int *ncolours);
|
||||||
void midend_timer(midend_data *me, float tplus);
|
void midend_timer(midend_data *me, float tplus);
|
||||||
|
int midend_num_presets(midend_data *me);
|
||||||
|
void midend_fetch_preset(midend_data *me, int n,
|
||||||
|
char **name, game_params **params);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* malloc.c
|
* malloc.c
|
||||||
@ -87,7 +90,9 @@ void random_free(random_state *state);
|
|||||||
* Game-specific routines
|
* Game-specific routines
|
||||||
*/
|
*/
|
||||||
game_params *default_params(void);
|
game_params *default_params(void);
|
||||||
|
int game_fetch_preset(int i, char **name, game_params **params);
|
||||||
void free_params(game_params *params);
|
void free_params(game_params *params);
|
||||||
|
game_params *dup_params(game_params *params);
|
||||||
char *new_game_seed(game_params *params);
|
char *new_game_seed(game_params *params);
|
||||||
game_state *new_game(game_params *params, char *seed);
|
game_state *new_game(game_params *params, char *seed);
|
||||||
game_state *dup_game(game_state *state);
|
game_state *dup_game(game_state *state);
|
||||||
|
112
windows.c
112
windows.c
@ -11,6 +11,13 @@
|
|||||||
|
|
||||||
#include "puzzles.h"
|
#include "puzzles.h"
|
||||||
|
|
||||||
|
#define IDM_NEW 0x0010
|
||||||
|
#define IDM_RESTART 0x0020
|
||||||
|
#define IDM_UNDO 0x0030
|
||||||
|
#define IDM_REDO 0x0040
|
||||||
|
#define IDM_QUIT 0x0050
|
||||||
|
#define IDM_PRESETS 0x0100
|
||||||
|
|
||||||
struct frontend {
|
struct frontend {
|
||||||
midend_data *me;
|
midend_data *me;
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
@ -20,6 +27,8 @@ struct frontend {
|
|||||||
HBRUSH *brushes;
|
HBRUSH *brushes;
|
||||||
HPEN *pens;
|
HPEN *pens;
|
||||||
UINT timer;
|
UINT timer;
|
||||||
|
int npresets;
|
||||||
|
game_params **presets;
|
||||||
};
|
};
|
||||||
|
|
||||||
void fatal(char *fmt, ...)
|
void fatal(char *fmt, ...)
|
||||||
@ -178,7 +187,7 @@ static frontend *new_window(HINSTANCE inst)
|
|||||||
r.bottom = y;
|
r.bottom = y;
|
||||||
AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
|
AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~
|
||||||
(WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED),
|
(WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED),
|
||||||
FALSE, 0);
|
TRUE, 0);
|
||||||
|
|
||||||
fe->hwnd = CreateWindowEx(0, "puzzle", "puzzle",
|
fe->hwnd = CreateWindowEx(0, "puzzle", "puzzle",
|
||||||
WS_OVERLAPPEDWINDOW &~
|
WS_OVERLAPPEDWINDOW &~
|
||||||
@ -187,6 +196,44 @@ static frontend *new_window(HINSTANCE inst)
|
|||||||
r.right - r.left, r.bottom - r.top,
|
r.right - r.left, r.bottom - r.top,
|
||||||
NULL, NULL, inst, NULL);
|
NULL, NULL, inst, NULL);
|
||||||
|
|
||||||
|
{
|
||||||
|
HMENU bar = CreateMenu();
|
||||||
|
HMENU menu = CreateMenu();
|
||||||
|
|
||||||
|
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game");
|
||||||
|
AppendMenu(menu, MF_ENABLED, IDM_NEW, "New");
|
||||||
|
AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart");
|
||||||
|
|
||||||
|
if ((fe->npresets = midend_num_presets(fe->me)) > 0) {
|
||||||
|
HMENU sub = CreateMenu();
|
||||||
|
int i;
|
||||||
|
|
||||||
|
AppendMenu(menu, MF_ENABLED|MF_POPUP, (UINT)sub, "Type");
|
||||||
|
|
||||||
|
fe->presets = snewn(fe->npresets, game_params *);
|
||||||
|
|
||||||
|
for (i = 0; i < fe->npresets; i++) {
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
midend_fetch_preset(fe->me, i, &name, &fe->presets[i]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: we ought to go through and do something
|
||||||
|
* with ampersands here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendMenu(menu, MF_SEPARATOR, 0, 0);
|
||||||
|
AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo");
|
||||||
|
AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo");
|
||||||
|
AppendMenu(menu, MF_SEPARATOR, 0, 0);
|
||||||
|
AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
|
||||||
|
SetMenu(fe->hwnd, bar);
|
||||||
|
}
|
||||||
|
|
||||||
hdc = GetDC(fe->hwnd);
|
hdc = GetDC(fe->hwnd);
|
||||||
fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
|
fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
|
||||||
ReleaseDC(fe->hwnd, hdc);
|
ReleaseDC(fe->hwnd, hdc);
|
||||||
@ -210,6 +257,65 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
DestroyWindow(hwnd);
|
DestroyWindow(hwnd);
|
||||||
return 0;
|
return 0;
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
|
||||||
|
case IDM_NEW:
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, 'n'))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
case IDM_RESTART:
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, 'r'))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
case IDM_UNDO:
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, 'u'))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
case IDM_REDO:
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, '\x12'))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
case IDM_QUIT:
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, 'q'))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;
|
||||||
|
|
||||||
|
if (p >= 0 && p < fe->npresets) {
|
||||||
|
RECT r;
|
||||||
|
HDC hdc;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
midend_set_params(fe->me, fe->presets[p]);
|
||||||
|
midend_new_game(fe->me, NULL);
|
||||||
|
midend_size(fe->me, &x, &y);
|
||||||
|
|
||||||
|
r.left = r.top = 0;
|
||||||
|
r.right = x;
|
||||||
|
r.bottom = y;
|
||||||
|
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);
|
||||||
|
|
||||||
|
DeleteObject(fe->bitmap);
|
||||||
|
|
||||||
|
hdc = GetDC(fe->hwnd);
|
||||||
|
fe->bitmap = CreateCompatibleBitmap(hdc, x, y);
|
||||||
|
ReleaseDC(fe->hwnd, hdc);
|
||||||
|
|
||||||
|
midend_redraw(fe->me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
return 0;
|
return 0;
|
||||||
@ -246,7 +352,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key != -1) {
|
if (key != -1) {
|
||||||
if (!midend_process_key(fe->me, -1, -1, key))
|
if (!midend_process_key(fe->me, 0, 0, key))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,7 +368,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
if (!midend_process_key(fe->me, -1, -1, (unsigned char)wParam))
|
if (!midend_process_key(fe->me, 0, 0, (unsigned char)wParam))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
return 0;
|
return 0;
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
|
Reference in New Issue
Block a user