home *** CD-ROM | disk | FTP | other *** search
- /* 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 <exec/memory.h>
- #include <intuition/intuition.h>
- #include "menu.h"
- #include "fonts.h"
-
- /* Forward prototypes */
- static void nudge(struct MenuItem *item, int delta);
- static struct Menu *
- new_menu(struct MenuPtr *menuptr, char *name);
- static struct MenuItem *
- new_item(struct MenuPtr *menuptr,
- struct Menu *menu, UBYTE *name);
- static struct MenuItem *
- new_subitem(struct MenuPtr *menuptr,
- struct MenuItem *item, UBYTE *name, long flags);
-
- /*
- 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)
-
- void trash_menus(struct MenuPtr *menuptr)
- {
- FreeRemember(&menuptr->MenuMemory, 1);
- menuptr->MenuMemory = 0;
- menuptr->MenuBar = 0;
- }
-
- void init_menus(struct MenuPtr *menuptr)
- {
- menuptr->MenuMemory = 0;
- menuptr->MenuBar = 0;
- }
-
- int add_menu(
- struct MenuPtr *menuptr,
- char *menuname,
- char *itemname,
- char *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, (UBYTE *)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, (UBYTE *)subitemname, flags);
- if(!subitem)
- return MENUNULL;
- return TOMENUNUM(i, j, k);
- } else {
- if(!item)
- item = new_item(menuptr, menu, (UBYTE *)itemname);
- if(!item)
- return MENUNULL;
- return TOMENUNUM(i, j, NOSUB);
- }
- }
-
- static struct Menu *
- new_menu(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 MenuItem *
- new_item(struct MenuPtr *menuptr, struct Menu *menu, UBYTE *name)
- {
- 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 = (APTR)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 void nudge(struct MenuItem *item, int delta)
- {
- while(item) {
- item->LeftEdge += delta;
- item = item->NextItem;
- }
- }
-
- static struct MenuItem *
- new_subitem(
- struct MenuPtr *menuptr,
- struct MenuItem *item,
- UBYTE *name,
- 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 = 1;
- if(flags != SUBITEM_NOCHECK) text->LeftEdge += CHECKWIDTH;
- 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 = (APTR)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<<i);
- prev->NextItem = subitem;
- } else {
- item->SubItem = subitem;
- if(flags & SUBITEM_SELECTOR)
- subitem->MutualExclude = ~1;
- }
-
- return subitem;
- }
-