New backend function: current_key_label()

This provides a way for the front end to ask how a particular key should
be labelled right now (specifically, for a given game_state and
game_ui).  This is useful on feature phones where it's conventional to
put a small caption above each soft key indicating what it currently
does.

The function currently provides labels only for CURSOR_SELECT and
CURSOR_SELECT2.  This is because these are the only keys that need
labelling on KaiOS.

The concept of labelling keys also turns up in the request_keys() call,
but there are quite a few differences.  The labels returned by
current_key_label() are dynamic and likely to vary with each move, while
the labels provided by request_keys() are constant for a given
game_params.  Also, the keys returned by request_keys() don't generally
include CURSOR_SELECT and CURSOR_SELECT2, because those aren't necessary
on platforms with pointing devices.  It might be possible to provide a
unified API covering both of this, but I think it would be quite
difficult to work with.

Where a key is to be unlabelled, current_key_label() is expected to
return an empty string.  This leaves open the possibility of NULL
indicating a fallback to button2label or the label specified by
request_keys() in the future.

It's tempting to try to implement current_key_label() by calling
interpret_move() and parsing its output.  This doesn't work for two
reasons.  One is that interpret_move() is entitled to modify the
game_ui, and there isn't really a practical way to back those changes
out.  The other is that the information returned by interpret_move()
isn't sufficient to generate a label.  For instance, in many puzzles it
generates moves that toggle the state of a square, but we want the label
to reflect which state the square will be toggled to.  The result is
that I've generally ended up pulling bits of code from interpret_move()
and execute_move() together to implement current_key_label().

Alongside the back-end function, there's a midend_current_key_label()
that's a thin wrapper around the back-end function.  It just adds an
assertion about which key's being requested and a default null
implementation so that back-ends can avoid defining the function if it
will do nothing useful.
This commit is contained in:
Ben Harris
2022-12-05 01:13:26 +00:00
parent 1d91522bab
commit a3310ab857
48 changed files with 717 additions and 0 deletions

View File

@ -2539,6 +2539,33 @@ static bool edge_placement_legal(const game_state *state, int x, int y)
return true;
}
static const char *current_key_label(const game_ui *ui,
const game_state *state, int button)
{
space *sp;
if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
sp = &SPACE(state, ui->cur_x, ui->cur_y);
if (ui->dragging) {
if (ui->cur_x == ui->srcx && ui->cur_y == ui->srcy)
return "Cancel";
if (ok_to_add_assoc_with_opposite(
state, &SPACE(state, ui->cur_x, ui->cur_y),
&SPACE(state, ui->dotx, ui->doty)))
return "Place";
return (ui->srcx == ui->dotx && ui->srcy == ui->doty) ?
"Cancel" : "Remove";
} else if (sp->flags & F_DOT)
return "New arrow";
else if (sp->flags & F_TILE_ASSOC)
return "Move arrow";
else if (sp->type == s_edge &&
edge_placement_legal(state, ui->cur_x, ui->cur_y))
return (sp->flags & F_EDGE_SET) ? "Clear" : "Edge";
}
return "";
}
static char *interpret_move(const game_state *state, game_ui *ui,
const game_drawstate *ds,
int x, int y, int button)
@ -3813,6 +3840,11 @@ const struct game thegame = {
decode_ui,
NULL, /* game_request_keys */
game_changed_state,
#ifdef EDITOR
NULL,
#else
current_key_label,
#endif
interpret_move,
execute_move,
PREFERRED_TILE_SIZE, game_compute_size, game_set_size,