{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{ }
{ GENERIC GRAPHICS }
{ ``````````````````````````````` }
{ }
{ A Generic Utilities unit, for use by any program.
Copyright İ by David Sinclair, 1990 2001.
I am releasing these units to the Pascal community. Feel free to use them in whole or part in your Pascal programs.
You are also welcome to modify these units to suit your needs. If you wish to re-distribute the sources with your changes,
please clearly indicate that you have changed them. In all cases, you must leave these comments and the copyright notice intact.
If you use a significant portion of these units, I would appreciate acknowledgement in your About dialog and/or documentation,
e.g. ³Dejal Generic Utilities copyright İ by David Sinclair, 1990 - 2001.²
Iıd appreciate it if you also e-mail me at if you find these units useful. If you have any questions about
these units, you can e-mail me at that address and I will do my best to help, time permitting. However, these units are provided
³as is² and I do not guarantee their reliablity or suitability for any particular purpose.
These units have been used extensively in my Dejal shareware and freeware products over the years. Most of the code was written
many years ago, and the code and style may not be optimal in all cases, but unless otherwise noted all routines have been used
in released software, so should work as described.
Please visit and try out Dejal QuickEncrypt and/or my other shareware products. If you want to show
your appreciation for these units financially, registrations for my shareware are always welcome! Or you can make a donation to
me via my online order form: .
I hope you find these units useful, and good luck in your Pascal endeavors!
- David Sinclair, Dejal
}
{ }
{ * * * }
{ UNIT HISTORY: }
{ }
{ Version: Start - finish dates: Comments / changes: }
{ }
{ 1.0: 27 October 1990 grafZoomRect code copied from a }
{ TransSkel sample. }
{ 1.1: 22 Nov 1990 Added grafGetFontState & grafSetFontState. }
{ 1.2: 23 Nov 1990 Moved fake QD Globs here from }
{ genShowInitIcon. }
{ 1.3: 27 Nov 1990 Moved fake QD Globs into a new }
{ genGlobals unit. }
{ 1.4: 22 February 1991 Added grafFullScreenWindow based on }
{ Darkness code. }
{ 1.4.1: 30 March 1991 Got round to debugging FullScreenWindow }
{ at last!! }
{ 1.5: 30 March 1991 Added grafShowHideMenubar (from }
{ HideMenubar). }
{ 1.6: 30 March 1991 Added grafRectOf function. }
{ 1.6.1: 12 April 1991 Allowed access to FontState routines in }
{ non-appls now that Iım using the TN }
{ version of QD globals access. }
{ 1.7: 13 April 1991 Added the grafZeroRect function. }
{ 1.8: 22 April 1991 Added the grafFontNormal procedure. }
{ 1.8.1: 9 June 1991 Fixed grafShowHideMenubar so it paints }
{ behind the menubar. }
{ 2.0: 20 December 1991 First public release, in library form. }
{ 2.1: 7 January 1992 Added the grafDrawIcon routine. }
{ 2.2: 2 August 1994 Moved drawing-related routines out of }
{ genDialogs (those now being grafInColour, }
{ grafGreyLinesItem, grafBlackLinesItem, }
{ grafGreyoutItem, grafInitAnimatedIcons, }
{ grafNextIconID and grafInitialIconID), and }
{ added the grafPalatinoFont routine. }
{ 2.3: 14 November 94 Added the grafGetClip, grafSetClip and }
{ grafDrawTitleItem routines. }
{ 2.4: 30 December 1994 Added the grafDrawIcon routine. Modified }
{ grafGetFontState and grafSetFontState to }
{ tidy up the source code pretty printing. }
{ 2.5: 910 January 1995 Added check for a cGrafPort in grafInColour, }
{ and added the grafGetPortSize routine. }
{ 2.6: 12 January 1995 Added the grafDrawTextItem and }
{ grafHasColour routines. }
{ 2.7: 20 January 1996 Added the grafSetFontSizeStyle and }
{ grafDrawStyledTextItem routines.
12 October 1997 Added the GrafDrawIconRect routine.
19 April 1998 Added the GrafGetItemRect routine.
16 April 1999 Added the GrafShowInitIcon routine.
27 October 2001 Public release as source code. }
{ * * * }
{ N.B: Most of my units require the compile-time variables applicationı }
{ and debugı, both of which are booleans. }
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
UNIT genGraphics;
INTERFACE
USES
genToolbox;
CONST
mBarHeightGlob = $BAA;
defaultMenuHeight = 20;
defaultDelayTicks = 1;
dontShowIconYet = -2; { Assumes that there is no icon with an ID of -2 }
{ when used with grafInstallIcon }
aICNResType = 'aICN'; { Used with the animated icon routines }
aIcnID = 128;
animate = -1;
greyColor = 0;
titlePlusLines = true;
titleWithoutLines = false;
Palatino = 9601;
TYPE
fontState = RECORD
font: integer;
face: style;
mode: integer;
size: integer
END;
displayOptions = (show, hide, swap);
aICN = RECORD
delayTicks, numIcons: integer;
icnID: ARRAY[1..1] OF integer
END;
aIcnPtr = ^aICN;
aIcnHandle = ^aIcnPtr;
{$IFC application}
VAR
theGrafIconID: integer;
aIcnHndl: aIcnHandle;
aIcnIndex: integer;
aIcnLastTicks: longint;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafZoomRect (startRect, endRect: rect; delayTicks: longint; drawOnDesktop: boolean);
PROCEDURE grafGetFontState (theDialog: dialogPtr; VAR theFontState: fontState);
PROCEDURE grafSetFontState (theDialog: dialogPtr; theFontState: fontState);
PROCEDURE grafSetFontSizeStyle (theDialog: DialogPtr; theFont, theSize: Integer; theStyle: Style);
FUNCTION grafFullScreenWindow: windowPtr;
PROCEDURE grafShowHideMenubar (displayMode: displayOptions; VAR oldHeight: integer);
FUNCTION grafRectOf (left, top, right, bottom: integer): rect;
FUNCTION grafZeroRect: rect;
PROCEDURE grafFontNormal;
FUNCTION grafHasColour: boolean;
FUNCTION grafInColour: boolean;
PROCEDURE grafDrawAnICON (theDialog: dialogPtr; itemNo, iconID: integer; drawIt: boolean);
PROCEDURE GrafDrawIconRect(theDialog: DialogPtr; iconID: Integer; transform: IconTransformType; iconRect: Rect);
{$IFC application}
PROCEDURE grafDrawIcon (theDialog: dialogPtr; itemNo, iconID: integer);
PROCEDURE grafChangeIcon (theDialog: dialogPtr; itemNo, iconID: integer);
{$ENDC}
PROCEDURE grafInstallIcon (theDialog: dialogPtr; itemNo, iconID: integer);
{$IFC application}
PROCEDURE grafInitAnimatedIcons (rndStart: boolean);
{$ENDC}
FUNCTION GrafGetIconSuite(iconID: Integer): Handle;
PROCEDURE GrafShowInitIcon (iconID: Integer);
FUNCTION grafGetClip: rgnHandle;
PROCEDURE grafSetClip (VAR oldClip: rgnHandle);
PROCEDURE grafDrawGreyLinesItem (theDialog: dialogPtr; theItem: integer);
PROCEDURE grafDrawBlackLinesItem (theDialog: dialogPtr; theItem: integer);
PROCEDURE grafDrawGreyoutItem (theDialog: dialogPtr; theItem: integer);
PROCEDURE grafDrawTextItem (theDialog: dialogPtr; theItem: integer; {}
theText: str255; justification: integer; colour: longint);
PROCEDURE grafDrawStyledTextItem (theDialog: DialogPtr; theItem: Integer; {}
theText: Str255; theFont, theSize: Integer; theStyle: Style; justification: Integer; {}
colour: Longint);
PROCEDURE grafDrawTitleItem (theDialog: dialogPtr; theItem: integer; {}
theText: str255; includeRedLines: boolean);
PROCEDURE grafUsePalatinoFont;
PROCEDURE grafGetPortSize (yourPort: grafPtr; VAR portHeight, portWidth: integer);
FUNCTION GrafGetItemRect(theDialog: DialogPtr; theItem: Integer): Rect;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
IMPLEMENTATION
PROCEDURE grafZoomRect (startRect, endRect: rect; delayTicks: longint; drawOnDesktop: boolean);
{ Smoothly interpolates the start rectangle into the end one, just like the Finderıs }
{ zooming. NOTE: Unless you specify true for drawOnDesktop, this procedure }
{ assumes that the current grafPort is the one you want to zoom inso make sure it }
{ is! If you pass true for drawOnDesktop it will open a grafPort to the screen then }
{ restore the former grafPort. The delayTicks parameter is used so that the zoom }
{ effect runs at the same speed on all Macs: pass defaultDelayTicks as a default, or 0 }
{ for maximum speed. }
{ From the MultiSkel demo program of TransSkel: written by Paul DuBois, 14 June }
{ 1986; ported to Lightspeed Pascal by Owen Hartnett, 7 January 1987; modified into a }
{ Generic Utility by David Sinclair, 27 October 1990; modified to create grafPort to the }
{ desktop if requested, 13 April 1991. }
CONST
zoomSteps = 15; { No of rects in interpolative series }
zoomRects = 4; { No of rects on-screen at one time }
VAR
zRect: ARRAY[1..zoomRects] OF rect;
curRect: rect;
jump: integer;
hDiff, vDiff, widDiff, htDiff: integer;
rWid, rHt: integer;
finalTicks: Longint; { Returned by delay & ignored }
pnState: penState;
myGray: pattern;
oldPort, newPort: grafPtr;
BEGIN
IF drawOnDesktop THEN
BEGIN
getPort(oldPort);
getWMgrPort(newPort);
IF newPort <> NIL THEN
setPort(newPort)
END;
stuffHex(@myGray, 'AA55AA55AA55AA55'); { Use this, rather than the built-in }
{ gray, so it will work when the }
{ QuickDraw globals arenıt available }
getPenState(pnState);
penNormal;
penMode(patXor);
penPat(myGray);
hDiff:= endRect.left - startRect.left; { Positive if moving to right }
vDiff:= endRect.top - startRect.top; { Positive if moving down }
rWid:= startRect.right - startRect.left;
rHt:= startRect.bottom - startRect.top;
widDiff:= (endRect.right - endRect.left) - rWid;
htDiff:= (endRect.bottom - endRect.top) - rHt;
zRect[1].topLeft:= point(0); { Initialise the first rectangle as a null one }
zRect[1].botRight:= point(0);
{ Order of evaluation is important in the rect coordinate calculations. Since all }
{ arithmetic is integer, you canıt save time by calculating j / zoomSteps and using }
{ thatitıll usually be zero. }
FOR jump:= 1 TO zoomSteps DO
BEGIN
frameRect(zRect[((jump - 1) MOD zoomRects) + 1]); { Erase last rect }
curRect.left:= startRect.left + (hDiff * jump) DIV zoomSteps;
curRect.top:= startRect.top + (vDiff * jump) DIV zoomSteps;
curRect.right:= curRect.left + rWid + (widDiff * jump) DIV zoomSteps;
curRect.bottom:= curRect.top + rHt + (htDiff * jump) DIV zoomSteps;
zRect[((jump - 1) MOD zoomRects) + 1]:= curRect; { Replacement rect }
frameRect(curRect);
delay(delayTicks, finalTicks)
END;
FOR jump:= zoomSteps TO zoomSteps + zoomRects - 1 DO { Erase remaining rects }
BEGIN
frameRect(zRect[((jump - 1) MOD zoomRects) + 1]);
delay(delayTicks, finalTicks)
END;
IF drawOnDesktop THEN
setPort(oldPort);
setPenState(pnState)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafGetFontState (theDialog: dialogPtr; VAR theFontState: fontState);
{ Similar to GetPort and GetPenState, this procedure returns a record containing }
{ relevant information about the specified dialogs font specifications. Used in }
{ conjunction with grafSetFontState to preserve the font state within a routine while }
{ you are temporarily changing it elsewhere. }
{ Written by David Sinclair, 22 November 1990. }
BEGIN
WITH theFontState, theDialog^ DO
BEGIN
font:= txFont;
face:= txFace;
mode:= txMode;
size:= txSize
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafSetFontState (theDialog: dialogPtr; theFontState: fontState);
{ Similar to SetPort and SetPenState, this procedure sets the specified dialogs font }
{ specifications to previously saved values. Used in conjunction with }
{ grafGetFontState to preserve the font state within a routine while you are }
{ temporarily changing it elsewhere. }
{ Written by David Sinclair, 22 November 1990. }
BEGIN
WITH theFontState, theDialog^ DO
BEGIN
txFont:= font;
txFace:= face;
txMode:= mode;
txSize:= size
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafSetFontSizeStyle (theDialog: DialogPtr; theFont, theSize: Integer; theStyle: Style);
{ Sets the current font, size and style to those specified. You might like to preserve the old font }
{ state first, and restore it afterwards, via grafGetFontState and grafSetFontState. }
{ Written by David Sinclair, 20 January 1996. }
BEGIN
IF theFont = Palatino THEN
GetFNum('Palatino', theFont);
TextFont(theFont);
TextSize(theSize);
TextFace(theStyle);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafFullScreenWindow: windowPtr;
{ Creates a big window which covers the entire screen(s) and the menu bar; for use by }
{ screensaver-type programs. You should already have called grafShowHideMenubar }
{ to hide the menubar (and remembered the old menubar height) before calling this }
{ function. }
{ Converted and modified from C by David Sinclair, 22 February 1991; from the }
{ DarkInit program of the Darkness MultiFinder screensaver by Lunarmobiscuit, }
{ İ 1989. }
VAR
wowItWorked: boolean;
theGrayRgn, screenRgn: rgnHandle;
screenRect: rect;
bigWindow: windowPtr;
BEGIN
wowItWorked:= false;
{ First, determine the size for the window }
theGrayRgn:= GetGrayRgn;
screenRect:= theGrayRgn^^.rgnBBox;
{ Set the top value to zero to include the menu bar also }
screenRect.top:= 0;
{ Open big window }
bigWindow:= NewWindow(NIL, screenRect, '', true, 0, pointer(-1), FALSE, 0);
IF (bigWindow) <> NIL THEN
BEGIN
SetPort(bigWindow);
{ At this point, the new window is the correct size, but the visRgn doesn't include the menu bar }
screenRgn:= NewRgn;
IF screenRgn <> NIL THEN
BEGIN
{ ScreenRect is global, but visrgn is local }
GlobalToLocal(screenRect.topLeft);
GlobalToLocal(screenRect.botRight);
{ Make region out of menu bar area }
RectRgn(screenRgn, screenRect);
{ Tack this onto the windowıs visRgn }
UnionRgn(bigWindow^.visRgn, screenRgn, bigWindow^.visRgn);
{ Get rid of the temp region }
DisposeRgn(screenRgn);
wowItWorked:= true
END
END;
IF wowItWorked THEN
grafFullScreenWindow:= bigWindow
ELSE
grafFullScreenWindow:= NIL
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafShowHideMenubar (displayMode: displayOptions; {}
VAR oldHeight: integer);
{ If the displayMode is swap, then hides the menubar if it is visible, otherwise }
{ restores it; otherwise does what the displayMode specifies (show or hide). Pass the }
{ old height when swapping or showing (if known)the routine passes back the old }
{ height whenever called, which you should store for later passing back to this }
{ routine. }
{ Hacked by David Sinclair, 26 November 1990. Written as an FKEY, 22 February 1991. }
{ Debugged so it actually works & put in genGraphics, 30 March 1991. Debugged so it }
{ paints the desktop behind the menubar after hiding, 9 June 1991. }
VAR
oldPort, newPort: grafPtr;
theGreyRgn, mBarRgn: rgnHandle;
heightGlob: integerPtr;
currentHeight: integer;
mBarRect: rect;
BEGIN
getPort(oldPort);
theGreyRgn:= getGrayRgn;
heightGlob:= integerPtr(mBarHeightGlob); { Pointer to low-mem glob }
currentHeight:= heightGlob^; { Get it }
mBarRect:= theGreyRgn^^.rgnBBox; { Set a rect of the normal menubar size }
mBarRect.top:= 0;
IF currentHeight > 0 THEN
mBarRect.bottom:= currentHeight
ELSE IF (oldHeight > 0) AND (oldHeight < 200) THEN
mBarRect.bottom:= oldHeight
ELSE
mBarRect.bottom:= defaultMenuHeight;
oldHeight:= mBarRect.bottom; { Pass it back for later use }
mBarRgn:= newRgn;
IF mBarRgn <> NIL THEN
BEGIN
rectRgn(mBarRgn, mBarRect); { Set a region of the normal menubar size }
IF (currentHeight = oldHeight) AND (displayMode <> show) THEN { Hide the menubar }
BEGIN
getWMgrPort(newPort);
heightGlob^:= 0; { Hide the menubar }
unionRgn(theGreyRgn, mBarRgn, theGreyRgn); { Add the menubar to the desktop }
paintBehind(frontWindow, mBarRgn);
calcVisBehind(frontWindow, mBarRgn)
END
ELSE IF (currentHeight = 0) AND (displayMode <> hide) THEN { Show the menubar }
BEGIN
heightGlob^:= oldHeight; { Restore the menubar }
diffRgn(theGreyRgn, mBarRgn, theGreyRgn); { Remove the menubar from the desktop }
drawMenuBar
END;
{ Get rid of the temp region }
DisposeRgn(mBarRgn)
END;
setPort(oldPort)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafRectOf (left, top, right, bottom: integer): rect;
{ Useful little function to take for co-ordinates and return a rectangle, like SetRect }
{ does, but as a function. }
{ Written by David Sinclair, 30 March 1991. }
VAR
theRect: rect;
BEGIN
setRect(theRect, left, top, right, bottom);
grafRectOf:= theRect
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafZeroRect: rect;
{ Simply returns a rectangle with all zeros, i.e. (0, 0, 0, 0). }
{ Written by David Sinclair, 13 April 1991. }
VAR
tempRect: rect;
BEGIN
WITH tempRect DO
BEGIN
topLeft:= point(0);
botRight:= topLeft
END;
grafZeroRect:= tempRect
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafFontNormal;
{ Simply sets the font type, size, style and mode for the current port to their default }
{ values, like PenNormal does for the QuickDraw pen. }
{ Written by David Sinclair, 22 April 1991. }
BEGIN
textFont(systemFont);
textFace([]);
textMode(srcOr);
textSize(systemFont)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafHasColour: boolean;
{ Returns true if the current machine has colour capabilities call grafInColour, below, if you }
{ want to know if the current window is actually in colour or not; this routine will just tell you }
{ whether or not the colour calls will crash the computer. }
{ Written by David Sinclair, 12 January 1995. }
CONST
colourQD = $100; { QD vers 1.00 is first with colour }
VAR
response: longint;
BEGIN
grafHasColour:= (gestalt(gestaltQuickDrawVersion, response) = noErr) & (loWord(response) >= colourQD);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafInColour: boolean;
{ Returns true if the current machine has colour capabilities, the main screen }
{ is currently deep enough, and the current port is a cGrafPort. If you just want to }
{ find out if Colour QuickDraw calls are allowed, call grafHasColour, above. }
{ Written by David Sinclair, 15 June 1994; added check for a cGrafPort, 9 January 1995; }
{ shifted check for Colour QD into a separate routine, 12 January 1995. }
CONST
minBitDepth = 4; { If 16 colours or more, weıre in colour }
VAR
colourPresent: boolean;
gdev: gdHandle; { For use with the getGDevice call }
currentPort: grafPtr;
BEGIN
colourPresent:= grafHasColour;
IF colourPresent THEN
BEGIN
colourPresent:= false;
gdev:= getGDevice; { Get main screen }
getPort(currentPort);
IF (gdev <> NIL) & (gdev^^.gdPMap <> NIL) & (currentPort <> NIL) THEN
IF gdev^^.gdPMap^^.pixelSize >= minBitDepth THEN
WITH currentPort^.portBits DO { See IM V-52, fig 3. }
colourPresent:= BTST(rowBytes, 15) & BTST(rowBytes, 14);
END;
grafInColour:= colourPresent
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawAnICON (theDialog: dialogPtr; itemNo, iconID: integer; drawIt: boolean);
{ Gets and draws the specified cicn or ICON, if it is valid. Looks first for a colour icon, }
{ then a black and white one if there is no colour icon. If none is found, uses the }
{ default Note icon. If dontShowIconYet is passed for the iconID, a null icon is }
{ installed. If false is passed for drawIt, the icon will be installed in the dialog icon }
{ item, but not drawn. }
{ Written by David Sinclair, 9-10 November 1991; dontShowIconYet option added 8 }
{ December 1991; made into a gen routine 7 January 1992. }
VAR
inColour: boolean;
itemType: integer;
theIcon, itemHandle: handle;
itemBox: rect;
BEGIN
IF iconID = dontShowIconYet THEN
BEGIN
GetDialogItem(theDialog, itemNo, itemType, itemHandle, itemBox);
SetDialogItem(theDialog, itemNo, iconItem, NIL, itemBox)
END
ELSE IF iconID <> 0 THEN
BEGIN
theIcon:= NIL;
inColour:= grafInColour;
IF inColour THEN
theIcon:= handle(getCIcon(iconID));
IF theIcon = NIL THEN
inColour:= false;
IF theIcon = NIL THEN { No icon yet, try a B&W one }
theIcon:= getIcon(iconID);
IF theIcon <> NIL THEN
BEGIN
GetDialogItem(theDialog, itemNo, itemType, itemHandle, itemBox);
IF theIcon <> NIL THEN
BEGIN
SetDialogItem(theDialog, itemNo, iconItem, theIcon, itemBox);
IF drawIt THEN
IF inColour THEN
plotCIcon(itemBox, cIconHandle(theIcon))
ELSE
plotIcon(itemBox, theIcon)
END
END
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE GrafDrawIconRect(theDialog: DialogPtr; iconID: Integer; transform: IconTransformType; iconRect: Rect);
{Draws the specified icon in the specified rectangle. Uses an icon family. Pass one of kTransformNone,
kTransformSelected, etc for transform; see Icons.p for constant definitions. Requires Mac OS 7 or later.}
{Written by David Sinclair, 12 October 1997.}
VAR
oldPort: GrafPtr;
err: OSErr;
BEGIN
GetPort(oldPort);
SetPort(theDialog);
err:= PlotIconID(iconRect,kAlignNone,transform,iconID);
SetPort(oldPort);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE drawTheIcon (theDialog: dialogPtr; itemNo: integer);
{ Draws the icon using the new sys 7 icon drawing routines if available, otherwise }
{ hacks it under sys 6. If running as an app, it uses the number passed to }
{ grafInstallIcon, below, otherwise defaults to the icon family with an ID of 128. }
{ Written by David Sinclair, 25 January 1992; modified to only use the new icon }
{ drawing routines if running in colour under System 7, 28 February 1992. }
CONST
sys7 = $0700; { System 7.0 version number }
VAR
oldPort: grafPtr;
response: longint;
iconID, itemType: integer;
itemHandle: handle;
itemBox: rect;
sys7andColour: boolean;
err: osErr;
theIcnList: handle;
BEGIN
getPort(oldPort);
setPort(theDialog);
{$IFC application}
iconID:= theGrafIconID;
{$ELSEC}
iconID:= aIcnID;
{$ENDC}
IF iconID <> 0 THEN
BEGIN
sys7andColour:= false;
IF gestalt(gestaltSystemVersion, response) = noErr THEN
IF loWord(response) >= sys7 THEN
sys7andColour:= grafInColour;
GetDialogItem(theDialog, itemNo, itemType, itemHandle, itemBox);
IF sys7andColour THEN
err:= plotIconID(itemBox, 0, 0, iconID)
ELSE
BEGIN
theIcnList:= getResource('ICN#', iconID);
IF theIcnList <> NIL THEN
BEGIN
plotIcon(itemBox, theIcnList);
releaseResource(theIcnList)
END
END
END;
setPort(oldPort)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
{$PUSH}
{$R-}
FUNCTION getNextIconID: integer;
{ Returns the ID of the icon to use for animated icon, based on the number of }
{ ticks since the previous one. If it is not yet time to change animated icons, it }
{ returns 0 (which tells the drawing handler not to change the icon). Uses info stored }
{ in globals. }
{ Written by David Sinclair, 14 November 1991; made into a genDialogs routine and }
{ debugged a bit, 6 June 1994; modified to automatically handle icon animation, }
{ 2 August 1994. }
VAR
iconID: integer;
BEGIN
IF aIcnHndl = NIL THEN { aICN missing or too small }
iconID:= 0 { Donıt change icon from the first one used }
ELSE
BEGIN
hLock(handle(aIcnHndl)); { Make sure it doesnıt go walkies while dereferenced }
IF tickCount - aIcnLastTicks < aIcnHndl^^.delayTicks THEN
iconID:= 0
ELSE
BEGIN
iconID:= aIcnHndl^^.icnID[aIcnIndex]; { Get next iconıs ID }
aIcnLastTicks:= tickCount; { Set last ticks value to this time }
aIcnIndex:= aIcnIndex + 1; { Increment index & check for range }
IF aIcnIndex > aIcnHndl^^.numIcons THEN
aIcnIndex:= 1
END;
hUnlock(handle(aIcnHndl)) { Let it loose until I need it again }
END;
getNextIconID:= iconID
END;
{$POP}
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
PROCEDURE grafDrawIcon (theDialog: dialogPtr; itemNo, iconID: integer);
{ This routine is the same as the following one, except it is designed to be used to draw an }
{ icon when it isnıt the ³main² icon in the dialog; usually when there are several icons }
{ identifying various things plus an animated icon; call this to draw those fixed icons. }
{ It will preserve the value of theGrafIconID global. Note: donıt pass this routine as a }
{ drawing proc, as it requires the iconID parameter. Instead, define a local routine to }
{ determine the correct icon ID for the current itemNo, and then call this routine. }
{ Written by David Sinclair, 30 December 1994. }
VAR
oldIconID: integer;
BEGIN
oldIconID:= theGrafIconID;
IF iconID = animate THEN
iconID:= getNextIconID;
IF (iconID <> 0) & (iconID <> dontShowIconYet) THEN
BEGIN
theGrafIconID:= iconID;
drawTheIcon(theDialog, itemNo);
END;
theGrafIconID:= oldIconID
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
PROCEDURE grafChangeIcon (theDialog: dialogPtr; itemNo, iconID: integer);
{ Changes the icon as installed by grafInstallIcon to the specified icon. Call this to }
{ animate a sequence of icons or to change it to a specified icon. Make sure you call }
{ the following routine before this one (youıd typically call grafInstallIcon from your }
{ dialog setup procedure, and grafChangeIcon from your event filter). Pass the ID of }
{ the icon to use, or the constant animate to automatically handle animated icons. }
{ The icon is only drawn if different from before (since simple updating of the icon }
{ is handled by the Dialog Manager via the installed handler). }
{ Written by David Sinclair, 25 January 1992; modified to automatically handle }
{ icon animation, 2 August 1994. }
BEGIN
IF iconID = animate THEN
iconID:= getNextIconID;
IF (iconID <> 0) & (iconID <> theGrafIconID) THEN
BEGIN
theGrafIconID:= iconID;
drawTheIcon(theDialog, itemNo)
END
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafInstallIcon (theDialog: dialogPtr; itemNo, iconID: integer);
{ Installs an icon family drawing routine into the icon userItem in the specified }
{ dialog, and initialises the icon global variable (if running as an app). This routine }
{ can be used to install an icon handler to look after updating the icon when }
{ necessary. Pass the ID of the icon to install, or the constant animate to automatically }
{ handle animated icons (using the aICN resource; note: you must have previously }
{ called grafInitAnimatedIcons to use animated icons). }
{ Written by David Sinclair, 25 January 1992; modified to automatically handle }
{ icon animation, 2 August 1994; added UPP support, 31 May 1997. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
theUPP: UserItemUPP;
BEGIN
{$IFC application}
IF iconID = animate THEN
theGrafIconID:= getNextIconID
ELSE
theGrafIconID:= iconID;
IF theGrafIconID = 0 THEN
theGrafIconID:= aIcnID;
{$ENDC}
GetDialogItem(theDialog, itemNo, itemType, itemHandle, itemBox);
IF (itemType = userItem) | (itemType = userItem + itemDisable) THEN BEGIN
theUPP:= NewUserItemProc(@DrawTheIcon);
SetDialogItem(theDialog, itemNo, itemType, Pointer(theUPP), itemBox);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
PROCEDURE grafInitAnimatedIcons (rndStart: boolean);
{ Initalises the animated icons global variables so that the initial icon used will be the }
{ first icon in the sequence (if rndStart is false) or a random icon from the sequence (if }
{ itıs true). }
{ Written by David Sinclair, 14 November 1991; rnd icon option added 11 January 1992; }
{ made into a genDialogs routine and debugged a bit, 6 June 1994. }
CONST
defaultTicks = 20;
BEGIN
theGrafIconID:= aIcnID; { Paranoia global initialisation }
aIcnIndex:= 1; { Initialise index to use the first icon }
aIcnHndl:= aIcnHandle(getResource(aICNResType, aIcnID));
IF aIcnHndl <> NIL THEN
IF aIcnHndl^^.numIcons < 2 THEN { Donıt need the resource if 0 or 1 icons }
BEGIN
releaseResource(handle(aIcnHndl));
aIcnHndl:= NIL
END
ELSE
BEGIN
hNoPurge(handle(aIcnHndl)); { Make sure it doesnıt vanish }
hLock(handle(aIcnHndl)); { Or go walkies while dereferenced }
IF aIcnHndl^^.delayTicks < 0 THEN { Make sure delay value is valid }
aIcnHndl^^.delayTicks:= defaultTicks;
aIcnLastTicks:= tickCount - aIcnHndl^^.delayTicks - 60;
{ Set last ticks value to suitably ancient time }
IF rndStart THEN { Start with a random icon }
aIcnIndex:= (abs(random) MOD aIcnHndl^^.numIcons) + 1;
hUnlock(handle(aIcnHndl)) { Let it loose until I need it again }
END
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION GrafGetIconSuite(iconID: Integer): Handle;
{The same as the Toolbox GetIconSuite routine, except it only gets the small icons, it detaches them from the resource
file, and it makes them unpurgable; which can be important in some situations (if you get garbage for an icon,
changes are this is the solution).}
{Written by David Sinclair, 25 January 1995; made generic, 17 April 1999.}
VAR
suiteHndl: Handle;
err: OSErr;
PROCEDURE AddIcon (iconType: ResType);
{Subroutine to get and add the specified bit depth of icon to the icon suite.}
VAR
iconHndl: Handle;
BEGIN
iconHndl:= GetResource(iconType, iconID);
IF iconHndl<>nil THEN BEGIN
DetachResource(iconHndl);
HNoPurge(iconHndl);
err:= AddIconToSuite(iconHndl, suiteHndl, iconType)
END;
END;
BEGIN
err:= NewIconSuite(suiteHndl);
IF err <> noErr THEN
suiteHndl:= nil
ELSE BEGIN
AddIcon(small1BitMask);
AddIcon(small4BitData);
AddIcon(small8BitData);
END;
GrafGetIconSuite:= suiteHndl
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE GrafShowInitIcon (iconID: Integer);
{Show the icon specified in the correct place during startup. Note: This code is roughly based on an assembly language
routine by Paul Mercer, Darin Adler, and Paul Snively from an idea by Steve Capps. We use this method to be
compatible with other Mac INITs. The low memory CurApName is a convenient place to store four bytes of
information so the next INIT doesnıt overwrite our icon. We store into myHoriz the horizontal pixel location
where the next INIT should go. We checksum the value and store the checksum in the next two bytes, so that
INITs can determine whether theyıre the 1st one loaded. It assumes that globals.qd.thePort has already been
initialised. It will only work under Mac OS 7.0 or later (but checks and wonıt do anything if under an earlier
version).}
{It was converted to LightSpeed C by Eric Shapiro, and to THINK Pascal by David Sinclair, 26 October 1990 (along
with other modifications); updated to use the new System 7 icon drawing routine, 4 May 1993; tidied and added
to genGraphics, 16 April 1999; added OS 7.0 check, 14 May 1999.}
CONST
curApName = $910; {Low-memory system global: see IM III-227}
iconHeight = 32;
iconWidth = 32;
firstX = 8;
bottomMargin = 8;
defMoveXBy = 40;
checksumConst = $1021;
minBitDepth = 4; {If 16 colours or more, use color icon}
VAR
myHoriz, myCheck: integerPtr; {Pointers to the low-memory global locations of icon position & checksum.}
err: Integer;
iconHandle: Handle; {Handle to 'ICN#' or 'cicn' resource}
gdev: GDHandle; {For use with the getGDevice call}
inColour: Boolean; {true='cicn' resource, else 'ICN#'}
oldPort, newPort: GrafPtr; {Entire GrafPort structure}
r: Rect; {Where to put the icon}
sysRec: SysEnvRec; {Record holding info about the machine being used}
response: Longint;
BEGIN
IF (Gestalt(gestaltSystemVersion,response)=noErr) & (response>=$0700) THEN BEGIN
myHoriz:= integerPtr(curApName + 32 - 4);
myCheck:= integerPtr(curApName + 32 - 2);
iconHandle:= nil;
inColour:= false;
err:= noErr;
{See whether we are running in colour or B&W.}
inColour:= (Gestalt(gestaltQuickDrawVersion, response) = noErr) & (LoWord(response) >= $0100);
GetPort(oldPort); {Save old GrafPort or CGrafPort for later restoring}
{Open a port so we can draw directly to screen. WindowMgrPort may not be initialised at this time!}
IF inColour THEN
newPort:= GrafPtr(NewPtr(SizeOf(CGrafPort)))
ELSE
newPort:= GrafPtr(NewPtr(SizeOf(GrafPort)));
err:= MemError;
IF err = noErr THEN BEGIN
IF inColour THEN
OpenCPort(CGrafPtr(newPort))
ELSE
OpenPort(newPort);
SetPort(newPort);
{Do a checksum on low memory to see if we're the 1st icon. If we are, then set the x location.}
IF BitXor(BitShift(myHoriz^, 1), checksumConst) <> myCheck^ THEN
myHoriz^:= firstX;
{Now plot the icon}
r:= newPort^.portRect;
r.top:= newPort^.portRect.bottom - (bottomMargin + iconHeight);
r.bottom:= newPort^.portRect.bottom - bottomMargin;
r.left:= myHoriz^;
r.right:= r.left + iconWidth;
err:= PlotIconID(r, 0, ttNone, iconID);
{Now offset the low memory location by defMoveXBy pixels}
myHoriz^:= myHoriz^ + defMoveXBy;
myCheck^:= BitXor(BitShift(myHoriz^, 1), checksumConst);
{Restore the port}
SetPort(oldPort);
IF inColour THEN
CloseCPort(CGrafPtr(newPort)) {Deallocate port structures}
ELSE
ClosePort(newPort);
DisposePtr(ptr(newPort));
END;
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION grafGetClip: rgnHandle;
{ Returns a handle to a COPY of the current clipping region, for later restoring by }
{ grafSetClip, below. }
{ Written by David Sinclair, 14 November 1994. }
VAR
oldClip: rgnHandle;
BEGIN
oldClip:= newRgn;
getClip(oldClip);
grafGetClip:= oldClip
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafSetClip (VAR oldClip: rgnHandle);
{ Restores the clipping region to the specified region; call when your drawing is }
{ finished. The region handle will be nil on return. }
{ Written by David Sinclair, 14 November 1994. }
BEGIN
IF oldClip <> NIL THEN
BEGIN
setClip(oldClip);
disposeRgn(oldClip);
oldClip:= NIL
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE drawBoxOrLineItem (theDialog: dialogPtr; theItem: integer; {}
frameOnly, useGrey: boolean);
{ Draws black or grey lines or boxes in the specified dialog. If grey is asked for, the }
{ line is true grey on colour machines. }
{ Written by David Sinclair, 27 January 1992; changed to do boxes, 30 August 1992; }
{ moved to genDialogs and modified to do both black and grey boxes or lines, }
{ 14 June 1994; modified to do both frames and filling, 25 July 1994. }
VAR
oldColour, greyColour: RGBColor;
pnState: penState;
itemType: integer;
itemHandle: handle;
itemBox: rect;
inColour: boolean;
BEGIN
getPenState(pnState);
inColour:= grafInColour;
IF inColour THEN
getForeColor(oldColour);
penNormal;
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
{$IFC application}
IF useGrey THEN
IF inColour THEN
BEGIN
greyColour.red:= $8000;
greyColour.green:= $8000;
greyColour.blue:= $8000;
RGBForeColor(greyColour)
END
ELSE
penPat(globals.qd.gray);
{$ENDC}
WITH itemBox DO
BEGIN
IF right > left + 1 THEN
right:= right - 1;
IF bottom > top + 1 THEN
bottom:= bottom - 1
END;
IF frameOnly THEN
frameRect(itemBox) { Draw the line or box }
ELSE
copyBits(theDialog^.portBits, theDialog^.portBits, itemBox, itemBox, srcCopy, NIL);
{ Grey out the contents of itemBox }
IF inColour THEN
RGBForeColor(oldColour);
setPenState(pnState)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawGreyLinesItem (theDialog: dialogPtr; theItem: integer);
{ Draws grey lines or boxes in the specified dialog. The line(s) are true grey on }
{ colour machines. }
{ Written by David Sinclair, 16 June 1994. }
BEGIN
drawBoxOrLineItem(theDialog, theItem, true, true)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawBlackLinesItem (theDialog: dialogPtr; theItem: integer);
{ Draws black lines or boxes in the specified dialog. }
{ Written by David Sinclair, 16 June 1994. }
BEGIN
drawBoxOrLineItem(theDialog, theItem, true, false)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawGreyoutItem (theDialog: dialogPtr; theItem: integer);
{ Greys out any other items within the itemıs rectangle; place a userItem over }
{ the items to grey out (dim), then call dlogSetDrawingProc passing this routine. }
{ Written by David Sinclair, 25 July 1994. }
BEGIN
drawBoxOrLineItem(theDialog, theItem, false, true)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawTextItem (theDialog: dialogPtr; theItem: integer; {}
theText: str255; justification: integer; colour: longint);
{ Draws the specified text in the specified userItem; pass one of the standard QuickDraw constants }
{ for colour (i.e. blackColor, redColor, etc), or the special constant greyColor to use grey, and one of }
{ the standard TextEdit constants for justification (i.e. teJustLeft, teJustCenter, or teJustRight). }
{ NOTE: do not install this routine as a drawing procedure, as it needs theText parameter: define a }
{ local routine to provide the appropriate values, and install that. }
{ Written by David Sinclair, 12 January 1995. }
VAR
hasColour: boolean;
oldColour, greyColour: RGBColor;
itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
hasColour:= grafHasColour;
IF hasColour THEN
BEGIN
GetForeColor(oldColour);
IF colour <> greyColor THEN
ForeColor(colour)
ELSE
BEGIN
greyColour.red:= $8000;
greyColour.green:= $8000;
greyColour.blue:= $8000;
RGBForeColor(greyColour)
END
END;
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF theText <> '' THEN
TETextBox(@theText[1], length(theText), itemBox, justification)
ELSE
EraseRect(itemBox);
IF hasColour THEN
RGBForeColor(oldColour);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawStyledTextItem (theDialog: DialogPtr; theItem: Integer; {}
theText: Str255; theFont, theSize: Integer; theStyle: Style; justification: Integer; {}
colour: Longint);
{ The same as grafDrawTextItem, above, except you can also specify a font, size and style for the text. }
{ NOTE: do not install this routine as a drawing procedure, as it needs the extra parameters: define }
{ a local routine to provide the appropriate values, and install that. }
{ Written by David Sinclair, 20 January 1996. }
VAR
oldFont: FontState;
BEGIN
grafGetFontState(theDialog, oldFont);
grafSetFontSizeStyle(theDialog, theFont, theSize, theStyle);
grafDrawTextItem(theDialog, theItem, theText, justification, colour);
grafSetFontState(theDialog, oldFont);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafDrawTitleItem (theDialog: dialogPtr; theItem: integer; {}
theText: str255; includeRedLines: boolean);
{ Draws the specified text in red, with two red lines belowpass titlePlusLines to }
{ include the lines, or titleWithoutLines to exclude them (e.g. if changing the title }
{ text, not updating the dialog). The userItem in question should be in the top-left }
{ corner of the dialog, and extend all the way across the dialog. The left and right }
{ margins should be off the visible area of the dialog. }
{ NOTE: do not install this routine as a drawing procedure, as it needs theText and }
{ includeRedLines parameters: define a local routine to provide the appropriate values, and }
{ install that. }
{ Written by David Sinclair, 7 May 1994; made into a genGraphics routine and made }
{ including the red lines optional, 14 November 1994. }
VAR
pnState: penState;
info: fontInfo;
itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
getPenState(pnState);
penNormal;
foreColor(redColor);
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
itemBox.left:= -1;
getFontInfo(info);
WITH itemBox, info DO
bottom:= top + ascent + descent + leading;
IF theText <> '' THEN
TETextBox(@theText[1], length(theText), itemBox, teJustLeft);
IF includeRedLines THEN
BEGIN
WITH itemBox DO
BEGIN
top:= bottom;
bottom:= top + 3
END;
frameRect(itemBox);
END;
foreColor(blackColor);
setPenState(pnState)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafUsePalatinoFont;
{ Sets the font of the current grafPort to Palatino, if possible, else Helvetica, or the }
{ default font if neither are available. }
{ Written by David Sinclair, 16 January 1992; made into a Generic Utilities routine, }
{ 2 August 1994; added TextSize call, 20 January 1996. }
CONST
stdSize = 12;
palatinoFont = 'Palatino';
helveticaFont = 'Helvetica';
VAR
fontNum: integer;
BEGIN
getFNum(palatinoFont, fontNum);
IF (fontNum = 0) | NOT realFont(fontNum, stdSize) THEN
BEGIN
getFNum(helveticaFont, fontNum);
IF (fontNum = 0) | NOT realFont(fontNum, stdSize) THEN
fontNum:= applFont
END;
TextFont(fontNum);
TextSize(stdSize);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE grafGetPortSize (yourPort: grafPtr; VAR portHeight, portWidth: integer);
{ Returns the height and width of the specified grafPort or cGrafPort. }
{ Written by David Sinclair, 910 January 1995. }
BEGIN
IF yourPort <> NIL THEN
WITH yourPort^.portRect DO
BEGIN
portHeight:= bottom;
portWidth:= right
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION GrafGetItemRect(theDialog: DialogPtr; theItem: Integer): Rect;
{Returns the rect of the specified item.}
{Written by David Sinclair, 19 April 1998.}
VAR
itemType: Integer;
itemHndl: Handle;
itemRect: Rect;
BEGIN
GetDialogItem(theDialog,theItem,itemType,itemHndl,itemRect);
GrafGetItemRect:= itemRect
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
END.