{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{
GENERIC DIALOGS
``````````````````````````
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: (Reverse chronology)
Start finish dates: Comments / changes:
27 October 2001 Public release as source code.
14 May 1999 Added the DlogInitialise routine.
19 April 1999 Added the DlogItemIsButton routine.
29 March 1998 Modified DlogFindKind to add a starting dialog parameter.
29 June 1997 Modified DlogCoerceEditable to allow dynamically changing editTexts to statTexts
or vice versa, even from a hit handler.
31 May 1997 Completed PowerMac-native support.
27 April 1997 Converted to CodeWarrior, and modified for PowerMac-native support.
23 March 1997 Added support for default-size offsets for modeless dialogs.
12, 9, 15, 22 Feb 1997 Added support for modeless dialogs.
16 February 1996 Added the dlogResizeDItems and dlogExpandingGeneva9 routines.
3 February 1996 Added dlogGetCurrentEditSelection.
30 January 1996 Added dlogSearchPrevDItems and support for Shift-Tabbing through edit items. Also
added the dlogDontManageOK routine.
29 January 1996 Added support for handling menu items while in a dialog [which I then disabled!].
20 January 1996 Added the dlogMoveDItems routine.
16 January 1996 Added the dlogLastEvent routine.
15 January 1996 Added the dlogUseFontSize routine.
* * *
}
{ OLD UNIT HISTORY: }
{ }
{ Version: Start - finish dates: Comments / changes: }
{ }
{ 1.0: 11 August 1990 Created and checked entire unit. }
{ 1.0.1: 14-15 Aug 1990 Revised routines and added dlogOSError, etc. }
{ 1.1: 19-21 Sep 1990 Added sub-filter proc ability & changed key }
{ equiv method to inteligent selection (cmd }
{ symbol or initial). }
{ 1.1.1: 22 September 1990 Fixed a few bugs here and there. }
{ 1.1.2: 30 September 1990 Changed the unit name to a genı prefix and }
{ routines to a dlogı prefix. }
{ 1.2: 2 October 1990 Added dlogStandardFile. }
{ 1.2.1: 17 November 90 Changed so it will only exitToShell if }
{ application on error. }
{ 1.2.2: 13 January 1991 Added the defaultID constant. }
{ 1.2.3: 14 March 1991 Fixed probs with dlogStandardFile by }
{ making it use globals & a dedicated }
{ filterProc & added the compile-time }
{ variable standardFileı to exclude if }
{ not needed. }
{ 1.3: 21 March 1991 Added the working message routines. }
{ 1.4: 22 March 1991 Moved dlogReallyBadError to genDebug. }
{ 1.4.1: 12 April 1991 Allowed dismissal of buttonless dialog with }
{ a keypress. }
{ 1.5: 22 September 1991 Added support for strings below the }
{ progress thingie. }
{ 1.6: 26 October 1991 Added dlogSFHook patch to allow }
{ dlogHookProcs. }
{ 1.6.1: 27 October 1991 Added more SystemTasks to the progress }
{ dialogs. }
{ 1.7: 28 October 1991 Added dlogSFFileFilter to allow file filter }
{ procs. }
{ 1.7.1: 2 November 1991 Added option of passing ignoreProgessBar }
{ to the dlogChangeTextMessage etc routines. }
{ 1.8: 8 November 1991 Moved the progress dialog routines into a }
{ new unit. }
{ 1.9: 12 November 1991 Added support for the menubar under }
{ System 7. }
{ 1.10: 11 December 1991 Added the dlogExpandingText procedure }
{ and changed dlogOSError to use a dialog }
{ rather than an alert. Also added the }
{ dlogDoErrorSound procedure. }
{ 1.10.1: 1213 Dec 1991 Debugging of dlogExpandingText. }
{ 1.10.2: 13 December 1991 Now only shows an error number in }
{ dlogOSError if a text message is unavailable. }
{ 1.10.3: 15 December 1991 Stopped dlogDialog from clickingı on }
{ inactive buttons with the keyboard. }
{ 2.0: 20 December 1991 First public release, in library form. }
{ 2.1: 1213 Jan 1992 Added support for automatic plural }
{ handling. }
{ 2.1.1: 21 January 1992 Added the userMsg constant for use with }
{ dlogOSError. }
{ 2.2: 20 April 1992 Added the dlogUserError procedure. }
{ 2.3: 26 April 1992 Changed the way buttons hilight from the }
{ keyboard to the standard method (i.e. }
{ highlights then unhilites, rather than just }
{ hilighting and removing the dialog). }
{ 2.4: 26 June 1992 Made the bold outline routine publically }
{ available, and increased the speed of }
{ drawing dialog contents. }
{ 2.4.1: 2 July 1992 Fixed NIL deref bug in findEquivButton }
{ if no match is found. }
{ 2.5: 10 July 1992 Added auto-centring of dialogs if building }
{ as an application. }
{ 2.6: 16 Sep 1992 Added the dlogUserWarning procedure }
{ 2.7: 22 May 1993 Added hookFirstCall in dlogDialog. }
{ 2.8: 28 August 1993 Added dlogNoError and dlogIgnoreError. }
{ 2.9: 4 June 1994 Added dlogItemIsCtrl, dlogSetControl, }
{ dlogSetDrawingProc & dlogChangeCtrlTitle. }
{ 2.10: 6 June 1994 Added dlogInitAnimatedIcons, }
{ dlogNextIconID, and dlogInitialIconID. }
{ 2.11: 1416 June 1994 Added the dlogDrawGreyLinesItem, }
{ dlogDrawBlackLinesItem, dlogGetItemText, }
{ dlogSetItemText, dlogInColour and }
{ dlogHiliteButton routines. }
{ 2.11.1: 25 June 1994 Modified dlogDialog to save and restore the }
{ previous ParamText strings, to fix problems }
{ when nesting dialogs, and dlogOSError to }
{ only append a period if there isnıt already a }
{ valid sentence terminator. }
{ 2.12: 23 July 1994 Added dlogProcDialog, dlogSimpleDialog, }
{ dlogInfoDialog, dlogGetCurrentEditItem, }
{ and dlogSetDefaultButton; we now have }
{ default button flipping at last! Also added }
{ the dlogResetItemStatus, dlogSetItemStatus, }
{ and dlogKeepOKDimmed routines and }
{ related support code to allow automatic }
{ management of editText length and OK }
{ button dimming when certain editText }
{ items are null. }
{ 2.12.1 5 July 1994 Added erasing to dlogDrawBoldOutline. }
{ 2.13: 6 July 1994 Added the dlogOldError procedure. }
{ 2.14: 6 July 1994 Added the itemColonsIllegal option to }
{ dlogSetItemStatus to filter out colons from }
{ filenames etc. }
{ 2.15: 7 July 1994 Added the dlogParamDialog routine. }
{ 2.16: 8 July 1994 Added the itemDigitsOnly option to }
{ dlogSetItemStatus to only accept entry of }
{ digits in editText fields. }
{ 2.16.1: 12 July 1994 dlogSetItemText now only changes the text }
{ if it is different from what is already there. }
{ 2.17: 13 July 1994 Added the dlogOKIsActive, }
{ dlogToggleCheckbox, dlogSetupRadioGroup, }
{ and dlogHandleRadioGroup routines. }
{ 2.18: 18 July 1994 Added the dlogEllipsisText routine. }
{ 2.19: 20 July 1994 Added the ability to have no default button }
{ (by passing zero to dlogSetDefaultButton). }
{ 2.19.1: 21 July 1994 Added menuEquivs compile-time variable }
{ to prevent bus errors when the app doesnıt }
{ have any menus. }
{ 2.20: 24 July 1994 Added the dlogEllipsisCtrlTitle routine, }
{ and modified dlogChangeCtrlTitle so that }
{ it only changes the title if the new one is }
{ different from the existing one. }
{ 2.21: 25 July 1994 Added the dlogCoerceEditable and }
{ dlogDrawGreyoutItem routines. }
{ 2.21.1: 28 July 1994 Fixed dlogResetItemStatus; it wasnıt initing }
{ the digitsOnly array. Also made sure that }
{ the fore colour is set to black in }
{ dlogDrawBoldOutline, so that I can use a }
{ different fore colour for statText etc items. }
{ 2.22: 2 August 1994 Moved drawing-related routines to the }
{ genGraphics unit, in an attempt to cut down }
{ the size of this unit (previously 120k!). }
{ 2.23: 11 August 1994 Added dlogUserErrStr & dlogUserWarnStr. }
{ 2.23.1: 13 October 1994 Added more sentence terminators. }
{ 2.24: 1011 Nov 1994 Tweaked a number of routines, including }
{ dlogSetItemStatus, dlogDrawBoldOutline, }
{ added dlogBoldOutlineMethod, and moved }
{ the old standard file routines into a separate }
{ unit, at long last! }
{ 2.25: 11 November 94 Changed filter infomation storage scheme }
{ to piggyback on the DialogRecord instead of }
{ storing it in a handle, as there was no real }
{ way to find out whether a given dialog was }
{ created with or without filter info (e.g. }
{ standard file dialogs). }
{ 2.26: 15 November 94 Added the dlogAutoStatus routine and }
{ associated support. }
{ 2.27: 2324 Nov 1994 Added the itemMenuMetasIllegal and }
{ itemBlankShownZero item status options. }
{ 2.28: 29 November 94 Added the itemDecimalsOnly status option. }
{ 2.29: 12 December 1994 Modified the dlogKeepOKDimmed routine }
{ to allow enabling or disabling of the feature. }
{ 2.29.1: 18 December 1994 The call to the DABeeper routine was }
{ crashing some Macs and not working on }
{ others, so it has been replaced with a }
{ simple SysBeep call. }
{ 2.29.2: 22 December 1994 Fixed a problem with period detection in }
{ the itemDecimalsOnly status option. }
{ 2.30: 12 January 1995 Added the dlogGetCtrlItem function. }
{ 2.31: 17 January 1995 Added the itemZeroIllegal status option. }
{ 2.32: 20 January 1995 Added the automatic notification features }
{ to dlogDialog, and added the }
{ dlogSetNotificationSnds, }
{ dlogNotifyForAttention, }
{ dlogNotifyOfCompletion and }
{ dlogHandleBoolRadioGroup routines. }
{ 2.33: 2 October 1995 Added dlogDontExportClipboard and fixed }
{ inconsistency in dlogHiliteButton. }
{ 2.34: 14 October 1995 Modified dlogHiliteButton so the bold }
{ outline is dimmed instead of toggled if }
{ Cancel is missing or already dimmed. }
{ * * * }
{ N.B: Most of my units require the compile-time variables applicationı }
{ and debugı, both of which are booleans. }
{ Iff your program has menus, you should also define the compile- }
{ time variable menuEquivsı (the value isnıt important). }
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
UNIT genDialogs;
INTERFACE
USES
genToolbox, genResources, genNumerics, genStrings;
CONST
itemNotFound = 0; { Returned by dlogSearchDItems to indicate just that }
zerothItem = 0; { Used with dlogSearchDItems when assigning result to the same }
{ variable as is used in the parameters (which is incremented) }
firstItem = 1; { Used with dlogSearchDItems to start at the first dialog item }
defaultID = 0; { Used to specify the default dialog ID for dlogStandardFile }
errorStringsID = 600; { ID numbers of the STR# resources containing the error strings }
moreErrStrsID = 601; { used by the genericErrorHandler }
miscDlogStrsID = 610; { Miscelaneous strings (in a STR#) used by the handlers }
unknownErrorIndex = 1; { Index number of the string for when we canıt find a }
{ specific error message; used by dlogOSError }
accessingIndex = 2; { Index number of the string accessingı; used by dlogOSError }
openingIndex = 3; { Index number of the string openingı; used by dlogOSError }
savingIndex = 4; { Index number of the string savingı; used by dlogOSError }
readingIndex = 5; { Index number of the string readingı; used by dlogOSError }
writingIndex = 6; { Index number of the string writingı; used by dlogOSError }
whileDoingIndex = 9; { Index number of the string whileı; used by dlogOSError }
idNoIndex = 10; { Index number of the string ID # = ı; used by dlogOSError }
quittingStrIndex = 12; { Index number of the string quittingı; used by dlogSaveChanges }
closingStrIndex = 13; { Index number of the string closingı; used by dlogSaveChanges }
osErrorDialogID = 600; { ID number of the DLOG resource used by dlogOSError }
userMsg = 1; { Pass this to dlogOSError when using your own messages }
osWarningDialogID = 610; { ID number of the user warning DLOG resource }
hookNothing = 0; {Matches no event; use to coerce an item hit to do nothing }
{ Note: hookNull is defined in the CTBUtilities unit; it equals 100 }
hookSetupInvisible = -1; { Passed to the dialog hook routine before the dialog has been shown }
hookSetupVisible = -2; { Passed to the dialog hook routine after the dialog has been shown and drawn }
hookFirstCall = hookSetupVisible; { Old constant, for compatiblity }
{ The following item hit hooks are only passed to modeless dialogs: }
hookQuit = -3; { The user chose File:Quit; only used for dlogModelessMenu to send a }
{ hookClose item hit to each open window }
hookClose = -4; { The user clicked in the Close box, chose File:Close, or File:Quit }
hookSave = -10; { The user chose File:Save }
hookSaveAs = -11; { The user chose File:Save As }
hookRevert = -12; { The user chose File:Revert to Saved }
hookCut = -20; { The user chose Edit:Cut }
hookCopy = -21; { The user chose Edit:Copy }
hookPaste = -22; { The user chose Edit:Paste}
hookClear = -23; { The user chose Edit:Clear }
hookSelectAll = -24; { The user chose Edit:Select All }
hookKeyReturn = -100; { The user pressed the Return key }
hookKeyEnter = -101; { The user pressed the Enter key }
hookKeyTab = -102; { The user pressed the Tab key }
hookKeyShiftTab = -103; { The user pressed the Shift-Tab key }
hookKeyHelp = -104; { The user pressed the Help key }
hookKeyFwdDel = -105; { The user pressed the Forward Delete key }
hookKeyHome = -106; { The user pressed the Home key }
hookKeyEnd = -107; { The user pressed the End key }
hookKeyPageUp = -108; { The user pressed the Page Up key }
hookKeyPageDown = -109; { The user pressed the Page Down key }
hookPosition = -200; { Not passed by the dlog routines; pass to your resize routine to position the wind }
hookGrow = -201; { The window was resized via grow box }
hookZoomIn = -202; { The window was zoomed in }
hookZoomOut = -203; { The window was zoomed out }
hookActivate = -300; { The window has just been activated }
hookDeactivate = -301; { The window has just been deactivated }
foreignKind = 0; { Returned by dlogGetKind if the window wasnıt created by this unit }
defaultKind = -1; { Returned if the window kind hasnıt been changed from the default }
modalKind = -99; { Returned if the window is in fact a modal dialog }
maxStatusItems = 63; { Maximum number of dialog items supported by }
{ dlogSetItemStatus (must be a multiple of 32 minus 1) }
maxStatusAsLongs = (maxStatusItems + 1) DIV 32;
itemCurrentLength = -1; { Used in dlogSetItemStatus if you want to set the options }
{ without changing the text length value }
itemDefaultLength = 255; { Used in dlogSetItemStatus for the default text length }
itemCurrentOptions = -1; { Used in dlogSetItemStatus if you want to set the text }
{ length value without changing the options }
itemDefaultOptions = 0; { Used in dlogSetItemStatus for the default options }
{ The following options can be added to have a combination of features for the item, }
{ e.g. itemDimOKIfNull + itemMultiLineEdit: }
itemDimOKIfNull = 1; { Dim the OK button if the editText item contents is null }
itemMultiLineEdit = 2; { Return will go to a new line instead of OKing the dialog }
itemColonsIllegal = 4; { Colons (³:²) will be filtered out; useful for filename entry }
itemMenuMetasIllegal = 8; { Meta-characters for menu items will be filtered out }
itemDecimalsOnly = 16; { Only digits (0..9) and one decimal point (.) will be allowed }
itemDigitsOnly = 32; { Only digits (0..9) will be allowed }
itemBlankShownZero = 64; { If the text is null, zero will be substituted instead }
itemZeroIllegal = 128; { Zero and null values will be replaced with the value 1 }
itemFilename = itemDimOKIfNull + itemColonsIllegal; { The standard options for filenames }
activate = true; { Used in dlogSetControl for the controlıs value }
deactivate = false;
toggleDefaults = true; { Used in dlogHiliteButton to specify whether to toggle the }
dimInSynch = false; { bold outline between the OK and Cancel buttons or dim it }
letMeHandleEdit = true; { Used in dlogInstallMenuHandler to specify whether to override the }
autoHandleEdit = false; { built-in Edit menu handling or not }
notificationIconID = 128; { ID of the small icon family used during notification }
notifyWithSilence = Chr(1); { Used in dlogSetNotificationSnds and dlogNotifyOfCompletion }
notifyWithBeep = ''; { to indicate a silence or a beep, respectively }
quitAppErr = 9702; { Returned by dlogEventLoop when the application should quit }
uppSetupDialogProcInfo = $000000C0; { PROCEDURE (4 byte param); }
uppItemHitProcInfo = $000003C0; { PROCEDURE (4 byte param, 4 byte param); (4-byte second param as it is a VAR) }
TYPE
AppearanceVersionType = (AppearanceNA,Appearance10,Appearance11); {Appearance not available, version 1.0 - 1.0.2, or version 1.1}
stdPats = (whitePat, ltGrayPat, grayPat, dkGrayPat, blackPat);
boldOutlineType = (boldActive, boldDim, boldErase);
ItemRange = SET OF 1..99;
SetupDialogProcPtr = ProcPtr; { PROCEDURE MySetupDialog(theDialog: DialogPtr); }
ItemHitProcPtr = ProcPtr; { PROCEDURE MyItemHit(theDialog: DialogPtr; VAR itemHit: Integer); }
SetupDialogUPP = UniversalProcPtr;
ItemHitUPP = UniversalProcPtr;
{$IFC application}
VAR
gAppearanceVersion: AppearanceVersionType;
inBackground: boolean; { If true, the application is in the background }
notifyErrorSound: str63; { Sound to play when an error dialog is displayed }
notifyAttentionSound: str63; { Sound to play when any other kind of dialog is displayed, }
{ iff the application is in the background }
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogInitialise;
FUNCTION DlogGetKind (theDialog: DialogPtr): Integer;
PROCEDURE DlogSetKind (theDialog: DialogPtr; kind: Integer);
FUNCTION DlogFindKind (theDialog: DialogPtr; kind: Integer): DialogPtr;
FUNCTION DlogKindAlreadyOpen (kind: Integer; select: Boolean): Boolean;
PROCEDURE DlogSetFirstList(theDialog: DialogPtr; firstListHdl: ListHandle);
FUNCTION DlogGetFirstList(theDialog: DialogPtr): ListHandle;
PROCEDURE DlogSetCurrentList(theDialog: DialogPtr; currentListHdl: ListHandle);
FUNCTION DlogGetCurrentList(theDialog: DialogPtr): ListHandle;
FUNCTION dlogCountDItems (theDialog: dialogPtr): integer;
FUNCTION dlogSearchDItems (theDialog: dialogPtr; startItem, theType: integer; {}
VAR itemHandle: handle; VAR itemBox: rect): integer;
FUNCTION dlogSearchPrevDItems (theDialog: DialogPtr; startItem, theType: Integer; {}
VAR itemHandle: Handle; VAR itemBox: Rect): Integer;
PROCEDURE dlogMoveDItems (theDialog: DialogPtr; theItems: ItemRange; deltaH, deltaV: Integer);
PROCEDURE dlogResizeDItems (theDialog: DialogPtr; theItems: ItemRange; deltaH, deltaV: Integer);
PROCEDURE dlogResetItemStatus (theDialog: dialogPtr; fromItem: integer);
PROCEDURE dlogSetItemStatus (theDialog: dialogPtr; theItem, {}
maximumLength, options: integer);
PROCEDURE dlogAutoStatus (theDialog: dialogPtr; auto: boolean);
PROCEDURE dlogDontManageOK (theDialog: DialogPtr);
PROCEDURE dlogKeepOKDimmed (theDialog: dialogPtr; keepDimmed: boolean);
FUNCTION dlogOKIsActive (theDialog: dialogPtr; ignoreKeepDimmed: boolean): boolean;
FUNCTION dlogItemIsCtrl (itemType: integer; itemHandle: handle): boolean;
FUNCTION DlogItemIsButton (theDialog: DialogPtr; theItem: Integer): Boolean;
FUNCTION dlogGetCtrlItem (theDialog: dialogPtr; theItem: integer; {}
VAR itemHandle: controlHandle): boolean;
PROCEDURE dlogSetControl (theDialog: dialogPtr; theItem: integer; {}
value, activateIt: boolean);
FUNCTION dlogToggleCheckbox (theDialog: dialogPtr; theItem: integer): boolean;
PROCEDURE dlogSetupRadioGroup (theDialog: dialogPtr; firstItem, {}
noOfItems: integer; currentValue: UNIV signedByte);
PROCEDURE dlogHandleRadioGroup (theDialog: dialogPtr; itemHit, firstItem, {}
noOfItems: integer; VAR results: UNIV signedByte);
FUNCTION dlogHandleBoolRadioGroup (theDialog: dialogPtr; itemHit, firstItem: integer): boolean;
PROCEDURE dlogBoldOutlineMethod (theDialog: dialogPtr; {}
toggleDefaultButtons: boolean);
PROCEDURE dlogDrawBoldOutline (theDialog: dialogPtr; theItem: integer; {}
draw: boldOutlineType);
PROCEDURE dlogSetDefaultButton (theDialog: dialogPtr; theItem: integer);
PROCEDURE dlogHiliteButton (theDialog: dialogPtr; theItem: integer; {}
activateIt: boolean);
FUNCTION dlogGetCurrentEditItem (theDialog: dialogPtr): integer;
PROCEDURE dlogGetCurrentEditSelection (theDialog: DialogPtr; VAR selStart, selEnd: Integer);
PROCEDURE DlogCoerceEditable (theDialog: DialogPtr; theItem: Integer; toEditText, allowStatHits: Boolean);
FUNCTION dlogGetItemText (theDialog: dialogPtr; theItem: integer): str255;
PROCEDURE dlogSetItemText (theDialog: dialogPtr; theItem: integer; theText: str255);
PROCEDURE dlogEllipsisText (theDialog: dialogPtr; theItem: integer; {}
leftText, rightText: str255);
PROCEDURE DlogSetDrawingProc (theDialog: DialogPtr; theItem: Integer; theProcedure: UserItemProcPtr);
PROCEDURE dlogChangeCtrlTitle (theDialog: dialogPtr; theItem: integer; {}
newTitle: str255);
PROCEDURE dlogEllipsisCtrlTitle (theDialog: dialogPtr; theItem: integer; {}
leftTitle, rightTitle: str255);
PROCEDURE dlogDontExportClipboard (theDialog: dialogPtr);
PROCEDURE dlogUseFontSize (theDialog: DialogPtr; theFont, theSize: Integer);
PROCEDURE dlogSetNotificationSnds (soundForErrors, soundForAttention: str255);
PROCEDURE dlogNotifyForAttention;
PROCEDURE dlogNotifyOfCompletion (soundForCompletion: str255);
FUNCTION dlogLastEvent (theDialog: DialogPtr): EventRecord;
PROCEDURE dlogTrackCursor (theDialog: DialogPtr);
PROCEDURE dlogSetTrackCursor (theDialog: DialogPtr; trackCursor: Boolean);
{ PROCEDURE dlogInstallMenuHandler (theDialog: dialogPtr; menuHandlerProc: ProcPtr; {]}
{ overrideEdit: Boolean);}
PROCEDURE dlogCentreWindow (theDialog: dialogPtr);
FUNCTION DlogDialog (dialogID: Integer; dlogSetupProc: SetupDialogProcPtr; eventFilterProc: ModalFilterProcPtr;
itemHitFilterProc: ItemHitProcPtr; str0, str1, str2, str3: Str255): Integer;
FUNCTION DlogProcDialog (dialogID: Integer; dlogSetupProc: SetupDialogProcPtr; eventFilterProc: ModalFilterProcPtr;
itemHitFilterProc: ItemHitProcPtr): Integer;
PROCEDURE dlogParamDialog (dialogID: integer; str0, str1, str2, str3: str255);
FUNCTION dlogSimpleDialog (dialogID: integer): integer;
PROCEDURE dlogInfoDialog (dialogID: integer);
PROCEDURE dlogInit;
FUNCTION dlogGetDesktopSize: Point;
PROCEDURE dlogGetPosAndSize (theDialog: DialogPtr; VAR thePos: Point; {}
VAR theWidth, theHeight: Integer);
FUNCTION dlogGetPosition (theDialog: DialogPtr): Point;
FUNCTION DlogModelessNew (dialogID, kind: Integer; eventFilterProc: ModalFilterProcPtr; itemHitFilterProc: ItemHitProcPtr;
sizeOfVars: Size; VAR vars: UNIV Ptr): DialogPtr;
PROCEDURE DlogModelessShow (theDialog: DialogPtr);
PROCEDURE dlogModelessVars (theDialog: DialogPtr; VAR vars: UNIV Ptr);
PROCEDURE dlogModelessAction (theDialog: DialogPtr; itemHit: Integer);
PROCEDURE dlogModelessMenu (itemHit: Integer);
PROCEDURE dlogModelessPosition (theDialog: DialogPtr; thePosition: Point);
FUNCTION dlogModelessStartResize (theDialog: DialogPtr; operation: Integer; {}
constrainH, constrainV: Boolean; thePosition: Point; VAR deltaH, deltaV: Integer): Boolean;
PROCEDURE dlogModelessFinishResize (theDialog: DialogPtr);
PROCEDURE HandleModelessActivate (theDialog: DialogPtr; activating: Boolean);
FUNCTION HandleModelessEvent (VAR theEvent: EventRecord): Boolean;
FUNCTION dlogEventLoop (VAR menuID, menuItem: Integer): OSErr;
{ FUNCTION dlogAlert (alertID: integer; str0, str1, str2, str3: str255): integer; }
PROCEDURE dlogExpandingText (theDialog: dialogPtr);
PROCEDURE dlogExpandingGeneva9 (theDialog: DialogPtr);
FUNCTION dlogOSError (errorNo: osErr; message, process, filename: str255): boolean;
FUNCTION dlogNoError (error: osErr): boolean;
PROCEDURE dlogReportError (error: osErr);
PROCEDURE dlogIgnoreError (error: osErr);
PROCEDURE dlogOldError (result: osErr; VAR error: osErr);
PROCEDURE dlogUserError (message: str255);
PROCEDURE dlogUserErrStr (stringID, stringIndex: integer);
PROCEDURE dlogUserWarning (message: str255);
PROCEDURE dlogUserWarnStr (stringID, stringIndex: integer);
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
IMPLEMENTATION
CONST
DAStringsGlob = $AA0;
TYPE
ItemBoolArray = RECORD
CASE Boolean OF
false: (
asBool: PACKED ARRAY[0..maxStatusItems] OF Boolean { Bit 0 is represents all }
);
true: (
asLong: PACKED ARRAY[1..maxStatusAsLongs] OF Longint
)
END;
ItemByteArray = PACKED ARRAY[0..maxStatusItems] OF Byte;
{ Yes, bytes are evil 2-byte variables for some unknown reason, but }
{ this is a packed array, so itıs okay. It has to be a byte to avoid }
{ problems in the dlogSetItemStatus routine. }
FilterDialogRec = RECORD
dialog: DialogRecord;
validity: OSType;
kind: Integer;
eventFilterUPP: ModalFilterUPP;
itemHitFilterUPP: ItemHitUPP;
sizeOfVars: Size;
vars: Ptr;
minWindowSize: Point;
firstListHdl: ListHandle;
currentListHdl: ListHandle;
lastEvent: EventRecord;
boldOutline: BoldOutlineType;
toggleOutline: Boolean;
buttonless: Boolean;
exportTEScrap: Boolean;
overrideEditMenu: Boolean;
statusInited: Boolean;
autoStatus: Boolean;
OKActive: Boolean;
keepOKDimmed: Boolean;
dontManageOK: Boolean;
trackCursor: Boolean;
growable: Boolean;
unused: Boolean;
dimOKIfEditNull: ItemBoolArray;
dimOK: ItemBoolArray;
multiLineEdit: ItemBoolArray;
colonsIllegal: ItemBoolArray;
menuMetasIllegal: ItemBoolArray;
digitsOnly: ItemBoolArray;
decimalsOnly: ItemBoolArray;
blankShownZero: ItemBoolArray;
zeroIllegal: ItemBoolArray;
maxLength: ItemByteArray;
END;
FilterPeek = ^FilterDialogRec;
DAStringsArray = ARRAY[0..3] OF StringHandle;
DAStringsPtr = ^DAStringsArray;
CONST
normalDialogSize = SizeOf(DialogRecord);
filterDialogSize = SizeOf(FilterDialogRec);
validFilterInfo = 'Filt';
invalidFilterInfo = 'Err!';
VAR
gOffsetPos: Point;
gQuittingApp: Boolean;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION NewItemHitProc(userRoutine: ItemHitProcPtr): ItemHitUPP;
{Returns a new UPP for a dialog item hit routine.}
{Written by David Sinclair, 27 April 1997.}
BEGIN
NewItemHitProc:= NewRoutineDescriptor(userRoutine,uppItemHitProcInfo,GetCurrentISA)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE CallSetupDialogProc(theDialog: DialogPtr; userRoutine: ProcPtr);
{Calls the dialog setup routine; a ProcPtr is used as this is only called once, so thereıs no need to store the UPP.}
{Written by David Sinclair, 31 May 1997.}
{$IFC GENERATINGPOWERPC}
VAR
theUPP: UniversalProcPtr;
ignored: Longint;
BEGIN
theUPP:= NewRoutineDescriptor(userRoutine,uppSetupDialogProcInfo,GetCurrentISA);
ignored:= CallUniversalProc(theUPP,uppSetupDialogProcInfo,theDialog);
DisposeRoutineDescriptor(theUPP);
END;
{$ELSEC}
INLINE
$205f, { movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode }
$4e90;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE CallItemHitProc(theDialog: DialogPtr; VAR itemHit: Integer; userRoutineUPP: ItemHitUPP);
{Calls the dialog item hit routine.}
{Written by David Sinclair, 31 May 1997.}
{$IFC GENERATINGPOWERPC}
VAR
ignored: Longint;
BEGIN
ignored:= CallUniversalProc(UniversalProcPtr(userRoutineUPP),uppItemHitProcInfo,theDialog,@itemHit);
END;
{$ELSEC}
INLINE
$205f, { movea.l (a7)+,a0 ; (a0) is a ptr to string, 4(a0) is mode }
$4e90;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogInitialise;
{Initialises the genDialog globals. Only call this if you want to use the Appearance Manager. Sets gAppearanceVersion
to AppearanceNA if it is not available, Appearance10 if version 1.0 - 1.0.2 is available, or Appearance11 if
version 1.1 is available.}
{Written by David Sinclair, 14 May 1999.}
VAR
response: Longint;
BEGIN
(*
gAppearanceVersion:= AppearanceVersionType(Ord(Gestalt(gestaltAppearanceAttr,response)=noErr));
IF (gAppearanceVersion > AppearanceNA) & (Gestalt(gestaltAppearanceVersion,response)=noErr) THEN BEGIN
IF response>=$0110 THEN
gAppearanceVersion:= Appearance11;
END;
*)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE InitFilterInfo (theDialog: dialogPtr; theEventFilterProc: ModalFilterProcPtr; theItemHitFilterProc: ItemHitProcPtr; varsSize: Size);
{ Procedure to initialise the filter information for the specified dialog. }
{ Written by David Sinclair, 21 September 1990; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994; }
{ added itemHitFilterProc, 2 February 1997; added varsSize, 9 February 1997;
{ added UPP support, 31 May 1997; added first and current lists, 13 September 1997. }
VAR
itemHandle: handle;
itemBox: rect;
BEGIN
IF theDialog <> NIL THEN
IF GetPtrSize(ptr(theDialog)) = filterDialogSize THEN
WITH FilterPeek(theDialog)^ DO
BEGIN
validity:= validFilterInfo; { Fill in the filter info record }
kind:= modalKind;
IF theEventFilterProc<>Nil THEN eventFilterUPP:= NewModalFilterProc(theEventFilterProc) ELSE eventFilterUPP:= Nil;
IF theItemHitFilterProc<>Nil THEN itemHitFilterUPP:= NewItemHitProc(theItemHitFilterProc) ELSE itemHitFilterUPP:= Nil;
sizeOfVars:= varsSize;
IF varsSize > 0 THEN vars:= NewPtr(varsSize) ELSE vars:= NIL;
IF (vars = NIL) | (GetPtrSize(vars) = 0) THEN sizeOfVars:= 0 ELSE numZeroBlock(vars, varsSize);
minWindowSize:= theDialog^.portRect.botRight;
firstListHdl:= Nil;
currentListHdl:= Nil;
lastEvent.what:= nullEvent;
boldOutline:= boldActive;
toggleOutline:= true;
buttonless:= dlogSearchDItems(theDialog, firstItem, ctrlItem + btnCtrl, itemHandle, itemBox) = itemNotFound;
exportTEScrap:= true;
statusInited:= false;
autoStatus:= true;
trackCursor:= true;
growable:= false;
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE resetItemStatus (theDialog: dialogPtr; fromItem: integer);
{ Resets the item status and max length information for all dialog items from }
{ the specified one onwards; pass zero to reset them all. Only called from }
{ validFilterDialog. }
{ Written by David Sinclair, 23 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
VAR
index: integer;
BEGIN
WITH filterPeek(theDialog)^ DO
BEGIN
IF NOT statusInited | (fromItem < 0) THEN
BEGIN
fromItem:= 0;
OKActive:= true;
keepOKDimmed:= false;
dontManageOK:= false;
END;
IF fromItem <= maxStatusItems THEN
FOR index:= fromItem TO maxStatusItems DO
BEGIN
dimOKIfEditNull.asBool[index]:= false;
dimOK.asBool[index]:= false;
multiLineEdit.asBool[index]:= false;
colonsIllegal.asBool[index]:= false;
menuMetasIllegal.asBool[index]:= false;
digitsOnly.asBool[index]:= false;
decimalsOnly.asBool[index]:= false;
blankShownZero.asBool[index]:= false;
zeroIllegal.asBool[index]:= false;
maxLength[index]:= 255;
END;
statusInited:= true
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION ValidFilterDialog (theDialog: DialogPtr; needStatusInfo: Boolean): Boolean;
{ Returns true if the dialog contains valid filter information; if it returns false, you }
{ must not attempt to modify any filter info as it is just a normal dialog (this could }
{ happen for standard file dialogs or progress dialogs, for example). If needStatusInfo }
{ is true, the status information is also checked, and initialised if not already. If true is }
{ returned, the port is guaranteed to be set to theDialog. }
{ Written by David Sinclair, 11 November 1994. }
VAR
valid: Boolean;
BEGIN
valid:= false;
IF theDialog <> NIL THEN
IF GetPtrSize(ptr(theDialog)) = filterDialogSize THEN
IF FilterPeek(theDialog)^.validity = validFilterInfo THEN
BEGIN
valid:= true;
SetPort(theDialog);
IF needStatusInfo & NOT FilterPeek(theDialog)^.statusInited THEN
ResetItemStatus(theDialog, 0)
END;
ValidFilterDialog:= valid
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogGetKind (theDialog: DialogPtr): Integer;
{Returns the kind of dialog; foreignKind for windows not created by the this unit, modalKind for modal dialogs or
defaultKind for modeless dialogs that havenıt previously called dlogSetKind, or whatever value was passed to
dlogSetKind.}
{Written by David Sinclair, 2 February 1997.}
VAR
kind: Integer;
BEGIN
IF ValidFilterDialog(theDialog, false) THEN
kind:= FilterPeek(theDialog)^.kind
ELSE
kind:= foreignKind;
DlogGetKind:= kind
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogSetKind (theDialog: DialogPtr; kind: Integer);
{Sets the kind value for the dialog. This can be used to identify different kinds of windows when activating menus,
etc. Pass a value in the range 1..MaxInt.}
{Written by David Sinclair, 2 February 1997.}
BEGIN
IF ValidFilterDialog(theDialog, false) THEN
FilterPeek(theDialog)^.kind:= kind;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogFindKind (theDialog: DialogPtr; kind: Integer): DialogPtr;
{Finds the next dialog of the specified kind after the given dialog (or from the first if theDialog is nil). Returns the
dialog pointer or nil if there are no more windows of that kind open.}
{Written by David Sinclair, 15 February 1997; added theDialog parameter, 29 March 1998.}
VAR
found: Boolean;
BEGIN
found:= false;
IF theDialog<>nil THEN
theDialog:= DialogPtr(WindowPeek(theDialog)^.nextWindow)
ELSE
theDialog:= FrontWindow;
WHILE (theDialog <> nil) & NOT found DO BEGIN
IF ValidFilterDialog(theDialog, false) & (FilterPeek(theDialog)^.kind = kind) THEN
found:= true
ELSE
theDialog:= DialogPtr(WindowPeek(theDialog)^.nextWindow)
END;
DlogFindKind:= theDialog
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogKindAlreadyOpen (kind: Integer; select: Boolean): Boolean;
{Call this to determine whether there is a dialog of the specified kind open already, or not. If there is one, and select
is true, it is selected. Useful when only one instance of a modeless dialog is allowed; pass true for select, and
only open a new one if this returns false; itıll then open a new one if one isnıt already open, otherwise itıll select
the old one.}
{Written by David Sinclair, 22 February 1997.}
VAR
theDialog: DialogPtr;
found: Boolean;
BEGIN
theDialog:= DlogFindKind(nil, kind);
found:= (theDialog <> nil);
IF found & select THEN BEGIN
SelectWindow(theDialog);
HiliteMenu(0);
END;
DlogKindAlreadyOpen:= found
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogSetFirstList(theDialog: DialogPtr; firstListHdl: ListHandle);
{Stores a handle to the dialogıs first list in the dialogıs info. Only the List Suite should
call this routine.}
{Written by David Sinclair, 13 September 1997.}
BEGIN
IF ValidFilterDialog(theDialog,false) THEN
FilterPeek(theDialog)^.firstListHdl:= firstListHdl
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogGetFirstList(theDialog: DialogPtr): ListHandle;
{Returns a handle to the dialogıs first list, from the specified dialogıs info, or Nil if
the dialog doesnıt contain valid data, or no list has been previously added. Only the
List Suite should call this routine.}
{Written by David Sinclair, 13 September 1997.}
BEGIN
IF ValidFilterDialog(theDialog,false) THEN
DlogGetFirstList:= FilterPeek(theDialog)^.firstListHdl
ELSE
DlogGetFirstList:= Nil
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogSetCurrentList(theDialog: DialogPtr; currentListHdl: ListHandle);
{Stores a handle to the dialogıs currently active list in the dialogıs info. Only the
List Suite should call this routine.}
{Written by David Sinclair, 13 September 1997.}
BEGIN
IF ValidFilterDialog(theDialog,false) THEN
FilterPeek(theDialog)^.currentListHdl:= currentListHdl
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogGetCurrentList(theDialog: DialogPtr): ListHandle;
{Returns a handle to the dialogıs currently active list, from the specified dialogıs info, or
Nil if the dialog doesnıt contain valid data, or no list is currently active. Only the
List Suite should call this routine.}
{Written by David Sinclair, 13 September 1997.}
BEGIN
IF ValidFilterDialog(theDialog,false) THEN
DlogGetCurrentList:= FilterPeek(theDialog)^.currentListHdl
ELSE
DlogGetCurrentList:= Nil
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogCountDItems (theDialog: dialogPtr): integer;
{ Returns the number of items in the item list for the specified dialog. }
{ Written by David Sinclair, 15 August 1990; fixed -1 bug 13 December 1991 (amazing }
{ that it could lurk this long!!). }
TYPE
countPtr = ^integer;
countHandle = ^countPtr;
BEGIN
dlogCountDItems:= countHandle(dialogPeek(theDialog)^.items)^^ + 1
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogSearchDItems (theDialog: dialogPtr; startItem, theType: integer; {}
VAR itemHandle: handle; VAR itemBox: rect): integer;
{ Routine to find a specified item type within a dialog and return its item number }
{ and box. }
{ Written by David Sinclair, 11 August 1990. }
VAR
done: boolean;
noOfItems, itemType: integer;
BEGIN
done:= false;
IF startItem < firstItem THEN
startItem:= firstItem;
noOfItems:= dlogCountDItems(theDialog);
REPEAT
IF startItem > noOfItems THEN
BEGIN
startItem:= itemNotFound;
done:= true
END
ELSE
BEGIN
GetDialogItem(theDialog, startItem, itemType, itemHandle, itemBox);
IF itemType = theType THEN
done:= true
ELSE
startItem:= startItem + 1
END
UNTIL done;
dlogSearchDItems:= startItem
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogSearchPrevDItems (theDialog: DialogPtr; startItem, theType: Integer; {}
VAR itemHandle: Handle; VAR itemBox: Rect): Integer;
{ The same as dlogSearchDItems, above, but searches backwards. }
{ Written by David Sinclair, 30 January 1996. }
VAR
done: Boolean;
noOfItems, itemType: Integer;
BEGIN
done:= false;
noOfItems:= dlogCountDItems(theDialog);
IF startItem > noOfItems THEN
startItem:= noOfItems;
REPEAT
IF startItem < firstItem THEN
BEGIN
startItem:= itemNotFound;
done:= true
END
ELSE
BEGIN
GetDialogItem(theDialog, startItem, itemType, itemHandle, itemBox);
IF itemType = theType THEN
done:= true
ELSE
startItem:= startItem - 1
END
UNTIL done;
dlogSearchPrevDItems:= startItem
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogMoveDItems (theDialog: DialogPtr; theItems: ItemRange; deltaH, deltaV: Integer);
{ Moves the specified items by deltaH and deltaV. Pass a range of items to move, e.g. }
{ [OK..Cancel, excitingEdit]. }
{ Written by David Sinclair, 20 January 1996. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
index: Integer;
count: Integer;
BEGIN
count:= dlogCountDItems(theDialog);
FOR index:= 1 TO count DO
IF index IN theItems THEN
BEGIN
GetDialogItem(theDialog, index, itemType, itemHandle, itemBox);
OffsetRect(itemBox, deltaH, deltaV);
SetDialogItem(theDialog, index, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
MoveControl(ControlHandle(itemHandle), itemBox.left, itemBox.top);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogResizeDItems (theDialog: DialogPtr; theItems: ItemRange; deltaH, deltaV: Integer);
{ Resizes the specified items by deltaH and deltaV. Pass a range of items to move, e.g. }
{ [OK..Cancel, excitingEdit]. }
{ Written by David Sinclair, 16 February 1996. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
index: Integer;
count: Integer;
BEGIN
count:= dlogCountDItems(theDialog);
FOR index:= 1 TO count DO
IF index IN theItems THEN
BEGIN
GetDialogItem(theDialog, index, itemType, itemHandle, itemBox);
itemBox.bottom:= itemBox.bottom + deltaV;
itemBox.right:= itemBox.right + deltaH;
SetDialogItem(theDialog, index, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
WITH itemBox DO
SizeControl(ControlHandle(itemHandle), right - left, bottom - top);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogResetItemStatus (theDialog: dialogPtr; fromItem: integer);
{ Resets the item status and max length information for all dialog items from the }
{ specified one onwards; pass zero to reset them all. Useful with multi-DITL dialogs. }
{ Written by David Sinclair, 23 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
BEGIN
IF validFilterDialog(theDialog, false) THEN
resetItemStatus(theDialog, fromItem)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetItemStatus (theDialog: dialogPtr; theItem, {}
maximumLength, options: integer);
{ Sets the item status information for the specified item. Pass the maximum edit }
{ item length in maximumLength (or itemDefaultLength for 255 characters, or }
{ itemCurrentLength to leave it the same as before), and one or more of the item }
{ status constants for options; you can add them to set multiple options at once (the }
{ default is itemDefaultOptions, or itemCurrentOptions to leave them the same and }
{ only alter the text length). NOTE: You should call this routine BEFORE calling }
{ dlogSetItemText if you are using the itemDimOKIfNull option, just in case the }
{ initial value is null (otherwise the OK button wonıt be dimmed until the user }
{ interacts with the field). }
{ Written by David Sinclair, 23 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
BEGIN
IF validFilterDialog(theDialog, true) & (theItem IN [0..maxStatusItems]) THEN
WITH filterPeek(theDialog)^ DO
BEGIN
IF options <> itemCurrentOptions THEN
BEGIN
dimOKIfEditNull.asBool[theItem]:= bitAnd(options, itemDimOKIfNull) <> 0;
dimOK.asBool[theItem]:= (theItem = 0) & dimOKIfEditNull.asBool[theItem];
multiLineEdit.asBool[theItem]:= bitAnd(options, itemMultiLineEdit) <> 0;
colonsIllegal.asBool[theItem]:= bitAnd(options, itemColonsIllegal) <> 0;
menuMetasIllegal.asBool[theItem]:= bitAnd(options, itemMenuMetasIllegal) <> 0;
digitsOnly.asBool[theItem]:= bitAnd(options, itemDigitsOnly) <> 0;
decimalsOnly.asBool[theItem]:= bitAnd(options, itemDecimalsOnly) <> 0;
blankShownZero.asBool[theItem]:= bitAnd(options, itemBlankShownZero) <> 0;
zeroIllegal.asBool[theItem]:= bitAnd(options, itemZeroIllegal) <> 0;
END;
IF (maximumLength <> itemCurrentLength) & (maximumLength IN [1..255]) THEN
maxLength[theItem]:= maximumLength;
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogAutoStatus (theDialog: dialogPtr; auto: boolean);
{ If auto is true, the item status filtering is done automatically, otherwise itıs }
{ left up to the client program. If you call the dlogGetItemText routine in your }
{ dialog hit handler, you should call this routine to deactivate the AutoStatus }
{ feature, to avoid filtering the hit items twice. There is no harm in filtering them }
{ twice, but itıs less efficient. You can use the constants activate and deactivate. }
{ AutoStatus is on by default. }
{ Written by David Sinclair, 15 November 1994. }
BEGIN
IF validFilterDialog(theDialog, false) THEN
filterPeek(theDialog)^.autoStatus:= auto
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogDontManageOK (theDialog: DialogPtr);
{ Call this routine to leave the OK button (i.e. item 1) alone, e.g. if it isnıt being }
{ used as an OK button. }
{ Written by David Sinclair, 30 January 1996. }
BEGIN
IF ValidFilterDialog(theDialog, true) THEN
filterPeek(theDialog)^.dontManageOK:= true
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogKeepOKDimmed (theDialog: dialogPtr; keepDimmed: boolean);
{ Call this routine to always keep the OK button dimmed, no matter what goes on }
{ with edit fields. }
{ Written by David Sinclair, 3 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994; }
{ modified to allow turning off the keep dimmed feature, 12 December 1994. }
BEGIN
IF validFilterDialog(theDialog, true) THEN
filterPeek(theDialog)^.keepOKDimmed:= keepDimmed
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogOKIsActive (theDialog: dialogPtr; ignoreKeepDimmed: boolean): boolean;
{ Returns true if the OK button isnıt dimmed, due to one or more editTexts being }
{ null when they shouldnıt be or whatever. Pass true for ignoreKeepDimmed if you }
{ want to know what the state of the button would be if it werenıt being kept dimmed }
{ by the previous routine, or false if you just want to find out itıs actual state. Note }
{ that passing true assumes that the state of the button is controlled automatically, i.e. }
{ you havenıt explicitly dimmed it yourself. }
{ Written by David Sinclair, 3 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
result: boolean;
BEGIN
result:= true;
IF ignoreKeepDimmed THEN { Report what the OK button would be, ignoring }
BEGIN { whether keepOKDimmed is true or not }
IF validFilterDialog(theDialog, false) & filterPeek(theDialog)^.statusInited THEN
result:= filterPeek(theDialog)^.OKActive
ELSE
ignoreKeepDimmed:= false
END;
IF NOT ignoreKeepDimmed THEN { Report the actual visual state of the OK button }
BEGIN
GetDialogItem(theDialog, ok, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
result:= controlHandle(itemHandle)^^.contrlHilite <> 255
END; { 0 = active, 255 = dimmed }
dlogOKIsActive:= result
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogItemIsCtrl (itemType: integer; itemHandle: handle): boolean;
{ Returns true if the specified itemType (as returned by GetDialogItem) is a control item, }
{ and the associated handle is not nil (this is worth checking since one normally }
{ coerces the handle into a ControlHandle and uses it; being nil would be Bad). }
{ Written by David Sinclair, 4 June 1994. }
CONST
ctrlBit = 2;
BEGIN
dlogItemIsCtrl:= BTST(itemType, ctrlBit) & (itemHandle <> NIL)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogItemIsButton (theDialog: DialogPtr; theItem: Integer): Boolean;
{Returns true if the specified item is a button, otherwise false.}
{Written by David Sinclair, 19 April 1999.}
VAR
itemType: Integer;
itemHndl: Handle;
itemBox: Rect;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHndl, itemBox);
DlogItemIsButton:= dlogItemIsCtrl(itemType, itemHndl) & (itemType IN [ctrlItem + btnCtrl])
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetCtrlItem (theDialog: dialogPtr; theItem: integer; {}
VAR itemHandle: controlHandle): boolean;
{ Call this if you need a controlHandle for the specified item, but donıt need its itemType and }
{ itemBox. This routine returns true if the item is a control item and the associated handle is }
{ not nil. The handle is returned as a controlHandle. }
{ Written by David Sinclair, 4 June 1994. }
CONST
ctrlBit = 2;
VAR
itemType: integer;
itemBox: rect;
valid: boolean;
BEGIN
valid:= false;
IF theDialog <> NIL THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, handle(itemHandle), itemBox);
valid:= BTST(itemType, ctrlBit) & (itemHandle <> NIL)
END;
dlogGetCtrlItem:= valid
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetControl (theDialog: dialogPtr; theItem: integer; {}
value, activateIt: boolean);
{ Turns off or on the specified radio button or checkbox as appropriate, and activates }
{ or deactivates it also. Use the constants activate and deactivate, or an expression. }
{ Written by David Sinclair, 5 December 1991; made into a genDialogs routine }
{ and added itemType checking, 4 June 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
SetControlValue(controlHandle(itemHandle), ord(value));
hiliteControl(controlHandle(itemHandle), ord(NOT activateIt) * 255)
END { 0 = active, 255 = dimmed }
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogToggleCheckbox (theDialog: dialogPtr; theItem: integer): boolean;
{ Similar to the previous routine, except that it toggles the checkbox value, and }
{ doesnıt alter the activation (dimming) state. The new value is returned. }
{ Written by David Sinclair, 13 July 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
result: boolean;
BEGIN
result:= false;
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
result:= GetControlValue(controlHandle(itemHandle)) = 0;
SetControlValue(controlHandle(itemHandle), ord(result));
END;
dlogToggleCheckbox:= result
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetupRadioGroup (theDialog: dialogPtr; firstItem, {}
noOfItems: integer; currentValue: UNIV signedByte);
{ Sets up a radio group. The radio button items are presumed to be sequential. Pass }
{ the first item in the group, the number of items in the group, and the current value }
{ of the controlling variable; currentValue is suitable for variables of set type or }
{ boolean; in the latter case, the second of the two radio buttons is considered true. }
{ Since the currentValue is a univ parameter, you donıt need to coerce it. }
{ Written by David Sinclair, 18 June 1994; made into a genDialogs routine, }
{ 13 July 1994. }
VAR
itemType, index: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
IF (firstItem > 0) & (noOfItems > 0) THEN
FOR index:= 0 TO noOfItems - 1 DO
BEGIN
GetDialogItem(theDialog, firstItem + index, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
SetControlValue(controlHandle(itemHandle), ord(currentValue = index));
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogHandleRadioGroup (theDialog: dialogPtr; itemHit, firstItem, {}
noOfItems: integer; VAR results: UNIV signedByte);
{ Handles a radio group. The radio button items are presumed to be sequential. Pass }
{ the item hit, the first item in the group, and the number of items in the group. The }
{ results are suitable for variables of set type or boolean; in the latter case, the second }
{ of the two radio buttons is considered true. Since results is a univ parameter, you }
{ donıt need to coerce it. }
{ Written by David Sinclair, 17 June 1994; made into a genDialogs routine, }
{ 13 July 1994. }
VAR
index: integer;
itemHandle: controlHandle;
BEGIN
IF (itemHit IN [firstItem..(firstItem + noOfItems - 1)]) & (firstItem > 0) & (noOfItems > 0) THEN
BEGIN
results:= itemHit - firstItem;
FOR index:= 0 TO noOfItems - 1 DO
BEGIN
IF dlogGetCtrlItem(theDialog, firstItem + index, itemHandle) THEN
SetControlValue(itemHandle, ord(results = index));
END
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogHandleBoolRadioGroup (theDialog: dialogPtr; itemHit, firstItem: integer): boolean;
{ Handles a boolean radio group, i.e. one where there are only two radio buttons, the first }
{ representing the false case, the second representing the true. These are a hassle to pass }
{ to the above routine if the value is stored in a packed array of boolean, so this routine will }
{ instead return the correct value as a function result. }
{ Written by David Sinclair, 20 January 1995. }
VAR
itemHandle: controlHandle;
secondSelected: boolean;
BEGIN
IF (firstItem > 0) & dlogGetCtrlItem(theDialog, firstItem, itemHandle) THEN
IF NOT (itemHit IN [firstItem, firstItem + 1]) THEN { Didnıt click on one of these, so just get value }
secondSelected:= GetControlValue(itemHandle) = 0
ELSE
BEGIN { Get the new value and update the radio buttons }
secondSelected:= itemHit <> firstItem;
SetControlValue(itemHandle, ord(NOT secondSelected));
IF dlogGetCtrlItem(theDialog, firstItem + 1, itemHandle) THEN
SetControlValue(itemHandle, ord(secondSelected));
END;
dlogHandleBoolRadioGroup:= secondSelected
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogBoldOutlineMethod (theDialog: dialogPtr; {}
toggleDefaultButtons: boolean);
{ Changes the method used to draw the bold outline around the default button. By }
{ default, the default button is toggled between OK and Cancel when the OK button is }
{ activated or dimmed respectively. If you pass dimInSynch, the bold outline is }
{ dimmed or activated in synch with the button, or if you pass toggleDefaults the }
{ default behavior is restored. You only need to call this routine if you prefer the }
{ dimming behaviour instead of the normal toggling behaviour. }
{ Written by David Sinclair, 10 November 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
BEGIN
IF validFilterDialog(theDialog, false) THEN
filterPeek(theDialog)^.toggleOutline:= toggleDefaultButtons;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogDrawBoldOutline (theDialog: dialogPtr; theItem: integer; {}
draw: boldOutlineType);
{ Draws a bold round rect around the specified item. Used to draw the bold outline }
{ around the default button in a dialog. Pass boldActive for draw to draw it black (i.e. }
{ in an active state, boldDim to draw it greyed, or boldErase to erase it. NOTE: The }
{ dialog routines in this unit automatically draw and update this outline (without }
{ using a userItem), so you donıt need to worry about it. Note, though, that if you use }
{ it together with a userItem, you will need to first make sure you set the userItemıs }
{ rect to the rect of the button you want outlined. }
{ Made into a publically available routine 26 June 1992; added erasing capability, }
{ 5 July 1994; added greying out capability, 10 September 1994; modifed to use the }
{ piggyback filter info instead of a record accessed via a handle, 11 November 1994. }
CONST
edgeCurve = 16;
gapBetween = -4;
lineSize = 3;
colourQD = $100; { QD vers 1.00 is first with colour }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
oldPen: penState;
oldPort: grafPtr;
response: longint;
oldColour, greyColour: RGBColor;
BEGIN
IF (theDialog <> NIL) & (theItem > 0) THEN
BEGIN
getPort(oldPort);
setPort(theDialog);
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
getPenState(oldPen);
{$IFC application}
getForeColor(oldColour);
IF draw = boldDim THEN
BEGIN
IF gestalt(gestaltQuickDrawVersion, response) = noErr THEN
IF loWord(response) >= colourQD THEN
BEGIN { Drawing grey in colour }
greyColour.red:= $8000;
greyColour.green:= $8000;
greyColour.blue:= $8000;
RGBForeColor(greyColour)
END
END
ELSE
foreColor(blackColor); { Drawing black or erasing }
{$ENDC}
penNormal;
penSize(lineSize, lineSize);
insetRect(itemBox, gapBetween, gapBetween);
{$IFC application}
IF draw = boldErase THEN
penMode(patBic);
{$ENDC}
frameRoundRect(itemBox, edgeCurve, edgeCurve);
{$IFC application}
RGBForeColor(oldColour);
{$ENDC}
setPenState(oldPen);
IF validFilterDialog(theDialog, false) THEN
filterPeek(theDialog)^.boldOutline:= draw;
{ Update the current state of the outline }
setPort(oldPort)
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetDefaultButton (theDialog: dialogPtr; theItem: integer);
{ Makes the specified button the default, redrawing the bold outline as appropriate. }
{ Note: if you call dlogHiliteButton to dim the OK button (or whatever button is item }
{ number 1), there is no need to call this routine; it is called automatically in that }
{ situation. Note that you can pass an item number of zero to make no default button }
{ (i.e. forcing the user to click the button with the mouse). }
{ Written by David Sinclair, 2 July 1994; passing zero support added 20 July 1994; modified to }
{ use a dimmed outline if the button is dimmed, and always draw the outline, 14 October 1995. }
VAR
itemType, oldDefault: integer;
itemHandle: handle;
itemBox: rect;
newOutline, oldOutline: boldOutlineType;
BEGIN
IF theItem > 0 THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
IF validFilterDialog(theDialog, false) THEN
oldOutline:= filterPeek(theDialog)^.boldOutline
ELSE
oldOutline:= boldActive;
IF (controlHandle(itemHandle)^^.contrlHilite = 0) THEN
newOutline:= boldActive
ELSE
newOutline:= boldDim;
oldDefault:= dialogPeek(theDialog)^.aDefItem;
dialogPeek(theDialog)^.aDefItem:= theItem;
IF (theItem <> oldDefault) | (newOutline <> oldOutline) THEN
BEGIN
IF theItem <> oldDefault THEN
dlogDrawBoldOutline(theDialog, oldDefault, boldErase);
dlogDrawBoldOutline(theDialog, theItem, newOutline);
END
END
END
ELSE { No default button }
BEGIN
oldDefault:= dialogPeek(theDialog)^.aDefItem;
dialogPeek(theDialog)^.aDefItem:= theItem;
IF oldDefault > 0 THEN
dlogDrawBoldOutline(theDialog, oldDefault, boldErase);
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogHiliteButton (theDialog: dialogPtr; theItem: integer; {}
activateIt: boolean);
{ Dims or activates the specified button as requested (but only if the button isnıt }
{ already in that state). If youıre dealing with the OK button (i.e. the button at item }
{ number 1), the bold outline is altered in accordance with the current method see }
{ the dlogBoldOutlineMethod routine. Use the constants activate and deactivate, or a }
{ boolean expression (e.g. theString <> null). }
{ Written by David Sinclair, 15 June 1994; added support for the dimming bold outline }
{ method, 10 November 1994; modifed to use the piggyback filter info instead of a }
{ record accessed via a handle, 11 November 1994; modified so that the bold outline is }
{ toggled even if the hilite state hasnıt changed, in case some external factor has }
{ influenced it, 2 October 1995; modified so that if the OK button is dimmed when there }
{ is no Cancel or Cancel is already dimmed, the bold outline is dimmed instead of }
{ toggled, 14 October 1995. }
VAR
newHilite: byte;
itemType: integer;
itemHandle: handle;
cancelHandle: controlHandle;
itemBox: rect;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
newHilite:= ord(NOT activateIt) * 255; { 0 = active, 255 = dimmed }
IF newHilite <> controlHandle(itemHandle)^^.contrlHilite THEN
hiliteControl(controlHandle(itemHandle), newHilite);
IF validFilterDialog(theDialog, false) & NOT filterPeek(theDialog)^.dontManageOK THEN
IF filterPeek(theDialog)^.toggleOutline & (theItem = ok) & (dialogPeek(theDialog)^.aDefItem IN [ok, cancel]) THEN
IF activateIt | NOT dlogGetCtrlItem(theDialog, cancel, cancelHandle) | (cancelHandle^^.contrlHilite <> 0) THEN
dlogSetDefaultButton(theDialog, ok)
ELSE
dlogSetDefaultButton(theDialog, cancel)
ELSE IF theItem = dialogPeek(theDialog)^.aDefItem THEN
IF activateIt THEN
dlogDrawBoldOutline(theDialog, theItem, boldActive)
ELSE
dlogDrawBoldOutline(theDialog, theItem, boldDim)
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetCurrentEditItem (theDialog: dialogPtr): integer;
{ Returns the item number of the currently active edit item. If there are no edit }
{ items in the dialog, zero is returned. }
{ Written by David Sinclair, 2 July 1994. }
BEGIN
dlogGetCurrentEditItem:= dialogPeek(theDialog)^.editField + 1
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogGetCurrentEditSelection (theDialog: DialogPtr; VAR selStart, selEnd: Integer);
{ Returns the selection range of the currently active edit item. If there are no edit items in the }
{ dialog, zeroes are returned. }
{ Written by David Sinclair, 3 February 1996. }
BEGIN
IF DialogPeek(theDialog)^.editField >= 0 THEN
BEGIN
selStart:= DialogPeek(theDialog)^.textH^^.selStart;
selEnd:= DialogPeek(theDialog)^.textH^^.selEnd;
END
ELSE
BEGIN
selStart:= 0;
selEnd:= 0;
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogCoerceEditable (theDialog: DialogPtr; theItem: Integer; toEditText, allowStatHits: Boolean);
{ Changes a statText item into an editText item, or vice versa. For allowStatHits, }
{ youıd normally pass false (or the constant deactivate), unless you want the new }
{ statText item to report hits. Hits are always allowed for editText items. NOTE: }
{ This routine will now work from a hit handler to dynamically change between the }
{ types. }
{ Written by David Sinclair, 25 July 1994; modified to dynamically adjust, 29 June 1997. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
i: Integer;
anyEdits: Boolean;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF itemType IN [editText, itemDisable + editText, statText, itemDisable + statText] THEN BEGIN
IF toEditText THEN
itemType:= editText
ELSE IF allowStatHits THEN
itemType:= statText
ELSE
itemType:= itemDisable + statText;
SetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
InsetRect(itemBox,-2,-2); {Remove or redraw the edit outline}
EraseRect(itemBox);
InsetRect(itemBox,-1,-1);
InvalRect(itemBox);
anyEdits:= False;
i:= CountDITL(theDialog);
REPEAT {Look for editText items}
GetDialogItem(theDialog,i,itemType,itemHandle,itemBox);
IF (itemType=editText) | (itemType=editText+itemDisable) THEN anyEdits:= True;
i:= i - 1;
UNTIL anyEdits | (i<=0);
IF NOT anyEdits THEN DialogPeek(theDialog)^.editField:= -1; {There are no editTexts left}
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE handleItemStatusStuff (theDialog: dialogPtr; theItem: integer; {}
VAR theText: str255);
{ Updates the item status information, ensures the text isnıt too long, and dims or }
{ undims the OK button as appropriate, etc. }
{ Written by David Sinclair, 3 July 1994; modifed to use the piggyback }
{ filter info instead of a record accessed via a handle, 11 November 1994. }
VAR
itemType, index, oldLength: integer;
itemHandle: handle;
itemBox: rect;
updateText, selectText, dotSighted: boolean;
BEGIN
updateText:= false;
selectText:= false;
IF validFilterDialog(theDialog, false) THEN
WITH filterPeek(theDialog)^ DO
IF statusInited THEN
BEGIN
IF theItem IN [1..maxStatusItems] THEN { theItem will be zero if calling while }
{ setting up in dlogDialog }
BEGIN
oldLength:= length(theText);
IF colonsIllegal.asBool[theItem] & (pos(':', theText) <> 0) THEN
theText:= strReplace(theText, ':', null);
IF menuMetasIllegal.asBool[theItem] THEN
BEGIN
theText:= strReplace(strReplace(strReplace(theText, ';', null), '^', null), '!', null);
theText:= strReplace(strReplace(strReplace(theText, '<', null), '/', null), '(', null);
END;
IF digitsOnly.asBool[theItem] | decimalsOnly.asBool[theItem] THEN
BEGIN
index:= 1;
dotSighted:= digitsOnly.asBool[theItem];
IF theText <> null THEN
REPEAT
IF NOT (theText[index] IN [period, '0'..'9']) | ((theText[index] = period) & dotSighted) THEN
delete(theText, index, 1)
ELSE
BEGIN
IF (theText[index] = period) THEN
dotSighted:= true;
index:= index + 1
END
UNTIL index > length(theText);
END;
IF blankShownZero.asBool[theItem] & (theText = null) THEN
BEGIN
theText:= '0';
updateText:= true;
selectText:= true;
END;
IF zeroIllegal.asBool[theItem] & (strToNum(theText) = 0) THEN
BEGIN
theText:= '1';
updateText:= true;
selectText:= true;
END;
IF length(theText) = 255 THEN { It might actually be longer, so truncate }
updateText:= true;
IF length(theText) > maxLength[theItem] THEN
theText:= copy(theText, 1, maxLength[theItem]); { Truncate if too long }
updateText:= (oldLength <> length(theText)) | updateText;
IF updateText THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
SetDialogItemText(itemHandle, theText)
END;
IF selectText THEN
SelectDialogItemText(theDialog, theItem, 0, maxInt);
dimOK.asBool[theItem]:= (theText = null) & dimOKIfEditNull.asBool[theItem];
END; { Is this item null, and do we care? }
index:= maxStatusAsLongs;
WHILE (index > 0) & (dimOK.asLong[index] = 0) DO { Are there any (significant) }
index:= index - 1; { null edit items? }
OKActive:= index = 0;
IF NOT dontManageOK THEN
dlogHiliteButton(theDialog, ok, OKActive & NOT keepOKDimmed);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetItemText (theDialog: dialogPtr; theItem: integer): str255;
{ Returns the current text of the specified statText or editText item, and handles }
{ options set via dlogSetItemStatus, if any. }
{ Written by David Sinclair, 14 June 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
theText: str255;
BEGIN
IF (theDialog <> NIL) & (theItem > 0) THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF itemType IN [statText, itemDisable + statText, editText, itemDisable + editText] THEN
GetDialogItemText(itemHandle, theText)
ELSE
theText:= null;
IF itemType IN [editText, itemDisable + editText] THEN
handleItemStatusStuff(theDialog, theItem, theText);
END
ELSE
theText:= null;
dlogGetItemText:= theText
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetItemText (theDialog: dialogPtr; theItem: integer; theText: str255);
{ Changes the contents of the specified statText or editText item, and handles }
{ options set via dlogSetItemStatus, if any. The text is only changed if it is different }
{ from what is already there. }
{ Written by David Sinclair, 14 June 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
oldText: str255;
BEGIN
IF (theDialog <> NIL) & (theItem > 0) THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF itemType IN [statText, itemDisable + statText, editText, itemDisable + editText] THEN
BEGIN
GetDialogItemText(itemHandle, oldText);
IF (theText = null) | (theText <> oldText) THEN
BEGIN
IF itemType IN [editText, itemDisable + editText] THEN
handleItemStatusStuff(theDialog, theItem, theText);
SetDialogItemText(itemHandle, theText);
END
END
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetTextPattern (theDialog: DialogPtr; theItem: Integer; textPattern: Str255; {}
options: Integer): Str255;
{ Similar to dlogGetItemText, above, but also formats the text using the specified pattern. }
{ . }
{ Written by David Sinclair, 3 February 1996. }
{ ĥĥĥ This routine is not yet implemented; I was going to use it in Dejal Register, but decided that it }
{ wasnıt useful enough for the overhead. Design thoughts, in case I decide to implement it in the }
{ future: }
{ The Get routine can either return the text in a formatted or unformatted state in either case the }
{ text is formatted in the edit field, but the return value is formatted or not. The Set routine always }
{ formats the text. For both you might be able to specify whether to format the text with or without }
{ sample text e.g. ³mm/yy² would be displayed as ³11/yy² or ³11² if ³11² was entered in which }
{ case Iıd have to select the first ³y² so that subsequent typing changes that, and Iıd adjust the selection }
{ range each time the user types. Tabbing wouldnıt be a problem, since the user could replace all the }
{ text, leaving the sample text. For Get, get the text from the edit field, call dlogSetTextPattern to format }
{ and set the text, then set the selection if necessary. }
BEGIN
dlogGetTextPattern:= dlogGetItemText(theDialog, theItem);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogEllipsisText (theDialog: dialogPtr; theItem: integer; {}
leftText, rightText: str255);
{ Changes the contents of the specified statText item such that it is ellipsised if }
{ necessary. The text is only changed if it is different from what is already there. }
{ Written by David Sinclair, 18 July 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
oldText: str255;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF itemType IN [statText, itemDisable + statText] THEN
BEGIN
GetDialogItemText(itemHandle, oldText);
leftText:= strEllipsis(leftText, rightText, itemBox.right - itemBox.left);
IF (leftText = null) | (leftText <> oldText) THEN
SetDialogItemText(itemHandle, leftText);
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DlogSetDrawingProc (theDialog: DialogPtr; theItem: Integer; theProcedure: UserItemProcPtr);
{ Installs the specified routine as the drawing procedure for the userItem. }
{ Pass @routineName for theProcedure. Note: you must call DlogDisposeDrawingProc }
{ before closing the dialog, to avoid fragmenting memory. }
{ Written by David Sinclair, 1 June 1994; made into a genDialogs routine, }
{ 4 June 1994; added UPP support, 31 May 1997. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
theUPP: UserItemUPP;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF (theProcedure <> NIL) & (itemType IN [userItem, itemDisable + userItem]) THEN BEGIN
theUPP:= NewUserItemProc(theProcedure);
SetDialogItem(theDialog, theItem, itemType, Pointer(theUPP), itemBox);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE DisposeAllDrawingProcs(theDialog: DialogPtr);
{ Removes the previously assigned routines as the drawing procedures for all userItems. Called by the dialog routines
when a dialog is closed. }
{ Written by David Sinclair, 31 May 1997. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
count: Integer;
index: Integer;
BEGIN
count:= DlogCountDItems(theDialog);
FOR index:= 1 TO count DO BEGIN
GetDialogItem(theDialog, index, itemType, itemHandle, itemBox);
IF (itemHandle <> Nil) & (itemType IN [userItem, itemDisable + userItem]) THEN BEGIN
DisposeRoutineDescriptor(UniversalProcPtr(itemHandle));
SetDialogItem(theDialog, index, itemType, Nil, itemBox);
END;
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogChangeCtrlTitle (theDialog: dialogPtr; theItem: integer; {}
newTitle: str255);
{ Changes the title of the specified control to the specified string, but only if the }
{ title has changed. }
{ Written by David Sinclair, 28 September 1992; made into a genDialogs routine }
{ and added itemType checking, 4 June 1994; added check that the text has changed, }
{ 24 July 1994. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
oldTitle: str255;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
GetControlTitle(controlHandle(itemHandle), oldTitle);
IF newTitle <> oldTitle THEN
SetControlTitle(controlHandle(itemHandle), newTitle)
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogEllipsisCtrlTitle (theDialog: dialogPtr; theItem: integer; {}
leftTitle, rightTitle: str255);
{ Changes the title of the specified control to the title made by adding the specified left }
{ and right parts such that the leftTitle is ellipsed if itıs too long to fit in the control. }
{ Especially useful for buttons with dynamic titles. The title is only changed if the }
{ new title is different from the previous one. }
{ Written by David Sinclair, 24 July 1994. }
VAR
itemType, allowance: integer;
itemHandle: handle;
itemBox: rect;
oldTitle: str255;
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
IF itemType IN [ctrlItem + btnCtrl, itemDisable + ctrlItem + btnCtrl] THEN
allowance:= 6
ELSE
allowance:= 10;
leftTitle:= strEllipsis(leftTitle, rightTitle, itemBox.right - itemBox.left - allowance);
GetControlTitle(controlHandle(itemHandle), oldTitle);
IF leftTitle <> oldTitle THEN
SetControlTitle(controlHandle(itemHandle), leftTitle)
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogDontExportClipboard (theDialog: dialogPtr);
{ Normally, dlogDialog will export the TE scrap contents to the Clipboard when the dialog is }
{ closed. Call this routine if you manipulate the Clipboard yourself, to avoid reverting the }
{ contents. }
{ Written by David Sinclair, 2 October 1995. }
BEGIN
IF validFilterDialog(theDialog, false) THEN
filterPeek(theDialog)^.exportTEScrap:= false
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogUseFontSize (theDialog: DialogPtr; theFont, theSize: Integer);
{ Makes the dialog use the specified font and size instead of the usual 12-point system font. }
{ Written by David Sinclair, 15 January 1996. }
VAR
info: FontInfo;
BEGIN
IF theDialog <> NIL THEN
BEGIN
TextFont(theFont);
TextSize(theSize);
GetFontInfo(info);
DialogPeek(theDialog)^.textH^^.txFont:= theFont;
DialogPeek(theDialog)^.textH^^.txSize:= theSize;
DialogPeek(theDialog)^.textH^^.lineHeight:= info.ascent + info.descent + info.leading;
DialogPeek(theDialog)^.textH^^.fontAscent:= info.ascent;
IF DialogPeek(theDialog)^.textH^^.teLength > 0 THEN
TECalText(DialogPeek(theDialog)^.textH);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE flashDialogItem (theDialog: dialogPtr; itemNo: integer);
{ Flashes the selected button a bit more than modelDialog does, for added effect. }
{ Taken from Paul Pottsı program. Called by handleEventFilter. }
CONST
delayTicks = 10;
VAR
finalTicks: Longint;
itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
IF itemNo <> itemNotFound THEN
BEGIN
GetDialogItem(theDialog, itemNo, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
BEGIN
hiliteControl(controlHandle(itemHandle), 1);
delay(delayTicks, finalTicks);
hiliteControl(controlHandle(itemHandle), 0)
END
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE findDefaultButton (theDialog: dialogPtr; VAR theItem: integer; {}
VAR theBox: rect; ignoreHiliting: boolean);
{ Finds which button is the default, and returns its item number and rectangle. Used by }
{ both handleDialogUpdate & handleEventFilter. }
{ Written by David Sinclair, 21 September 1990. }
VAR
theType: integer;
itemHandle: handle;
BEGIN
theItem:= dialogPeek(theDialog)^.aDefItem;
IF theItem > 0 THEN
GetDialogItem(theDialog, theItem, theType, itemHandle, theBox)
ELSE
theType:= 0;
IF theType <> ctrlItem + btnCtrl THEN
theItem:= itemNotFound
ELSE IF (controlHandle(itemHandle)^^.contrlHilite = 255) & NOT ignoreHiliting THEN
theItem:= itemNotFound
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION findEquivButton (theDialog: dialogPtr; theKey: Char): integer;
{ Function to determine what, if any, item in the dialog (i.e. a button) corresponds to the }
{ keyboard equivalent the user typed. Works out what the key equivs are by looking for }
{ the character after a command-symbol in the button title, or failing that the initial }
{ character of the buttonıs title. Used by handleEventFilter. }
{ Written by David Sinclair, 11 August 1990; fixed bug with NIL deref if no match is }
{ found, 2 July 1992. }
VAR
foundIt: boolean;
buttonTitle: str255;
keyEquiv: Char;
keyStr: Str1;
theItem, itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
{ findDefaultButton(theDialog, defaultButton, itemBox, true);}
foundIt:= false;
theItem:= zerothItem;
IF theKey IN [escChar, period] THEN
theKey:= 'C';
REPEAT
theItem:= dlogSearchDItems(theDialog, theItem + 1, ctrlItem + btnCtrl, itemHandle, itemBox);
IF theItem = itemNotFound THEN
foundIt:= true
ELSE
{if theItem <> defaultButton then}
BEGIN
GetControlTitle(controlHandle(itemHandle), buttonTitle);
keyStr:= Copy(buttonTitle, pos(commandSymbol, buttonTitle) + 1, 1);
keyEquiv:= keyStr[1];
{ This will give the character after the command }
{ symbol if there is one, or the initial char if not }
IF keyEquiv = theKey THEN
foundIt:= true
ELSE
BEGIN
strSwapCharCase(keyEquiv);
IF keyEquiv = theKey THEN
foundIt:= true
END
END
UNTIL foundIt;
IF theItem <> itemNotFound THEN
BEGIN
GetDialogItem(theDialog, theItem, itemType, itemHandle, itemBox);
IF controlHandle(itemHandle)^^.contrlHilite = 255 THEN
theItem:= itemNotFound
END;
findEquivButton:= theItem
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
FUNCTION getNMIconHandle: handle;
{ Returns a handle to an icon with the appropriate bit depth. }
{ Written by David Sinclair, 25 January 1995. }
VAR
returnHndl: 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
err:= numGetResource(iconHndl, iconType, notificationIconID);
IF err = noErr THEN
BEGIN
HNoPurge(iconHndl);
err:= AddIconToSuite(iconHndl, returnHndl, iconType)
END;
END;
BEGIN
err:= NewIconSuite(returnHndl);
IF err <> noErr THEN
returnHndl:= NIL
ELSE
BEGIN
addIcon(small1BitMask);
addIcon(small4BitData);
addIcon(small8BitData);
END;
getNMIconHandle:= returnHndl
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION getNMSoundHandle (eventString: str255; VAR releaseWhenDone: boolean): handle;
{ Returns the appropriate sound handle to pass to the notification request, based on the }
{ event code. True is passed back in releaseWhenDone if you should call releaseResource }
{ for the returned sound handle before disposing of the NM record. If it is false, donıt }
{ touch it. }
{ Written by David Sinclair, 8 July 1992; moved to genDialogs, 20 January 1995. }
VAR
returnHndl: handle;
BEGIN
releaseWhenDone:= false;
returnHndl:= NIL;
IF eventString = notifyWithBeep THEN { Play the system beep }
returnHndl:= handle(-1)
ELSE IF eventString <> notifyWithSilence THEN { Play a user-specified sound }
BEGIN
returnHndl:= getNamedResource('snd ', eventString);
IF returnHndl = NIL THEN
returnHndl:= handle(-1)
ELSE
BEGIN
hNoPurge(returnHndl);
releaseWhenDone:= true
END
END;
getNMSoundHandle:= returnHndl
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE notifyForForeground (eventString: str255; iconInForeground, soundInForeground: boolean);
{ If we are in the background, queues a notification request then waits until the user brings us into }
{ the foreground. Handles update events in the meantime. In either case, this routine plays any }
{ appropriate sound as specified by the user. Pass a valid sound name or one of the other }
{ constants (see dlogSetNotificationSnd, below), and pass true for iconInForeground and }
{ soundInForeground if the icon and sound are allowed to be used in the foreground as well as }
{ in the background. }
{ Written by David Sinclair, 14 November 1991, with the osEvt handler based on the }
{ code in SoundApp, an excellent DTS sample program; check for background and playing }
{ the prefs sounds added 8 July 1992; moved to genDialogs, 20 January 1995. }
CONST
getHighByte = 24; { 24 bits (three bytes) to shift right }
theSleepTime = 60;
VAR
myNotification: NMRec;
myErr: osErr;
theEvent: eventRecord;
oldPort: grafPtr;
theWindow: windowPtr;
index: integer;
releaseWhenDone: boolean;
BEGIN
IF iconInForeground | soundInForeground | inBackground THEN
WITH myNotification DO
BEGIN
qType:= ord(nmType); { Set queue type }
nmMark:= ord(inBackground); { Put mark in Application menu if in background, }
{ or in the Apple menu if in the foreground }
IF iconInForeground | inBackground THEN
nmIcon:= getNMIconHandle { Get the icon to alternate in the menubar }
ELSE
nmIcon:= NIL;
IF soundInForeground | inBackground THEN
nmSound:= getNMSoundHandle(eventString, releaseWhenDone)
ELSE
nmSound:= NIL;
nmStr:= NIL; { Donıt put up an alert }
nmResp:= NIL; { No response procedure }
nmRefCon:= 0 { Donıt need a refCon }
END;
myErr:= NMInstall(@myNotification); { Install the notification request }
IF myErr = noErr THEN
BEGIN
FOR index:= 1 TO 10 DO { Get the notification started }
systemTask;
IF myNotification.nmIcon <> NIL THEN
REPEAT
IF waitNextEvent(osMask + updateMask, theEvent, theSleepTime, NIL) THEN
CASE theEvent.what OF
osEvt: { osEvt code based on SoundApp }
BEGIN
IF BSR(theEvent.message, getHighByte) = suspendResumeMessage THEN
IF BAnd(theEvent.message, resumeFlag) <> 0 THEN
inBackground:= FALSE {it was a resume event}
ELSE
inBackground:= TRUE {it was a suspend event}
END;
updateEvt:
IF windowPeek(theEvent.message)^.windowKind = dialogKind THEN
BEGIN { Repaint a dialog }
getPort(oldPort);
theWindow:= windowPtr(theEvent.message);
setPort(theWindow);
beginUpdate(theWindow);
drawDialog(theWindow);
endUpdate(theWindow);
setPort(oldPort)
END;
OTHERWISE
; { Ignore other events }
END
UNTIL NOT inBackground;
myErr:= NMRemove(@myNotification); { Remove the notification request }
WITH myNotification DO
BEGIN
IF nmIcon <> NIL THEN
myErr:= DisposeIconSuite(nmIcon, true);
IF releaseWhenDone & (nmSound <> NIL) & (nmSound <> handle(-1)) THEN
releaseResource(nmSound);
END
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetNotificationSnds (soundForErrors, soundForAttention: str255);
{ Sets the sounds to play when displaying error dialogs and other dialogs (while in the background). }
{ Pass either a valid sound name (which shouldnıt be longer than 63 characters), or the constant }
{ notifyWithSilence to not play any sound, or notifyWithBeep to play a system beep. }
{ Written by David Sinclair, 20 January 1995. }
BEGIN
notifyErrorSound:= copy(soundForErrors, 1, 63);
notifyAttentionSound:= copy(soundForAttention, 1, 63);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogNotifyForAttention;
{ Call this if you display a dialog through some other method than calling a genDialogs routine }
{ to inherit the normal notification behaviour. (The genProgressDialogs routines call this routine }
{ for you.) }
{ Written by David Sinclair, 20 January 1995. }
BEGIN
notifyForForeground(notifyAttentionSound, false, false);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogNotifyOfCompletion (soundForCompletion: str255);
{ Call this when an operation is complete, to play the specified sound and blink the applicationıs }
{ icon in the menubar. Pass either a valid sound name or one of the constants notifyWithSilence }
{ or notifyWithBeep. }
{ Written by David Sinclair, 20 January 1995. }
BEGIN
notifyForForeground(soundForCompletion, true, true);
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogLastEvent (theDialog: DialogPtr): EventRecord;
{ Returns the most recent event received for this dialog. }
{ Written by David Sinclair, 16 January 1996. }
VAR
theEvent: EventRecord;
BEGIN
IF ValidFilterDialog(theDialog, false) THEN
theEvent:= FilterPeek(theDialog)^.lastEvent
ELSE
theEvent.what:= nullEvent;
dlogLastEvent:= theEvent
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogTrackCursor (theDialog: DialogPtr);
{ Changes the cursor shape to whatever is appropriate at the momemt. You only need to call this }
{ if you are handling cursor tracking manually, and you donıt currently need a custom cursor. By }
{ default, cursor tracking is automatic. }
{ Written by David Sinclair, 11 August 1990; made publically available, 22 February 1997. }
VAR
mouseLoc: point;
count, itemNo: integer;
itemHandle: handle;
itemBox: rect;
useIBeam: boolean;
BEGIN
GetMouse(mouseLoc);
useIBeam:= false;
count:= firstItem;
REPEAT
itemNo:= dlogSearchDItems(theDialog, count, editText, itemHandle, itemBox);
IF itemNo <> itemNotFound THEN
IF PtInRect(mouseLoc, itemBox) THEN
useIBeam:= true
ELSE
count:= itemNo + 1
UNTIL (itemNo = itemNotFound) | useIBeam;
IF useIBeam THEN
SetCursor(GetCursor(iBeamCursor)^^)
ELSE
{$IFC application}
SetCursor(globals.qd.arrow);
{$ELSEC}
SetCursor(GetCursor(arrowCursor)^^);
{$ENDC}
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogSetTrackCursor (theDialog: DialogPtr; trackCursor: Boolean);
{ Call this routine to enable or disable automatic cursor tracking. If you disable automatic cursor }
{ tracking, call dlogTrackCursor, above, if after checking for a custom cursor, one isnıt required. }
{ Written by David Sinclair, 22 February 1997. }
BEGIN
IF ValidFilterDialog(theDialog, false) THEN
FilterPeek(theDialog)^.trackCursor:= trackCursor
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE HandleDrawGrow (theDialog: DialogPtr);
{ Draws the grow icon, without drawing the scrollbar lines too. }
{ Written by David Sinclair, 15 February 1997. }
VAR
growRect: Rect;
oldClip: RgnHandle;
newClip: RgnHandle;
BEGIN
oldClip:= NewRgn;
IF oldClip <> NIL THEN
GetClip(oldClip);
growRect:= theDialog^.portRect;
growRect.left:= growRect.right - 15;
growRect.top:= growRect.bottom - 15;
newClip:= NewRgn;
IF newClip <> NIL THEN
BEGIN
RectRgn(newClip, growRect);
SetClip(newClip);
DisposeRgn(newClip);
END;
DrawGrowIcon(theDialog);
IF oldClip <> NIL THEN
BEGIN
SetClip(oldClip);
DisposeRgn(oldClip);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE HandleDialogUpdate (theDialog: dialogPtr);
{ This is used for dialog drawing such as the default button: used by the }
{ HandleEventFilter and dlogModelessEvent. }
{ Written by David Sinclair, 11 August 1990. Based on Kirk Chaseıs code; modifed to }
{ use the piggyback filter info instead of a record accessed via a handle, 11 November }
{ 1994; added call to HandleDrawGrow, 15 February 1997. }
VAR
itemNo: integer;
itemBox: rect;
BEGIN
IF ValidFilterDialog(theDialog, false) THEN
BEGIN
IF FilterPeek(theDialog)^.growable THEN
HandleDrawGrow(theDialog);
FindDefaultButton(theDialog, itemNo, itemBox, true);
IF itemNo <> itemNotFound THEN
dlogDrawBoldOutline(theDialog, itemNo, FilterPeek(theDialog)^.boldOutline);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION HandleTab (theDialog: DialogPtr; VAR itemHit: Integer): Boolean;
{ Supports Tabbing through edit items. Implemented as a routine so I can support keyboard targetting }
{ one day. }
VAR
itemHandle: Handle;
itemBox: Rect;
count: Integer;
BEGIN
count:= dlogCountDItems(theDialog);
itemHit:= dlogGetCurrentEditItem(theDialog);
IF itemHit > 0 THEN
BEGIN
itemHit:= dlogSearchDItems(theDialog, itemHit + 1, editText, itemHandle, itemBox);
IF itemHit = itemNotFound THEN
itemHit:= dlogSearchDItems(theDialog, 1, editText, itemHandle, itemBox);
SelectDialogItemText(theDialog, itemHit, 0, maxInt);
END;
HandleTab:= (itemHit <> itemNotFound)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION HandleShiftTab (theDialog: DialogPtr; VAR itemHit: Integer): Boolean;
{ Supports Shift-Tabbing through edit items. }
VAR
itemHandle: Handle;
itemBox: Rect;
BEGIN
itemHit:= dlogGetCurrentEditItem(theDialog);
IF itemHit > 0 THEN
BEGIN
itemHit:= dlogSearchPrevDItems(theDialog, itemHit - 1, editText, itemHandle, itemBox);
IF itemHit = itemNotFound THEN
itemHit:= dlogSearchPrevDItems(theDialog, dlogCountDItems(theDialog), editText, itemHandle, itemBox);
SelectDialogItemText(theDialog, itemHit, 0, maxInt);
END;
HandleShiftTab:= (itemHit <> itemNotFound)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE HandleMenuCommand (theDialog: DialogPtr; menuSelection: Longint; VAR itemHit: Integer);
{ Handles menu commands for the dialog, if and as appropriate. }
{ Written by David Sinclair, 6 July 1994; added support for the Select All command and the menu }
{ handler proc, 29 January 1996. }
CONST
normalEditMenuID = 130;
cutItem = 3;
copyItem = 4;
pasteItem = 5;
clearItem = 6;
selectAllItem = 8;
VAR
menuID: Integer;
menuItem: Integer;
currentEdit: Integer;
BEGIN
menuID:= HiWord(menuSelection);
menuItem:= LoWord(menuSelection);
itemHit:= 999;
IF menuID <> 0 THEN
BEGIN
IF (menuID = normalEditMenuID) & (menuItem <= selectAllItem) THEN
BEGIN
CASE menuItem OF
cutItem:
DialogCut(theDialog);
copyItem:
DialogCopy(theDialog);
pasteItem:
DialogPaste(theDialog);
clearItem:
DialogDelete(theDialog);
selectAllItem:
BEGIN
currentEdit:= dlogGetCurrentEditItem(theDialog);
IF currentEdit > 0 THEN
SelectDialogItemText(theDialog, currentEdit, 0, maxInt);
END;
OTHERWISE
;
END; { of case }
itemHit:= dlogGetCurrentEditItem(theDialog);
END;
END;
HiliteMenu(0);
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE HandleMenuBarClick (theDialog: DialogPtr; theEvent: EventRecord; VAR itemHit: Integer);
{ Checks for a mouse down in the menu bar under System 7.0 & handles it by tracking the }
{ menus if there is oneonly the Show Balloons Help menu item should be enabled. }
{ Written by David Sinclair, 12 November 1991; modified to support a menu handler proc, }
{ 29 January 1996. }
VAR
response: Longint;
theWindow: WindowPtr;
menuResult: Longint;
BEGIN
IF Gestalt(gestaltHelpMgrAttr, response) = noErr THEN
IF BitTst(@response, 31 - gestaltHelpMgrPresent) THEN
IF FindWindow(theEvent.where, theWindow) = inMenuBar THEN
BEGIN
InitCursor;
menuResult:= MenuSelect(theEvent.where);
HandleMenuCommand(theDialog, menuResult, itemHit);
SetCursor(GetCursor(watchCursor)^^);
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION handleEventFilter (theDialog: dialogPtr; VAR theEvent: eventRecord; VAR itemHit: integer): boolean;
{ Filter proc for modal dialogs. Handles disk inserts, key equivs, updating & cursor changing. }
{ Written by David Sinclair, 11 August 1990, with code from Paul Potts & Kirk Chase. }
{ Major changes 19-22 September 1990; fixed illegal keyboard clicking bug, 15 December }
{ 1991; modifed to use the piggyback filter info instead of a record accessed via a }
{ handle, 11 November 1994. }
CONST
selectAllCmd = $00820008; { i.e. 130 in the high byte, 8 in the low byte }
VAR
key: Char; { Holds the key pressed }
itemBox: rect;
currentEditItem: integer;
diResult: integer; { Returned by diBadMount }
diskEvent: eventRecord; { Returned by getNextEvent, below }
return, noEditText, cmdKeyDown: boolean;
theUPP: ModalFilterUPP;
menuSelection: longint;
BEGIN
return:= false;
itemHit:= 0;
SetPort(theDialog); { Make sure the dialogıs port is active }
IF validFilterDialog(theDialog, false) THEN
BEGIN
{ HandleMenuAvailablity(theDialog, false);}
theUPP:= FilterPeek(theDialog)^.eventFilterUPP;
IF theUPP <> NIL THEN return:= CallModalFilterProc(theDialog, theEvent, itemHit, theUPP);
IF return = false THEN
BEGIN
{ Handle disk mounts }
IF getNextEvent(diskMask, diskEvent) = true THEN
IF hiWord(diskEvent.message) <> noErr THEN
BEGIN
{$IFC application}
diskEvent.where.h:= ((globals.qd.screenbits.bounds.right - globals.qd.screenbits.bounds.left) DIV 2) - (304 DIV 2);
diskEvent.where.v:= ((globals.qd.screenbits.bounds.bottom - globals.qd.screenbits.bounds.top) DIV 3) - (104 DIV 2);
{$ELSEC}
diskEvent.where.h:= 104; { Default to compact Mac values when screenBits }
diskEvent.where.v:= 62; { is unavailable (if running as INIT, FKEY etc) }
{$ENDC}
initCursor;
diResult:= diBadMount(diskEvent.where, diskEvent.message)
END; { Disk events }
setPort(theDialog); { Make sure the dialogıs port is active }
{ Change the cursor shape to whatever is appropriate at the moment }
IF FilterPeek(theDialog)^.trackCursor THEN
dlogTrackCursor(theDialog);
{ Handle other event types }
CASE theEvent.what OF
updateEvt:
BEGIN
handleDialogUpdate(theDialog);
return:= false
END;
autoKey:
IF (BitAnd(theEvent.message, charCodeMask) = tabKey) & (dlogGetCurrentEditItem(theDialog) > 0) THEN
IF BitAnd(theEvent.modifiers, shiftKey) <> 0 THEN
return:= HandleShiftTab(theDialog, itemHit)
ELSE
return:= HandleTab(theDialog, itemHit);
keyDown:
IF filterPeek(theDialog)^.buttonless THEN
BEGIN
itemHit:= 1;
return:= true { Exit modalDialog }
END
ELSE
BEGIN
key:= Chr(bitAnd(theEvent.message, charCodeMask));
currentEditItem:= dlogGetCurrentEditItem(theDialog);
CASE ord(key) OF { If a key has been pressed, we want to interpret it properly }
returnKey, enterKey:
IF (ord(key) = enterKey) | (currentEditItem < 1) | NOT filterPeek(theDialog)^.statusInited | NOT filterPeek(theDialog)^.multiLineEdit.asBool[currentEditItem] THEN
BEGIN
findDefaultButton(theDialog, itemHit, itemBox, false);
IF itemHit <> itemNotFound THEN
BEGIN
flashDialogItem(theDialog, itemHit);
return:= true { Exit modalDialog }
END
ELSE
theEvent.what:= nullEvent { Ignore the key }
END;
tabKey:
IF (BitAnd(theEvent.message, charCodeMask) = tabKey) & (currentEditItem > 0) THEN
IF BitAnd(theEvent.modifiers, shiftKey) <> 0 THEN
return:= HandleShiftTab(theDialog, itemHit)
ELSE
return:= HandleTab(theDialog, itemHit);
OTHERWISE { Maybe a key equiv }
BEGIN
noEditText:= currentEditItem < 1;
cmdKeyDown:= bitAnd(theEvent.modifiers, cmdKey) <> 0;
IF noEditText | (NOT noEditText & cmdKeyDown) | (key = escChar) THEN
{ If there is an editText item in the dialog, we need to }
{ worry about whether the Command key is down }
{ or not, otherwise sure ya worry! }
BEGIN
menuSelection:= 0;
IF cmdKeyDown THEN { Look for a menu equiv first }
BEGIN
{$IFC NOT UNDEFINED menuEquivs}
menuSelection:= menuKey(key); { A bus error will result if this is }
{ called in an app with no menus }
{$ENDC}
IF key IN ['A', 'a'] THEN
menuSelection:= selectAllCmd;
HandleMenuCommand(theDialog, menuSelection, itemHit);
IF itemHit <> 0 THEN
return:= true
ELSE IF NOT noEditText THEN
BEGIN
itemHit:= currentEditItem;
return:= true
END
END;
IF hiWord(menuSelection) = 0 THEN { Then look for a button equiv }
BEGIN
itemHit:= findEquivButton(theDialog, key);
IF itemHit <> itemNotFound THEN
BEGIN
flashDialogItem(theDialog, itemHit);
return:= true
END
END
END
END
END { Key code case }
END; { KeyDown }
mouseDown:
BEGIN
HandleMenuBarClick(theDialog, theEvent, itemHit); { Check for & handle menu bar clicks }
IF itemHit <> 0 THEN
return:= true
ELSE
{ If there are no buttons, dismiss dialog with a mouse click }
IF filterPeek(theDialog)^.buttonless THEN
BEGIN
itemHit:= 1;
return:= true
END
ELSE
return:= false
END;
OTHERWISE
return:= false; { We donıt handle any other types of events, }
{ so these get sent to modalDialog unchanged }
END { Event case }
END; { If }
filterPeek(theDialog)^.lastEvent:= theEvent;
END;
handleEventFilter:= return
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE HandleItemHit (theDialog: DialogPtr; VAR itemHit: Integer);
{ Handles built-in item hit filtering, then calls the userıs hit handling routine, if any. }
{ If autoStatus is true, the item status filtering is done automatically, otherwise itıs }
{ left up to the client program (which would probably do it anyway by calling the }
{ dlogGetItemText routine). }
{ Written by David Sinclair, 2 July 1994; added UPP support, 31 May 1997. }
VAR
itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
itemText: Str255;
BEGIN
SetPort(theDialog); { Make sure the dialogıs port is active }
IF ValidFilterDialog(theDialog, false) THEN BEGIN
IF itemHit > 0 THEN
IF FilterPeek(theDialog)^.autoStatus THEN
BEGIN
GetDialogItem(theDialog, itemHit, itemType, itemHandle, itemBox);
IF itemType IN [editText, itemDisable + editText] THEN
itemText:= DlogGetItemText(theDialog, itemHit); { All the filtering is done in here }
END
ELSE
ELSE
HandleItemStatusStuff(theDialog, 0, itemText); { Hilite the OK button correctly }
IF FilterPeek(theDialog)^.itemHitFilterUPP <> NIL THEN CallItemHitProc(theDialog, itemHit, FilterPeek(theDialog)^.itemHitFilterUPP);
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
PROCEDURE dlogCentreWindow (theDialog: dialogPtr);
{ Centres the dialog (or window) on the screen. Currently only looks at the main screen. }
{ Written by David Sinclair, 10 July 1992; removed check for System 7, 16 February 1997. }
CONST
heightOfMBar = 20;
VAR
oldPort: grafPtr;
position: point;
BEGIN
IF theDialog <> NIL THEN
WITH theDialog^, position, globals.qd.screenbits DO
BEGIN
getPort(oldPort);
setPort(theDialog);
h:= (bounds.right - portRect.right) DIV 2; { Remember: portRect is local }
v:= (bounds.bottom - heightOfMBar - portRect.bottom) DIV 2 + heightOfMBar;
moveWindow(theDialog, h, v, false);
setPort(oldPort)
END
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogDialog (dialogID: Integer; dlogSetupProc: SetupDialogProcPtr; eventFilterProc: ModalFilterProcPtr;
itemHitFilterProc: ItemHitProcPtr; str0, str1, str2, str3: Str255): Integer;
{ Routine to handle dialogs completely. If you want to include anything fancy not }
{ already handled, e.g. special interpreting of keypresses or whatever, specify your }
{ own event filter proc, which will be called before my custom filter proc or the standard }
{ one does anything. For even more flexablity and power, specify a routine to call }
{ straight after setting up the dialog but before displaying it or calling ModalDialog, }
{ and / or a routine to call just after ModalDialog returns. If you wish to use }
{ expanding / contracting statText items like System 7 does for its alerts, and support }
{ automatic plural handling, either pass @dlogExpandingText as the setup proc (if }
{ you donıt want your own setup proc), or call dlogExpandingText from your setup }
{ proc. If you specify an itemHitFilterProc procedure, it will be called with the special }
{ itemHit value of hookFirstCall once the dialog has been displayed and drawn but }
{ before any events are handled. }
{ Procedure declarations: }
{ procedure myDlogSetupProc (theDialog: dialogPtr); }
{ function myEventFilterProc (theDialog: dialogPtr; var theEvent: eventRecord; }
{ var itemHit: integer): boolean; }
{ procedure myItemHitProc (theDialog: dialogPtr; var itemHit: integer); }
{ Written by David Sinclair, 11 August 1990, with code by Kirk Chase. }
{ Modified by David Sinclair, 19 September 1990, to handle filterProcs & eventFilters; }
{ hookFirstCall added 22 May 1993; modified to save and restore ParamText strings, }
{ 25 June 1994; modifed to use the piggyback filter info instead of a record accessed via }
{ a handle, 11 November 1994; exports scrap at start if a sub-dialog, 4 February 1996;
{ added UPP support, 27 April 1997. }
VAR
oldPort: GrafPtr;
theDialog: DialogPtr;
dlogEventFilterUPP: ModalFilterUPP;
index, itemHit, itemType: Integer;
itemHandle: Handle;
itemBox: Rect;
buttonless: Boolean;
DAStrings: DAStringsArray;
oldParams: ARRAY[0..3] OF Str255;
ignored: OSErr;
BEGIN
GetPort(oldPort);
SetCursor(getCursor(watchCursor)^^);
IF ValidFilterDialog(oldPort, false) THEN { If this is a sub-dialog, export the scrap to preserve it }
BEGIN
ignored:= ZeroScrap;
ignored:= TEToScrap;
END;
DAStrings:= DAStringsPtr(ptr(DAStringsGlob))^;
FOR index:= 0 TO 3 DO { Save the previous ParamText strings, JIC }
IF DAStrings[index] <> NIL THEN
oldParams[index]:= DAStrings[index]^^
ELSE
oldParams[index]:= null;
ParamText(str0, str1, str2, str3);
theDialog:= DialogPtr(NewPtr(SizeOf(FilterDialogRec)));
{ Allocate the space for the dialog and filter info }
IF (resError = noErr) & (theDialog <> NIL) THEN
theDialog:= GetNewDialog(dialogID, Ptr(theDialog), Pointer(-1));
{ Read the dialog resource }
IF (resError <> noErr) | (theDialog = NIL) THEN { Major problem! }
BEGIN
ResReallyBadError;
DlogDialog:= 0
END
ELSE
BEGIN
{$IFC application}
DlogCentreWindow(theDialog); { Centre the dialog on the screen }
{$ENDC}
dlogEventFilterUPP:= NewModalFilterProc(@HandleEventFilter);
InitFilterInfo(theDialog, eventFilterProc, itemHitFilterProc, 0);
buttonless:= FilterPeek(theDialog)^.buttonless;
SetPort(theDialog);
IF dlogSetupProc <> NIL THEN
BEGIN
CallSetupDialogProc(theDialog,dlogSetupProc); { Allow setting up radio buttons etc }
HandleItemStatusStuff(theDialog, 0, str3); { Dim OK button if necessary }
END;
{ HandleMenuAvailablity(theDialog, false);}
itemHit:= hookSetupInvisible;
HandleItemHit(theDialog, itemHit);
IF (dialogID = osErrorDialogID) | (dialogID = osWarningDialogID) THEN
NotifyForForeground(notifyErrorSound, false, true)
ELSE
NotifyForForeground(notifyAttentionSound, false, false);
ShowWindow(theDialog);
SetPort(theDialog);
BeginUpdate(theDialog);
HandleDialogUpdate(theDialog);
DrawDialog(theDialog);
EndUpdate(theDialog);
ignored:= TEFromScrap;
InitCursor;
itemHit:= hookSetupVisible;
HandleItemHit(theDialog, itemHit);
REPEAT
ModalDialog(dlogEventFilterUPP, itemHit); { Process all events and then some! }
HandleItemHit(theDialog, itemHit);
{ Allow user checking of result }
IF itemHit > 0 THEN
GetDialogItem(theDialog, itemHit, itemType, itemHandle, itemBox)
ELSE
itemType:= 0
UNTIL (itemType = ctrlItem + btnCtrl) | buttonless; { Keep on going until a button is }
{ clicked, provided there are buttons }
IF FilterPeek(theDialog)^.exportTEScrap THEN
BEGIN
ignored:= ZeroScrap;
ignored:= TEToScrap;
END;
DisposeAllDrawingProcs(theDialog);
CloseDialog(theDialog);
NumDisposeHandle(dialogPeek(theDialog)^.items);
IF dlogEventFilterUPP<>Nil THEN
DisposeRoutineDescriptor(UniversalProcPtr(dlogEventFilterUPP));
IF FilterPeek(theDialog)^.eventFilterUPP<>Nil THEN
DisposeRoutineDescriptor(UniversalProcPtr(FilterPeek(theDialog)^.eventFilterUPP));
IF FilterPeek(theDialog)^.itemHitFilterUPP<>Nil THEN
DisposeRoutineDescriptor(UniversalProcPtr(FilterPeek(theDialog)^.itemHitFilterUPP));
DisposePtr(ptr(theDialog));
SetPort(oldPort);
FOR index:= 0 TO 3 DO { Restore the previous ParamText strings }
IF DAStrings[index] <> NIL THEN
SetString(DAStrings[index], oldParams[index])
ELSE
DAStrings[index]:= NewString(oldParams[index]);
DlogDialog:= itemHit
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogProcDialog (dialogID: Integer; dlogSetupProc: SetupDialogProcPtr; eventFilterProc: ModalFilterProcPtr;
itemHitFilterProc: ItemHitProcPtr): Integer;
{ Similar to calling dlogDialog, but without the hassle of the four string parameters, }
{ if you donıt need to param anything. }
{ Written by David Sinclair, 2 June 1994. }
BEGIN
DlogProcDialog:= DlogDialog(dialogID, dlogSetupProc, eventFilterProc, itemHitFilterProc, null, null, null, null)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogParamDialog (dialogID: integer; str0, str1, str2, str3: str255);
{ Similar to calling dlogDialog, but without the hassle of the three procedure }
{ parameters, if you donıt need them, and without returning which button was }
{ clicked (if you donıt care, or there is only one button (or none)). Useful for }
{ information-only dialogs. }
{ Written by David Sinclair, 7 June 1994. }
VAR
ignored: integer;
BEGIN
ignored:= dlogDialog(dialogID, NIL, NIL, NIL, str0, str1, str2, str3)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogSimpleDialog (dialogID: integer): integer;
{ Similar to calling dlogDialog, but without the hassle of the three procPtrs or the }
{ four string parameters, if you donıt need them. }
{ Written by David Sinclair, 2 June 1994. }
BEGIN
dlogSimpleDialog:= dlogDialog(dialogID, NIL, NIL, NIL, null, null, null, null)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogInfoDialog (dialogID: integer);
{ Similar to calling dlogDialog, but without the hassle of the three procPtrs or the }
{ four string parameters, if you donıt need them, and without returning which }
{ button was clicked (if you donıt care, or there is only one button (or none)). Useful }
{ for information-only dialogs. }
{ Written by David Sinclair, 2 June 1994. }
VAR
ignored: integer;
BEGIN
ignored:= dlogDialog(dialogID, NIL, NIL, NIL, null, null, null, null)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogInit;
{ If you want to use any modeless dialogs, or call dlogEventLoop, you must call this routine first to }
{ initialise the dialog globals. }
{ Written by David Sinclair, 9 February 1997. }
BEGIN
gOffsetPos.h:= 0;
gOffsetPos.v:= 0;
gQuittingApp:= false;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetDesktopSize: Point;
{ Returns the size of the total desktop, i.e. including all screens. }
{ Written by David Sinclair, 15 February 1997. }
BEGIN
dlogGetDesktopSize:= GetGrayRgn^^.rgnBBox.botRight
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE dlogGetPosAndSize (theDialog: DialogPtr; VAR thePos: Point; {}
VAR theWidth, theHeight: Integer);
{ Returns the current position and size of the dialog. }
{ Written by David Sinclair, 16 February 1997. }
BEGIN
IF theDialog <> NIL THEN
BEGIN
SetPort(theDialog);
thePos:= Point(0);
LocalToGlobal(thePos);
theWidth:= theDialog^.portRect.right;
theHeight:= theDialog^.portRect.bottom;
END
ELSE
BEGIN
thePos:= Point(0);
theWidth:= 0;
theHeight:= 0;
END;
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION dlogGetPosition (theDialog: DialogPtr): Point;
{ Returns the current position of the dialog. }
{ Written by David Sinclair, 16 February 1997. }
VAR
thePos: Point;
BEGIN
thePos:= Point(0);
IF theDialog <> NIL THEN
BEGIN
SetPort(theDialog);
LocalToGlobal(thePos);
END;
dlogGetPosition:= thePos
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION DlogModelessNew (dialogID, kind: Integer; eventFilterProc: ModalFilterProcPtr; itemHitFilterProc: ItemHitProcPtr;
sizeOfVars: Size; VAR vars: UNIV Ptr): DialogPtr;
{Similar to DlogDialog, but opens a modeless dialog instead of a modal one. Call this routine to open the window, then
DlogModelessShow to show it. If an error occurs, the user is alerted. Pass the dialog ID and a value for the kind
(see DlogSetKind, above); pass defaultKind if you donıt need to differentiate between window kinds. Pass a procedure
to call to handle any filtering of the events, and one to handle hits on dialog items. After calling this routine, check
that the returned DialogPtr is not Nil, then do setup of the dialog, then call DlogModelessShow to show and draw it.
Note: unlike DlogDialog, the Clipboard is never touched, and the ParamText call is not supported. Use the same routine
descriptions as for DlogDialog. Unlike modal dialogs, modeless dialogs can open several instances of each window,
so the variables for the window should be stored in a block allocated by this routine. Pass the size of this record in
the sizeOfVars parameter, above, and call DlogModelessVars, below, to retrieve a pointer to the block for the current
window. The vars are also returned by this routine; theyıre guaranteed to be valid if returned DialogPtr is valid, and
if you passed a sizeOfVars > 0. If you donıt need vars (e.g. when converting old single-instance dialogs that use
globals), pass zero. If you only want one instance of the window, call DlogKindAlreadyOpen first.}
{Written by David Sinclair, 12 & 9 February 1997; removed setup routine call and split showing code to separate routine,
1 June 1997.}
VAR
theDialog: DialogPtr;
itemBox: Rect;
desktopSize: Point;
ignored: Boolean;
BEGIN
SetCursor(GetCursor(watchCursor)^^);
gQuittingApp:= false;
vars:= Nil;
theDialog:= DialogPtr(NewPtr(SizeOf(FilterDialogRec)));
{ Allocate the space for the dialog and filter info }
IF (ResError = noErr) & (theDialog <> NIL) THEN
theDialog:= GetNewDialog(dialogID, Ptr(theDialog), Pointer(-1));
{ Read the dialog resource }
IF (ResError <> noErr) | (theDialog = NIL) THEN BEGIN { Major problem! }
ignored:= dlogOSError(memFullErr, null, null, null);
theDialog:= Nil;
HiliteMenu(0);
END
ELSE BEGIN
{$IFC application}
dlogCentreWindow(theDialog); { Centre the window on the screen }
{$ENDC}
desktopSize:= DlogGetDesktopSize;
itemBox.top:= 15;
itemBox.left:= 5;
itemBox.bottom:= desktopSiz