Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
PopUpTkl.c
/* |
File: PopUpTkl.c |
Contains: the code to process the mPopUpMsg message from the Menu |
Manager. This involves calculating the rectangle that the popup menu should |
appear in. |
Written by: |
Copyright: Copyright © 1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source 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 source |
code, but that you've made changes. |
Change History (most recent first): |
8/10/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
/******************************************************************************\ |
* Header Files |
\******************************************************************************/ |
#include <Memory.h> |
#include <Menus.h> |
#include <OSUtils.h> |
#include <Script.h> |
#include <Types.h> |
#include "Concordia.h" |
#include "DrawTkl.h" |
#include "PopUpTkl.h" |
#include "SizeTkl.h" |
/******************************************************************************\ |
* Prototypes |
\******************************************************************************/ |
void FindScreen (Rect *menuRect, |
Rect *retScreenRect); |
#pragma segment Main |
/******************************************************************************\ |
* DoPopUpMsg - Calculate a popup menu's rectangle |
* |
* DoPopUpMsg calculates the menu rectangle for the popup menu specified by |
* TheMenu. This rectangle is returned in MenuRect. The top-left corner of the |
* menu item specified by PopUpItem will appear at the coordinates given by |
* TopPos and LeftPos. The vertical coordinate of the top of the menu's |
* rectangle is returned. If the menu runs off of the screen, its size and |
* position will be adjusted. |
* |
* Coding Notes |
* #A# - This loop calculates the total height of the menu (Height), the width of |
* the menu (Width), the height of the tallest item in the menu |
* (MaxHeight), and the distance from the top of the menu to the item |
* specified by PopUpItem (ItemPos). |
* #B# - Read this as: if the height of this menu is too small to display the |
* tallest menu item and two scroll icons,then. . . |
* #C# - If the height of the tallest menu item plus two scroll icons is more |
* than the height of the entire menu, adjust the menu's position so that |
* the entire menu is displayed. Otherwise, set the height of the menu to |
* the height of the tallest item plus two scroll icons. |
\******************************************************************************/ |
short |
DoPopUpMsg (MenuHandle TheMenu,Rect* MenuRect,short TopPos,short LeftPos,short PopUpItem) |
{ |
Str255 *ItemString; //-> Item's string |
ItemInfoPtr ItemInfo; //-> Item info |
short TestWidth; //Width of item to test |
short TestHeight; //Width of menu to test |
short Height; //Height of menu |
short Width; //Width of menu |
short MaxHeight; //Height of tallest menu item |
short ItemInd; //Item number of item being checked. |
short ItemPos; //Dist from menu top to PopUpItem in pixels |
short MenuTop; //Coord of top of menu rect, even if off screen |
Rect ScrnRect; //Rectangle of screen minus menu bar and margins |
short HeightAdj; //New coord of menu top/bottom if small menu |
Height = Width = MaxHeight = 0; |
ItemInd = 1; |
ItemPos = 0; |
HLock ((Handle) TheMenu); |
ItemString = (Str255 *) (**TheMenu).menuData; |
ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString)); |
while ((*ItemString) [0] != (char) 0) //#A# |
{ |
ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString)); |
TestHeight = CalcItemHeight (*ItemString, ItemInfo); |
TestWidth = CalcItemWidth (*ItemString, ItemInfo); |
if (ItemInd == PopUpItem) |
ItemPos = Height; |
if (TestWidth > Width) |
Width = TestWidth; |
if (TestHeight > MaxHeight) |
MaxHeight = TestHeight; |
Height += TestHeight; |
ItemInd += 1; |
ItemString = (Str255 *) (ItemInfo + 1); |
} |
HUnlock ((Handle) TheMenu); |
MenuTop = TopPos - ItemPos; |
MenuRect->left = LeftPos; |
MenuRect->top = MenuTop; |
MenuRect->right = MenuRect->left + Width; |
MenuRect->bottom = MenuRect->top + Height; |
FindScreen (MenuRect, &ScrnRect); |
InsetRect (&ScrnRect, scrnMargin, scrnMargin); |
if (MenuRect->top < ScrnRect.top) |
{ |
MenuRect->top = ScrnRect.top; |
if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) < |
MaxHeight) //#B# |
{ |
if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C# |
HeightAdj = MenuRect->top + Height; |
else |
HeightAdj = MenuRect->top + MaxHeight + (short) (2 * |
scrlIconHeight); |
MenuTop += HeightAdj - MenuRect->bottom; |
MenuRect->bottom = HeightAdj; |
} |
} |
if (MenuRect->right > ScrnRect.right) |
OffsetRect (MenuRect, ScrnRect.right - MenuRect->right, 0); |
if (MenuRect->left < ScrnRect.left) |
OffsetRect (MenuRect, ScrnRect.left - MenuRect->left, 0); |
if (MenuRect->bottom > ScrnRect.bottom) |
{ |
MenuRect->bottom = ScrnRect.bottom; |
if (MenuRect->bottom - MenuRect->top - (short) (2 * scrlIconHeight) < |
MaxHeight) //#B# |
{ |
if (MaxHeight + (short) (2 * scrlIconHeight) >= Height) //#C# |
HeightAdj = MenuRect->bottom - Height; |
else |
HeightAdj = MenuRect->bottom - MaxHeight - (short) (2 * |
scrlIconHeight); |
MenuTop -= MenuRect->top - HeightAdj; |
MenuRect->top = HeightAdj; |
} |
} |
return MenuTop; |
} |
/******************************************************************************\ |
* Private: FindScreen - Find rectangle of the screen containing most of the menu |
* |
* Color QuickDraw machines can have more than one screen, and pop-up menus |
* should appear on the screen that contains the most of the menuÕs area. This |
* function returns the rectangle of the screen (in global coordinates) that |
* contains most of the menu whose rectangle (also in global coordinates) is |
* passed in the menuRect parameter. The screenÕs rectangle is returned in the |
* retScreenRect parameter. If the screen that contains the most of the menu is |
* the main screen (i.e. the screen with the menu bar), then the height of the |
* menu bar is added to the top of retScreenRect, effectively removing the menu |
* bar from the rectangle. When Concordia is used on a machine without Color |
* QuickDraw, then the rectangle of the main screen is always returned. Non- |
* Color QuickDraw machines with more than one screen (available from third-party |
* manufacturers) patch QuickDraw to support their screens, and itÕs impossible |
* to determine the rectangles of the auxiliary screens without using |
* manufacturer-specific techniques. Because of this, Concordia does not take |
* advantage of auxiliary screens on non-Color QuickDraw machines. |
* |
* The rectangles of all attached screens are determined through the GDevice list |
* thatÕs maintained by the system. ThereÕs one GDevice in the list for every |
* screen attached to the system. GDevice routines only exist on Color QuickDraw |
* machines, so the first thing that FindScreen does is to determine whether itÕs |
* running on a machine that has Color QuickDraw or not. If itÕs not, then the |
* screen rectangle is taken from the screenBits.bounds QuickDraw global. If |
* Color QuickDraw is available, then the GDevice list is used to determine the |
* appropriate screen. |
* |
* The first GDevice in the GDevice list is retrieved from the GetDeviceList |
* function. The next GDevice in the list is retrieved from the GetNextDevice |
* function. Through these two functions, every GDevice in the GDevice list can |
* be retrieved. |
* |
* For every GDevice in the list, the area of intersection between the menuÕs |
* rectangle and the screenÕs rectangle (found in the gdRect field of the GDevice |
* structure) is calculated. If the area of intersection is the greatest found |
* so far, then it and its GDevice is saved, and the rectangle of that screen is |
* placed into retScreenRect. |
* |
* After every GDevice in the GDevice list has been checked, the GDevice for the |
* screen containing most of the menuÕs rectangle is checked to see if itÕ the |
* GDevice for the main screen. This is done by comparing the GDevice handle |
* against the handle for the main screenÕs GDevice returned by GetMainDevice. |
* If the GDevice is in fact the main screenÕs GDevice, then the height of the |
* menu bar is removed from retScreenRect. |
\******************************************************************************/ |
static void |
FindScreen (menuRect, retScreenRect) |
Rect *menuRect; /* Menu rectangle before processing for screen */ |
Rect *retScreenRect; /* Returns rectangle of screen appropriate for menu */ |
{ |
GDHandle aGDevice; /* Handle to each screenÕs GDevice */ |
GDHandle maxGDevice; /* Handle to GDevice containing most of menu */ |
long area; /* Menu rect/screen rect intersection area */ |
long maxArea; /* Max menu rect/screen rect intersect area found */ |
Rect commonRect; /* Intersection between menu rect and screen rect */ |
SysEnvRec environs; /* Current running environment */ |
/* Determine whether Color QuickDraw is implemented or not */ |
(void) SysEnvirons (curSysEnvVers, /*<*/&environs); |
/* Use GDevices if Color QuickDraw is implemented, else use screenBits */ |
if (environs.hasColorQD) |
{ |
/* Assume max intersection area is 0 and get first GDevice in list */ |
maxArea = 0L; |
maxGDevice = nil; |
aGDevice = GetDeviceList (); |
/* Loop through all screen GDevices */ |
while (aGDevice != nil) |
{ |
/* Calc area of intersection between menu rect and screen rect */ |
SectRect (menuRect, &(**aGDevice).gdRect, /*<*/&commonRect); |
area = (long) (commonRect.bottom - commonRect.top) * (commonRect. |
right - commonRect.left); |
/* If max area found so far, get screenÕs rect and save area */ |
if (area > maxArea) |
{ |
*retScreenRect = (**aGDevice).gdRect; |
maxGDevice = aGDevice; |
maxArea = area; |
} |
/* Go to the next GDevice in the list */ |
aGDevice = GetNextDevice (aGDevice); |
} |
/* If GDevice with most of menu is main screen, remove MBar height */ |
if (maxGDevice == GetMainDevice ()) |
retScreenRect->top += GetMBarHeight (); |
} |
else |
{ |
*retScreenRect = qd.screenBits.bounds; |
retScreenRect->top += GetMBarHeight (); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-08-28