From a3310ab857f088489b35ebf10733ba284a24d27f Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Mon, 5 Dec 2022 01:13:26 +0000 Subject: 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. --- tracks.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'tracks.c') diff --git a/tracks.c b/tracks.c index 5392c25..9b5ef4c 100644 --- a/tracks.c +++ b/tracks.c @@ -2121,6 +2121,35 @@ static bool ui_can_flip_square(const game_state *state, int x, int y, bool notra return true; } +static const char *current_key_label(const game_ui *ui, + const game_state *state, int button) +{ + if (IS_CURSOR_SELECT(button) && ui->cursor_active) { + int gx = ui->curx / 2, gy = ui->cury / 2; + int w = state->p.w; + int direction = + ((ui->curx % 2) == 0) ? L : ((ui->cury % 2) == 0) ? U : 0; + if (direction && + ui_can_flip_edge(state, gx, gy, direction, + button == CURSOR_SELECT2)) { + unsigned ef = S_E_FLAGS(state, gx, gy, direction); + switch (button) { + case CURSOR_SELECT: return (ef & E_TRACK) ? "Clear" : "Track"; + case CURSOR_SELECT2: return (ef & E_NOTRACK) ? "Clear" : "X"; + } + } + if (!direction && + ui_can_flip_square(state, gx, gy, button == CURSOR_SELECT2)) { + unsigned sf = state->sflags[gy*w+gx]; + switch (button) { + case CURSOR_SELECT: return (sf & S_TRACK) ? "Clear" : "Track"; + case CURSOR_SELECT2: return (sf & S_NOTRACK) ? "Clear" : "X"; + } + } + } + return ""; +} + static char *edge_flip_str(const game_state *state, int x, int y, int dir, bool notrack, char *buf) { unsigned ef = S_E_FLAGS(state, x, y, dir); char c; @@ -2973,6 +3002,7 @@ const struct game thegame = { decode_ui, NULL, /* game_request_keys */ game_changed_state, + current_key_label, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, -- cgit v1.1