From a11ee53ef844522b48b06ddffed268fa86d7b2ec Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 13 Aug 2023 14:03:26 +0100 Subject: [PATCH] Keen, Solo, Towers, Undead, Unequal, Group: new UI preference. If you're using the mouse to change pencil marks, you have to right-click to pencil-highlight a square, then press a number or letter key to add or remove a highlight. That causes the highlight to vanish again. So adding or removing multiple pencil marks requires a right-click + keypress per mark. Chris's Android port reversed that decision, making the pencil highlight persist so that you could 'click' just once and then press multiple pencil keys. That makes it easier to add lots of highlights, but harder to just remove a single one (click + press + click to remove the highlight), unless you don't mind keeping the highlight around afterwards cluttering up your view. In other words, this is just the sort of thing users might reasonably disagree on. So now we have an organised preferences system, we can let them disagree, and each configure it whichever way they like! This only affects mouse-based play. The keyboard cursor has _always_ worked this way, because it doesn't disappear at all; its behaviour is unchanged, and independent of the new preference. --- keen.c | 46 ++++++++++++++++++++++-- solo.c | 46 ++++++++++++++++++++++-- towers.c | 47 +++++++++++++++++++------ undead.c | 87 +++++++++++++++++++++++++++------------------- unequal.c | 46 ++++++++++++++++++++++-- unfinished/group.c | 46 ++++++++++++++++++++++-- 6 files changed, 263 insertions(+), 55 deletions(-) diff --git a/keen.c b/keen.c index 7022611..2d03b6b 100644 --- a/keen.c +++ b/keen.c @@ -1525,6 +1525,17 @@ struct game_ui { * allowed on immutable squares. */ bool hcursor; + + /* + * User preference option: if the user right-clicks in a square + * and presses a number key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -1535,6 +1546,8 @@ static game_ui *new_ui(const game_state *state) ui->hpencil = false; ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); + ui->pencil_keep_highlight = false; + return ui; } @@ -1543,6 +1556,28 @@ static void free_ui(game_ui *ui) sfree(ui); } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -1791,7 +1826,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return dupstr(buf); } @@ -2479,7 +2521,7 @@ const struct game thegame = { free_game, true, solve_game, false, NULL, NULL, /* can_format_as_text_now, text_format */ - NULL, NULL, /* get_prefs, set_prefs */ + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ diff --git a/solo.c b/solo.c index 29ae1dd..b9e4ab3 100644 --- a/solo.c +++ b/solo.c @@ -4557,6 +4557,17 @@ struct game_ui { * allowed on immutable squares. */ bool hcursor; + + /* + * User preference option: if the user right-clicks in a square + * and presses a number or letter key to add/remove a pencil mark, + * do we hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -4567,6 +4578,8 @@ static game_ui *new_ui(const game_state *state) ui->hpencil = false; ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); + ui->pencil_keep_highlight = false; + return ui; } @@ -4575,6 +4588,28 @@ static void free_ui(game_ui *ui) sfree(ui); } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -4723,7 +4758,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return dupstr(buf); } @@ -5632,7 +5674,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, - NULL, NULL, /* get_prefs, set_prefs */ + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ diff --git a/towers.c b/towers.c index 297ada8..0e93c09 100644 --- a/towers.c +++ b/towers.c @@ -1174,6 +1174,17 @@ struct game_ui { * it in just in case. */ int three_d; + + /* + * User preference option: if the user right-clicks in a square + * and presses a number key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static void legacy_prefs_override(struct game_ui *ui_out) @@ -1199,6 +1210,7 @@ static game_ui *new_ui(const game_state *state) ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); ui->three_d = true; + ui->pencil_keep_highlight = false; legacy_prefs_override(ui); return ui; @@ -1213,24 +1225,30 @@ static config_item *get_prefs(game_ui *ui) { config_item *ret; - ret = snewn(2, config_item); + ret = snewn(3, config_item); - ret[0].name = "Puzzle appearance"; - ret[0].kw = "appearance"; - ret[0].type = C_CHOICES; - ret[0].u.choices.choicenames = ":2D:3D"; - ret[0].u.choices.choicekws = ":2d:3d"; - ret[0].u.choices.selected = ui->three_d; + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; - ret[1].name = NULL; - ret[1].type = C_END; + ret[1].name = "Puzzle appearance"; + ret[1].kw = "appearance"; + ret[1].type = C_CHOICES; + ret[1].u.choices.choicenames = ":2D:3D"; + ret[1].u.choices.choicekws = ":2d:3d"; + ret[1].u.choices.selected = ui->three_d; + + ret[2].name = NULL; + ret[2].type = C_END; return ret; } static void set_prefs(game_ui *ui, const config_item *cfg) { - ui->three_d = cfg[0].u.choices.selected; + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; + ui->three_d = cfg[1].u.choices.selected; } static void game_changed_state(game_ui *ui, const game_state *oldstate, @@ -1550,7 +1568,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return dupstr(buf); } diff --git a/undead.c b/undead.c index 38543ba..0213d0e 100644 --- a/undead.c +++ b/undead.c @@ -1644,6 +1644,17 @@ struct game_ui { int hx, hy; /* as for solo.c, highlight pos */ bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ bool ascii; + + /* + * User preference option: if the user right-clicks in a square + * and presses a monster key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -1653,6 +1664,9 @@ static game_ui *new_ui(const game_state *state) ui->hx = ui->hy = ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); ui->ascii = false; + + ui->pencil_keep_highlight = false; + return ui; } @@ -1660,24 +1674,30 @@ static config_item *get_prefs(game_ui *ui) { config_item *ret; - ret = snewn(2, config_item); + ret = snewn(3, config_item); - ret[0].name = "Monster representation"; - ret[0].kw = "monsters"; - ret[0].type = C_CHOICES; - ret[0].u.choices.choicenames = ":Pictures:Letters"; - ret[0].u.choices.choicekws = ":pictures:letters"; - ret[0].u.choices.selected = ui->ascii; + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; - ret[1].name = NULL; - ret[1].type = C_END; + ret[1].name = "Monster representation"; + ret[1].kw = "monsters"; + ret[1].type = C_CHOICES; + ret[1].u.choices.choicenames = ":Pictures:Letters"; + ret[1].u.choices.choicekws = ":pictures:letters"; + ret[1].u.choices.selected = ui->ascii; + + ret[2].name = NULL; + ret[2].type = C_END; return ret; } static void set_prefs(game_ui *ui, const config_item *cfg) { - ui->ascii = cfg[0].u.choices.selected; + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; + ui->ascii = cfg[1].u.choices.selected; } static void free_ui(game_ui *ui) { @@ -1840,39 +1860,34 @@ static char *interpret_move(const game_state *state, game_ui *ui, if (ui->hshow && ui->hpencil) { xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)]; if (xi >= 0 && !state->common->fixed[xi]) { + buf[0] = '\0'; + if (button == 'g' || button == 'G' || button == '1') { sprintf(buf,"g%d",xi); - if (!ui->hcursor) { - ui->hpencil = false; - ui->hshow = false; - } - return dupstr(buf); - } - if (button == 'v' || button == 'V' || button == '2') { + } else if (button == 'v' || button == 'V' || button == '2') { sprintf(buf,"v%d",xi); - if (!ui->hcursor) { - ui->hpencil = false; - ui->hshow = false; - } - return dupstr(buf); - } - if (button == 'z' || button == 'Z' || button == '3') { + } else if (button == 'z' || button == 'Z' || button == '3') { sprintf(buf,"z%d",xi); - if (!ui->hcursor) { - ui->hpencil = false; - ui->hshow = false; - } - return dupstr(buf); - } - if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 || - button == '0' || button == '\b') { - if (!ui->hcursor) { - ui->hpencil = false; - ui->hshow = false; - } + } else if (button == 'e' || button == 'E' || + button == CURSOR_SELECT2 || button == '0' || + button == '\b') { if (state->pencils[xi] == 0) return ui->hcursor ? NULL : MOVE_UI_UPDATE; sprintf(buf,"E%d",xi); + } + + if (buf[0]) { + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && + !(ui->hpencil && ui->pencil_keep_highlight)) { + ui->hpencil = false; + ui->hshow = false; + } return dupstr(buf); } } diff --git a/unequal.c b/unequal.c index 0adee9d..f778df0 100644 --- a/unequal.c +++ b/unequal.c @@ -1436,6 +1436,17 @@ static char *solve_game(const game_state *state, const game_state *currstate, struct game_ui { int hx, hy; /* as for solo.c, highlight pos */ bool hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ + + /* + * User preference option: if the user right-clicks in a square + * and presses a number key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -1446,6 +1457,8 @@ static game_ui *new_ui(const game_state *state) ui->hpencil = false; ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); + ui->pencil_keep_highlight = false; + return ui; } @@ -1454,6 +1467,28 @@ static void free_ui(game_ui *ui) sfree(ui); } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -1632,7 +1667,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return dupstr(buf); } @@ -2155,7 +2197,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, - NULL, NULL, /* get_prefs, set_prefs */ + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ diff --git a/unfinished/group.c b/unfinished/group.c index 8eac96a..c622e9a 100644 --- a/unfinished/group.c +++ b/unfinished/group.c @@ -1252,6 +1252,17 @@ struct game_ui { int dragnum; /* element being dragged */ int dragpos; /* its current position */ int edgepos; + + /* + * User preference option: if the user right-clicks in a square + * and presses a letter key to add/remove a pencil mark, do we + * hide the mouse highlight again afterwards? + * + * Historically our answer was yes. The Android port prefers no. + * There are advantages both ways, depending how much you dislike + * the highlight cluttering your view. So it's a preference. + */ + bool pencil_keep_highlight; }; static game_ui *new_ui(const game_state *state) @@ -1264,6 +1275,8 @@ static game_ui *new_ui(const game_state *state) ui->hcursor = false; ui->drag = 0; + ui->pencil_keep_highlight = false; + return ui; } @@ -1272,6 +1285,28 @@ static void free_ui(game_ui *ui) sfree(ui); } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Keep mouse highlight after changing a pencil mark"; + ret[0].kw = "pencil-keep-highlight"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->pencil_keep_highlight; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->pencil_keep_highlight = cfg[0].u.boolean.bval; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -1676,7 +1711,14 @@ static char *interpret_move(const game_state *state, game_ui *ui, } movebuf = sresize(movebuf, buflen+1, char); - if (!ui->hcursor) ui->hshow = false; + /* + * Hide the highlight after a keypress, if it was mouse- + * generated. Also, don't hide it if this move has changed + * pencil marks and the user preference says not to hide the + * highlight in that situation. + */ + if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) + ui->hshow = false; return movebuf; } @@ -2323,7 +2365,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, - NULL, NULL, /* get_prefs, set_prefs */ + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */