UI change to Filling: allow multiple squares to be set at once.

(This change adds a new possibility to the save format, such that new save
files won't necessarily be loadable by old binaries. I think that's acceptable
-- it's certainly happened before -- but I couldn't find anything in the
developer docs explicitly blessing it.)

[originally from svn r7849]
This commit is contained in:
Jacob Nevins
2008-02-10 18:43:29 +00:00
parent 9673a2a733
commit ace2c7dafd
2 changed files with 73 additions and 34 deletions

View File

@ -976,20 +976,22 @@ static char *solve_game(game_state *state, game_state *currstate,
*****************************************************************************/ *****************************************************************************/
struct game_ui { struct game_ui {
int x, y; /* highlighted square, or (-1, -1) if none */ int *sel; /* w*h highlighted squares, or NULL */
}; };
static game_ui *new_ui(game_state *state) static game_ui *new_ui(game_state *state)
{ {
game_ui *ui = snew(game_ui); game_ui *ui = snew(game_ui);
ui->x = ui->y = -1; ui->sel = NULL;
return ui; return ui;
} }
static void free_ui(game_ui *ui) static void free_ui(game_ui *ui)
{ {
if (ui->sel)
sfree(ui->sel);
sfree(ui); sfree(ui);
} }
@ -1005,6 +1007,11 @@ static void decode_ui(game_ui *ui, char *encoding)
static void game_changed_state(game_ui *ui, game_state *oldstate, static void game_changed_state(game_ui *ui, game_state *oldstate,
game_state *newstate) game_state *newstate)
{ {
/* Clear any selection */
if (ui->sel) {
sfree(ui->sel);
ui->sel = NULL;
}
} }
#define PREFERRED_TILE_SIZE 32 #define PREFERRED_TILE_SIZE 32
@ -1029,23 +1036,34 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
const int tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1; const int tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
const int ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; const int ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;
char *move = NULL;
int i;
assert(ui); assert(ui);
assert(ds); assert(ds);
button &= ~MOD_MASK; button &= ~MOD_MASK;
if (tx >= 0 && tx < w && ty >= 0 && ty < h) { if (button == LEFT_BUTTON || button == LEFT_DRAG) {
/* A left-click anywhere will clear the current selection. */
if (button == LEFT_BUTTON) { if (button == LEFT_BUTTON) {
if ((tx == ui->x && ty == ui->y) || state->shared->clues[w*ty+tx]) if (ui->sel) {
ui->x = ui->y = -1; sfree(ui->sel);
else ui->x = tx, ui->y = ty; ui->sel = NULL;
}
}
if (tx >= 0 && tx < w && ty >= 0 && ty < h) {
if (!ui->sel) {
ui->sel = snewn(w*h, int);
memset(ui->sel, 0, w*h*sizeof(int));
}
if (!state->shared->clues[w*ty+tx])
ui->sel[w*ty+tx] = 1;
}
return ""; /* redraw */ return ""; /* redraw */
} }
}
assert((ui->x == -1) == (ui->y == -1)); if (!ui->sel) return NULL;
if (ui->x == -1) return NULL;
assert(state->shared->clues[w*ui->y + ui->x] == 0);
switch (button) { switch (button) {
case ' ': case ' ':
@ -1061,17 +1079,32 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
if (button > (w == 2 && h == 2? 3: max(w, h))) return NULL; if (button > (w == 2 && h == 2? 3: max(w, h))) return NULL;
} }
{ for (i = 0; i < w*h; i++) {
const int i = w*ui->y + ui->x; char buf[32];
char buf[64]; if (ui->sel[i]) {
ui->x = ui->y = -1; assert(state->shared->clues[i] == 0);
if (state->board[i] == button) { if (state->board[i] != button) {
return ""; /* no change - just update ui */ sprintf(buf, "%s%d", move ? "," : "", i);
if (move) {
move = srealloc(move, strlen(move)+strlen(buf)+1);
strcat(move, buf);
} else { } else {
sprintf(buf, "%d_%d", i, button); move = smalloc(strlen(buf)+1);
return dupstr(buf); strcpy(move, buf);
} }
} }
}
}
if (move) {
char buf[32];
sprintf(buf, "_%d", button);
move = srealloc(move, strlen(move)+strlen(buf)+1);
strcat(move, buf);
}
sfree(ui->sel);
ui->sel = NULL;
/* Need to update UI at least, as we cleared the selection */
return move ? move : "";
} }
static game_state *execute_move(game_state *state, char *move) static game_state *execute_move(game_state *state, char *move)
@ -1085,18 +1118,22 @@ static game_state *execute_move(game_state *state, char *move)
for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0'; for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0';
new_state->cheated = TRUE; new_state->cheated = TRUE;
} else { } else {
char *endptr;
const int i = strtol(move, &endptr, 0);
int value; int value;
if (endptr == move) return NULL; char *endptr, *delim = strchr(move, '_');
if (*endptr != '_') return NULL; if (!delim) return NULL;
move = endptr + 1; value = strtol(delim+1, &endptr, 0);
value = strtol(move, &endptr, 0); if (*endptr || endptr == delim+1) return NULL;
if (endptr == move) return NULL; if (value < 0 || value > 9) return NULL;
if (*endptr != '\0') return NULL;
if (i < 0 || i >= sz || value < 0 || value > 9) return NULL;
new_state = dup_game(state); new_state = dup_game(state);
while (*move) {
const int i = strtol(move, &endptr, 0);
if (endptr == move) return NULL;
if (i < 0 || i >= sz) return NULL;
new_state->board[i] = value; new_state->board[i] = value;
if (*endptr == '_') break;
if (*endptr != ',') return NULL;
move = endptr + 1;
}
} }
/* /*
@ -1414,7 +1451,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 (x == ui->x && y == ui->y) { } else if (ui->sel && ui->sel[y*w+x]) {
flags |= CURSOR_BG; flags |= CURSOR_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);

View File

@ -2233,9 +2233,11 @@ Filling was contributed to this collection by Jonas K\u00F6{oe}lker.
\H{filling-controls} \I{controls, for Filling}Filling controls \H{filling-controls} \I{controls, for Filling}Filling controls
To play Filling, simply click the mouse in any empty square and then To play Filling, simply click the mouse in any empty square and then
type a digit on the keyboard to fill that square. If you make a type a digit on the keyboard to fill that square. By dragging the
mistake, click the mouse in the incorrect square and press 0, Space, mouse, you can select multiple squares to fill with a single keypress.
Backspace or Enter to clear it again (or use the Undo feature). 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
feature).
(All the actions described in \k{common-actions} are also available.) (All the actions described in \k{common-actions} are also available.)