{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} { } { 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: 9­10 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 in‹so 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 } { that‹itı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 below‹pass 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, 9­10 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.