diff options
| author | Simon Tatham <anakin@pobox.com> | 2023-04-21 15:50:05 +0100 |
|---|---|---|
| committer | Simon Tatham <anakin@pobox.com> | 2023-04-23 13:25:06 +0100 |
| commit | 0058331aeb027f7441a04d99cc7c1e445bd896d9 (patch) | |
| tree | dbc122795b93195c7bb1b7c7b51e50927b547415 | |
| parent | 0d1a1f08bac25a4641c38a8e42dfa6e2bb9981d7 (diff) | |
| download | puzzles-0058331aeb027f7441a04d99cc7c1e445bd896d9.zip puzzles-0058331aeb027f7441a04d99cc7c1e445bd896d9.tar.gz puzzles-0058331aeb027f7441a04d99cc7c1e445bd896d9.tar.bz2 puzzles-0058331aeb027f7441a04d99cc7c1e445bd896d9.tar.xz | |
New backend functions: get_prefs and set_prefs.
These are similar to the existing pair configure() and custom_params()
in that get_prefs() returns an array of config_item describing a set
of dialog-box controls to present to the user, and set_prefs()
receives the same array with answers filled in and implements the
answers. But where configure() and custom_params() operate on a
game_params structure, the new pair operate on a game_ui, and are
intended to permit GUI configuration of all the settings I just moved
into that structure.
However, nothing actually _calls_ these routines yet. All I've done in
this commit is to add them to 'struct game' and implement them for the
functions that need them.
Also, config_item has new fields, permitting each config option to
define a machine-readable identifying keyword as well as the
user-facing description. For options of type C_CHOICES, each choice
also has a keyword. These keyword fields are only defined at all by
the new get_prefs() function - they're left uninitialised in existing
uses of the dialog system. The idea is to use them when writing out
the user's preferences into a configuration file on disk, although I
haven't actually done any of that work in this commit.
| -rw-r--r-- | blackbox.c | 1 | ||||
| -rw-r--r-- | bridges.c | 1 | ||||
| -rw-r--r-- | cube.c | 1 | ||||
| -rw-r--r-- | devel.but | 114 | ||||
| -rw-r--r-- | dominosa.c | 1 | ||||
| -rw-r--r-- | fifteen.c | 25 | ||||
| -rw-r--r-- | filling.c | 1 | ||||
| -rw-r--r-- | flip.c | 1 | ||||
| -rw-r--r-- | flood.c | 1 | ||||
| -rw-r--r-- | galaxies.c | 1 | ||||
| -rw-r--r-- | guess.c | 1 | ||||
| -rw-r--r-- | inertia.c | 1 | ||||
| -rw-r--r-- | keen.c | 1 | ||||
| -rw-r--r-- | lightup.c | 23 | ||||
| -rw-r--r-- | loopy.c | 32 | ||||
| -rw-r--r-- | magnets.c | 1 | ||||
| -rw-r--r-- | map.c | 25 | ||||
| -rw-r--r-- | mines.c | 1 | ||||
| -rw-r--r-- | mosaic.c | 1 | ||||
| -rw-r--r-- | net.c | 1 | ||||
| -rw-r--r-- | netslide.c | 1 | ||||
| -rw-r--r-- | nullgame.c | 1 | ||||
| -rw-r--r-- | palisade.c | 1 | ||||
| -rw-r--r-- | pattern.c | 1 | ||||
| -rw-r--r-- | pearl.c | 25 | ||||
| -rw-r--r-- | pegs.c | 1 | ||||
| -rw-r--r-- | puzzles.h | 16 | ||||
| -rw-r--r-- | range.c | 26 | ||||
| -rw-r--r-- | rect.c | 1 | ||||
| -rw-r--r-- | samegame.c | 1 | ||||
| -rw-r--r-- | signpost.c | 25 | ||||
| -rw-r--r-- | singles.c | 1 | ||||
| -rw-r--r-- | sixteen.c | 1 | ||||
| -rw-r--r-- | slant.c | 25 | ||||
| -rw-r--r-- | solo.c | 1 | ||||
| -rw-r--r-- | tents.c | 1 | ||||
| -rw-r--r-- | towers.c | 25 | ||||
| -rw-r--r-- | tracks.c | 1 | ||||
| -rw-r--r-- | twiddle.c | 1 | ||||
| -rw-r--r-- | undead.c | 1 | ||||
| -rw-r--r-- | unequal.c | 1 | ||||
| -rw-r--r-- | unfinished/group.c | 1 | ||||
| -rw-r--r-- | unfinished/separate.c | 1 | ||||
| -rw-r--r-- | unfinished/slide.c | 1 | ||||
| -rw-r--r-- | unfinished/sokoban.c | 1 | ||||
| -rw-r--r-- | unruly.c | 1 | ||||
| -rw-r--r-- | untangle.c | 1 |
47 files changed, 378 insertions, 19 deletions
@@ -1556,6 +1556,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 */ new_ui, free_ui, encode_ui, @@ -3289,6 +3289,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1760,6 +1760,7 @@ const struct game thegame = { free_game, false, NULL, /* solve */ false, NULL, NULL, /* can_format_as_text_now, text_format */ + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -332,23 +332,49 @@ game ID etc). It persists until the user finishes playing that game and begins another one (or closes the window); in particular, \q{Restart Game} does \e{not} destroy the \c{game_ui}. -\c{game_ui} is useful for implementing user-interface state which is -not part of \c{game_state}. Common examples are keyboard control -(you wouldn't want to have to separately Undo through every cursor -motion) and mouse dragging. See \k{writing-keyboard-cursor} and -\k{writing-howto-dragging}, respectively, for more details. - -Another use for \c{game_ui} is to store highly persistent data such -as the Mines death counter. This is conceptually rather different: -where the Net cursor position was \e{not important enough} to -preserve for the player to restore by Undo, the Mines death counter -is \e{too important} to permit the player to revert by Undo! - -A final use for \c{game_ui} is to pass information to the redraw -function about recent changes to the game state. This is used in -Mines, for example, to indicate whether a requested \q{flash} should -be a white flash for victory or a red flash for defeat; see -\k{writing-flash-types}. +There are various things that you might store in \c{game_ui}, which +are conceptually different from each other, but I haven't yet found a +need to split them out into smaller sub-structures for different +purposes: + +\dt Transient UI state: + +\dd Storing a piece of UI state in \c{game_state} means that you can +only update it by appending a move to the undo chain. Some UI state +shouldn't really be treated this way. For example, if your puzzle has +a keyboard-controlled cursor, you probably don't want every cursor +movement to be an undoable action, because the history of where the +cursor went just isn't interesting. More likely the cursor should just +move freely, and the only undoable actions are the ones where you +modify the element under the cursor. So you'd store the cursor +position in \c{game_ui} rather than \c{game_state}. See +\k{writing-keyboard-cursor} for more details. + +\lcont{ Another example of this is the state of an ongoing mouse drag. +If there's an undoable action involved, it will probably occur when +the drag is released. In between, you still need to store state that +the redraw function will use to update the display \dash and that can +live in \c{game_ui}. See \k{writing-howto-dragging} for more details +of this. } + +\dt Persistent UI state: + +\dd An example of this is the counter of deaths in Mines or Inertia. +This shouldn't be reverted by pressing Undo, for the opposite reason +to the cursor position: the cursor position is too boring to store the +history of, but the deaths counter is too \e{important}! + +\dt Information about recent changes to the game state: + +\dd This is used in Mines, for example, to indicate whether a +requested \q{flash} should be a white flash for victory or a red flash +for defeat; see \k{writing-flash-types}. + +\dt User preferences: + +\dd Any user preference about display or UI handled by +\cw{get_prefs()} and \cw{set_prefs()} will need to live in +\c{game_ui}, because that's the structure that those functions access. \H{backend-simple} Simple data in the back end @@ -579,7 +605,8 @@ its initial value; the front end will modify the value fields and return the updated array to \cw{custom_params()} (see \k{backend-custom-params}). -The \cw{config_item} structure contains the following elements: +The \cw{config_item} structure contains the following elements used by +this function: \c const char *name; \c int type; @@ -688,6 +715,57 @@ the dialog box will stay open.) If the game's \c{can_configure} flag is set to \cw{false}, this function is never called and can be \cw{NULL}. +\S{backend-get-prefs} \cw{get_prefs()} + +\c config_item *(*get_prefs)(game_ui *ui); + +This function works very like \cw{configure()}, but instead of +receiving a \c{game_params} and returning GUI elements describing the +data in it, this function receives a \c{game_ui} and returns GUI +elements describing any user preferences stored in that. + +This function should only deal with fields of \c{game_ui} that are +user-settable preferences. In-game state like cursor position and +mouse drags, or per-game state like death counters, are nothing to do +with this function. + +If there are no user preferences, you can set both this function +pointer and \c{set_prefs} to \cw{NULL}. + +In every \c{config_item} returned from this function, you must set an +additional field beyond the ones described in \k{backend-configure}: + +\c const char *kw; + +This should be an identifying keyword for the user preference in +question, suitable for use in configuration files. That means it +should remain stable, even if the user-facing wording in the \c{name} +field is reworded for clarity. If it doesn't stay stable, old +configuration files will not be read correctly. + +For \c{config_item}s of type \cw{C_CHOICES}, you must also set an +extra field in \c{u.choices}: + +\c const char *choicekws; + +This has the same structure as the \c{choicenames} field (a list of +values delimited by the first character in the whole string), and it +provides an identifying keyword for each individual choice in the +list, in the same order as the entries of \c{choicenames}. + +\S{backend-set-prefs} \cw{set_prefs()} + +\c void (*set_prefs)(game_ui *ui, const config_item *cfg); + +This function is the counterpart to \cw{set_prefs()}, as +\cw{custom_params()} is to \cw{configure()}. It receives an array of +\c{config_item}s which was originally created by \cw{get_prefs()}, +with the controls' values updated from user input, and it should +transcribe the new settings into the provided \c{game_ui}. + +If there are no user preferences, you can set both this function +pointer and \c{get_prefs} to \cw{NULL}. + \S{backend-validate-params} \cw{validate_params()} \c const char *(*validate_params)(const game_params *params, @@ -3442,6 +3442,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -484,6 +484,30 @@ static game_ui *new_ui(const game_state *state) return ui; } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Sense of arrow keys"; + ret[0].kw = "arrow-semantics"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = ":Move the tile:Move the gap"; + ret[0].u.choices.choicekws = ":tile:gap"; + ret[0].u.choices.selected = ui->invert_cursor; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->invert_cursor = cfg[0].u.choices.selected; +} + static void free_ui(game_ui *ui) { sfree(ui); @@ -1122,6 +1146,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -2174,6 +2174,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1337,6 +1337,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1365,6 +1365,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -4129,6 +4129,7 @@ const struct game thegame = { true, solve_game, #endif true, game_can_format_as_text_now, game_text_format, + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1518,6 +1518,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 */ new_ui, free_ui, encode_ui, @@ -2231,6 +2231,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 */ new_ui, free_ui, encode_ui, @@ -2479,6 +2479,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1867,6 +1867,28 @@ static game_ui *new_ui(const game_state *state) return ui; } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Draw non-light marks even when lit"; + ret[0].kw = "show-lit-blobs"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->draw_blobs_when_lit; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->draw_blobs_when_lit = cfg[0].u.boolean.bval; +} + static void free_ui(game_ui *ui) { sfree(ui); @@ -2353,6 +2375,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -931,6 +931,37 @@ static void free_ui(game_ui *ui) sfree(ui); } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(3, config_item); + + ret[0].name = "Draw excluded grid lines faintly"; + ret[0].kw = "draw-faint-lines"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->draw_faint_lines; + + ret[1].name = "Auto-follow unique paths of edges"; + ret[1].kw = "auto-follow"; + ret[1].type = C_CHOICES; + ret[1].u.choices.choicenames = + ":No:Based on grid only:Based on grid and game state"; + ret[1].u.choices.choicekws = ":off:fixed:adaptive"; + ret[1].u.choices.selected = ui->autofollow; + + ret[2].name = NULL; + ret[2].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->draw_faint_lines = cfg[0].u.boolean.bval; + ui->autofollow = cfg[1].u.choices.selected; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -3710,6 +3741,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -2459,6 +2459,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2333,6 +2333,30 @@ static game_ui *new_ui(const game_state *state) return ui; } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Victory flash effect"; + ret[0].kw = "flash-type"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = ":Cyclic:Each to white:All to white"; + ret[0].u.choices.choicekws = ":cyclic:each-white:all-white"; + ret[0].u.choices.selected = ui->flash_type; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->flash_type = cfg[0].u.choices.selected; +} + static void free_ui(game_ui *ui) { sfree(ui); @@ -3291,6 +3315,7 @@ const struct game thegame = { free_game, true, solve_game, false, NULL, NULL, /* can_format_as_text_now, text_format */ + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -3193,6 +3193,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 */ new_ui, free_ui, encode_ui, @@ -1609,6 +1609,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -3270,6 +3270,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 */ new_ui, free_ui, encode_ui, @@ -1858,6 +1858,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -237,6 +237,7 @@ const struct game thegame = { free_game, false, NULL, /* solve */ false, NULL, NULL, /* can_format_as_text_now, text_format */ + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1380,6 +1380,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2078,6 +2078,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1916,6 +1916,30 @@ 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 = "Puzzle appearance"; + ret[0].kw = "appearance"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = ":Traditional:Loopy-style"; + ret[0].u.choices.choicekws = ":traditional:loopy"; + ret[0].u.choices.selected = ui->gui_style; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->gui_style = cfg[0].u.choices.selected; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -2744,6 +2768,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -1361,6 +1361,7 @@ const struct game thegame = { free_game, false, NULL, /* solve */ true, game_can_format_as_text_now, game_text_format, + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -127,8 +127,13 @@ typedef struct psdata psdata; */ enum { C_STRING, C_CHOICES, C_BOOLEAN, C_END }; struct config_item { - /* Not dynamically allocated */ + /* Not dynamically allocated: the GUI display name for the option */ const char *name; + /* Not dynamically allocated: the keyword identifier for the + * option. Only examined in the case where this structure is being + * used for options that appear in config files, i.e. the + * get_prefs method fills this in but configure does not. */ + const char *kw; /* Value from the above C_* enum */ int type; union { @@ -146,6 +151,13 @@ struct config_item { */ const char *choicenames; /* + * choicekws is non-NULL, not dynamically allocated, and + * contains a parallel list of keyword strings used to + * represent the enumeration in config files. As with 'kw' + * above, this is only expected to be set by get_prefs. + */ + const char *choicekws; + /* * Indicates the chosen index from the options in * choicenames. In the above example, 0==Foo, 1==Bar and * 2==Baz. @@ -676,6 +688,8 @@ struct game { bool can_format_as_text_ever; bool (*can_format_as_text_now)(const game_params *params); char *(*text_format)(const game_state *state); + config_item *(*get_prefs)(game_ui *ui); + void (*set_prefs)(game_ui *ui, const config_item *cfg); game_ui *(*new_ui)(const game_state *state); void (*free_ui)(game_ui *ui); char *(*encode_ui)(const game_ui *ui); @@ -1271,6 +1271,31 @@ static game_ui *new_ui(const game_state *state) return ui; } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Mouse button order"; + ret[0].kw = "left-mouse-button"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = + ":Left to fill, right to dot:Left to dot, right to fill"; + ret[0].u.choices.choicekws = ":fill:dot"; + ret[0].u.choices.selected = ui->swap_buttons; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->swap_buttons = cfg[0].u.choices.selected; +} + static void free_ui(game_ui *ui) { sfree(ui); @@ -1834,6 +1859,7 @@ struct game const thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -2995,6 +2995,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1666,6 +1666,7 @@ const struct game thegame = { free_game, false, NULL, /* solve */ true, game_can_format_as_text_now, game_text_format, + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1437,6 +1437,30 @@ 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 = "Victory rotation effect"; + ret[0].kw = "flash-type"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = ":Unidirectional:Meshing gears"; + ret[0].u.choices.choicekws = ":unidirectional:gears"; + ret[0].u.choices.selected = ui->gear_mode; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->gear_mode = cfg[0].u.choices.selected; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -2292,6 +2316,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -1852,6 +1852,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1191,6 +1191,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1617,6 +1617,30 @@ static game_ui *new_ui(const game_state *state) return ui; } +static config_item *get_prefs(game_ui *ui) +{ + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Mouse button order"; + ret[0].kw = "left-button"; + ret[0].type = C_CHOICES; + ret[0].u.choices.choicenames = ":Left \\, right /:Left /, right \\"; + ret[0].u.choices.choicekws = ":\\:/"; + ret[0].u.choices.selected = ui->swap_buttons; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->swap_buttons = cfg[0].u.choices.selected; +} + static void free_ui(game_ui *ui) { sfree(ui); @@ -2204,6 +2228,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -5630,6 +5630,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2649,6 +2649,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1209,6 +1209,30 @@ 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 = "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[1].name = NULL; + ret[1].type = C_END; + + return ret; +} + +static void set_prefs(game_ui *ui, const config_item *cfg) +{ + ui->three_d = cfg[0].u.choices.selected; +} + static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { @@ -2084,6 +2108,7 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, NULL, /* encode_ui */ @@ -3047,6 +3047,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1305,6 +1305,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2784,6 +2784,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2154,6 +2154,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 */ new_ui, free_ui, NULL, /* encode_ui */ diff --git a/unfinished/group.c b/unfinished/group.c index dfa466d..7faee89 100644 --- a/unfinished/group.c +++ b/unfinished/group.c @@ -2323,6 +2323,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 */ new_ui, free_ui, NULL, /* encode_ui */ diff --git a/unfinished/separate.c b/unfinished/separate.c index 635d7c6..6ca0725 100644 --- a/unfinished/separate.c +++ b/unfinished/separate.c @@ -835,6 +835,7 @@ const struct game thegame = { free_game, false, solve_game, false, game_can_format_as_text_now, game_text_format, + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ diff --git a/unfinished/slide.c b/unfinished/slide.c index 6368eba..c797d7e 100644 --- a/unfinished/slide.c +++ b/unfinished/slide.c @@ -2328,6 +2328,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 */ new_ui, free_ui, NULL, /* encode_ui */ diff --git a/unfinished/sokoban.c b/unfinished/sokoban.c index 3b847af..1f3c688 100644 --- a/unfinished/sokoban.c +++ b/unfinished/sokoban.c @@ -1450,6 +1450,7 @@ const struct game thegame = { free_game, false, solve_game, false, game_can_format_as_text_now, game_text_format, + NULL, NULL, /* get_prefs, set_prefs */ new_ui, free_ui, NULL, /* encode_ui */ @@ -2030,6 +2030,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 */ new_ui, free_ui, NULL, /* encode_ui */ @@ -1454,6 +1454,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 */ new_ui, free_ui, NULL, /* encode_ui */ |