chiark / gitweb /
Update changelog for 20170923.ff218728-0+iwj2~3.gbpc58e0c release
[sgt-puzzles.git] / puzzles.h
index 1847d9c7b8964a740061f79d5375785be901071c..40f5bcbce3a45bb2172ff8d5de43b42fb958a8e0 100644 (file)
--- a/puzzles.h
+++ b/puzzles.h
@@ -47,6 +47,15 @@ enum {
     CURSOR_RIGHT,
     CURSOR_SELECT,
     CURSOR_SELECT2,
+    /* UI_* are special keystrokes generated by front ends in response
+     * to menu actions, never passed to back ends */
+    UI_LOWER_BOUND,
+    UI_QUIT,
+    UI_NEWGAME,
+    UI_SOLVE,
+    UI_UNDO,
+    UI_REDO,
+    UI_UPPER_BOUND,
     
     /* made smaller because of 'limited range of datatype' errors. */
     MOD_CTRL       = 0x1000,
@@ -64,6 +73,7 @@ enum {
 #define IS_CURSOR_MOVE(m) ( (m) == CURSOR_UP || (m) == CURSOR_DOWN || \
                             (m) == CURSOR_RIGHT || (m) == CURSOR_LEFT )
 #define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2)
+#define IS_UI_FAKE_KEY(m) ( (m) > UI_LOWER_BOUND && (m) < UI_UPPER_BOUND )
 
 /*
  * Flags in the back end's `flags' word.
@@ -127,31 +137,85 @@ typedef struct psdata psdata;
  */
 enum { C_STRING, C_CHOICES, C_BOOLEAN, C_END };
 struct config_item {
-    /*
-     * `name' is never dynamically allocated.
-     */
-    char *name;
-    /*
-     * `type' contains one of the above values.
-     */
+    /* Not dynamically allocated */
+    const char *name;
+    /* Value from the above C_* enum */
     int type;
-    /*
-     * For C_STRING, `sval' is always dynamically allocated and
-     * non-NULL. For C_BOOLEAN and C_END, `sval' is always NULL.
-     * For C_CHOICES, `sval' is non-NULL, _not_ dynamically
-     * allocated, and contains a set of option strings separated by
-     * a delimiter. The delimeter is also the first character in
-     * the string, so for example ":Foo:Bar:Baz" gives three
-     * options `Foo', `Bar' and `Baz'.
-     */
-    char *sval;
-    /*
-     * For C_BOOLEAN, this is TRUE or FALSE. For C_CHOICES, it
-     * indicates the chosen index from the `sval' list. In the
-     * above example, 0==Foo, 1==Bar and 2==Baz.
-     */
-    int ival;
+    union {
+        struct { /* if type == C_STRING */
+            /* Always dynamically allocated and non-NULL */
+            char *sval;
+        } string;
+        struct { /* if type == C_CHOICES */
+            /*
+             * choicenames is non-NULL, not dynamically allocated, and
+             * contains a set of option strings separated by a
+             * delimiter. The delimiter is also the first character in
+             * the string, so for example ":Foo:Bar:Baz" gives three
+             * options `Foo', `Bar' and `Baz'.
+             */
+            const char *choicenames;
+            /*
+             * Indicates the chosen index from the options in
+             * choicenames. In the above example, 0==Foo, 1==Bar and
+             * 2==Baz.
+             */
+            int selected;
+        } choices;
+        struct {
+            /* just TRUE or FALSE */
+            int bval;
+        } boolean;
+    } u;
+};
+
+/*
+ * Structure used to communicate the presets menu from midend to
+ * frontend. In principle, it's also used to pass the same information
+ * from game to midend, though games that don't specify a menu
+ * hierarchy (i.e. most of them) will use the simpler fetch_preset()
+ * function to return an unstructured list.
+ *
+ * A tree of these structures always belongs to the midend, and only
+ * the midend should ever need to free it. The front end should treat
+ * them as read-only.
+ */
+struct preset_menu_entry {
+    char *title;
+    /* Exactly one of the next two fields is NULL, depending on
+     * whether this entry is a submenu title or an actual preset */
+    game_params *params;
+    struct preset_menu *submenu;
+    /* Every preset menu entry has a number allocated by the mid-end,
+     * so that midend_which_preset() can return a value that
+     * identifies an entry anywhere in the menu hierarchy. The values
+     * will be allocated reasonably densely from 1 upwards (so it's
+     * reasonable for the front end to use them as array indices if it
+     * needs to store GUI state per menu entry), but no other
+     * guarantee is given about their ordering.
+     *
+     * Entries containing submenus have ids too - not only the actual
+     * presets are numbered. */
+    int id;
 };
+struct preset_menu {
+    int n_entries;             /* number of entries actually in use */
+    int entries_size;          /* space currently allocated in this array */
+    struct preset_menu_entry *entries;
+};
+/* For games which do want to directly return a tree of these, here
+ * are convenience routines (in midend.c) for constructing one. These
+ * assume that 'title' and 'encoded_params' are already dynamically
+ * allocated by the caller; the resulting preset_menu tree takes
+ * ownership of them. */
+struct preset_menu *preset_menu_new(void);
+struct preset_menu *preset_menu_add_submenu(struct preset_menu *parent,
+                                            char *title);
+void preset_menu_add_preset(struct preset_menu *menu,
+                            char *title, game_params *params);
+/* Helper routine front ends can use for one of the ways they might
+ * want to organise their preset menu usage */
+game_params *preset_menu_lookup_by_id(struct preset_menu *menu, int id);
 
 /*
  * Platform routines
@@ -160,12 +224,12 @@ struct config_item {
 /* We can't use #ifdef DEBUG, because Cygwin defines it by default. */
 #ifdef DEBUGGING
 #define debug(x) (debug_printf x)
-void debug_printf(char *fmt, ...);
+void debug_printf(const char *fmt, ...);
 #else
 #define debug(x)
 #endif
 
-void fatal(char *fmt, ...);
+void fatal(const char *fmt, ...);
 void frontend_default_colour(frontend *fe, float *output);
 void deactivate_timer(frontend *fe);
 void activate_timer(frontend *fe);
@@ -177,7 +241,7 @@ void get_random_seed(void **randseed, int *randseedsize);
 drawing *drawing_new(const drawing_api *api, midend *me, void *handle);
 void drawing_free(drawing *dr);
 void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
-               int align, int colour, char *text);
+               int align, int colour, const char *text);
 void draw_rect(drawing *dr, int x, int y, int w, int h, int colour);
 void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour);
 void draw_polygon(drawing *dr, int *coords, int npoints,
@@ -192,7 +256,7 @@ void start_draw(drawing *dr);
 void draw_update(drawing *dr, int x, int y, int w, int h);
 void end_draw(drawing *dr);
 char *text_fallback(drawing *dr, const char *const *strings, int nstrings);
-void status_bar(drawing *dr, char *text);
+void status_bar(drawing *dr, const char *text);
 blitter *blitter_new(drawing *dr, int w, int h);
 void blitter_free(drawing *dr, blitter *bl);
 /* save puts the portion of the current display with top-left corner
@@ -242,36 +306,36 @@ void midend_redraw(midend *me);
 float *midend_colours(midend *me, int *ncolours);
 void midend_freeze_timer(midend *me, float tprop);
 void midend_timer(midend *me, float tplus);
-int midend_num_presets(midend *me);
-void midend_fetch_preset(midend *me, int n,
-                         char **name, game_params **params);
+struct preset_menu *midend_get_presets(midend *me, int *id_limit);
 int midend_which_preset(midend *me);
 int midend_wants_statusbar(midend *me);
 enum { CFG_SETTINGS, CFG_SEED, CFG_DESC, CFG_FRONTEND_SPECIFIC };
 config_item *midend_get_config(midend *me, int which, char **wintitle);
-char *midend_set_config(midend *me, int which, config_item *cfg);
-char *midend_game_id(midend *me, char *id);
+const char *midend_set_config(midend *me, int which, config_item *cfg);
+const char *midend_game_id(midend *me, const char *id);
 char *midend_get_game_id(midend *me);
 char *midend_get_random_seed(midend *me);
 int midend_can_format_as_text_now(midend *me);
 char *midend_text_format(midend *me);
-char *midend_solve(midend *me);
+const char *midend_solve(midend *me);
 int midend_status(midend *me);
 int midend_can_undo(midend *me);
 int midend_can_redo(midend *me);
-void midend_supersede_game_desc(midend *me, char *desc, char *privdesc);
-char *midend_rewrite_statusbar(midend *me, char *text);
+void midend_supersede_game_desc(midend *me, const char *desc,
+                                const char *privdesc);
+char *midend_rewrite_statusbar(midend *me, const char *text);
 void midend_serialise(midend *me,
-                      void (*write)(void *ctx, void *buf, int len),
+                      void (*write)(void *ctx, const void *buf, int len),
                       void *wctx);
-char *midend_deserialise(midend *me,
-                         int (*read)(void *ctx, void *buf, int len),
-                         void *rctx);
-char *identify_game(char **name, int (*read)(void *ctx, void *buf, int len),
-                    void *rctx);
+const char *midend_deserialise(midend *me,
+                               int (*read)(void *ctx, void *buf, int len),
+                               void *rctx);
+const char *identify_game(char **name,
+                          int (*read)(void *ctx, void *buf, int len),
+                          void *rctx);
 void midend_request_id_changes(midend *me, void (*notify)(void *), void *ctx);
 /* Printing functions supplied by the mid-end */
-char *midend_print_puzzle(midend *me, document *doc, int with_soln);
+const char *midend_print_puzzle(midend *me, document *doc, int with_soln);
 int midend_tilesize(midend *me);
 
 /*
@@ -329,7 +393,12 @@ void pos2c(int w, int h, int pos, int *cx, int *cy);
  * by one pixel; useful for highlighting. Outline is omitted if -1. */
 void draw_text_outline(drawing *dr, int x, int y, int fonttype,
                        int fontsize, int align,
-                       int text_colour, int outline_colour, char *text);
+                       int text_colour, int outline_colour, const char *text);
+
+/* Copies text left-justified with spaces. Length of string must be
+ * less than buffer size. */
+void copy_left_justified(char *buf, size_t sz, const char *str);
+
 /*
  * dsf.c
  */
@@ -514,6 +583,7 @@ struct game {
     const char *winhelp_topic, *htmlhelp_topic;
     game_params *(*default_params)(void);
     int (*fetch_preset)(int i, char **name, game_params **params);
+    struct preset_menu *(*preset_menu)(void);
     void (*decode_params)(game_params *, char const *string);
     char *(*encode_params)(const game_params *, int full);
     void (*free_params)(game_params *params);
@@ -521,17 +591,17 @@ struct game {
     int can_configure;
     config_item *(*configure)(const game_params *params);
     game_params *(*custom_params)(const config_item *cfg);
-    char *(*validate_params)(const game_params *params, int full);
+    const char *(*validate_params)(const game_params *params, int full);
     char *(*new_desc)(const game_params *params, random_state *rs,
                      char **aux, int interactive);
-    char *(*validate_desc)(const game_params *params, const char *desc);
+    const char *(*validate_desc)(const game_params *params, const char *desc);
     game_state *(*new_game)(midend *me, const game_params *params,
                             const char *desc);
     game_state *(*dup_game)(const game_state *state);
     void (*free_game)(game_state *state);
     int can_solve;
     char *(*solve)(const game_state *orig, const game_state *curr,
-                   const char *aux, char **error);
+                   const char *aux, const char **error);
     int can_format_as_text_ever;
     int (*can_format_as_text_now)(const game_params *params);
     char *(*text_format)(const game_state *state);
@@ -576,7 +646,7 @@ struct game {
  */
 struct drawing_api {
     void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize,
-                     int align, int colour, char *text);
+                     int align, int colour, const char *text);
     void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour);
     void (*draw_line)(void *handle, int x1, int y1, int x2, int y2,
                      int colour);
@@ -589,7 +659,7 @@ struct drawing_api {
     void (*unclip)(void *handle);
     void (*start_draw)(void *handle);
     void (*end_draw)(void *handle);
-    void (*status_bar)(void *handle, char *text);
+    void (*status_bar)(void *handle, const char *text);
     blitter *(*blitter_new)(void *handle, int w, int h);
     void (*blitter_free)(void *handle, blitter *bl);
     void (*blitter_save)(void *handle, blitter *bl, int x, int y);
@@ -622,6 +692,14 @@ extern const int gamecount;
 extern const game thegame;
 #endif
 
+/*
+ * Special string value to return from interpret_move in the case
+ * where the game UI has been updated but no actual move is being
+ * appended to the undo chain. Must be declared as a non-const char,
+ * but should never actually be modified by anyone.
+ */
+extern char UI_UPDATE[];
+
 /* A little bit of help to lazy developers */
 #define DEFAULT_STATUSBAR_TEXT "Use status_bar() to fill this in."