home *** CD-ROM | disk | FTP | other *** search
- /* Menus.c */
- /*****************************************************************************/
- /* */
- /* System Dependency Library for Building Portable Software */
- /* Macintosh Version */
- /* Written by Thomas R. Lawrence, 1993 - 1994. */
- /* */
- /* This file is Public Domain; it may be used for any purpose whatsoever */
- /* without restriction. */
- /* */
- /* This package is distributed in the hope that it will be useful, */
- /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
- /* */
- /* Thomas R. Lawrence can be reached at tomlaw@world.std.com. */
- /* */
- /*****************************************************************************/
-
- #include "MiscInfo.h"
- #include "Debug.h"
- #include "Audit.h"
- #include "Definitions.h"
-
- #ifdef THINK_C
- #pragma options(pack_enums)
- #endif
- #include <Menus.h>
- #include <Fonts.h>
- #include <Desk.h>
- #ifdef THINK_C
- #pragma options(!pack_enums)
- #endif
-
- #include "Menus.h"
- #include "Memory.h"
- #include "Array.h"
-
-
- /* structure represents a menu */
- struct MenuType
- {
- /* menu resource ID number (must be unique) */
- short MenuID;
- /* handle pointing to system's idea of what the menu is */
- MenuHandle DaMenuHandle;
- };
-
-
- /* structure represents a menu item (it remembers the menu and index of item) */
- struct MenuItemType
- {
- /* Menu ID + Item Index number used by menu manager to identify item */
- long MenuManagerID;
- /* pointer to the menu record for the menu that contains the item. */
- MenuType* WhatMenu;
- };
-
-
- /* list of menus (for finding unique menu IDs) */
- static ArrayRec* OurMenuList = NIL;
-
- /* list of items in the menus (for searching during menu-choice events) */
- static ArrayRec* OurItemList = NIL;
-
- /* the Apple menu record. NIL means there is no Apple menu */
- static MenuType* AppleMenu = NIL;
-
- /* number of "real" items on the apple menu. This is set to 0 whenever the */
- /* apple menu is created. */
- static long NumAppleMenuItems;
-
- /* flag indicating that menu bar needs to be redrawn */
- static MyBoolean RedrawMenuBarFlag = False;
-
- /* debugging flag */
- EXECUTE(static MyBoolean Initialized = False;)
-
-
- /* Initialize the menu subsystem. This must be called before any menu routines */
- /* are used. It is local to Level 0 and called from module Screen (InitializeScreen) */
- /* and should not be called from anywhere else. */
- MyBoolean Eep_InitializeMenus(void)
- {
- ERROR(Initialized,PRERR(ForceAbort,"InitializeMenus called more than once"));
- /* create list that contains menus */
- OurMenuList = NewArray();
- if (OurMenuList == NIL)
- {
- FailurePoint1:
- return False;
- }
- /* create the list that will hold all of the menu item records (for searching) */
- OurItemList = NewArray();
- if (OurItemList == NIL)
- {
- FailurePoint2:
- DisposeArray(OurMenuList);
- goto FailurePoint1;
- }
- /* initialize the apple menu variable to indicate that there isn't one */
- AppleMenu = NIL;
- EXECUTE(Initialized = True);
- return True;
- }
-
-
- /* Destroy any menu stuff that needs to be cleaned up before the program quits. */
- /* this should not be called from anywhere else except ShutdownScreen */
- void Eep_ShutdownMenus(void)
- {
- ERROR(!Initialized,PRERR(ForceAbort,
- "ShutdownMenus: Menu manager hasn't been initialized"));
- ERROR(ArrayGetLength(OurMenuList) != 0,PRERR(AllowResume,
- "Eep_ShutdownMenus: still some menus in existence"));
- ERROR(ArrayGetLength(OurItemList) != 0,PRERR(AllowResume,
- "Eep_ShutdownMenus: still some menu items in existence"));
- DisposeArray(OurMenuList);
- DisposeArray(OurItemList);
- }
-
-
- /* create an implementation defined "utility" menu. On the Macintosh, this is */
- /* the standard "Apple Menu". */
- MenuType* MakeAppleMenu(void)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- /* if an apple menu exists, we return it instead of creating a new one */
- if (AppleMenu == NIL)
- {
- /* create a new menu normally with an apple character */
- AppleMenu = MakeNewMenu("\024");
- if (AppleMenu == NIL)
- {
- return NIL;
- }
- /* initialize item count */
- NumAppleMenuItems = 0;
- /* append the line and desk accessory list */
- AppendMenu(AppleMenu->DaMenuHandle,"\p(-");
- AddResMenu(AppleMenu->DaMenuHandle,'DRVR');
- }
- CheckPtrExistence(AppleMenu);
- return AppleMenu;
- }
-
-
- /* create a new menu with the specified name. The menu will not */
- /* be displayed on the menu bar */
- MenuType* MakeNewMenu(char* MenuName)
- {
- unsigned char NameTemp[256];
- long Scan;
- long Limit;
- MenuType* Menu;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- /* allocate the menu record */
- Menu = (MenuType*)AllocPtrCanFail(sizeof(MenuType),"MenuType");
- if (Menu == NIL)
- {
- FailurePoint1:
- return NIL;
- }
- /* convert name to a pascal string */
- Scan = 0;
- while ((Scan < 255) && (MenuName[Scan] != 0))
- {
- NameTemp[Scan + 1] = MenuName[Scan];
- Scan += 1;
- }
- NameTemp[0] = Scan;
- /* find an unused ID number */
- Limit = ArrayGetLength(OurMenuList);
- Menu->MenuID = 256; /* skip 0..255 which are reserved for hierarchical menus */
- LoopPoint:
- for (Scan = 0; Scan < Limit; Scan += 1)
- {
- if (Menu->MenuID == ((MenuType*)ArrayGetElement(OurMenuList,Scan))->MenuID)
- {
- Menu->MenuID += 1;
- goto LoopPoint;
- }
- ERROR(Scan > 16383,PRERR(ForceAbort,"MakeNewMenu: out of menu IDs"));
- }
- /* allocate the menu itself */
- Menu->DaMenuHandle = NewMenu(Menu->MenuID,NameTemp);
- if (Menu->DaMenuHandle == NIL)
- {
- FailurePoint2:
- ReleasePtr((char*)Menu);
- goto FailurePoint1;
- }
- /* add menu to list */
- if (!ArrayAppendElement(OurMenuList,Menu))
- {
- FailurePoint3:
- DisposeMenu(Menu->DaMenuHandle);
- goto FailurePoint2;
- }
- return Menu;
- }
-
-
- /* hide a menu if it's on the menu bar and delete it and all of the items */
- /* it contains. */
- void KillMenuAndDeleteItems(MenuType* TheMenu)
- {
- long Scan;
- long Limit;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheMenu);
- /* remove menu from our list of menus */
- ArrayDeleteElement(OurMenuList,ArrayFindElement(OurMenuList,TheMenu));
- /* remove menu from the menu bar */
- HideMenu(TheMenu);
- /* dispose the system menu block */
- DisposeMenu(TheMenu->DaMenuHandle);
- /* reset the apple menu value if we're disposing that */
- if (TheMenu == AppleMenu)
- {
- AppleMenu = NIL;
- }
- /* dispose all translation entries for the menu */
- Limit = ArrayGetLength(OurItemList);
- Scan = 0;
- while (Scan < Limit)
- {
- MenuItemType* MenuItem;
-
- MenuItem = (MenuItemType*)ArrayGetElement(OurItemList,Scan);
- if ((MenuItem->MenuManagerID >> 16) == TheMenu->MenuID)
- {
- /* dispose the item */
- ArrayDeleteElement(OurItemList,Scan);
- ReleasePtr((char*)MenuItem);
- /* since there's one less item now, decrement limit */
- Limit -= 1;
- /* note that we don't increment scan */
- }
- else
- {
- /* scan is only incremented if we didn't delete the element */
- Scan += 1;
- }
- }
- /* finally, delete the menu record */
- ReleasePtr((char*)TheMenu);
- }
-
-
- /* post a menu to the menu bar if it isn't already there */
- void ShowMenu(MenuType* TheMenu)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheMenu);
- /* append menu to menu bar */
- InsertMenu(TheMenu->DaMenuHandle,0);
- /* set flag to indicate that the menu bar needs to be redrawn */
- RedrawMenuBarFlag = True;
- }
-
-
- /* remove a menu from the menu bar if it is there */
- void HideMenu(MenuType* TheMenu)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheMenu);
- /* remove menu from menu bar */
- DeleteMenu(TheMenu->MenuID);
- /* set flag to indicate that the menu bar needs to be redrawn */
- RedrawMenuBarFlag = True;
- }
-
-
- /* append a new item to an existing menu. The Shortcut specifies a key that */
- /* can be used instead of pulling down the menu. How this is done and which */
- /* keys are allowed are implementation defined. On the Macintosh, the Command */
- /* key is used; keys should be numbers or upper case letters. If two menu items */
- /* are specified with the same shortcut, the result is undefined. */
- /* by default, the item is greyed out (disabled). */
- MenuItemType* MakeNewMenuItem(MenuType* TheMenu, char* MenuItemName,
- char Shortcut)
- {
- unsigned char NameTemp[256];
- long Scan;
- MenuItemType* MenuItem;
- short Index;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheMenu);
- /* allocate record */
- MenuItem = (MenuItemType*)AllocPtrCanFail(sizeof(MenuItemType),"MenuItemType");
- if (MenuItem == NIL)
- {
- FailurePoint1:
- return NIL;
- }
- /* add item to the item list */
- if (!ArrayAppendElement(OurItemList,MenuItem))
- {
- FailurePoint2:
- ReleasePtr((char*)MenuItem);
- goto FailurePoint1;
- }
- /* find out where on menu the item should be placed */
- if (TheMenu == AppleMenu)
- {
- Index = NumAppleMenuItems + 1;
- NumAppleMenuItems += 1;
- }
- else
- {
- Index = CountMItems(TheMenu->DaMenuHandle) + 1;
- }
- /* insert a dummy item (name will be changed) */
- InsMenuItem(TheMenu->DaMenuHandle,"\px",Index - 1);
- /* convert name */
- Scan = 0;
- while ((Scan < 255) && (MenuItemName[Scan] != 0))
- {
- NameTemp[Scan + 1] = MenuItemName[Scan];
- Scan += 1;
- }
- NameTemp[0] = Scan;
- /* set the name properly */
- SetItem(TheMenu->DaMenuHandle,Index,NameTemp);
- SetItemCmd(TheMenu->DaMenuHandle,Index,Shortcut);
- /* set item's ID mapping */
- MenuItem->MenuManagerID = ((long)(TheMenu->MenuID) << 16) | Index;
- MenuItem->WhatMenu = TheMenu;
- return MenuItem;
- }
-
-
- /* delete the specified item from the menu. */
- void KillMenuItem(MenuItemType* TheItem)
- {
- long Scan;
- long Limit;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- /* remove item from item list */
- ArrayDeleteElement(OurItemList,ArrayFindElement(OurItemList,TheItem));
- /* delete item from actual menu */
- DelMenuItem(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff);
- /* fix up item IDs for items after this one on the same menu */
- Limit = ArrayGetLength(OurItemList);
- for (Scan = 0; Scan < Limit; Scan += 1)
- {
- MenuItemType* OtherItem;
-
- OtherItem = (MenuItemType*)ArrayGetElement(OurItemList,Scan);
- if (((TheItem->MenuManagerID >> 16) == (OtherItem->MenuManagerID >> 16))
- && ((TheItem->MenuManagerID & 0xffff) < (OtherItem->MenuManagerID & 0xffff)))
- {
- /* all items after this one move up. We don't have to do masking and */
- /* all that because item IDs (low 16 bits) are positive, so a borrow */
- /* will never occur */
- OtherItem->MenuManagerID -= 1;
- }
- }
- /* fix up apple menu length */
- if (TheItem->WhatMenu == AppleMenu)
- {
- NumAppleMenuItems -= 1;
- }
- /* release the memory */
- ReleasePtr((char*)TheItem);
- }
-
-
- /* enable a menu item. Items may only be selected if enabled. */
- void EnableMenuItem(MenuItemType* TheItem)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- EnableItem(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff);
- }
-
-
- /* disable a menu item. */
- void DisableMenuItem(MenuItemType* TheItem)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- DisableItem(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff);
- }
-
-
- /* Set an implementation defined mark to indicate that the menu item has been */
- /* persistently selected. On the Macintosh, this places a checkmark to the left */
- /* of the name of the menu item */
- void SetItemCheckmark(MenuItemType* TheItem)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- SetItemMark(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff,checkMark);
- }
-
-
- /* remove the implementation defined mark */
- void ClearItemCheckmark(MenuItemType* TheItem)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- SetItemMark(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff,noMark);
- }
-
-
- /* change the name of a menu item */
- void ChangeItemName(MenuItemType* TheItem, char* NewName)
- {
- unsigned char NameTemp[256];
- long Scan;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheItem);
- Scan = 0;
- while ((Scan < 255) && (NewName[Scan] != 0))
- {
- NameTemp[Scan + 1] = NewName[Scan];
- Scan += 1;
- }
- NameTemp[0] = Scan;
- SetItem(TheItem->WhatMenu->DaMenuHandle,TheItem->MenuManagerID & 0xffff,NameTemp);
- }
-
-
- /* Add an implementation defined "separator" to the end of the menu. On the */
- /* Macintosh, this separator is a grey line. */
- void AppendSeparator(MenuType* TheMenu)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- CheckPtrExistence(TheMenu);
- AppendMenu(TheMenu->DaMenuHandle,"\p(-");
- }
-
-
- /* Disable all menu items, remove any checkmarks */
- void WipeMenusClean(void)
- {
- long Scan;
- long Limit;
-
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- Limit = ArrayGetLength(OurItemList);
- for (Scan = 0; Scan < Limit; Scan += 1)
- {
- MenuItemType* Item;
-
- Item = (MenuItemType*)ArrayGetElement(OurItemList,Scan);
- DisableMenuItem(Item);
- ClearItemCheckmark(Item);
- }
- }
-
-
- /* internal routine for converting the number returned from the Toolbox into */
- /* one of our own ID numbers. if the MMID number is an apple menu item, then */
- /* it is handled here and NIL is returned. */
- MenuItemType* Eep_MMID2ItemID(long MMID)
- {
- ERROR(!Initialized,PRERR(ForceAbort,"Menu manager hasn't been initialized"));
- if ((AppleMenu != NIL) && ((MMID >> 16) == AppleMenu->MenuID)
- && ((MMID & 0xffff) > NumAppleMenuItems))
- {
- Str255 DeskAccName;
-
- GetItem(AppleMenu->DaMenuHandle,MMID & 0xffff,DeskAccName);
- APRINT(("*OpenDeskAcc %p",DeskAccName));
- OpenDeskAcc(DeskAccName);
- HiliteMenu(0);
- }
- else
- {
- long Scan;
- long Limit;
-
- Limit = ArrayGetLength(OurItemList);
- for (Scan = 0; Scan < Limit; Scan += 1)
- {
- MenuItemType* Item;
-
- Item = (MenuItemType*)ArrayGetElement(OurItemList,Scan);
- if (Item->MenuManagerID == MMID)
- {
- return Item;
- }
- }
- }
- /* fall through == no item. */
- return NIL;
- }
-
-
- /* this is called from the event loop to redraw the menu bar if it needs it. */
- /* redraws are deferred and unified to save time. */
- void Eep_RedrawMenuBar(void)
- {
- if (RedrawMenuBarFlag)
- {
- DrawMenuBar();
- RedrawMenuBarFlag = False;
- }
- }
-