home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / clib / progs / haswinlib / c / menu < prev    next >
Encoding:
Text File  |  1991-02-04  |  34.0 KB  |  808 lines

  1. /* >$.CLIB.C.menu
  2.  *
  3.  *      HASWIN Graphics Library
  4.  *     =========================
  5.  *
  6.  *      Copyright (C) H.A.Shaw 1990.
  7.  *              Howard A. Shaw.
  8.  *              The Unit for Space Sciences,
  9.  *              Room 165,
  10.  *              Physics Building,
  11.  *              University of Kent at Canterbury.
  12.  *              Canterbury.
  13.  *              Kent.  CT2 7NJ
  14.  *      You may use and distribute this code freely, however please leave
  15.  *      it alone.  If you find bugs (and there will be many) please contact
  16.  *      me and the master source can be modified.  If you keep me informed
  17.  *      of who you give copies of this to then I can get release upgrades
  18.  *      to them.
  19.  *
  20.  *      routines to control menus.
  21.  */
  22. #include "includes.h"
  23.  
  24. static int haswin_freemenumem(int *actual) {
  25.  
  26.         int    *blk;
  27.  
  28.         if (!actual)
  29.                 return(HASWIN_FALSE);
  30.         blk = &actual[7];
  31. /*
  32.  *      blk points at the item data for each menu item in turn.
  33.  *      blk[0]  - flags
  34.  *      blk[1]  - >= 0x8000: submenu pointer
  35.  *                <  0x7FFF: window handle
  36.  *                -1         nothing
  37.  *      blk[2]  - menu icon flags
  38.  *      blk[3]  - pointer to menu item name
  39.  *      blk[4]  - pointer to validation string(text), or sprite area, or -1
  40.  *      blk[5]  - blk[3] buffer length.
  41.  */
  42.         while ((blk[0]&0x80) != 0x80) {
  43.                 if (blk[1] >= 0x8000)
  44.                         if (!haswin_freemenumem((int *)(blk[1])))
  45.                                 return(HASWIN_FALSE);
  46.                 switch (blk[2] & 0x00000003) {
  47.                 case 0x00000001: /* a text item */
  48.                 case 0x00000003: /* a text and sprite item */
  49.                         if ((blk[4]>0x8000) && (!haswin_free((char *)(blk[4])))) {
  50.                                 haswin_errorbox("haswin_freemenumen: free fails - &blk[4]");
  51.                                 return(HASWIN_FALSE);
  52.                         }
  53.                         /* FALL THRU */
  54.                 case 0x00000002: /* a sprite item */
  55.                         if (!haswin_free((char *)(blk[3]))) {
  56.                                 haswin_errorbox("haswin_freemenumen: free fails - &blk[3]");
  57.                                 return(HASWIN_FALSE);
  58.                         }
  59.                         /* FALL THRU */
  60.                 case 0x00000000: /* not a text or sprite */
  61.                         break;
  62.                 }
  63.                 blk = &blk[6];
  64.         }
  65. /*
  66.  *      REMEMBER: the pointer actual should have been created with
  67.  *      haswin_mallocblock().
  68.  */
  69.         if (!haswin_freeblock(actual)) {
  70.                 haswin_errorbox("haswin_freemenumen: fails - actual");
  71.                 return(HASWIN_FALSE);
  72.         }
  73.         return(HASWIN_TRUE);
  74. }
  75.  
  76. menu *haswin_makemenu(menu *mu, char *str, int (*makemenu)(struct menu *), int (*domenu)(char *, struct menu *), int (*message)(buffer *, struct menu *)) {
  77.  
  78.         if (!mu) {
  79.                 mu = (menu *)haswin_malloc(sizeof(menu), "haswin_makemenu", "new menu");
  80.                 mu->menu     = 0;
  81.                 mu->actual   = 0;
  82.                 mu->extra    = 0;
  83.                 mu->makemenu = 0;
  84.                 mu->domenu   = 0;
  85.                 mu->message  = 0;
  86.                 mu->x = mu->y = 0;
  87.                 mu->topx = mu->topy = 0;
  88.                 mu->ifrom = mu->wfrom = 0;
  89.                 mu->mhelp = mu->whelp = mu->ihelp = 0;
  90.         }
  91.         if (str) {
  92.                 mu->menu = haswin_mallocblock(mu->menu, asciilen(str), "haswin_makemenu", "mu->menu");
  93.                 strcpy(mu->menu, str);
  94.         } else {
  95.                 if (mu->menu) {
  96.                         haswin_freeblock(mu->menu);
  97.                         mu->menu = 0;
  98.                 }
  99.         }
  100.         if (makemenu)
  101.                 mu->makemenu = makemenu;
  102.         if (domenu)
  103.                 mu->domenu   = domenu;
  104.         if (message)
  105.                 mu->message  = message;
  106.         return(mu);
  107. }
  108.  
  109. /*
  110.  *      build a menu.  Uses the icon building bits to create the icons
  111.  *      data within the menu.
  112.  *
  113.  *      A menu is built from a string of the following form...
  114.  *
  115.  *      [topts]title.(menu)[opts]item.(menu)[opts]item ...
  116.  *
  117.  *      topts - one of:
  118.  *            &NN     - title background colour NN, <sp>, ends.
  119.  *            $NN     - title foreground colour NN, <sp>, ends.
  120.  *            *NN     - work background colour NN, <sp>, ends.
  121.  *            @NN     - work foreground colour NN, <sp>, ends.
  122.  *            >NN     - maximum width of menu, <sp>, ends.
  123.  *            <NN     - minimum width of menu, <sp>, ends.
  124.  *            ^NN     - minimum height between lines, <sp>, ends.
  125.  *            <sp>,   - spacer, ignored.
  126.  *
  127.  *      title - title of menu (12 characters max.)
  128.  *
  129.  *      item  - item name.
  130.  *
  131.  *      opts  - one of:
  132.  *            -       - dotted menu seperator above.
  133.  *            _       - dotted menu seperator below.
  134.  *            /       - place tick at left.
  135.  *            |       - generate menuwarning message.
  136.  *            #       - item in inner menu is a window name.
  137.  *            (menu)  - inner menu, or window name (must be before options).
  138.  *
  139.  *            Note that options are passed to haswin_buildiconflags for
  140.  *            processing.  This means the following are allowed in a menu
  141.  *            item option list:
  142.  *            <sp>,   - spacer, ignored.
  143.  *            T       - Text icon.
  144.  *            S       - Sprite icon, can be combined with T.
  145.  *            B       - icon has border.
  146.  *            <       - left adjust text.
  147.  *            >       - right adjust text.
  148.  *            F       - filled background.
  149.  *            $NN     - use antialiased font NN (<sp>, ends).
  150.  *            h       - display any sprite 1/2 size.
  151.  *            ?       - icon needs help to redraw.
  152.  *            !       - do not select.
  153.  *            *       - force selection.
  154.  *            +NN     - make icon writable, buffer length NN (<sp>, ends).
  155.  *            ^       - vertical centering.
  156.  *            ~       - don't cancel on selection of another in ESG.
  157.  *            &NN     - background colour (<sp>, ends).
  158.  *            @NN     - foreground colour (<sp>, ends).
  159.  *            {str}   - validation string "str".
  160.  *            [blk]   - sprite area control block "blk".
  161.  *            :       - everything after is item name.
  162.  *            `font`  - use antialiased font called "font".
  163.  *
  164.  *      NOTE: items in '...' quotes will not be processed, the ' marks
  165.  *            are removed however.
  166.  *
  167.  *      "str" is a pointer to the string to work from
  168.  *      "width" is a pointer to an integer to return the width of this level
  169.  *      in.
  170.  *      "buf" points to a buffer to use as the working area for this menu.
  171.  *      Buf has been allocated using haswin_mallocblock() above.  If not the
  172.  *      memory allocator is going to get VERY pissed off.  The int at buf[-1]
  173.  *      is the length of the buffer.  NOTE: we must be very careful about
  174.  *      this.  If the buffer is too small then we had better reallocate it.
  175.  */   
  176.  
  177. static int *haswin_buildmenu(char *str, int *width, int *buf) {
  178.  
  179.         char            *title, *menubuf, *ptr, *ptr1, *data, *menu;
  180.         char            *itemstart, *innerstart, buff[256];
  181.         int             i, menui, menucnt, flgs, quoted, bracketcnt;
  182.         int             minwidth, gotmaxdata, windowed;
  183.         int             thiswidth, maxwidth, height, maxdata, numstate;
  184.         int             gotmenu12, gotmenu13, gotmenu14, gotmenu15;
  185.         int             charx, chary;
  186.         window          *win;
  187.  
  188.         charx = haswin_readvduvariable(VDUVAR_CharXsize);
  189.         chary = haswin_readvduvariable(VDUVAR_CharYsize);
  190.         title = menu = data = (char *)haswin_malloc(asciilen(str)+1, "haswin_buildmenu", "menu");
  191.         /* make a copy of the menu */
  192.         strcpy(title, str);
  193.         /* remove the title (up to first '.') and move menu to menu start */
  194.         while (*menu != '.')
  195.                 menu++;
  196.         *(menu++) = '\0';
  197. /* scan through menu chopping at '.' or quotes into separate menu items */
  198.         ptr = menu;
  199.         menucnt=1;
  200.         bracketcnt=0;
  201.         quoted = 0;
  202.         while (*ptr) {
  203.                 if (*ptr == '\'') {
  204.                         if (quoted)
  205.                                 quoted = HASWIN_FALSE;
  206.                         else
  207.                                 quoted = HASWIN_TRUE;
  208.                 }
  209.                 if (!quoted) {
  210.                         if (*ptr == '(')
  211.                                 bracketcnt++;
  212.                         else if (*ptr == ')')
  213.                                 bracketcnt--;
  214.                         else if ((bracketcnt == 0) && (*ptr == '.')) {
  215.                                 *ptr = '\0';
  216.                                 menucnt++;
  217.                         }
  218.                 }
  219.                 ptr++;
  220.         }
  221. /*
  222.  *      at this point menucnt is the number of items in the menu.
  223.  *      try to use "buf" as a buffer for this level of the menu.
  224.  */
  225.         menubuf = (char *)haswin_mallocblock(buf, 28+((menucnt+1)*24)+1, "haswin_buildmenu", "menu buffer");
  226.  
  227. /*
  228.  *      now scan the title options looking for colour and size info
  229.  */
  230.         gotmenu12 = gotmenu13 = gotmenu14 = gotmenu15 = thiswidth = 0;
  231.         maxwidth = 1000;
  232.         minwidth = 0;
  233.         height = 0;
  234.         ptr1 = title;
  235.         numstate = 0;
  236.         while (*ptr1) {
  237.                 if (quoted) {
  238.                         if (*ptr1 == '\'')
  239.                                 quoted = HASWIN_FALSE;
  240.                 } else {
  241.                         switch (*ptr1) {
  242.                         case '\'':
  243.                                 quoted = HASWIN_TRUE;
  244.                                 break;
  245.                         case  ' ':
  246.                                 numstate = 0;
  247.                                 break;
  248.                         case  '0':
  249.                         case  '1':
  250.                         case  '2':
  251.                         case  '3':
  252.                         case  '4':
  253.                         case  '5':
  254.                         case  '6':
  255.                         case  '7':
  256.                         case  '8':
  257.                         case  '9':
  258.                                 switch (numstate) {
  259.                                 case 1: gotmenu12++;
  260.                                         menubuf[12]=menubuf[12]*10+(*ptr1)-'0';
  261.                                         break;
  262.                                 case 2: gotmenu13++; 
  263.                                         menubuf[13]=menubuf[13]*10+(*ptr1)-'0';
  264.                                         break;
  265.                                 case 3: gotmenu14++; 
  266.                                         menubuf[14]=menubuf[14]*10+(*ptr1)-'0';
  267.                                         break;
  268.                                 case 4: gotmenu15++; 
  269.                                         menubuf[15]=menubuf[15]*10+(*ptr1)-'0';
  270.                                         break;
  271.                                 case 5: 
  272.                                         maxwidth = maxwidth*10+(*ptr1)-'0';
  273.                                         break;
  274.                                 case 6: 
  275.                                         minwidth = minwidth*10+(*ptr1)-'0';
  276.                                         break;
  277.                                 case 7: 
  278.                                         height = height*10+(*ptr1)-'0';
  279.                                         break;
  280.                                 default:
  281.                                         goto title_scan_ended;
  282.                                 }
  283.                                 break;
  284.                         /* title foreground colour */
  285.                         case '$':
  286.                                 menubuf[12] = gotmenu12 = 0;
  287.                                 numstate = 1;
  288.                                 break;
  289.                         /* title background colour */
  290.                         case '&':
  291.                                 menubuf[13] = gotmenu13 = 0;
  292.                                 numstate = 2;
  293.                                 break;
  294.                         /* work foreground colour */
  295.                         case '@':
  296.                                 menubuf[14] = gotmenu14 = 0;
  297.                                 numstate = 3;
  298.                                 break;
  299.                         /* work background colour */
  300.                         case '*':
  301.                                 menubuf[15] = gotmenu15 = 0;
  302.                                 numstate = 4;
  303.                                 break;
  304.                         case '>':
  305.                                 maxwidth = 0;
  306.                                 numstate = 5;
  307.                                 break;
  308.                         case '<':
  309.                                 minwidth = 0;
  310.                                 numstate = 6;
  311.                                 break;
  312.                         case '^':
  313.                                   height = 0;
  314.                                 numstate = 7;
  315.                                 break;
  316.                         default:
  317.                                  goto title_scan_ended;
  318.                         }
  319.                 }
  320.                 ptr1++;
  321.         }
  322. title_scan_ended:
  323.         if (quoted)
  324.                 haswin_interrorprintf("haswin_buildmenu: no terminating \' quote in menu title %s", title);
  325.         if (!gotmenu12)
  326.                 menubuf[12] =  7;
  327.         if (!gotmenu13)
  328.                 menubuf[13] =  2;
  329.         if (!gotmenu14)
  330.                 menubuf[14] = 13;
  331.         if (!gotmenu15)
  332.                 menubuf[15] =  0;
  333.         if (menubuf[12] > 15) {
  334.                 haswin_internalerror("haswin_buildmenu: $: illegal colour");
  335.                 menubuf[12] = 7;
  336.         }
  337.         if (menubuf[13] > 15) {
  338.                 haswin_internalerror("haswin_buildmenu: &: illegal colour");
  339.                 menubuf[13] = 2;
  340.         }
  341.         if (menubuf[14] > 15) {
  342.                 haswin_internalerror("haswin_buildmenu: @: illegal colour");
  343.                 menubuf[14] = 13;
  344.         }
  345.         if (menubuf[15] > 15) {
  346.                 haswin_internalerror("haswin_buildmenu: *: illegal colour");
  347.                 menubuf[15] = 0;
  348.         }
  349.         thiswidth = (asciilen(title)>12) ? 12 : asciilen(title);
  350.         if (minwidth < thiswidth)
  351.                 minwidth = thiswidth;
  352.         if (maxwidth < thiswidth)
  353.                 maxwidth = thiswidth;
  354.         if (minwidth > maxwidth)
  355.                 haswin_internalerror("haswin_buildmenu: max and min widths are odd!");
  356.         if (height < chary+4)
  357.                 height = chary + 4;
  358. /*
  359.  * minwidth is the minimum width, the greater of given or the title width.
  360.  * maxwidth is the maximum width, either 10000000 or given.
  361.  */
  362.         strncpy(menubuf, ptr1, 12);
  363.         ptr = &(menubuf[28]);
  364.         ptr1 = menu;
  365. /*
  366.  *      now we scan along each ('\0' separated) menu item
  367.  *      using haswin_buildiconflags() to build the main icon bits.
  368.  */
  369.         for (menui=0; menui<menucnt; menui++) {
  370.                 if (menui==menucnt-1)
  371.                         flgs = 0x80;
  372.                 else
  373.                         flgs = 0x00;
  374.                 maxdata = gotmaxdata = 0;
  375.                 numstate = windowed = 0;
  376.                 itemstart = ptr1;
  377.                 innerstart = (char *)0;
  378.                 while (*ptr1) {
  379.                         switch (*ptr1) {
  380.                         case  ',':
  381.                         case  ' ':
  382.                                 numstate = 0;
  383.                                 break;
  384.                         case  '0':
  385.                         case  '1':
  386.                         case  '2':
  387.                         case  '3':
  388.                         case  '4':
  389.                         case  '5':
  390.                         case  '6':
  391.                         case  '7':
  392.                         case  '8':
  393.                         case  '9':
  394.                                 if (numstate == 1) {
  395.                                         maxdata = maxdata*10+(*ptr1)-'0';
  396.                                         gotmaxdata++;
  397.                                         break;
  398.                                 } else
  399.                                         goto menu_scan_ended;
  400.                                 break;
  401.                         case  '+':
  402.                                 flgs |= 0x04;
  403.                                 maxdata = gotmaxdata = 0;
  404.                                 numstate = 1;
  405.                                 break;
  406.                         case '\'':
  407.                                 /* skip everything between ' ' marks */
  408.                                 while ((*ptr1) && (*ptr1 |= '\''))
  409.                                         ptr1++;
  410.                                 break;
  411.                         case '(':
  412.                                 ptr1++;
  413.                                 innerstart = ptr1;
  414.                                 bracketcnt = 1;
  415.                                 while ((bracketcnt > 0) && (*ptr1)) {
  416.                                         if (*ptr1 == '(')
  417.                                                 bracketcnt++;
  418.                                         else if (*ptr1 == ')')
  419.                                                 bracketcnt--;
  420.                                         ptr1++;
  421.                                 }
  422.                                 if ((!bracketcnt) && (ptr1[-1] == ')'))
  423.                                         *(--ptr1) = '\0';
  424.                                 itemstart = ptr1+1;
  425.                                 break;
  426.                         case ':':
  427.                                 goto menu_scan_ended;
  428.                         }
  429.                         ptr1++;
  430.                 }
  431. menu_scan_ended:
  432.                 haswin_buildiconflags(itemstart, 7, 0, 0, &(((int *)ptr)[2]), buff, 256);
  433.                 for (i=0; ((buff[i]) && (i<256)); i++) {
  434.                         switch (buff[i]) {
  435.                         case  '/':
  436.                                 flgs |= 0x01;
  437.                                 break;
  438.                         case  '_':
  439.                                 flgs |= 0x02;
  440.                                 break;
  441.                         case  '-':
  442.                                 if (menui > 0)
  443.                                         ((int *)ptr)[-6] |= 0x02;
  444.                                 break;
  445.                         case  '|':
  446.                                 flgs |= 0x08;
  447.                                 break;
  448.                         case  '#':
  449.                                 windowed++;
  450.                                 break;
  451.                         default:
  452.                                 haswin_interrorprintf("haswin_buildmenu: unknown option %c in menu (%s)", buff[i], str);
  453.                                 break;
  454.                         }
  455.                 }
  456.                 if (windowed) {
  457.                         if (innerstart) {
  458.                                 if ((win=haswin_findwindowname(innerstart)) == (window *)0) {
  459.                                         haswin_interrorprintf("haswin_buildmenu: cannot find a window named \"%s\" in item %s", innerstart, itemstart);
  460.                                         ((int *)ptr)[1] = -1;
  461.                                 } else
  462.                                         ((int *)ptr)[1] = win->handle;
  463.                         } else {
  464.                                 haswin_interrorprintf("haswin_buildmenu: cannot find a window name in \"()\" in item %s", itemstart);
  465.                         }
  466.                 } else if (innerstart) {
  467.                         if ((buf) && (haswin_validpointer((void *)((int *)ptr)[1])))
  468.  
  469.                                 ((int *)ptr)[1] = (int)haswin_buildmenu(innerstart, 0, (int *)(((int *)ptr)[1]));
  470.                         else
  471.                                 ((int *)ptr)[1] = (int)haswin_buildmenu(innerstart, 0, 0);
  472.                 } else
  473.                         ((int *)ptr)[1] = -1;
  474.                 ((int *)ptr)[0] = flgs;
  475.                 if ((thiswidth=asciilen(ptr1)) > minwidth)
  476.                         minwidth = thiswidth;
  477.                 while (*ptr1)
  478.                         ptr1++;
  479.                 ptr1++;
  480.                 ptr+=24;
  481.         }
  482.         if (minwidth > maxwidth)
  483.                 minwidth = maxwidth;
  484.         ((int *)menubuf)[4]  = minwidth*charx;
  485.         ((int *)menubuf)[5]  = height;
  486.         ((int *)menubuf)[6]  = 0;
  487.         if (width)
  488.                 *width = minwidth+2;
  489.         if (!haswin_free(title))
  490.                 haswin_errorbox("haswin_buildmenu: haswin_free() fails");
  491.         return((int *)menubuf);
  492. }
  493.  
  494. /*
  495.  *      given an icon, window and extra create a correct menu extra field.
  496.  *      This is used by the routine "haswin_createmenu()" and
  497.  *      "haswin_recreatemenu()".
  498.  */
  499. static char *haswin_createmenuextra(window *win, icon *ic, char *extra) {
  500.  
  501.         register char   *ptr;
  502.         window          *wptr;
  503.  
  504. /*
  505.  *      we build the extra data for the menu we have.  Note that the
  506.  *      max we can add is:
  507.  */
  508. #define MENU_EXTRA asciilen(".-%s.-(infomation)#:Info.(Action.:/Open.:/Close):Window.((file_load)#!:Load.(file_save)#!:Save.(Options./:Add./:Replace):Options):!Files.(Help on.%c:Icon.%c:Window.%c:Menu):!Help.-:Quit")
  509.  
  510.         if ((extra) && (extra[0] != '\0')) {
  511.                 ptr = haswin_malloc(MENU_EXTRA + asciilen(extra),
  512.                         "haswin_createmenuextra", "string");
  513.                 sprintf(ptr, ".-%s", extra);
  514.         } else {
  515.                 ptr = haswin_malloc(MENU_EXTRA,
  516.                         "haswin_createmenuextra", "string");
  517.                 ptr[0] = '\0';
  518.         }
  519.         /* Are we on the icon bar with an Information window to open ? */
  520.         if ((ic) && (ic->whandle < 0) && (haswin_flags & HASWIN_FLAGS_INFOWIN))
  521.                 strcat(ptr, ".(information)#-:Info.");
  522.         else
  523.                 strcat(ptr, ".-!:Info.");
  524.         /* do we have an icon with a window to open ? */
  525.         if ((ic) && (ic->window)) {
  526.                 if (haswin_getwindowflags(ic->window) & WINDOW_OPEN)
  527.                         strcat(ptr, "(Action./:Open.:Close):Window");
  528.                 else
  529.                         strcat(ptr, "(Action.:Open./:Close):Window");
  530.         } else
  531.                 strcat(ptr, "!:Window");
  532.         if ((ic) && (ic->whandle < 0) && (haswin_flags & HASWIN_FLAGS_FILEMENU)) {
  533.                 strcat(ptr, ".(Filing.(file_load)#");
  534.                 if (!haswin_loadfileroutine)
  535.                         strcat(ptr, "!");
  536.                 strcat(ptr, ":Load.(file_save)#");
  537.                 if (!haswin_savefileroutine)
  538.                         strcat(ptr, "!");
  539.                 strcat(ptr, ":Save.(Options.");
  540.                 if (haswin_fileoptions & HASWIN_OPTIONS_ADD)
  541.                         strcat(ptr, "/:Add.:Replace):Options):Files");
  542.                 else
  543.                         strcat(ptr, ":Add./:Replace):Options):Files");
  544.         }
  545.         strcat(ptr, ".(Help on.");
  546.         if ((ic) && (ic->help)) {
  547.                 haswin_menu.ihelp = ic->help;
  548.                 strcat(ptr, "/");
  549.         } else {
  550.                 haswin_menu.ihelp = (window *)0;
  551.                 strcat(ptr, "!");
  552.         }
  553.         strcat(ptr, ":Icon.");
  554.         if (ic)
  555.                 wptr = haswin_findwindowhandle(ic->whandle);
  556.         else
  557.                 wptr = (window *)0;
  558.         if (((int)win > 0) && (win->help)) {
  559.                 haswin_menu.whelp = win->help;
  560.                 strcat(ptr, "/");
  561.         } else if ((ic) && ((wptr=haswin_findwindowhandle(ic->whandle)) != 0) && (wptr->help)) {
  562.                 haswin_menu.whelp = wptr->help;
  563.                 strcat(ptr, "/");
  564.         } else {
  565.                 haswin_menu.whelp = (window *)0;
  566.                 strcat(ptr, "!");
  567.         }
  568.         strcat(ptr, ":Window.");
  569.         if ((ic) && (ic->menu) && (ic->menu->mhelp)) {
  570.                 haswin_menu.mhelp = ic->menu->mhelp;
  571.                 strcat(ptr, "/");
  572.         } else if (((int)win > 0) && (win->menu) && (win->menu->mhelp)) {
  573.                 haswin_menu.mhelp = win->menu->mhelp;
  574.                 strcat(ptr, "/");
  575.         } else {
  576.                 haswin_menu.mhelp = (window *)0;
  577.                 strcat(ptr, "!");
  578.         }
  579.         strcat(ptr, ":Menu):Help");
  580.  
  581.         /* do we have an icon with a QUIT ? */
  582.         if ((ic) && (ic->flags & ICON_CANQUIT))
  583.                 strcat(ptr, ".-:Quit");
  584.         return(ptr);
  585. }
  586.  
  587. /*
  588.  *      given an icon and window create a menu.  The icon takes priority
  589.  *      over the window.  The 'extra' is added to the menu.  The 'user'
  590.  *      routine takes priority over any existing routine.
  591.  *      X and Y are the positions to create the menu at.  We adjust so that
  592.  *      X is in the middle of the top level menu.
  593.  *
  594.  *      The chosing of the text string for the menu is actually the easy bit
  595.  *      haswin_buildmenu() above actually does all the clever stuff.  We keep
  596.  *      a record of the window, icon and extra fields we are given in case
  597.  *      we have to recreate the menu later with haswin_recreatemenu() below.
  598.  *      If called with window==0, icon==0 and extra==0 then remove any menu.
  599.  */
  600. static int      haswin_menuwindow = 0;
  601. static int      haswin_menuicon = 0;
  602. static char     *haswin_menuextra = 0;
  603.  
  604. int haswin_createmenu(window *win, icon *ic, char *extra,
  605.                         int (*user)(char *, menu *), int x, int y) {
  606.  
  607.         static char     *menu_total = 0;
  608.         int             i, charx;
  609.         register char   *ptr;
  610.         char            *ptr1;
  611.         _kernel_swi_regs  regs;
  612.  
  613.         if ((!win) && (!ic) && (!extra)) {
  614.                 if (haswin_menu.actual != 0) {
  615.                         /* first free the menu we already have */
  616.                         if (haswin_menu.menu) {
  617.                                 if (!haswin_freeblock(haswin_menu.menu))
  618.                                         haswin_internalerror("haswin_createmenu: failed to free haswin_menu.menu");
  619.                                 haswin_menu.menu = 0;
  620.                         }
  621.                         if (!haswin_freemenumem(haswin_menu.actual))
  622.                                 haswin_internalerror("haswin_createmenu: failed to freemenumem haswin_menu.actual");
  623.                         haswin_menu.actual = 0;
  624.                 }
  625.                 regs.r[1] = -1;
  626.                 return(haswin_swi(HASWIN_Create_menu, ®s));
  627.         }
  628. /*
  629.  *      we do the menu if...
  630.  *      1)  We have an extra field,
  631.  *      or
  632.  *      2)  We have an ic on the icon bar, with a loadfileroutine or a
  633.  *          savefileroutine,
  634.  *      or
  635.  *      3)  We have an ic with ic->menu or ic->window or ic->help or
  636.  *          ic->flags ICON_CANQUIT,
  637.  *      or
  638.  *      4)  We have a win with win->menu or win->help.
  639.  */
  640.         if (!(extra || (((int)win > 0) && (win->menu || win->help)) ||
  641.              (ic && (((ic->whandle < 0) && (haswin_loadfileroutine || haswin_savefileroutine)) || ic->menu || ic->window || ic->help || (ic->flags&ICON_CANQUIT))) ))
  642.                 return(HASWIN_FALSE);
  643.  
  644.         if (haswin_menu.actual != 0) {
  645.                 /* first free the menu we already have */
  646.                 if (haswin_menu.menu) {
  647.                         if (!haswin_freeblock(haswin_menu.menu))
  648.                                 haswin_internalerror("haswin_createmenu: failed to free haswin_menu.menu");
  649.                         haswin_menu.menu = 0;
  650.                 }
  651.                 if (!haswin_freemenumem(haswin_menu.actual))
  652.                         haswin_internalerror("haswin_createmenu: failed to freemenumem haswin_menu.actual");
  653.                 haswin_menu.actual = 0;
  654.         }
  655.  
  656.         if ((int)win > 0)
  657.                 haswin_menuwindow = win->handle;
  658.         else
  659.                 haswin_menuwindow = (int)win;
  660.         if ((int)ic > 0)
  661.                 haswin_menuicon = ic->ihandle;
  662.         else
  663.                 haswin_menuicon = (int)ic;
  664.         if (extra) {
  665.                 haswin_menuextra = haswin_realloc(haswin_menuextra,
  666.                                            asciilen(extra)+1,
  667.                                            "haswin_createmenu",
  668.                                            "menu extra string");
  669.                 strcpy(haswin_menuextra, extra);
  670.         } else {
  671.                 haswin_menuextra = haswin_realloc(haswin_menuextra, 1,
  672.                                            "haswin_createmenu",
  673.                                            "menu extra string");
  674.                 haswin_menuextra[0] = '\0';
  675.         }
  676.         ptr1 = haswin_createmenuextra(win, ic, extra);
  677. /*
  678.  *      the "extra, ihelp, mhelp, whelp" fields are now setup.
  679.  */
  680.         if (ic) {
  681.                 /* if we have an icon then we use it */
  682.                 if (ic->menu) {
  683.                         /* the icon has a menu, so copy it into the one to
  684.                            create */
  685.                         haswin_menu.x = ic->menu->x;
  686.                         haswin_menu.y = ic->menu->y;
  687.                         haswin_menu.ifrom = ic->menu->ifrom;
  688.                         haswin_menu.wfrom = ic->menu->wfrom;
  689.                         haswin_menu.makemenu = ic->menu->makemenu;
  690.                         haswin_menu.domenu = ic->menu->domenu;
  691.                         haswin_menu.message = ic->menu->message;
  692.                         if (ic->menu->menu) {
  693.                                 haswin_menu.menu = haswin_mallocblock(0, asciilen(ic->menu->menu)+1,"haswin_createmenu", "icon menu menu");
  694.                                 strcpy(haswin_menu.menu, ic->menu->menu);
  695.                         } else {
  696.                                 haswin_menu.menu = haswin_mallocblock(0, 1, "haswin_createmenu", "icon menu menu");
  697.                                 haswin_menu.menu[0] = '\0';
  698.                         }
  699.                 } else {
  700.                         /* the icon has no menu, so invent one.  Use the
  701.                            icon name as the title. */
  702.                         ptr = haswin_geticonname(ic);
  703.                         haswin_menu.menu = haswin_mallocblock(0, asciilen(ptr)+1,"haswin_createmenu", "icon name");
  704.                         strcpy(haswin_menu.menu, ptr);
  705.                         haswin_menu.ifrom = ic->ihandle;
  706.                         haswin_menu.wfrom = ic->whandle;
  707.                         haswin_menu.x = 0;
  708.                         haswin_menu.y = 0;
  709.                         haswin_menu.makemenu = 0;
  710.                         haswin_menu.domenu = 0;
  711.                         haswin_menu.message = 0;
  712.                 }
  713.         } else if ((int)win > 0) {
  714.                 /* if we have a window then try it */
  715.                 if (win->menu) {
  716.                         /* the window has a menu, so copy it into the one
  717.                            to create */
  718.                         haswin_menu.x = win->menu->x;
  719.                         haswin_menu.y = win->menu->y;
  720.                         haswin_menu.ifrom = win->menu->ifrom;
  721.                         haswin_menu.wfrom = win->menu->wfrom;
  722.                         haswin_menu.makemenu = win->menu->makemenu;
  723.                         haswin_menu.domenu = win->menu->domenu;
  724.                         haswin_menu.message = win->menu->message;
  725.                         if (win->menu->menu) {
  726.                                 haswin_menu.menu = haswin_mallocblock(0, asciilen(win->menu->menu)+1, "haswin_createmenu", "window menu menu");
  727.                                 strcpy(haswin_menu.menu, win->menu->menu);
  728.                         } else {
  729.                                 haswin_menu.menu = haswin_mallocblock(0, 1, "haswin_createmenu", "icon menu menu");
  730.                                 haswin_menu.menu[0] = '\0';
  731.                         }
  732.                 } else {
  733.                         /* the window has no menu, so invent one.  Use the
  734.                            window name as the title. */
  735.                         ptr = haswin_getwindowname(win);
  736.                         haswin_menu.menu = haswin_mallocblock(0, asciilen(ptr)+1, "haswin_createmenu", "window name");
  737.                         strcpy(haswin_menu.menu, ptr);
  738.                         haswin_menu.ifrom = -1;
  739.                         haswin_menu.wfrom = win->handle;
  740.                         haswin_menu.x = 0;
  741.                         haswin_menu.y = 0;
  742.                         haswin_menu.makemenu = 0;
  743.                         haswin_menu.domenu = 0;
  744.                         haswin_menu.message = 0;
  745.                 }
  746.         } else {
  747.                 /* we have neither icon nor window, so create a blank menu */
  748.                 haswin_menu.menu = haswin_mallocblock(0, 5, "haswin_createmenu", "Menu name");
  749.                 strcpy(haswin_menu.menu, "Menu");
  750.                 haswin_menu.ifrom = -1;
  751.                 haswin_menu.wfrom = -1;
  752.                 haswin_menu.x = 0;
  753.                 haswin_menu.y = 0;
  754.                 haswin_menu.makemenu = 0;
  755.                 haswin_menu.domenu = 0;
  756.                 haswin_menu.message = 0;
  757.         }
  758.         menu_total = haswin_realloc(menu_total, asciilen(haswin_menu.menu)+asciilen(ptr1)+1, "haswin_createmenu", "final menu string");
  759.         sprintf(menu_total, "%s%s", haswin_menu.menu, ptr1);
  760.         haswin_free(ptr1);
  761.         i = 0;
  762.         haswin_menu.actual = haswin_buildmenu(menu_total, &i, haswin_menu.actual);
  763.         if (user)
  764.                 haswin_menu.domenu = user;
  765.         charx = haswin_readvduvariable(VDUVAR_CharXsize);
  766.         haswin_menu.topx = x - i*charx/2;
  767.         haswin_menu.topy = y;
  768.         regs.r[1] = (int)haswin_menu.actual;
  769.         regs.r[2] = haswin_menu.topx;
  770.         regs.r[3] = haswin_menu.topy;
  771.         return(haswin_swi(HASWIN_Create_menu, ®s));
  772. }
  773.  
  774. int haswin_recreatemenu() {
  775.  
  776.         static char       *menu_total = 0;
  777.         _kernel_swi_regs  regs;
  778.         window            *win;
  779.         char              *ptr;
  780.         icon              *ic;
  781.  
  782.         if (haswin_menu.actual == 0)
  783.                 return(HASWIN_FALSE);
  784.         if (!haswin_menu.menu)
  785.                 return(HASWIN_FALSE);
  786.         if (!haswin_menu.extra) {
  787.                 haswin_menu.extra = haswin_mallocblock(0, 1, "haswin_recreatemenu", "extra field");
  788.                 haswin_menu.extra[0] = '\0';
  789.         }
  790.         if (haswin_menuwindow) {
  791.                 win = haswin_findwindowhandle(haswin_menuwindow);
  792.                 ic = haswin_findiconhandle(win, haswin_menuicon);
  793.         } else {
  794.                 win = 0;
  795.                 ic = 0;
  796.         }
  797.         ptr = haswin_createmenuextra(win, ic, haswin_menuextra);
  798.         menu_total = haswin_realloc(menu_total, asciilen(haswin_menu.menu)+asciilen(ptr)+1, "haswin_recreatemenu", "final menu");
  799.         sprintf(menu_total, "%s%s", haswin_menu.menu, ptr);
  800.         haswin_free(ptr);
  801.         haswin_menu.actual = haswin_buildmenu(menu_total, 0, haswin_menu.actual);
  802.         regs.r[1] = (int)haswin_menu.actual;
  803.         regs.r[2] = haswin_menu.topx;
  804.         regs.r[3] = haswin_menu.topy;
  805.         return(haswin_swi(HASWIN_Create_menu, ®s));
  806. }
  807.  
  808.