home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-05-05 | 29.0 KB | 913 lines | [TEXT/MPS ] |
- /*
- ** Apple Macintosh Developer Technical Support
- ** Simple Tear-Off Menu Definition
- **
- ** File: TearOff.MDEF.c
- ** Written by: C.K. Haun and Eric Soldan
- **
- ** Copyright © 1992-1993 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /* You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes. */
-
- /*
-
- What does it take to tear a menu off? Do you need to patch things?
- Do you need to write an assembly language interface to the Menu Manager?
- Do I need weird stand-alone globals?
-
- Nah, just a little MDEF.
-
- And here it is. This MDEF 'tears off', allowing you to know the user
- has torn it off, and at which point you'll make a palette window for it.
- No patches, no hacking, just code.
-
- This MDEF is also a CIconic MDEF, but the same technique will work
- with a Text menu, or anything else.
-
- NOTE: The MDEF handles non-color quickdraw machines correctly. For non-color quickdraw
- machines, the bitmap of the CIcon is used, and CopyBits is used for these systems.
-
-
- How The Tear Off Part Works:
-
- When the user is tracking around in a menu, you are periodically called to highlight and
- de-highlight the items the user is tracking over. This is the whole key to tearing off.
- When the user goes outside the bounding rectangle of the menu, the Menu Manager tells you
- to de-highlight the last item they were over, and does NOT tell you to highlight a new one.
-
- This MDEF watches for that situation, when it sees that there are no items highlighted
- (easier than you'd think) it checks to see if the user is dragging in the Desktop area
- (screen minus this menu and the menu bar) and if they are, it drags a gray outline of
- the menu around until they:
- 1) release the mouse.
- 2) go back in the menu or menu bar.
-
- If they release the mouse in a valid area for a tear off (not in the menu bar or current menu)
- then the MDEF lets you, the application, know that the user tore off. It does this by passing
- back an item number of -1, that's the flag to you that says "Hey, something tore it".
- The 'where' the user wants is a little sneakier. The Menu struture that this MDEF uses has a
- dummy item at the end. That dummy item is never drawn, it's just a placeholder. When the
- user tears-off, I stuff the rectangle that they tore off at in the last menu item, as bytes
- 1 through 8 in the string.
-
- So in your application, you can do a
- GetMenuItemText(theMenu,CountMItems(theMenu),tempString);
- BlockMove((Ptr)tempString + 1), (Ptr)&myTornOffRct, sizeof(Rect));
-
- and create your palette at that rect.
-
-
- Why not something like:
- GetMenuItemText(theMenu,CountMItems(theMenu),tempString);
- myTornOffRct = *(Rect *)(tempString + 1);
-
- Because this code will crash on 68000 machines (a move with an odd address, ya know).
- So do the ugly BlockMove and you'll be happy.
-
- Pretty simple, huh?
-
-
- Pay the most attention to the code in the ChooseIt and DragTearOff functions.
-
-
- How The CIcon Part Works:
-
- Drawing CIcons instead of text in a menu is not hard, the only thing that's at all interesting
- in that part of the code is how the CIcon id's are stored for the menu items.
-
- Ascii text is used for the CIcon id's. Actual numeric values are not used. Numeric
-
- Actual numeric values for the CIcons are NOT stored in the menu structure. Numeric values could
- have been used, but this would make it hard to use ResEdit to edit the menu structure.
- Therefore the CIcon resource IDs are stored in their string representation.
-
- This has been extended to allow alternate CIcons per menu item. By marking the menu item,
- you can determine which cicon to actually draw. (DTS.Draw uses this facility, so there is a
- complete sample demonstrating this.)
-
- The special dummy menu item on the end does more than just return the rect in bytes 1-8.
- It also allows you to use ResEdit to determine other attributes of the menu without
- having to modify and recompile the MDEF.
-
- The format for the extra menu item is:
-
- bytes 1-8: Reserved to return the tear-off rect.
- A -1 is returned as the menu item to indicate to the application that the user
- tore-off the menu.
-
- bytes 9-N: 16 ascii numbers, delimited by commas.
- These numbers tell the MDEF how to behave. The numbers are:
-
- 1) Number of columns in menu
-
- 2) Menu vert size
- 3) Menu horiz size
-
- 4) Item vert size
- 5) Item horiz size
-
- 6) CIcon vert size
- 7) CIcon horiz size
-
- 8) CIcon vert offset
- 9) CIcon horiz offset
-
- 10) Invert vert size
- 11) Invert horiz size
-
- 12) Invert vert offset
- 13) Invert horiz offset
-
- 14) Invert vert border size
- 15) Invert horiz border size
-
- 16) No invert -- use CIcon offset
-
- The numbers end up mapping out 3 working rectangles. They can be charted:
-
- a------------------------------------------+
- | |
- | c------------------------------------+ |
- | | | |
- | | e------------------------------+ | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | | | | |
- | | +------------------------------f | |
- | | | |
- | +------------------------------------d |
- | |
- +------------------------------------------b
-
- Rect a-b is the item rect. The item rect is calculated based on the number of columns in
- the menu, the menu item number, and the menu item vert/horiz sizes.
-
- Rect c-d is the cicon rect. The cicon is drawn inside the item rect. The size is determined by
- the cicon vert/horiz sizes. Where in the item rect is determined by the cicon vert/horiz offsets.
-
-
- Rect e-f is the invert area for the item. Either the entire invert rect is inverted, or just
- the frame. If the Invert vert/horiz border size is non-zero, then just the frame of the
- invert rect is inverted.
-
-
- Here is a sample entry for the TearOff.MDEF to interpret.
- Remember, it is added to the menu as the last item. The last item is never
- displayed. It is just used for information.
-
- # # # # # # # # # # # # # # # #
- 1 1 1 1 1 1 1
- 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
- -------------------------------------------------
- TearRect,1,119,31,20,32,20,32,0,0,19,31,0,0,2,2,0
- | | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | | -- Don't do an invert to show selection. CIcons
- | | | | | | | | | | | | | | | | can look bad inverted sometimes. For these cases,
- | | | | | | | | | | | | | | | | you may wish to draw a different CIcon when the
- | | | | | | | | | | | | | | | | user is tracking across the item. If this value
- | | | | | | | | | | | | | | | | is 0, then the invert rules are applied. If this
- | | | | | | | | | | | | | | | | value is non-zero, then it is added to the CIcon
- | | | | | | | | | | | | | | | | ID that would normally be drawn at that point,
- | | | | | | | | | | | | | | | | and that CIcon is drawn instead. When the user
- | | | | | | | | | | | | | | | | tracks outside this item and an invert would
- | | | | | | | | | | | | | | | | normally be done to unhilite the item, the regular
- | | | | | | | | | | | | | | | | CIcon is redrawn.
- | | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | | ---- Invert horiz border size. If this and vert are
- | | | | | | | | | | | | | | | non-zero, then the invert rect has a frame size
- | | | | | | | | | | | | | | | of the horiz/vert values.
- | | | | | | | | | | | | | | |
- | | | | | | | | | | | | | | ------ Invert vert border size. If this and horiz are
- | | | | | | | | | | | | | | non-zero, then the invert rect has a frame size
- | | | | | | | | | | | | | | of the horiz/vert values.
- | | | | | | | | | | | | | |
- | | | | | | | | | | | | | -------- Invert horiz offset. The invert rect is calculated,
- | | | | | | | | | | | | | and then it is offset by this amount horizontally.
- | | | | | | | | | | | | |
- | | | | | | | | | | | | ---------- Invert vert offset. The invert rect is calculated,
- | | | | | | | | | | | | and then it is offset by this amount vertically.
- | | | | | | | | | | | |
- | | | | | | | | | | | ------------ Invert horiz size. The invert rect is this wide.
- | | | | | | | | | | | It's upper left corner is the item corner, offset
- | | | | | | | | | | | by the horiz/vert invert offsets.
- | | | | | | | | | | |
- | | | | | | | | | | --------------- Invert vert size. The invert rect is this tall.
- | | | | | | | | | | It's upper left corner is the item corner, offset
- | | | | | | | | | | by the horiz/vert invert offsets.
- | | | | | | | | | |
- | | | | | | | | | ------------------ CIcon horiz offset. The CIcon rect is calculated,
- | | | | | | | | | and then it is offset by this amount horizontally.
- | | | | | | | | |
- | | | | | | | | -------------------- CIcon vert offset. The CIcon rect is calculated,
- | | | | | | | | and then it is offset by this amount vertically.
- | | | | | | | |
- | | | | | | | |--------------------- CIcon horiz size. The CIcon rect is this wide.
- | | | | | | | It's upper left corner is the item corner, offset
- | | | | | | | by the CIcon horiz/vert offsets.
- | | | | | | |
- | | | | | | ------------------------- CIcon vert size. The CIcon rect is this tall.
- | | | | | | It's upper left corner is the item corner, offset
- | | | | | | by the CIcon horiz/vert offsets.
- | | | | | |
- | | | | | ---------------------------- Item horiz size. The item rect is this wide.
- | | | | | It's upper left corner is the item corner, offset
- | | | | | by the item horiz/vert offsets.
- | | | | |
- | | | | ------------------------------- Item vert size. The item rect is this tall.
- | | | | It's upper left corner is the item corner, offset
- | | | | by the item horiz/vert offsets.
- | | | |
- | | | ---------------------------------- Menu horiz size. The entire menu is this wide.
- | | |
- | | -------------------------------------- Menu vert size. The entire menu is this tall.
- | |
- | ----------------------------------------- Number of columns in menu.
- |
- ----------------------------------------------- Return result for the TearOff rect. This must
- 8 bytes long exactly.
-
-
- Note that you can stop putting values in at any point. Any fields that don't have a value are
- assumed to be 0, except for the number-of-columns field. (0 columns is a bad thing.) The
- number-of-columns field is assumed to be 1.
-
- An additional feature of the MDEF is that you can control how it behaves on color v.s. b/w
- monitors. Of course, just by the fact the the MDEF uses CIcons, you have a good deal of control
- over how the menu looks on different monitors. You may also wish to control other behaviors,
- depending on the screen depth.
-
- The sample extra-item above was:
-
- TearRect,1,119,31,20,32,20,32,0,0,19,31,0,0,2,2
-
- If we change this to:
-
- TearRect,1,119,31,20,32,20,32,0,0,19,31,0,0,2.0,2.0
-
- we get a different behavior for b/w screens v.s. color screens. Actually, we get a different
- behavior for not-enough-color screens v.s. enough color. Not enough color is any monitor with
- less than 8-bit color.
-
- The 2.0 entries are split values. The 2 is used if the screen has enough color, and the 0 is
- used if it doesn't. From the above usage table, we can see that if either if the invert
- border sizes is 0, then it inverts the entire border rect. By adding the .0 to these entries,
- we now have a different behavior for enough-color v.s. not enough color.
-
- What if we want the distinction to be any amount of color v.s. b/w? Then we do this:
-
- TearRect,1.2,119,31,20,32,20,32,0,0,19,31,0,0,2.0,2.0
-
- Since the number of columns doesn't change based on the scren depth, putting a .2 on the
- number of columns field would seem to make mo sense. However, when this field has a split value,
- it is interpreted differently for the number-of-columns field. It is used as the minimum depth
- of the screen for it to be considered a color screen. The default is 8, but by extending the
- number-of-columns field, you can override the 8 default and use whatever depth you like. So,
- for this case, a screen depth of 2 or greater is a color screen, and 1-deep is b/w.
-
-
- • Things that AREN'T in here! •
- This MDEF does NOT scroll, support heirarchical menus, or PopUps.
- The thought of a Hierarchical tear-off can cause brain seizures.
-
- If you need more information about HMenus, scrolling, and Popups, please
- see the excellent MDEF sample called Concordia on the Developer CD.
-
- Any bugs or comments....
- C.K. Haun or Eric Soldan
- Apple DTS (ALink : DEVSUPPORT)
-
- */
-
-
-
- #include <Types.h>
- #include <Quickdraw.h>
- #include <Balloons.h>
- #include <Controls.h>
- #include <Events.h>
- #include <Memory.h>
- #include <ToolUtils.h>
- #include <Menus.h>
- #include <Packages.h>
- #include <Resources.h>
- #include <Script.h>
- #include <GestaltEqu.h>
-
- #include "GWLayers.h"
-
- #define kSlop 6
- #define kWDEFTitleSize 9
- #define kExtremeNeg -32767 + 1
- #define kExtremePos 32767 - 1
-
- #define kItemRect 0
- #define kIconRect 1
- #define kInvertRect 2
- #define kMaxNumParms 16
-
- #define kNumCols 0
- #define kMenuHeight 1
- #define kMenuWidth 2
- #define kItemHeight 3
- #define kItemWidth 4
- #define kIconHeight 5
- #define kIconWidth 6
- #define kIconHeightOffset 7
- #define kIconWidthOffset 8
- #define kInvertHeight 9
- #define kInvertWidth 10
- #define kInvertHeightOffset 11
- #define kInvertWidthOffset 12
- #define kInvertBorderHeight 13
- #define kInvertBorderWidth 14
- #define kInvertIconOffsetID 15
-
- #define kQDOriginal 0
-
- pascal void main(short message, MenuHandle menu, Rect *menuRct, Point hit, short *item);
-
- void DrawItem (MenuHandle menu, Rect menuRct, short item, Boolean invert, Boolean invOn);
- void ChooseIt (MenuHandle menu, Rect menuRct, Point hit, short *item);
- Rect CalcItemRect (MenuHandle menu, Rect menuRct, short item, Boolean rectType);
- RgnHandle CalcItemSelectRgn(MenuHandle menu, Rect menuRct, short item);
- short GetNumItems (MenuHandle menu);
- short GetMenuData (MenuHandle menu, short data[]);
- Boolean DragTearOff (Rect menuRct, Point thePoint, Rect *passedRct);
- Rect FrameGrayRect (Rect rct);
-
- Rect GetMainScreenRect(void);
- long GetGestaltResult(OSType gestaltSelector);
- short GetMainScreenDepth(void);
-
- void DoBalloon(MenuHandle menu, Rect menuRct, Point tip, short item);
- void UndoBalloon(void);
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- pascal void main(short message, MenuHandle menu, Rect *menuRct, Point hit, short *item)
- {
- short qq, numItems, data[kMaxNumParms];
-
- switch (message) {
- case mDrawMsg:
- numItems = GetNumItems(menu);
- for (qq = 1; qq <= numItems; qq++) DrawItem(menu, *menuRct, qq, false, false);
- break;
-
- case mChooseMsg:
- ChooseIt(menu, *menuRct, hit, item);
- break;
-
- case mSizeMsg:
- GetMenuData(menu, data);
- (*menu)->menuHeight = data[kMenuHeight];
- (*menu)->menuWidth = data[kMenuWidth];
- break;
-
- case mPopUpMsg: /* I am not supporting Popups, so I'm ignoring these */
- case mDrawItemMsg:
- case mCalcItemMsg:
- break;
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* ChooseIt is the main work-horse routine.
- ** The Menu Manager calls this routine continually during tracking to highlight
- ** and dehighlight the items the user is tracking over */
-
- void ChooseIt(MenuHandle menu, Rect menuRct, Point hit, short *item)
- {
- short ii, numItems;
- long enableFlags;
- Str63 infoText;
- Rect itemRct, tearRct;
- Boolean justUnselected;
-
- enableFlags = (*menu)->enableFlags;
- if (!(enableFlags & 0x01)) enableFlags = 0;
-
- numItems = GetNumItems(menu);
-
- if (*item == -1) {
- UndoBalloon();
- GetMenuItemText(menu, numItems + 1, infoText);
- BlockMove(infoText + 1, (Ptr)&tearRct, sizeof(Rect));
- InsetRect(&tearRct, -1, -1);
- FrameGrayRect(tearRct);
- return;
- }
-
- if ((*item < 0) || (*item > numItems)) return;
- /* Make sure values are valid. */
-
- for (ii = numItems; ii; --ii) {
- itemRct = CalcItemRect(menu, menuRct, ii, kItemRect); /* Get rect for first/next item. */
- if (PtInRect(hit, &itemRct)) break; /* Are we in an item? If so, we
- ** know what we want to know. */
- }
-
- justUnselected = false;
-
- if (*item != ii) { /* If things have changed... */
-
- if (*item) { /* If we had an old selected item, deselect it. */
- UndoBalloon();
- DrawItem(menu, menuRct, *item, true, false);
- justUnselected = true;
- }
-
- if (*item = ii) { /* If we have a new selected item, select it. */
- if ((enableFlags & (0x01 << ii)))
- DrawItem(menu, menuRct, ii, true, true);
- else
- *item = 0;
- DoBalloon(menu, menuRct, hit, ii);
- }
- }
- else DoBalloon(menu, menuRct, hit, *item);
-
- if (justUnselected) { /* If we just unselected an item... */
-
- if (!ii) { /* If we haven't selected a new item... */
-
- if ((enableFlags & (0x01 << ++numItems))) { /* If TearOff feature is enabled... */
-
- if (DragTearOff(menuRct, hit, &tearRct)) {
- /* if this returned true, then they let up on the mouse whilst they were dragging */
- /* the outline, otherwise they went back and we press on */
- /* So, the final rectangle is in passedRct. */
- /* And, as I mentioned above, we have a dummy item at the end of our menu. */
- /* That dummy item is where we will sneakily store the rectangle, like so... */
-
- UndoBalloon();
-
- GetMenuItemText(menu, numItems, infoText);
- BlockMove((Ptr)&tearRct, infoText + 1, sizeof(Rect));
- SetMenuItemText(menu, numItems, infoText);
-
- *item = -1;
- }
- }
- }
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* DrawItem draws our item.
- ** In this MDEF, I grab the text of the menu item, change it to a number, and then get
- ** a cicon with that resID and plot that cicon. */
-
- void DrawItem(MenuHandle menu, Rect menuRct, short theItem, Boolean invert, Boolean invOn)
- {
- Rect iconRct, rct;
- Str32 itemText, str;
- long num;
- short mark, i, ii;
- CIconHandle cicon;
- RgnHandle rgn, oldClip, newClip;
- short data[kMaxNumParms];
-
- GetItemMark(menu, theItem, &mark);
- if (mark >= '0') mark -= '0';
-
- GetMenuItemText(menu, theItem, itemText);
- itemText[++itemText[0]] = ','; /* Give us a terminator character. */
- for (ii = 0; mark > -1; --mark) {
- if (ii >= itemText[0]) break;
- for (i = 0; itemText[++ii] != ','; ++i);
- BlockMove(itemText + ii - i, str + 1, str[0] = i);
- StringToNum(str, &num);
- }
-
- if (invert) {
- GetMenuData(menu, data);
- if (data[kInvertIconOffsetID]) {
- if (invOn)
- num += data[kInvertIconOffsetID];
- }
- else {
- rgn = CalcItemSelectRgn(menu, menuRct, theItem);
- InvertRgn(rgn);
- DisposeRgn(rgn);
- return;
- }
- }
-
- if (cicon = ReadCIcon(num)) {
- iconRct = CalcItemRect(menu, menuRct, theItem, kIconRect);
- SectRect(&iconRct, &menuRct, &rct);
- oldClip = NewRgn();
- newClip = NewRgn();
- RectRgn(newClip, &rct);
- GetClip(oldClip);
- SetClip(newClip);
- DrawCIcon(cicon, iconRct);
- SetClip(oldClip);
- DisposeRgn(oldClip);
- DisposeRgn(newClip);
- KillCIcon(cicon);
- }
- }
-
-
-
- /*****************************************************************************/
-
-
- /*
- ** DragTearOff does the actual tearing off.
- **
- ** As long as the mouse stays outside the menu and the menu bar area, I will
- ** drag a rectangle around. This ends if:
- **
- ** 1) The user lets up on the mouse. In that case, I return the ending rectangle
- ** and a TRUE
- ** 2) The user goes back into the menu or menu bar. In that case, I return FALSE
- */
-
- Boolean DragTearOff(Rect menuRct, Point thePoint, Rect *passedRct)
- {
- Rect dragRct, menubarRct;
- Point endPoint, pp;
- long ll;
- Boolean dragRctOn;
-
- if (PtInRect(thePoint, &menuRct)) return(false);
- /* If currently in the menu, get out of here. */
-
- menubarRct = GetMainScreenRect(); /* Calc the menubar rect. */
- menubarRct.bottom = menubarRct.top + GetMBarHeight();
-
- if (PtInRect(thePoint, &menubarRct)) return(false);
- /* If currently in the menubar, get out of here. */
-
- dragRct = menuRct; /* Drag this puppy around until the user lets go,
- ** or until the user bumps into the badRgn. */
-
- InsetRect(&dragRct, kSlop, kSlop);
- ll = PinRect(&dragRct, thePoint);
- InsetRect(&dragRct, -kSlop, -kSlop);
-
- pp = *(Point *)≪
- OffsetRect(&dragRct, thePoint.h - pp.h, thePoint.v - pp.v);
- /* Get the rect to be over the mouse location by at least a little slop. */
-
- InsetRect(&dragRct, -1, -1);
-
- /* Keep tracking the mouse and moving the rect until they release the mouse button,
- ** or until they bump into the menu or the menubar. */
-
- dragRctOn = false;
-
- while (StillDown()) {
-
- GetMouse(&endPoint);
-
- if (!EqualPt(endPoint, thePoint)) { /* They moved... */
-
- if (dragRctOn) {
- FrameGrayRect(dragRct); /* Erase the old rect */
- dragRctOn = false;
- }
-
- if (PtInRect(thePoint, &menuRct)) break;
- if (PtInRect(thePoint, &menubarRct)) break;
-
- OffsetRect(&dragRct, endPoint.h - thePoint.h, endPoint.v - thePoint.v);
- thePoint = endPoint;
-
- InsetRect(&menuRct, -kSlop, -kSlop);
- dragRctOn = !PtInRect(thePoint, &menuRct);
- InsetRect(&menuRct, kSlop, kSlop);
-
- if (dragRctOn) FrameGrayRect(dragRct); /* Frame the new position */
- Delay(1, &ll); /* Reduce tearing. */
- }
- }
-
- if (dragRctOn) dragRct = FrameGrayRect(dragRct); /* Erase the gray region. */
- InsetRect(&dragRct, 1, 1);
-
- *passedRct = dragRct; /* pass back the end rect position, whatever it is */
- return(dragRctOn); /* and go hither */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- Rect CalcItemRect(MenuHandle menu, Rect menuRct, short item, Boolean rectType)
- {
- Rect itemRct;
- short ii, data[kMaxNumParms];
-
- GetMenuData(menu, data);
-
- ii = --item / data[kNumCols];
- itemRct.top = ii * data[kItemHeight];
- switch (rectType) {
- case kItemRect:
- SetRect(&itemRct, 0, itemRct.top, data[kItemWidth], itemRct.top + data[kItemHeight]);
- break;
- case kIconRect:
- SetRect(&itemRct, 0, itemRct.top, data[kIconWidth], itemRct.top + data[kIconHeight]);
- OffsetRect(&itemRct, data[kIconWidthOffset], data[kIconHeightOffset]);
- break;
- case kInvertRect:
- SetRect(&itemRct, 0, itemRct.top, data[kInvertWidth], itemRct.top + data[kInvertHeight]);
- OffsetRect(&itemRct, data[kInvertWidthOffset], data[kInvertHeightOffset]);
- break;
- }
-
- OffsetRect(&itemRct, menuRct.left, menuRct.top);
-
- ii *= data[kNumCols];
- ii = item - ii;
- OffsetRect(&itemRct, ii * data[kItemWidth], 0);
-
- return(itemRct);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- RgnHandle CalcItemSelectRgn(MenuHandle menu, Rect menuRct, short item)
- {
- Rect rct;
- RgnHandle rgn, interiorRgn;
- short data[kMaxNumParms];
-
- rct = CalcItemRect(menu, menuRct, item, kInvertRect);
- RectRgn(rgn = NewRgn(), &rct);
-
- GetMenuData(menu, data);
- if (data[kInvertBorderHeight] || data[kInvertBorderWidth]) {
- InsetRect(&rct, data[kInvertBorderWidth], data[kInvertBorderHeight]);
- RectRgn(interiorRgn = NewRgn(), &rct);
- DiffRgn(rgn, interiorRgn, rgn);
- DisposeRgn(interiorRgn);
- }
-
- return(rgn);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- short GetMenuData(MenuHandle menu, short data[])
- {
- short numItems, ii, parm, i, c, depth, colorDepth;
- Str255 infoText;
- Str15 str;
- long num;
-
- for (i = 0; i < kMaxNumParms; ++i) data[i] = 0;
-
- GetMenuItemText(menu, (numItems = GetNumItems(menu)) + 1, infoText);
-
- for (;;) { /* Make sure there are no invisible chars (c/r's) on end of string. */
- if (infoText[0] < 9) break;
- if ((infoText[infoText[0]] > ' ') && (infoText[infoText[0]] < 'f')) break;
- --infoText[0];
- }
-
- infoText[++infoText[0]] = ','; /* Give us a terminator character. */
-
- ii = 8;
- if (infoText[9] == ',') ++ii; /* Skip possible first optional delimiter. */
-
- depth = GetMainScreenDepth();
- colorDepth = 8;
-
- for (parm = 0; parm < kMaxNumParms; ++parm) {
-
- if (ii >= infoText[0]) break;
-
- for (i = 0;; ++i) {
- c = infoText[++ii];
- if ((!c) || (c == ',') || (c == '.')) break;
- }
- if (!c) break;
- BlockMove(infoText + ii - i, str + 1, str[0] = i);
- StringToNum(str, &num);
- data[parm] = num;
-
- if (c == '.') {
- for (i = 0;; ++i) {
- c = infoText[++ii];
- if ((!c) || (c == ',')) break;
- }
- if (!c) break;
- BlockMove(infoText + ii - i, str + 1, str[0] = i);
- StringToNum(str, &num);
- if (!parm) {
- colorDepth = num;
- }
- else
- if (depth < colorDepth)
- data[parm] = num;
- }
- }
-
- if (!data[kNumCols]) data[kNumCols] = 1;
-
- return(numItems);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- short GetNumItems(MenuHandle menu)
- {
- return(CountMItems(menu) - 1);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- Rect FrameGrayRect(Rect frameRct)
- {
- PenState thePen;
- RgnHandle oldClip;
- Pattern Gray;
- Rect rct;
- short mbh;
-
- GetPenState(&thePen); /* I'm going to be changing pen information, so save the old */
-
- /* get the pattern I want from the System file, since I don't have */
- /* access to Application Globals (A5) since I'm standalone */
- /* I _could_ rely on the current port information, but I'm too */
- /* paranoid for that */
-
- Gray.pat[0] = 0;
- GetIndPattern(&Gray, sysPatListID, 4);
-
- GetClip(oldClip = NewRgn());
- SetRect(&rct, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
- ClipRect(&rct); /* Allow drawing everywhere. */
-
- PenMode(patXor); /* set up for gray dragging */
- PenPat(&Gray);
-
- mbh = GetMBarHeight() + kWDEFTitleSize;
- if (frameRct.top < mbh) OffsetRect(&frameRct, 0, (mbh - frameRct.top));
- FrameRect(&frameRct);
-
- SetPenState(&thePen); /* restore the pen */
- SetClip(oldClip); /* restore the original clip */
- DisposeRgn(oldClip);
-
- return(frameRct);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #ifdef THINK_C
- Rect GetMainScreenRect(void)
- {
- GDHandle mainDevice;
- GrafPtr mainPort;
-
- if (((GetGestaltResult(gestaltQuickdrawVersion) >> 8) & 0xFF) > kQDOriginal) {
- mainDevice = GetMainDevice();
- return((*mainDevice)->gdRect);
- }
- else {
- GetWMgrPort(&mainPort);
- return(mainPort->portRect);
- }
- }
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- #ifdef THINK_C
- long GetGestaltResult(OSType gestaltSelector)
- {
- long gestaltResult;
-
- if (Gestalt(gestaltSelector, &gestaltResult) == noErr)
- return(gestaltResult);
- else
- return(0);
- }
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- short GetMainScreenDepth(void)
- {
- GDHandle mainDevice;
- PixMapHandle pmap;
-
- if (((GetGestaltResult(gestaltQuickdrawVersion) >> 8) & 0xFF) > kQDOriginal) {
- mainDevice = GetMainDevice();
- pmap = (*mainDevice)->gdPMap;
- return((*pmap)->pixelSize);
- }
-
- return(1);
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- void DoBalloon(MenuHandle menu, Rect menuRct, Point tip, short item)
- {
- Rect rct;
- short v;
-
- if (GetGestaltResult(gestaltSystemVersion) >= 0x0700) {
- if (StillDown()) {
- if(!HMIsBalloon()) {
- rct = CalcItemRect(menu, menuRct, item, kItemRect);
- v = rct.bottom - rct.top;
- v /= 2;
- tip.v = rct.top + v;
- tip.h = rct.right - 8;
- HMShowMenuBalloon(item, (*menu)->menuID, (*menu)->enableFlags, 0, tip, nil, nil, 0, 0);
- }
- }
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- void UndoBalloon(void)
- {
- if (GetGestaltResult(gestaltSystemVersion) >= 0x0700) {
- if(HMIsBalloon())
- HMRemoveBalloon();
- }
- }
-
-
-
-