home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c160 / 1.ddi / SOURCE / N4.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-11-21  |  29.9 KB  |  1,295 lines

  1.  
  2. /* n4.c    (c)Copyright Sequiter Software Inc., 1987-1990.  All rights reserved.
  3.  
  4.    Menu Routines
  5. */
  6.  
  7. #include "d4all.h"
  8. #include "w4.h"
  9. #include "g4char.h"
  10. #include "u4error.h"
  11. #include "p4misc.h"
  12.  
  13. #ifdef VARARGS
  14. #include <varargs.h>
  15. #else
  16. #include <stdarg.h>
  17. #endif
  18.  
  19. #include <string.h>
  20. #include <ctype.h>
  21. #ifndef UNIX
  22. #include <io.h>
  23. #endif
  24.  
  25. extern GET     *v4get ;
  26. extern CB_WINDOW  *v4window ;
  27. extern CB_WINDOW  *v4window_ptr ;
  28. extern MENU  *v4menu ;
  29.  
  30. static char  key_data[20] ;   /* Key Data Entered When Searching Menus */
  31. static int   key_len = 0 ;
  32.  
  33. extern int  v4up_key ;
  34. extern int  v4exit_key ;
  35. extern int  v4return_start ;
  36. extern int  v4return_end ;
  37.  
  38. extern int  v4screen_width  ;     /* Width in display characters */
  39. extern int  v4screen_width2 ;     /* Width in storage bytes */
  40. extern int  v4screen_height ;
  41. extern int  v4display_bytes ;     /* Width in storage bytes */
  42.  
  43. extern int  v4cur_window ;    /* The Selected Window */
  44. extern int  v4first_window ;
  45.  
  46. #ifdef UNIX
  47.    extern int  v4refresh_on ;
  48. #endif
  49.  
  50. typedef struct menu_data_st
  51. {
  52.    int  ref ;      /* The reference number of the current menu selection */
  53.    int  pos ;      /* The position (from 0) of the current selection */
  54.  
  55.    int  tot_entries ; /* The total number of entries in the menu */
  56.    int  scr_entries ; /* The number of entries which fit on the screen */
  57.  
  58.    int  num_rows ;    /* The number of rows in each menu */
  59.    int  num_cols ;    /* The number of column positions in each menu */
  60.  
  61.    int  do_calc ;     /* 1 to calculate the (row,col) positions, otherwise 0 */
  62. }  MENU_DATA ;
  63.  
  64. static void  calc_pos( int, MENU_DATA *, int, int *, int *) ;
  65. static void  make_top( MENU_DATA * ) ;
  66. static void  refresh_menu( MENU_DATA * ) ;
  67. static void  display_item( MENU_DATA *, int ) ;
  68. static int   skip( MENU_DATA *, int ) ;
  69. static void  menu_home_end( MENU_DATA *, int ) ;
  70. static int   menu_top_bottom( MENU_DATA *, int ) ;
  71. static void  menu_pgup_pgdn( MENU_DATA *, int ) ;
  72. static void  menu_up_down( MENU_DATA *, int ) ;
  73. static int   menu_key( MENU_DATA *, int ) ;
  74. static int   top_bottom_ref( MENU_DATA *, int ) ;
  75.  
  76. static int   is_window_ref( int ) ;
  77.  
  78. static int  is_window_ref( int w_ref )
  79. {
  80.    int  on_ref ;
  81.  
  82.    on_ref =  v4first_window ;
  83.    while ( on_ref >= 0 )
  84.    {
  85.       if ( w_ref == on_ref )  return 1 ;
  86.       on_ref =  v4window[on_ref].next ;
  87.    }
  88.    return 0 ;
  89. }
  90.  
  91. static  top_bottom_ref( MENU_DATA *m_ptr, int sign )
  92. {
  93.    int  on_pos, on_ref, num_pos ;
  94.  
  95.    on_pos =  m_ptr->pos ;
  96.    on_ref =  m_ptr->ref ;
  97.  
  98.    if ( sign < 0 )
  99.    {
  100.       while( on_pos-- > 0  &&  on_ref >= 0 )
  101.      on_ref =  v4menu[on_ref].prev ;
  102.    }
  103.    else
  104.    {
  105.       num_pos =  m_ptr->scr_entries - on_pos - 1 ;
  106.       while( num_pos-- > 0  &&  on_ref >= 0 )
  107.      on_ref =  v4menu[on_ref].next ;
  108.    }
  109.  
  110.    return( on_ref ) ;
  111. }
  112.  
  113. static void calc_pos( int menu_ref, MENU_DATA *m_ptr, int i, 
  114.                       int *row_ptr, int *col_ptr )
  115. {
  116.    if ( ! m_ptr->do_calc )
  117.    {
  118.       *row_ptr =  v4menu[menu_ref].row ;
  119.       *col_ptr =  v4menu[menu_ref].col ;
  120.       return ;
  121.    }
  122.  
  123.    if ( v4window_ptr->horizontal )
  124.    {
  125.       *row_ptr =  i / m_ptr->num_cols ;
  126.       *col_ptr =  (i% m_ptr->num_cols) * v4window_ptr->item_width +1 ;
  127.    }
  128.    else
  129.    {
  130.       *row_ptr =  i % m_ptr->num_rows ;
  131.       *col_ptr =  (i/ m_ptr->num_rows) * v4window_ptr->item_width +1 ;
  132.    }
  133. }
  134.  
  135.  
  136. /* Makes the Current Entry as Close to the Top Entry as Possible */
  137. static void  make_top( MENU_DATA *m_ptr )
  138. {
  139.    int  ref, n ;
  140.  
  141.    n =  0 ;
  142.    ref =  m_ptr->ref ;
  143.  
  144.    while ( ref >= 0  &&  ++n < m_ptr->scr_entries )
  145.       ref =  v4menu[ref].next ;
  146.  
  147.    m_ptr->pos =  m_ptr->scr_entries - n ;
  148. }
  149.  
  150.  
  151. static void  refresh_menu( MENU_DATA *m_ptr )
  152. {
  153.    int  save_ref, save_pos ;
  154.  
  155.    w4activate(-1) ;
  156.    w4clear( 0 ) ;
  157.  
  158.    if ( m_ptr->pos < 0 )  m_ptr->pos =  0 ;
  159.    if ( m_ptr->pos >= m_ptr->scr_entries )
  160.         m_ptr->pos =  m_ptr->scr_entries - 1 ;
  161.  
  162.    save_ref =  m_ptr->ref ;
  163.    save_pos =  m_ptr->pos ;
  164.    display_item( m_ptr, -1 ) ;
  165.  
  166.    for( ;; )
  167.    {
  168.       m_ptr->pos++ ;
  169.       m_ptr->ref =  v4menu[m_ptr->ref].next ;
  170.       if ( m_ptr->pos >= m_ptr->scr_entries  || m_ptr->ref < 0 )  break ;
  171.  
  172.       display_item( m_ptr, 0 ) ;
  173.    }
  174.  
  175.    m_ptr->ref =  save_ref ;
  176.    m_ptr->pos =  save_pos ;
  177.  
  178.    for( ;; )
  179.    {
  180.       m_ptr->pos-- ;
  181.       m_ptr->ref =  v4menu[m_ptr->ref].prev ;
  182.       if ( m_ptr->pos < 0  || m_ptr->ref < 0 )  break ;
  183.  
  184.       display_item( m_ptr, 0 ) ;
  185.    }
  186.  
  187.    m_ptr->ref =  save_ref ;
  188.    m_ptr->pos =  save_pos ;
  189. }
  190.  
  191.  
  192. /*  display_item
  193.  
  194.     do_att Value    Meaning
  195.  
  196.        -1       Display completely with selected attribute
  197.       >= 0      Display that number of characters blinking and
  198.             intense.  This is used to display the matching
  199.             search characters in a different manner.
  200.     0       Display normally.  If their is a special key
  201.             highlight position, the character will be
  202.             displayed intensely.  Their will be no
  203.             special highlight key for search windows.
  204. */
  205.  
  206. static void  display_item( MENU_DATA *m_ptr, int do_att )
  207. {
  208.    int   row, col, len, pos ;
  209.    char *ptr ;
  210.    MENU *menu_ptr ;
  211.  
  212.    calc_pos( m_ptr->ref, m_ptr, m_ptr->pos, &row, &col ) ;
  213.    menu_ptr =  v4menu +  m_ptr->ref ;
  214.  
  215.    ptr =  menu_ptr->item_ptr ;
  216.    len =  (int) strlen(ptr) ;
  217.    if ( len > v4window_ptr->item_width )
  218.       len =  v4window_ptr->item_width ;
  219.  
  220.    if ( do_att )
  221.    {
  222.       if ( do_att < 0 )
  223.       {
  224.      w4num_att( row, col, ptr, len, v4window_ptr->menu_att_active) ;
  225.       }
  226.       else
  227.       {
  228.      if ( do_att > len )  do_att =  len ;
  229.      w4num_att( row, col, ptr, do_att,
  230.              v4window_ptr->menu_att_active | B_BLINK | F_INTENSE ) ;
  231.      w4num_att( row, col+do_att, ptr+ do_att, len- do_att,
  232.              v4window_ptr->menu_att_active) ;
  233.       }
  234.    }
  235.    else
  236.    {
  237.       if ( menu_ptr->key_highlight_pos < 0  ||
  238.        menu_ptr->key_highlight_pos >= len ||
  239.        v4window_ptr->key_read != 1 ||
  240.        menu_ptr->skip_over )
  241.       {
  242.      w4num_att( row, col, ptr, len, menu_ptr->attribute ) ;
  243.       }
  244.       else
  245.       {
  246.      pos =  menu_ptr->key_highlight_pos ;
  247.  
  248.      w4num_att( row, col, ptr, pos, menu_ptr->attribute ) ;
  249.      w4num_att( row, col+pos, ptr+pos, 1, menu_ptr->attribute | F_INTENSE) ;
  250.      pos++ ;
  251.      w4num_att( row, col+pos, ptr+pos, len-pos, menu_ptr->attribute ) ;
  252.       }
  253.    }
  254. }
  255.  
  256. /* Skips if necessary in the specified direction to a valid menu option */
  257.  
  258. static int  skip( MENU_DATA *m_ptr, int sign )
  259. {
  260.    int  ref, pos ;
  261.  
  262.    ref =  m_ptr->ref ;
  263.    pos =  m_ptr->pos ;
  264.  
  265.    while ( v4menu[ref].skip_over )
  266.    {
  267.       if ( sign < 0 )
  268.       {
  269.      ref =  v4menu[ref].prev ;
  270.      pos-- ;
  271.      if ( ref < 0 )
  272.      {
  273.         if ( m_ptr->ref == v4window_ptr->last_menu)  return -1 ;
  274.  
  275.         m_ptr->ref =  v4window_ptr->first_menu ;
  276.         m_ptr->pos =  0 ;
  277.         skip( m_ptr, 1) ;
  278.         return -1 ;
  279.      }
  280.       }
  281.       else
  282.       {
  283.      ref =  v4menu[ref].next ;
  284.      pos++ ;
  285.      if ( ref < 0 )
  286.      {
  287.         if ( m_ptr->ref == v4window_ptr->first_menu)  return 1 ;
  288.  
  289.         m_ptr->ref =  v4window_ptr->last_menu ;
  290.         m_ptr->pos =  m_ptr->scr_entries-1 ;
  291.         skip( m_ptr, -1) ;
  292.         return 1 ;
  293.      }
  294.       }
  295.    }
  296.  
  297.    m_ptr->pos =  pos ;
  298.    m_ptr->ref =  ref ;
  299.  
  300.    return 0 ;
  301. }
  302.  
  303. static void  menu_home_end( MENU_DATA *m_ptr, int sign )
  304. {
  305.    MENU_DATA  old_data ;
  306.  
  307.    key_len =  0 ;
  308.  
  309.    memcpy( (char *) &old_data, (char *) m_ptr, sizeof(MENU_DATA) ) ;
  310.    if ( sign < 0 )
  311.    {
  312.       m_ptr->pos =  0 ;
  313.       m_ptr->ref =  v4window_ptr->first_menu ;
  314.    }
  315.    else
  316.    {
  317.       m_ptr->pos =  m_ptr->scr_entries-1 ;
  318.       m_ptr->ref =  v4window_ptr->last_menu ;
  319.    }
  320.  
  321.    skip(m_ptr, sign) ;
  322.  
  323.    if ( top_bottom_ref(m_ptr,sign) != top_bottom_ref(&old_data,sign) )
  324.    {
  325.       refresh_menu( m_ptr ) ;
  326.       return ;
  327.    }
  328.  
  329.    display_item( &old_data, 0 ) ;
  330.    display_item( m_ptr, -1 ) ;
  331. }
  332.  
  333. /* Returns TRUE if already on top or bottom; otherwise, moves to top or bottom */
  334. static int  menu_top_bottom( MENU_DATA *m_ptr, int sign )
  335. {
  336.    MENU_DATA  test ;
  337.  
  338.    memcpy( (char *) &test, (char *) m_ptr, sizeof(MENU_DATA) ) ;
  339.    test.ref =  top_bottom_ref( &test, sign ) ;
  340.  
  341.    if ( sign < 0 )
  342.       test.pos =  0 ;
  343.    else
  344.       test.pos =  m_ptr->scr_entries- 1 ;
  345.  
  346.    if ( m_ptr->ref == test.ref )  return( 1 ) ;
  347.  
  348.    skip( &test, sign ) ;
  349.    if ( test.ref == m_ptr->ref )  return( 1 ) ;
  350.  
  351.    memcpy( (char *) m_ptr, (char *) &test, sizeof(MENU_DATA) ) ;
  352.    refresh_menu( m_ptr ) ;
  353.  
  354.    return ( 0 ) ;
  355. }
  356.  
  357.  
  358. static void  menu_pgup_pgdn( MENU_DATA *m_ptr, int sign )
  359. {
  360.    int  i, next_ref ;
  361.  
  362.    key_len =  0 ;
  363.  
  364.    if ( menu_top_bottom(m_ptr, sign)  )
  365.    {
  366.       for ( i=0; i< m_ptr->scr_entries; i++ )
  367.       {
  368.      if ( sign < 0 )
  369.         next_ref =  v4menu[m_ptr->ref].prev ;
  370.      else
  371.         next_ref =  v4menu[m_ptr->ref].next ;
  372.      if (next_ref < 0)  break ;
  373.      m_ptr->ref =  next_ref ;
  374.       }
  375.  
  376.       if ( sign < 0 )
  377.      m_ptr->pos =  0 ;
  378.       else
  379.      m_ptr->pos =  m_ptr->scr_entries - 1;
  380.  
  381.       skip( m_ptr, sign ) ;
  382.       refresh_menu( m_ptr ) ;
  383.    }
  384. }
  385.  
  386. static void  menu_up_down( MENU_DATA *m_ptr, int sign )
  387. {
  388.    MENU_DATA  old_data ;
  389.    int  next_ref ;
  390.  
  391.    if ( sign < 0 )
  392.       next_ref =  v4menu[m_ptr->ref].prev ;
  393.    else
  394.       next_ref =  v4menu[m_ptr->ref].next ;
  395.  
  396.    if ( next_ref < 0 )
  397.    {
  398.       menu_home_end( m_ptr, -sign ) ;
  399.       return ;
  400.    }
  401.  
  402.    key_len =  0 ;
  403.    memcpy( (char *) &old_data, (char *) m_ptr, sizeof(MENU_DATA) ) ;
  404.  
  405.    m_ptr->ref  =  next_ref ;
  406.    m_ptr->pos +=  sign ;
  407.  
  408.    if ( skip( m_ptr, sign ) )
  409.    {
  410.       memcpy( (char *) m_ptr, (char *) &old_data, sizeof(MENU_DATA) ) ;
  411.       menu_home_end( m_ptr, -sign ) ;
  412.       return ;
  413.    }
  414.  
  415.    if ( m_ptr->pos < 0 || m_ptr->pos >= m_ptr->scr_entries )
  416.       refresh_menu( m_ptr ) ;
  417.    else
  418.    {
  419.       display_item( &old_data, 0 ) ;
  420.       display_item( m_ptr, -1 ) ;
  421.    }
  422. }
  423.  
  424. /* Returns -2 if not found; else 0 */
  425. static  int  menu_key( MENU_DATA *m_ptr, int ch )  
  426. {
  427.    int  ref, i, pos, is_found, ch_upper, ch_lower ;
  428.  
  429.    if ( v4window_ptr->ignore_case &&  ch <= 0x7E )
  430.    {
  431.       ch_upper =  u4toupper( ch ) ;
  432.       ch_lower =  u4tolower( ch ) ;
  433.    }
  434.    else
  435.       ch_upper =  ch_lower =  ch ;
  436.  
  437.    if ( v4window_ptr->key_read > 0 )
  438.    {
  439.       pos =  m_ptr->pos ;
  440.       ref =  m_ptr->ref ;
  441.  
  442.       is_found =  0 ;
  443.  
  444.       if ( v4window_ptr->key_read == 2  &&  key_len < sizeof(key_data) )
  445.      key_data[key_len++] =  (char) ch ;
  446.  
  447.       for ( i = 0; i<= m_ptr->tot_entries; i++, pos++ )
  448.       {
  449.      if ( ref < 0 )
  450.      {
  451.         pos -=  m_ptr->tot_entries ;
  452.         ref  =  v4window_ptr->first_menu ;
  453.      }
  454.  
  455.      if ( ! v4menu[ref].skip_over )
  456.      {
  457.         if ( v4window_ptr->key_read == 1 )
  458.         {
  459.            if ( (ch_upper == (int) v4menu[ref].key_value ||
  460.              ch_lower == (int) v4menu[ref].key_value)  &&
  461.              (ref != m_ptr->ref || i > 0) )  is_found =  1 ;
  462.         }
  463.         else
  464.         {
  465.            /* String Compare */
  466.            if ( v4window_ptr->ignore_case )
  467.            {
  468.           if ( strnicmp( key_data, v4menu[ref].item_ptr, (size_t) key_len ) == 0 )
  469.              is_found =  1 ;
  470.            }
  471.            else
  472.            {
  473.           if ( strncmp( key_data, v4menu[ref].item_ptr, (size_t) key_len ) == 0 )
  474.              is_found =  1 ;
  475.            }
  476.         }
  477.      }
  478.  
  479.      if ( is_found )
  480.      {
  481.         if ( pos >= m_ptr->scr_entries || pos < 0 )
  482.         {
  483.            m_ptr->ref =  ref ;
  484.            make_top( m_ptr ) ;  /* Make Found Entry the Top if Possible */
  485.            refresh_menu( m_ptr ) ;
  486.            if ( v4window_ptr->key_read == 2 )
  487.           display_item( m_ptr, key_len ) ;
  488.            else
  489.           if ( v4menu[m_ptr->ref].key_activate )  return (RETURN) ;
  490.            return 0 ;
  491.         }
  492.         else
  493.         {
  494.            display_item( m_ptr, 0 ) ;
  495.            m_ptr->ref =  ref ;
  496.            m_ptr->pos =  pos ;
  497.            if ( v4window_ptr->key_read == 2 )
  498.           display_item( m_ptr, key_len ) ;
  499.            else
  500.            {
  501.           display_item( m_ptr, -1 ) ;
  502.           if ( v4menu[m_ptr->ref].key_activate )  return (RETURN) ;
  503.            }
  504.            return 0 ;
  505.         }
  506.      }
  507.  
  508.      ref =  v4menu[ref].next ;
  509.       }
  510.       if ( key_len > 0 )  key_len-- ;
  511.    }
  512.  
  513.    return -2 ;
  514. }
  515.  
  516. int  n4( char *label )
  517. {
  518.    return( n4item( -1, -1, label )  ) ;
  519. }
  520.  
  521.  
  522. static  int (*rou_ptr)(void) =  0 ;
  523.  
  524. #ifdef KR
  525.    void n4char_routine( char_rou )
  526.    int (*char_rou)() ;
  527. #else
  528.    void n4char_routine( int (*char_rou)(void) )
  529. #endif
  530. {
  531.    rou_ptr =  char_rou ;
  532. }
  533.  
  534. #ifdef UNIX
  535. int  n4char()
  536. {
  537.    int  rc ;
  538.  
  539.    v4refresh_on =  1 ;
  540.    w4refresh(-1) ;
  541.  
  542.    if ( u4ptr_equal( (void *) rou_ptr, (void *) 0 ) )
  543.       rc =  g4char() ;
  544.    else
  545.       rc =  (*rou_ptr)() ;
  546.  
  547.    v4refresh_on =  0 ;
  548.  
  549.    return( rc ) ;
  550. }
  551. #else
  552. int n4char()
  553. {
  554.    if ( u4ptr_equal( (void *) rou_ptr, (void *) 0 ) )
  555.       return g4char() ;
  556.    else
  557.       return (*rou_ptr)() ;
  558. }
  559. #endif
  560.  
  561.  
  562. static void  n4act_return( int, int, int ) ;
  563.  
  564. static void  n4act_return( int menu_ref, int prev_ref, int save_refresh_on )
  565. {
  566.    n4message_do( "" ) ;
  567.    w4deactivate( v4menu[menu_ref].window_ref ) ;
  568.    w4select( prev_ref ) ;
  569.  
  570.    #ifdef UNIX
  571.       v4refresh_on =  save_refresh_on ;
  572.       w4refresh(-1) ;
  573.    #endif
  574. }
  575.  
  576.  
  577. int  n4activate( int w_ref )
  578. {
  579.    int     ch, up_ch, down_ch, up_ch2, down_ch2, new_ch ;
  580.    int     max_width, cur_width, prev_ref ;
  581.    MENU  *menu_ptr ;
  582.    MENU_DATA  m ;
  583.    int  save_refresh_on ;
  584.  
  585.    prev_ref =  w4select( w_ref ) ;
  586.    save_refresh_on =  v4window_ptr->force_refresh =  0 ;
  587.  
  588.    new_ch =  key_len =  max_width =  m.do_calc =  m.tot_entries =  0 ;
  589.  
  590.    for( m.ref =  v4window_ptr->first_menu; m.ref >= 0;
  591.     m.ref =  v4menu[m.ref].next )
  592.    {
  593.       menu_ptr =  v4menu +  m.ref ;
  594.       m.tot_entries ++ ;
  595.       cur_width =  (int) strlen( menu_ptr->item_ptr ) ;
  596.       if ( cur_width > max_width )  max_width =  cur_width ;
  597.  
  598.       if ( menu_ptr->row < 0  ||  menu_ptr->col < 0 )  m.do_calc =  1 ;
  599.    }
  600.    if ( m.tot_entries < 0 )
  601.    {
  602.       w4select( prev_ref ) ;
  603.       return 0 ;
  604.    }
  605.  
  606.    /* Initialize the menu data */
  607.    m.num_rows =  v4window_ptr->height ;
  608.    m.num_cols =  v4window_ptr->width-2 ;
  609.    if ( v4window_ptr->item_width <= 0 )
  610.       v4window_ptr->item_width =  v4window_ptr->width-2 ;
  611.    m.num_cols   /=  v4window_ptr->item_width ;
  612.    if ( m.do_calc )
  613.       m.scr_entries =  m.num_rows * m.num_cols ;
  614.    else
  615.    {
  616.       m.num_rows =  m.tot_entries ;
  617.       m.num_cols =  1 ;
  618.       m.scr_entries =  m.tot_entries ;
  619.    }
  620.    if ( m.scr_entries > m.tot_entries )  m.scr_entries =  m.tot_entries ;
  621.    if ( m.scr_entries <= 0 )
  622.    {
  623.       w4select( prev_ref ) ;
  624.       return 0 ;
  625.    }
  626.  
  627.    #ifdef UNIX
  628.       save_refresh_on =  v4refresh_on ;
  629.       v4refresh_on =  0 ;
  630.    #endif
  631.  
  632.    w4activate( w_ref ) ;
  633.  
  634.    if ( v4window_ptr->start_item < 0 )
  635.       menu_home_end( &m, -1 ) ;
  636.    else
  637.    {
  638.       m.ref =  v4window_ptr->start_item ;
  639.       make_top( &m ) ;
  640.       refresh_menu( &m ) ;
  641.    }
  642.  
  643.    if ( v4window_ptr->horizontal )
  644.    {
  645.       up_ch   =  LEFT ;
  646.       down_ch =  RIGHT ;
  647.       up_ch2  =  CTRL_S ;
  648.       down_ch2=  CTRL_D ;
  649.    }
  650.    else
  651.    {
  652.       up_ch   =  UP ;
  653.       down_ch =  DOWN ;
  654.       up_ch2  =  CTRL_E ;
  655.       down_ch2=  CTRL_X ;
  656.    }
  657.  
  658.    for(;;)
  659.    {
  660.       w4select( v4menu[m.ref].window_ref ) ;
  661.  
  662.       if ( v4window_ptr->force_refresh )
  663.       {
  664.      v4window_ptr->force_refresh =  0 ;
  665.      refresh_menu( &m ) ;
  666.       }
  667.  
  668.       if ( new_ch > 0 )
  669.       {
  670.      ch =  new_ch ;
  671.      new_ch =  0 ;
  672.      if ( ch == v4window_ptr->up_key )
  673.         ch =  0 ; /* Only Up One at a Time */
  674.      n4message_do( v4menu[m.ref].message ) ;
  675.       }
  676.       else
  677.       {
  678.      if ( ! u4ptr_equal( (void *) v4menu[m.ref].reaction, (void *) 0) )
  679.      {
  680.         #ifdef UNIX
  681.            if ( ! u4ptr_equal( (void *) v4menu[m.ref].reaction , (void *) n4sub_menu) )
  682.            {
  683.           v4refresh_on =  1 ;
  684.           w4refresh(-1) ;
  685.            }
  686.         #endif
  687.         ch =  (*v4menu[m.ref].reaction)( v4menu[m.ref].parm_data ) ;
  688.  
  689.         #ifdef UNIX
  690.            v4refresh_on =  0 ;
  691.         #endif
  692.         if ( ch < 0 )
  693.         {
  694.            n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  695.            return( ch ) ;
  696.         }
  697.         if ( ch == 0 )
  698.         {
  699.            n4message_do( v4menu[m.ref].message ) ;
  700.            ch = n4char() ;
  701.         }
  702.      }
  703.      else
  704.      {
  705.         n4message_do( v4menu[m.ref].message ) ;
  706.         ch =  n4char() ;
  707.      }
  708.       }
  709.  
  710.  
  711.       w4select( v4menu[m.ref].window_ref ) ;
  712.  
  713.       switch( ch )
  714.       {
  715.      case UP:
  716.      case LEFT:
  717.      case CTRL_E:
  718.      case CTRL_S:
  719.         if ( ch == up_ch  || ch == up_ch2 )
  720.         {
  721.            menu_up_down( &m, -1 ) ;
  722.         }
  723.         else
  724.         {
  725.            if ( v4window_ptr->arrow_exit )
  726.            {
  727.                  n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  728.           return( ch ) ;
  729.            }
  730.         }
  731.         break ;
  732.  
  733.      case DOWN:
  734.      case RIGHT:
  735.      case CTRL_X:
  736.      case CTRL_D:
  737.         if ( ch == down_ch  ||  ch == down_ch2 )
  738.         {
  739.            menu_up_down( &m, 1 ) ;
  740.         }
  741.         else
  742.         {
  743.            if ( v4window_ptr->arrow_exit )
  744.            {
  745.                  n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  746.           return( ch ) ;
  747.            }
  748.         }
  749.         break ;
  750.  
  751.      case HOME:
  752.      case CTRL_A:
  753.         menu_home_end( &m, -1 ) ;
  754.         break ;
  755.  
  756.      case END:
  757.         menu_home_end( &m, 1 ) ;
  758.         break ;
  759.  
  760.      case PGUP:
  761.      case CTRL_R:
  762.         menu_pgup_pgdn( &m, -1 ) ;
  763.         break ;
  764.  
  765.      case PGDN:
  766.      case CTRL_N:
  767.         menu_pgup_pgdn( &m, 1 ) ;
  768.         break ;
  769.  
  770.      case BACK_SPACE:
  771.         if (key_len > 0)
  772.         {
  773.            if ( --key_len > 0 )
  774.           display_item( &m, key_len ) ;
  775.            else
  776.           display_item( &m, -1 ) ;
  777.         }
  778.         break ;
  779.  
  780.      case RETURN:
  781.         if ( key_len > 0 )
  782.         {
  783.            key_len =  0 ;
  784.            display_item( &m, -1 ) ;
  785.         }
  786.         if ( u4ptr_equal( (void *) v4menu[m.ref].action, (void *) 0) &&
  787.              u4ptr_equal( (void *) v4menu[m.ref].reaction, (void *) 0) )
  788.         {
  789.            n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  790.            return ( v4menu[m.ref].parm_data ) ;
  791.         }
  792.         if ( u4ptr_equal( (void *) v4menu[m.ref].action, (void *) 0 ) )
  793.                new_ch =  0 ;
  794.             else
  795.             {
  796.            #ifdef UNIX
  797.               if ( ! u4ptr_equal( (void *) v4menu[m.ref].action, (void *) n4sub_menu))
  798.               {
  799.              v4refresh_on =  1 ;
  800.              w4refresh(-1) ;
  801.               }
  802.            #endif
  803.            new_ch = (*v4menu[m.ref].action)( v4menu[m.ref].parm_data) ;
  804.            #ifdef UNIX
  805.               v4refresh_on =  0 ;
  806.            #endif
  807.            if ( new_ch < 0 )
  808.            {
  809.               n4act_return( m.ref, prev_ref, save_refresh_on) ;
  810.               return ( new_ch ) ;
  811.            }
  812.            w4select( v4menu[m.ref].window_ref ) ;
  813.            if ( ! v4window_ptr->force_refresh )
  814.           display_item( &m, -1 ) ;
  815.            break ;
  816.             }
  817.  
  818.      default:
  819.         if ( ch == v4window_ptr->exit_key ||  ch == v4window_ptr->up_key )
  820.         {
  821.            n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  822.            return( ch ) ;
  823.         }
  824.  
  825.         if ( ch >= 0x1 && ch <= 0x7F00 )
  826.         {
  827.            new_ch =  menu_key( &m, ch ) ;
  828.            if ( new_ch == -2 )
  829.            {
  830.           new_ch =  0 ;
  831.           if ( ch >= v4window_ptr->return_start &&
  832.                ch <= v4window_ptr->return_end )
  833.           {
  834.                   n4act_return( m.ref, prev_ref, save_refresh_on ) ;
  835.              return( ch ) ;
  836.           }
  837.            }
  838.         }
  839.         break ;
  840.       }
  841.    }
  842. }
  843.  
  844.  
  845. void  n4arrow_exit()
  846. {
  847.    v4window_ptr->arrow_exit =  1 ;
  848. }
  849.  
  850.  
  851. void  n4attribute( long attribute, long attribute_active )
  852. {
  853.    v4window_ptr->menu_attribute  =  attribute ;
  854.    v4window_ptr->menu_att_active =  attribute_active ;
  855. }
  856.  
  857.  
  858. void  n4attribute_item( int item_ref, long attribute )
  859. {
  860.    MENU *menu_ptr ;
  861.  
  862.    menu_ptr =  v4menu +  item_ref ;
  863.    menu_ptr->attribute =  attribute ;
  864. }
  865.  
  866.  
  867. void  n4get_calc( int w_ref )
  868. {
  869.    int  on_get, on_menu ;
  870.    GET    *get_ptr ;
  871.    CB_WINDOW    *w2_ptr, *w_ptr ;
  872.  
  873.    w_ptr =  v4window + w_ref ;
  874.  
  875.    for (on_get= w_ptr->first_get; on_get >= 0; on_get = get_ptr->next)
  876.    {
  877.        get_ptr =  v4get+ on_get ;
  878.  
  879.        if ( u4ptr_equal( (void *) get_ptr->call, (void *) g4menu) ||
  880.             u4ptr_equal( (void *) get_ptr->call, (void *) g4menu_help ))
  881.        {
  882.       w2_ptr =  v4window + get_ptr->call_data ;
  883.       #ifdef UNIX
  884.          w2_ptr->up_key    =  CTRL_Q ;
  885.       #else
  886.          w2_ptr->up_key    =  ESC ;
  887.       #endif
  888.       w2_ptr->exit_key     =  SHIFT_TAB ;
  889.       w2_ptr->return_start =  0 ;
  890.       w2_ptr->return_end   =  0x7F ;
  891.  
  892.       n4calc( get_ptr->call_data,
  893.              w_ptr->start_row + get_ptr->row +1,
  894.              w_ptr->start_col + get_ptr->col ) ;
  895.  
  896.       for ( on_menu=w2_ptr->first_menu; on_menu>=0; on_menu=v4menu[on_menu].next)
  897.       {
  898.          v4menu[on_menu].parm_data =  -on_menu ;
  899.          if ( on_menu == 0 )
  900.         v4menu[on_menu].parm_data =  0x7FFF ;
  901.       }
  902.        }
  903.    }
  904. }
  905.  
  906.  
  907. void  n4horizontal()
  908. {
  909.    v4window_ptr->horizontal =  1 ;
  910. }
  911.  
  912. int  n4item( int row, int col, char *label )
  913. {
  914.    MENU *menu_ptr ;
  915.  
  916.    if ( v4menu == (MENU *) 0 )
  917.       if(  h4create( (char **) &v4menu, 20, (int) sizeof(MENU), 20) < 0 ) return -1 ;
  918.  
  919.    v4window_ptr->last_menu =  h4get( (char **) &v4menu, v4window_ptr->last_menu ) ;
  920.    if ( v4window_ptr->last_menu < 0 )  return -1 ;
  921.  
  922.    if ( v4window_ptr->first_menu < 0 )
  923.       v4window_ptr->first_menu =  v4window_ptr->last_menu ;
  924.    menu_ptr =  v4menu+ v4window_ptr->last_menu ;
  925.  
  926.    menu_ptr->row =  row ;
  927.    menu_ptr->col =  col ;
  928.    menu_ptr->window_ref =  v4cur_window ;
  929.    menu_ptr->item_ptr =  label ;
  930.    menu_ptr->attribute =  v4window_ptr->menu_attribute ;
  931.    menu_ptr->parm_data =  v4window_ptr->last_menu ;
  932.    n4key( (int) label[0], 1, 0 ) ;
  933.  
  934.    return ( v4window_ptr->last_menu ) ;
  935. }
  936.  
  937. char *  n4item_text( int i_ref )
  938. {
  939.    return ( v4menu[i_ref].item_ptr ) ;
  940. }
  941.  
  942. void  n4item_width( int item_width )
  943. {
  944.    v4window_ptr->item_width =  item_width ;
  945. }
  946.  
  947.  
  948. void  n4key( int chr, int active, int highlight_pos )
  949. {
  950.    MENU *menu_ptr ;
  951.  
  952.    if ( v4window_ptr->last_menu < 0 )  return ;
  953.    menu_ptr =  v4menu +  v4window_ptr->last_menu ;
  954.    menu_ptr->key_value    =  chr ;
  955.    menu_ptr->key_activate     =  active ;
  956.    menu_ptr->key_highlight_pos=  highlight_pos ;
  957. }
  958.  
  959.  
  960. void  n4key_set( int set_code, int ignore_case )
  961. {
  962.    v4window_ptr->key_read    =  set_code ;
  963.    v4window_ptr->ignore_case =  ignore_case ;
  964. }
  965.  
  966.  
  967. void  n4key_special( int up_key, int exit_key, int return_start, int return_end )
  968. {
  969.    v4up_key      =  up_key ;
  970.    v4exit_key    =  exit_key ;
  971.    v4return_start=  return_start ;
  972.    v4return_end  =  return_end ;
  973. }
  974.  
  975. extern int  v4menu_row, v4menu_col ;
  976. static void  calc_lotus(int, int, int) ;
  977.  
  978. void  n4lotus( int w_ref )
  979. {
  980.    CB_WINDOW  *w_ptr ;
  981.  
  982.    if ( ! is_window_ref( w_ref ) )
  983.    {
  984.       u4error( E_WINDOW_REF, "(n4lotus)", (char *) 0 ) ;
  985.       return ;
  986.    }
  987.  
  988.    w_ptr =  v4window +  w_ref ;
  989.  
  990.    if ( w_ptr->start_row < 0 )  w_ptr->start_row =  0 ;
  991.    if ( w_ptr->start_col < 0 )  w_ptr->start_col =  0 ;
  992.  
  993.    calc_lotus( w_ref, w_ptr->start_row, w_ptr->start_col ) ;
  994.    v4menu_row =  w_ptr->start_row+1 ;
  995.    v4menu_col =  w_ptr->start_col ;
  996. }
  997.  
  998.  
  999. static void  calc_lotus( int window_ref, int start_row, int start_col )
  1000. {
  1001.    int    menu_on, cur_col, start_window ;
  1002.    MENU  *menu_ptr ;
  1003.    int   *i_ptr ;
  1004.  
  1005.    if ( ! is_window_ref( window_ref ) )
  1006.    {
  1007.       u4error( E_WINDOW_REF, "(calc_lotus)", (char *) 0 ) ;
  1008.       return ;
  1009.    }
  1010.  
  1011.    start_window =  w4select( window_ref ) ;
  1012.  
  1013.    v4window_ptr->start_row =  start_row ;
  1014.    v4window_ptr->start_col =  start_col ;
  1015.    v4window_ptr->return_start =  0 ;
  1016.    v4window_ptr->return_end   =  0 ;
  1017.    #ifdef UNIX
  1018.       v4window_ptr->up_key    =  CTRL_Q ;
  1019.    #else
  1020.       v4window_ptr->up_key    =  ESC ;
  1021.    #endif
  1022.    v4window_ptr->exit_key     =  '/' ;
  1023.  
  1024.    cur_col =  0 ;
  1025.  
  1026.    for( menu_on= v4window_ptr->first_menu; menu_on >= 0; menu_on = menu_ptr->next)
  1027.    {
  1028.       menu_ptr =  v4menu +  menu_on ;
  1029.  
  1030.       menu_ptr->row =  0 ;
  1031.       menu_ptr->col =  cur_col ;
  1032.  
  1033.       if ( u4ptr_equal( (void *) menu_ptr->reaction, (void *) n4sub_menu) ||
  1034.        u4ptr_equal( (void *) menu_ptr->action, (void *) n4sub_menu))
  1035.       {
  1036.      i_ptr =  (int *) menu_ptr->ptr_data ;
  1037.      calc_lotus( *i_ptr, start_row, start_col ) ;
  1038.       }
  1039.  
  1040.       cur_col +=  (int) strlen( menu_ptr->item_ptr ) + 3 ;
  1041.    }
  1042.  
  1043.    v4window_ptr->height =  1 ;
  1044.    v4window_ptr->width  =  v4screen_width - start_col ;
  1045.  
  1046.    w4popup() ;
  1047.    n4horizontal() ;
  1048.  
  1049.    w4select( start_window ) ;
  1050. }
  1051.  
  1052.  
  1053. void  n4message( char *message_ptr )
  1054. {
  1055.    MENU *menu_ptr ;
  1056.  
  1057.    if ( v4window_ptr->last_menu < 0 )  return ;
  1058.    menu_ptr =  v4menu +  v4window_ptr->last_menu ;
  1059.    menu_ptr->message =  message_ptr ;
  1060. }
  1061.  
  1062.  
  1063. void  n4action( ACTION *action )
  1064. {
  1065.    if ( v4window_ptr->last_menu < 0 )  return ;
  1066.    v4menu[v4window_ptr->last_menu].action =   action ;
  1067. }
  1068.  
  1069.  
  1070. void  n4reaction( ACTION *action )
  1071. {
  1072.    if ( v4window_ptr->last_menu < 0 )  return ;
  1073.    v4menu[v4window_ptr->last_menu].reaction =   action ;
  1074. }
  1075.  
  1076. /* Makes a Pull Down Menu out of the Currently Selected Menu */
  1077. void  n4pulldown( int w_ref )
  1078. {
  1079.    int    menu_on, cur_col, old_window_ref ;
  1080.    MENU  *menu_ptr ;
  1081.    int   *i_ptr ;
  1082.  
  1083.    if ( ! is_window_ref( w_ref ) )
  1084.    {
  1085.       u4error( E_WINDOW_REF, "(n4pulldown)", (char *) 0 ) ;
  1086.       return ;
  1087.    }
  1088.  
  1089.    old_window_ref =  v4cur_window ;
  1090.    w4select( w_ref ) ;
  1091.  
  1092.    if ( v4window_ptr->start_row < 0 )  v4window_ptr->start_row =  0 ;
  1093.    if ( v4window_ptr->start_col < 0 )  v4window_ptr->start_col =  0 ;
  1094.  
  1095.    cur_col =  1 ;
  1096.  
  1097.    for (menu_on= v4window_ptr->first_menu; menu_on>= 0; menu_on= menu_ptr->next)
  1098.    {
  1099.       menu_ptr =  v4menu +  menu_on ;
  1100.  
  1101.       menu_ptr->row =  0 ;
  1102.       menu_ptr->col =  cur_col ;
  1103.  
  1104.       if ( u4ptr_equal( (void *) menu_ptr->reaction, (void *) n4sub_menu) ||
  1105.        u4ptr_equal( (void *) menu_ptr->action,   (void *) n4sub_menu))
  1106.       {
  1107.      i_ptr =  (int *) menu_ptr->ptr_data ;
  1108.  
  1109.      n4calc( *i_ptr, v4window_ptr->start_row+1,
  1110.                v4window_ptr->start_col+cur_col ) ;
  1111.      v4window[*i_ptr].arrow_exit =  1 ;
  1112.       }
  1113.  
  1114.       cur_col +=  (int) strlen( menu_ptr->item_ptr ) + 3 ;
  1115.    }
  1116.  
  1117.    v4window_ptr->width =  cur_col-2 ;
  1118.    v4window_ptr->height=  1 ;
  1119.    w4popup() ;
  1120.    n4horizontal() ;
  1121.  
  1122.    w4select( old_window_ref ) ;
  1123. }
  1124.  
  1125.  
  1126. /* Assume not popped up, no border, and (start_row,start_col) is
  1127.    the upper left hand corner of the new window.
  1128.  
  1129.    Calculate the coordinate of the window and underlying windows.
  1130.    Assign the border and specify the window to be 'popup'.
  1131.    Adjust the (start_row,start_col) if necessary.
  1132. */
  1133.  
  1134. void  n4calc( int w_ref, int start_row, int start_col )
  1135. {
  1136.    int  start_ref, on_menu ;
  1137.    int  max_width, width, num, i ;
  1138.    MENU  *menu_ptr ;
  1139.  
  1140.    if ( ! is_window_ref( w_ref ) )
  1141.    {
  1142.       u4error( E_WINDOW_REF, "(n4calc)", (char *) 0 ) ;
  1143.       return ;
  1144.    }
  1145.  
  1146.    start_ref =  w4select( w_ref ) ;
  1147.  
  1148.    if ( v4window_ptr->title != (char *) 0 )
  1149.       max_width =  (int) strlen( v4window_ptr->title ) -2 ;
  1150.    else
  1151.       max_width =  0 ;
  1152.  
  1153.    if ( v4window_ptr->border_chars == (char *) 0 )
  1154.       w4border( SINGLE, F_WHITE ) ;
  1155.  
  1156.    num =  0 ;
  1157.  
  1158.    for (on_menu= v4window_ptr->first_menu; on_menu>= 0; on_menu= menu_ptr->next)
  1159.    {
  1160.       menu_ptr =  v4menu +  on_menu ;
  1161.       num ++ ;
  1162.  
  1163.       width =  (int) strlen( menu_ptr->item_ptr ) ;
  1164.       if ( width > max_width )  max_width =  width ;
  1165.  
  1166.       menu_ptr->row =  -1 ;
  1167.       menu_ptr->col =  -1 ;
  1168.    }
  1169.  
  1170.    max_width += 2 ;  /* Two columns for the edges */
  1171.    if ( num >  v4screen_height -2 - start_row )
  1172.       num =  v4screen_height -2 - start_row ;
  1173.    if ( max_width > v4screen_width -2 )  max_width =  v4screen_width  -2 ;
  1174.  
  1175.    v4window_ptr->width  =  max_width ;
  1176.    v4window_ptr->height =  num ;
  1177.  
  1178.    if ( start_col + max_width+2 >  v4screen_width )
  1179.       start_col =  v4screen_width -max_width -2 ;
  1180.  
  1181.    v4window_ptr->start_row =  start_row+1 ;
  1182.    v4window_ptr->start_col =  start_col+1 ;
  1183.  
  1184.    i = start_row+1 ;
  1185.  
  1186.    for (on_menu= v4window_ptr->first_menu; on_menu>= 0; on_menu= menu_ptr->next)
  1187.    {
  1188.       menu_ptr =  v4menu +  on_menu ;
  1189.       i++ ;
  1190.  
  1191.       if ( u4ptr_equal( (void *) menu_ptr->reaction, (void *) n4sub_menu) ||
  1192.        u4ptr_equal( (void *) menu_ptr->action, (void *) n4sub_menu))
  1193.       {
  1194.      int  *i_ptr ;
  1195.      i_ptr =  (int *) menu_ptr->ptr_data ;
  1196.      n4calc( *i_ptr, i, v4window_ptr->start_col+ 1 ) ;
  1197.       }
  1198.    }
  1199.  
  1200.    w4border( v4window_ptr->border_chars, v4window_ptr->border_attribute ) ;
  1201.    w4popup() ;
  1202.  
  1203.    w4select( start_ref ) ;
  1204. }
  1205.  
  1206.  
  1207. void  n4refresh( int w_ref )
  1208. {
  1209.    v4window[w_ref].force_refresh =  1 ;
  1210.    return ;
  1211. }
  1212.  
  1213.  
  1214. int  n4search( char *ptr )
  1215. {
  1216.    int  on_menu, len, total_len, i ;
  1217.    char *item_ptr ;
  1218.  
  1219.    /* Len is the number of non-blank characters in 'ptr' */
  1220.    len =  total_len =  (int) strlen(ptr) ;
  1221.    len--;
  1222.    while ( len >= 0  && ptr[len] == ' ' )  len-- ;
  1223.    len++ ;
  1224.  
  1225.    for( on_menu= v4window_ptr->first_menu; on_menu>= 0; on_menu= v4menu[on_menu].next)
  1226.    {
  1227.       if ( v4menu[on_menu].skip_over )  continue ;
  1228.  
  1229.       if ( strncmp( (item_ptr = v4menu[on_menu].item_ptr), ptr, (size_t) len ) == 0 )
  1230.       {
  1231.      for(i=len;; i++)
  1232.      {
  1233.         if ( item_ptr[i] == '\000' || i==total_len )  return( on_menu ) ;
  1234.         /* If there is another non-blank character, there is no match */
  1235.         if ( item_ptr[i] != ' ' )  break ;
  1236.      }
  1237.       }
  1238.    }
  1239.  
  1240.    return -1 ;
  1241. }
  1242.  
  1243.  
  1244. int  n4skip_over( int item_ref, int flag )
  1245. {
  1246.    int  rc ;
  1247.    if ( item_ref < 0 )  return -1;
  1248.  
  1249.    rc =  v4menu[item_ref].skip_over ;
  1250.    v4menu[item_ref].skip_over =  flag ;
  1251.  
  1252.    return  rc ;
  1253. }
  1254.  
  1255.  
  1256. void  n4start_item( int start_item_ref )
  1257. {
  1258.    v4window[v4menu[start_item_ref].window_ref].start_item =  start_item_ref ;
  1259. }
  1260.  
  1261. void  n4parm( int new_parm_data )
  1262. {
  1263.    if ( v4window_ptr->last_menu < 0 )  return ;
  1264.    v4menu[v4window_ptr->last_menu].parm_data =   new_parm_data ;
  1265. }
  1266.  
  1267. void  n4ptr_save( void *new_ptr_data )
  1268. {
  1269.    if ( v4window_ptr->last_menu < 0 )  return ;
  1270.    v4menu[v4window_ptr->last_menu].ptr_data =   new_ptr_data ;
  1271. }
  1272.  
  1273. void  n4int_save( int new_int_data )
  1274. {
  1275.    if ( v4window_ptr->last_menu < 0 )  return ;
  1276.    v4menu[v4window_ptr->last_menu].int_data =   new_int_data ;
  1277. }
  1278.  
  1279. void *n4ptr_get( int item_ref )
  1280. {
  1281.    return  v4menu[item_ref].ptr_data ;
  1282. }
  1283.  
  1284. int  n4int_get( int item_ref )
  1285. {
  1286.    return  v4menu[item_ref].int_data ;
  1287. }
  1288.  
  1289. int  n4sub_menu( int item_ref )
  1290. {
  1291.    int *window_ref_ptr ;
  1292.    window_ref_ptr =  (int *) n4ptr_get( item_ref ) ;
  1293.    return  n4activate( *window_ref_ptr ) ;
  1294. }
  1295.