Keyboard interface for Filling, from James H.

[originally from svn r8412]
This commit is contained in:
Simon Tatham
2009-01-14 20:44:25 +00:00
parent 96315bc2ba
commit c826fdc062
2 changed files with 66 additions and 16 deletions

View File

@ -76,12 +76,14 @@
static unsigned char verbose; static unsigned char verbose;
static void printv(char *fmt, ...) { static void printv(char *fmt, ...) {
#ifndef PALM
if (verbose) { if (verbose) {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
vprintf(fmt, va); vprintf(fmt, va);
va_end(va); va_end(va);
} }
#endif
} }
/***************************************************************************** /*****************************************************************************
@ -104,13 +106,13 @@ struct game_state {
int completed, cheated; int completed, cheated;
}; };
static const struct game_params defaults[3] = {{7, 9}, {9, 13}, {13, 17}}; static const struct game_params filling_defaults[3] = {{7, 9}, {9, 13}, {13, 17}};
static game_params *default_params(void) static game_params *default_params(void)
{ {
game_params *ret = snew(game_params); game_params *ret = snew(game_params);
*ret = defaults[1]; /* struct copy */ *ret = filling_defaults[1]; /* struct copy */
return ret; return ret;
} }
@ -119,10 +121,10 @@ static int game_fetch_preset(int i, char **name, game_params **params)
{ {
char buf[64]; char buf[64];
if (i < 0 || i >= lenof(defaults)) return FALSE; if (i < 0 || i >= lenof(filling_defaults)) return FALSE;
*params = snew(game_params); *params = snew(game_params);
**params = defaults[i]; /* struct copy */ **params = filling_defaults[i]; /* struct copy */
sprintf(buf, "%dx%d", defaults[i].h, defaults[i].w); sprintf(buf, "%dx%d", filling_defaults[i].h, filling_defaults[i].w);
*name = dupstr(buf); *name = dupstr(buf);
return TRUE; return TRUE;
@ -340,7 +342,7 @@ static void make_board(int *board, int w, int h, random_state *rs) {
/* I abuse the board variable: when generating the puzzle, it /* I abuse the board variable: when generating the puzzle, it
* contains a shuffled list of numbers {0, ..., nsq-1}. */ * contains a shuffled list of numbers {0, ..., nsq-1}. */
for (i = 0; i < sz; ++i) board[i] = i; for (i = 0; i < (int)sz; ++i) board[i] = i;
while (1) { while (1) {
int change; int change;
@ -349,7 +351,7 @@ static void make_board(int *board, int w, int h, random_state *rs) {
/* while the board can in principle be fixed */ /* while the board can in principle be fixed */
do { do {
change = FALSE; change = FALSE;
for (i = 0; i < sz; ++i) { for (i = 0; i < (int)sz; ++i) {
int a = SENTINEL; int a = SENTINEL;
int b = SENTINEL; int b = SENTINEL;
int c = SENTINEL; int c = SENTINEL;
@ -381,7 +383,7 @@ static void make_board(int *board, int w, int h, random_state *rs) {
} }
} while (change); } while (change);
for (i = 0; i < sz; ++i) board[i] = dsf_size(dsf, i); for (i = 0; i < (int)sz; ++i) board[i] = dsf_size(dsf, i);
sfree(dsf); sfree(dsf);
printv("returning board number %d\n", nboards); printv("returning board number %d\n", nboards);
@ -982,6 +984,7 @@ static char *solve_game(game_state *state, game_state *currstate,
struct game_ui { struct game_ui {
int *sel; /* w*h highlighted squares, or NULL */ int *sel; /* w*h highlighted squares, or NULL */
int cur_x, cur_y, cur_visible;
}; };
static game_ui *new_ui(game_state *state) static game_ui *new_ui(game_state *state)
@ -989,6 +992,7 @@ static game_ui *new_ui(game_state *state)
game_ui *ui = snew(game_ui); game_ui *ui = snew(game_ui);
ui->sel = NULL; ui->sel = NULL;
ui->cur_x = ui->cur_y = ui->cur_visible = 0;
return ui; return ui;
} }
@ -1065,10 +1069,28 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
if (!state->shared->clues[w*ty+tx]) if (!state->shared->clues[w*ty+tx])
ui->sel[w*ty+tx] = 1; ui->sel[w*ty+tx] = 1;
} }
ui->cur_visible = 0;
return ""; /* redraw */ return ""; /* redraw */
} }
if (!ui->sel) return NULL; if (IS_CURSOR_MOVE(button)) {
ui->cur_visible = 1;
move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, 0);
return "";
}
if (IS_CURSOR_SELECT(button)) {
if (!ui->cur_visible) {
ui->cur_visible = 1;
return "";
}
if (!ui->sel) {
ui->sel = snewn(w*h, int);
memset(ui->sel, 0, w*h*sizeof(int));
}
if (state->shared->clues[w*ui->cur_y + ui->cur_x] == 0)
ui->sel[w*ui->cur_y + ui->cur_x] ^= 1;
return "";
}
switch (button) { switch (button) {
case ' ': case ' ':
@ -1086,8 +1108,9 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
for (i = 0; i < w*h; i++) { for (i = 0; i < w*h; i++) {
char buf[32]; char buf[32];
if (ui->sel[i]) { if ((ui->sel && ui->sel[i]) ||
assert(state->shared->clues[i] == 0); (!ui->sel && ui->cur_visible && (w*ui->cur_y+ui->cur_x) == i)) {
if (state->shared->clues[i] != 0) continue; /* in case cursor is on clue */
if (state->board[i] != button) { if (state->board[i] != button) {
sprintf(buf, "%s%d", move ? "," : "", i); sprintf(buf, "%s%d", move ? "," : "", i);
if (move) { if (move) {
@ -1106,6 +1129,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
move = srealloc(move, strlen(move)+strlen(buf)+1); move = srealloc(move, strlen(move)+strlen(buf)+1);
strcat(move, buf); strcat(move, buf);
} }
if (!ui->sel) return move ? move : NULL;
sfree(ui->sel); sfree(ui->sel);
ui->sel = NULL; ui->sel = NULL;
/* Need to update UI at least, as we cleared the selection */ /* Need to update UI at least, as we cleared the selection */
@ -1173,6 +1197,7 @@ enum {
COL_CORRECT, COL_CORRECT,
COL_ERROR, COL_ERROR,
COL_USER, COL_USER,
COL_CURSOR,
NCOLOURS NCOLOURS
}; };
@ -1207,6 +1232,10 @@ static float *game_colours(frontend *fe, int *ncolours)
ret[COL_CORRECT * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_CORRECT * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1];
ret[COL_CORRECT * 3 + 2] = 0.9F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_CORRECT * 3 + 2] = 0.9F * ret[COL_BACKGROUND * 3 + 2];
ret[COL_CURSOR * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0];
ret[COL_CURSOR * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1];
ret[COL_CURSOR * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2];
ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 0] = 1.0F;
ret[COL_ERROR * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_ERROR * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1];
ret[COL_ERROR * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_ERROR * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2];
@ -1254,10 +1283,11 @@ static void game_free_drawstate(drawing *dr, game_drawstate *ds)
#define BORDER_DR 0x020 #define BORDER_DR 0x020
#define BORDER_UL 0x040 #define BORDER_UL 0x040
#define BORDER_DL 0x080 #define BORDER_DL 0x080
#define CURSOR_BG 0x100 #define HIGH_BG 0x100
#define CORRECT_BG 0x200 #define CORRECT_BG 0x200
#define ERROR_BG 0x400 #define ERROR_BG 0x400
#define USER_COL 0x800 #define USER_COL 0x800
#define CURSOR_SQ 0x1000
static void draw_square(drawing *dr, game_drawstate *ds, int x, int y, static void draw_square(drawing *dr, game_drawstate *ds, int x, int y,
int n, int flags) int n, int flags)
@ -1279,7 +1309,7 @@ static void draw_square(drawing *dr, game_drawstate *ds, int x, int y,
BORDER + y*TILE_SIZE, BORDER + y*TILE_SIZE,
TILE_SIZE, TILE_SIZE,
TILE_SIZE, TILE_SIZE,
(flags & CURSOR_BG ? COL_HIGHLIGHT : (flags & HIGH_BG ? COL_HIGHLIGHT :
flags & ERROR_BG ? COL_ERROR : flags & ERROR_BG ? COL_ERROR :
flags & CORRECT_BG ? COL_CORRECT : COL_BACKGROUND)); flags & CORRECT_BG ? COL_CORRECT : COL_BACKGROUND));
@ -1368,6 +1398,16 @@ static void draw_square(drawing *dr, game_drawstate *ds, int x, int y,
BORDER_WIDTH, BORDER_WIDTH,
COL_GRID); COL_GRID);
if (flags & CURSOR_SQ) {
int coff = TILE_SIZE/8;
draw_rect_outline(dr,
BORDER + x*TILE_SIZE + coff,
BORDER + y*TILE_SIZE + coff,
TILE_SIZE - coff*2,
TILE_SIZE - coff*2,
COL_CURSOR);
}
unclip(dr); unclip(dr);
draw_update(dr, draw_update(dr,
@ -1457,7 +1497,7 @@ static void draw_grid(drawing *dr, game_drawstate *ds, game_state *state,
if (flashy || !shading) { if (flashy || !shading) {
/* clear all background flags */ /* clear all background flags */
} else if (ui->sel && ui->sel[y*w+x]) { } else if (ui->sel && ui->sel[y*w+x]) {
flags |= CURSOR_BG; flags |= HIGH_BG;
} else if (v) { } else if (v) {
int size = dsf_size(ds->dsf_scratch, y*w+x); int size = dsf_size(ds->dsf_scratch, y*w+x);
if (size == v) if (size == v)
@ -1465,6 +1505,8 @@ static void draw_grid(drawing *dr, game_drawstate *ds, game_state *state,
else if (size > v) else if (size > v)
flags |= ERROR_BG; flags |= ERROR_BG;
} }
if (ui->cur_visible && x == ui->cur_x && y == ui->cur_y)
flags |= CURSOR_SQ;
/* /*
* Borders at the very edges of the grid are * Borders at the very edges of the grid are
@ -1585,8 +1627,8 @@ static void game_print_size(game_params *params, float *x, float *y)
* I'll use 6mm squares by default. * I'll use 6mm squares by default.
*/ */
game_compute_size(params, 600, &pw, &ph); game_compute_size(params, 600, &pw, &ph);
*x = pw / 100.0; *x = pw / 100.0F;
*y = ph / 100.0; *y = ph / 100.0F;
} }
static void game_print(drawing *dr, game_state *state, int tilesize) static void game_print(drawing *dr, game_state *state, int tilesize)
@ -1705,3 +1747,5 @@ int main(int argc, char **argv) {
} }
#endif #endif
/* vim: set shiftwidth=4 tabstop=8: */

View File

@ -2315,6 +2315,12 @@ If you make a mistake, click the mouse in the incorrect square and
press 0, Space, Backspace or Enter to clear it again (or use the Undo press 0, Space, Backspace or Enter to clear it again (or use the Undo
feature). feature).
You can also move around the grid with the cursor keys; typing a digit will
fill the square containing the cursor with that number, or typing 0, Space,
or Enter will clear it. You can also select multiple squares for numbering
or clearing by using the return key, before typing a digit to fill in the
highlighted squares (as above).
(All the actions described in \k{common-actions} are also available.) (All the actions described in \k{common-actions} are also available.)
\H{filling-parameters} \I{parameters, for Filling}Filling parameters \H{filling-parameters} \I{parameters, for Filling}Filling parameters