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.
This commit is contained in:
Simon Tatham
2023-08-13 14:03:26 +01:00
parent 503f1c4ab8
commit a11ee53ef8
6 changed files with 263 additions and 55 deletions

46
keen.c
View File

@ -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 */

46
solo.c
View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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 */