home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / YADME10.LHA / YADME10 / src / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-19  |  13.3 KB  |  495 lines

  1. #include <stdio.h>
  2. /*
  3.  *  MENU.C
  4.  *
  5.  *  Menu routines... made to take up as little space as possible, and
  6.  *  thus uses many tricks which you should watch out for.
  7.  *  ------------------------------------------------------------------
  8.  *  Changes added 06/94 by Karl Lukas
  9.  *
  10.  *  Menus can now have keyboard shortcuts: menuadd <men> <item|c> <cmd>
  11.  *  The vertical bar '|' and the command character c must immediatly
  12.  *  follow the item name 
  13.  *
  14.  *  Menu items can now be separated by NM_BARLABELs:
  15.  *    menuadd <men> "NM_BARLABEL|n" null
  16.  *  The vertical bar '|' and width of the separator n must immediatly
  17.  *  follow the NM_BARLABEL keyword. If you dont't supply a width
  18.  *  value a fixed default value will be used
  19.  *
  20.  *  These changes are semi-font-adaptive, i.e. they rely on the '~'
  21.  *  tilde character. Very large fonts might cause a visual mess.
  22.  */
  23.  
  24. #include "defs.h"
  25. #include "graphics/gfxbase.h"
  26. #include "graphics/rastport.h"
  27. #include <string.h>
  28.  
  29. extern struct GfxBase *GfxBase;
  30. extern BYTE GetShortcut(char *itemname);    /* Added 06/94 by Karl Lukas */
  31. extern int GetBarlabLength(char *itemname); /* Added 06/94 by Karl Lukas */
  32.  
  33. #define BARLAB_DEFAULT 22                /* Default length of separator,  KL */
  34. #define BARLAB_MAXLENGTH 50              /* Don't increase this value,    KL */
  35.  
  36. typedef struct {
  37.     ITEM item;
  38.     char *com;
  39. } XITEM;
  40.  
  41. char menucmd_buffer[256];
  42.  
  43. short Menuoff;
  44. short DoMenuoff;
  45.  
  46. MENU *Menu;
  47.  
  48. void
  49. menu_strip(win)
  50. WIN *win;
  51. {
  52.     if (!Menuoff && Menu) {
  53.     SetMenuStrip(win,Menu);
  54.     Forbid();
  55.     win->Flags &= ~RMBTRAP;
  56.     Permit();
  57.     }
  58. }
  59.  
  60. void menu_off(void)
  61. {
  62.     ED *ed;
  63.     if (Menuoff == 0) {
  64.     for (ed = (ED *)DBase.mlh_Head; ed->Node.mln_Succ; ed = (ED *)ed->Node.mln_Succ) {
  65.         ClearMenuStrip(ed->Win);
  66.         Forbid();
  67.         ed->Win->Flags |= RMBTRAP;
  68.         Permit();
  69.     }
  70.     }
  71.     ++Menuoff;
  72. }
  73.  
  74. void menu_on(void)
  75. {
  76.     ED *ed;
  77.     if (Menu && Menuoff == 1) {
  78.     fixmenu();
  79.     for (ed = (ED *)DBase.mlh_Head; ed->Node.mln_Succ; ed = (ED *)ed->Node.mln_Succ) {
  80.         SetMenuStrip(ed->Win,Menu);
  81.         Forbid();
  82.         ed->Win->Flags &= ~RMBTRAP;
  83.         Permit();
  84.     }
  85.     }
  86.     --Menuoff;
  87. }
  88.  
  89. void do_menuoff(void)
  90. {
  91.     menu_off();
  92.     ++DoMenuoff;
  93. }
  94.  
  95. void do_menuon(void)
  96. {
  97.     if (DoMenuoff) {
  98.     --DoMenuoff;
  99.     menu_on();
  100.     }
  101. }
  102.  
  103. char *menutomacro(char *str)
  104. {
  105.     char header[64];
  106.     char itembuf[64];
  107.     short i;
  108.     char *ptr;
  109.     MENU *menu;
  110.     ITEM *item;
  111.  
  112.     for (i = 0; str[i] && str[i] != '-'; ++i);
  113.     if (str[i] == '-') {
  114.     strncpy(header, str, i);
  115.     header[i] = 0;
  116.     strcpy(itembuf, str + i + 1);
  117.     for (menu = Menu; menu; menu = menu->NextMenu) {
  118.         if (ncstrcmp(header, menu->MenuName) == 0) {
  119.         for (item = menu->FirstItem; item; item = item->NextItem) {
  120.             ptr = (char *)((ITEXT *)item->ItemFill)->IText;
  121.             if (ncstrcmp(itembuf, ptr) == 0) {
  122.             ptr = ((XITEM *)item)->com;
  123.             goto done;
  124.             }
  125.         }
  126.         }
  127.     }
  128.     }
  129.     ptr = NULL;
  130. done:
  131.     return(ptr);
  132. }
  133.  
  134.  
  135. /* Changed 06/94 by Karl Lukas. Now Handles CHECKIT menus */
  136.  
  137. char *menu_cmd(UWORD Code)
  138. {
  139.     XITEM *item;
  140.     if (item = (XITEM *)ItemAddress(Menu, Code))
  141.     {
  142.        if (item->item.Flags & CHECKIT)
  143.        {
  144.           char *command = item->com;
  145.           int i = 0;
  146.           while (command[i] && (command[i] != '|'))
  147.              i++;
  148.           if (command[i] != '|')
  149.           {
  150.              title("Command error in CHECKIT menu");
  151.              return NULL;
  152.           }
  153.           if (item->item.Flags & CHECKED)
  154.           {
  155.              strncpy(menucmd_buffer, command, i);
  156.              menucmd_buffer[i] = 0;
  157.           }
  158.           else
  159.              strcpy(menucmd_buffer, command + i + 1); 
  160.           return menucmd_buffer;
  161.           
  162.        }
  163.        else
  164.           return(item->com);
  165.     
  166.     }
  167.     return(NULL);
  168. }
  169.  
  170. /*
  171.  *  new fixmenu by BIX:dhack handles 2.0 fonts
  172.  */
  173.  
  174. void fixmenu(void)
  175. {
  176.     MENU *menu;
  177.     ITEM *item;
  178.     ITEXT *it;
  179.     int row, col, maxc, scr;
  180.     struct IntuiText itxt;  /* To find width in case of proportional fonts */
  181.  
  182.     /* Initialize the few elements needed */
  183.     itxt.ITextFont = Ep->Win->WScreen->Font;
  184.     itxt.NextText = NULL;
  185.  
  186.     col = 0;
  187.     for (menu = Menu; menu; menu = menu->NextMenu) {
  188.     short offset;  /* Offset for width; used for position of item
  189.               relative to it's menu header at end of loop */
  190.  
  191.     /* Put this menu header into the IntuiText and figure out how
  192.        wide it is in pixels */
  193.     itxt.IText = menu->MenuName;
  194.     maxc = IntuiTextLength(&itxt);    /* This is now # of pixels */
  195.  
  196.     /* Find 'average' character size */
  197.     offset = (maxc/strlen(menu->MenuName))*2;
  198.     menu->Width = maxc + offset;
  199.  
  200.     row = 0;
  201.     for (item = menu->FirstItem; item; item = item->NextItem) {
  202.         it = (ITEXT *)item->ItemFill;
  203.         item->TopEdge = row;
  204.         if(it != NULL) {
  205.         it->TopEdge = 1;     /* Center in select box */
  206.         it->LeftEdge = offset/4;                               /* Changed /4 KL*/
  207.         it->DrawMode = JAM1;     /* How workbench's menus are... */
  208.         }
  209.  
  210.         /* Figure out how wide this item is */
  211.         itxt.IText = ((ITEXT *)item->ItemFill)->IText;
  212.         scr = IntuiTextLength(&itxt);  /* This is now # of pixels */
  213.  
  214.             if (item->Flags & COMMSEQ)      /* KL */
  215.                scr += COMMWIDTH;            /* KL COMMSEQ's need additional space */
  216.  
  217.             if (item->Flags & CHECKIT)      /* KL */
  218.             {                               /* KL */
  219.                scr += CHECKWIDTH;           /* KL CHECKIT's need additional space */
  220.                it->LeftEdge += CHECKWIDTH;  /* KL */
  221.             }                               /* KL */
  222.  
  223.         if (scr > maxc)
  224.         maxc = scr;
  225.  
  226.         /* Figure out how tall the text is */
  227.         if(Ep->Win->WScreen->Font != NULL)
  228.         item->Height = Ep->Win->WScreen->Font->ta_YSize + 2;   /* Changed from 2 to 1, KL */
  229.  
  230.         else /* This is something to default to, just in case */
  231.         item->Height = GfxBase->DefaultFont->tf_YSize + 2;     /* Changed from 2 to 1, KL */
  232.  
  233.  
  234.             if (*it->IText == '~')                                     /* This is a NM_BARLAB, KL */
  235.             {                                                          /* KL */
  236.                 item->TopEdge++;                                       /* KL */
  237.                 item->Height = item->Height / 2 + 3;                   /* KL */
  238.             }                                                          /* KL */
  239.  
  240.         row += item->Height;
  241.     }
  242.     maxc += offset / 4;                                            /* Changed KL */
  243.  
  244.     /* Fit the menu onto the screen */
  245.     if( (maxc+10) > Ep->Win->WScreen->Width ) {   /* Wider than screen! */
  246.         offset = -col;
  247.         /* Unfortunately, this won't reduce the menu's width */
  248.         maxc = Ep->Win->WScreen->Width - 12;
  249.     } else if( (offset = Ep->Win->WScreen->Width - (col+maxc+10)) > 0 )
  250.         offset = 0;
  251.  
  252.     for (item = menu->FirstItem; item; item = item->NextItem) {
  253.         item->Width = maxc;
  254.         item->LeftEdge = offset / 4;                               /* Changed KL */
  255.     }
  256.  
  257.     menu->LeftEdge = col;
  258.     menu->Height = row;
  259.     col += menu->Width;
  260.     }
  261. }
  262.  
  263.  
  264. #ifdef NOTDEF
  265. void fixmenu(void)
  266. {
  267.     MENU *menu;
  268.     ITEM *item;
  269.     ITEXT *it;
  270.     int row, col, maxc, scr;
  271.  
  272.     col = 0;
  273.     for (menu = Menu; menu; menu = menu->NextMenu) {
  274.     short hdr_width;
  275.     maxc = strlen(menu->MenuName);
  276.     hdr_width = maxc * 8 + 16;
  277.     menu->Width = hdr_width;
  278.     row = 0;
  279.     for (item = menu->FirstItem; item; item = item->NextItem) {
  280.         it = (ITEXT *)item->ItemFill;
  281.         item->TopEdge = row;
  282.         scr = strlen(((ITEXT *)item->ItemFill)->IText);
  283.         if (scr > maxc)
  284.         maxc = scr;
  285.         item->Height = 10;
  286.         row += item->Height;
  287.     }
  288.     maxc = (maxc * 8) + 16;
  289.     for (item = menu->FirstItem; item; item = item->NextItem)
  290.         item->Width = maxc;
  291.     menu->LeftEdge = col;
  292.     menu->Height = row;
  293.     col += hdr_width;
  294.     }
  295. }
  296. #endif
  297.  
  298. /*
  299.  *  menuclear
  300.  *  menuadd    header    item    command
  301.  *  menudel    header    item
  302.  *  menudelhdr    header
  303.  */
  304.  
  305. void do_menuclear(void)
  306. {
  307.     menu_off();
  308.     while (Menu) {
  309.     av[1] = (ubyte *)Menu->MenuName;
  310.     do_menudelhdr();
  311.     }
  312.     menu_on();
  313. }
  314.  
  315. /* Keyboard shortcuts and separators added by Karl Lukas 06/94 */
  316.  
  317. void do_menuadd(void)
  318. {
  319.     int checkit = 0;
  320.     MENU *menu, **mpr;
  321.     ITEM *item, **ipr;
  322.     ITEXT *it;
  323.     BYTE shortcut = 0;                                                     /* KL */
  324.     char *barlabel = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; /* KL */
  325.     int barlength = 0;                                                     /* KL */
  326.  
  327.     menu_off();
  328.     mpr = &Menu;
  329.     for (menu = *mpr; menu; menu = *mpr) {
  330.     if (strcmp(av[1], menu->MenuName) == 0) {
  331.         ipr = &menu->FirstItem;
  332.         for (item = *ipr; item; item = *ipr) {
  333.         if (strcmp(av[2], ((ITEXT *)item->ItemFill)->IText) == 0)
  334.             goto newname;
  335.         ipr = &item->NextItem;
  336.         }
  337.         goto newitem;
  338.     }
  339.     mpr = &menu->NextMenu;
  340.     }
  341. newmenu:    /*    create new menu */
  342.     menu = malloc(sizeof(MENU));
  343.     clrmem(menu, sizeof(MENU));
  344.     menu->NextMenu = *mpr;
  345.     *mpr = menu;
  346.     menu->Flags = MENUENABLED;
  347.     menu->MenuName = malloc(strlen(av[1])+1);
  348.     strcpy(menu->MenuName, av[1]);
  349.     ipr = &menu->FirstItem;
  350.     *ipr = NULL;
  351. newitem:    /*    create new item */
  352.     it = malloc(sizeof(ITEXT));
  353.     clrmem(it, sizeof(ITEXT));
  354.     it->BackPen = 1;
  355.     it->DrawMode = JAM2;
  356.  
  357.     if (strncmp(av[2], "NM_BARLAB", 9) == 0)                   /* KL */
  358.     {                                                          /* KL */
  359.        barlength = GetBarlabLength(av[2]);                     /* KL */
  360.        av[2] = malloc(barlength + 1);                          /* KL */
  361.        strncpy(av[2], barlabel, barlength);                    /* KL */
  362.        av[2][barlength] = 0;                                   /* KL */
  363.     }                                                          /* KL */
  364.     else                                                       /* KL */
  365.        shortcut = GetShortcut(av[2]);                          /* KL */
  366.  
  367.     if (av[2][0] == '_')                                       /* KL */
  368.     {                                                          /* KL */
  369.        if (av[2][1] == '_') /* CHECKIT, initial state unchecked,  KL */
  370.        {                                                       /* KL */
  371.           checkit = 2;                                         /* KL */
  372.           memmove(av[2], av[2] + 2, strlen(av[2] + 1));        /* KL */
  373.        }                                                       /* KL */
  374.        else  /* Initial state CHECKED                             KL */
  375.        {                                                       /* KL */
  376.           checkit = 1;                                         /* KL */
  377.           memmove(av[2], av[2] + 1, strlen(av[2]));            /* KL */
  378.        }                                                       /* KL */
  379.     }                                                          /* KL */
  380.  
  381.     it->IText = malloc(strlen(av[2])+1);
  382.     strcpy(it->IText, av[2]);
  383.     item = malloc(sizeof(XITEM));
  384.     clrmem(item, sizeof(XITEM));
  385.     item->NextItem = *ipr;
  386.     *ipr = item;
  387.     item->ItemFill = (APTR)it;
  388.  
  389.     item->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  390.  
  391.     if (barlength)                                             /* KL */
  392.        item->Flags = ITEMENABLED|ITEMTEXT|HIGHNONE;            /* KL */
  393.     if (shortcut)                                              /* KL */
  394.     {                                                          /* KL */
  395.        item->Flags |= COMMSEQ;                                 /* KL */
  396.        item->Command = shortcut;                               /* KL */
  397.     }                                                          /* KL */
  398.     if (checkit == 1)                                          /* KL */
  399.        item->Flags |= CHECKIT|CHECKED|MENUTOGGLE;              /* KL */
  400.     if (checkit == 2)                                          /* KL */
  401.        item->Flags |= CHECKIT|MENUTOGGLE;                      /* KL */
  402.  
  403. newname:    /*    create new name */
  404.     if (((XITEM *)item)->com)
  405.     free(((XITEM *)item)->com);
  406.     ((XITEM *)item)->com = malloc(strlen(av[3])+1);
  407.     strcpy(((XITEM *)item)->com, av[3]);
  408.     menu_on();
  409. }
  410.  
  411. BYTE GetShortcut(char *itemname) /* Added 06/94 by Karl Lukas */
  412. {
  413.    int i = 0;
  414.  
  415.    while (itemname[i] && (itemname[i] != '|'))
  416.       i++;
  417.    if (itemname[i])
  418.       itemname[i++] = 0;
  419.    return (BYTE)itemname[i];  
  420. }
  421.  
  422. int GetBarlabLength(char *itemname)
  423. {
  424.    int ret = BARLAB_DEFAULT;
  425.  
  426.    if (itemname[9] == '|' && itemname[10] >= '0' && itemname[10] <= '9')
  427.       ret = atoi(itemname + 10);
  428.    if (ret > BARLAB_MAXLENGTH)
  429.       ret = BARLAB_DEFAULT;
  430.    return ret;
  431. }
  432.  
  433.  
  434. void do_menudelhdr(void)
  435. {
  436.     MENU *menu;
  437.     MENU **mpr;
  438.  
  439.     menu_off();
  440.     mpr = &Menu;
  441.     for (menu = *mpr; menu; menu = *mpr) {
  442.     if (strcmp(av[1], menu->MenuName) == 0) {
  443.         if (menu->FirstItem) {
  444.         while (menu->FirstItem) {
  445.             av[2] = ((ITEXT *)menu->FirstItem->ItemFill)->IText;
  446.             if (do_menudel())
  447.             break;
  448.         }
  449.         break;
  450.         }
  451.         *mpr = menu->NextMenu;
  452.         free(menu->MenuName);
  453.         free(menu);
  454.         break;
  455.     }
  456.     mpr = &menu->NextMenu;
  457.     }
  458.     menu_on();
  459. }
  460.  
  461. int do_menudel(void)
  462. {
  463.     MENU *menu;
  464.     ITEM *item, **ipr;
  465.     ITEXT *it;
  466.     short ret = 0;
  467.  
  468.     menu_off();
  469.     for (menu = Menu; menu; menu = menu->NextMenu) {
  470.     if (strcmp(av[1], menu->MenuName) == 0) {
  471.         ipr = &menu->FirstItem;
  472.         for (item = *ipr; item; item = *ipr) {
  473.         it = (ITEXT *)item->ItemFill;
  474.         if (strcmp(av[2], it->IText) == 0) {
  475.             *ipr = item->NextItem;
  476.             free(it->IText);
  477.             free(it);
  478.             free(((XITEM *)item)->com);
  479.             free(item);
  480.             if (!menu->FirstItem) {
  481.             do_menudelhdr();
  482.             ret = 1;
  483.             }
  484.             menu_on();
  485.             return((int)ret);
  486.         }
  487.         ipr = &item->NextItem;
  488.         }
  489.     }
  490.     }
  491.     menu_on();
  492.     return((int)ret);
  493. }
  494.  
  495.