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.
DrawTkl.c
/* |
File: DrawTkl.c |
Contains: the code to process the mDrawMsg message from the Menu |
Manager. This source file contains the routines to do ALL drawing, including |
the scroll icons. |
Written by: |
Copyright: Copyright © 1991-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 <Resources.h> |
#include <ToolUtils.h> |
#include <Icons.h> |
#include <Types.h> |
#include "Concordia.h" |
#include "DrawTkl.h" |
#include "SizeTkl.h" |
/******************************************************************************\ |
* Constants & Macros |
\******************************************************************************/ |
#define scrlSICNID -12288 //Resource ID of scroll arrows SICN |
/******************************************************************************\ |
* Type Declarations |
\******************************************************************************/ |
/* Small icon data */ |
typedef Byte SICNData [32]; |
/******************************************************************************\ |
* Function Prototypes |
\******************************************************************************/ |
void DimRect (Rect *); |
void DrawSICN (SICNData **, short, short, short); |
void DrawICON (Handle, Rect *); |
#pragma segment Main |
/******************************************************************************\ |
* DoDrawMsg - Draw a menu |
* |
* DoDrawMsg draws the menu specified by TheMenu. The rectangle in global coord- |
* inates that the menu occupies is specified in MenuRect. If the system global |
* TopMenuItem is not equal to the top coordinate of MenuRect, a top scroll bar |
* is drawn. If the menu extends below the bottom of MenuRect, a bottom scroll |
* bar is drawn. The Menu Manager (I guess) sets TopMenuItem properly for pull- |
* down menus, while the popup menu tackler (DoPopupMsg) sets TopMenuItem |
* properly for popup menus. DoDrawMsg sets the system global AtMenuBottom to |
* the bottom of the entire menu, regardless of whether it fits on the screen or |
* not. |
* |
* Coding Notes |
* #A# - The sole purpose of this loop is to find the total height of the menu in |
* pixels ignoring the size of the screen. Seems like kind of a waste, |
* doesn't it? |
* #B# - The clip rectangle, MenuClip is only set if the menu has scroll icons. |
* This is determined here. |
* #C# - This loop draws each of the menu items. |
* #D# - Side-effect: system global AtMenuBottom set to coordinate of bottom of |
* Menu regardless of whether the menu fits or not. |
* #E# - We donÕt need the menuEnabled bit any more so get rid of it by shifting |
* it out. Then we have to set the high bit so that all items beyond the |
* 31st will be enabled. With arithmetic right shifting, this high bit |
* will be preserved. |
\******************************************************************************/ |
void |
DoDrawMsg (TheMenu, MenuRect) |
MenuHandle TheMenu; //=> Menu to draw >> |
Rect *MenuRect; //-> Menu's rectangle in global coords >> |
{ |
Str255 *ItemString; //-> Menu item's string |
ItemInfoPtr ItemInfo; //-> Item info |
Rect ItemRect; //Item's rectangle |
Rect TotMenuRect; //Menu's rectangle w/o clipping to screen |
RgnHandle SaveClip; //=> Saved clip region |
Rect MenuClip; //Clip region of menu if menu scrolls |
long EnableFlags; //Menu's enable flags |
SaveClip = (RgnHandle) null; |
if ((**TheMenu).enableFlags & 1) |
{ |
EnableFlags = (unsigned long) (**TheMenu).enableFlags >> 1; //#E# |
EnableFlags |= 0x80000000; |
} |
else |
EnableFlags = 0; |
SetRect (&TotMenuRect, MenuRect->left, sgTopMenuItem, MenuRect->right, |
sgTopMenuItem); |
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)); |
TotMenuRect.bottom += CalcItemHeight (*ItemString, ItemInfo); |
ItemString = (Str255 *) (ItemInfo + 1); |
} |
HUnlock ((Handle) TheMenu); |
MenuClip = *MenuRect; |
if (TotMenuRect.top != MenuRect->top || TotMenuRect.bottom != MenuRect-> |
bottom) //#B# |
{ |
if (TotMenuRect.top != MenuRect->top) |
{ |
DrawScroll (MenuRect, topScroll); |
MenuClip.top += scrlIconHeight; |
} |
if (TotMenuRect.bottom != MenuRect->bottom) |
{ |
DrawScroll (MenuRect, botScroll); |
MenuClip.bottom -= scrlIconHeight; |
} |
SaveClip = NewRgn (); |
GetClip (SaveClip); |
ClipRect (&MenuClip); |
} |
HLock ((Handle) TheMenu); |
ItemString = (Str255 *) (**TheMenu).menuData; |
ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString)); |
ItemRect = TotMenuRect; |
ItemRect.bottom = ItemRect.top; |
while ((*ItemString) [0] != (char) 0) //#C# |
{ |
ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString)); |
ItemRect.bottom += CalcItemHeight (*ItemString, ItemInfo); |
if (ItemRect.bottom > MenuClip.top && ItemRect.top < MenuClip.bottom) |
DrawItem (*ItemString, ItemInfo, &ItemRect, (short) (EnableFlags & |
1)); |
ItemString = (Str255 *) (ItemInfo + 1); |
ItemRect.top = ItemRect.bottom; |
EnableFlags >>= 1; |
} |
HUnlock ((Handle) TheMenu); |
if (SaveClip != (RgnHandle) null) |
{ |
SetClip (SaveClip); |
DisposeRgn (SaveClip); |
} |
sgAtMenuBottom = TotMenuRect.bottom; //#D# |
*((short *) ((*sgMBSaveLoc) + 16)) = 1; |
} |
#pragma segment Main |
/******************************************************************************\ |
* DrawItem - Draw a menu item |
* |
* DrawItem draws a menu item whose text is specified by ItemString and whose |
* item information is specified by ItemData. The rectangle that the item |
* occupies on the screen is specified by ItemRect. If the item is enabled, |
* Enabled must be true, otherwise it must be false. DrawItem also draws mark |
* characters (like check marks); big, scaled, and disabled icons, dims items if |
* they're not enabled, and draws gray lines if the item string begins with a |
* hyphen. Any command key characters that aren't printable are ignored. If the |
* specified item icon can't be found, it is not drawn (of course), but space is |
* left for it. |
* |
* Coding Notes: |
* #A# - This calculation figures out the proper vertical coordinate to begin |
* drawing the item string so that it's centered vertically in ItemRect. |
* #B# - Draw the mark character unless this is a hierarchical menu item. |
* #C# - Draw the command-key equivalent |
* #E# - Draw the item icon |
* #F# - With these command-key equivalents, icons are half their size. |
* #G# - If couldn't load icon, ignore drawing and continue |
* #H# - With this command-key equivalent, icon is dimmed. |
* #I# - These values will be used to set the location of the item string. |
\******************************************************************************/ |
void |
DrawItem (Str255 ItemString,ItemInfoPtr ItemData,Rect* ItemRect,short Enabled) |
{ |
short HorzPos; //Horizontal position to draw item |
short VertPos; //Vertical position to draw item |
short MarkWidth; //Width of item mark |
Handle ItemIcon; //=> Item's icon |
Rect IconRect; //Rectangle of icon |
short IconSize; //Size of icon in pixels |
FontInfo CurrFont; //Current font's characteristics |
PenState CurrPen; //Current characteristics of graphics pen |
short CurrFile; //Refnum of current resource file |
SICNData **SICNRes; //=> SICN resource |
TextStateRec TextState; //Current characteristics of text drawing |
GetPenState (&CurrPen); |
if (ItemString [1] == '-') |
{ |
PenSize (1, 1); |
PenMode (patOr); |
PenPat (&qd.gray); |
MoveTo (ItemRect->left, ItemRect->top + ItemRect->bottom >> 1); |
Line (ItemRect->right - ItemRect->left, 0); |
} |
else |
{ |
PenMode (patOr); |
GetTextState (&TextState); |
TextFace (normal); |
TextMode (srcOr); |
GetFontInfo (&CurrFont); |
MarkWidth = CurrFont.widMax; |
if (ItemData->markChar != '\0' || ItemData->kbdEquiv != '\0') |
{ |
VertPos = ((short) ((ItemRect->bottom - ItemRect->top) - (CurrFont. |
ascent + CurrFont.descent + CurrFont.leading) >> 1) + |
CurrFont.ascent + ItemRect->top); //#A# |
if (ItemData->markChar != (char) 0 && ItemData->kbdEquiv != |
hMenuCmd) //#B# |
{ |
HorzPos = ItemRect->left + itemHorzMarg; |
MoveTo (HorzPos, VertPos); |
DrawChar (ItemData->markChar); |
} |
if (ItemData->kbdEquiv > '!') //#C# |
{ |
HorzPos = ItemRect->right - itemHorzMarg - |
CurrFont.widMax - CharWidth (cmmdCharCode); |
MoveTo (HorzPos, VertPos); |
DrawChar (cmmdCharCode); |
DrawChar (ItemData->kbdEquiv); |
} |
else if (ItemData->kbdEquiv == hMenuCmd) |
{ |
HorzPos = ItemRect->right - sicnSize; |
VertPos = (short) ((ItemRect->bottom - ItemRect->top - (short) |
sicnSize) >> 1) + ItemRect->top; |
CurrFile = CurResFile (); |
UseResFile (0); |
if ((SICNRes = (SICNData **) Get1Resource ('SICN', scrlSICNID)) |
!= (SICNData **) null) |
DrawSICN (SICNRes, heirArrow, HorzPos, VertPos); |
UseResFile (CurrFile); |
} |
} |
if (ItemData->iconNum != (Byte) 0) //#E# |
{ |
IconSize = iconSize; |
if (ItemData->kbdEquiv == (char) 0x1D || ItemData->kbdEquiv == |
(char) 0x1F) //#F# |
IconSize >>= 1; |
if ((ItemIcon = GetIcon (ItemData->iconNum + 256)) != (Handle) null) //#G# |
{ |
IconRect.top = (ItemRect->bottom - ItemRect->top - |
IconSize >> 1) + ItemRect->top; |
IconRect.left = ItemRect->left + itemHorzMarg + MarkWidth + |
markItemGap; |
IconRect.bottom = IconRect.top + IconSize; |
IconRect.right = IconRect.left + IconSize; |
DrawICON (ItemIcon, &IconRect); |
if (ItemData->kbdEquiv == (char) 0x1F) //#H# |
DimRect (&IconRect); |
} |
IconSize += iconItemGap; //#I# |
} |
else |
IconSize = 0; //#I# |
TextFace (ItemData->charStyle); |
GetFontInfo (&CurrFont); |
VertPos = (short) ((ItemRect->bottom - ItemRect->top) - (CurrFont. |
ascent + CurrFont.descent + CurrFont.leading) >> 1) + CurrFont. |
ascent + ItemRect->top; |
HorzPos = ItemRect->left + itemHorzMarg + MarkWidth + markItemGap + |
IconSize; |
MoveTo (HorzPos, VertPos); |
DrawString (ItemString); |
SetTextState (&TextState); |
if (! Enabled) |
DimRect (ItemRect); |
} |
SetPenState (&CurrPen); |
} |
#pragma segment Main |
/******************************************************************************\ |
* DimRect - Dim a rectangle |
* |
* DimRect dims the rectangle specified by ItemRect by bit-clearing it with a |
* medium gray pattern. Normally, we could do this just by drawing over the item |
* with the standard gray pattern, but there's a problem: what if the menu has |
* scrolled an odd number of pixels and we have to draw part of a dimmed menu |
* item? We'll end up with the gray pattern that's out of phase with the part of |
* the menu item that was already drawn. To solve this, DimRect creates its own |
* pattern "on the fly" in GrayPat. Two gray patterns can be created, each one |
* being out of out of phase with the other by one pixel. The particular pattern |
* is chosen by checking to see whether the system global, TopMenuItem, is odd or |
* even. The current pen state is unchanged. |
\******************************************************************************/ |
static void |
DimRect (TheRect) |
Rect *TheRect; //-> Rectangle to dim >> |
{ |
PenState CurrPen; //Current characteristics of graphics pen |
short PatElem; //Pattern element |
short GrayPat [4]; //Gray pattern (not 8 bytes 'cause it's easier here |
short PatInd; //Index into pattern array |
GetPenState (&CurrPen); |
PenMode (patBic); |
if ((sgTopMenuItem & 0x0001) == 0) |
PatElem = (short) 0xAA55; |
else |
PatElem = (short) 0x55AA; |
for (PatInd = 0; PatInd < 4; PatInd++) |
GrayPat [PatInd] = PatElem; |
PenPat ((Pattern*) GrayPat); |
PaintRect (TheRect); |
SetPenState (&CurrPen); |
} |
#pragma segment Main |
/******************************************************************************\ |
* DrawScroll - Draw a scroll arrow |
* |
* DrawScroll draws a top scroll arrow if Which is topScroll, and it draws a |
* bottom scroll arrow if which is botScroll. The menu's rectangle must be |
* specified in MenuRect. |
\******************************************************************************/ |
void |
DrawScroll (Rect* MenuRect,short Which) |
{ |
SICNData **SICNRes; //=> SICN resource |
short HorzPos; //Horizontal position of icon |
short VertPos; //Vertical position of icon |
Rect ScrlRect; //Rectangle of scroll icon area |
PenState CurrPen; //Current pen state |
short CurrFile; //Current resource file's refnum |
HorzPos = (short) ((MenuRect->right - MenuRect->left - sicnSize) >> 1) + |
MenuRect->left; |
ScrlRect = *MenuRect; |
GetPenState (&CurrPen); |
PenPat (&qd.black); |
PenMode (patCopy); |
PenSize (1, 1); |
if (Which == topScroll) |
{ |
ScrlRect.bottom = ScrlRect.top + scrlIconHeight; |
EraseRect (&ScrlRect); |
MoveTo (MenuRect->left, MenuRect->top + scrlIconHeight - 1); |
Line (MenuRect->right - MenuRect->left, 0); |
VertPos = MenuRect->top + 1; |
} |
else |
{ |
ScrlRect.top = ScrlRect.bottom - scrlIconHeight; |
EraseRect (&ScrlRect); |
MoveTo (MenuRect->left, MenuRect->bottom - scrlIconHeight); |
Line (MenuRect->right - MenuRect->left, 0); |
VertPos = MenuRect->bottom - 1 - sicnSize; |
} |
PenMode (patOr); |
CurrFile = CurResFile (); |
UseResFile (0); |
if ((SICNRes = (SICNData **) Get1Resource ('SICN', scrlSICNID)) != |
(SICNData **) null) |
DrawSICN (SICNRes, Which, HorzPos, VertPos); |
UseResFile (CurrFile); |
SetPenState (&CurrPen); |
} |
#pragma segment Main |
/******************************************************************************\ |
* DrawSICN - Draw a small icon |
* |
* DrawSICN draws the small icon specified by TheIcon into the current port. |
* Each SICNData can hold any number of SICNs, so Index specifies which SICN to |
* draw, 0 specifying the first. HorzPos and VertPos specify the horizontal and |
* vertical position to draw the top-left corner of the icon in local |
* coordinates. If TheIcon doesn't specify a SICN or if Index is out of range, |
* garbage will be drawn. The transfer mode will be the equivalent of the |
* current pen mode of the current port. For example, if the current pen mode is |
* patXor, the SICN will be drawn in srcXor mode. |
\******************************************************************************/ |
static void |
DrawSICN (SICNData** TheIcon,short Index,short HorzPos,short VertPos) |
{ |
BitMap IconBits; //Bitmap for icon |
GrafPtr CurrPort; //-> Current GrafPort |
Rect SICNRect; //Rectangle to draw icon into |
short TransMode; //Transfer mode to use |
HLock ((Handle) TheIcon); |
SetRect (&IconBits.bounds, 0, 0, sicnSize, sicnSize); |
IconBits.rowBytes = 2; |
IconBits.baseAddr = (Ptr) (*TheIcon + Index); |
SetRect (&SICNRect, HorzPos, VertPos, HorzPos + sicnSize, VertPos + |
sicnSize); |
GetPort (&CurrPort); |
if (CurrPort->pnMode == patCopy || CurrPort->pnMode == notPatCopy) |
TransMode = srcCopy; |
else if (CurrPort->pnMode == patOr || CurrPort->pnMode == notPatOr) |
TransMode = srcOr; |
else if (CurrPort->pnMode == patXor || CurrPort->pnMode == notPatXor) |
TransMode = srcXor; |
else if (CurrPort->pnMode == patBic || CurrPort->pnMode == notPatBic) |
TransMode = srcBic; |
CopyBits (&IconBits, &CurrPort->portBits, &IconBits.bounds, &SICNRect, |
TransMode, (RgnHandle) null); |
HUnlock ((Handle) TheIcon); |
} |
#pragma segment Main |
/******************************************************************************\ |
* DrawICON - Draw an icon |
* |
* DrawICON draws the icon specified by TheIcon into the current port. IconRect |
* specifies the size and location to draw the icon in local coordinates. If |
* TheIcon doesn't specify an ICON, garbage will be drawn. The transfer mode |
* will be the equivalent of the current pen mode of the current port. For |
* example, if the current pen mode is patXor, the ICON will be drawn in srcXor |
* mode. |
\******************************************************************************/ |
static void |
DrawICON (TheIcon, IconRect) |
Handle TheIcon; //=> Icon data >> |
Rect *IconRect; //-> Rectangle to draw icon into >> |
{ |
BitMap IconBits; //Bitmap for icon |
GrafPtr CurrPort; //-> Current GrafPort |
short TransMode; //Transfer mode to use |
HLock (TheIcon); |
SetRect (&IconBits.bounds, 0, 0, iconSize, iconSize); |
IconBits.rowBytes = 4; |
IconBits.baseAddr = *TheIcon; |
GetPort (&CurrPort); |
if (CurrPort->pnMode == patCopy || CurrPort->pnMode == notPatCopy) |
TransMode = srcCopy; |
else if (CurrPort->pnMode == patOr || CurrPort->pnMode == notPatOr) |
TransMode = srcOr; |
else if (CurrPort->pnMode == patXor || CurrPort->pnMode == notPatXor) |
TransMode = srcXor; |
else if (CurrPort->pnMode == patBic || CurrPort->pnMode == notPatBic) |
TransMode = srcBic; |
CopyBits (&IconBits, &CurrPort->portBits, &IconBits.bounds, IconRect, |
TransMode, (RgnHandle) null); |
HUnlock (TheIcon); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-08-28