home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dots151.zip / GRAPHSRC.ZIP / WINDOW.C < prev    next >
C/C++ Source or Header  |  1990-06-16  |  34KB  |  1,445 lines

  1. #define SHRINK
  2. /*
  3.  
  4.     wint - implement graphics mode menus for Turbo C
  5.  
  6. */
  7.  
  8. #include <dos.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11.  
  12. #include <stdio.h>
  13. #include "g.h"
  14. #include "scr_ci.h"
  15. #include "window.h"
  16. #ifndef SHRINK
  17. #include "mif.h"
  18. #endif
  19.  
  20. #define MAXCHARS 38        /* # characters in queue (where mouse-
  21.                                 generated characters are saved) */
  22. #define MAXMSG 20        /* maximum # messages in message queue */
  23.  
  24. static CurVis = 0;        /* nonzero if mouse cursor is visible */
  25.  
  26. /* ------------- general purpose programs ---------------------------- */
  27.  
  28.     /*    
  29.         queued_chars[chHead] is where the next character will be placed
  30.         queued_chars[chTail] has the next character to be delivered
  31.         chHead == chTail when the queue is empty 
  32.     */
  33. static int chHead, chTail;
  34. static char queued_chars[MAXCHARS];
  35.  
  36. static key_avail()         /* return nonzero if a keyboard char is available */
  37. {    
  38.     union REGS regs;
  39.     regs.h.ah = 0xb;
  40.     regs.x.dx = 0;
  41.     return (chHead - chTail) || intdos(®s, ®s);
  42. }
  43.  
  44. static min(a, b) int a, b;
  45. {    if(a < b) return a;
  46.     return b;
  47. }
  48.  
  49. static max(a, b) int a, b;
  50. {    if(a > b) return a;
  51.     return b;
  52. }
  53.  
  54. ungets(s) char *s;
  55. {    int i;
  56.     while(*s)
  57.         {i = chHead + 1;
  58.         if(i >= MAXCHARS) i = 0;
  59.         if(i == chTail) return;
  60.         queued_chars[chHead] = *s++;
  61.         chHead = i;
  62.         }
  63. }
  64.  
  65. static key_in()
  66. {    int ch;
  67. #ifdef __TURBOC__
  68.     union REGS regs;
  69. #endif
  70.     while(1)
  71.         {
  72.         deliver();                        /* deliver one message from queue */
  73.         if(chHead != chTail)
  74.             {ch = queued_chars[chTail];
  75.             if(++chTail >= MAXCHARS) chTail = 0;
  76.             return ch;
  77.             }
  78. #ifdef _DESMET_
  79.         if(_os(0xb, 0)) 
  80. #else
  81. #ifdef __TURBOC__
  82.         regs.h.ah = 0xb;
  83.         regs.x.dx = 0;
  84.         if(intdos(®s, ®s))
  85. #endif /* __TURBOC__ */
  86. #endif /* _DESMET_ */
  87.             return scr_ci();
  88.         }
  89. }
  90.  
  91. static char *gmem(num) int num;
  92. {    char *mp, *malloc();
  93.     mp = malloc(num);
  94.     if(!mp) 
  95.         {
  96. #ifndef SHRINK
  97.         fprintf(stderr, "out of memory\n"); 
  98. #endif
  99.         exit(1);
  100.         }
  101.     return mp;
  102. }
  103.  
  104. /*    get string, edit */
  105. getse(s, appending, x, y, w, norm, high) 
  106. char *s; 
  107. int appending, x, y, w, norm, high;
  108. {    int ch, i, j, n, maxn, inserting;
  109.  
  110.     inserting = 0;
  111.  
  112.     if(79*char_width > w) maxn = w/char_width;
  113.     else maxn = 79;    /* assume the input buffer is 80 bytes long */
  114.     maxn -= 2;        /* allow for the two spaces printed after the string */
  115.  
  116.     n = strlen(s);
  117.     if(n > maxn) n = maxn;
  118.     s[n] = 0;
  119.  
  120.     if(appending) i = n;
  121.     else i = 0;
  122.  
  123.     set_color(norm & 0x0f);
  124.     set_background_color(norm >> 4);
  125.     gotoxy(x, y);
  126.     (*draw_text)(s);
  127.     gotoxy(x + n*char_width, y);
  128.     (*draw_text)("  ");
  129.  
  130.     set_color(high & 0x0f);
  131.     set_background_color(high >> 4);
  132.     gotoxy(x + i*char_width, y);
  133.     (*draw_char)(i < n ? s[i] : ' ');
  134.  
  135.     ch = key_in();
  136.  
  137.     if(!appending)
  138.         {switch(ch)
  139.             {case 3:
  140.             case ESC:
  141.             case 0x0d:
  142.             case ctrl_right_char:
  143.             case ctrl_left_char:
  144.             case right_char:
  145.             case up_char:
  146.             case down_char:
  147.             case ins_char: 
  148.             case del_char:
  149.             case end_char:
  150.             case home_char:
  151.                 break;
  152.             default:
  153.                 for (i = 0; i < n; i++) s[i] = ' ';
  154.                 set_color(norm & 0x0f);
  155.                 set_background_color(norm >> 4);
  156.                 gotoxy(x, y);
  157.                 (*draw_text)(s);
  158.                 s[0] = i = n = 0;
  159.             }
  160.         }
  161.  
  162.     while(1)
  163.         {switch(ch)
  164.             {case 3:
  165.             case ESC:
  166.                 return 0;                /* abnormal return */
  167.             case RETURN:
  168.             case up_char:
  169.             case down_char:
  170.                 return ch;                /* normal return */
  171.             case left_char: 
  172.                 {if(i) i--;
  173.                 break;
  174.                 }
  175.             case BS:
  176.                 {if (i == 0) break;
  177.                 i--;
  178.                 /*  fall into... */
  179.                 }
  180.             case del_char:
  181.                 {if (i == n) break;
  182.                 for (j = i; j < n; j++) s[j] = s[j + 1];
  183.                 n--;
  184.                 break;
  185.                 }
  186.             case ins_char: 
  187.                 {inserting ^= 1;
  188.                 break;
  189.                 }
  190.             case ctrl_right_char:
  191.                 {while(i < n && s[i] != ' ') i++;
  192.                 while(i < n && s[i] == ' ') i++;
  193.                 break;
  194.                 }
  195.             case ctrl_left_char:
  196.                 {while(i && s[i-1] == ' ') i--;
  197.                 while(i && s[i-1] != ' ') i--;
  198.                 break;
  199.                 }
  200.             case right_char:
  201.                 {if(i < n && i < maxn) i++;
  202.                 break;
  203.                 }
  204.             case end_char:
  205.                 {i = n;
  206.                 break;
  207.                 }
  208.             case home_char:
  209.                 {i = 0;
  210.                 break;
  211.                 }
  212.             default:
  213.                 {if(ch < ' ' || ch > 0x7f) break;
  214.                 if(inserting)
  215.                     if(n >= maxn) break;
  216.                     else
  217.                         for (j = n++; j >= i; j--) 
  218.                             s[j + 1] = s[j];
  219.                 else if(i == n) 
  220.                     if(n >= maxn) break;
  221.                     else s[++n] = 0;
  222.                 s[i++] = ch;
  223.                 break;
  224.                 }
  225.             }
  226.         set_color(norm & 0x0f);
  227.         set_background_color(norm >> 4);
  228.         gotoxy(x, y);
  229.         (*draw_text)(s);
  230.         gotoxy(x + n*char_width, y);
  231.         (*draw_text)("  ");
  232.  
  233.         set_color(high & 0x0f);
  234.         set_background_color(high >> 4);
  235.         gotoxy(x + i*char_width, y);
  236.         (*draw_char)(i < n ? s[i] : ' ');
  237.  
  238.         ch = key_in();
  239.         }
  240. }
  241.  
  242. /* ------------- window programs ------------------------------------- */
  243.  
  244. #define WINMAX 30
  245. WINDOW *WinStack[WINMAX];
  246. int WinVis = 0;
  247.  
  248. static x0, y0, xp, yp, b_left, b_right, b_up, b_down, 
  249.     ShowingBox = 0, ShowingCross = 0;
  250. static CURSOR CursorShape;
  251. CURSOR DragShape = BOX;
  252.  
  253.  
  254. WINDOW *CreateWindow(text, x, y, extra) 
  255. char *text;         /* displayed at the top of this window */
  256. int x, y;            /* upper left corner of window */
  257. int extra;            /* extra bytes to allocate at end of this WINDOW */
  258. {    WINDOW *pw;
  259.     int nb, bx, by, thisw, maxw;
  260.  
  261.     pw = (WINDOW *)gmem(sizeof(WINDOW) + extra);
  262.  
  263.     pw->text = text;
  264.     pw->accept = MsgWindow;
  265.  
  266.     pw->x = x;
  267.     pw->y = y;
  268.  
  269.     pw->w = strlen(text) * char_width;
  270.     pw->h = char_height;
  271.  
  272.     pw->window_style = 1;
  273.     pw->border_style = 1;
  274.                                         /* 0 -> white */
  275.     pw->norm = (max_color&0x0f)<<4;        /* background in high order nibble, */
  276.     pw->high = max_color&0x0f;            /* forground in low order */
  277.     pw->vis = 0;
  278.  
  279.     return pw;
  280. }
  281.  
  282. #define RR(x)    /*                \
  283. {FILE *buf;                     \
  284. buf = fopen("debug", "a");        \
  285. fprintf x;                         \
  286. fclose(buf);                    \
  287. }                               /**/
  288.  
  289. void MsgWindow(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
  290. {    int bx, by, i, j, restore;
  291.     char buf[100];
  292.     switch(msg)
  293.         {
  294.         case REDRAW:
  295.             if(pw->vis == 0) 
  296.                 {
  297.                 if(WinVis >= WINMAX) break;
  298.                 WinStack[WinVis++] = pw; pw->vis = 1;
  299. /*
  300. {FILE *dfile;
  301. dfile = fopen("c:debug", "a");
  302. fprintf(dfile, "adding window: WinVis = %d, WinStack[WinVis-1] = %04x\n",
  303.                                                 WinVis, WinStack[WinVis-1]);
  304. fclose(dfile);
  305. }
  306. */
  307.                 }
  308. /*
  309. {FILE *dfile;
  310. dfile = fopen("c:debug", "a");
  311. fprintf(dfile, "   redrawing window: WinVis = %d, WinStack[WinVis-1] = %04x\n",
  312.                                                 WinVis, WinStack[WinVis-1]);
  313. fclose(dfile);
  314. }
  315. */
  316.             bx = pw->x; by = pw->y;
  317. #ifndef SHRINK
  318.             if(restore = CurVis) HideMouseCursor(); 
  319. #endif /* SHRINK */
  320.             set_background_color(pw->norm >> 4);
  321.             ClearBox(bx, by, bx + pw->w, by + pw->h + 1);
  322.         
  323.             if(strlen(pw->text)) 
  324.                 {
  325.                 gotoxy(bx, by + char_height);
  326.                 set_color(pw->norm & 0x0f);
  327.                 (*draw_text)(pw->text);
  328.                 }
  329.             
  330.             set_color(pw->norm & 0x0f);
  331.             if(pw->border_style == 1) 
  332.                 box(bx - 1, by - 1, bx + pw->w, by + pw->h);
  333. #ifndef SHRINK
  334.             if(restore) ShowMouseCursor();
  335. #endif /* SHRINK */
  336.             break;
  337. #ifndef SHRINK
  338.         case DRAG:
  339.             SetHorizontalLimits(0, pixels_wide - 1);    /* release cursor */
  340.             SetVerticalLimits(0, pixels_high - 1);
  341.  
  342.             bx = data[0] - b_left;
  343.             if(bx <= 0) bx = 1;
  344.             if(bx + pw->w >= pixels_wide) bx = pixels_wide - pw->w - 1;
  345.             by = data[1] - b_up;
  346.             if(by < 0) by = 0;
  347.             if(by + pw->h >= pixels_high) by = pixels_high - pw->h - 1;
  348.             data[0] = bx;
  349.             data[1] = by;
  350.             (*pw->accept)(MOVETO, data, pw);
  351.             break;
  352. #endif /* SHRINK */
  353.         case CLEAR:
  354.             if(pw->vis)
  355.                 {
  356. /*
  357. {FILE *dfile;
  358. dfile = fopen("c:debug", "a");
  359. fprintf(dfile, "clearing window: WinVis = %d, WinStack[0] = %04x\n",
  360.                                                         WinVis, WinStack[0]);
  361. fclose(dfile);
  362. }
  363. */
  364.                 for (i = j = 0; i < WinVis; i++)
  365.                     if(WinStack[i] != pw) WinStack[j++] = WinStack[i];
  366.                 WinVis = j;
  367.                 pw->vis = 0;
  368.                 }
  369.         case HIDE:
  370.             bx = pw->x; by = pw->y;
  371. #ifndef SHRINK
  372.             if(restore = CurVis) HideMouseCursor();
  373. #endif /* SHRINK */
  374.             set_background_color(pw->norm >> 4);
  375. RR((buf, "msg = %d (%s)\n", msg, msg==CLEAR?"CLEAR":(msg==HIDE?"HIDE":"?") ))
  376.             if((pw->norm >> 4) == max_color && bx == 0 && by == 0 && 
  377.                             pw->w == pixels_wide-1 && pw->h == pixels_high-1)
  378.                 {
  379. RR((buf, "clearing screen (%d*%d window)\n", pw->w, pw->h))
  380.                 clear_graphics();
  381.                 }
  382.             else
  383.                 {
  384. RR((buf, "clearing box.. color %d!=%d, %d*%d window starting at (%d,%d)\n", pw->norm>>4, max_color, pw->w, pw->h, bx, by))
  385.                 ClearBox(max(0, bx - 1), max(0, by - 1), 
  386.                                     min(pixels_wide - 1, bx + pw->w + 1), 
  387.                                     min(pixels_high - 1, by + pw->h + 1));
  388.                 }
  389. #ifndef SHRINK
  390.             if(restore) ShowMouseCursor();
  391. #endif /* SHRINK */
  392.             break;
  393.         case START_DRAGGING:
  394.             DragShape = BORDER;
  395.             b_left = xp - pw->x + 1;
  396.             b_up = yp - pw->y;
  397.             b_right = pw->w - b_left;
  398.             b_down = pw->h - b_up;
  399.                                                     /* cage cursor */
  400. #ifndef SHRINK
  401.             SetHorizontalLimits(b_left, pixels_wide - b_right - 1);
  402.             SetVerticalLimits(b_up, pixels_high - b_down - 1);
  403. #endif /* SHRINK */
  404.             break;
  405.         case MOVETO:
  406.             bx = data[0];
  407.             if(bx < 1) bx = 1;
  408.             if(bx + pw->w >= pixels_wide) bx = pixels_wide - 1 - pw->w;
  409.  
  410.             by = data[1];
  411.             if(by < 0) by = 0;
  412.             if(by + pw->h >= pixels_high) by = pixels_high - 1 - pw->h;
  413.  
  414.             pw->x = bx;
  415.             pw->y = by;
  416.             break;
  417.         case RESIZE:
  418.             bx = data[0];
  419.             if(bx < 1) bx = 1;
  420.             if(bx + pw->x >= pixels_wide) bx = pixels_wide - 1 - pw->x;
  421.  
  422.             by = data[1];
  423.             if(by < 0) by = 0;
  424.             if(by + pw->y >= pixels_high) by = pixels_high - 1 - pw->y;
  425.  
  426.             pw->w = bx;
  427.             pw->h = by;
  428.             break;
  429.         default:
  430.             ;
  431.             /* nothing */            
  432.         }
  433. }
  434.  
  435. WinCovers(pw1, pw2) WINDOW *pw1, *pw2;
  436. {    return (pw1->x <= pw2->x &&
  437.             pw1->y <= pw2->y &&
  438.             pw1->x + pw1->w >= pw2->x + pw2->w &&
  439.             pw1->y + pw1->h >= pw2->y + pw2->h);
  440. }
  441.  
  442. WinOverlaps(pw1, pw2) WINDOW *pw1, *pw2;
  443. {     return (pw2->x < pw1->x + pw1->w && 
  444.             pw2->x + pw2->w > pw1->x &&
  445.             pw2->y < pw1->y + pw1->h && 
  446.             pw2->y + pw2->h > pw1->y);
  447. }
  448.  
  449. WinShowString(s, x, y, pw) char *s; int x, y; WINDOW *pw;
  450. {
  451.     if(pw->vis == 0)(*pw->accept)(REDRAW, NULL, pw);
  452.     set_color(pw->norm & 0x0f);
  453.     set_background_color(pw->norm >> 4);
  454.     gotoxy(pw->x + x, pw->y + y);
  455.     (*draw_text)(s);
  456. }
  457.  
  458. WinGetString(query, s, appending, x, y, pw) 
  459. char *query, *s; 
  460. int appending, x, y; 
  461. WINDOW *pw;
  462. {
  463.     pw->text = query;
  464.     (*pw->accept)(REDRAW, NULL, pw);
  465.     return getse(s, appending, pw->x + x, pw->y + y, pw->w - x, pw->norm, 
  466.                                                                     pw->high);
  467. }
  468.  
  469.     /*    
  470.         queued message i has three parts: 
  471.             qm_msg[i]    message number
  472.             qm_data[i]    the associated data (four integers)
  473.             qm_pw[i]    pointer to the addressee (a window)
  474.  
  475.         xx[msgHead] is where the next message will be placed
  476.         xx[msgTail] has the next message to be delivered
  477.         (where xx is one of the above three arrays)
  478.  
  479.         When msgHead == msgTail, the queue is empty.  xx[msgHead] is
  480.         always unused, but when (msgHead + 1)%MAXMSG == msgTail, the
  481.         queue is full.
  482.  
  483.         A collection of arrays is used rather than the more intuitive
  484.         array of structures because the latter doesn't work when 
  485.         DS != SS (i.e.  when messages are being deposited by the mouse
  486.         event handler).
  487.  
  488.     */ 
  489. static int msgHead, msgTail; 
  490. static MESSAGE qm_msg[MAXMSG]; 
  491. static int qm_data[MAXMSG][4]; 
  492. static WINDOW *qm_pw[MAXMSG];
  493.  
  494. deposit(msg, data, pw) MESSAGE msg; int data[]; WINDOW *pw; 
  495. {    int i, j;
  496.  
  497.     i = msgHead + 1;
  498.     if(i >= MAXMSG) i = 0;
  499.     if(i == msgTail) return;    /* queue is full - drop the message */
  500.  
  501.     qm_msg[chHead] = msg;
  502.     for (j = 0; j < 4; j++) qm_data[chHead][j] = data[j];
  503.     qm_pw[chHead] = pw;
  504.  
  505.     msgHead = i;
  506. }
  507.  
  508. deliver()
  509. {
  510.     if(msgHead != msgTail)
  511.         {
  512.         (*qm_pw[chTail]->accept)(qm_msg[chTail], qm_data[chTail], 
  513.                                                             qm_pw[chTail]);
  514.         if(++msgTail >= MAXMSG) msgTail = 0;
  515.         }
  516. }
  517.  
  518. /* ------------- menu programs --------------------------------------- */
  519.  
  520. MENU *CreateVMenu(text, pb, x, y, extra)
  521. char *text;         /* displayed at the top of this menu */
  522. BUTTON *pb;         /* an array of buttons */
  523. int x, y;            /* upper left corner of menu */
  524. int extra;            /* extra bytes to allocate at end of this MENU */
  525. {    MENU *pm;
  526.     int nb, bx, by, thisw, maxw;
  527.  
  528.     pm = (MENU *)CreateWindow(text, x, y, 
  529.                                         sizeof(MENU) - sizeof(WINDOW) + extra);
  530.  
  531.     pm->w_accept = pm->accept;
  532.     pm->accept = MsgMenu;
  533.     pm->pab = pb;
  534.  
  535.     bx = 0; by = 0;
  536.     maxw = strlen(text);
  537.     if(strlen(text)) by += char_height;    /* leave room for text */
  538.     for (nb = 0; (pb + nb)->text; nb++)
  539.         {thisw = strlen((pb + nb)->text);        /* find longest text string */
  540.         if(maxw < thisw) maxw = thisw;
  541.         }
  542.     maxw *= char_width;
  543.  
  544.     while(pb->text)
  545.         {
  546.         pb->pm = 0;
  547.         if(pb->accept == NULL) pb->accept = MsgButton;
  548.         pb->norm = pm->norm;
  549.         pb->high = pm->high;
  550.         pb->x = bx;
  551.         pb->y = by;
  552.         pb->w = maxw;
  553.         pb->h = char_height + 1;
  554.         by += char_height + 1;
  555.  
  556.         pb++;
  557.         }
  558.  
  559.     if(char_h_adjusted) pm->x = x;
  560.     else pm->x = (x/char_width)*char_width;
  561.     if(char_v_adjusted) pm->y = y;
  562.     else pm->y = (y/char_height)*char_height;
  563.  
  564.     pm->w = maxw + 1;
  565.     pm->h = by + 1;
  566.     pm->menu_style = 0;
  567.     pm->sel = 0;
  568.     pm->cButtons = nb;
  569.  
  570.     return pm;
  571. }
  572.  
  573. MENU *CreateHMenu(pb, x, y, extra) 
  574. BUTTON *pb;         /* an array of buttons */
  575. int x, y;            /* upper left corner of menu */
  576. int extra;            /* extra bytes to allocate at end of this MENU */
  577. {    MENU *pm;
  578.     int nb, bx, by, thisw, maxw;
  579.     static char dummy[] = "";
  580.  
  581.     pm = (MENU *)CreateWindow(dummy, x, y, 
  582.                                         sizeof(MENU) - sizeof(WINDOW) + extra);
  583.  
  584.     pm->w_accept = pm->accept;
  585.     pm->accept = MsgMenu;
  586.  
  587.     pm->pab = pb;
  588.  
  589.     nb = 0; bx = 0; by = 1;
  590.     while(pb->text)
  591.         {
  592.         pb->pm = 0;
  593.         if(pb->accept == NULL) pb->accept = MsgButton;
  594.         pb->norm = pm->norm;
  595.         pb->high = pm->high;
  596.         pb->x = bx;
  597.         pb->y = by;
  598.         pb->w = char_width*strlen(pb->text);
  599.         pb->h = char_height + 1;
  600.  
  601.         bx += pb->w;
  602.         if(by >= pixels_wide) break;  /* the entries won't fit on the screen */
  603.  
  604.         pb++;
  605.         nb++;
  606.         }
  607.     pm->w = bx;
  608.     pm->h = char_height + 1;
  609.  
  610.     if(char_h_adjusted) pm->x = x;
  611.     else pm->x = (x/char_width)*char_width;
  612.     if(char_v_adjusted) pm->y = y;
  613.     else pm->y = (y/char_height)*char_height;
  614.  
  615.     pm->menu_style = 1;
  616.     pm->sel = 0;
  617.     pm->cButtons = nb;
  618.  
  619.     return pm;
  620. }
  621.  
  622. void MsgMenu(msg, data, pm) MESSAGE msg; int *data; MENU *pm;
  623. {    int i, x, y, dx, dy, bx, by, origin[2], restore;
  624.     BUTTON *pb, *pbc;
  625.     MENU *pm2;
  626.  
  627.     pbc = pb = pm->pab;
  628.  
  629.     x = data[0] - pm->x;
  630.     y = data[1] - pm->y;    /* get mouse location wrt menu origin */
  631.     
  632.     for (i = 0; i < pm->cButtons; i++)
  633.         {
  634.         if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h)) 
  635.              break;
  636.         pbc++;
  637.         }
  638.     if(pbc - pb >= pm->cButtons) pbc = 0;
  639.     switch(msg)
  640.         {
  641.         case MOVETO:
  642.             if(restore = pm->vis) (*pm->accept)(HIDE, data, pm);
  643.  
  644.             bx = data[0];
  645.             if(bx < char_width) bx = char_width;
  646.             if(bx + pm->w >= pixels_wide) bx = pixels_wide - pm->w - 1;
  647.             if(!char_h_adjusted) bx -= bx%char_width;
  648.  
  649.             by = data[1];
  650.             if(by < 0) by = 0;
  651.             if(by + pm->h >= pixels_high) by = pixels_high - pm->h - 1;
  652.             if(!char_v_adjusted) by -= by%char_height;
  653.  
  654.             dx = bx - pm->x;
  655.             dy = by - pm->y;
  656.  
  657.             data[0] = bx;
  658.             data[1] = by;
  659.             (*pm->w_accept)(MOVETO, data, pm);
  660.             if(restore) (*pm->accept)(REDRAW, data, pm);
  661.  
  662.             pbc = pm->pab;
  663.             for (i = 0; i < pm->cButtons; i++)
  664.                 {
  665.                 if(pm2 = pbc->pm)
  666.                     {data[0] = pm2->x + dx;
  667.                     data[1] = pm2->y + dy;
  668.                     (*pm2->accept)(MOVETO, data, pm2);
  669.                     }
  670.                 pbc++;
  671.                 }
  672. /**/
  673.             break;
  674.         case MOVE:
  675.             x = data[0] - pm->x;
  676.             y = data[1] - pm->y;    /* get location wrt menu origin */
  677.             if(pbc)
  678.                 {if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h)) 
  679.                     break;    /* no change */
  680.                 (*pbc->accept)(NORMALIZE, data, pbc);
  681.                 }
  682.             pm->sel = -1;
  683.             origin[0] = pm->x;
  684.             origin[1] = pm->y;
  685.             for (i = 0; i < pm->cButtons; i++)
  686.                 {pbc = pb + i;
  687.                 if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h))
  688.                     {(*pbc->accept)(HIGHLIGHT, origin, pbc);
  689.                     pm->sel = i;
  690.                     break;
  691.                     }
  692.                 }
  693.             break;
  694.         case CLICK:
  695.         case RELEASE:
  696.             if(pbc) 
  697.                 (*pbc->accept)(msg, data, pbc);
  698.             break;
  699.         case REDRAW:
  700.             (*pm->w_accept)(msg, data, (WINDOW *)pm);
  701.             origin[0] = pm->x;
  702.             origin[1] = pm->y;
  703.             if(restore = CurVis) HideMouseCursor();
  704.             for (i = 0; i < pm->cButtons; i++)
  705.                 {pbc = pb + i;
  706.                 (*pbc->accept)((i == pm->sel) ? HIGHLIGHT : NORMALIZE, 
  707.                                                             origin, pbc);
  708.                 }
  709.             if(restore) ShowMouseCursor();
  710.             break;
  711.         default:
  712.             (*pm->w_accept)(msg, data, (WINDOW *)pm);
  713.         }
  714. }
  715.  
  716. inside(x, y, x1, y1, w, h) int x, y, x1, y1, w, h;
  717. {    return x1 <= x && x <= x1 + w && y1 <= y && y <= y1 + h;
  718. }
  719.  
  720. void MsgButton(msg, data, pb) MESSAGE msg; int *data; BUTTON *pb;
  721. {    int attrib, restore;
  722.  
  723.     switch(msg)
  724.         {
  725.         case NORMALIZE:
  726.             attrib = pb->norm;
  727.             goto DISPLAY_BUTTON;
  728.  
  729.         case HIGHLIGHT:
  730.             attrib = pb->high;
  731.  
  732. DISPLAY_BUTTON:
  733.             if(restore = CurVis) HideMouseCursor(); 
  734.             gotoxy(data[0] + pb->x, data[1] + pb->y + char_height);
  735.             set_color(attrib&0x0f);
  736.             set_background_color(attrib >> 4);
  737.             (*draw_text)(pb->text);
  738.             if(restore) ShowMouseCursor();
  739.             break;
  740.  
  741.         case CLICK:
  742.             ungets(pb->val);
  743.             break;
  744.         default:
  745.             ;
  746.         }
  747. }
  748.  
  749. /*    return value of chosen item, or zero */
  750. MenuResponse(pm) MENU *pm; 
  751. {
  752.     int cmd, current, k, next, prev, origin[4];
  753.         /* 
  754.             note we set origin immediately before each use, since the user
  755.             may have dragged the menu since the function was called.
  756.         */
  757.     
  758.     BUTTON *pb, *pbc;
  759.  
  760.     if(pm->menu_style == 0) /* vertical menu */
  761.         {next = down_char; 
  762.         prev = up_char;
  763.         }
  764.     else
  765.         {next = right_char;
  766.         prev = left_char;
  767.         }
  768.  
  769.     pb = pm->pab;
  770.  
  771.     current = pm->sel;
  772.     if(current < 0 || current >= pm->cButtons) pm->sel = current = 0;
  773.     (*pm->accept)(REDRAW, NULL, pm);
  774.  
  775.     while(1)
  776.         {
  777.         if(current != pm->sel)
  778.             {                    /* display current option */
  779.             origin[0] = pm->x;
  780.             origin[1] = pm->y;
  781.             pbc = pb + pm->sel;
  782.             (*pbc->accept)(NORMALIZE, origin, pbc);
  783.             pbc = pb + current;
  784.             (*pbc->accept)(HIGHLIGHT, origin, pbc);
  785.             pm->sel = current;        /* save key for next time */
  786.             }
  787.         cmd = key_in();
  788.  
  789.         if(pm->menu_style == 1)            /* special keys for horizontal menus */
  790.             {if(cmd == down_char) 
  791.                 cmd = RETURN;
  792.             else if(cmd == up_char) 
  793.                 cmd = ESC;
  794.             }
  795.         else if(pm->menu_style == 0)    /* special keys for vertical menus */
  796.             {if(cmd == pgup_char) 
  797.                 cmd = home_char;
  798.             else if(cmd == pgdn_char) 
  799.                 cmd = end_char;
  800.             }
  801.  
  802.         if(cmd == next)
  803.             {if (++current >= pm->cButtons) 
  804.                 current = 0;
  805.             }
  806.         else if (cmd == prev)
  807.             {if (--current<0) 
  808.                 current = pm->cButtons-1;
  809.             }
  810.         else
  811.             {switch(cmd)
  812.                 {case ESC:                            /* ESCAPE */
  813.                     return 0;
  814.                 case RETURN:                        /* CARRIAGE RETURN */
  815.                                     /* return current selection */
  816.                     return pb[current].val[0];
  817.                 case home_char:
  818.                     current = 0;
  819.                     break;
  820.                 case end_char:
  821.                     current = pm->cButtons-1;
  822.                     break;
  823.                 default:
  824.                     cmd = tolower(cmd);
  825.                     for (k = 0; k < pm->cButtons; k++)
  826.                         {if (cmd == tolower(pb[k].trigger[0])) 
  827.                             {if(k != pm->sel)
  828.                                 {
  829.                                                     /* highlight selected option */
  830.             /*                    (*pm->accept)(REDRAW, NULL, pm); */
  831.                                 origin[0] = pm->x;
  832.                                 origin[1] = pm->y;
  833.                                 pbc = pb + pm->sel;
  834.                                 (*pbc->accept)(NORMALIZE, origin, pbc);
  835.                                 pbc = pb + k;
  836.                                 (*pbc->accept)(HIGHLIGHT, origin, pbc);
  837.                                 pm->sel = k;        /* save key for next time */
  838.                                 }
  839.                             return pb[k].val[0];
  840.                             }
  841.                         }
  842.                 }
  843.             }
  844.         }    
  845. }
  846.  
  847. /* ------------- mouse programs -------------------------------------- */
  848.  
  849. extern unsigned _rax, _rbx, _rcx, _rdx;
  850.  
  851. typedef enum
  852.     {START, PRESSED, DRAGGING
  853.     } MOUSE_STATE;
  854. MOUSE_STATE state = START;
  855. static mouseInstalled = 0;
  856.  
  857. HideMouseCursor()
  858. {    
  859. #ifndef SHRINK
  860.     if(mouseInstalled) HideCursor();
  861.     CurVis = 0;
  862. #endif
  863. }
  864.  
  865. ShowMouseCursor()
  866. {    
  867. #ifndef SHRINK
  868.     if(mouseInstalled)
  869.         {ShowCursor();
  870.         CurVis = 1;
  871.         }
  872. #endif
  873. }
  874.  
  875. #ifndef __TURBOC__
  876. int IsMouse()
  877. {    unsigned int_offset, int_segment;
  878.     char instruction;
  879.  
  880. #ifndef SHRINK
  881.     _lmove(2, 0x33*4, 0, &int_offset, _showds());
  882.     _lmove(2, 0x33*4 + 2, 0, &int_segment, _showds());
  883.     if(int_offset == 0 && int_segment == 0) return 0;
  884.     _lmove(1, int_offset, int_segment, &instruction, _showds());
  885.     if(instruction == 0xcf) return 0;
  886.     _rax = 0;
  887.     _doint(0x33);
  888.     if(_rax == 0) 
  889. #endif
  890.         return 0;
  891. #ifndef SHRINK
  892.     return mouseInstalled = _rbx;
  893. #endif
  894. }
  895. #endif
  896.  
  897. HideMouse()        
  898. {
  899. #ifndef SHRINK
  900.         switch(CursorShape)
  901.             {case CROSS: flip_cross(xp, yp); break;
  902.             case BORDER:    flip_box(xp - b_left, yp - b_up, 
  903.                                                 xp + b_right, yp + b_down); 
  904.                             break;
  905.             case BOX:        flip_box(x0, y0, xp, yp); break;
  906.             case LINE:        (*flip_line)(x0, y0, xp, yp); break;
  907.             default: HideMouseCursor();
  908.             }
  909. #endif
  910. }
  911.  
  912. ShowMouse()        
  913. {
  914. #ifndef SHRINK
  915.         switch(CursorShape)
  916.             {case CROSS: flip_cross(xp, yp); break;
  917.             case BORDER:    flip_box(xp - b_left, yp - b_up, 
  918.                                                 xp + b_right, yp + b_down); 
  919.                             break;
  920.             case BOX:        flip_box(x0, y0, xp, yp); break;
  921.             case LINE:        (*flip_line)(x0, y0, xp, yp); break;
  922.             default: ShowMouseCursor();
  923.             }
  924. #endif
  925. }
  926.  
  927. #ifndef SHRINK
  928. /*
  929.     This mouse handler is called by the mouse driver (MOUSE.COM or
  930.     MOUSE.SYS).  Since it is in effect an interrupt handler, it cannot
  931.     use most DOS services since DOS isn't reentrant.  In addition, the
  932.     mouse driver assumes it is calling a large model program, whereas
  933.     this is a small model program.  The assembly language interface
  934.     reset DS and CS and uses a near CALL rather than a far CALL, but DS
  935.     and SS are still different.  This means that this program and any
  936.     program it calls can use statics, locals, and pointers to statics,
  937.     but not pointers to locals (since pointers are always dereferenced
  938.     using DS).  This also means local arrays can't be passed to a
  939.     function.
  940. */
  941. void far MouseHandler(trigger, status, hor, ver) int trigger, status, hor, ver;
  942. {    static int data[4], flag = 0;
  943.     int i, x1, y1;
  944. /*    char buf[80]; */
  945.     MESSAGE msg;
  946.     WINDOW *pw;
  947.  
  948.     flag++;
  949.     if(flag > 1)         /* don't permit multiple simultaneous invocations */
  950.         {flag--; return;
  951.         }
  952.     msg = INVALID;
  953.  
  954.     if(trigger & 2)    /* press left button */
  955.         {state = PRESSED;
  956.         x0 = hor; y0 = ver;
  957.         }
  958.     else if(trigger & 4)    /* release left button */
  959.         {if(state == DRAGGING) 
  960.             {
  961.             SetHorizontalLimits(0, pixels_wide - 1);    /* release cursor */
  962.             SetVerticalLimits(0, pixels_high - 1);
  963.             if(abs(x0 - xp) + abs(y0 - yp) > 3) 
  964.                 {msg = DRAG;
  965.                 data[2] = x0; data[3] = y0;
  966.                 }
  967.             else 
  968.                 {msg = CLICK;
  969.                 data[0] = x0; data[1] = y0;
  970.                 }
  971.             HideMouse();
  972.             CursorShape = NORMAL;
  973.             DragShape = BOX;
  974.             ShowMouseCursor();
  975.             }
  976.         else if(state == PRESSED) msg = CLICK;
  977.         state = START;
  978.         }
  979.     else if(trigger & 8) ungets("\033");    /* right button generates ESC */
  980.     else if(trigger & 1)         /* moving */
  981.         {if(state == PRESSED) 
  982.             {state = DRAGGING;
  983.             xp = hor; yp = ver;
  984.             HideMouse();
  985.             CursorShape = DragShape;
  986.             msg = START_DRAGGING;
  987.             ShowMouse();
  988.             }
  989.         else if(state == DRAGGING)
  990.             {HideMouse();
  991.             xp = hor; yp = ver;
  992.             CursorShape = DragShape;
  993.             ShowMouse();
  994.             }
  995.         }
  996.  
  997. /*
  998.         {if(ShowingCross) 
  999.             {flip_cross(xp, yp); ShowingCross = 0; 
  1000.             x0 = xp = hor;
  1001.             y0 = yp = ver;
  1002.             ShowingBox = 1;
  1003.             }
  1004.         else if(ShowingBox) 
  1005.             {flip_box(x0, y0, xp, yp); ShowingBox = 0; 
  1006.             ShowMouseCursor();
  1007.             }
  1008.         else 
  1009.             {HideMouseCursor(); 
  1010.             xp = hor; yp = ver; 
  1011.             flip_cross(xp, yp); ShowingCross = 1;
  1012.             }
  1013.         }
  1014.  
  1015.     if(trigger &  1) msg = MOVE;
  1016.     if(trigger &  2) msg = PRESS;
  1017.     if(trigger &  4) msg = RELEASE;
  1018.     if(trigger &  8) msg = PRESSR;
  1019.     if(trigger & 16) msg = RELEASER;
  1020. */
  1021.  
  1022.     data[0] = hor; data[1] = ver;
  1023.     if(msg != INVALID)
  1024.         {
  1025.         if(msg == DRAG || msg == START_DRAGGING) {x1 = x0; y1 = y0;}
  1026.         else {x1 = hor; y1 = ver;}
  1027.         for (i = WinVis; i--; )
  1028.             {pw = WinStack[i];
  1029.             if(inside(x1, y1, pw->x, pw->y, pw->w, pw->h))
  1030.                 {
  1031.                 deposit(msg, data, pw);
  1032.                 break;
  1033.                 }
  1034.             }
  1035.         }
  1036.     flag--;
  1037. }
  1038. #endif /* SHRINK */
  1039. /*
  1040. SetEventHandler (mask, handler)
  1041.     int mask;
  1042.     mask    weight    meaning
  1043.     0          1        change cursor position
  1044.     1        2        press left button
  1045.     2        4        release left button
  1046.     3        8        press right button
  1047.     4        16        release right button
  1048.     5-15             not used
  1049.  
  1050.     int *handler()
  1051.          called as: (*handler)(trigger, buttonStatus, horizontal, vertical)
  1052.           trigger = mask with condition bit set that triggered call
  1053.      buttonStatus = button state (bit 0 = left, bit 1 = right)
  1054.        horizontal = horizontal cursor position
  1055.          vertical = vertical cursor position
  1056. */
  1057.  
  1058. /* ------------- graphics programs ----------------------------------- */
  1059.  
  1060. box(x0, y0, x1, y1) int x0, y0, x1, y1;
  1061. {
  1062.     (*draw_line)(x0, y0, x0, y1);
  1063.     (*draw_line)(x1, y1, x0, y1);
  1064.     (*draw_line)(x1, y1, x1, y0);
  1065.     (*draw_line)(x0, y0, x1, y0);
  1066. }
  1067.  
  1068. flip_cross(x, y) int x, y;
  1069. {
  1070.     (*flip_line)(0, y, pixels_wide-1, y);
  1071.     (*flip_line)(x, 0, x, pixels_high-1);
  1072. }
  1073.  
  1074. flip_box(x0, y0, x1, y1) int x0, y0, x1, y1;
  1075. {
  1076. #ifndef SHRINK
  1077.     HideMouseCursor();
  1078.     (*flip_line)(x0, y0, x0, y1);
  1079.     (*flip_line)(x1, y1, x0, y1);
  1080.     (*flip_line)(x1, y1, x1, y0);
  1081.     (*flip_line)(x0, y0, x1, y0);
  1082.     ShowMouseCursor();
  1083. #endif
  1084. }
  1085.  
  1086. ClearBox(x1, y1, x2, y2) int x1, y1, x2, y2;
  1087. {    int t;
  1088.     if (y2 < y1) {t = y1; y1 = y2; y2 = t;}
  1089.     while(y1 < y2) {(*erase_line)(x1, y1, x2, y1); y1++;}
  1090. }
  1091.  
  1092. /* ------------- test program ---------------------------------------- */
  1093. #ifdef MAIN
  1094.  
  1095. show_window(pw) WINDOW *pw;
  1096. {    printf("window...\n");
  1097.     printf("        text  \"%s\"\n", pw->text);
  1098.     printf("message handler at %04x\n", pw->accept);
  1099.     printf("      origin  (%3d,%3d)\n", pw->x, pw->y);
  1100.     printf("        size  (%3d,%3d)\n", pw->w, pw->h);
  1101.     printf("window style  %d\n", pw->window_style);
  1102.     printf("border style  %d\n", pw->border_style);
  1103.     printf("        norm  %02x\n", pw->norm);
  1104.     printf("        high  %02x\n", pw->high);
  1105. }
  1106.  
  1107. show_button(pb) BUTTON *pb;
  1108. {    printf("button...\n");
  1109.     printf("              text  \"%0.20s\"\n", pb->text);
  1110.     printf("           trigger  \"%0.20s\"\n", pb->trigger);
  1111.     printf("               val  \"%0.20s\"\n", pb->val);
  1112.     printf("message handler at  %04x\n", pb->accept);
  1113.     printf("          child at  %04x\n", pb->pm);
  1114.     printf("              high  %02x\n", pb->high);
  1115.     printf("              norm  %02x\n", pb->norm);
  1116.     printf("            origin  (%d,%d)\n", pb->x, pb->y);
  1117.     printf("              size  (%d,%d)\n", pb->w, pb->h);
  1118. }
  1119.  
  1120. show_menu(pm) MENU *pm;
  1121. {    BUTTON *pb;
  1122.     show_window(pm);
  1123.     printf("%20s %4s %4s %4s %5s %4s %4s %9s %9s\n",
  1124.     "text", "trig", "val", "hand", "child", "high", "norm", "origin", "size");
  1125.     for (pb = pm->pab; *(int *)pb; pb++) 
  1126.         {printf("%20.20s %4.4s %4.4s %04x  %04x   %02x   %02x (%3d,%3d) (%3d,%3d)\n",
  1127.             pb->text, pb->trigger, pb->val, pb->accept, pb->pm, 
  1128.             pb->high, pb->norm, pb->x, pb->y, pb->w, pb->h);
  1129.         }
  1130. }
  1131.  
  1132. char *msg_label[]={"INVALID","REDRAW","CLEAR","RESIZE","MOVETO","MOVE","CLICK",
  1133.                             "CLICKR","DRAG","RELEASE","HIGHLIGHT","NORMALIZE"};
  1134.  
  1135. BUTTON astuff[] =
  1136.     {
  1137.         {" file ", "f", "f"},
  1138.           {" big  ", "b", "b"},
  1139.         {" edit ", "e", "e"},
  1140.         {" view ", "v", "v"},
  1141.         {" quit ", "q", "q"},
  1142.         {0}
  1143.     };
  1144. BUTTON fButtons[] =
  1145.     {
  1146.         {" save ", "s", "s"},
  1147.         {" load ", "l", "l"},
  1148.         {" new ",  "n", "n"},
  1149.         {" quit ", "q", "q"},
  1150.         {" beep ", "b", "b"},
  1151.         {0}
  1152.     };
  1153. BUTTON bButtons[] =
  1154.     {
  1155.         {" at astra per aspera ", "a", "a"},
  1156.         {" be prepared ","b", "b"},
  1157.         {" don't tread on me ", "d", "d"},
  1158.         {" I shall return ", "i", "i"},
  1159.         {" if anything can go wrong, it will ", "i", "i"},
  1160.         {" live free or die ", "l", "l"},
  1161.         {" mind your own business ", "m", "m"},
  1162.         {" Murphy was an optimist ", "u", "u"},
  1163.         {" old soldiers never die ", "o", "o"},
  1164.         {" there's no such thing as a free lunch ", "t", "t"},
  1165.         {" use it or lose it ", "u", "u"},
  1166.         {0}
  1167.     };
  1168. BUTTON eButtons[] =
  1169.     {
  1170.         {" cross ",   "c", "c"},
  1171.         {" replace ", "r", "r"},
  1172.         {" delete ",  "d", "d"},
  1173.         {" box ",     "b", "b"},
  1174.         {" line ",    "l", "l"},
  1175.         {0}
  1176.     };
  1177. BUTTON vButtons[] =
  1178.     {
  1179.         {" zoom ", "z", "z"},
  1180.         {" pan ",  "p", "p"},
  1181.         {0}
  1182.     };
  1183.  
  1184. MENU *amen, *fmen, *bmen, *emen, *vmen, stack_array[30], **mstack = &stack_array[30];
  1185. WINDOW *bwin;
  1186.  
  1187. AddLine(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
  1188. {
  1189.     if(msg == DRAG) 
  1190.         {
  1191. #ifndef SHRINK
  1192.         HideMouseCursor();
  1193. #endif /* SHRINK */
  1194.         (*draw_line)(data[0], data[1], data[2], data[3]);
  1195. #ifndef SHRINK
  1196.         ShowMouseCursor();
  1197.         SetHorizontalLimits(0, pixels_wide - 1);
  1198.         SetVerticalLimits(0, pixels_high - 1);
  1199. #endif /* SHRINK */
  1200.         }
  1201.     else if(msg == START_DRAGGING)
  1202.         DragShape = LINE;
  1203.     else MsgWindow(msg, data, pw);
  1204. }
  1205.  
  1206. AddBox(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
  1207. {
  1208.     if(msg == DRAG) 
  1209.         {
  1210. #ifndef SHRINK
  1211.         HideMouseCursor();
  1212. #endif /* SHRINK */
  1213.         box(data[0], data[1], data[2], data[3]);
  1214. #ifndef SHRINK
  1215.         ShowMouseCursor();
  1216.         SetHorizontalLimits(0, pixels_wide - 1);
  1217.         SetVerticalLimits(0, pixels_high - 1);
  1218. #endif /* SHRINK */
  1219.         }
  1220.     else if(msg == START_DRAGGING)
  1221.         DragShape = BOX;
  1222.     else MsgWindow(msg, data, pw);
  1223. }
  1224.  
  1225. edit_menu()
  1226. {
  1227.     int ch;
  1228.     while(ch = MenuResponse(emen))
  1229.         {switch(ch)
  1230.             {case 'b':
  1231.                 bwin->accept = AddBox;
  1232.                 DragShape = BOX;
  1233.                 break;
  1234.             case 'l':
  1235.                 bwin->accept = AddLine;
  1236.                 DragShape = LINE;
  1237.                 break;
  1238.             case 'c':
  1239.                 bwin->accept = AddBox;
  1240.                 DragShape = CROSS;
  1241.                 break;
  1242.             }
  1243.         }
  1244.     (*emen->accept)(CLEAR, NULL, emen);
  1245. }
  1246.  
  1247. view_menu()
  1248. {
  1249.     int ch;
  1250.     while(ch = MenuResponse(vmen))
  1251.         {
  1252.         }
  1253.     (*vmen->accept)(CLEAR, NULL, vmen);
  1254. }
  1255.  
  1256. file_menu()
  1257. {
  1258.     int ch;
  1259.     while(ch = MenuResponse(fmen))
  1260.         {
  1261.         if(ch == 'b') putchar(7);
  1262.         }
  1263.     (*fmen->accept)(CLEAR, NULL, fmen);
  1264. }
  1265.  
  1266. big_menu()
  1267. {
  1268.     int ch;
  1269.     while(ch = MenuResponse(bmen))
  1270.         {
  1271.         if(ch == 'b') putchar(7);
  1272.         }
  1273.     (*bmen->accept)(CLEAR, NULL, bmen);
  1274. }
  1275.  
  1276. background()
  1277. {    int x0;
  1278.     for (x0 = 0; x0 < pixels_wide; x0 += 10)
  1279.         (*draw_line)(x0, 0, x0, pixels_high - 1);
  1280. }
  1281.  
  1282. main()
  1283. {    BUTTON *pb;
  1284.     WINDOW *qwin, *dwin;
  1285.     int status, hor, ver, left, right, middle, numButtons, i;
  1286.     int data[2], ch;
  1287.     char buf[128];
  1288.  
  1289.     init_graphics(); 
  1290.  
  1291. #ifndef SHRINK
  1292.     IsMouse();
  1293.  
  1294.     if(mouseInstalled)
  1295.         {
  1296.         FlagReset(&status, &numButtons);
  1297. /*        SetEventHandler(1 + 2 + 4 + 8, MouseHandler); */
  1298.  
  1299.         ShowCursor();
  1300.         getchar();
  1301.         HideCursor();
  1302.         getchar();
  1303.         ShowCursor();
  1304.         getchar();
  1305.         HideCursor();
  1306.         getchar();
  1307.         }
  1308. #endif /* SHRINK */
  1309.  
  1310.     data[0] = data[1] = 0;
  1311.  
  1312.     bwin = CreateWindow("background", char_width, 0, 0);
  1313.     bwin->w = 400;
  1314.     bwin->h = 200;
  1315.     bwin->accept = AddLine;
  1316.     bwin->border_style = 0;        /* no border */
  1317.  
  1318. /*    amen = CreateHMenu(astuff, 20, 35, 0); */
  1319.     amen = CreateVMenu("", astuff, 20, 35, 0);
  1320.  
  1321.     pb = amen->pab;
  1322.     pb->pm = fmen = CreateVMenu("", fButtons, amen->x + pb->x + char_width, 
  1323.                                                 amen->y + pb->y + pb->h, 0);
  1324.     pb++;
  1325.     pb->pm = bmen = CreateVMenu("", bButtons, amen->x + pb->x + char_width, 
  1326.                                                 amen->y + pb->y + pb->h, 0);
  1327.     pb++;
  1328.     pb->pm = emen = CreateVMenu("", eButtons, amen->x + pb->x + char_width, 
  1329.                                                 amen->y + pb->y + pb->h, 0);
  1330.     pb++;
  1331.     pb->pm = vmen = CreateVMenu("", vButtons, amen->x + pb->x + char_width, 
  1332.                                                 amen->y + pb->y + pb->h, 0);
  1333.  
  1334.     *--mstack = 0;                    /* signals the bottom of the menu stack */
  1335.  
  1336. /*
  1337.     show_menu(amen); getchar();
  1338.     show_menu(fmen); getchar();
  1339.     show_menu(bmen); getchar();
  1340.     show_menu(emen); getchar();
  1341.     show_menu(vmen); getchar();
  1342. */
  1343. /*
  1344. {FILE *dfile;
  1345.  
  1346. dfile = fopen("c:debug", "a");
  1347. fprintf(dfile, "amen = %04x\n", amen);
  1348. fprintf(dfile, "fmen = %04x\n", fmen);
  1349. fprintf(dfile, "bmen = %04x\n", bmen);
  1350. fprintf(dfile, "emen = %04x\n", emen);
  1351. fprintf(dfile, "vmen = %04x\n", vmen);
  1352. fclose(dfile);
  1353. }
  1354.     set_intensity(1.);
  1355.     set_background_intensity(0.);
  1356. */    
  1357.  
  1358.     background();
  1359.  
  1360.     qwin = CreateWindow("query window", 6*char_width, 17*char_height, 0);
  1361.     qwin->w = 40*char_width;
  1362.     qwin->h = 2*char_height;
  1363.  
  1364.     dwin = CreateWindow("display window", 6*char_width, 20*char_height, 0);
  1365.     dwin->w = 40*char_width;
  1366.     dwin->h = 2*char_height;
  1367. /*
  1368.     strcpy(buf, "2.718281828");
  1369.     WinGetString("string, no appending", buf, 0, char_width, 2*char_height, qwin);
  1370.     (*qwin->accept)(CLEAR, NULL, qwin);
  1371.  
  1372.     WinShowString(buf, char_width, 2*char_height, dwin);
  1373.     getchar();
  1374.     (*dwin->accept)(CLEAR, NULL, dwin);
  1375.  
  1376.     strcpy(buf, "3.1417");
  1377.     WinGetString("string, appending", buf, 1, char_width, 2*char_height, qwin);
  1378.     (*qwin->accept)(CLEAR, NULL, qwin);
  1379.  
  1380.     WinShowString(buf, char_width, 2*char_height, dwin);
  1381.     getchar();
  1382.     (*dwin->accept)(CLEAR, NULL, dwin);
  1383. */
  1384. /*
  1385.     if(mouseInstalled)
  1386.         WinShowString("mouse present", char_width, 2*char_height, dwin);
  1387.     else 
  1388.         WinShowString("mouse absent", char_width, 2*char_height, dwin);
  1389.     getchar();
  1390.     (*dwin->accept)(CLEAR, NULL, dwin);
  1391. */
  1392. #ifndef SHRINK
  1393.     if(mouseInstalled)
  1394.         {
  1395.         FlagReset(&status, &numButtons);
  1396.         SetEventHandler(1 + 2 + 4 + 8, MouseHandler);
  1397.  
  1398.         ShowMouseCursor(); 
  1399.         sprintf(buf, "CurVis=%d", CurVis);
  1400.         WinShowString(buf, char_width, 2*char_height, dwin);
  1401.         getchar();
  1402.         ShowCursor(); putchar(7);
  1403.         WinShowString("ShowCursor() called", char_width, 2*char_height, dwin);
  1404.         getchar();
  1405.         (*dwin->accept)(CLEAR, NULL, dwin);
  1406.         }
  1407. #endif
  1408.  
  1409.     (*bwin->accept)(REDRAW, NULL, bwin);
  1410.  
  1411.     while(ch = MenuResponse(amen))
  1412.         {if(ch == 'q') break;
  1413.         if(ch == 'f') file_menu();
  1414.         if(ch == 'b') big_menu();
  1415.         if(ch == 'e') edit_menu();
  1416.         if(ch == 'v') view_menu();
  1417.         }
  1418.     (*amen->accept)(CLEAR, NULL, amen);
  1419.     
  1420. #ifndef SHRINK
  1421.     if(mouseInstalled)
  1422.         {
  1423.         SetEventHandler(0, MouseHandler);
  1424.         HideMouse();
  1425.         }
  1426. #endif
  1427.  
  1428.     gotoxy(200,100);
  1429.     set_color(0);
  1430.     set_background_color(max_color);
  1431.     sprintf(buf, "character returned was %3d = %02x = '%c' ", 
  1432.                                                 ch, ch, isprint(ch)?ch:'.');
  1433.     (*draw_text)(buf);
  1434.     getchar();
  1435.  
  1436.     finish_graphics(); 
  1437.  
  1438.     if(!mouseInstalled) printf("there is no mouse installed");
  1439.  
  1440.     printf("\nbye!");
  1441. }
  1442.  
  1443. #endif /* MAIN */
  1444.  
  1445.