; A 386 MENU definition is a sequence of menu entries (read bytes and dwords) ; these data structure will evolve from release to release ; but will always be backward compatible. ; ; MENU DATA IS BYTE ALIGNED ; (remember to write ALIGN BYTE before every menu definition!!!)] ; ; Every menu entry is defined as: ; a FOUR BYTES HEADER (four bytes into a DWORD!!!!!!) containing ; the menu_type byte plus other three bytes with optional informations ; (usually column positions and input field lenght) ; ; after those mandatory four bytes, there are one or more DWORDS ; with data depending on the menu type. ; (usually these dwords are offsets pointing to actual data) ; ; The FIRST menu entry must be of M_HEADER type (the menu title) ; and the LAST must be of M_END type ( the end of menu marker plus ; pointers to optional text). ; ; So a menu will always look like: ; ; MENU TITLE ; -> entry 1 entry_value ; entry 2 entry_value ; ...... ; entry n entry_value ; EXPLANATORY TEXT (optional) ; ; the M_HEADER contains a field containing the maximum "menu width" ; expressed in characters, so the menu handling software can decide ; on the flight what character size it can use. ; The menu height in character depend on how many entries there are ; and how many lines of "explanatory text" are present in the ; M_END entry. ; ; YOU CAN TRUST A MAXIMUM WIDTH OF 38 CHARACTERS IS ALWAYS POSSIBLE ; AND A MAXIMUM HEIGHT OF 25 LINES, DO NOT EXCEED THIS. ; BECAUSE OF THE 25 LINES OF TEXT LIMIT ; THERE CAN BE UP TO (22 - LINES_OF_ENDING_TEXT) MENU ENTRIES. ; (there is at least an interline between title, entries and ending text) ; As a rule of thumb, better do not exceed 10 menu entries and 5 lines of ; ending text. ; And now, more explanations.. ; ; The following menu entries are described using this layout: ; ENTRY_NAME ENTRY_TEXT ENTRY_VALUE COMMENTS ; ; ENTRY_DEFINITION ; ; EXTRA DESCRIPTIONS ; ; Header: text menu title ; ; db M_HEADER,t_col,maxwidth,touchngo ; dd text_p,x,y ; ; x,y = initial position IN PIXELS of the upper left border ; of this menu, or -1,-1 if the menu manager can freely choose ; where popup these. ; N.B. if x,y are out of range or the menu manager supports ; popup menu repositioning, these values will be ; modified by the menu manager. ; t_col = column position of entry name ; text_p = code32 offset to asciiz string to show starting from ; t_col column. ; maxwidth = maximum menu width in characters ; touchngo: 0 = only ESC or selection of an "exit" entry will end this menu ; 1 = AFTER the fisrt selection of an entry this menu will end ; (useful to implement "save game" or "load game" menu) ; Bar: text <-]#############[+> a "volume level" bar ; ; db M_BAR,t_col,in_col,in_len ; dd text_p, value_p, func_p, min, max, step ; ; in_col = colum position of the "volume level bar" ; starting with the <-] character ; in_len = lenght of the "volume bar" (excluding the <-] and [+> characters) ; value_p = code32 offset to the variable containing the value to show/set ; min = minimum allowed value ; max = maximum allowed value ; func_p = code32 offset of function to call every time the entry value ; is altered (use this for value checking/correction ; or to trigger special actions depending on the value ) ; Function parameters: ; in: ; Segment registers pointing to the usual 386P segments. ; EAX = value "requested by user" ; to set into the variable pointed by value_p ; out: ; EAX = ALLOWED value to store into the variable ; (the menu manager will store it properly) ; IF carry set THEN ; "refresh" completely this menu ; (useful to show messages) ; END IF ; All other registers preserved. ; ; step = increment/decrement step for the variable pointed by value_p ; ; Int: text <-]_____________[+> a 32bit integer value ; ; db M_INT,t_col,in_col,idigits ; dd text_p, value_p, func_p, min, max, step ; ; idigits = maximum number of digits including optional sign character ; ; Unsigned: text <-]_____________[+> a 32bit dword value ; ; db M_UNSIGNED,t_col,in_col,udigits ; dd text_p, value_p, func_p, min, max, step ; ; udigits = maximum number of digits (and no sign) ; ; Pick_list: text <-]_____________[+> choose from a list ; ; db M_PICK,t_col,in_col,max_item_len ; dd text_p, value_p, func_p, picklist_p, picktop ; ; max_item_len = maximum lenght in characters of the strings ; pointed by the "pick list" table ; (EVERY STRING pointed by the picklist must have this ; lenght (ecluding the final NUL). ; value_p = pointer to a dword with values ranging ; from 0 (for the first picklist string) ; to picktop-1 (for the last picklist string). ; picklist_p = pointer to a list of pointers (all code32 offsets) ; to strings describing the "values" you can choose ; i.e: if piclist_p contains offset choose_level ; and picktop contains 5 ; and max_item_len contains 28 ; somewere there will be: ; ; choose_level dd offset easy ; 0 ; dd offset normal ; 1 ; dd offset hard ; 2 ; dd offset very_hard ; 3 ; dd offset impossible ; 4 ; ; easy db 'KINDERGARDEN MODE ',0 ; normal db 'NOT A PROBLEM ',0 ; hard db 'GOOD ENOUGH ',0 ; very_hard db 'TOUGH ENOUGH! ',0 ; impossible db 'BAD,UGLY AND DANGEROUS!',0 ; ; ; String: text _____________ string entry ; ; db M_STRING,t_col,in_col,max_string_characters ; dd text_p, value_p, sfunc_p, ; ; sfunc_p == same parameter convention as into bar entries but remember ; this time the value passed is a POINTER. ; (so you can't change it, but you can change the bytes ; pointed by it) ; ; Submenu: text call a submenu ; ; db M_MENU,t_col,thru,m_disable ; dd text_p, menu_p ; ; menu_p = code32 offset of M_HEADER entry of menu to call ; when this entry is clicked. ; thru : 0 = when returning, reactivate this menu and refresh screen ; 1 = when returning, quit this menu automatically. ; m_disable: 0= this submenu can be activated ; 1= submenu disabled ; ; Call: text call a subroutine ; ; db M_CALL,t_col,thru,0 ; dd text_p, procedure_p ; ; procedure_p = code32 offset of code to call ; when this entry is clicked. ; The function assumes cs=_SelCode, ds=es=ss=fs=_SelData ; gs=_SelZero, like the _PopMenu procedure. ; The called procedure must preserve all registers. ; ; Toggle: [] text boolean entry ; ; db M_TOGGLE,t_col,flag_col,0 ; dd text_p, bool_p, func_p, ; ; flag_col = column position of '[]' on/off character ; bool_p = pointer to BYTE that can be toggled to 0 or to 1 ; when clicking on this entry. ; ; Key: text keytext keyboard key value ; ; db M_KEY,t_col,key_col,0 ; dd text_p, key_p, func_p ; ; key_col = column position of TEXT (obtained from _KeyNames) ; describing the key. ; key_p = pointer to BYTE that contains the key code ; func_p = pointer to function the menu system will call ; to check if the selected character is correct ; (example: ; in a keyboard-emulated joystick setup routine ; you want different characters for every ; "direction" or "button") ; in: eax = character code ; out: eax = allowed code ; ( 0 if you want make the user retry ; with another key ) ; IF (CARRY SET) AND (EAX!=0) THEN ; refresh all the displayed data ; Exit: text "exit from this menu" ; ; db M_EXIT,t_col,0,0 ; dd exit_text_p ; ; exit_text_p = pointer to the entry name ; (for example: 'CONTINUE GAME',0) ; ; End: etext end menu marker ; etext with optional text ; .... ; etext ; ; db M_END,t_col,t_lines,0 ; dd etext_p ; ; t_lines = lines of text/string count of strings pointed by etext_p ; ; etext_p = pointer to a table of pointers to asciiz text strings ; to show on the bottom of the menu ; if ( etext_p == 0 ) then no text ; For example: ; if etext_p contains offset menu_usage ; and t_lines contains 4 ; and there is: ; ; menu_usage dd e0,e1,e2,e3,e4,e5 ; ; e0 db ' HOW',0 ; e1 db ' MANY',0 ; e2 db ' LINES',0 ; e3 db 'YOU',0 ; e4 db 'WILL',0 ; e5 db ' SEE?',0 ; ; You will see on the bottom of the menu: ; HOW ; MANY ; LINES ; YOU ; ; (the other strings are not displayed) ; YOU CAN WRITE on the "ending text strings" ; (or simply you can change the pointers into the table) ; to display new messages or show "non alterable" info. ; (use the func_p entries to check entry values and change the ending text ; according on what happened). You may wonder why i used pointers (actually 32bit offsets) to variables and text instead of embedding 'em into the menu. The reason is quite simple, using offsets you can "bolt on" a menu "above" existing code, and LET THE MENU TEXT SELF-CONFIGURE (more on this later into INTERNATIONAL.TXT ). Another thing you have to remember is that the menu definition must be backward compatible, and that the MENU HANDLING MODULE may change!!!! The current 386menu module is designed for 320x200 screens but if you want, you can make a menu handler for 80x25 text screens or for svga screen resolutions. The current 386menu module will work with any video mode with 320x200 resolution or higher, but on higher resolutions it will usually appear in the upper left corner with tiny characters (if you want something fancier, code it).