;** ;** BRIEF -- Basic Reconfigurable Interactive Editing Facility ;** ;** Written by Dave Nanian and Michael Strickman. ;** ;** help.m: ;** ;** This macro contains the BRIEF help system. Display of menus and the like ;** is handled by the BRIEF dialog manager. ;** #include "dialog.h" #define FIRST_MENU_LINE 3 #define FIRST_MENU_COL 20 (extern to_top add_to_path ) ;** ;** help: ;** ;** This macro is used as the main help command. It's called when ;** the user presses Alt-h. ;** (macro help ( (int _user_kbd) (global _user_kbd) (= _user_kbd (inq_keyboard)) (process_help_menu "Help Menu" "help.mnu") ) ) ;** ;** _context_help: ;** ;** This macro is used as the "help" registered macro. It is called ;** when a prompt is displayed on the status line and the user presses ;** Alt-h. Write a replacement macro if you want your own help to be ;** be available for your own commands. The macro should check if the ;** last command is one of your macros, and if so call display_help ;** with the name of your help file; if not, just call _context_help ;** (so that all replacement macros are eventually called). ;** (macro _context_help ( (= _user_kbd (inq_keyboard)) (display_help (inq_command)) ) ) ;** ;** process_help_menu: ;** ;** This macro takes four parameters: the buffer name, file name, ;** height and width of the menu. It sets things up and calls the ;** dialog manager to deal with the actual display and manipulation of ;** the menus. (If height & width are omitted, menu is sized ;** automatically based on the contents of the menu buffer.) ;** (macro process_help_menu ( (string buf_name file_name ) (int height width startline startcol ) (get_parm 0 buf_name) (get_parm 1 file_name) (get_parm 2 height) (get_parm 3 width) ;** ;** Successive menus are offset by a constant amount from the ;** first one. The dialog manager automatically keeps track of ;** the current menu level. Note that if height and width are ;** omitted, height == startline and width == startcol. ;** (+= height (= startline (+ FIRST_MENU_LINE _dialog_level))) (+= width (= startcol (+ FIRST_MENU_COL (* _dialog_level 2)))) ;** ;** Here we call the dialog manager to create the help menu. ;** Whenever an interesting event occurs, the dialog manager will ;** call process_help_event. ;** ;** Note that process_help_event function may call this ;** routine to display an additional menu. ;** (_process_menu startcol height width startline buf_name "Select a Category" file_name NULL "process_help_event" TRUE) (returns TRUE) ) ) ;** ;** process_help_event: ;** ;** Action macro called by the dialog manager. Used to add buttons ;** to the menu or handle picking from the menu. ;** (macro process_help_event ( (int key) (string action) (get_parm 0 key) ;** If a menu button was picked, we parse the action off ;** the menu button and execute it. (if (== key DIALOG_PICK_MENU) ( (get_parm 2 action) (execute_macro (substr action (+ (index action ";") 1))) ) ;else (if (== key DIALOG_CREATE_MENU) ( (get_parm 2 action) (_help_add_button action) ) ) ) (returns TRUE) ) ) ;** ;** display_help: ;** ;** display_help takes a help keyword and displays the appropriate ;** help information in an overlapping window. It uses the global ;** variable _dialog_level to tie the grey - and Esc keystrokes in ;** with the rest of the menu package (grey - will remove the window, ;** and Esc will remove windows until the _dialog_level is 0). ;** ;** The optional second parameter is the name of the help file. ;** (macro display_help ( (int orig_buffer file_buffer ) (string topic commands ) (= commands "help.txt") (get_parm 1 commands) (if (= file_buffer (create_buffer "Help File" (add_to_path _dialog_dir commands) 1)) ( (get_parm 0 topic) (message "Locating help text...") (= orig_buffer (inq_buffer)) (set_buffer file_buffer) (tabs 3) (if (|| (search_fwd (+ (+ "\xc" topic) "\xc")) (search_back (+ (+ "\xc" topic) "\xc"))) ( (int loc) (message "Help display for %s." topic) (if (= loc (index (= commands (read)) "\xc\"")) (= commands (substr commands (+ loc 1) (- (strlen commands) (+ loc 2)))) ;else (= commands "") ) (beginning_of_line) (down) (if (== (inq_called) "_context_help") (create_window 2 21 76 2 " for assignment, or to exit help") ;else (create_window 2 21 76 2 " for menu, for assignment, to exit help") ) (attach_buffer file_buffer) (keyboard_push) (assign_to_key "" "_exit") (assign_to_key "" "_help_exit") (assign_to_key "" "_help_up") (assign_to_key "" "_help_down") (assign_to_key "" (+ "_help_assignment " commands)) (refresh) (process) (keyboard_pop) (delete_window) (search_back (+ (+ "\xc" topic) "\xc")) (beginning_of_line) ) ;else (error "No help available for %s." topic) ) (set_buffer orig_buffer) ) ;else (error "Help file not found.") ) ) ) ;** ;** _help_down: ;** ;** _help_down is called when the PgDn key is pressed: it ensures that ;** the user does not go past the end of the help file. Since the command ;** name begins with an underscore, the current command is not reassigned. ;** (macro _help_down ( (int line col old_line old_col ) (inq_position old_line old_col) (search_fwd "\xc") (inq_position line col) (move_abs old_line old_col) (page_down) (if (<= (- line old_line) 18) (move_abs old_line old_col) ) ) ) ;** ;** _help_up: ;** ;** Goes up a page in the help file. Since the command name begins ;** with an underscore, the current command is not reassigned. ;** (macro _help_up ( (int line col old_line old_col ) (inq_position old_line old_col) (search_back "\xc") (inq_position line col) (move_abs old_line old_col) (page_up) (if (<= (- old_line line) 18) (move_abs old_line old_col) ) ) ) ;** ;** key_specific_help: ;** ;** Gets help for the user using the keys, not the menus. ;** (macro key_specific_help ( (int saved_level key_value ) (string sequence assignment ) ;** ;** The dialog level is saved and restored when we enter and exit ;** key-specific help. During execution, we set the _dialog_level to ;** 0; a press of Esc will then only remove the help screen. ;** ;** If this wasn't done, extra "exit" calls would be done, and ;** the next time a window came up it would be removed immediately. ;** (= saved_level _dialog_level) (= _dialog_level 0) (keyboard_push _user_kbd) (while (!= key_value (key_to_int "")) ( (message "Press the key you want help on, to exit.") (while (== (= key_value (read_char)) -1)) (sprintf sequence "#%u" key_value) ;** ;** If the key assignment we have obtained is ambiguous, we keep ;** appending additional key assignments to it until we find a ;** command (or fail). ;** (while (== (= assignment (inq_assignment sequence)) "ambiguous") ( (message "Press next key in sequence, to exit.") (while (== (= key_value (read_char)) -1)) (if (== key_value (key_to_int "")) (break) ) (sprintf sequence "%s#%u" sequence key_value) ) ) (if (== key_value (key_to_int "")) (break) ) (display_help assignment) ) ) (= _dialog_level saved_level) (keyboard_pop 1) (message "") ) ) ;** ;** _help_assignment: ;** ;** This macro takes a command name as a parameter, creates a window ;** and displays the keys assigned to that command. ;** (macro _help_assignment ( (string commands this_command keys ) (int old_buf key_buf loc comma_loc semi_loc key_read have_assignment ) (get_parm 0 commands) (keyboard_push _user_kbd) (= old_buf (inq_buffer)) (set_buffer (= key_buf (create_buffer "Keys" NULL 1))) (tabs 4) (while (strlen commands) ( (if (&& semi_loc (|| (< semi_loc comma_loc) (! comma_loc))) (insert "\n\nSee also:\n") ) (= comma_loc (index commands ",")) (= semi_loc (index commands ";")) (if (&& semi_loc (|| (< semi_loc comma_loc) (! comma_loc))) (= loc semi_loc) ;else (= loc comma_loc) ) (if loc ( (= this_command (substr commands 1 (- loc 1))) (= commands (substr commands (+ loc 1))) ) ;else ( (= this_command commands) (= commands "") ) ) (if (!= this_command "") ( (++ have_assignment) (if (== (= keys (inq_assignment this_command 1)) "") (= keys (+ (+ (inq_assignment "execute_macro" 1) "<-and> ") this_command)) ) (insert (+ (+ "\n \"" this_command) "\" is assigned to:\n\t\t")) (while (= loc (index keys "<-")) ( (insert (substr keys 1 (- loc 1))) (= keys (substr keys loc)) (if (= loc (index keys "<-and>")) (= keys (substr keys (+ loc 6))) ;else (if (= loc (index keys "<-also>")) ( (insert "\n\t\t") (= keys (substr keys (+ loc 7))) ) ;else ( (= keys "") (break) ) ) ) ) ) (insert (+ keys "\n")) ) ) ) ) ;** ;** If any assignments were found, we display them in a window. ;** (if have_assignment ( (keyboard_push) (assign_to_key "" "_exit") (assign_to_key "" "_exit") (assign_to_key "" "_assign_up") (assign_to_key "" "_assign_down") (top_of_buffer) (create_window 6 15 72 4 " or to exit, or to scroll") (attach_buffer key_buf) (refresh) (process) (keyboard_pop) (delete_window) ) ) (if (! have_assignment) (beep) ) (delete_buffer key_buf) (set_buffer old_buf) (keyboard_pop 1) ) ) (macro _assign_up (page_up) ) (macro _assign_down ( (page_down) (move_rel (* (inq_position) -1)) ) ) ;** ;** _help_exit: ;** ;** Exits from the help system; calls exit to remove the help ;** window, and pushes back an if the dialog manager is active ;** to remove the other (menu) windows. ;** (macro _help_exit ( (if _dialog_level (push_back (key_to_int "")) ) (exit) ) ) ;** ;** _help_add_button: ;** ;** Used to add buttons to existing menus. This macro does nothing, ;** but you can write a replacement macro for it that checks the only ;** parameter (the buffer name) and adds buttons. When your replacement ;** macro is called, the menu buffer will be current and the menu will ;** be unformatted (just as it is on disk). ;** Make sure your replacement calls _help_add_button so that all ;** other replacement macros eventually get called. ;** (macro _help_add_button (returns TRUE) )