[e16e8f2] | 1 | Overview of writing code using the menu system |
---|
| 2 | ---------------------------------------------- |
---|
| 3 | |
---|
| 4 | This file contains implementation and developer documentation. |
---|
| 5 | For simple cases, you should start by using simple.c as a template. |
---|
| 6 | complex.c illustrates most of the features available in the menu system. |
---|
| 7 | |
---|
| 8 | Menu Features currently supported are: |
---|
| 9 | * menu items, |
---|
| 10 | * submenus, |
---|
| 11 | * disabled items, |
---|
| 12 | * checkboxes, |
---|
| 13 | * invisible items (useful for dynamic menus), and |
---|
| 14 | * Radio menus, |
---|
| 15 | * Context sensitive help |
---|
| 16 | * Authenticated users |
---|
| 17 | |
---|
| 18 | The keys used are: |
---|
| 19 | |
---|
| 20 | * Arrow Keys, PgUp, PgDn, Home, End Keys |
---|
| 21 | * Space to switch state of a checkbox |
---|
| 22 | * Enter to choose the item |
---|
| 23 | * Escape to exit from it |
---|
| 24 | * Shortcut keys |
---|
| 25 | |
---|
| 26 | 1. Overview |
---|
| 27 | ----------- |
---|
| 28 | |
---|
| 29 | The code usually consists of many stages. |
---|
| 30 | |
---|
| 31 | * Configuring the menusytem |
---|
| 32 | * Installing global handlers [optional] |
---|
| 33 | * Populating the menusystem |
---|
| 34 | * Executing the menusystem |
---|
| 35 | * Processing the result |
---|
| 36 | |
---|
| 37 | 1.1 Configuring the menusystem |
---|
| 38 | ------------------------------ |
---|
| 39 | This includes setting the window the menu system should use, |
---|
| 40 | the choice of colors, the title of the menu etc. In most functions |
---|
| 41 | calls, a value of -1 indicates that the default value be used. |
---|
| 42 | For details about what the arguments are look at function |
---|
| 43 | declarations in menu.h |
---|
| 44 | |
---|
| 45 | <code> |
---|
| 46 | // Choose the default title and setup default values for all attributes.... |
---|
| 47 | init_menusystem(NULL); |
---|
| 48 | set_window_size(1,1,23,78); // Leave one row/col border all around |
---|
| 49 | |
---|
| 50 | // Choose the default values for all attributes and char's |
---|
| 51 | // -1 means choose defaults (Actually the next 4 lines are not needed) |
---|
| 52 | set_normal_attr (-1,-1,-1,-1); |
---|
| 53 | set_status_info (-1,-1); |
---|
| 54 | set_title_info (-1,-1); |
---|
| 55 | set_misc_info(-1,-1,-1,-1); |
---|
| 56 | </code> |
---|
| 57 | |
---|
| 58 | 1.2 Populating the menusystem |
---|
| 59 | ----------------------------- |
---|
| 60 | This involves adding a menu to the system, and the options which |
---|
| 61 | should appear in the menu. An example is given below. |
---|
| 62 | |
---|
| 63 | <code> |
---|
| 64 | MAINMENU = add_menu(" Menu Title ",-1); |
---|
| 65 | CHECKED = 1; |
---|
| 66 | add_item("option1","Status 1",OPT_RUN,"kernel1 arg1=val1",0); |
---|
| 67 | add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); |
---|
| 68 | add_item("othermenu","Status 3",OPT_SUBMENU,"menuname",0); |
---|
| 69 | add_sep(); |
---|
| 70 | add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED); |
---|
| 71 | add_item("Exit ","Status String",OPT_EXITMENU,NULL,0); |
---|
| 72 | </code> |
---|
| 73 | |
---|
| 74 | The call to add_menu has two arguments, the first being the title of |
---|
| 75 | the menu and the second an upper bound on the number of items in the menu. |
---|
| 76 | Putting a -1, will use the default (see MENUSIZE in menu.h). If you try |
---|
| 77 | to add more items than specified, the extra items will not appear in |
---|
| 78 | the menu. The accuracy of this number affects the memory required |
---|
| 79 | to run the system. |
---|
| 80 | |
---|
| 81 | If you do not want to keep track of the return values, you can also use |
---|
| 82 | the following variant of add_menu |
---|
| 83 | |
---|
| 84 | <code> |
---|
| 85 | add_named_menu("main"," Menu Title ",-1) |
---|
| 86 | </code> |
---|
| 87 | |
---|
| 88 | This creates a new menu as before and gives it a name "main". When using named |
---|
| 89 | menus, you get an alternate way for adding submenu's. See below for details. |
---|
| 90 | |
---|
| 91 | The call to add_item has five arguments. |
---|
| 92 | The first argument is the text which appears in the menu itself. |
---|
| 93 | The second argument is the text displayed in the status line. |
---|
| 94 | The third argument indicates the type of this menuitem. It is one of |
---|
| 95 | the following |
---|
| 96 | |
---|
| 97 | * OPT_RUN : executable content |
---|
| 98 | * OPT_EXITMENU : exits menu to parent |
---|
| 99 | * OPT_SUBMENU : if selected, displays a submenu |
---|
| 100 | * OPT_CHECKBOX : associates a boolean with this item which can be toggled |
---|
| 101 | * OPT_RADIOMENU: associates this with a radio menu. |
---|
| 102 | After execution, the data field of this item will point |
---|
| 103 | to the option selected. |
---|
| 104 | * OPT_SEP : A menu seperator (visually divide menu into parts) |
---|
| 105 | * OPT_RADIOITEM: this item is one of the options in a RADIOMENU |
---|
| 106 | * OPT_INACTIVE : A disabled item (user cannot select this) |
---|
| 107 | * OPT_INVISIBLE: This item will not be displayed. |
---|
| 108 | |
---|
| 109 | The fourth argument is the value of the data field always a string. |
---|
| 110 | Usually this string is just copied and nothing is done with it. Two |
---|
| 111 | cases, where it is used. |
---|
| 112 | |
---|
| 113 | In case of a radiomenu the input string is ignored and the "data" field |
---|
| 114 | points to the menuitem chosen (Dont forget to typecast this pointer to |
---|
| 115 | (t_menuitem *) when reading this info). |
---|
| 116 | |
---|
| 117 | In case of a submenu, this string if non-trivial is interpreted as the |
---|
| 118 | name of the submenu which should be linked there. This interpretation |
---|
| 119 | happens when the menu is first run and not when the menu system is being |
---|
| 120 | created. This allows the user to create the menusystem in an arbitrary |
---|
| 121 | order. |
---|
| 122 | |
---|
| 123 | |
---|
| 124 | The fifth argument is a number whose meaning depends on the type of the |
---|
| 125 | item. For a CHECKBOX it should be 0/1 setting the initial state of the |
---|
| 126 | checkbox. For a SUBMENU it should be the index of the menu which should |
---|
| 127 | be displayed if this option is chosen. Incase the data field is non-trivial, |
---|
| 128 | this number is ignored and computed later. For a RADIOMENU it should be the |
---|
| 129 | index of the menu which contains all the options (All items in that menu |
---|
| 130 | not of type RADIOITEM are ignored). For all other types, this |
---|
| 131 | argument has no meaning at all. |
---|
| 132 | |
---|
| 133 | A call to add_sep is a convenient shorthand for calling add_item |
---|
| 134 | with the type set to OPT_SEP. |
---|
| 135 | |
---|
| 136 | 1.3 Executing the menusystem |
---|
| 137 | ---------------------------- |
---|
| 138 | This is the simplest of all. Just call showmenus, with the index |
---|
| 139 | of the main menu as its argument. It returns a pointer to the menu |
---|
| 140 | item which was selected by the user. |
---|
| 141 | |
---|
| 142 | <code> |
---|
| 143 | choice = showmenus(MAIN); // Initial menu is the one with index MAIN |
---|
| 144 | // or choice = showmenus(find_menu_num("main")); // Initial menu is the one named "main" |
---|
| 145 | </code> |
---|
| 146 | |
---|
| 147 | 1.4 Processing the result |
---|
| 148 | ------------------------- |
---|
| 149 | This pointer will either be NULL (user hit Escape) or always point |
---|
| 150 | to a menuitem which can be "executed", i.e. it will be of type OPT_RUN. |
---|
| 151 | Usually at this point, all we need to do is to ask syslinux to run |
---|
| 152 | the command associated with this menuitem. The following code executes |
---|
| 153 | the command stored in choice->data (there is no other use for the data |
---|
| 154 | field, except for radiomenu's) |
---|
| 155 | |
---|
| 156 | <code> |
---|
| 157 | if (choice) |
---|
| 158 | { |
---|
| 159 | if (choice->action == OPT_RUN) |
---|
| 160 | { |
---|
| 161 | if (syslinux) runcommand(choice->data); |
---|
| 162 | else csprint(choice->data,0x07); |
---|
| 163 | return 1; |
---|
| 164 | } |
---|
| 165 | csprint("Error in programming!",0x07); |
---|
| 166 | } |
---|
| 167 | </code> |
---|
| 168 | |
---|
| 169 | 2. Advanced features |
---|
| 170 | -------------------- |
---|
| 171 | Everycall to add_item actually returns a pointer to the menuitem |
---|
| 172 | created. This can be useful when using any of the advanced features. |
---|
| 173 | |
---|
| 174 | 2.1 extra_data |
---|
| 175 | -------------- |
---|
| 176 | For example, every menuitem has an "extra_data" field (a pointer) |
---|
| 177 | which the user can use to point any data he/she pleases. The menusystem |
---|
| 178 | itself does not use this field in anyway. |
---|
| 179 | |
---|
| 180 | 2.2 helpid |
---|
| 181 | ---------- |
---|
| 182 | Every item also has a field called "helpid". It is meant to hold some |
---|
| 183 | kind of identifier which can be referenced and used to generate |
---|
| 184 | a context sensitive help system. This can be set after a call to |
---|
| 185 | add_item as follows |
---|
| 186 | <code> |
---|
| 187 | add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU); |
---|
| 188 | set_item_options('A',4516); |
---|
| 189 | </code> |
---|
| 190 | |
---|
| 191 | The first is the shortcut key for this entry. You can put -1 to ensure |
---|
| 192 | that the shortcut key is not reset. The second is some unsigned integer. |
---|
| 193 | If this value is 0xFFFF, then the helpid is not changed. |
---|
| 194 | |
---|
| 195 | 2.3 Installing global handlers |
---|
| 196 | ------------------------------ |
---|
| 197 | It is possible to register handlers for the menu system. These are |
---|
| 198 | user functions which are called by the menusystem in certain |
---|
| 199 | situations. Usually the handlers get a pointer to the menusystem |
---|
| 200 | datastructure as well as a pointer to the current item selected. |
---|
| 201 | Some handlers may get additional information. Some handlers are |
---|
| 202 | required to return values while others are not required to do so. |
---|
| 203 | |
---|
| 204 | Currently the menusystem support three types of global handlers |
---|
| 205 | * timeout handler |
---|
| 206 | * screen handler |
---|
| 207 | * keys handler |
---|
| 208 | |
---|
| 209 | 2.3.1 timeout handler |
---|
| 210 | --------------------- |
---|
| 211 | This is installed using a call to "reg_ontimeout(fn,numsteps,stepsize)" |
---|
| 212 | function. fn is a pointer to a function which takes no arguments and |
---|
| 213 | returns one of CODE_WAIT, CODE_ENTER, CODE_ESCAPE. This function is |
---|
| 214 | called when numsteps*stepsize Centiseconds have gone by without any |
---|
| 215 | user input. If the function returns CODE_WAIT then the menusystem |
---|
| 216 | waits for user input (for another numsteps*stepsize Centiseconds). If |
---|
| 217 | CODE_ENTER or CODE_ESCAPE is returned, then the system pretends that |
---|
| 218 | the user hit ENTER or ESCAPE on the keyboard and acts accordingly. |
---|
| 219 | |
---|
| 220 | 2.3.2 Screen handler |
---|
| 221 | -------------------- |
---|
| 222 | This is installed using a call to "reg_handler(HDLR_SCREEN,fn)". fn is |
---|
| 223 | a pointer to a function which takes a pointer to the menusystem |
---|
| 224 | datastructure and the current item selected and returns nothing. |
---|
| 225 | This is called everytime a menu is drawn (i.e. everytime user changes |
---|
| 226 | the current selection). This is meant for displaying any additional |
---|
| 227 | information which reflects the current state of the system. |
---|
| 228 | |
---|
| 229 | 2.3.3 Keys handler |
---|
| 230 | ------------------ |
---|
| 231 | This is installed using a call to "reg_handler(HDLR_KEYS,fn)". fn is |
---|
| 232 | a pointer to a function which takes a pointer to the menusystem |
---|
| 233 | datastructure, the current item and the scan code of a key and returns |
---|
| 234 | nothing. This function is called when the user presses a key which |
---|
| 235 | the menusystem does not know to dealwith. In any case, when this call |
---|
| 236 | returns the screen should not have changed in any way. Usually, |
---|
| 237 | one can change the active page and display any output needed and |
---|
| 238 | reset the active page when you return from this call. |
---|
| 239 | |
---|
| 240 | complex.c implements a key_handler, which implements a simple |
---|
| 241 | context sensitive help system, by displaying the contents of a |
---|
| 242 | file whose name is based on the helpid of the active item. |
---|
| 243 | |
---|
| 244 | Also, complex.c's handler allows certain users to make changes |
---|
| 245 | to edit the commands associated with a menu item. |
---|
| 246 | |
---|
| 247 | 2.4 Installing item level handlers |
---|
| 248 | ---------------------------------- |
---|
| 249 | In addition to global handlers, one can also install handlers for each |
---|
| 250 | individual item. A handler for an individual item is a function which |
---|
| 251 | takes a pointer to the menusystem datastructure and a pointer to the |
---|
| 252 | current item and return a structure of type t_handler_return. Currently |
---|
| 253 | it has two bit fields "valid" and "refresh". |
---|
| 254 | |
---|
| 255 | This handler is called when the user hits "enter" on a RUN item, or |
---|
| 256 | changes the status of a CHECKBOX, or called *after* a radio menu choice |
---|
| 257 | has been set. In all other cases, installing a handler has no effect. |
---|
| 258 | |
---|
| 259 | The handler can change any of the internal datastructures it pleases. |
---|
| 260 | For e.g. in a radiomenu handler, one can change the text displayed |
---|
| 261 | on the menuitem depending on which choice was selected (see complex.c |
---|
| 262 | for an example). The return values are ignored for RADIOMENU's. |
---|
| 263 | |
---|
| 264 | In case of RUN items: the return values are used as follows. If the |
---|
| 265 | return value of "valid" was false, then this user choice is ignored. |
---|
| 266 | This is useful if the handler has useful side effects. For e.g. |
---|
| 267 | complex.c has a Login item, whose handler always return INVALID. It |
---|
| 268 | sets a global variable to the name of the user logged in, and enables |
---|
| 269 | some menu items, and makes some invisible items visible. |
---|
| 270 | |
---|
| 271 | * If the handler does not change the visibility status of any items, |
---|
| 272 | the handler should set "refresh" to 0. |
---|
| 273 | * If the handler changes the visibility status of items in the current |
---|
| 274 | menu set "refresh" to 1. |
---|
| 275 | * If you are changing the visibility status of items in menu's currently |
---|
| 276 | not displayed, then you can set "refresh" to 0. |
---|
| 277 | * Changing the visibility status of items in another menu |
---|
| 278 | which is currently displayed, is not supported. If you do it, |
---|
| 279 | the screen contents may not reflect the change until you get to the |
---|
| 280 | menu which was changed. When you do get to that menu, you may notice |
---|
| 281 | pieces of the old menu still on the screen. |
---|
| 282 | |
---|
| 283 | In case of CHECKBOXES: the return value of "valid" is ignored. Because, |
---|
| 284 | the handler can change the value of checkbox if the user selected value |
---|
| 285 | is not appropriate. only the value of "refresh" is honored. In this case |
---|
| 286 | all the caveats in the previous paragraph apply. |
---|
| 287 | |
---|
| 288 | menu.h defines two instances of t_handler_return |
---|
| 289 | ACTION_VALID and ACTION_INVALID for common use. These set the valid flag |
---|
| 290 | to 1 and 0 respectively and the refresh flag to 0. |
---|
| 291 | |
---|
| 292 | 3. Things to look out for |
---|
| 293 | ------------------------- |
---|
| 294 | When you define the menu system, always declare it in the opposite |
---|
| 295 | order, i.e. all lower level menu's should be defined before the higher |
---|
| 296 | level menus. This is because in order to define the MAINMENU, you need |
---|
| 297 | to know the index assigned to all its submenus. |
---|
| 298 | |
---|
| 299 | 4. Additional Modules |
---|
| 300 | --------------------- |
---|
| 301 | You can make use of the following additional modules, in writing your |
---|
| 302 | handlers. |
---|
| 303 | |
---|
| 304 | * Passwords |
---|
| 305 | * Help |
---|
| 306 | |
---|
| 307 | 4.1 Passwords |
---|
| 308 | ------------- |
---|
| 309 | This module was written by Th. Gebhardt. This is basically a modification |
---|
| 310 | of the DES crypt function obtained by removing the dependence of the |
---|
| 311 | original crypt function on C libraries. The following functions are |
---|
| 312 | defined |
---|
| 313 | |
---|
| 314 | init_passwords(PWDFILE) |
---|
| 315 | // Read in the password database from the file |
---|
| 316 | authenticate_user(user,pwd) |
---|
| 317 | // Checks if user,pwd is valid |
---|
| 318 | isallowed(user,perm) |
---|
| 319 | // Checks if the user has a specified permission |
---|
| 320 | close_passwords() |
---|
| 321 | // Unloads password database from memory |
---|
| 322 | |
---|
| 323 | See the sample password file for more details about the file format |
---|
| 324 | and the implementation of permissions. |
---|
| 325 | |
---|
| 326 | See complex.c for a example of how to use this. |
---|
| 327 | |
---|
| 328 | 4.2 Help |
---|
| 329 | -------- |
---|
| 330 | This can be used to set up a context sensitive help system. The following |
---|
| 331 | functions are defined |
---|
| 332 | |
---|
| 333 | init_help(HELPBASEDIR) |
---|
| 334 | // Initialises the help system. All help files will be loaded |
---|
| 335 | // from the directory specified. |
---|
| 336 | runhelpsystem(context) |
---|
| 337 | // Displays the contents of HELPBASEDIR/hlp<context>.txt |
---|
| 338 | |
---|
| 339 | In order to have a functioning help system, you just need to create |
---|
| 340 | the hlp<NNNNN>.txt files and initialize the help system by specifying |
---|
| 341 | the base directory. |
---|
| 342 | |
---|
| 343 | The first line of this file assumed to be the title of the help screen. |
---|
| 344 | You can use ^N and ^O to change attributes absolutely and relatively, |
---|
| 345 | i.e. [^O]46 (i.e. Ctrl-O followed by chars 4 and 6) will set the |
---|
| 346 | attribute to 46, while [^N]08 will XOR the current attribute with |
---|
| 347 | specified number, thus in this case the first [^N]08 will turn on |
---|
| 348 | highlighting and the second one will turn it off. |
---|