1 /**
2  * \file ui-menu.h
3  * \brief Generic menu interaction functions
4  *
5  * Copyright (c) 2007 Pete Mack
6  * Copyright (c) 2010 Andi Sidwell
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  */
19 
20 #ifndef INCLUDED_UI_MENU_H
21 #define INCLUDED_UI_MENU_H
22 
23 #include "ui-output.h"
24 
25 /*** Constants ***/
26 
27 /* Colors for interactive menus */
28 enum
29 {
30 	CURS_UNKNOWN = 0,		/* Use gray / dark blue for cursor */
31 	CURS_KNOWN = 1			/* Use white / light blue for cursor */
32 };
33 
34 /**
35  * Type wrapper for various row styles.
36  */
37 typedef enum _menu_row_style_t {
38 	MN_ROW_STYLE_DISABLED = CURS_UNKNOWN,
39 	MN_ROW_STYLE_ENABLED = CURS_KNOWN,
40 } menu_row_style_t;
41 
42 /**
43  * Type wrapper for row validity.
44  */
45 typedef enum _menu_row_validity_t {
46 	MN_ROW_INVALID = 0,
47 	MN_ROW_VALID = 1,
48 	MN_ROW_HIDDEN = 2,
49 } menu_row_validity_t;
50 
51 /* Cursor colours for different states */
52 extern const byte curs_attrs[2][2];
53 
54 /* Standard menu orderings */
55 extern const char lower_case[];			/* abc..z */
56 extern const char upper_case[];			/* ABC..Z */
57 extern const char all_letters[];		/* abc..zABC..Z */
58 
59 
60 /*
61   Together, these classes define the constant properties of
62   the various menu classes.
63 
64   A menu consists of:
65    - menu_iter, which describes how to handle the type of "list" that's
66      being displayed as a menu
67    - a menu_skin, which describes the layout of the menu on the screen.
68    - various bits and bobs of other data (e.g. the actual list of entries)
69  */
70 struct menu;
71 
72 
73 
74 /*** Predefined menu "skins" ***/
75 
76 /**
77  * Types of predefined skins available.
78  */
79 typedef enum
80 {
81 	/*
82 	 * A simple list of actions with an associated name and id.
83 	 * Private data: an array of menu_action
84 	 */
85 	MN_ITER_ACTIONS = 1,
86 
87 	/*
88 	 * A list of strings to be selected from - no associated actions.
89 	 * Private data: an array of const char *
90 	 */
91 	MN_ITER_STRINGS = 2
92 } menu_iter_id;
93 
94 
95 /**
96  * Primitive menu item with bound action.
97  */
98 typedef struct
99 {
100 	int flags;
101 	char tag;
102 	const char *name;
103 	void (*action)(const char *title, int row);
104 } menu_action;
105 
106 
107 /**
108  * Flags for menu_actions.
109  */
110 #define MN_ACT_GRAYED     0x0001 /* Allows selection but no action */
111 #define MN_ACT_HIDDEN     0x0002 /* Row is hidden, but may be selected via tag */
112 
113 
114 /**
115  * Underlying function set for displaying lists in a certain kind of way.
116  */
117 typedef struct
118 {
119 	/* Returns menu item tag (optional) */
120 	char (*get_tag)(struct menu *menu, int oid);
121 
122 	/*
123 	 * Validity checker (optional--all rows are assumed valid if not present)
124  	 * Return values will be interpreted as: 0 = no, 1 = yes, 2 = hide.
125  	 */
126 	int (*valid_row)(struct menu *menu, int oid);
127 
128 	/* Displays a menu row */
129 	void (*display_row)(struct menu *menu, int oid, bool cursor,
130 			int row, int col, int width);
131 
132 	/* Handle 'positive' events (selections or cmd_keys) */
133 	/* XXX split out into a select handler and a cmd_key handler */
134 	bool (*row_handler)(struct menu *menu, const ui_event *event, int oid);
135 
136 	/* Called when the screen resizes */
137 	void (*resize)(struct menu *m);
138 } menu_iter;
139 
140 
141 
142 /*** Menu skins ***/
143 
144 /**
145  * Identifiers for the kind of layout to use
146  */
147 typedef enum
148 {
149 	MN_SKIN_SCROLL = 1,   /**< Ordinary scrollable single-column list */
150 	MN_SKIN_OBJECT = 2,   /**< Special single-column list for object choice */
151 	MN_SKIN_COLUMNS = 3   /**< Multicolumn view */
152 } skin_id;
153 
154 
155 /* Class functions for menu layout */
156 typedef struct
157 {
158 	/* Determines the cursor index given a (mouse) location */
159 	int (*get_cursor)(int row, int col, int n, int top, region *loc);
160 
161 	/* Displays the current list of visible menu items */
162 	void (*display_list)(struct menu *menu, int cursor, int *top, region *);
163 
164 	/* Specifies the relative menu item given the state of the menu */
165 	char (*get_tag)(struct menu *menu, int pos);
166 
167 	/* Process a direction */
168 	ui_event (*process_dir)(struct menu *menu, int dir);
169 } menu_skin;
170 
171 
172 
173 /*** Base menu structure ***/
174 
175 /**
176  * Flags for menu appearance & behaviour
177  */
178 enum
179 {
180 	/* Tags are associated with the view, not the element */
181 	MN_REL_TAGS = 0x01,
182 
183 	/* No tags -- movement key and mouse browsing only */
184 	MN_NO_TAGS = 0x02,
185 
186 	/* Tags to be generated by the display function */
187 	MN_PVT_TAGS = 0x04,
188 
189 	/* Tag selections can be made regardless of the case of the key pressed.
190 	 * i.e. 'a' activates the line tagged 'A'. */
191 	MN_CASELESS_TAGS = 0x08,
192 
193 	/* double tap (or keypress) for selection; single tap is cursor movement */
194 	MN_DBL_TAP = 0x10,
195 
196 	/* no select events to be triggered */
197 	MN_NO_ACTION = 0x20,
198 
199 	/* Tags can be selected via an inscription */
200 	MN_INSCRIP_TAGS = 0x40
201 };
202 
203 
204 /* Base menu type */
205 struct menu
206 {
207 	/** Public variables **/
208 	const char *header;
209 	const char *title;
210 	const char *prompt;
211 
212 	/* Keyboard shortcuts for menu selection-- shouldn't overlap cmd_keys */
213 	const char *selections;
214 
215 	/* Menu selections corresponding to inscriptions */
216 	char *inscriptions;
217 
218 	/* String of characters that when pressed, menu handler should be called */
219 	/* Mustn't overlap with 'selections' or some items may be unselectable */
220 	const char *cmd_keys;
221 
222 	/* String of characters that when pressed, return an EVT_SWITCH */
223 	/* Mustn't overlap with previous blah blah */
224 	const char *switch_keys;
225 
226   	/* auxiliary browser help function */
227 	void (*browse_hook)(int oid, void *db, const region *loc);
228 
229 	/* This is an auxiliary function to allow predefined skins to handle
230 	 * events for cmd_keys or switch_keys within menu_select() rather than
231 	 * have menu_select()'s caller handle them.  If used, the function
232 	 * should return true if the event, ev, was handled or false if it was
233 	 * not. oid is the index of the cursor position in the list. */
234 	bool (*keys_hook)(struct menu *m, const ui_event *ev, int oid);
235 
236 	/* Flags specifying the behavior of this menu (from struct menu_flags) */
237 	int flags;
238 
239 
240 	/** Private variables **/
241 
242 	/* Stored boundary, set by menu_layout().  This is used to calculate
243 	 * where the menu should be displayed on display & resize */
244 	region boundary;
245 
246 	int filter_count;        /* number of rows in current view */
247 	const int *filter_list;  /* optional filter (view) of menu objects */
248 
249 	int count;               /* number of rows in underlying data set */
250 	void *menu_data;         /* the data used to access rows. */
251 
252 	const menu_skin *skin;      /* menu display style functions */
253 	const menu_iter *row_funcs; /* menu skin functions */
254 
255 	/* State variables */
256 	int cursor;             /* Currently selected row */
257 	int top;                /* Position in list for partial display */
258 	region active;          /* Subregion actually active for selection */
259 	int cursor_x_offset;    /* Adjustment to the default position of the cursor on a line. */
260 };
261 
262 
263 
264 /*** Menu API ***/
265 
266 /**
267  * Allocate and return a new, initialised, menu.
268  */
269 struct menu *menu_new(skin_id, const menu_iter *iter);
270 struct menu *menu_new_action(menu_action *acts, size_t n);
271 void menu_free(struct menu *m);
272 
273 
274 /**
275  * Initialise a menu, using the skin and iter functions specified.
276  */
277 void menu_init(struct menu *menu, skin_id skin, const menu_iter *iter);
278 
279 
280 /**
281  * Given a predefined menu kind, return its iter functions.
282  */
283 const menu_iter *menu_find_iter(menu_iter_id iter_id);
284 
285 
286 /**
287  * Set menu private data and the number of menu items.
288  *
289  * Menu private data is then available from inside menu callbacks using
290  * menu_priv().
291  */
292 void menu_setpriv(struct menu *menu, int count, void *data);
293 
294 
295 /**
296  * Return menu private data, set with menu_setpriv().
297  */
298 void *menu_priv(struct menu *menu);
299 
300 
301 /*
302  * Set a filter on what items a menu can display.
303  *
304  * Use this if your menu private data has 100 items, but you want to choose
305  * which ones of those to display at any given time, e.g. in an inventory menu.
306  * object_list[] should be an array of indexes to display, and n should be its
307  * length.
308  */
309 void menu_set_filter(struct menu *menu, const int object_list[], int n);
310 
311 
312 /**
313  * Remove any filters set on a menu by menu_set_filer().
314  */
315 void menu_release_filter(struct menu *menu);
316 
317 
318 /**
319  * Ready a menu for display in the region specified.
320  *
321  * XXX not ready for dynamic resizing just yet
322  */
323 bool menu_layout(struct menu *menu, const region *loc);
324 
325 
326 /**
327  * Display a menu.
328  * If reset_screen is true, it will reset the screen to the previously saved
329  * state before displaying.
330  */
331 void menu_refresh(struct menu *menu, bool reset_screen);
332 
333 
334 /**
335  * Run a menu.
336  *
337  * 'notify' is a bitwise OR of ui_event_type events that you want to
338  * menu_select to return to you if they're not handled inside the menu loop.
339  * e.g. if you want to handle key events without specifying a menu_iter->handle
340  * function, you can set notify to EVT_KBRD, and any non-navigation keyboard
341  * events will stop the menu loop and return them to you.
342  *
343  * Some events are returned by default, and else are EVT_ESCAPE and EVT_SELECT.
344  *
345  * Event types that can be returned:
346  *   EVT_ESCAPE: no selection; go back (by default)
347  *   EVT_SELECT: menu->cursor is the selected menu item (by default)
348  *   EVT_MOVE:   the cursor has moved
349  *   EVT_KBRD:   unhandled keyboard events
350  *   EVT_MOUSE:  unhandled mouse events
351  *   EVT_RESIZE: resize events
352  *
353  * XXX remove 'notify'
354  *
355  * If popup is true, the screen background is saved before starting the menu,
356  * and restored before each redraw. This allows variably-sized information
357  * at the bottom of the menu.
358  */
359 ui_event menu_select(struct menu *menu, int notify, bool popup);
360 
361 /**
362  * Set the menu cursor to the next valid row.
363  */
364 void menu_ensure_cursor_valid(struct menu *m);
365 
366 
367 /* Interal menu stuff that cmd-know needs because it's quite horrible */
368 bool menu_handle_mouse(struct menu *menu, const ui_event *in, ui_event *out);
369 bool menu_handle_keypress(struct menu *menu, const ui_event *in, ui_event *out);
370 
371 /**
372  * Allow adjustment of the cursor's default x offset.
373  */
374 void menu_set_cursor_x_offset(struct menu *m, int offset);
375 
376 /*** Dynamic menu handling ***/
377 
378 struct menu *menu_dynamic_new(void);
379 void menu_dynamic_add(struct menu *m, const char *text, int value);
380 void menu_dynamic_add_valid(struct menu *m, const char *text, int value, menu_row_validity_t valid);
381 void menu_dynamic_add_label(struct menu *m, const char *text, const char label, int value, char *label_list);
382 void menu_dynamic_add_label_valid(struct menu *m, const char *text, const char label, int value, char *label_list, menu_row_validity_t valid);
383 size_t menu_dynamic_longest_entry(struct menu *m);
384 void menu_dynamic_calc_location(struct menu *m, int mx, int my);
385 int menu_dynamic_select(struct menu *m);
386 void menu_dynamic_free(struct menu *m);
387 
388 #endif /* INCLUDED_UI_MENU_H */
389