home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / toswinsc.zoo / winmenu.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  8KB  |  401 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include <stdlib.h>
  13. #include <stddef.h>
  14. #include <string.h>
  15. #include <osbind.h>
  16. #include <gemfast.h>
  17. #include "xgem.h"
  18. #include "twdefs.h"
  19.  
  20. #define FM_COPY 3
  21.  
  22. /* given a mouse x and y coordinate
  23.  * (msx, msy) and the x, y coordinate
  24.  * of a menu bar, find which of the
  25.  * bar's menus should be displayed
  26.  * (if any), On return, the (x,y)
  27.  * coordinate at which the drop-down
  28.  * should be placed is put in *xp and
  29.  * *yp
  30.  */
  31.  
  32. /* if we're *way* outside of the menu area,
  33.  * make the menu go away
  34.  */
  35.  
  36. #define GOAWAY ((MENU *)-1L)
  37.  
  38. static MENU *
  39. whichmenu(bar, barx, bary, msx, msy, xp, yp)
  40.     MENU *bar;
  41.     int barx, bary, msx, msy;
  42.     int *xp, *yp;
  43. {
  44.     MENU *m;
  45.     int xpixel;
  46.     int leftx;
  47.  
  48.     if (msx < barx || msy < bary)
  49.         return GOAWAY;
  50.  
  51.     if (msy > bary+gl_hbox)
  52.         return 0;
  53.     xpixel = barx;
  54.     m = bar;
  55.     while(m) {
  56.         leftx = xpixel;
  57.         xpixel += gl_wchar * (strlen(m->title)+2);
  58.         if (msx < xpixel) {
  59.             *xp = leftx+1;
  60.             *yp = bary+gl_hbox;
  61.             return m;
  62.         }
  63.         m = m->next;
  64.     }
  65.     return 0;
  66. }
  67.  
  68.  
  69. /*
  70.  * create an object for a drop down menu, with
  71.  * upper corner (x, y)
  72.  */
  73.  
  74. static OBJECT *
  75. makemenu(m, x, y)
  76.     MENU *m;
  77.     int x, y;
  78. {
  79.     extern int entrylen __PROTO(( ENTRY * ));
  80.     extern char *entrystr __PROTO(( ENTRY *, int ));
  81.  
  82.     OBJECT *popobj;
  83.     ENTRY *e;
  84.     int numobjects, wide, i;
  85.  
  86.     numobjects = 1;
  87.     wide = 0;
  88.  
  89.     for (e = m->contents; e; e = e->next) {
  90.         numobjects++;
  91.         if ( (i = entrylen(e)) > wide)
  92.             wide = i;
  93.     }
  94.     popobj = malloc(numobjects * sizeof(OBJECT));
  95.     if (!popobj) return 0;
  96. /* first, create the box around the menu */
  97.     popobj[0].ob_next = -1;
  98.     popobj[0].ob_head = 1;
  99.     popobj[0].ob_tail = numobjects - 1;
  100.     popobj[0].ob_type = G_BOX;
  101.     popobj[0].ob_flags = LASTOB; popobj[0].ob_state = NORMAL;
  102.     popobj[0].ob_spec = 0x00ff1100L;
  103.     popobj[0].ob_x = x/gl_wchar; popobj[0].ob_y = y/gl_hchar;
  104.     popobj[0].ob_width = wide;
  105.     popobj[0].ob_height = numobjects - 1;
  106.  
  107.     i = 1;
  108.     for (e = m->contents; e; e = e->next) {
  109.         popobj[i].ob_next = (e->next) ? i+1 : 0;
  110.         popobj[i].ob_head = popobj[i].ob_tail = -1;
  111.         popobj[i].ob_type = G_STRING;
  112.         popobj[i].ob_flags = NONE;
  113.         popobj[i].ob_state = e->state;
  114.         popobj[i].ob_spec = (long)entrystr(e, wide);
  115.         if (!popobj[i].ob_spec) return 0;
  116.         popobj[i].ob_x = 0; popobj[i].ob_y = i - 1;
  117.         popobj[i].ob_width = wide; popobj[i].ob_height = 1;
  118.         i++;
  119.     }
  120.     popobj[i-1].ob_flags = LASTOB;
  121.  
  122. /* now, fix up the object tree */
  123.     for (i = 0; i < numobjects; i++)
  124.         rsrc_obfix(popobj, i);
  125.  
  126.     popobj[0].ob_x = x;
  127.     popobj[0].ob_y = y;
  128.  
  129.     return popobj;
  130. }
  131.  
  132. static void
  133. freeobj(obj)
  134.     OBJECT *obj;
  135. {
  136.     int i;
  137.  
  138.     for (i = 1; i; i++) {
  139.         free((void *)obj[i].ob_spec);
  140.         if (obj[i].ob_flags & LASTOB)
  141.             break;
  142.     }
  143.     free(obj);
  144. }
  145.  
  146. #define screen_planes gl_screenplanes
  147.  
  148. static MFDB scr_mfdb;
  149.  
  150. static void
  151. savearea(mfdb, x, y, w, h)
  152.     MFDB *mfdb;
  153.     int x, y, w, h;
  154. {
  155.     int blitrec[8];
  156.  
  157.     blitrec[0] = x;
  158.     blitrec[1] = y;
  159.     blitrec[2] = x + w - 1;
  160.     blitrec[3] = y + h - 1;
  161.     blitrec[4] = 0;
  162.     blitrec[5] = 0;
  163.     blitrec[6] = w - 1;
  164.     blitrec[7] = h - 1;
  165.  
  166. /* mfdb->fd_addr is assumed to be set already */
  167.     mfdb->fd_w = w;
  168.     mfdb->fd_h = h;
  169.     mfdb->fd_wdwidth = ((w+15)/16);
  170.     mfdb->fd_stand = 0;
  171.     mfdb->fd_nplanes = screen_planes;
  172.  
  173.     hide_mouse();
  174.     set_clip(x, y, w, h);
  175.     vro_cpyfm(vdi_handle, FM_COPY, blitrec, &scr_mfdb, mfdb);
  176.     show_mouse();
  177. }
  178.  
  179. static void
  180. restorearea(mfdb, x, y, w, h)
  181.     MFDB *mfdb;
  182.     int x, y, w, h;
  183. {
  184.     int blitrec[8];
  185.  
  186.     blitrec[0] = 0;
  187.     blitrec[1] = 0;
  188.     blitrec[2] = w-1;
  189.     blitrec[3] = h-1;
  190.     blitrec[4] = x;
  191.     blitrec[5] = y;
  192.     blitrec[6] = x+w-1;
  193.     blitrec[7] = y+h-1;
  194.  
  195.     hide_mouse();
  196.     set_clip(x, y, w, h);
  197.     vro_cpyfm(vdi_handle, FM_COPY, blitrec, mfdb, &scr_mfdb);
  198.     show_mouse();
  199. }
  200.  
  201. /*
  202.  * deal with user interactions with a drop-down menu bar
  203.  * (x,y) is the upper left hand corner of the region
  204.  * containing the bar
  205.  */
  206.  
  207. void
  208. dropdown_menu(bar, x, y)
  209.     MENU *bar;
  210.     int x,y;
  211. {
  212.     OBJECT *popobj = 0;
  213.     MENU *m, *lastm, *tmpm;
  214.     ENTRY *e;
  215.     int i;
  216.     int w, h;
  217.     int event, msx, msy, mbutton, mbreturn, keycode, dummy;
  218.     int curobj = -1;
  219.     int newobj;
  220.     unsigned lowbyte, hibyte;
  221.     int barx, bary;
  222.     long blitbuf;
  223.     MFDB blit_mfdb;
  224.     int newx, newy;
  225.     int drawn = 0;
  226.     int winhandle;
  227.     int winowner;
  228.  
  229.     wind_update(BEG_MCTRL);
  230. /* check to see that we have the right top window */
  231.     wind_get(0, WF_TOP, &winhandle, &winowner, &dummy, &dummy);
  232.     if (!gl_topwin ||
  233.         gl_topwin->wi_handle != winhandle) {
  234.         wind_update(END_MCTRL);
  235.         return;
  236.     }
  237.  
  238.     barx = x;
  239.     bary = y;
  240.  
  241.     msx = msy = 0;
  242.     event = evnt_multi(MU_M1,
  243.         2, 0x0001, 0x0001,
  244.         1, msx, msy, 1, 1,
  245.         0, 0, 0, 0, 0,
  246.         0L, 0L,
  247.         &msx, &msy, &mbutton, &dummy,
  248.         &keycode, &mbreturn);
  249.  
  250.     wind_get(0, WF_SCREEN, &hibyte, &lowbyte, &dummy, &dummy);
  251.     blitbuf = ((long)hibyte << 16L) | lowbyte;
  252.  
  253.     blit_mfdb.fd_addr = blitbuf;
  254. /*
  255.  * find which (if any) menu should be displayed
  256.  */
  257.  
  258.  
  259.     m = whichmenu(bar, barx, bary, msx, msy, &newx, &newy);
  260.     if (!m || m == GOAWAY) {
  261.         wind_update(END_MCTRL);
  262.         return;
  263.     }
  264.     lastm = 0;
  265.     w = h = 0;
  266.  
  267. /* display the tree and interact with it */
  268.  
  269.     for(;;) {
  270.         if (m != lastm) {
  271.             if (popobj) {
  272.                 freeobj(popobj);
  273.                 popobj = 0;
  274.             }
  275.             if (drawn) {
  276.                 restorearea(&blit_mfdb, x, y, w, h);
  277.                 drawn = 0;
  278.             }
  279.             if (!m || (m == GOAWAY)) {
  280.                 break;
  281.             }
  282.             lastm = m;
  283.             x = newx;
  284.             y = newy;
  285.  
  286.     /* create a new object tree */
  287.             popobj = makemenu(m, x, y);
  288.             if (!popobj) {
  289.                 break;
  290.             }
  291.     /* "-1" takes care of the bordering box */
  292.             x = popobj[0].ob_x - 1;
  293.             y = popobj[0].ob_y - 1;
  294.             if (x >= xdesk+wdesk)
  295.                 x = xdesk+wdesk-1;
  296.             if (y >= ydesk+hdesk) {
  297.                 break;
  298.             };
  299.             w = popobj[0].ob_width + 2;
  300.             h = popobj[0].ob_height + 2;
  301.             if (x + w > xdesk + wdesk) {
  302.                 w = xdesk + wdesk - x;
  303.             }
  304.             if (y + h > ydesk + hdesk)
  305.                 h = ydesk + hdesk - y;
  306.  
  307.     /* save the area we're about to draw over */
  308.             savearea(&blit_mfdb, x, y, w, h);
  309.  
  310.     /* now actually draw the object */
  311.             objc_draw(popobj, 0, 1, x, y, w, h);
  312.             drawn = 1;
  313.         }
  314.  
  315.         event = evnt_multi(MU_BUTTON|MU_M1|MU_KEYBD,
  316.             2, 0x0001, 0x0001,
  317.             1, msx, msy, 1, 1,
  318.             0, 0, 0, 0, 0,
  319.             0L, 0L,
  320.             &msx, &msy, &mbutton, &dummy,
  321.             &keycode, &mbreturn);
  322.  
  323.         if (event & MU_M1) {
  324.             if (msx >= x && msx <= x+w && msy >= y && msy <= y+h) {
  325.                 newobj = objc_find(popobj, 0, 1, msx, msy);
  326.             } else {
  327.                 newobj = -1;
  328.                 tmpm = whichmenu(bar, barx, bary, msx, msy, &newx, &newy);
  329.                 if (tmpm)
  330.                     m = tmpm;
  331.                 else if (msy - y > h + gl_hbox)
  332.                     m = GOAWAY;
  333.                 else if (msx - x > w + gl_wbox)
  334.                     m = GOAWAY;
  335.             }
  336.  
  337.             if (curobj > 0 && curobj != newobj) {
  338.                 objc_change(popobj, curobj, 0, x, y, w, h,
  339.                     NORMAL, 1);
  340.             }
  341.             curobj = newobj;
  342.             if (curobj > 0 && popobj[curobj].ob_state != DISABLED) {
  343.                 objc_change(popobj, curobj, 0,x,y,w,h,
  344.                         SELECTED, 1);
  345.             } else {
  346.                 curobj = -1;
  347.             }
  348.         }
  349.         if (event & MU_KEYBD) {
  350.             lowbyte = keycode & 0x00ff;
  351.             i = 1;
  352.             for (e = m->contents; e; e = e->next) {
  353.                 if ((lowbyte && e->keycode == lowbyte) ||
  354.                      e->keycode == keycode) {
  355.                     curobj = i;
  356.                     break;
  357.                 } else i++;
  358.             }
  359.         }
  360.         if (event & MU_BUTTON) {
  361.             break;
  362.         }
  363.     }
  364.  
  365. /* free memory allocated by `entrystr' */
  366.     if (popobj) {
  367.         freeobj(popobj);
  368.     }
  369.     if (drawn)
  370.         restorearea(&blit_mfdb, x, y, w, h);
  371.  
  372.     wind_update(END_MCTRL);
  373.     if (curobj > 0) {
  374.         for (e = m->contents; e; e = e->next) {
  375.             --curobj;
  376.             if (curobj == 0) {
  377.                 (*e->func)(e->arg);
  378.                 break;
  379.             }
  380.         }
  381.     }
  382. }
  383.  
  384. char *
  385. menustr(bar)
  386.     MENU *bar;
  387. {
  388.     static char buf[80];
  389.     char *s = buf;
  390.  
  391.     buf[0] = 0;
  392.     while(bar) {
  393.         strcat(s, " ");
  394.         strcat(s, bar->title);
  395.         strcat(s, " ");
  396.         bar = bar->next;
  397.     }
  398.     return buf[0] ? buf : 0;
  399. }
  400.  
  401.