home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w055 / 4.ddi / SOURCES.LIF / HISTORY.PEL < prev    next >
Encoding:
Text File  |  1990-09-27  |  24.1 KB  |  1,010 lines

  1. # $Header:   P:/source/ppee/macros/history.pev   1.106   24 Sep 1990 17:25:02   skipr  $
  2.  
  3. ##############################################################################
  4. #
  5. #           Sage Software - POLYTRON Division
  6. #             1700 NW 167th Place
  7. #               Beaverton, OR 97006
  8. #
  9. #   Copyright 1990, Sage Software, Inc.
  10. #
  11. #   Permission is hereby granted for licensed users of Sage Professional
  12. #   Editor and PolyAwk to copy and modify this source code for their own
  13. #   personal use.  These derivative works may be distributed only to other
  14. #   licensed Sage Professional Editor and PolyAwk users.  All other usage
  15. #   is prohibited without express written permission from Sage Software.
  16. #
  17. ##############################################################################
  18.  
  19. #### $Workfile:   history.pel  $: Response history support
  20.  
  21.  
  22. ## local variables
  23. #
  24. local    FIELD_SIZE = 14        # width of the directory window
  25. local    saveBuffer
  26. local    saveWindow
  27. local    ALT_H = 0x2300
  28. local    ALT_K = 0x2500
  29. local    ALT_L = 0x2600
  30.  
  31. local    historyArray
  32. local    historyName
  33. local    historyElement
  34. local   historyPromptString  # current prompt string displayed by prompt_history
  35.  
  36. #------------------------------------------------------------------#
  37.  
  38. global    edit_file_dir    # set to 1 to display dir list from edit_file_key()
  39.  
  40. ##    prompt_history()
  41. #
  42. # Prompt the user for a string and process all illegally typed characters
  43. # through the _bapPromptKey() function.  The parameters passed are as
  44. # follows:
  45. #
  46. #    index     - a string identifying which history stack to use
  47. #    promptstr - first parameter to prompt()
  48. #    defaultstr- second parameter to prompt()
  49. #    usehistory- if defaultstr == "" and usehistory == 1, use the
  50. #            last history item
  51. #
  52. # Example:
  53. #    prompt_history( "SEARCH", "Search for: ", "noname" )
  54. #
  55. #    Each time this is called an a valid input string is entered
  56. #    and returned by prompt(), it is added to the history stack for
  57. #    "SEARCH" and subsequent calls can access this stack.
  58. #
  59. global function prompt_history( index, promptstr, defaultstr, usehistory ) {
  60.     local    patt;
  61.     local    i = 0;
  62.     local    id = function_id( "_bad_prompt_key" );
  63.  
  64.     if (!(index i in historyArray))
  65.         historyArray[ index i ] = i;
  66.  
  67.     #
  68.     # install an event handler to make command history
  69.     # available to the prompt function.
  70.     #
  71.     attach_event_handler( EVENT_INVALID_PCHAR, id )
  72.  
  73.     #
  74.     # let the command history functions know where to find
  75.     # the command history for this specified call.
  76.     #
  77.     historyName = index;
  78.     historyElement = defaultstr ? -1 : 0;
  79.  
  80.     #
  81.     # prompt for the search pattern and provide command history
  82.     #
  83.     if ((historyElement == 0) && (usehistory)) {
  84.         defaultstr = current_history_item( index );
  85.         historyElement = -1;
  86.     }
  87.     patt = prompt( historyPromptString = promptstr, defaultstr )
  88.  
  89.     #
  90.     # remove the prompt event handler
  91.     #
  92.     delete_event( EVENT_INVALID_PCHAR, id )
  93.  
  94.     if (patt)
  95.         add_prompt_history( index, patt )
  96.     return patt;
  97. }
  98.  
  99.  
  100. ##    _bad_prompt_key()
  101. #
  102. # This is the event handler used to handle bad keys entered from the prompt
  103. # primitive.
  104. #
  105. # A few notes:
  106. #
  107. #    o    This function will receive any key which is not a simple upper
  108. #    or lower case letter, including <Enter>, <Spacebar>, <Ctrl-A> etc.
  109. #
  110. #    o    The "prompt_response" variable contains the current input string
  111. #    at the prompt.  This string can be modified in any manner and will
  112. #    be reflected at the prompt line.
  113. #
  114. #    o    The value of "current_key" will be processed when this function
  115. #    returns as if this function was never called.  If you wish that
  116. #    the key not be processed, set "current_key = 0"; or if you wish to
  117. #    replace it with a different key, set "current_key = <your_keycode>".
  118. #    For example, setting current_key to "KEYCODE_HOME" will cause the
  119. #    cursor to move to the beginning of the prompt response.
  120. #
  121. #    o    Setting current_key to the magic value -1 resets prompt() to its
  122. #    initial state, i.e. it highlights the current prompt_response value
  123. #    and places the cursor at the end of the response.  If the
  124. #    prompt_response variable is changed without setting current_key
  125. #    to -1, the cursor position will be left unchanged.
  126. #
  127. global function _bad_prompt_key() {
  128.  
  129.     local    min = 0;
  130.     local    max;
  131.     local    saveBuffer
  132.     local    scancode
  133.     local    orig_x, orig_y,x,y,x_diff,y_diff,new_x0,new_y0, winid, save_winid
  134.  
  135.  
  136.     if (current_key == ALT_H) {
  137.         display_help_item( "prompt " historyName );
  138.         current_key = 0;
  139.         return;
  140.     }
  141.  
  142.  
  143.     if (current_key == KEYCODE_TAB) {
  144.         #
  145.         # if we are performing an edit_file and a TAB
  146.         # was pressed, then display dir listing
  147.         #
  148.         if (historyName == "EDITFILE") {
  149.             displayDirContents()
  150.             return;
  151.         }
  152.         #
  153.         # if we are performing an invoke_function (F10) and a TAB
  154.         # was pressed, then display function listing
  155.         #
  156.         if (historyName == "XMACRO") {
  157.             displayFunctionList()
  158.             return;
  159.         }
  160.     } else if (current_key == ALT_L) {
  161.         if (historyName == "EDITFILE") {
  162.             defaultFileName();
  163.             return;
  164.         }
  165.     } else if (current_key == ALT_K) {
  166.         prompt_response = substr(prompt_response,1,
  167.             window_cursor_x - length(historyPromptString));
  168.         return;
  169.     } else if ((current_key == LEFT_PRESS) &&
  170.         ((winid = window_containing( mouse_event_x, mouse_event_y))) &&
  171.         !(window_border_contains( mouse_event_x, mouse_event_y, winid ))){
  172.  
  173.     
  174.         save_winid = current_window;
  175.         current_window = winid;
  176.  
  177.         new_x0 = orig_x = mouse_event_x - window_text_x0;
  178.         new_y0 = orig_y = mouse_event_y - window_text_y0;
  179.  
  180.         x_diff = 1;
  181.         y_diff = 1;
  182.  
  183.         highlight_window( new_x0, new_y0, x_diff, y_diff, color_highlight );
  184.  
  185.         x = mouse_display_x;
  186.         y = mouse_display_y;
  187.  
  188.         while ( and(mouse_buttons, LEFT_BUTTON) ){
  189.             if ((x != mouse_display_x) || (y != mouse_display_y)){
  190.                 x = mouse_display_x;
  191.                 y = mouse_display_y;
  192.  
  193.                 if (!window_contains( x, y ) ||
  194.                     window_border_contains( x, y ))
  195.                     continue;
  196.  
  197.                 highlight_window( new_x0, new_y0, x_diff, y_diff, color_text );
  198.  
  199.                 new_x0 = mouse_display_x - window_text_x0;
  200.                 new_y0 = mouse_display_y - window_text_y0;
  201.  
  202.                 if (orig_x > new_x0) {
  203.                     x_diff = orig_x - new_x0 + 1;
  204.                 } else {
  205.                     x_diff = new_x0 - orig_x + 1;
  206.                     new_x0 = orig_x;
  207.                 }
  208.  
  209.                 if (orig_y > new_y0) {
  210.                     y_diff = orig_y - new_y0 + 1;
  211.                 } else {
  212.                     y_diff = new_y0 - orig_y + 1;
  213.                     new_y0 = orig_y;
  214.                 }
  215.  
  216.                 highlight_window( new_x0, new_y0, x_diff, y_diff, color_highlight );
  217.                 display_update();
  218.             }
  219.         }
  220.  
  221.         highlight_window( new_x0, new_y0, x_diff, y_diff, color_text );
  222.  
  223.         if ((x_diff != 1) || (y_diff != 1)){
  224.             prompt_response = ""
  225.             while (y_diff-- > 0) {
  226.                 window_cursor_x = new_x0;
  227.                 window_cursor_y = new_y0++;
  228.                 prompt_response = prompt_response read_window( x_diff )
  229.             }
  230.         }
  231.         assign_current_window( save_winid );
  232.         display_update();
  233.         current_key = KEYCODE_END;
  234.         return;
  235.     }
  236.  
  237.  
  238.  
  239.  
  240.     #
  241.     # is there something in the buffer?
  242.     #
  243.     max = historyArray[ historyName min ];
  244.  
  245.     scancode = shiftr(current_key, 8)
  246.     if (scancode == SCANCODE_DOWN) {
  247.         # get previous command
  248.         if (max)
  249.             historyElement = (historyElement + 1) % max
  250.     } else if (scancode == SCANCODE_UP) {
  251.         # get next command
  252.         if (max) {
  253.             if (historyElement <= 0)        # skip first entry if < 0
  254.                 historyElement = max + historyElement;
  255.             if (historyElement)
  256.                 historyElement--;
  257.         }
  258.     } else {
  259.         #
  260.         # Didn't find any keys that we want to handle so
  261.         # just return.
  262.         #
  263.         return;
  264.     }
  265.  
  266.     #
  267.     # read the response out of the buffer
  268.     #
  269.     # index was 0..n-1, it should be 1..n
  270.     current_key = 0;
  271.     if (max <= 0)
  272.         return;
  273.     prompt_response = historyArray[ historyName (historyElement + 1) ];
  274.     current_key = -1    # highlight the new prompt response
  275. }
  276.  
  277. ## find an item in the command history array
  278. #
  279. global function current_history_item( index ){
  280.     local    i = 0;
  281.  
  282.     if (index i in historyArray) {
  283.         i = historyArray[ index i ];
  284.         if (i)
  285.             return historyArray[ index i ];
  286.     }
  287.     return "";
  288. }
  289.  
  290.  
  291. ## add an item to the command history array
  292. #
  293. global function add_prompt_history( index, patt ) {
  294.     local    i = 0;
  295.     local    promptCount = 0;
  296.  
  297.     if (index i in historyArray)
  298.         promptCount = historyArray[ index i ];
  299.  
  300.     #
  301.     # don't add this pattern to the history if the previous pattern
  302.     # is the same.
  303.     #
  304.     if ( !promptCount || \
  305.         (promptCount && (historyArray[ index promptCount ] != patt)) ) {
  306.         historyArray[ index i ] = ++promptCount;
  307.         historyArray[ index promptCount ] = patt;
  308.     }
  309.  
  310.     return patt
  311. }
  312.  
  313.  
  314.  
  315. #--------- display directory specified and allow movement within it --------#
  316.  
  317.  
  318. ## displayDirContents()
  319. #
  320. # Display all of the files in the current directory which start with
  321. # the pattern specified of *.* if none.
  322. #
  323. # Maybe add changing directories and other items later.
  324. #
  325. local function displayDirContents() {
  326.  
  327.     local    ch
  328.     local    fname
  329.     local    numOfEntries = 0    # number of files in current directory
  330.     local    lastname
  331.     local    dir_buffer        # buffer which contains the file names
  332.     local    windowHeight
  333.     local    prompt_start
  334.     local    l,r,c,i
  335.     local    nname
  336.     local    srchname
  337.     local    tmp
  338.     local    insert_prev_dir = FALSE;
  339.     local    find_flags;
  340.     local    windowlines;
  341.     local    cr_pressed
  342.     local    dir_list
  343.     local    file_list
  344.     local    dirInfo = ""
  345.     local    maxWidth = FIELD_SIZE
  346.  
  347.  
  348.     init_menu_colors();
  349.  
  350.     prompt_start = prompt_response
  351.     l = rindex( prompt_start, "\\" )
  352.     r = rindex( prompt_start, "/" )
  353.     c = rindex( prompt_start, ":" )
  354.     l = l > r ? l : r
  355.     l = l > c ? l : c
  356.     prompt_start = prefix( prompt_start, l )
  357.  
  358.     saveWindow = current_window;
  359.     saveBuffer = current_buffer;
  360.  
  361.     # create a new buffer to put the filenames into
  362.     current_buffer =            \
  363.     dir_buffer =                \
  364.         create_buffer( "", "", BUFFER_SYSTEM + BUFFER_NO_UNDO )
  365.  
  366.     #
  367.     # read in all of normal file names from the current directory
  368.     # and insert them into the current_buffer
  369.     #
  370.     srchname = prompt_response
  371.     if ( (!srchname) || (rindex(srchname, "?") != length( srchname ))) {
  372.         tmp = path_ext( srchname )
  373.         if ( !tmp ) {
  374.             if ( length(path_fname(srchname)) >= 8 )
  375.                 srchname = srchname ".*"
  376.             else
  377.                 srchname = srchname "*.*"
  378.         } else {
  379.             if ( length(tmp) < 4 ) {
  380.                 srchname = srchname "*"
  381.             }
  382.         }
  383.     }
  384.  
  385.     find_flags = _SUBDIR        # include only directories
  386.  
  387.     # in case directory search takes a long time
  388.     message( "Working..." )
  389.  
  390.     for (i=0; i < 2; i++) {
  391.         fname = findfirst( srchname, find_flags );
  392.         fname = path_fname( fname ) path_ext( fname )
  393.  
  394.         while (fname) {
  395.             if (i == 0) {
  396.                 lastname = fname "\\"
  397.                 dir_list[ toupper(lastname) ] = ""
  398.             } else {
  399.                 lastname = tolower(fname)
  400.                 if ( edit_file_dir ){
  401.                     dirInfo = filesize()
  402.                     if ( dirInfo >= 0 ) {
  403.                         dirInfo = sprintf( "%7d  %s",
  404.                             filesize(),
  405.                             ctime( filetime()))
  406.                     } else {
  407.                         dirInfo = ""
  408.                     }
  409.                 }
  410.                 file_list[ lastname ] = dirInfo
  411.             }
  412.             numOfEntries++
  413.             fname = findnext()
  414.         }
  415.         find_flags = _NORMAL    # include normal files
  416.     }
  417.  
  418.     if (".\\" in dir_list) {
  419.         numOfEntries--;
  420.         delete( dir_list[ ".\\" ] )
  421.     }
  422.  
  423.     for (i in dir_list) {
  424.         insert_string( i "\n" )
  425.     }
  426.  
  427.     for (i in file_list) {
  428.         if ( edit_file_dir ){
  429.             i = i substr( "               ",        \
  430.                     1,                \
  431.                     FIELD_SIZE - length(i))        \
  432.                         file_list[i]
  433.             if ( length(i) > maxWidth ){
  434.                 maxWidth = length(i)
  435.             }
  436.         }
  437.         insert_string( i "\n" )
  438.     }
  439.  
  440.     backspace();
  441.  
  442.     # restore the old buffer for the current window
  443.     current_buffer = saveBuffer;
  444.  
  445.     #
  446.     # create the window making it just wide enough for a file name
  447.     #
  448.     windowlines = display_height - 8;
  449.     if (numOfEntries > 1 || insert_prev_dir) {
  450.         windowHeight = (numOfEntries > windowlines) ? windowlines : numOfEntries;
  451.         current_window =
  452.             create_factory_window( 10,            \
  453.                 display_height - windowHeight -6,    \
  454.                 maxWidth + 2,                \
  455.                 windowHeight + 2,            \
  456.                 WINDOW_MENU0 + WINDOW_SB_RIGHT )
  457.  
  458.         highlight_screen( 11,                    \
  459.                 display_height - windowHeight -5,    \
  460.                 maxWidth + 2,                \
  461.                 windowHeight + 2,            \
  462.                 SHADOW_COLOR );
  463.  
  464.         visible_end_buffer = ""
  465.         visible_tabs = ""
  466.         visible_virtual_lines   = ""
  467.  
  468.         # current_buffer = dir_buffer;
  469.         attach_window_buffer( current_window, dir_buffer )
  470.     }
  471.  
  472.     if ( numOfEntries == 0 ) {
  473.         # no files match the file pattern
  474.         delete_buffer( dir_buffer );
  475.         current_key = 0;
  476.         current_buffer = saveBuffer
  477.         return;
  478.     } else if ((numOfEntries == 1) && (!insert_prev_dir)) {
  479.         #
  480.         # only one file that matched, just set the prompt response
  481.         #
  482.         delete_buffer( dir_buffer );
  483.         prompt_response = prompt_start lastname;
  484.         current_buffer = saveBuffer
  485.         current_key = KEYCODE_END
  486.         return;
  487.     }
  488.  
  489.     message( "File: " prompt_response )
  490.  
  491.     #
  492.     # reset the position to the top of the list and highlight the
  493.     # first entry
  494.     #
  495.     goto_buffer_top()
  496.     drop_anchor( LINE_SELECTION )
  497.  
  498.     do {
  499.         display_update();        # update the screen
  500.  
  501.         ch = getchar();
  502.  
  503.         if (ch == 0) {
  504.             ch = getchar();        # expanded code, get rest of key
  505.  
  506.             if (ch == SCANCODE_DOWN) {
  507.                 menu_down_key(1)
  508.             } else if (ch == SCANCODE_UP) {
  509.                 menu_up_key(1)
  510.             } else if (ch == SCANCODE_PGUP) {
  511.                 menu_up_key( windowHeight )
  512.             } else if (ch == SCANCODE_PGDN) {
  513.                 menu_down_key( windowHeight )
  514.             } else if (ch == SCANCODE_HOME) {
  515.                 menu_home_key()
  516.             } else if (ch == SCANCODE_END) {
  517.                 menu_end_key()
  518.             } else if (ch == 0x23) {    # HELP
  519.                 display_help_item( "directory menu" );
  520.             } else if ((ch == SCANCODE_LEFT_PRESS) || \
  521.                     (ch == SCANCODE_LEFT_CLICK)) {
  522.                 menu_mouse_key()
  523.             }
  524.         } else {
  525.             if (ch == ASCII_ESC) {
  526.                 remove_menu( 1 );
  527.                 current_key = KEYCODE_ESC
  528.                 return;
  529.             } else if (ch == ASCII_BACKSPACE) {
  530.                 remove_menu( 1 )
  531.                 current_key = KEYCODE_END;
  532.                 return;
  533.             } else if (ch == ASCII_CR) {
  534.                 cr_pressed = TRUE;
  535.             } else if (chr(ch) ~ /[\\/]/) {
  536.                 remove_menu( 1 )
  537.                 current_key = ch
  538.                 return
  539.             } else {
  540.                 dir_search_i( ch );
  541.             }
  542.         }
  543.     } while ( !cr_pressed );
  544.  
  545.     #
  546.     # read the response out of the buffer
  547.     # and instruct prompt to accept it
  548.     # immediately.
  549.     #
  550.     goto_bol()
  551.     i = read_buffer()
  552.     if ( edit_file_dir ){
  553.         if ( match( i, / / )){
  554.             i = substr( i, 1, RSTART-1 )
  555.         }
  556.     }
  557.     prompt_response = prompt_start i
  558.  
  559.     remove_menu( 1 )
  560.     if ( prompt_response ~ /\\$/ ) {    # is it a subdir?
  561.         current_key = 0;
  562.         ungetkey( KEYCODE_TAB )        # yes, push a TAB
  563.     } else {
  564.         current_key = KEYCODE_ENTER    # no, exit prompt with a CR
  565.     }
  566. }
  567.  
  568.  
  569. ## perform an incremental search through the display list of file names
  570. #    As the search pattern is entered, it is display in a dialog window
  571. #    at the bottom of the screen and a highlight is placed over the
  572. #    appropriate entry.
  573. #
  574. local function dir_search_i( ch ) {
  575.     local    pattern = "",
  576.         char    = "",
  577.         level    = 0,
  578.         is_diag = 0+dialog_window;
  579.  
  580.     if (!is_diag) {
  581.         toggle_dialog();
  582.     }
  583.     display_update();
  584.  
  585.  
  586.     while (TRUE) {
  587.  
  588.         if ((ch == 0) || (ch == ASCII_ESC) || (ch == ASCII_CR)) {
  589.             break;
  590.         } else if (ch == ASCII_BACKSPACE) {
  591.             #
  592.             # remove the last char in the search string and
  593.             # restore the previous position
  594.             #
  595.             pattern = substr( pattern, 0, length( pattern ) - 1)
  596.             if (level) {
  597.                 raise_anchor()
  598.                 restore_position( TRUE );
  599.                 drop_anchor( LINE_SELECTION );
  600.                 level--;
  601.             }
  602.         } else {
  603.             #
  604.             # It is a normal ascii character.
  605.             # Let's search for the new pattern.  If we find it,
  606.             # save the previous position and advance to the
  607.             # newly found string.
  608.             #
  609.             char = chr( ch );
  610.             raise_anchor();
  611.             save_position();
  612.             message( "Directory-Search for: %s\137", pattern char)
  613.             if (search( "^" quote_regex(pattern char), \
  614.                 SEARCH_REGEX+SEARCH_MAXIMAL_MATCH+SEARCH_WRAPS+SEARCH_FORWARD+SEARCH_IGNORE_CASE)) {
  615.                 pattern = pattern char
  616.                 level++;
  617.             } else {
  618.                 beep();
  619.                 restore_position( FALSE );
  620.             }
  621.             drop_anchor( LINE_SELECTION );
  622.         }
  623.         display_update()
  624.  
  625.         # display the prompt message with a fake cursor
  626.         message( "Directory-Search for: %s\334", pattern)
  627.  
  628.         # get the next ascii character from the keyboard
  629.         # ignore extended character which have an ascii code of 0
  630.         ch = getchar()
  631.     }
  632.  
  633.     message( "" );
  634.  
  635.     while (level--)
  636.         restore_position( FALSE );
  637.  
  638.     toggle_dialog( is_diag );
  639.     display_update();
  640.     ungetkey( ch );
  641. }
  642.  
  643.  
  644. ## determine the buffer name of the current buffer.
  645. #
  646. local function defaultFileName(){
  647.     if (historyArray[ historyName 0 ]) {
  648.         prompt_response = buffer_name;
  649.         current_key = KEYCODE_END
  650.     } else {
  651.         beep();
  652.     }
  653. }
  654.  
  655.  
  656. #--------- display list of functions and allow movement within it --------#
  657.  
  658.  
  659. ## displayFunctionList()
  660. #
  661. # Display all of the functions available which start with
  662. # the pattern specified of at least two characters (zero or one might
  663. # take too long)
  664. #
  665. local function displayFunctionList() {
  666.  
  667.     local    symbol_list
  668.     local    sorted_symbol_list
  669.     local    searchFor
  670.     local    priorBuffer = current_buffer
  671.     local    tempBuffer
  672.     local    numOfEntries
  673.     local    windowHeight
  674.     local    windowWidth
  675.     local    prefix
  676.     local    i
  677.     local    result
  678.     local    symbolMatchFlag = 0x0f
  679.  
  680.     current_key = 0
  681.  
  682.     # extract question mark
  683.     if ( substr( prompt_response, 1, 1 ) == "?" ) {
  684.         prefix = "?"
  685.         searchFor = substr( prompt_response, 2 )
  686.     } else {
  687.         searchFor = prompt_response
  688.         # uncomment the following line to omit variables from
  689.         # <F10> command completion (if no "?" is present)
  690.         #symbolMatchFlag = 0x05
  691.     }
  692.  
  693.     # in case symbol_match takes a long time
  694.     message( "Working..." )
  695.  
  696.     # read a list of all symbols beginning with the specified pattern
  697.     if ( length( searchFor ) < 2 || !(symbol_list = \
  698.             symbol_match( searchFor, symbolMatchFlag )) ) {
  699.         message( "Command: " )
  700.         beep()
  701.         return
  702.     }
  703.  
  704.     message( "" )
  705.  
  706.     # create a system buffer for the list
  707.     current_buffer = tempBuffer =    \
  708.             create_buffer( "Function List", \
  709.                     "", \
  710.                     BUFFER_SYSTEM + BUFFER_NO_UNDO )
  711.  
  712.     # how many did we get?
  713.     for (i in symbol_list) {
  714.         sorted_symbol_list[ symbol_list[i] ] = numOfEntries++
  715.     }
  716.  
  717.     # build the menu buffer
  718.     for (i in sorted_symbol_list) {
  719.         insert_string( i "\n" )
  720.         if ( windowWidth < length(i)) {
  721.             windowWidth = length(i)
  722.         }
  723.     }
  724.     backspace()            # delete the last newline
  725.  
  726.     delete( symbol_list )        # deallocate the arrays
  727.     delete( sorted_symbol_list )
  728.  
  729.     # restore the old buffer for the current window
  730.     current_buffer = priorBuffer
  731.  
  732.     if ( numOfEntries == 0 ) {        # no match
  733.         beep()
  734.  
  735.     } else if ( numOfEntries == 1 ) {    # only one match
  736.         prompt_response = prefix i
  737.         current_key = KEYCODE_END
  738.  
  739.     } else {
  740.  
  741.         # create the window just wide enough for the longest string
  742.  
  743.         windowHeight = (numOfEntries > display_height - 8)    \
  744.             ? display_height - 8    \
  745.             : numOfEntries;
  746.         if ( windowWidth > (display_width - 20) ) {
  747.             windowWidth = display_width - 20
  748.         }
  749.  
  750.         result = menu_vertical( tempBuffer,            \
  751.                 10, display_height - windowHeight - 4,    \
  752.                 windowWidth, windowHeight )
  753.  
  754.         if (result) {
  755.             prompt_response = prefix result
  756.             current_key = KEYCODE_END
  757.         } else {
  758.             current_key = KEYCODE_ESC
  759.         }
  760.     }
  761.  
  762.     delete_buffer( tempBuffer )
  763. }
  764.  
  765.  
  766. #--------------------- menu functions -------------------------------------#
  767.  
  768. ## display a vertical menu at the given x,y,width,height coordinates
  769. #    on the screen.  The str contains the list of items for
  770. #    the menu with a '\n' separating each entry.
  771. #
  772. #    This function just inserts the string into a buffer and
  773. #    calls menu_vertical.
  774. #
  775. #    Use of the left mouse button to select entries is available.
  776. #
  777. global function list_vertical( str, x, y, width, height, rettype ){
  778.     local    cb = current_buffer;
  779.     local    buffer;
  780.     local    eol_str = default_buffer_eol_string;
  781.  
  782.     default_buffer_eol_string = "\n";
  783.     current_buffer =
  784.     buffer = create_buffer( "", "", BUFFER_SYSTEM+BUFFER_NO_UNDO+BUFFER_REAL_SPACE_ONLY );
  785.     default_buffer_eol_string = eol_str;
  786.  
  787.     insert_string( str );
  788.     current_buffer = cb;
  789.  
  790.     str = menu_vertical( buffer, x,y,width,height, rettype );
  791.     delete_buffer( buffer );
  792.     return str;
  793. }
  794.  
  795.  
  796. ## display a vertical menu at the given x,y,width,height coordinates
  797. #    on the screen.  The buffer is any system or regular buffer
  798. #    containing the list of items for the menu with a '\n'
  799. #    separating each entry.
  800. #
  801. #    Use of the left mouse button to select entries is available.
  802. #
  803. #    buffer = buffer where each line is an element of the menu
  804. #    x,y,width,height  = dimensions of menu box
  805. #    rettype = 0 - return a string
  806. #            = 1 - return index of selected item
  807. #
  808. global function menu_vertical( buffer, x, y, width, height, rettype ) {
  809.     local    retstr
  810.     local    ch
  811.     local    retindex;
  812.  
  813.     retindex = -1;
  814.  
  815.     init_menu_colors()
  816.  
  817.     saveWindow = current_window
  818.     saveBuffer = current_buffer
  819.  
  820.     highlight_screen( x+1, y+1, width+2, height+2, SHADOW_COLOR )
  821.  
  822.     #
  823.     # create the window using the dimensions given
  824.     #
  825.     current_window =
  826.         create_factory_window( x,y,width+2,height+2,    \
  827.             WINDOW_MENU0 + WINDOW_SB_RIGHT )
  828.  
  829.     color_text = BAR_COLOR
  830.     color_border = BAR_COLOR
  831.     color_highlight = HBAR_COLOR
  832.  
  833.     attach_window_buffer( current_window, buffer )
  834.  
  835.     goto_buffer_bottom();
  836.     if (current_line <= height)
  837.         window_flags = and( window_flags, not( WINDOW_SB_RIGHT ));
  838.  
  839.  
  840.     #
  841.     # reset the position to the top of the list and highlight the
  842.     # first entry
  843.     #
  844.     goto_buffer_top()
  845.     drop_anchor( LINE_SELECTION )
  846.  
  847.     do {
  848.         display_update()        # update the screen
  849.  
  850.         ch = getchar()
  851.  
  852.         if (ch == 0) {
  853.             ch = getchar()        # expanded code, get rest of key
  854.             if (ch == SCANCODE_DOWN) {
  855.                 menu_down_key(1)
  856.             } else if (ch == SCANCODE_UP) {
  857.                 menu_up_key(1)
  858.             } else if (ch == SCANCODE_PGUP) {
  859.                 menu_up_key( height )
  860.             } else if (ch == SCANCODE_PGDN) {
  861.                 menu_down_key( height )
  862.             } else if (ch == 0x23) {    # HELP
  863.                 goto_bol()
  864.                 display_help_item( ltrim( trim( read_buffer())) )
  865.             } else if (ch == 0x3B){        # F1
  866.                 goto_bol()
  867.                 library( read_buffer() );
  868.             } else if ((ch == SCANCODE_LEFT_PRESS) || \
  869.                     (ch == SCANCODE_LEFT_CLICK)) {
  870.                 menu_mouse_key()
  871.             }
  872.         } else {
  873.             if (ch == ASCII_ESC) {
  874.                 break
  875.             } else if (ch == ASCII_CR) {
  876.                 #
  877.                 # read the response out of the buffer
  878.                 #
  879.                 goto_bol()
  880.                 retindex = current_line
  881.                 retstr = read_buffer()
  882.                 break
  883.             } else {
  884.                 beep()
  885.             }
  886.         }
  887.     } while (TRUE)
  888.  
  889.     remove_menu( 0 );
  890.     return rettype ? retindex : retstr
  891. }
  892.  
  893.  
  894. ## take down a menu and associated buffer
  895. #
  896. local function remove_menu( del_buffer ) {
  897.  
  898.     # remove the selection
  899.     raise_anchor()
  900.  
  901.     # optionally remove the system buffer
  902.     if ( del_buffer ) {
  903.         delete_buffer()
  904.     }
  905.  
  906.     # remove the system window
  907.     delete_window()
  908.     if ( saveWindow ) {
  909.         current_window = saveWindow
  910.     }
  911.  
  912.     # retore the original buffer
  913.     current_buffer = saveBuffer
  914.  
  915.     # remove the shadow window
  916.     display_redraw()
  917.  
  918.     current_key = 0
  919.     message( "" )
  920. }
  921.  
  922.  
  923. ## process a down key press from within a menu
  924. #
  925. local function menu_down_key( lines ) {
  926.  
  927.     if ( down( lines )) {
  928.         #
  929.         # redisplay the highlight on the new selection
  930.         #
  931.         raise_anchor()
  932.         drop_anchor( LINE_SELECTION )
  933.     }
  934. }
  935.  
  936.  
  937. ## process an up key press from within a menu
  938. #
  939. local function menu_up_key( lines ){
  940.  
  941.     if ( up( lines )) {
  942.         #
  943.         # redisplay the highlight on the new selection
  944.         #
  945.         raise_anchor()
  946.         drop_anchor( LINE_SELECTION )
  947.     }
  948. }
  949.  
  950. ## process a home key press from within a menu
  951. #
  952. local function menu_home_key(){
  953.  
  954.     raise_anchor()
  955.     goto_buffer_top();
  956.     drop_anchor( LINE_SELECTION )
  957. }
  958.  
  959. ## process an end key press from within a menu
  960. #
  961. local function menu_end_key(){
  962.  
  963.     raise_anchor()
  964.     goto_buffer_bottom();
  965.     drop_anchor( LINE_SELECTION )
  966. }
  967.  
  968. ## process a mouse press from within a menu
  969. #
  970. global function menu_mouse_key(){
  971.     local    mousePos
  972.  
  973.     if ( window_contains( mouse_event_x, mouse_event_y )) {
  974.         mousePos = mouse_position(1)
  975.         if ( mousePos == MOUSE_IN_TEXT || mousePos == MOUSE_E ) {
  976.  
  977.             # track the mouse cursor, highlighting the
  978.             # current line, for as long as the mouse cursor
  979.             # is depressed
  980.  
  981.             setHighlightedScrolling( current_window )
  982.             left_press( 1 )
  983.             goto_bol()
  984.             display_update()
  985.             setHighlightedScrolling( 0 )
  986.  
  987.             if ( !region_type() ) {
  988.                 drop_anchor( LINE_SELECTION )
  989.             }
  990.  
  991.             if ( mousePos == MOUSE_E ) {    # right scroll bar
  992.                 return 1
  993.             }
  994.  
  995.             # if they end up in the text region, consider
  996.             # it a selection
  997.             if ( window_contains( mouse_event_x, mouse_event_y ) &&
  998.                     !window_border_contains(
  999.                         mouse_event_x, mouse_event_y )) {
  1000.                 ungetkey( KEYCODE_ENTER )
  1001.             }
  1002.         }
  1003.         return 1
  1004.     }
  1005.  
  1006.     # mouse was clicked outside of current window
  1007.     ungetkey( KEYCODE_ESC )
  1008.     return 0
  1009. }
  1010.