/* easy menus: Copyright 1987 Peter da Silva, all rights reserved. * * Permission is granted to use this in any application, so long as * this notice is retained in the source. Permission is granted to * modify the code as you like, so long as this notice (between the * first line beginning "easy menus" and the end of this paragraph, * inclusive) is retained intact. * * Usage: * * #include "menu.h" * * struct MenuPtr menudata; * struct MenuPtr *menuptr = &menudata; * * init_menus(menuptr); / * Just zero menu pointer out * / * * for(each menu item) { * add_menu(menuptr, menu, item, subitem, flags); * } * * Flags: * SUBITEM_NOCHECK -- subitem does not require a checkmark. * SUBITEM_SELECTOR -- subitem is a 1 of n selector, use mutual-exclude. * SUBITEM_TOGGLE -- subitem is a toggled flag. * SUBITEM_SELECTED -- defaults to checked. * * * SetMenuStrip(yourwindow, menuptr->MenuBar); * * ... * * ClearMenuStrip(yourwindow); * * trash_menus(menuptr); * * Notes: * * if you don't want any subitems, use zero for the subitem value. * * subitem is always initialised as a CHECKIT item with all the other * subitems mutually excluded. * * it is intended that the menu be set up with all action items in * the first level of the menu, and all toggles in the second level... * this is a piece of blatant authoritarianism on my part. I've seen * too many menus with no rhyme or reason. Look at AmigaTerm (the term * program that comes with the Amiga modem) some time. Baud rate has * an item all by itself, but word size is hidden off in a menu with * things like bell sound. * * the appearance of the menus produced by this is (in my humble * opinion) good. I took some care making text centered in menu boxes, * for example. */ #include #include #include "menu.h" #include "fonts.h" /* struct MenuPtr { struct Menu *MenuBar; struct Remember *MenuMemory; }; */ char *AllocRemember(); static struct Menu *new_menu(); static struct MenuItem *new_item(), *new_subitem(); #define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k)) #define TextLen(s) (strlen(s)*FONTWIDTH) trash_menus(menuptr) struct MenuPtr *menuptr; { FreeRemember(&menuptr->MenuMemory, 1); menuptr->MenuMemory = 0; menuptr->MenuBar = 0; } init_menus(menuptr) struct MenuPtr *menuptr; { menuptr->MenuMemory = 0; menuptr->MenuBar = 0; } int add_menu(menuptr, menuname, itemname, subitemname, flags) struct MenuPtr *menuptr; char *menuname, *itemname, *subitemname; long flags; { int i, j, k; struct Menu *menu; struct MenuItem *item; struct MenuItem *subitem; if(menuptr->MenuBar) { for(i = 0, menu = menuptr->MenuBar; menu; menu = menu->NextMenu, i++ ) if(strcmp(menuname, menu->MenuName)==0) break; if(!menu) menu = new_menu(menuptr, menuname); if(!menu) return MENUNULL; } else { i = 0; menu = new_menu(menuptr, menuname); if(!menu) return MENUNULL; } for(j = 0, item = menu->FirstItem; item; item = item->NextItem, j++ ) { struct IntuiText *text; text = (struct IntuiText *)item->ItemFill; if(strcmp(itemname, text->IText) == 0) break; } if(subitemname) { if(!item) item = new_item(menuptr, menu, itemname); if(!item) return MENUNULL; for(k = 0, subitem = item->SubItem; subitem; subitem = subitem->NextItem, k++ ) { struct IntuiText *text; text = (struct IntuiText *)subitem->ItemFill; if(strcmp(subitemname, text->IText) == 0) break; } if(!subitem) subitem = new_subitem(menuptr, item, subitemname, flags); if(!subitem) return MENUNULL; return TOMENUNUM(i, j, k); } else { if(!item) item = new_item(menuptr, menu, itemname); if(!item) return MENUNULL; return TOMENUNUM(i, j, NOSUB); } } static struct Menu * new_menu(menuptr, name) struct MenuPtr *menuptr; char *name; { struct Menu *menu; menu = (struct Menu *)AllocRemember( &menuptr->MenuMemory, sizeof(struct Menu), MEMF_PUBLIC); if(!menu) return 0; menu->NextMenu = NULL; menu->LeftEdge = 0; menu->TopEdge = 0; menu->Width = TextLen(name)+FONTWIDTH; menu->Height = 0; menu->Flags = MENUENABLED; menu->MenuName = name; menu->FirstItem = 0; if(menuptr->MenuBar) { struct Menu *ptr, *prev; for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) { menu->LeftEdge += ptr->Width; prev = ptr; } prev->NextMenu = menu; } else { menuptr->MenuBar = menu; } return menu; } static struct item * new_item(menuptr, menu, name) struct MenuPtr *menuptr; char *name; struct Menu *menu; { struct MenuItem *item; struct IntuiText *text; item = (struct MenuItem *)AllocRemember( &menuptr->MenuMemory, sizeof(struct MenuItem), MEMF_PUBLIC); if(!item) return 0; text = (struct IntuiText *)AllocRemember( &menuptr->MenuMemory, sizeof(struct IntuiText), MEMF_PUBLIC); if(!text) return 0; text->FrontPen = AUTOFRONTPEN; text->BackPen = AUTOBACKPEN; text->DrawMode = JAM2; text->LeftEdge = 1; text->TopEdge = 1; text->ITextFont = NULL; text->IText = name; text->NextText = NULL; item->NextItem = NULL; item->LeftEdge = 0; item->TopEdge = 0; item->Width = IntuiTextLength(text)+2; if(item->Width <= menu->Width) item->Width = menu->Width+1; item->Height = FONTHEIGHT+1; item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED; item->MutualExclude = 0; item->ItemFill = text; item->SelectFill = NULL; item->Command = 0; item->SubItem = NULL; item->NextSelect = NULL; if(menu->FirstItem) { struct MenuItem *ptr, *prev; for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) { if(item->Width > ptr->Width) { if(ptr->SubItem) nudge(ptr->SubItem, item->Width-ptr->Width); ptr->Width = item->Width; } else if(ptr->Width>item->Width) item->Width = ptr->Width; prev = ptr; } item->TopEdge = prev->TopEdge + prev->Height; prev->NextItem = item; } else { menu->FirstItem = item; } return item; } static nudge(item, delta) struct MenuItem *item; int delta; { while(item) { item->LeftEdge += delta; item = item->NextItem; } } static struct item * new_subitem(menuptr, item, name, flags) struct MenuPtr *menuptr; char *name; struct MenuItem *item; long flags; { struct MenuItem *subitem; struct IntuiText *text; subitem = (struct MenuItem *)AllocRemember( &menuptr->MenuMemory, sizeof(struct MenuItem), MEMF_PUBLIC); if(!subitem) return 0; text = (struct IntuiText *)AllocRemember( &menuptr->MenuMemory, sizeof(struct IntuiText), MEMF_PUBLIC); if(!text) return 0; text->FrontPen = AUTOFRONTPEN; text->BackPen = AUTOBACKPEN; text->DrawMode = JAM2; text->LeftEdge = CHECKWIDTH+1; text->TopEdge = 1; text->ITextFont = NULL; text->IText = name; text->NextText = NULL; subitem->NextItem = NULL; subitem->LeftEdge = item->Width; subitem->TopEdge = 0; subitem->Width = IntuiTextLength(text)+2; if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH; subitem->Height = FONTHEIGHT+1; subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP; subitem->MutualExclude = 0; if(flags != SUBITEM_NOCHECK) { subitem->Flags |= CHECKIT; if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE; if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED; } subitem->ItemFill = text; subitem->SelectFill = NULL; subitem->Command = 0; subitem->SubItem = NULL; subitem->NextSelect = NULL; if(item->SubItem) { struct MenuItem *ptr, *prev; int i; for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) { if(subitem->Width > ptr->Width) ptr->Width = subitem->Width; else if(ptr->Width>subitem->Width) subitem->Width = ptr->Width; prev = ptr; } subitem->TopEdge = prev->TopEdge + prev->Height; if(flags & SUBITEM_SELECTOR) subitem->MutualExclude = ~(1<NextItem = subitem; } else { item->SubItem = subitem; if(flags & SUBITEM_SELECTOR) subitem->MutualExclude = ~1; } return subitem; }