home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- /*
- * MENU.C
- *
- * Menu routines... made to take up as little space as possible, and
- * thus uses many tricks which you should watch out for.
- * ------------------------------------------------------------------
- * Changes added 06/94 by Karl Lukas
- *
- * Menus can now have keyboard shortcuts: menuadd <men> <item|c> <cmd>
- * The vertical bar '|' and the command character c must immediatly
- * follow the item name
- *
- * Menu items can now be separated by NM_BARLABELs:
- * menuadd <men> "NM_BARLABEL|n" null
- * The vertical bar '|' and width of the separator n must immediatly
- * follow the NM_BARLABEL keyword. If you dont't supply a width
- * value a fixed default value will be used
- *
- * These changes are semi-font-adaptive, i.e. they rely on the '~'
- * tilde character. Very large fonts might cause a visual mess.
- */
-
- #include "defs.h"
- #include "graphics/gfxbase.h"
- #include "graphics/rastport.h"
- #include <string.h>
-
- extern struct GfxBase *GfxBase;
- extern BYTE GetShortcut(char *itemname); /* Added 06/94 by Karl Lukas */
- extern int GetBarlabLength(char *itemname); /* Added 06/94 by Karl Lukas */
-
- #define BARLAB_DEFAULT 22 /* Default length of separator, KL */
- #define BARLAB_MAXLENGTH 50 /* Don't increase this value, KL */
-
- typedef struct {
- ITEM item;
- char *com;
- } XITEM;
-
- char menucmd_buffer[256];
-
- short Menuoff;
- short DoMenuoff;
-
- MENU *Menu;
-
- void
- menu_strip(win)
- WIN *win;
- {
- if (!Menuoff && Menu) {
- SetMenuStrip(win,Menu);
- Forbid();
- win->Flags &= ~RMBTRAP;
- Permit();
- }
- }
-
- void menu_off(void)
- {
- ED *ed;
- if (Menuoff == 0) {
- for (ed = (ED *)DBase.mlh_Head; ed->Node.mln_Succ; ed = (ED *)ed->Node.mln_Succ) {
- ClearMenuStrip(ed->Win);
- Forbid();
- ed->Win->Flags |= RMBTRAP;
- Permit();
- }
- }
- ++Menuoff;
- }
-
- void menu_on(void)
- {
- ED *ed;
- if (Menu && Menuoff == 1) {
- fixmenu();
- for (ed = (ED *)DBase.mlh_Head; ed->Node.mln_Succ; ed = (ED *)ed->Node.mln_Succ) {
- SetMenuStrip(ed->Win,Menu);
- Forbid();
- ed->Win->Flags &= ~RMBTRAP;
- Permit();
- }
- }
- --Menuoff;
- }
-
- void do_menuoff(void)
- {
- menu_off();
- ++DoMenuoff;
- }
-
- void do_menuon(void)
- {
- if (DoMenuoff) {
- --DoMenuoff;
- menu_on();
- }
- }
-
- char *menutomacro(char *str)
- {
- char header[64];
- char itembuf[64];
- short i;
- char *ptr;
- MENU *menu;
- ITEM *item;
-
- for (i = 0; str[i] && str[i] != '-'; ++i);
- if (str[i] == '-') {
- strncpy(header, str, i);
- header[i] = 0;
- strcpy(itembuf, str + i + 1);
- for (menu = Menu; menu; menu = menu->NextMenu) {
- if (ncstrcmp(header, menu->MenuName) == 0) {
- for (item = menu->FirstItem; item; item = item->NextItem) {
- ptr = (char *)((ITEXT *)item->ItemFill)->IText;
- if (ncstrcmp(itembuf, ptr) == 0) {
- ptr = ((XITEM *)item)->com;
- goto done;
- }
- }
- }
- }
- }
- ptr = NULL;
- done:
- return(ptr);
- }
-
-
- /* Changed 06/94 by Karl Lukas. Now Handles CHECKIT menus */
-
- char *menu_cmd(UWORD Code)
- {
- XITEM *item;
- if (item = (XITEM *)ItemAddress(Menu, Code))
- {
- if (item->item.Flags & CHECKIT)
- {
- char *command = item->com;
- int i = 0;
- while (command[i] && (command[i] != '|'))
- i++;
- if (command[i] != '|')
- {
- title("Command error in CHECKIT menu");
- return NULL;
- }
- if (item->item.Flags & CHECKED)
- {
- strncpy(menucmd_buffer, command, i);
- menucmd_buffer[i] = 0;
- }
- else
- strcpy(menucmd_buffer, command + i + 1);
- return menucmd_buffer;
-
- }
- else
- return(item->com);
-
- }
- return(NULL);
- }
-
- /*
- * new fixmenu by BIX:dhack handles 2.0 fonts
- */
-
- void fixmenu(void)
- {
- MENU *menu;
- ITEM *item;
- ITEXT *it;
- int row, col, maxc, scr;
- struct IntuiText itxt; /* To find width in case of proportional fonts */
-
- /* Initialize the few elements needed */
- itxt.ITextFont = Ep->Win->WScreen->Font;
- itxt.NextText = NULL;
-
- col = 0;
- for (menu = Menu; menu; menu = menu->NextMenu) {
- short offset; /* Offset for width; used for position of item
- relative to it's menu header at end of loop */
-
- /* Put this menu header into the IntuiText and figure out how
- wide it is in pixels */
- itxt.IText = menu->MenuName;
- maxc = IntuiTextLength(&itxt); /* This is now # of pixels */
-
- /* Find 'average' character size */
- offset = (maxc/strlen(menu->MenuName))*2;
- menu->Width = maxc + offset;
-
- row = 0;
- for (item = menu->FirstItem; item; item = item->NextItem) {
- it = (ITEXT *)item->ItemFill;
- item->TopEdge = row;
- if(it != NULL) {
- it->TopEdge = 1; /* Center in select box */
- it->LeftEdge = offset/4; /* Changed /4 KL*/
- it->DrawMode = JAM1; /* How workbench's menus are... */
- }
-
- /* Figure out how wide this item is */
- itxt.IText = ((ITEXT *)item->ItemFill)->IText;
- scr = IntuiTextLength(&itxt); /* This is now # of pixels */
-
- if (item->Flags & COMMSEQ) /* KL */
- scr += COMMWIDTH; /* KL COMMSEQ's need additional space */
-
- if (item->Flags & CHECKIT) /* KL */
- { /* KL */
- scr += CHECKWIDTH; /* KL CHECKIT's need additional space */
- it->LeftEdge += CHECKWIDTH; /* KL */
- } /* KL */
-
- if (scr > maxc)
- maxc = scr;
-
- /* Figure out how tall the text is */
- if(Ep->Win->WScreen->Font != NULL)
- item->Height = Ep->Win->WScreen->Font->ta_YSize + 2; /* Changed from 2 to 1, KL */
-
- else /* This is something to default to, just in case */
- item->Height = GfxBase->DefaultFont->tf_YSize + 2; /* Changed from 2 to 1, KL */
-
-
- if (*it->IText == '~') /* This is a NM_BARLAB, KL */
- { /* KL */
- item->TopEdge++; /* KL */
- item->Height = item->Height / 2 + 3; /* KL */
- } /* KL */
-
- row += item->Height;
- }
- maxc += offset / 4; /* Changed KL */
-
- /* Fit the menu onto the screen */
- if( (maxc+10) > Ep->Win->WScreen->Width ) { /* Wider than screen! */
- offset = -col;
- /* Unfortunately, this won't reduce the menu's width */
- maxc = Ep->Win->WScreen->Width - 12;
- } else if( (offset = Ep->Win->WScreen->Width - (col+maxc+10)) > 0 )
- offset = 0;
-
- for (item = menu->FirstItem; item; item = item->NextItem) {
- item->Width = maxc;
- item->LeftEdge = offset / 4; /* Changed KL */
- }
-
- menu->LeftEdge = col;
- menu->Height = row;
- col += menu->Width;
- }
- }
-
-
- #ifdef NOTDEF
- void fixmenu(void)
- {
- MENU *menu;
- ITEM *item;
- ITEXT *it;
- int row, col, maxc, scr;
-
- col = 0;
- for (menu = Menu; menu; menu = menu->NextMenu) {
- short hdr_width;
- maxc = strlen(menu->MenuName);
- hdr_width = maxc * 8 + 16;
- menu->Width = hdr_width;
- row = 0;
- for (item = menu->FirstItem; item; item = item->NextItem) {
- it = (ITEXT *)item->ItemFill;
- item->TopEdge = row;
- scr = strlen(((ITEXT *)item->ItemFill)->IText);
- if (scr > maxc)
- maxc = scr;
- item->Height = 10;
- row += item->Height;
- }
- maxc = (maxc * 8) + 16;
- for (item = menu->FirstItem; item; item = item->NextItem)
- item->Width = maxc;
- menu->LeftEdge = col;
- menu->Height = row;
- col += hdr_width;
- }
- }
- #endif
-
- /*
- * menuclear
- * menuadd header item command
- * menudel header item
- * menudelhdr header
- */
-
- void do_menuclear(void)
- {
- menu_off();
- while (Menu) {
- av[1] = (ubyte *)Menu->MenuName;
- do_menudelhdr();
- }
- menu_on();
- }
-
- /* Keyboard shortcuts and separators added by Karl Lukas 06/94 */
-
- void do_menuadd(void)
- {
- int checkit = 0;
- MENU *menu, **mpr;
- ITEM *item, **ipr;
- ITEXT *it;
- BYTE shortcut = 0; /* KL */
- char *barlabel = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"; /* KL */
- int barlength = 0; /* KL */
-
- menu_off();
- mpr = &Menu;
- for (menu = *mpr; menu; menu = *mpr) {
- if (strcmp(av[1], menu->MenuName) == 0) {
- ipr = &menu->FirstItem;
- for (item = *ipr; item; item = *ipr) {
- if (strcmp(av[2], ((ITEXT *)item->ItemFill)->IText) == 0)
- goto newname;
- ipr = &item->NextItem;
- }
- goto newitem;
- }
- mpr = &menu->NextMenu;
- }
- newmenu: /* create new menu */
- menu = malloc(sizeof(MENU));
- clrmem(menu, sizeof(MENU));
- menu->NextMenu = *mpr;
- *mpr = menu;
- menu->Flags = MENUENABLED;
- menu->MenuName = malloc(strlen(av[1])+1);
- strcpy(menu->MenuName, av[1]);
- ipr = &menu->FirstItem;
- *ipr = NULL;
- newitem: /* create new item */
- it = malloc(sizeof(ITEXT));
- clrmem(it, sizeof(ITEXT));
- it->BackPen = 1;
- it->DrawMode = JAM2;
-
- if (strncmp(av[2], "NM_BARLAB", 9) == 0) /* KL */
- { /* KL */
- barlength = GetBarlabLength(av[2]); /* KL */
- av[2] = malloc(barlength + 1); /* KL */
- strncpy(av[2], barlabel, barlength); /* KL */
- av[2][barlength] = 0; /* KL */
- } /* KL */
- else /* KL */
- shortcut = GetShortcut(av[2]); /* KL */
-
- if (av[2][0] == '_') /* KL */
- { /* KL */
- if (av[2][1] == '_') /* CHECKIT, initial state unchecked, KL */
- { /* KL */
- checkit = 2; /* KL */
- memmove(av[2], av[2] + 2, strlen(av[2] + 1)); /* KL */
- } /* KL */
- else /* Initial state CHECKED KL */
- { /* KL */
- checkit = 1; /* KL */
- memmove(av[2], av[2] + 1, strlen(av[2])); /* KL */
- } /* KL */
- } /* KL */
-
- it->IText = malloc(strlen(av[2])+1);
- strcpy(it->IText, av[2]);
- item = malloc(sizeof(XITEM));
- clrmem(item, sizeof(XITEM));
- item->NextItem = *ipr;
- *ipr = item;
- item->ItemFill = (APTR)it;
-
- item->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
-
- if (barlength) /* KL */
- item->Flags = ITEMENABLED|ITEMTEXT|HIGHNONE; /* KL */
- if (shortcut) /* KL */
- { /* KL */
- item->Flags |= COMMSEQ; /* KL */
- item->Command = shortcut; /* KL */
- } /* KL */
- if (checkit == 1) /* KL */
- item->Flags |= CHECKIT|CHECKED|MENUTOGGLE; /* KL */
- if (checkit == 2) /* KL */
- item->Flags |= CHECKIT|MENUTOGGLE; /* KL */
-
- newname: /* create new name */
- if (((XITEM *)item)->com)
- free(((XITEM *)item)->com);
- ((XITEM *)item)->com = malloc(strlen(av[3])+1);
- strcpy(((XITEM *)item)->com, av[3]);
- menu_on();
- }
-
- BYTE GetShortcut(char *itemname) /* Added 06/94 by Karl Lukas */
- {
- int i = 0;
-
- while (itemname[i] && (itemname[i] != '|'))
- i++;
- if (itemname[i])
- itemname[i++] = 0;
- return (BYTE)itemname[i];
- }
-
- int GetBarlabLength(char *itemname)
- {
- int ret = BARLAB_DEFAULT;
-
- if (itemname[9] == '|' && itemname[10] >= '0' && itemname[10] <= '9')
- ret = atoi(itemname + 10);
- if (ret > BARLAB_MAXLENGTH)
- ret = BARLAB_DEFAULT;
- return ret;
- }
-
-
- void do_menudelhdr(void)
- {
- MENU *menu;
- MENU **mpr;
-
- menu_off();
- mpr = &Menu;
- for (menu = *mpr; menu; menu = *mpr) {
- if (strcmp(av[1], menu->MenuName) == 0) {
- if (menu->FirstItem) {
- while (menu->FirstItem) {
- av[2] = ((ITEXT *)menu->FirstItem->ItemFill)->IText;
- if (do_menudel())
- break;
- }
- break;
- }
- *mpr = menu->NextMenu;
- free(menu->MenuName);
- free(menu);
- break;
- }
- mpr = &menu->NextMenu;
- }
- menu_on();
- }
-
- int do_menudel(void)
- {
- MENU *menu;
- ITEM *item, **ipr;
- ITEXT *it;
- short ret = 0;
-
- menu_off();
- for (menu = Menu; menu; menu = menu->NextMenu) {
- if (strcmp(av[1], menu->MenuName) == 0) {
- ipr = &menu->FirstItem;
- for (item = *ipr; item; item = *ipr) {
- it = (ITEXT *)item->ItemFill;
- if (strcmp(av[2], it->IText) == 0) {
- *ipr = item->NextItem;
- free(it->IText);
- free(it);
- free(((XITEM *)item)->com);
- free(item);
- if (!menu->FirstItem) {
- do_menudelhdr();
- ret = 1;
- }
- menu_on();
- return((int)ret);
- }
- ipr = &item->NextItem;
- }
- }
- }
- menu_on();
- return((int)ret);
- }
-
-