home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!zaphod.mps.ohio-state.edu!uakari.primate.wisc.edu!ames!eos!data.nas.nasa.gov!taligent!keith@taligent.com
- From: keith@taligent.com (Keith Rollin)
- Newsgroups: comp.sys.mac.programmer
- Subject: Re: menubar in dialogs (long)
- Message-ID: <Bs55p8.1D8@taligent.com>
- Date: 29 Jul 92 08:17:31 GMT
- References: <kaas-280792151810@jojo.cc.ruu.nl>
- Sender: usenet@taligent.com (More Bytes Than You Can Read)
- Organization: Taligent
- Lines: 855
-
- In article <kaas-280792151810@jojo.cc.ruu.nl>, kaas@cc.ruu.nl (Dick Kaas)
- writes:
- >
- > I'm planning to write a TCL pane for a menu-bar.
- >
- > Is there a simple way to implement a menubar into dialogs (like WP and
- > superboomerang) without having to write a complete menu package by
- > yourself?
- >
- > I have looked at the low memory globals, such as MenuBarHook etc. None of
- > these seem useful.
- >
-
- I did one of these. I wouldn't consider the approach I took to be "simple."
- Although I wrote the bulk of it in a couple of nights, they were long nights. I
- had to re-implement and wrap up a lot of stuff. My first attempt that tried
- setting the origin of the window manager port at strategic times didn't work
- because of a bug in System 7.0's background saving and restoring routines.
-
- I did it as a control to make it easy for others to use. It's included below.
-
- How to use: create a control item in your DITL, and specify the CDEF shown
- below. When the user clicks on the item, the dialog manager will call
- TrackControl. If you are writing a TCL pane, then call TrackControl yourself.
- The control will track the menus and leave the chosen item in contrlValue, so
- all you have to do is call GetCtlValue to get the chosen menu item.
-
- If you want to manipulate the menubar, use one of the macros starting with a "Z"
- included below. Those macros will call the CDEF directly with a custom message
- number. Please note that for the CallIt macro to work, the CDEF must be marked
- as locked. If you don't want to lock your CDEF, then you'll need a more
- elaborate way to call the CDEF than just dereferencing the handle and jumping.
- As an example of what you might need, I've included a commented-out function at
- the end of this posting that calls the standard MBDF directly.
-
- A note: pay no attention to the UseGlobals and DoneWithGlobals stuff. That's for
- an MPW package that allows globals in standalone code. If you are using THINK C,
- don't worry about it. If you are using MPW, use the techniques shown in Technote
- #256.
-
- (BTW: as you'll see below, MenubarHook _was_ useful!)
-
- As a final note, I found it useful to write a wrapper for the standard MDEF.
- Because the below CDEF essentially works by using popup menus, you need to have
- fine control over where the popup menus show up. The standard MBDF will try to
- position popup menus so that as much of them will appear on the screen as
- possible. However, we don't want that with our menubar CDEF; we want to the top
- of the menu to be right below the menubar. Therefore, I wrap up the standard
- MDEF with one of my own that first calls the standard MDEF, and then checks to
- see if the message handled was mPopUpMsg. If so, the top of the menu is adjusted
- by executing "menuRect->top = *itemID;".
-
- Sorry for the lack of any comments in the source code...
-
- -------------
- MenubarCDEF.h
- -------------
-
- #ifndef THINK_C
- #include <Controls.h>
- #endif
-
- #define kStayPutMDEF 90
-
- #define clearMenuBar 128
- #define deleteMenu 129 // param = ID of menu to remove
- #define drawMenuBar 130
- #define flashMenuBar 131 // param = ID of menu to flash
- #define getMenuBar 132 // result = handle to custom data
- #define getMHandle 133 // param = menu ID, result = menuHandle
- #define hiliteMenu 134 // param = ID of menu to hilite
- #define insertMenu 135 // param = menuHandle, varCode = before menu ID
- #define menuKey 136 // param = char, result = same as MenuKey
- #define menuSelect 137 // param = startPt, result = same as MenuSelect
- #define setMenuBar 138 // param = result from getMenuBar
-
- typedef pascal long (*CDEFProc)(short varCode, ControlHandle theControl,
- short msg, long param);
-
- #define CallIt(ctl) ((CDEFProc) *((**ctl).contrlDefProc))
-
- #define ZClearMenuBar(ctl) CallIt(ctl)(0, ctl, clearMenuBar, 0)
- #define ZDeleteMenu(ctl, menuID) CallIt(ctl)(0, ctl, deleteMenu, menuID)
- #define ZDrawMenuBar(ctl) CallIt(ctl)(0, ctl, drawMenuBar, 0)
- #define ZFlashMenuBar(ctl, menuID) CallIt(ctl)(0, ctl, flashMenuBar, menuID)
- #define ZGetMenuBar(ctl) (Handle) CallIt(ctl)(0, ctl, getMenuBar, 0)
- #define ZGetMHandle(ctl, menuID) (MenuHandle) CallIt(ctl)(0, ctl, getMHandle,
- menuID)
- #define ZHiliteMenu(ctl, menuID) CallIt(ctl)(0, ctl, hiliteMenu, 0)
- #define ZInsertMenu(ctl, mh, id) CallIt(ctl)(id, ctl, insertMenu, mh)
- #define ZMenuKey(ctl, key) CallIt(ctl)(0, ctl, menuKey, key)
- #define ZMenuSelect(ctl, startPt) CallIt(ctl)(0, ctl, menuSelect, startPt)
- #define ZSetMenuBar(ctl, mbar) CallIt(ctl)(0, ctl, setMenuBar, mbar)
-
-
-
- -------------
- MenubarCDEF.c
- -------------
-
-
- /*
- To do:
-
- % Support hierarchicals
- % Support color
- */
-
- #include "MetaGlobal.h"
- #include "MenubarCDEF.h"
-
- #ifdef THINK_C
- #include <SetUpA4.h>
- Ptr GetA0(void) = { 0x2008 };
- #else
- #include <Types.h>
- #include <Memory.h>
- #include <Menus.h>
- #include <OSEvents.h> // For EvQPtr
- #include <Resources.h> // For GetResource
- #include <Script.h> // For GetMBarHeight
- #include <ToolUtils.h> // For HiWord, LoWord
- #include <Windows.h> // we return inMenubar as our part
- #include "SAGlobals.h"
-
- #define MenuHook (*(ProcPtr*) 0xA30)
- #define MenuList (*(Handle*) 0xA1C)
- #endif
-
- #define NIL NULL
- #define kTopMargin 1
- #define kBottomMargin 1
- #define kTextMargin 8
-
-
- typedef struct {
- MenuHandle menu;
- short menuLeft;
- } MenuRec, *MenuRecPtr;
-
-
- typedef struct {
- MenuHandle menu;
- short reserved;
- } HMenuRec, *HMenuRecPtr;
-
-
- typedef struct {
- short lastMenu;
- short lastRight;
- short mbResID;
- MenuRec menus[1];
- // short lastHMenu;
- // PixMapHandle menuTitleSave;
- // MenuRec hmenus[1];
- } MenuBar, *MenuBarPtr, **MenuBarHdl;
-
-
- ProcPtr gOldMenuHook;
- ControlHandle gControl;
- MenuBarHdl gMenuList;
- short gTheMenu; // _Index_ of currently hilighted menu
- short gNormalHeight;
- FontInfo gFontInfo;
- short gBaseline;
-
-
- pascal long main(short varCode, ControlHandle theControl, short msg, long
- param);
-
- void DrawMyControl(short part);
- short TestMyControl(Point location);
- void InitMyControl(void);
- void DisposeMyControl(void);
-
- void DoClearMenuBar(void);
- void DoDeleteMenu(short menuID);
- void DoDrawMenuBar(void);
- void DoFlashMenuBar(short menuID);
- MenuBarHdl DoGetMenuBar(void);
- MenuHandle DoGetMHandle(short menuID);
- void DoHiliteMenu(short menuID);
- void DoInsertMenu(MenuHandle menu, short before);
- long DoMenuKey(char theKey);
- long DoMenuSelect(Point startPt);
- void DoSetMenuBar(MenuBarHdl menuBar);
-
- void DrawMenuTitle(short menuIndex);
- short FindHitMenu(Point location); // returns menuIndex (or -1)
- short GetFreeHMenuID(void);
- Rect GetHitRect(short menuIndex);
- Rect GetInvertRect(short menuIndex);
- short GetMenuCount(void);
- MenuHandle GetNthMenu(short index);
- Point GetTitleLocation(short menuIndex);
- short IDToIndex(short);
- short IndexToID(short);
- void MyMenuHook(void);
- void SwapMenuBars(void);
-
- //--------------------------------------------------------------------------------
-
- pascal long main(short varCode, ControlHandle theControl, short msg, long param)
- {
- long result;
- Ptr oldA5;
- char oldState;
- Handle ourHandle;
- Ptr ourPtr;
-
- ourPtr = GetA0();
-
- #ifdef THINK_C
- RememberA0();
- SetUpA4();
- #else
- oldA5 = UseGlobals();
- #endif
-
- ourHandle = RecoverHandle(ourPtr);
- oldState = HGetState(ourHandle);
- HLock(ourHandle);
-
- result = 0;
- gControl = theControl;
- GetFontInfo(&gFontInfo);
- gBaseline = kTopMargin + gFontInfo.leading + gFontInfo.ascent;
-
- if (msg < 128) {
- switch (msg) {
- case drawCntl:
- DrawMyControl((short) param);
- break;
- case testCntl:
- result = TestMyControl(*(Point*) ¶m);
- break;
- case initCntl:
- InitMyControl();
- break;
- case dispCntl:
- DisposeMyControl();
- break;
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle) param, &(**gControl).contrlRect);
- result = 1;
- break;
- }
- } else {
- switch (msg) {
- case clearMenuBar:
- DoClearMenuBar();
- break;
- case deleteMenu:
- DoDeleteMenu((short) param);
- break;
- case drawMenuBar:
- DoDrawMenuBar();
- break;
- case flashMenuBar:
- DoFlashMenuBar((short) param);
- break;
- case getMenuBar:
- result = (long) DoGetMenuBar();
- break;
- case getMHandle:
- result = (long) DoGetMHandle((short) param);
- break;
- case hiliteMenu:
- DoHiliteMenu((short) param);
- break;
- case insertMenu:
- DoInsertMenu((MenuHandle) param, varCode);
- break;
- case menuKey:
- result = DoMenuKey((char) param);
- break;
- case menuSelect:
- result = DoMenuSelect(*(Point*) ¶m);
- break;
- case setMenuBar:
- DoSetMenuBar((MenuBarHdl) param);
- break;
- }
- }
-
- #ifdef THINK_C
- RestoreA4();
- #else
- DoneWithGlobals(oldA5);
- #endif
-
- HSetState(ourHandle, oldState);
-
- return result;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DrawMyControl(short part)
- {
- #pragma unused (part)
-
- if ((**gControl).contrlVis != false) {
- DoDrawMenuBar();
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- short TestMyControl(Point location)
- {
- short hitPart;
-
- hitPart = 0;
- if (FindHitMenu(location) >= 0) {
- hitPart = inMenuBar;
- if (Button()) {
- DoMenuSelect(location);
- if ((**gControl).contrlValue == 0) {
- hitPart = 0;
- }
- }
- }
-
- return hitPart;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void InitMyControl()
- {
- Handle menuBar;
-
- gOldMenuHook = NIL;
- gMenuList = NIL;
- gTheMenu = -1;
- gNormalHeight = GetMBarHeight();
- (**gControl).contrlRect.bottom = (**gControl).contrlRect.top + gBaseline
- + gFontInfo.descent + gFontInfo.leading + kBottomMargin;
-
- GetMBarHeight() = 0;
- menuBar = GetNewMBar((**gControl).contrlMin);
- if (menuBar != NIL) {
- gMenuList = (MenuBarHdl) menuBar;
- } else {
- menuBar = GetMenuBar();
- ClearMenuBar();
- gMenuList = (MenuBarHdl) GetMenuBar();
- SetMenuBar(menuBar);
- DisposeHandle(menuBar);
- }
- GetMBarHeight() = gNormalHeight;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DisposeMyControl()
- {
- DisposeHandle((Handle) gMenuList);
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoClearMenuBar()
- {
- SwapMenuBars();
- ClearMenuBar();
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoDeleteMenu(short menuID)
- {
- if (IndexToID(gTheMenu) == menuID)
- gTheMenu = -1;
-
- SwapMenuBars();
- DeleteMenu(menuID);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoDrawMenuBar()
- {
- Rect frame;
- short loop;
-
- PenNormal();
- frame = (**gControl).contrlRect;
- FrameRect(&frame);
-
- gTheMenu = -1;
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- DrawMenuTitle(loop);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoFlashMenuBar(short menuID)
- {
- Rect bounds;
-
- if (menuID != 0)
- DoHiliteMenu(menuID);
- else {
- bounds = (**gControl).contrlRect;
- InsetRect(&bounds, 1, 1);
- InvertRect(&bounds);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuBarHdl DoGetMenuBar()
- {
- return gMenuList;
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuHandle DoGetMHandle(short menuID)
- {
- short menuIndex;
-
- menuIndex = IDToIndex(menuID);
- if (menuIndex >= 0)
- return GetNthMenu(menuIndex);
- else
- return NIL;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoHiliteMenu(short menuID)
- {
- short menuIndex;
- Rect invertRect;
-
- menuIndex = IDToIndex(menuID);
- if (menuIndex != gTheMenu) {
- if (menuIndex >= 0) {
- invertRect = GetInvertRect(menuIndex);
- InvertRect(&invertRect);
- }
- gTheMenu = menuIndex;
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoInsertMenu(MenuHandle menu, short before)
- {
- SwapMenuBars();
- InsertMenu(menu, before);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- long DoMenuKey(char theKey)
- {
- char upperKey[2];
- short loop;
- MenuHandle menu;
- short mItems;
- short menuItem;
- short key;
-
- upperKey[0] = 1;
- upperKey[1] = theKey;
- UprString((StringPtr) &upperKey, true);
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- menu = GetNthMenu(loop);
- mItems = CountMItems(menu);
- for (menuItem = 1; menuItem <= mItems; menuItem++) {
- if (menuItem > 31 || (((**menu).enableFlags & (1 << menuItem)) != 0)) {
- GetItemCmd(menu, menuItem, &key);
- if (key == upperKey[1]) {
- return ((long) (**menu).menuID << 16) + menuItem;
- }
- }
- }
- }
-
- return 0;
- }
-
-
- //--------------------------------------------------------------------------------
-
- long DoMenuSelect(Point startPt)
- {
- #pragma unused (startPt)
-
- Point currentLocation;
- short oldMenuIndex;
- short newMenuIndex;
- Rect invertRect;
- Point where;
- MenuHandle menu;
- long menuAndItem;
- short oldMenuID;
- Handle myMDEF;
-
- menuAndItem = 0;
- while (Button()) {
- GetMouse(¤tLocation);
- oldMenuIndex = gTheMenu;
- newMenuIndex = FindHitMenu(currentLocation);
- if (oldMenuIndex != newMenuIndex) {
- gTheMenu = newMenuIndex;
- DrawMenuTitle(oldMenuIndex);
- if (newMenuIndex >= 0) {
- DrawMenuTitle(newMenuIndex);
-
- invertRect = GetInvertRect(newMenuIndex);
- where.v = invertRect.bottom + 1;
- where.h = invertRect.left + 1;
- LocalToGlobal(&where);
-
- gOldMenuHook = MenuHook;
- MenuHook = (ProcPtr) MyMenuHook;
-
- menu = GetNthMenu(newMenuIndex);
-
- oldMenuID = (**menu).menuID;
- (**menu).menuID = GetFreeHMenuID();
-
- myMDEF = GetResource('MDEF', kStayPutMDEF);
- if (myMDEF != NIL) {
- (**(StdHeaderHdl) myMDEF).refCon = (long) (**menu).menuProc;
- (**menu).menuProc = myMDEF;
- }
-
- InsertMenu(menu, hierMenu);
- menuAndItem = PopUpMenuSelect(menu, where.v, where.h, 1);
- DeleteMenu((**menu).menuID);
-
- (**menu).menuID = oldMenuID;
-
- if (myMDEF != NIL) {
- (**menu).menuProc = (Handle) (**(StdHeaderHdl) myMDEF).refCon;
- (**(StdHeaderHdl) myMDEF).refCon = (long) NIL;
- }
-
- MenuHook = gOldMenuHook;
-
- if (HiWord(menuAndItem) != 0)
- menuAndItem = ((long) oldMenuID << 16) + (short) menuAndItem;
-
- (**gControl).contrlValue = HiWord(menuAndItem);
- (**gControl).contrlMax = LoWord(menuAndItem);
- }
- }
- }
-
- if (gTheMenu != -1) {
- oldMenuIndex = gTheMenu;
- gTheMenu = -1;
- DrawMenuTitle(oldMenuIndex);
- }
-
- return menuAndItem;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DoSetMenuBar(MenuBarHdl menuBar)
- {
- DisposeHandle((Handle) gMenuList);
- gMenuList = menuBar;
- DoDrawMenuBar();
- }
-
-
- //--------------------------------------------------------------------------------
-
- void DrawMenuTitle(short menuIndex)
- {
- Rect invertRect;
- Point titleLocation;
- MenuHandle menu;
-
- if ((menuIndex >= 0) && (menuIndex < GetMenuCount())) {
-
- invertRect = GetInvertRect(menuIndex);
- EraseRect(&invertRect);
-
- menu = GetNthMenu(menuIndex);
- if ((((**menu).enableFlags & 1) == 0) || ((**gControl).contrlHilite == 255))
- TextMode(grayishTextOr);
- else
- TextMode(srcOr);
-
- titleLocation = GetTitleLocation(menuIndex);
- MoveTo(titleLocation.h, titleLocation.v);
- HLock((Handle) menu);
- DrawString((**menu).menuData);
- HUnlock((Handle) menu);
-
- if (gTheMenu == menuIndex)
- InvertRect(&invertRect);
- }
- }
-
-
- //--------------------------------------------------------------------------------
-
- short FindHitMenu(Point location)
- {
- short loop;
- Rect hitRect;
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- hitRect = GetHitRect(loop);
- if (PtInRect(location, &hitRect)) {
- break;
- }
- }
-
- return loop; // returns -1 if no hit
- }
-
-
- //--------------------------------------------------------------------------------
-
- short GetFreeHMenuID(void)
- {
- short index;
-
- for (index = 235-20; index > 0; index--) {
- if (GetMHandle(index) == NIL)
- return index;
- }
- return -1;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Rect GetHitRect(short menuIndex)
- {
- Rect bounds;
- RectPtr rectPtr;
- MenuBarPtr menuBarPtr;
-
- rectPtr = &(**gControl).contrlRect;
- menuBarPtr = *gMenuList;
-
- bounds.top = rectPtr->top + 1;
- bounds.bottom = rectPtr->bottom - 1;
- bounds.left = rectPtr->left + menuBarPtr->menus[menuIndex].menuLeft;
- menuIndex++;
- bounds.right = rectPtr->left + ((menuIndex < GetMenuCount())
- ? menuBarPtr->menus[menuIndex].menuLeft
- : menuBarPtr->lastRight);
-
- return bounds;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Rect GetInvertRect(short menuIndex)
- {
- Rect bounds;
-
- bounds = GetHitRect(menuIndex);
- bounds.left--;
- bounds.right += 4;
- return bounds;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short GetMenuCount()
- {
- return (**gMenuList).lastMenu / (short) sizeof(MenuRec);
- }
-
-
- //--------------------------------------------------------------------------------
-
- MenuHandle GetNthMenu(short index)
- {
- return (**gMenuList).menus[index].menu;
- }
-
-
- //--------------------------------------------------------------------------------
-
- Point GetTitleLocation(short menuIndex)
- {
- Point result;
-
- result.h = (**gMenuList).menus[menuIndex].menuLeft + kTextMargin;
- result.v = (**gControl).contrlRect.top + gBaseline;
-
- return result;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short IDToIndex(short menuID)
- {
- short loop;
-
- for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
- if ((**GetNthMenu(loop)).menuID == menuID)
- break;
- }
- return loop;
- }
-
-
- //--------------------------------------------------------------------------------
-
- short IndexToID(short menuIndex)
- {
- if ((menuIndex >= 0) && (menuIndex < GetMenuCount()))
- return (**GetNthMenu(menuIndex)).menuID;
- else
- return 0;
- }
-
-
- //--------------------------------------------------------------------------------
-
- void MyMenuHook()
- {
- typedef void (*MenuHookProc)(void);
-
- GrafPtr oldPort;
- Point mouseLocation;
- short hitMenu;
- Ptr oldA5;
-
- #ifdef THINK_C
- SetUpA4();
- #else
- oldA5 = UseGlobals();
- #endif
-
- if (gOldMenuHook != NIL)
- ((MenuHookProc) gOldMenuHook)();
-
- GetPort(&oldPort);
- SetPort((**gControl).contrlOwner);
- GetMouse(&mouseLocation);
- hitMenu = FindHitMenu(mouseLocation);
- if ((hitMenu >= 0) && (hitMenu != gTheMenu)) {
- PostEvent(mouseUp, 0);
- }
- SetPort(oldPort);
-
- #ifdef THINK_C
- RestoreA4();
- #else
- DoneWithGlobals(oldA5);
- #endif
- }
-
-
- //--------------------------------------------------------------------------------
-
- void SwapMenuBars()
- {
- MenuBarHdl oldMenuBar;
-
- oldMenuBar = (MenuBarHdl) MenuList;
- MenuList = (Handle) gMenuList;
- gMenuList = oldMenuBar;
- }
-
-
-
-
-
- #if 0
-
- void CalcMenuPositions(short index);
- long CallMBDF(short message, short param1, long param2);
-
- //--------------------------------------------------------------------------------
-
- void CalcMenuPositions(short index)
- {
- SwapMenuBars();
- CallMBDF(2, 0, (index+1) * 6);
- SwapMenuBars();
- }
-
-
- //--------------------------------------------------------------------------------
-
- long CallMBDF(short message, short param1, long param2)
- {
- typedef pascal long (*MBDFProc)(short selector, short message, short
- parameter1,
- long parameter2);
- Handle mbdfHandle;
- short mbResID;
- short resID;
- short mbVariant;
- char oldState;
- long result;
-
- mbResID = (**gMenuList).mbResID;
- resID = mbResID >> 3;
- mbVariant = mbResID & 0x0007;
- mbdfHandle = GetResource('MBDF', resID);
- if (mbdfHandle != NIL) {
- if (*mbdfHandle == NIL) {
- LoadResource(mbdfHandle);
- }
- if (*mbdfHandle != NIL) {
-
- oldState = HGetState(mbdfHandle);
- HLock(mbdfHandle);
- result = ((MBDFProc) *mbdfHandle)(mbVariant, message, param1, param2);
- HSetState(mbdfHandle, oldState);
- return result;
- }
- }
-
- SysError(dsMBarNFnd);
- }
- #endif
-
-
- --
- Keith Rollin
- Phantom Programmer
- Taligent, Inc.
-