From 5ec86c03a8bc911bb3dbd77fb7c827eeca975594 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 9 Aug 2023 09:43:04 +0100 Subject: [PATCH] move_cursor(): handle visible flag; return useful value This adds an extra parameter to move_cursor() that's an optional pointer to a bool indicating whether the cursor is visible. This allows for centralising the common idiom of having the keyboard cursor become visible when a cursor key is pressed. Consistently with the vast majority of existing puzzles, the cursor moves even if it was invisible before, and becomes visible even if it can't move. The function now also returns one of the special constants that can be returned by interpret_move(), so that the caller can correctly return MOVE_UI_UPDATE or MOVE_NO_EFFECT without needing to carefully check for changes itself. Callers are updated only to the extent that they all pass NULL as the new argument. Most of them could now be substantially simplified. --- blackbox.c | 2 +- bridges.c | 2 +- devel.but | 13 +++++++++++-- dominosa.c | 2 +- fifteen.c | 2 +- filling.c | 2 +- galaxies.c | 3 ++- keen.c | 2 +- lightup.c | 3 ++- magnets.c | 3 ++- map.c | 2 +- mines.c | 3 ++- misc.c | 14 +++++++++++--- mosaic.c | 2 +- palisade.c | 4 ++-- pattern.c | 3 ++- pearl.c | 4 ++-- pegs.c | 2 +- puzzles.h | 3 ++- rect.c | 3 ++- signpost.c | 2 +- singles.c | 2 +- sixteen.c | 6 +++--- slant.c | 2 +- solo.c | 2 +- tents.c | 4 ++-- towers.c | 2 +- unequal.c | 5 +++-- unfinished/group.c | 2 +- unruly.c | 2 +- 30 files changed, 64 insertions(+), 39 deletions(-) diff --git a/blackbox.c b/blackbox.c index 2025d1d..43323f9 100644 --- a/blackbox.c +++ b/blackbox.c @@ -930,7 +930,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (IS_CURSOR_MOVE(button)) { int cx = ui->cur_x, cy = ui->cur_y; - move_cursor(button, &cx, &cy, state->w+2, state->h+2, false); + move_cursor(button, &cx, &cy, state->w+2, state->h+2, false, NULL); if ((cx == 0 && cy == 0 && !CAN_REVEAL(state)) || (cx == 0 && cy == state->h+1) || (cx == state->w+1 && cy == 0) || diff --git a/bridges.c b/bridges.c index 0cbe779..6de61f1 100644 --- a/bridges.c +++ b/bridges.c @@ -2446,7 +2446,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (ui->dragging) { int nx = ui->cur_x, ny = ui->cur_y; - move_cursor(button, &nx, &ny, state->w, state->h, false); + move_cursor(button, &nx, &ny, state->w, state->h, false, NULL); if (nx == ui->cur_x && ny == ui->cur_y) return MOVE_NO_EFFECT; update_drag_dst(state, ui, ds, diff --git a/devel.but b/devel.but index 65c1571..4d205ac 100644 --- a/devel.but +++ b/devel.but @@ -5239,8 +5239,8 @@ The returned string is dynamically allocated and should be \S{utils-move-cursor} \cw{move_cursor()} -\c void move_cursor(int button, int *x, int *y, int w, int h, -\c bool wrap); +\c char *move_cursor(int button, int *x, int *y, int w, int h, +\c bool wrap, bool *visible); This function can be called by \cw{interpret_move()} to implement the default keyboard API for moving a cursor around a grid. @@ -5263,6 +5263,15 @@ of the grid will result in it wrapping round to the corresponding square on the opposite edge. If \c{wrap} is \cw{false}, such a move will have no effect. +If \c{visible} is not \cw{NULL}, it points to a flag indicating +whether the cursor is visible. This will be set to \cw{true} if +\c{button} represents a cursor-movement key. + +The function returns one of the special constants that can be returned +by \cw{interpret_move()}. The return value is \cw{MOVE_UNUSED} if +\c{button} is unrecognised, \cw{MOVE_UI_UPDATE} if \c{x}, \c{y}, or +\c{visible} was updated, and \cw{MOVE_NO EFFECT} otherwise. + \S{utils-divvy-rectangle} \cw{divvy_rectangle()} \c int *divvy_rectangle(int w, int h, int k, random_state *rs); diff --git a/dominosa.c b/dominosa.c index 3ff0c97..d649e05 100644 --- a/dominosa.c +++ b/dominosa.c @@ -2832,7 +2832,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, } else if (IS_CURSOR_MOVE(button)) { ui->cur_visible = true; - move_cursor(button, &ui->cur_x, &ui->cur_y, 2*w-1, 2*h-1, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, 2*w-1, 2*h-1, false, NULL); return MOVE_UI_UPDATE; } else if (IS_CURSOR_SELECT(button)) { diff --git a/fifteen.c b/fifteen.c index 2f10122..6651d43 100644 --- a/fifteen.c +++ b/fifteen.c @@ -766,7 +766,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, button = flip_cursor(button); /* the default */ if (ui->invert_cursor) button = flip_cursor(button); /* undoes the first flip */ - move_cursor(button, &nx, &ny, state->w, state->h, false); + move_cursor(button, &nx, &ny, state->w, state->h, false, NULL); } else if ((button == 'h' || button == 'H') && !state->completed) { if (!compute_hint(state, &nx, &ny)) return MOVE_NO_EFFECT;/* shouldn't happen, since ^^we^^checked^^ */ diff --git a/filling.c b/filling.c index 0ab4f08..80a06dd 100644 --- a/filling.c +++ b/filling.c @@ -1498,7 +1498,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (IS_CURSOR_MOVE(button)) { ui->cur_visible = true; - move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false, NULL); if (ui->keydragging) goto select_square; return MOVE_UI_UPDATE; } diff --git a/galaxies.c b/galaxies.c index 7f1d605..c56b07a 100644 --- a/galaxies.c +++ b/galaxies.c @@ -3021,7 +3021,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, else return MOVE_UI_UPDATE; } else if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, + false, NULL); if (ui->cur_x < 1) ui->cur_x = 1; if (ui->cur_y < 1) ui->cur_y = 1; ui->cur_visible = true; diff --git a/keen.c b/keen.c index 1446740..7022611 100644 --- a/keen.c +++ b/keen.c @@ -1748,7 +1748,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, } } if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->hx, &ui->hy, w, w, false); + move_cursor(button, &ui->hx, &ui->hy, w, w, false, NULL); ui->hshow = true; ui->hcursor = true; return MOVE_UI_UPDATE; diff --git a/lightup.c b/lightup.c index 15e0a67..64c41f7 100644 --- a/lightup.c +++ b/lightup.c @@ -1975,7 +1975,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, } ui->cur_visible = true; } else if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false, + NULL); ui->cur_visible = true; nullret = empty; } else diff --git a/magnets.c b/magnets.c index a437b59..6d7eb00 100644 --- a/magnets.c +++ b/magnets.c @@ -1844,7 +1844,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action; if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false, + NULL); ui->cur_visible = true; return MOVE_UI_UPDATE; } else if (IS_CURSOR_SELECT(button)) { diff --git a/map.c b/map.c index e7681a0..c7dbd29 100644 --- a/map.c +++ b/map.c @@ -2486,7 +2486,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h, - false); + false, NULL); ui->cur_visible = true; ui->cur_moved = true; ui->cur_lastmove = button; diff --git a/mines.c b/mines.c index d1787f5..91fe6e2 100644 --- a/mines.c +++ b/mines.c @@ -2423,7 +2423,8 @@ static char *interpret_move(const game_state *from, game_ui *ui, cy = FROMCOORD(y); if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false, + NULL); ui->cur_visible = true; return MOVE_UI_UPDATE; } diff --git a/misc.c b/misc.c index 334e08d..6b5f3f8 100644 --- a/misc.c +++ b/misc.c @@ -351,15 +351,16 @@ void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col) draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col); } -void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap) +char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap, + bool *visible) { - int dx = 0, dy = 0; + int dx = 0, dy = 0, ox = *x, oy = *y; switch (button) { case CURSOR_UP: dy = -1; break; case CURSOR_DOWN: dy = 1; break; case CURSOR_RIGHT: dx = 1; break; case CURSOR_LEFT: dx = -1; break; - default: return; + default: return MOVE_UNUSED; } if (wrap) { *x = (*x + dx + maxw) % maxw; @@ -368,6 +369,13 @@ void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap) *x = min(max(*x+dx, 0), maxw - 1); *y = min(max(*y+dy, 0), maxh - 1); } + if (visible != NULL && !*visible) { + *visible = true; + return MOVE_UI_UPDATE; + } + if (*x != ox || *y != oy) + return MOVE_UI_UPDATE; + return MOVE_NO_EFFECT; } /* Used in netslide.c and sixteen.c for cursor movement around edge. */ diff --git a/mosaic.c b/mosaic.c index b2cb0a5..8cca7b9 100644 --- a/mosaic.c +++ b/mosaic.c @@ -1190,7 +1190,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->prev_cur_x = ui->cur_x; ui->prev_cur_y = ui->cur_y; move_cursor(button, &ui->cur_x, &ui->cur_y, state->width, - state->height, false); + state->height, false, NULL); ui->cur_visible = true; return MOVE_UI_UPDATE; } else if (IS_CURSOR_SELECT(button)) { diff --git a/palisade.c b/palisade.c index 83b5983..028633b 100644 --- a/palisade.c +++ b/palisade.c @@ -969,7 +969,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, int dir, i = ui->y * w + ui->x; x = ui->x; y = ui->y; - move_cursor(button, &x, &y, w, h, false); + move_cursor(button, &x, &y, w, h, false, NULL); if (OUT_OF_BOUNDS(x, y, w, h)) return NULL; for (dir = 0; dir < 4; ++dir) @@ -989,7 +989,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, return string(80, "F%d,%d,%dF%d,%d,%d", ui->x, ui->y, flag, x, y, newflag); } else { - move_cursor(button, &ui->x, &ui->y, w, h, false); + move_cursor(button, &ui->x, &ui->y, w, h, false, NULL); return MOVE_UI_UPDATE; } } diff --git a/pattern.c b/pattern.c index 1eafaff..734b70b 100644 --- a/pattern.c +++ b/pattern.c @@ -1395,7 +1395,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (IS_CURSOR_MOVE(button)) { int x = ui->cur_x, y = ui->cur_y, newstate; char buf[80]; - move_cursor(button, &ui->cur_x, &ui->cur_y, state->common->w, state->common->h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, + state->common->w, state->common->h, false, NULL); ui->cur_visible = true; if (!control && !shift) return MOVE_UI_UPDATE; diff --git a/pearl.c b/pearl.c index 6c64ee9..51897b0 100644 --- a/pearl.c +++ b/pearl.c @@ -2201,10 +2201,10 @@ static char *interpret_move(const game_state *state, game_ui *ui, move = mark_in_direction(state, ui->curx, ui->cury, KEY_DIRECTION(button), control, tmpbuf); if (control && !shift && *move) - move_cursor(button, &ui->curx, &ui->cury, w, h, false); + move_cursor(button, &ui->curx, &ui->cury, w, h, false, NULL); return move; } else { - move_cursor(button, &ui->curx, &ui->cury, w, h, false); + move_cursor(button, &ui->curx, &ui->cury, w, h, false, NULL); if (ui->ndragcoords >= 0) update_ui_drag(state, ui, ui->curx, ui->cury); } diff --git a/pegs.c b/pegs.c index 1a2b9cd..c770bf3 100644 --- a/pegs.c +++ b/pegs.c @@ -947,7 +947,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, /* Not jumping; move cursor as usual, making sure we don't * leave the gameboard (which may be an irregular shape) */ int cx = ui->cur_x, cy = ui->cur_y; - move_cursor(button, &cx, &cy, w, h, false); + move_cursor(button, &cx, &cy, w, h, false, NULL); ui->cur_visible = true; if (state->grid[cy*w+cx] == GRID_HOLE || state->grid[cy*w+cx] == GRID_PEG) { diff --git a/puzzles.h b/puzzles.h index b4d33de..f545653 100644 --- a/puzzles.h +++ b/puzzles.h @@ -424,7 +424,8 @@ void draw_rect_outline(drawing *dr, int x, int y, int w, int h, /* Draw a set of rectangle corners (e.g. for a cursor display). */ void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col); -void move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap); +char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap, + bool *visible); /* Used in netslide.c and sixteen.c for cursor movement around edge. */ int c2pos(int w, int h, int cx, int cy); diff --git a/rect.c b/rect.c index a20cf18..7228837 100644 --- a/rect.c +++ b/rect.c @@ -2415,7 +2415,8 @@ static char *interpret_move(const game_state *from, game_ui *ui, enddrag = true; erasing = (button == RIGHT_RELEASE); } else if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, false, + NULL); ui->cur_visible = true; active = true; if (!ui->cur_dragging) return MOVE_UI_UPDATE; diff --git a/signpost.c b/signpost.c index 4f7eaf3..38c4795 100644 --- a/signpost.c +++ b/signpost.c @@ -1511,7 +1511,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, char buf[80]; if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, false); + move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, false, NULL); ui->cshow = true; if (ui->dragging) { ui->dx = COORD(ui->cx) + TILE_SIZE/2; diff --git a/singles.c b/singles.c index 0270331..23b8a4c 100644 --- a/singles.c +++ b/singles.c @@ -1505,7 +1505,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, enum { NONE, TOGGLE_BLACK, TOGGLE_CIRCLE, UI } action = NONE; if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true); + move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, true, NULL); ui->cshow = true; action = UI; } else if (IS_CURSOR_SELECT(button)) { diff --git a/sixteen.c b/sixteen.c index 1f4c7e1..f8763ff 100644 --- a/sixteen.c +++ b/sixteen.c @@ -634,9 +634,9 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (x < 0 || x >= state->w || y < 0 || y >= state->h) return NULL; move_cursor(button | pad, &x, &y, - state->w, state->h, false); + state->w, state->h, false, NULL); move_cursor(button | pad, &xwrap, &ywrap, - state->w, state->h, true); + state->w, state->h, true, NULL); if (x != xwrap) { sprintf(buf, "R%d,%c1", y, x ? '+' : '-'); @@ -657,7 +657,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, int x = ui->cur_x + 1, y = ui->cur_y + 1; move_cursor(button | pad, &x, &y, - state->w + 2, state->h + 2, false); + state->w + 2, state->h + 2, false, NULL); if (x == 0 && y == 0) { int t = ui->cur_x; diff --git a/slant.c b/slant.c index 134d49e..6ce0a49 100644 --- a/slant.c +++ b/slant.c @@ -1739,7 +1739,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, action = (button == CURSOR_SELECT2) ? ANTICLOCKWISE : CLOCKWISE; } else if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false); + move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false, NULL); ui->cur_visible = true; return MOVE_UI_UPDATE; } else if (button == '\\' || button == '\b' || button == '/') { diff --git a/solo.c b/solo.c index d934110..29ae1dd 100644 --- a/solo.c +++ b/solo.c @@ -4661,7 +4661,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, } } if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->hx, &ui->hy, cr, cr, false); + move_cursor(button, &ui->hx, &ui->hy, cr, cr, false, NULL); ui->hshow = true; ui->hcursor = true; return MOVE_UI_UPDATE; diff --git a/tents.c b/tents.c index ff4af33..607b6ab 100644 --- a/tents.c +++ b/tents.c @@ -1678,7 +1678,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (shift || control) { int len = 0, i, indices[2]; indices[0] = ui->cx + w * ui->cy; - move_cursor(button, &ui->cx, &ui->cy, w, h, false); + move_cursor(button, &ui->cx, &ui->cy, w, h, false, NULL); indices[1] = ui->cx + w * ui->cy; /* NONTENTify all unique traversed eligible squares */ @@ -1693,7 +1693,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, tmpbuf[len] = '\0'; if (len) return dupstr(tmpbuf); } else - move_cursor(button, &ui->cx, &ui->cy, w, h, false); + move_cursor(button, &ui->cx, &ui->cy, w, h, false, NULL); return MOVE_UI_UPDATE; } if (ui->cdisp) { diff --git a/towers.c b/towers.c index 718f9f6..297ada8 100644 --- a/towers.c +++ b/towers.c @@ -1501,7 +1501,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, } return NULL; } - move_cursor(button, &ui->hx, &ui->hy, w, w, false); + move_cursor(button, &ui->hx, &ui->hy, w, w, false, NULL); ui->hshow = true; ui->hcursor = true; return MOVE_UI_UPDATE; diff --git a/unequal.c b/unequal.c index 4b2bc42..0adee9d 100644 --- a/unequal.c +++ b/unequal.c @@ -1553,7 +1553,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (shift_or_control) { int nx = ui->hx, ny = ui->hy, i; bool self; - move_cursor(button, &nx, &ny, ds->order, ds->order, false); + move_cursor(button, &nx, &ny, ds->order, ds->order, false, NULL); ui->hshow = true; ui->hcursor = true; @@ -1582,7 +1582,8 @@ static char *interpret_move(const game_state *state, game_ui *ui, return dupstr(buf); } else { - move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, false); + move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, false, + NULL); ui->hshow = true; ui->hcursor = true; return MOVE_UI_UPDATE; diff --git a/unfinished/group.c b/unfinished/group.c index b008e82..8eac96a 100644 --- a/unfinished/group.c +++ b/unfinished/group.c @@ -1615,7 +1615,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (IS_CURSOR_MOVE(button)) { int cx = find_in_sequence(state->sequence, w, ui->hx); int cy = find_in_sequence(state->sequence, w, ui->hy); - move_cursor(button, &cx, &cy, w, w, false); + move_cursor(button, &cx, &cy, w, w, false, NULL); ui->hx = state->sequence[cx]; ui->hy = state->sequence[cy]; ui->hshow = true; diff --git a/unruly.c b/unruly.c index 18c411f..eddd641 100644 --- a/unruly.c +++ b/unruly.c @@ -1628,7 +1628,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, /* Keyboard move */ if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cx, &ui->cy, w2, h2, false); + move_cursor(button, &ui->cx, &ui->cy, w2, h2, false, NULL); ui->cursor = true; return MOVE_UI_UPDATE; }