From: jacob Date: Sun, 10 Feb 2008 18:43:29 +0000 (+0000) Subject: UI change to Filling: allow multiple squares to be set at once. X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/commitdiff_plain/b182e5d58190f834c2dc49e777cdc12e38a60c00 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.) git-svn-id: svn://svn.tartarus.org/sgt/puzzles@7849 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/filling.c b/filling.c index cccd898..48874b7 100644 --- a/filling.c +++ b/filling.c @@ -976,20 +976,22 @@ static char *solve_game(game_state *state, game_state *currstate, *****************************************************************************/ 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) { game_ui *ui = snew(game_ui); - ui->x = ui->y = -1; + ui->sel = NULL; return ui; } static void free_ui(game_ui *ui) { + if (ui->sel) + sfree(ui->sel); 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, game_state *newstate) { + /* Clear any selection */ + if (ui->sel) { + sfree(ui->sel); + ui->sel = NULL; + } } #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 ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; + char *move = NULL; + int i; + assert(ui); assert(ds); 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 ((tx == ui->x && ty == ui->y) || state->shared->clues[w*ty+tx]) - ui->x = ui->y = -1; - else ui->x = tx, ui->y = ty; - return ""; /* redraw */ + if (ui->sel) { + sfree(ui->sel); + 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 */ } - assert((ui->x == -1) == (ui->y == -1)); - if (ui->x == -1) return NULL; - assert(state->shared->clues[w*ui->y + ui->x] == 0); + if (!ui->sel) return NULL; switch (button) { 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; } - { - const int i = w*ui->y + ui->x; - char buf[64]; - ui->x = ui->y = -1; - if (state->board[i] == button) { - return ""; /* no change - just update ui */ - } else { - sprintf(buf, "%d_%d", i, button); - return dupstr(buf); - } + for (i = 0; i < w*h; i++) { + char buf[32]; + if (ui->sel[i]) { + assert(state->shared->clues[i] == 0); + if (state->board[i] != button) { + sprintf(buf, "%s%d", move ? "," : "", i); + if (move) { + move = srealloc(move, strlen(move)+strlen(buf)+1); + strcat(move, buf); + } else { + move = smalloc(strlen(buf)+1); + 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) @@ -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'; new_state->cheated = TRUE; } else { - char *endptr; - const int i = strtol(move, &endptr, 0); int value; - if (endptr == move) return NULL; - if (*endptr != '_') return NULL; - move = endptr + 1; - value = strtol(move, &endptr, 0); - if (endptr == move) return NULL; - if (*endptr != '\0') return NULL; - if (i < 0 || i >= sz || value < 0 || value > 9) return NULL; + char *endptr, *delim = strchr(move, '_'); + if (!delim) return NULL; + value = strtol(delim+1, &endptr, 0); + if (*endptr || endptr == delim+1) return NULL; + if (value < 0 || value > 9) return NULL; new_state = dup_game(state); - new_state->board[i] = value; + 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; + 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) { /* clear all background flags */ - } else if (x == ui->x && y == ui->y) { + } else if (ui->sel && ui->sel[y*w+x]) { flags |= CURSOR_BG; } else if (v) { int size = dsf_size(ds->dsf_scratch, y*w+x); diff --git a/puzzles.but b/puzzles.but index 42e9203..5d41c47 100644 --- a/puzzles.but +++ b/puzzles.but @@ -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 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 -mistake, click the mouse in the incorrect square and press 0, Space, -Backspace or Enter to clear it again (or use the Undo feature). +type a digit on the keyboard to fill that square. By dragging the +mouse, you can select multiple squares to fill with a single keypress. +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.)