home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1995 March
/
macformat-022.iso
/
Shareware City
/
Developers
/
MA3.1.1 & CW4.5
/
Modifications
/
*OR* replace these files
/
UMenuMgr.cp
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS
UTF-8
Wrap
Text File
|
1994-09-17
|
60.9 KB
|
1,993 lines
|
[
TEXT/MPS
]
/*
* This file has been changed from the original MacApp 3.1.1
* to support the metrowerks CodeWarrior compilers C/C++ 1.1.1.
* These changes are known *not* to work with earlier versions
* of CodeWarrior. Every attempt though has been made to to keep
* this file compatible with other development environments.
*
* Mark Anderson
* metrowerks
* 9/16/94
*
*/
//----------------------------------------------------------------------------------------
// UMenuMgr.cp
// Copyright © 1984-1994 by Apple Computer Inc. All rights reserved.
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
// Theory of Operation
//
// This unit provides two features: It implements a command numbering system that is
// independent of menu/ item placement, and implements a framework for optimizing menu
// setups. The command numbering system works by assigning commands a unique command
// number, and providing a mechanism for mapping command numbers to menu/ item pairs. A
// set of routines are provide to manipulate commands via their command number rather
// than their menu and item numbers.
//
// Each command can be assigned an integer command number from 1 to 32767. To associate a
// command number with a menu item, menu resources are defined with the 'CMNU' resource
// type--not the 'MENU' type. The 'CMNU' type is just like the 'MENU' type, with an
// additional command number field for each menu item. This unit converts the 'CMNU'
// resource into a 'MENU' dynamically at run time.
//
// The items of some menus cannot be determined until run-time. The font menu is an
// example. In such cases, no command number is assigned by you. Instead, the command
// number is equal to -(256 * menu + item). The procedure CommandToMenuItem converts a
// command number to a menu id and item number by the following method:
//
// - If the command number is positive, the command table is searched for the number. If
// it is found, CommandToMenuItem returns the corre- sponding menu id and item
// number. Otherwise the menu and item are zero.
//
// - If the command number is negative, the menu number is the upper eight bits, and the
// item number the lower eight bits, of the absolute value of the command number. (This
// implies that menu id's must be <= 127 and item numbers must be <= 255.) The function
// CommandFromMenuItem converts menu/ items to command numbers by the following method:
//
// - If the item number is positive, the command table is search for the given menu/ item
// pair. If found, the corresponding command number is returned. If not found, the number
// returned is equal to
// -(256 * menu + item).
// - If the item number is negative, the number returned is equal to
// -item number.
//
// Note that CommandToMenuItem and CommandFromMenuItem work regardless of whether the
// command is actually installed in the menu bar. MacApp takes advantage of this feature
// by having a set of generic "buzz" commands, whose primary use is to set the name of the
// Undo command (e.g. 'Undo Drawing').
//
// The second feature of this unit is to optimize menu setups (changing the appearance of
// menus and items). Normally, each call to CheckItem, SetItemStyle and SetCommandIcon in
// turn calls CalcMenuSize because the width or height of the menu may have changed. If
// menu setups are done all at one time, then CalcMenuSize can be deferred until the end
// of the setup process. The procedure PerformMenuSetup implements this mechanism. It relies
// on the fact that menu setups are done all at once, and that you will call
// SetCommandName, SetItemStyle and SetCommandIcon instead of SetItem, SetItemStyle and
// SetCommandIcon. It works only for menus whose id is from 1 to mLastMenu. Menus with IDs
// greater than mLastMenu are not affected by this scheme.
//
// PerformMenuSetup accepts one parameter, a procedure which actually implements the menu
// appearance changes. SetupMenus performs the following steps:
//
// - Before calling your menu setup procedure, StartupMenuSetup is called. It disables all
// menus and items, remembers the current menu proc and enabled flags of each menu, and
// sets the MenuProc of each menu to gHNullMenuProc, thereby disabling CalcMenuSize.
//
// - Your procedure is called.It in turn calls SetCommandName, SetCmdStyle, SetCommandIcon,
// Enable, EnableCheck, or a Toolbox routine (provided it isn't SetItem, SetItemStyle or
// SetCommandIcon).
//
// - Menus with at least one enabled item are enabled, CalcMenuSize is called for those
// menus that need it, each menu's menuproc is restored, and DrawMenuBar is called if the
// enabled state of any menu changed.
//----------------------------------------------------------------------------------------
#ifndef __UMENUMGR__
#include <UMenuMgr.h>
#endif
#ifndef __STDIO__
#include <stdio.h>
#endif
#ifndef __GEOMETRY__
#include <Geometry.h>
#endif
#ifndef __MEMORY__
#include <Memory.h>
#endif
#ifndef __UOBJECT__
#include <UObject.h>
#endif
#ifndef __UFAILURE__
#include <UFailure.h>
#endif
#ifndef __ULIST__
#include <UList.h>
#endif
#ifndef __UPATCH__
#include <UPatch.h>
#endif
#ifndef __UMEMORY__
#include <UMemory.h>
#endif
#ifndef __TEXTEDIT__
#include <TextEdit.h>
#endif
#ifndef __OSUTILS__
#include <OSUtils.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __UMACAPPGLOBALS__
#include <UMacAppGlobals.h>
#endif
#ifndef __TRAPS__
#include <Traps.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __UITERATOR__
#include <UIterator.h>
#endif
#ifndef __UAPPLICATION__
#include <UApplication.h>
#endif
#ifndef __BALLOONS__
#include <Balloons.h>
#endif
#ifndef __LOWMEM__
#include <LowMem.h>
#endif
//----------------------------------------------------------------------------------------
const Boolean kHierarchical = true;
const Boolean kNotHierarchical = !kHierarchical;
const Boolean kDoHierarchical = true;
const Boolean kDontDoHierarchical = !kDoHierarchical;
typedef struct MenuCmdRecord
{
CommandNumber theCmdNumber;
ResNumber theMenuNumber;
short theItemNumber;
} *MenuCmdRecordPtr, ** MenuCmdRecordHandle;
//----------------------------------------------------------------------------------------
// TCmdTable:
//----------------------------------------------------------------------------------------
DeclareClassDesc(TCmdTable);
class TCmdTable : public TSortedDynamicArray
{
DeclareClass(TCmdTable);
public:
void ICmdTable();
virtual CompareResult CompareElements(void* Element1,
void* Element2); // override
virtual void CommandToMenuItem(CommandNumber theCommand,
MenuID& menu,
short& item);
virtual CommandNumber CommandFromMenuItem(short menu, short item);
// Given a menuID,item # return the appropriate command number.
// If there is no such command number, return -BOR(((menu) << 8), item).
// If the item number is <0 then assume that it is a negative command number.
void AddToTable(CommandNumber commandNumber,
MenuID menuNumber,
short itemNumber);
void AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
MenuID menuNumber,
short itemNumber);
// This adds a menu item/command number after the menus have already been
// set up, and updates all the tables
void DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber);
// This deletes a menu item/command number after the menus have already
// been set up, and updates all the tables
};
//----------------------------------------------------------------------------------------
// TMenuTable:
//----------------------------------------------------------------------------------------
DeclareClassDesc(TMenuTable);
class TMenuTable : public TSortedHandleList
{
DeclareClass(TMenuTable);
public:
void IMenuTable();
MenuHandle GetMenu(MenuID menuID);
virtual CompareResult Compare(Handle item1, Handle item2); // override
};
typedef struct MenuIDRecord
{
ResNumber fMenuResID;
MenuID fMenuID;
} *MenuIDRecordPtr, **MenuIDRecordHandle;
//----------------------------------------------------------------------------------------
// TMenuIDList:
//----------------------------------------------------------------------------------------
DeclareClassDesc(TMenuIDList);
class TMenuIDList: public TSortedDynamicArray
{
DeclareClass(TMenuIDList);
public:
void IMenuIDList();
virtual CompareResult CompareElements(void* Element1, void* Element2); // override
MenuID MenuIDFromResID(ResNumber menuResID);
void AddToTable(ResNumber menuResID, MenuID menuID);
};
Handle pHNullMenuProc = NULL; // Handle to NULL menu proc
TCmdTable* gCmdTable = NULL; // command numbers and their associated menu
// and item numbers
TMenuTable* gMenuTable = NULL; // list of menus created/managed by MacApp
TMenuIDList* gMenuIDList; // list of menu IDs sorted by resource ID
pascal void NullMenuProc(short message,
MenuHandle aMenuHandle,
CRect& menuRect,
CPoint hitPt,
short& whichItem);
//----------------------------------------------------------------------------------------
static Boolean gMenusAreInvalid = true;
// Used by InvalidateMenus to track whether menus need to be setup.
static Boolean gMenuBarIsInvalid = true;
// Used by InvalidateMenuBar, if the InvalMenuBar trap is not implemented, to track
// whether the menubar is invalid and will need redrawing.
TMenuBarManager* gMenuBarManager = NULL;
#if qDebug
Boolean gTraceSetupMenus = false;
#endif
//========================================================================================
// struct CGetMenuID
//========================================================================================
struct CGetMenuID
{
public:
// Fields
ResNumber& menuResID;
TMenuIDList* theMenuIDList;
// Constructor
CGetMenuID(ResNumber& aMenuResID, TMenuIDList* aMenuIDList) :
menuResID(aMenuResID),
theMenuIDList(aMenuIDList)
{
}
};
//----------------------------------------------------------------------------------------
// TestMenuResIDs:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CompareResult TestMenuResIDs(ArrayIndex anItem, void* staticLink)
{
CGetMenuID* testInfo = (CGetMenuID*)staticLink;
ResNumber theMenuResIDitem;
theMenuResIDitem = ((MenuIDRecordPtr)testInfo->theMenuIDList->ComputeAddress(anItem))->fMenuResID;
if (theMenuResIDitem > testInfo->menuResID)
return kItemGreaterThanCriteria;
else if (theMenuResIDitem < testInfo->menuResID)
return kItemLessThanCriteria;
else
return kItemEqualCriteria;
} // TestMenuResIDs
//========================================================================================
// CLASS TMenuIDList
//========================================================================================
#undef Inherited
#define Inherited TSortedDynamicArray
#pragma segment MAInit
DefineClass(TMenuIDList, Inherited);
//----------------------------------------------------------------------------------------
// TMenuIDList::IMenuIDList:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void TMenuIDList::IMenuIDList()
{
this->ISortedDynamicArray(0, sizeof(MenuIDRecord));
} // TMenuIDList::IMenuIDList
//----------------------------------------------------------------------------------------
// TMenuIDList::CompareElements:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CompareResult TMenuIDList::CompareElements(void* Element1, void* Element2) // override
{
ResNumber theResNumber1 = ((MenuIDRecordPtr)Element1)->fMenuResID;
ResNumber theResNumber2 = ((MenuIDRecordPtr)Element2)->fMenuResID;
if (theResNumber1 > theResNumber2)
return kItem1GreaterThanItem2;
else if (theResNumber1 < theResNumber2)
return kItem1LessThanItem2;
else
return kItem1EqualItem2;
} // TMenuIDList::CompareElements
//----------------------------------------------------------------------------------------
// TMenuIDList::AddToTable:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuIDList::AddToTable(ResNumber menuResID, MenuID menuID)
{
MenuIDRecord arec;
arec.fMenuResID = menuResID;
arec.fMenuID = menuID;
this->InsertElementInOrder((Ptr) & arec);
} // TMenuIDList::AddToTable
//----------------------------------------------------------------------------------------
// TMenuIDList::MenuIDFromResID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuID TMenuIDList::MenuIDFromResID(ResNumber menuResID)
{
ArrayIndex index;
CGetMenuID aCGetMenuID(menuResID,this);
if (this->DoSearchElement(&TestMenuResIDs, &aCGetMenuID, index))
{
MenuIDRecordPtr aMenuIDListPtr = (MenuIDRecordPtr)ComputeAddress(index);
return aMenuIDListPtr->fMenuID;
}
return 0;
} // TMenuIDList::MenuIDFromResID
//========================================================================================
// CLASS TCmdTable
//========================================================================================
#undef Inherited
#define Inherited TSortedDynamicArray
#pragma segment MAInit
DefineClass(TCmdTable, Inherited);
//----------------------------------------------------------------------------------------
// TCmdTable::ICmdTable:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void TCmdTable::ICmdTable()
{
this->ISortedDynamicArray(0, sizeof(MenuCmdRecord));
} // TCmdTable::ICmdTable
//----------------------------------------------------------------------------------------
// TCmdTable::CompareElements:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CompareResult TCmdTable::CompareElements(void* Element1, void* Element2) // override
{
CommandNumber theCommanditem1 = ((MenuCmdRecordPtr)Element1)->theCmdNumber;
CommandNumber theCommanditem2 = ((MenuCmdRecordPtr)Element2)->theCmdNumber;
if (theCommanditem1 > theCommanditem2)
return kItem1GreaterThanItem2;
else if (theCommanditem1 < theCommanditem2)
return kItem1LessThanItem2;
else
return kItem1EqualItem2;
} // TCmdTable::CompareElements
//--------------------------------------------------------------------------------------------------
class CCmdToMenuItem
{
public:
CommandNumber& theCommand;
TCmdTable* theCmdTable;
CCmdToMenuItem(CommandNumber& aCommand,
TCmdTable* aCmdTable) :
theCommand(aCommand),
theCmdTable(aCmdTable)
{
}
};
#pragma segment MAMenuRes
CompareResult CmdToMenuItem_TestItem(ArrayIndex anItem, void* staticLink)
{
CCmdToMenuItem* testInfo = (CCmdToMenuItem*)staticLink;
CommandNumber theCommanditem;
theCommanditem = ((MenuCmdRecordPtr)testInfo->theCmdTable->ComputeAddress(anItem))->theCmdNumber;
if (theCommanditem > testInfo->theCommand)
return kItemGreaterThanCriteria;
else if (theCommanditem < testInfo->theCommand)
return kItemLessThanCriteria;
else
return kItemEqualCriteria;
}
//----------------------------------------------------------------------------------------
// TCmdTable::CommandToMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TCmdTable::CommandToMenuItem(CommandNumber theCommand,
MenuID& menu,
short& item)
{
ArrayIndex index = 0;
MenuCmdRecordPtr aMenuCmdRecordPtr;
CCmdToMenuItem aCCmdToMenuItem(theCommand, this);
if (theCommand < 0) /* negative commands are mapped not table based */
{
menu = (short)((-theCommand) >> 8);
item = (short)((-theCommand) & 255);
}
else
{
if (this->DoSearchElement(&CmdToMenuItem_TestItem, &aCCmdToMenuItem, index))
{
do
{
index--;
if (index == 0)
break;
aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
}
while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
++index;
do
{
aMenuCmdRecordPtr = (MenuCmdRecordPtr)ComputeAddress(index);
if (aMenuCmdRecordPtr->theCmdNumber == theCommand)
{
menu = aMenuCmdRecordPtr->theMenuNumber;
item = aMenuCmdRecordPtr->theItemNumber;
if (::GetMenuHandle(menu) != NULL)
break;
}
++index;
}
while (aMenuCmdRecordPtr->theCmdNumber == theCommand);
}
else// not found
{
menu = 0;
item = 0;
}
} // else
} // TCmdTable::CommandToMenuItem
//----------------------------------------------------------------------------------------
// TCmdTable::CommandFromMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CommandNumber TCmdTable::CommandFromMenuItem(short menu, short item)
// Given a menuID/item # return the appropriate command number. if there
// is no such command number, return -BOR(((menu) << 8), item). If the
// item number is <0 then assume that it is a negative command number.
{
if (item < 0)
return -item;
else
{
if (item > 0)
{
// Search the table linearly.
for (ArrayIndex i = 1; i <= this->GetSize(); ++i)
{
MenuCmdRecordPtr aMenuCmdRecordPtr = (MenuCmdRecordPtr)this->ComputeAddress(i);
if ((menu == aMenuCmdRecordPtr->theMenuNumber) && (item == aMenuCmdRecordPtr->theItemNumber))
{
return aMenuCmdRecordPtr->theCmdNumber;
}
}
}
#if qDebugMsg
if ((menu > 127) || (item > 255))
{
fprintf(stderr, "menu : %1d , item : %1d \n", menu, item);
fprintf(stderr, "Menu/item number is too big for a negative command number!\n");
ProgramBreak("Try using a negative item number instead.");
}
#endif
return -((menu << 8) | item);
}
} // TCmdTable::CommandFromMenuItem
//----------------------------------------------------------------------------------------
// TCmdTable::AddToTable:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void TCmdTable::AddToTable(CommandNumber commandNumber,
MenuID menuNumber,
short itemNumber)
{
MenuCmdRecord arec;
if (commandNumber > 0) // Negative numbers are mapped not tabled
{
arec.theCmdNumber = commandNumber;
arec.theMenuNumber = menuNumber;
arec.theItemNumber = itemNumber;
this->InsertElementInOrder((Ptr) & arec);
}
} // TCmdTable::AddToTable
//----------------------------------------------------------------------------------------
// TCmdTable::AddNewCmdToTableAndUpdateTable:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TCmdTable::AddNewCmdToTableAndUpdateTable(CommandNumber commandNumber,
MenuID menuNumber,
short itemNumber)
{
MenuCmdRecord arec;
for (ArrayIndex i = 1; i <= this->GetSize(); i++)
{
this->GetElementsAt(i, &arec, 1);
if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber >= itemNumber))
{
// If we have found an item in the same menu as we are adding to and it is
// the same index or greater then bump its itemNumber
arec.theItemNumber++;
// Write it back out
this->ReplaceElementsAt(i, &arec, 1);
}
}
// Insert the new menu item
arec.theCmdNumber = commandNumber;
arec.theMenuNumber = menuNumber;
arec.theItemNumber = itemNumber;
this->InsertElementInOrder((Ptr) &arec);
} // TCmdTable::AddNewCmdToTableAndUpdateTable
//----------------------------------------------------------------------------------------
// TCmdTable::DeleteCmdAndUpdateTable:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TCmdTable::DeleteCmdAndUpdateTable(CommandNumber theMenuItemCommandNumber)
{
MenuCmdRecord arec;
short menuNumber;
short itemNumber;
this->CommandToMenuItem(theMenuItemCommandNumber, menuNumber, itemNumber);
for (ArrayIndex i = 1; i <= this->GetSize(); i++)
{
this->GetElementsAt(i, &arec, 1);
if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber > itemNumber))
{
// If we have found an item in the same menu as we are deleting from and its
// index is greater then decrement its itemNumber
arec.theItemNumber--;
// Write it back out
this->ReplaceElementsAt(i, &arec, 1);
}
else if ((arec.theMenuNumber == menuNumber) && (arec.theItemNumber == itemNumber))
{
// Delete the element
this->DeleteElementsAt(i, 1);
}
}
} // TCmdTable::DeleteCmdAndUpdateTable
//----------------------------------------------------------------------------------------
// TestForMenuID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CompareResult TestForMenuID(Handle anItem, void* staticLink)
{
MenuID* menuID = (MenuID*)staticLink;
short menuIDitem = (*((MenuHandle)anItem))->menuID;
if (menuIDitem > *menuID)
return kItemGreaterThanCriteria;
else if (menuIDitem < *menuID)
return kItemLessThanCriteria;
else
return kItemEqualCriteria;
} // TestForMenuID
//========================================================================================
// CLASS TMenuTable
//========================================================================================
#undef Inherited
#define Inherited TSortedHandleList
#pragma segment MAInit
DefineClass(TMenuTable, Inherited);
//----------------------------------------------------------------------------------------
// TMenuTable::IMenuTable:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void TMenuTable::IMenuTable()
{
this->ISortedHandleList();
} // TMenuTable::IMenuTable
//----------------------------------------------------------------------------------------
// TMenuTable::GetMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle TMenuTable::GetMenu(MenuID menuID)
{
ArrayIndex index;
return ((MenuHandle)this->DoSearch(&TestForMenuID, &menuID, index)); // discard index
} // TMenuTable::GetMenu
//----------------------------------------------------------------------------------------
// TMenuTable::Compare:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CompareResult TMenuTable::Compare(Handle item1, Handle item2) // override
{
MenuID menuID1 = (*((MenuHandle)item1))->menuID;
MenuID menuID2 = (*((MenuHandle)item2))->menuID;
if (menuID1 > menuID2)
return kItem1GreaterThanItem2;
else if (menuID1 < menuID2)
return kItem1LessThanItem2;
else
return kItem1EqualItem2;
} // TMenuTable::Compare
//========================================================================================
// GLOBAL Procedures
//========================================================================================
#undef Inherited
#if qDebugMsg
//----------------------------------------------------------------------------------------
// TraceMenuName:
//----------------------------------------------------------------------------------------
#pragma segment MADebug
char TraceMenuName(CommandNumber aCommand)
// For debugging purposes only--used to dump the name and number of a command
{
CStr255 cmdName;
CommandToName(aCommand, cmdName);
fprintf(stderr, " %1d [%s],", aCommand, (char *) cmdName);
return ' ';
} // TraceMenuName
#endif
//----------------------------------------------------------------------------------------
// InvalidateMenus:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void InvalidateMenus()
{
gMenusAreInvalid = true;
} // InvalidateMenus
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
struct MenuBarRecord
{
ResNumber nMenus;
ResNumber menuResID[1000];
};
//----------------------------------------------------------------------------------------
// AddMenuBar:
//----------------------------------------------------------------------------------------
typedef MenuBarRecord* MenuBarPtr, ** MenuBarHandle;
void AddMenuBar(ResNumber itsID,
Boolean isHierarchical)
{
short hier = 0;
MenuBarHandle hmbar;
if (isHierarchical)
hier = -1;
hmbar = (MenuBarHandle)GetResource('MBAR', itsID);
if (hmbar)
{
for (ResNumber i = 0; i < (*hmbar)->nMenus; ++i)
{
ResNumber menuResID = (*hmbar)->menuResID[i];
MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
if (!::GetMenuHandle( menuID )) // do nothing if it's already in menubar
{
MenuHandle aMenu = MAGetMenu(menuResID);
if (aMenu)
{
MAInsertMenu(aMenu, menuResID, hier);
// a visible menu needed insertion thus the menubar became invalid
if (!isHierarchical)
InvalidateMenuBar();
}
}
}
ReleaseResource((Handle)hmbar);
// hmbar = NULL;
}
} // AddMenuBar
//----------------------------------------------------------------------------------------
// ValidateMenus:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void ValidateMenus()
{
gMenusAreInvalid = false;
} // ValidateMenus
//----------------------------------------------------------------------------------------
// MenusHavePendingUpdate:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
Boolean MenusHavePendingUpdate()
{
return gMenusAreInvalid;
} // MenusHavePendingUpdate
//----------------------------------------------------------------------------------------
// InvalidateMenuBar:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void InvalidateMenuBar()
{
InvalidateMenus(); // if the menubar is invalidated then the
// menu items must be also
// On systems that have "InvalMenuBar" use that functionality. The system will redraw
// the menu bar at the next convenient time.
if (qNeedsSystem7 || TrapExists(_InvalMenuBar))
InvalMenuBar();
else
gMenuBarIsInvalid = true;
} // InvalidateMenuBar
//----------------------------------------------------------------------------------------
// ValidateMenuBar:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
static void ValidateMenuBar()
{
gMenuBarIsInvalid = false;
} // ValidateMenuBar
//----------------------------------------------------------------------------------------
// MenuBarHasPendingUpdate:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
static Boolean MenuBarHasPendingUpdate()
{
return gMenuBarIsInvalid;
} // MenuBarHasPendingUpdate
//----------------------------------------------------------------------------------------
// CommandEnabled:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
Boolean CommandEnabled(CommandNumber command)
{
MenuID menuNo;
short itemNo;
MenuHandle theMenu;
theMenu = CommandToComponents(command, menuNo, itemNo);
if (theMenu)
if ((itemNo > 0) && (itemNo < 32))
return ((((*theMenu)->enableFlags >> itemNo) & 0x01) != 0);
else
return true;
else
return false;
} // CommandEnabled
//----------------------------------------------------------------------------------------
// CommandFromMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CommandNumber CommandFromMenuItem(short menu,
short item)
{
return gCmdTable->CommandFromMenuItem(menu, item);
} // CommandFromMenuItem
//----------------------------------------------------------------------------------------
// CommandToMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void CommandToMenuItem(CommandNumber aCommand,
MenuID& menu,
short& item)
{
gCmdTable->CommandToMenuItem(aCommand, menu, item);
} // CommandToMenuItem
//----------------------------------------------------------------------------------------
// CommandToName:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void CommandToName(CommandNumber aCommand,
CStr255& menuText)
{
short anItem;
ResNumber aMenu;
menuText = "";
MenuHandle mHandle = CommandToComponents(aCommand, aMenu, anItem);
if (mHandle)
GetMenuItemText(mHandle, anItem, menuText);
} // CommandToName
//----------------------------------------------------------------------------------------
// CommandToComponents:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle CommandToComponents(CommandNumber command,
MenuID& menuNo,
short& itemNo)
{
CommandToMenuItem(command, menuNo, itemNo);
if (menuNo) // was found
return MAGetMenuHandle(menuNo);
else
return NULL;
} // CommandToComponents
//----------------------------------------------------------------------------------------
// Enable:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void Enable(CommandNumber aCommand,
Boolean canDo)
{
MenuID menu;
short item;
#if qDebugMsg
if (gTraceSetupMenus)
fprintf(stderr, "..... Enable(%c%s)\n", TraceMenuName(aCommand), (char *) gBoolString[canDo]);
#endif
MenuHandle aMenuHandle = CommandToComponents(aCommand, menu, item);
if (aMenuHandle)
if (canDo)
EnableItem(aMenuHandle, item);
else
DisableItem(aMenuHandle, item);
} // Enable
//----------------------------------------------------------------------------------------
// EnableCheck:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void EnableCheck(CommandNumber aCommand,
Boolean canDo,
Boolean checkIt)
{
MenuID menu;
short item;
MenuHandle aMenuHandle;
#if qDebugMsg
if (gTraceSetupMenus)
fprintf(stderr, "..... EnableCheck(%c%s, %s)\n",
TraceMenuName(aCommand),
(char *) gBoolString[canDo],
(char *) gBoolString[checkIt]);
#endif
aMenuHandle = CommandToComponents(aCommand, menu, item);
if (aMenuHandle)
{
if (canDo)
EnableItem(aMenuHandle, item);
else
DisableItem(aMenuHandle, item);
CheckItem(aMenuHandle, item, checkIt);
}
} // EnableCheck
//========================================================================================
// GLOBAL Procedures
//========================================================================================
#undef Inherited
//----------------------------------------------------------------------------------------
// GetResMenu: Allow us to get a menu when it's not available via ::GetMenuHandle.
//----------------------------------------------------------------------------------------
MenuHandle GetResMenu(ResNumber menuResID)
{
MenuHandle theMenuHandle;
FailInfo fi;
short oldResFile = CurResFile();
Try(fi)
{
UseResFile(gApplicationRefNum);
theMenuHandle = (MenuHandle) GetResource('MENU', menuResID);
fi.Success();
}
else
{
UseResFile(oldResFile);
fi.ReSignal();
}
UseResFile(oldResFile);
return theMenuHandle;
} // GetResMenu
//----------------------------------------------------------------------------------------
// ConvertToMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
MenuHandle ConvertToMenu(Handle CMNUHandle)
{
MenuHandle theMenuHandle = NULL;
Ptr theCMNUPtr;
Ptr theMENUPtr;
short i;
MenuID menuNo;
short itemNo;
CommandNumber cmdNo;
Ptr endPtr;
theMenuHandle = (MenuHandle)NewPermHandle(GetHandleSize(CMNUHandle));
LockHandleHigh(CMNUHandle);
LockHandleHigh((Handle)theMenuHandle);
theCMNUPtr = (Ptr)StripLong(*CMNUHandle);
theMENUPtr = (Ptr)StripLong(*theMenuHandle);
menuNo = *((IntegerPtr)theCMNUPtr);
i = (*((CStr255 *)(theCMNUPtr + 14))).Length() + 15;
BlockMove(theCMNUPtr, theMENUPtr, i); // move menu header into MENU resource
theCMNUPtr = (Ptr)(theCMNUPtr + i);
theMENUPtr = (Ptr)(theMENUPtr + i);
itemNo = 0;
endPtr = (Ptr)(theCMNUPtr + GetHandleSize(CMNUHandle));
while ((theCMNUPtr < endPtr) && (((*((CStr255 *)theCMNUPtr)).Length()) != 0))
{
i = ((*((CStr255 *)theCMNUPtr)).Length()) + 5;
BlockMove(theCMNUPtr, theMENUPtr, i); // move menu item data sans command number
theCMNUPtr = (Ptr)(theCMNUPtr + i);
theMENUPtr = (Ptr)(theMENUPtr + i);
if ((((long)theCMNUPtr) & 0x00000001) == 1)// word align
theCMNUPtr = (Ptr)(theCMNUPtr + 1);
cmdNo = *((CommandNumberPtr)theCMNUPtr);
++itemNo;
theCMNUPtr = (Ptr) (theCMNUPtr + sizeof(CommandNumber));
gCmdTable->AddToTable(cmdNo, menuNo, itemNo);
}
(*theMENUPtr) = 0; // termination mark
++theMENUPtr;
SetPermHandleSize((Handle)theMenuHandle, (Size)(theMENUPtr - StripLong((*theMenuHandle))));
HUnlock(CMNUHandle);
HUnlock((Handle)theMenuHandle);
return theMenuHandle;
} // ConvertToMenu
//----------------------------------------------------------------------------------------
// InitUMenuMgr:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void InitUMenuMgr()
{
short num;
MenuHandle newMenu;
Handle h;
short i;
ResNumber menuResID;
ResType menuResourceType;
Str255 menuResourceName;
// Create the MenuResID -> MenuID translation table
gMenuIDList = new TMenuIDList;
gMenuIDList->IMenuIDList();
// Create the command table
gCmdTable = new TCmdTable;
gCmdTable->ICmdTable();
// Create the menu table
gMenuTable = new TMenuTable;
gMenuTable->IMenuTable();
// initialize all CMNUs with positive id
num = CountResources('CMNU');
FailResError();
for (i = 1; i <= num; ++i)
{
Handle aCMNUHandle = GetIndResource('CMNU', i);
FailNILResource(aCMNUHandle);
GetResInfo( aCMNUHandle, &menuResID, &menuResourceType, menuResourceName );
short menuID = (* (MenuHandle) aCMNUHandle)->menuID;
if (((* (MenuHandle) aCMNUHandle)->menuID) > 0) // not in reserved range
{
// load the menudef and store it's reference in the menu
newMenu = ConvertToMenu(aCMNUHandle);
h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)) );
(*newMenu)->menuProc = h;
MAInsertInMenuTable(newMenu,menuResID);
}
}
// initialize all MENUs with positive id
num = CountResources('MENU');
FailResError();
for (i = 1; i <= num; ++i)
{
newMenu = (MenuHandle)GetIndResource('MENU', i);
if (newMenu)
{
GetResInfo( (Handle)newMenu, &menuResID, &menuResourceType, menuResourceName );
THz itsZone = HandleZone((Handle)newMenu);
// not a System menu and not in reserved range
if ((itsZone != SystemZone()) && ((*newMenu)->menuID) > 0)
{
// load the menudef and store it's reference in the menu
// h = GetResource('MDEF', (short)(((long)(*newMenu)->menuProc) >> sizeof(short)));
h = GetResource('MDEF', *((short*)(&(*newMenu)->menuProc)) );
(*newMenu)->menuProc = h;
MAInsertInMenuTable(newMenu,menuResID);
}
}
}
#if !qPowerPC
// Create the NULL menu proc
pHNullMenuProc = NewPermHandle(sizeof(JmpInstructionTemplate));
PatchJmpInstruction(*pHNullMenuProc, (void*)StripLong(NullMenuProc));
#else
// Create a MenuDefUPP for PowerPC builds…
pHNullMenuProc = NewPermHandle(sizeof(RoutineDescriptor));
RoutineDescriptor aMDEFUPP = BUILD_ROUTINE_DESCRIPTOR(uppMenuDefProcInfo, NullMenuProc);
BlockMove(&aMDEFUPP, *pHNullMenuProc, sizeof(RoutineDescriptor));
#endif
#if qDebugMsg
if (cUndo - cEditBase != kSysUndo)
fprintf(stderr, "Invalid UNDO command number\n");
if (cCut - cEditBase != kSysCut)
fprintf(stderr, "Invalid CUT command number\n");
if (cCopy - cEditBase != kSysCopy)
fprintf(stderr, "Invalid COPY command number\n");
if (cPaste - cEditBase != kSysPaste)
fprintf(stderr, "Invalid PASTE command number\n");
if (cClear - cEditBase != kSysClear)
fprintf(stderr, "Invalid CLEAR command number\n");
#endif
} // InitUMenuMgr
//----------------------------------------------------------------------------------------
// IsManagedMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
Boolean IsManagedMenu(MenuHandle theMenu)
{
return gMenuTable->GetIdentityItemNo((Handle)theMenu) != kEmptyIndex;
} // IsManagedMenu
//----------------------------------------------------------------------------------------
// MAGetMenuHandle:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle MAGetMenuHandle(MenuID menuID)
{
MenuHandle theMenu = ::GetMenuHandle(menuID); // do this first ... the menu is likely to
// be in the menubar and more likely of
// success, hence, faster
if (theMenu == NULL) // Try the menu list
{
theMenu = gMenuTable->GetMenu(menuID);
}
return theMenu;
} // MAGetMenuHandle
//----------------------------------------------------------------------------------------
// MAGetMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle MAGetMenu(ResNumber menuResID)
{
MenuID menuID = gMenuIDList->MenuIDFromResID(menuResID);
MenuHandle theMenu = MAGetMenuHandle(menuID); // First see if the menu is resident
if (theMenu == NULL) // darn! Try the resource chain
theMenu = GetResMenu(menuResID);
return theMenu;
} // MAGetMenu
//----------------------------------------------------------------------------------------
// MAGetNewMBar:
//----------------------------------------------------------------------------------------
#pragma segment MAInit
Handle MAGetNewMBar(ResNumber menuRsrcID)
{
MCTableHandle theColorTab;
Handle itsRsrcHandle;
SignedByte savedState;
Handle itsNewMBar;
if (qNeedsColorQD || gConfiguration.hasColorQD)
theColorTab = GetMCInfo();
// make the 'MBAR' resource non-purgeable, so the Toolbox doesn't die
itsRsrcHandle = GetResource('MBAR', menuRsrcID);
if (itsRsrcHandle)
{
savedState = HGetState(itsRsrcHandle);
HNoPurge(itsRsrcHandle);
}
itsNewMBar = GetNewMBar(menuRsrcID);
// restore the 'MBAR' resource
if (itsRsrcHandle)
HSetState(itsRsrcHandle, savedState);
if (theColorTab && (qNeedsColorQD || gConfiguration.hasColorQD))
{
HLock((Handle)theColorTab);
SetMCEntries((short)(GetHandleSize((Handle)theColorTab) / sizeof(MCEntry)), (*theColorTab));
HUnlock((Handle)theColorTab);
DisposeMCInfo(theColorTab);
}
return itsNewMBar;
} // MAGetNewMBar
//----------------------------------------------------------------------------------------
// MAInsertInMenuTable:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void MAInsertInMenuTable( MenuHandle theMenu, ResNumber menuResID )
{
gMenuTable->Insert((Handle) theMenu);
// Add the menu to the translation table
gMenuIDList->AddToTable( menuResID, (*theMenu)->menuID );
} // MAInsertInMenuTable
//----------------------------------------------------------------------------------------
// MAInsertMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void MAInsertMenu(MenuHandle theMenu, ResNumber menuResID, MenuID beforeID)
{
MenuCRsrcHandle theColorRsrc;
InsertMenu(theMenu, beforeID);
// Since only GetMenu automatically loads the appropriate color information,
// and (sigh) since we can only call GetMenu once, and if you call DeleteMenu
// all the good color stuff goes away (double sigh) we'll have to help out
// the Menu Manager by doing its job for it
if (qNeedsColorQD || gConfiguration.hasColorQD)
{
// n.b. This is using the menuID of the menu as a resource ID, which is incorrect
theColorRsrc = (MenuCRsrcHandle)GetResource('mctb', menuResID);
if (theColorRsrc)
{
HLock((Handle)theColorRsrc);
SetMCEntries((*theColorRsrc)->numEntries, &((*theColorRsrc)->mcEntryRecs[0]));
HUnlock((Handle)theColorRsrc);
ReleaseResource((Handle)theColorRsrc);
}
}
} // MAInsertMenu
//----------------------------------------------------------------------------------------
// NeedCalcMenuSize:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void NeedCalcMenuSize(MenuHandle aMenuHandle)
{
if ((*aMenuHandle)->menuProc == pHNullMenuProc)
(*aMenuHandle)->menuWidth = 0;
} // NeedCalcMenuSize
//----------------------------------------------------------------------------------------
// NullMenuProc: a NULL menuProc that is used to inhibit re-calculating the menu's size
// after each call to EnableItem, CheckItem, etc.
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
pascal void NullMenuProc(short,
MenuHandle aMenuHandle,
CRect& ,
CPoint,
short&)
{
(*aMenuHandle)->menuWidth = 0;
} // NullMenuProc
//----------------------------------------------------------------------------------------
// If hierarchical the range of IDs for applications is restricted. See IM V-236.
const ResNumber kHierarchicalMin = 0;
const ResNumber kHierarchicalMax = 235;
typedef Boolean EnableArray[mLastMenu + 1]; // Saved enable flags
typedef Handle SavePrArray[mLastMenu + 1]; // Saved menu procs
struct SetupStruct
{
EnableArray wasEnabled;
SavePrArray savedProcs;
};
typedef SetupStruct* SetupStructPtr;
//----------------------------------------------------------------------------------------
// IsSetupMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
Boolean IsSetupMenu(MenuHandle aMenuHandle,
Boolean isHierarchical)
{
if (!IsHandle((Handle) aMenuHandle))
{
#if qDebug
VerboseIsHandle((Handle) aMenuHandle);
ProgramBreak("In IsSetupMenu: not handed a handle.");
#endif
return false;
}
MenuID menuID = (*aMenuHandle)->menuID;
if (menuID == mApple) return false; // _NEVER_ managed!
#if qDebug
if (menuID == mDebug) return true;
#endif
if (isHierarchical)
{
if ((menuID < kHierarchicalMin) || (menuID > kHierarchicalMax))
return false; // must be in valid range for hierarchicals
}
return ((menuID >= mFirstMenu) && (menuID <= mLastMenu)); // Range of managed menus
} // IsSetupMenu
//----------------------------------------------------------------------------------------
// StartMenuSetup:
//----------------------------------------------------------------------------------------
void StartMenuSetup(MenuHandle aMenuHandle,
Boolean isHierarchical,
void* staticLink)
{
if (IsSetupMenu(aMenuHandle, isHierarchical))
{
/* Remember the menu itself was enabled, and disable the menu
and all of its items. */
MenuID menuID = (*aMenuHandle)->menuID;
((SetupStructPtr)staticLink)->wasEnabled[menuID] = (Boolean)((*aMenuHandle)->enableFlags & 1);
(*aMenuHandle)->enableFlags = 0;
// Save the menu's menuproc and set it to the NullMenuProc, so that
// CalcMenuSize is disabled (will do ÇalcMenuSize at end of setup).
((SetupStructPtr)staticLink)->savedProcs[menuID] = (*aMenuHandle)->menuProc;// See comment below
(*aMenuHandle)->menuProc = pHNullMenuProc;
// Uncheck all items.
short nItems = CountMItems(aMenuHandle);
for (short item = 1; item <= nItems; ++item)// Make sure we don't check items with sub-menus
{
short theCmd;
GetItemCmd(aMenuHandle, item, &theCmd);
if (theCmd != hMenuCmd)
CheckItem(aMenuHandle, item, false);// moves/purges memory
}
}
} // StartMenuSetup
//----------------------------------------------------------------------------------------
// EndMenuSetup:
//----------------------------------------------------------------------------------------
void EndMenuSetup(MenuHandle aMenuHandle,
Boolean isHierarchical,
void* staticLink)
{
long newFlags;
if (IsSetupMenu(aMenuHandle, isHierarchical))
{
newFlags = (*aMenuHandle)->enableFlags;
// If any items are enabled, enable the menu
if (newFlags != 0)
{
newFlags = (1 | newFlags);
(*aMenuHandle)->enableFlags = newFlags;
}
// If the menu's enabled state changed, we have to draw the menu bar.
if (((newFlags & 1) == 1) != ((SetupStructPtr)staticLink)->wasEnabled[(*aMenuHandle)->menuID])
InvalidateMenuBar();
// Restore the menuproc.
(*aMenuHandle)->menuProc = ((SetupStructPtr)staticLink)->savedProcs[(*aMenuHandle)->menuID];
// menuWidth set to 0 by routines that require CalcMenuSize, by
// calling NeedCalcMenu.
if (!(*aMenuHandle)->menuWidth)
CalcMenuSize(aMenuHandle);
}
} // EndMenuSetup
//----------------------------------------------------------------------------------------
// PerformMenuSetup:
//----------------------------------------------------------------------------------------
void PerformMenuSetup(MenuSetupType TheMenuSetterUpper, void* staticLink)
{
SetupStruct itsSetupStruct;
{// in a block to destroy the iterator
CMenuIterator iter;
for (MenuHandle item = iter.FirstMenu(); iter.More(); item = (MenuHandle)iter.NextMenu())
StartMenuSetup(item, kHierarchical, &itsSetupStruct);
}
TheMenuSetterUpper(staticLink);
{// in a block to destroy the iterator
CMenuIterator iter;
for (MenuHandle item = iter.FirstMenu(); iter.More(); item = (MenuHandle)iter.NextMenu())
EndMenuSetup(item, kHierarchical, &itsSetupStruct);
}
if (MenuBarHasPendingUpdate()) // Never executed on system with InvalMenuBar
{
// if InvalMenuBar is available don't redraw the menubar directly
if (!qNeedsSystem7 || !TrapExists(_InvalMenuBar))
DrawMenuBar();
ValidateMenuBar();
}
ValidateMenus();
} // PerformMenuSetup
//----------------------------------------------------------------------------------------
// SetCommandIcon:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void SetCommandIcon(CommandNumber aCommand,
Byte menuIcon)
{
MenuID menuID;
short item;
MenuHandle aMenuHandle;
#if qDebugMsg
if (gTraceSetupMenus)
fprintf(stderr, "..... SetCommandIcon(%c%d)\n", TraceMenuName(aCommand), menuIcon);
#endif
aMenuHandle = CommandToComponents(aCommand, menuID, item);
if (aMenuHandle)
SetItemIcon(aMenuHandle, item, menuIcon);
} // SetCommandIcon
//----------------------------------------------------------------------------------------
// SetCommandName:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void SetCommandName(CommandNumber aCommand,
const CStr255& menuText)
{
MenuID menuID;
short item;
MenuHandle aMenuHandle;
#if qDebugMsg
if (gTraceSetupMenus)
fprintf(stderr, "..... SetCommandName(%c“%s”)\n", TraceMenuName(aCommand), (char *) menuText);
#endif
#if qDebug
if (menuText.IsEmpty())
ProgramBreak("SetCommandName: empty menuText - may corrupt the menu handle!");
#endif
aMenuHandle = CommandToComponents(aCommand, menuID, item);
if (aMenuHandle)
SetMenuItemText(aMenuHandle, item, menuText);
} // SetCommandName
//----------------------------------------------------------------------------------------
// SetIndividualCommandName:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void SetIndividualCommandName(CommandNumber aCommand,
ResNumber rsrcID,
short strIndex)
{
CStr255 s;
GetIndString(s, rsrcID, strIndex);
SetCommandName(aCommand, s);
} // SetIndividualCommandName
//----------------------------------------------------------------------------------------
// SetMenuState:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void SetMenuState(CommandNumber aCommand,
ResNumber rsrcID,
short falseBuzzItem,
short trueBuzzItem,
Boolean stateVariable)
{
short buzzItem;
if (stateVariable)
buzzItem = trueBuzzItem;
else
buzzItem = falseBuzzItem;
SetIndividualCommandName(aCommand, rsrcID, buzzItem);
} // SetMenuState
//----------------------------------------------------------------------------------------
// SetStyle:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void SetStyle(CommandNumber aCommand, /* Style */ short aStyle)
{
MenuID menuID;
short item;
MenuHandle aMenuHandle;
#if qDebugMsg
if (gTraceSetupMenus)
fprintf(stderr, "..... SetStyle(%c%d)\n", TraceMenuName(aCommand), *((Ptr) & aStyle));
#endif
aMenuHandle = CommandToComponents(aCommand, menuID, item);
if (aMenuHandle)
SetItemStyle(aMenuHandle, item, aStyle);
} // SetStyle
//========================================================================================
// CLASS CMenuIterator
//========================================================================================
#undef Inherited
#define Inherited CHandleIterator
//----------------------------------------------------------------------------------------
// CMenuIterator::CMenuIterator: A simple iterator for menus.
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
CMenuIterator::CMenuIterator() : CHandleIterator(gMenuTable)
{
} // CMenuIterator::CMenuIterator
//----------------------------------------------------------------------------------------
// CMenuIterator::~CMenuIterator:
//----------------------------------------------------------------------------------------
#pragma segment IteratorRes
CMenuIterator::~CMenuIterator()
{
} // CMenuIterator::~CMenuIterator
//----------------------------------------------------------------------------------------
// CMenuIterator::CurrentMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle CMenuIterator::CurrentMenu()
{
return (MenuHandle)this->CurrentHandle();
} // CMenuIterator::CurrentMenu
//----------------------------------------------------------------------------------------
// CMenuIterator::FirstMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle CMenuIterator::FirstMenu()
{
return (MenuHandle)this->FirstHandle();
} // CMenuIterator::FirstMenu
//----------------------------------------------------------------------------------------
// CMenuIterator::NextMenu:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
MenuHandle CMenuIterator::NextMenu()
{
return (MenuHandle)this->NextHandle();
} // CMenuIterator::NextMenu
//----------------------------------------------------------------------------------------
// CMenuIterator::Advance:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void CMenuIterator::Advance() // override
{
CHandleIterator::Advance();
// only point at menus that are in the menulist
if (this->More() && !::GetMenuHandle((*(this->CurrentMenu()))->menuID))
this->Advance();
} // CMenuIterator::Advance
//========================================================================================
// CLASS TMenuBarManager
//========================================================================================
#undef Inherited
#define Inherited TObject
#pragma segment MAInit
DefineClass(TMenuBarManager, Inherited);
//----------------------------------------------------------------------------------------
// TMenuBarManager::TMenuBarManager: Empty constructor to satisfy the compiler.
//----------------------------------------------------------------------------------------
#pragma segment ConstructorRes
TMenuBarManager::TMenuBarManager()
{
} // TMenuBarManager::TMenuBarManager
//----------------------------------------------------------------------------------------
// TMenuBarManager::IMenuBarManager:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::IMenuBarManager( ResNumber otherMenus )
{
const CStr255 kParamText1 = "^0";
this->IObject();
fDisplayedMenus = kNoResource;
fPreferredMenuBarID = kNoResource;
fDisplayedHierMenus = kNoResource;
fPreferredHierMenuBarID = kNoResource;
// Add in the "other" menus, then clear them from the MenuBar
AddMenuBar(otherMenus, false);
ClearMenuBar();
// Initialize the Apple menu
MenuHandle aMenu = MAGetMenu(mApple);
if (aMenu)
AppendResMenu(aMenu, 'DRVR');
// If the "About" item contains the paramtext keystring (^0) then substitute the
// Application's name
CStr255 s;
CommandToName(cAboutApp, s);
short i = s.Pos(kParamText1);
if (i)
{
CStr255 apName;
gApplication->GetApplicationName(apName);
s.Delete(i, kParamText1.Length());
s.Insert(apName, i);
SetCommandName(cAboutApp, s);
}
} // TMenuBarManager::IMenuBarManager
//----------------------------------------------------------------------------------------
// TMenuBarManager::SetPreferredMenuBarID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::SetPreferredMenuBarID ( ResNumber theID )
{
fPreferredMenuBarID = theID;
} // TMenuBarManager::SetPreferredMenuBarID
//----------------------------------------------------------------------------------------
// TMenuBarManager::GetPreferredMenuBarID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
ResNumber TMenuBarManager::GetPreferredMenuBarID ()
{
return fPreferredMenuBarID;
} // TMenuBarManager::GetPreferredMenuBarID
//----------------------------------------------------------------------------------------
// TMenuBarManager::SetPreferredHierMenuBarID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::SetPreferredHierMenuBarID ( ResNumber theID )
{
fPreferredHierMenuBarID = theID;
} // TMenuBarManager::SetPreferredHierMenuBarID
//----------------------------------------------------------------------------------------
// TMenuBarManager::GetPreferredHierMenuBarID:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
ResNumber TMenuBarManager::GetPreferredHierMenuBarID ()
{
return fPreferredHierMenuBarID;
} // TMenuBarManager::GetPreferredHierMenuBarID
//----------------------------------------------------------------------------------------
// TMenuBarManager::InstallPreferredMenus:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::InstallPreferredMenus ()
{
if( ( (fDisplayedMenus != fPreferredMenuBarID) && (fPreferredMenuBarID != kNoResource) )
|| ( (fDisplayedHierMenus != fPreferredHierMenuBarID) && (fPreferredHierMenuBarID != kNoResource) ) )
{
ClearMenuBar();
if (fPreferredMenuBarID != kNoResource)
{
AddMenuBar (fPreferredMenuBarID, false /* not hierarchical */);
fDisplayedMenus = fPreferredMenuBarID;
}
else
AddMenuBar (fDisplayedMenus, false /* not hierarchical */);
if (fPreferredHierMenuBarID != kNoResource)
{
AddMenuBar (fPreferredHierMenuBarID, true /* hierarchical */);
fDisplayedHierMenus = fPreferredHierMenuBarID;
}
else
AddMenuBar (fDisplayedHierMenus, true /* hierarchical */);
// We must reinsert the help menus whenever ClearMenuBar is called
gApplication->InstallHelpMenuItems();
}
} // TMenuBarManager::InstallPreferredMenus
//----------------------------------------------------------------------------------------
// TMenuBarManager::Reset:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::Reset ()
{
fPreferredMenuBarID = kNoResource;
fPreferredHierMenuBarID = kNoResource;
} // TMenuBarManager::Reset
//----------------------------------------------------------------------------------------
// TMenuBarManager::AddHelpMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::AddHelpMenuItem( CStr255 helpText, CommandNumber helpCommand )
{
MenuHandle helpMenu = NULL;
short newHelpItemNo = 9999;
const CStr255 kParamText1 = "^0";
OSErr err = noErr;
// If the help item contains the paramtext keystring (^0) then substitute the
// Application's name
short i = helpText.Pos(kParamText1);
if (i)
{
CStr255 apName;
gApplication->GetApplicationName(apName);
helpText.Delete(i, kParamText1.Length());
helpText.Insert(apName, i);
}
// Put the help item at the end of the help menu if it's available
if( gConfiguration.hasHelpMgr )
{
err = HMGetHelpMenuHandle( &helpMenu );
}
// If there's no help menu, then put the help item into the Apple menu
else
{
helpMenu = ::GetMenuHandle( mApple ); // In System 6, the Apple menu serves as the help menu
if( helpMenu != NULL )
{
CStr255 menuText;
short nAppleItems = CountMItems( helpMenu );
// Put the help items right at the dividing line before the desk accessories
newHelpItemNo = 1;
while( newHelpItemNo <= nAppleItems )
{
GetMenuItemText( helpMenu, newHelpItemNo, menuText );
if( menuText == "-" )
break;
// If the help item is already in this menu, do nothing
if( menuText == helpText )
return;
++newHelpItemNo;
}
}
}
// If we have a reference to a menu, insert the help command
if( (err == noErr) && (helpMenu != NULL) )
{
short oldMenu;
short oldItem;
// If the new help item is to be inserted at the end of
// the list, make sure that its number is correct
short nHelpItems = CountMItems( helpMenu );
if( newHelpItemNo > nHelpItems )
newHelpItemNo = nHelpItems + 1;
// Insert the menu, then change its name. This avoids problems
// that might occur if the application name included metacharacters
CStr255 helpStr = "Help";
insertmenuitem( helpMenu, helpStr, newHelpItemNo - 1 );
SetMenuItemText( helpMenu, newHelpItemNo, helpText );
// Add the help command number to the command table, but only if it's not already there
if( CommandToComponents(helpCommand,oldMenu,oldItem) == NULL )
gCmdTable->AddToTable(helpCommand, (*helpMenu)->menuID, newHelpItemNo);
}
} // TMenuBarManager::AddHelpMenuItem
//----------------------------------------------------------------------------------------
// TMenuBarManager::AddMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::AddMenuItem(const CStr255& theMenuItemText,
MenuID menuNumber,
short insertAfterItem,
CommandNumber theMenuItemCommandNumber)
{
short theMenuItem = insertAfterItem;
MenuHandle theMenuHandle = GetMenuHandle(menuNumber);
// If we have a reference to a menu, insert the new menu item
if ((theMenuHandle != NULL) && (theMenuItemText.Length() > 0))
{
short oldMenu;
short oldItem;
short curNumItems;
// Figure out where to insert the new menu item
curNumItems = CountMItems(theMenuHandle);
if (theMenuItem > curNumItems)
theMenuItem = curNumItems + 1;
else
// The user passed in where to insert it after so add one to take this into account
theMenuItem++;
// Insert the menu, then change its name. This avoids problems
// that might occur if the application name included metacharacters
// One is subtracted here to take into account insert after item that InsMenuItem does
::InsertMenuItem(theMenuHandle, (ConstStr255Param)"\ptemp", theMenuItem - 1);
::SetMenuItemText(theMenuHandle, theMenuItem, theMenuItemText);
// Add the help command number to the command table, but only if it's not already there
if( CommandToComponents(theMenuItemCommandNumber, oldMenu, oldItem) == NULL )
gCmdTable->AddNewCmdToTableAndUpdateTable(theMenuItemCommandNumber, (*theMenuHandle)->menuID, theMenuItem);
// Make sure the menu is updated
NeedCalcMenuSize(theMenuHandle);
}
} // TMenuBarManager::AddMenuItem
//----------------------------------------------------------------------------------------
// TMenuBarManager::DeleteMenuItem:
//----------------------------------------------------------------------------------------
#pragma segment MAMenuRes
void TMenuBarManager::DeleteMenuItem(CommandNumber theMenuItemCommandNumber)
{
short theMenuNumber;
short theItemNumber;
gCmdTable->CommandToMenuItem(theMenuItemCommandNumber, theMenuNumber, theItemNumber);
if (theMenuNumber)
{
MenuHandle theMenu = MAGetMenuHandle(theMenuNumber);
// Delete the menu item from the menu
if (theMenu != NULL)
{
::DeleteMenuItem(theMenu, theItemNumber);
// Make sure the menu is updated
NeedCalcMenuSize(theMenu);
}
// Delete the command number from the table
gCmdTable->DeleteCmdAndUpdateTable(theMenuItemCommandNumber);
}
} // TMenuBarManager::DeleteMenuItem