aboutsummaryrefslogtreecommitdiff
path: root/devel.but
diff options
context:
space:
mode:
authorSimon Tatham <anakin@pobox.com>2023-04-21 15:50:05 +0100
committerSimon Tatham <anakin@pobox.com>2023-04-23 13:25:06 +0100
commit0058331aeb027f7441a04d99cc7c1e445bd896d9 (patch)
treedbc122795b93195c7bb1b7c7b51e50927b547415 /devel.but
parent0d1a1f08bac25a4641c38a8e42dfa6e2bb9981d7 (diff)
downloadpuzzles-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.
Diffstat (limited to 'devel.but')
-rw-r--r--devel.but114
1 files changed, 96 insertions, 18 deletions
diff --git a/devel.but b/devel.but
index 0fb1a14..68a0df2 100644
--- a/devel.but
+++ b/devel.but
@@ -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,