{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{ }
{ GENERIC PROGRESS 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. }
{ 20 July 1997 Clicks in other windows are now disallowed, and now updates other windows. }
{ 21 April 1996 Changed progress bar colours to match the Finder. }
{ }
{ * * * }
{ OLD UNIT HISTORY: }
{ }
{ Version: Start - finish dates: Comments / changes: }
{ }
{ 1.0: 811 Nov 1991 Moved the working message routines from }
{ genDialogs into a new unit, fixed the Cancel }
{ button bug, restructured the routines, added }
{ multiple button names option and }
{ converted the dialog into a movable modal }
{ dialog. Major improvement! }
{ 1.1: 12 November 91 Added position remembering and }
{ auto-adjusting. }
{ 1.2: 13 November 91 Made it use a normal window frame if not }
{ running under System 7. }
{ 1.3: 14 November 91 Added support for noting context switching. }
{ 1.4: 15 November 91 Added support for menu item selection }
{ handling. }
{ 1.5: 24 November 91 Added cursor management switch and }
{ boolean constants. }
{ 1.6: 89 December 91 Added option of not showing an icon }
{ immediately. }
{ 1.7: 11 December 1991 Added the dlogExpandingText support (to }
{ allow variable size progress text) to }
{ progDisplayMessage. }
{ 2.0: 20 December 1991 First public release, in library form. }
{ 2.1: 7 January 1992 Moved the icon drawing routine into }
{ genGraphics. }
{ 2.1.1: 13 January 1992 SysWindow mouse-downs handled. }
{ 2.2: 23 January 1992 Added progDisplayMsgWindow. }
{ 2.3: 2425 Jan 1992 Moved inBackground into a global variable }
{ and dimmed the button when in the }
{ background. }
{ 2.4: 2527 Jan 1992 Converted over to using icon families }
{ (ICN#, icl8, etc) using the new PlotIconID }
{ trap (if available), and made the progress bar }
{ use colour (if available). }
{ 2.5: 28 February 1992 Now only uses new plot icon trap if in }
{ colour and under System 7. }
{ 2.6: 22 Sep 1992 Prog bar pattern used with both B&W and }
{ colour now. }
{ 2.7: 27 Sep 1992 Added protection so it is not possible to }
{ have a progress bar that goes outside its box. }
{ 2.8: 28 Sep 1992 Added support for the Escape key to Cancel. }
{ 2.8.1: 3 October 1992 Fixed Escape key handling: was checking for }
{ the Command key down! }
{ 2.9: 4 June 1994 Added the progGetColour routine. }
{ 2.9.1: 1213 June 1994 Changed the currentItem and maxItem }
{ parameters to longints instead of integers, }
{ changed the unused parameter from a var }
{ parameter to a value one, and added a check }
{ that new top or bottom text is actually }
{ different from what it already is. }
{ 2.10: 2 August 1994 Moved the animated icon drawing }
{ routines to genGraphics, and modified the }
{ progress routines to support automatic }
{ icon animation (via the revised routines }
{ in genGraphics). }
{ 2.11: 20 January 1995 Moved the inBackground global to the }
{ genDialogs unit, and added a call to the new }
{ dlogNotifyForAttention routine in }
{ progDisplayMsgWindow. }
{ * * * }
{ N.B: Most of my units require the compile-time variables applicationı }
{ and debugı, both of which are booleans. }
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
UNIT genProgressDialogs;
INTERFACE
USES
genToolbox, genResources, genStrings, genDialogs, genGraphics;
CONST
progressDialogID = 800; { ID number of the progress DLOG resource }
iProgIcon = 1;
iProgTopText = 2;
iProgButton = 3;
iProgBar = 4;
iProgBotText = 5;
ignoreProgressBar = -1; { Used to tell progChangeMessage not to change the }
{ value of the progress bar (i.e. donıt redraw it) }
progSleepTime = 60;
buttonStringsID = 800; { ID number of the STR# resource containing button names }
noButton = 0; { Used to tell progDisplayMessage what string to use for the }
useCancel = 1; { button, or to not have a button }
useStop = 2;
useQuit = 3;
useProgBar = true;
dontUseProgBar = false;
useProgText = true;
dontUseProgText = false;
manageCursors = true;
dontManageCursors = false;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progGetColour: RGBColor;
PROCEDURE progSetColour (barColour: RGBColor; barPattern: stdPats);
PROCEDURE progProgressBar (theRect: rect; currentItem, maxItem: longint);
FUNCTION progChangeMessage (messageDialog: dialogPtr; unused: boolean; {}
VAR menuSelection: longint; iconID: integer; topText, bottomText: str255; {}
currentItem, maxItem: longint; manageTheCursor: boolean): boolean;
FUNCTION progDisplayMsgWindow (storage: ptr; windowType: integer; {}
VAR position: point; windowTitle: str255; iconID: integer; topText: str255; {}
noOfLines, buttonName: integer; useProgressBar, useProgressText, {}
manageTheCursor: boolean): dialogPtr;
FUNCTION progDisplayMessage (storage: ptr; VAR position: point; {}
windowTitle: str255; iconID: integer; topText: str255; noOfLines, {}
buttonName: integer; useProgressBar, useProgressText, {}
manageTheCursor: boolean): dialogPtr;
FUNCTION progRemoveMessage (messageDialog: dialogPtr): point;
FUNCTION progGetBottomTextWidth (messageDialog: dialogPtr): integer;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
IMPLEMENTATION
{$IFC application}
VAR
progColour: RGBColor;
progPattern: stdPats;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progGetColour: RGBColor;
{ Returns the standard progress bar colour: dark grey, as used in the Finder. }
{ Written by David Sinclair, 19 April 1994. }
VAR
theColour: RGBColor;
BEGIN
WITH theColour DO
BEGIN
red:= $4444;
green:= red;
blue:= red;
END;
progGetColour:= theColour
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{$IFC application}
PROCEDURE progSetColour (barColour: RGBColor; barPattern: stdPats);
{ Sets the colour or pattern to use for filling the progress bar. The colour is only used }
{ on colour machines, of course; and the pattern is only used on non-colour }
{ machines. Make sure you call this routine before any other prog routine. }
{ Written by David Sinclair, 25 January 1992. }
BEGIN
progColour:= barColour;
progPattern:= barPattern
END;
{$ENDC}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
PROCEDURE progProgressBar (theRect: rect; currentItem, maxItem: longint);
{ Displays a progress bar in the current grafPort or cGrafPort within the }
{ specified rectangle: it uses the pattern to fill the bar, and if a cGrafPort (i.e. }
{ colour is available) it uses the colour specified though the progSetColour }
{ routine also. Pass in currentItem a number within the range 0 maxItem, }
{ and the total number of items in the following field. The bar is calculated by }
{ simply dividing currentItem by maxItem, and filling this percentage of the }
{ rectangle. Use the following routines to automate the process of making a }
{ progress dialog. }
{ Written by David Sinclair, 21 March 1991; colour support added 25 January }
{ 1992; patterns used even when colour used, 22 September 1992; protection }
{ so progress bar canıt draw outside its box, 27 September 1992. }
VAR
oldColour, lightBlue: RGBColor;
thePort: grafPtr;
inColour: boolean;
pnState: penState;
thePat: pattern;
oldRight: integer;
rightReal: real;
BEGIN
getPort(thePort);
IF NOT emptyRect(theRect) & (thePort <> NIL) THEN
BEGIN
WITH thePort^.portBits DO { See IM V-52, fig 3. }
inColour:= BTST(rowBytes, 15) & BTST(rowBytes, 14);
getPenState(pnState);
IF inColour THEN
getForeColor(oldColour);
penNormal;
IF (currentItem >= 0) & (maxItem >= 1) THEN
BEGIN
{$IFC application}
CASE progPattern OF
whitePat:
thePat:= globals.qd.white;
ltGrayPat:
thePat:= globals.qd.ltGray;
grayPat:
thePat:= globals.qd.gray;
dkGrayPat:
thePat:= globals.qd.dkGray;
OTHERWISE
thePat:= globals.qd.black
END;
{$ELSEC}
{ Use this, rather than the built- }
stuffHex(@thePat, 'AA55AA55AA55AA55'); { in gray, so it will work when }
{ QD globals arenıt available. }
{$ENDC}
frameRect(theRect); { Draw the frame around the progress bar }
IF currentItem > 0 THEN
WITH theRect DO
BEGIN
IF inColour THEN
{$IFC application}
RGBForeColor(progColour);
{$ELSEC}
RGBForeColor(progGetColour);
{$ENDC}
penPat(thePat);
oldRight:= right;
insetRect(theRect, 1, 1);
rightReal:= (currentItem / maxItem) * (right - left) + left;
right:= RIntToL(rightReal);
IF right >= oldRight THEN
right:= oldRight - 1;
paintRect(theRect); { Fill in the current progress through the bar }
IF inColour THEN
RGBForeColor(oldColour);
penNormal;
{ moveTo(right, top);}
{ lineTo(right, bottom); { Draw a black line at current position within job ]}
left:= right;
right:= oldRight - 1
END
ELSE
insetRect(theRect, 1, 1); { If currentItem = 0 just erase entire contents }
END;
IF inColour THEN
BEGIN
GetForeColor(oldColour);
lightBlue.red:= $CCCC;
lightBlue.green:= $CCCC;
lightBlue.blue:= $FFFF;
RGBForeColor(lightBlue)
END;
PaintRect(theRect); { Ensure remainder of bar is empty }
IF inColour THEN
RGBForeColor(oldColour);
setPenState(pnState)
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION doProgressEvent (messageDialog: dialogPtr; VAR menuSelection: longint; {}
manageTheCursor: boolean): boolean;
{ Handles the event loop for the progress dialog: moving the dialog and clicking in }
{ the button. Returns true if the button was clicked (or cmd-. pressed), and updates }
{ the current value of inBackground for the application plus the ID & item number }
{ of any menu selections, or 0 if none. You should pass an empty longint and a }
{ boolean constant (of whether to change the cursor to a watch after mouse downs or }
{ not) to this routine. }
{ Written by David Sinclair, 8 & 1415 & 24 November 1991; sysWindow clicks handled }
{ 13 January 1992; inBackground moved to a global 24 January 1992. }
CONST
eventsIWant = everyEvent - diskMask - highLevelEventMask;
delayTicks = 10;
getHighByte = 24; { 24 bits (three bytes) to shift right }
escKeyCode = $35;
homeKeyCode = $73;
endKeyCode = $77;
VAR
otherDialog: DialogPtr;
ignored, cancelled: boolean;
itemType: integer;
itemHandle: handle;
itemBox, boundsRect: rect;
finalTicks: longint;
theEvent: eventRecord;
theWindow: windowPtr;
oldPort: grafPtr;
theControl: controlHandle;
menuID, menuItem: integer;
menuHndl: menuHandle;
accName: str255;
accNumber: integer;
keyPressed: char;
BEGIN
cancelled:= false;
menuSelection:= 0;
IF waitNextEvent(eventsIWant, theEvent, progSleepTime, NIL) THEN
BEGIN
ignored:= isDialogEvent(theEvent); { Call this just to support Balloon Help }
CASE theEvent.what OF
mouseDown: { Mouse click }
BEGIN
CASE findWindow(theEvent.where, theWindow) OF
inSysWindow: { Clicked in a DA window }
systemClick(theEvent, theWindow);
inContent:
IF theWindow <> frontWindow THEN
SysBeep(5)
ELSE
IF theWindow = messageDialog THEN
BEGIN { Clicked in dialog content }
getPort(oldPort);
setPort(messageDialog); { Make sure the dialogıs port is active }
GetDialogItem(messageDialog, iProgButton, itemType, itemHandle, itemBox);
globalToLocal(theEvent.where);
IF findControl(theEvent.where, messageDialog, theControl) <> 0 THEN
IF theControl = controlHandle(itemHandle) THEN { Clicked in the button }
BEGIN
initCursor;
IF trackControl(theControl, theEvent.where, NIL) <> 0 THEN { Lets cancel! }
cancelled:= true;
IF manageTheCursor THEN
setCursor(getCursor(watchCursor)^^)
END;
setPort(oldPort)
END;
inDrag:
IF theWindow = messageDialog THEN
BEGIN { Drag dialog around the screen }
initCursor;
boundsRect:= globals.qd.screenbits.bounds;
insetRect(boundsRect, 4, 4);
dragWindow(theWindow, theEvent.where, boundsRect);
IF manageTheCursor THEN
setCursor(getCursor(watchCursor)^^)
END;
inMenuBar:
BEGIN
initCursor;
menuSelection:= menuSelect(theEvent.where);
menuID:= hiWord(menuSelection);
IF menuID = 0 THEN
menuSelection:= 0
ELSE
BEGIN
menuHndl:= menuHandle(getResource('MENU', menuID));
menuItem:= loWord(menuSelection);
IF menuHndl <> NIL THEN
IF (menuHndl^^.menuData = appleSymbol) & (menuItem > 2) THEN
BEGIN
GetMenuItemText(menuHndl, menuItem, accName);
accNumber:= openDeskAcc(accName);
menuSelection:= 0
END
END;
IF manageTheCursor THEN
setCursor(getCursor(watchCursor)^^)
END;
OTHERWISE
; { Ignore other clicks }
END
END;
keyDown:
BEGIN
getPort(oldPort);
setPort(messageDialog); { Make sure the dialogıs port is active }
keyPressed:= chr(band(theEvent.message, charCodeMask));
{$IFC NOT UNDEFINED player}
{$IFC player}
IF (keyPressed = upChar) | (keyPressed = homeChar) THEN
menuSelection:= $00830001 { i.e. menu ID 131, item 1 }
ELSE IF keyPressed = leftChar THEN
menuSelection:= $00830002
ELSE IF keyPressed = rightChar THEN
menuSelection:= $00830003
ELSE IF (keyPressed = downChar) | (keyPressed = endChar) THEN
menuSelection:= $00830004
ELSE IF keyPressed = space THEN
menuSelection:= $00830006;
IF menuSelection = 0 THEN
{$ENDC}
{$ENDC}
IF (band(theEvent.modifiers, cmdKey) <> 0) | (keyPressed = escChar) THEN
BEGIN { Command-key equiv }
IF (keyPressed = period) | (keyPressed = escChar) THEN
BEGIN { Command-. or Escape pressed }
GetDialogItem(messageDialog, iProgButton, itemType, itemHandle, itemBox);
hiliteControl(controlHandle(itemHandle), 1);
delay(delayTicks, finalTicks);
hiliteControl(controlHandle(itemHandle), 0);
cancelled:= true
END
ELSE
menuSelection:= menuKey(keyPressed) { Menu command-key equiv }
END;
setPort(oldPort)
END;
updateEvt: BEGIN
otherDialog:= WindowPtr(theEvent.message);
IF otherDialog = messageDialog THEN BEGIN { Repaint dialog }
GetPort(oldPort);
SetPort(messageDialog);
BeginUpdate(messageDialog);
DrawDialog(messageDialog);
EndUpdate(messageDialog);
SetPort(oldPort)
END
ELSE IF DlogGetKind(otherDialog)<>foreignKind THEN BEGIN
GetPort(oldPort);
SetPort(otherDialog);
BeginUpdate(otherDialog);
DrawDialog(otherDialog);
EndUpdate(otherDialog);
SetPort(oldPort)
END;
END;
{$IFC application}
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;
{$ENDC}
OTHERWISE
; { Ignore other events }
END
END;
doProgressEvent:= cancelled
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progChangeMessage (messageDialog: dialogPtr; unused: boolean; {}
VAR menuSelection: longint; iconID: integer; topText, bottomText: str255; {}
currentItem, maxItem: longint; manageTheCursor: boolean): boolean;
{ Alters the working message dialog contents to reflect the specified changes. Call }
{ this routine every time through your work loop to update its contents and handle }
{ events (e.g. dragging the window around or context switching). Pass any boolean }
{ value for unused, which does nothing but is there for historical reasons (used to be }
{ inBackground, before that was made into a global variable), and a longint variable }
{ so any menu selections (e.g. Quit, Close, or whatever) are returned to your }
{ application (if not necessary, simply ignore that value)a menuSelection of 0 }
{ mean no menus selected or already handled, and if non-zero the high word }
{ contains the menu ID and the low word the menu item, as from the message field }
{ of the event record. Pass the constant animate for the iconID to automatically handle }
{ animated icons. Pass a zero or null for any items which arenıt to be changed, }
{ except pass ignoreProgressBar for either currentItem or maxItem if you donıt want }
{ to change the position of the progress bar this time. Otherwise, you must always }
{ specify both the current item number and total number of items if you are using a }
{ progress bar. (Note that you can start, stop and restart using the progress bar at any }
{ time, not just when you call progDisplayMessage or progDisplayMsgWindow.) Pass }
{ zero for these two parameters if a progress bar is not being used. You should pass }
{ the same constant for the manageTheCursor parameter as for progDisplayMessage / }
{ progDisplayMsgWindow, but if you change it then make sure you set the cursor to }
{ what you want before calling this routine. Returns false if the cancel button was }
{ clicked, otherwise true. }
{ Original version written by David Sinclair, 21 March 1991; progress text option }
{ added 22 September 1991; ignoreProgressBar option added 2 November 1991; }
{ movable modal dialog implemented 8 November 1991; context switching support }
{ added 14 November 1991; menu item selection handling support added 15 }
{ November 1991; cursor management option added 24 November 1991; specifying }
{ the window type added 23 January 1992; inBackground moved to a global variable }
{ 24 January 1992; changed currentItem and maxItem to longints instead of integers, }
{ changed unused to be a value parameter instead of a var one, and added check that }
{ new top or bottom text is actually different from what it already is, 1213 June 1994. }
VAR
cancelled: boolean;
itemType, ignored, loopy: integer;
itemHandle: handle;
itemBox, progressBox: rect;
oldText: str255;
oldPort: grafPtr;
BEGIN
cancelled:= false;
IF messageDialog <> NIL THEN
BEGIN
getPort(oldPort);
setPort(messageDialog);
{$IFC application}
grafChangeIcon(messageDialog, iProgIcon, iconID); { Update the icon }
{$ENDC}
IF topText <> null THEN { Write the top text }
BEGIN
GetDialogItem(messageDialog, iProgTopText, itemType, itemHandle, itemBox);
GetDialogItemText(itemHandle, oldText);
IF topText <> oldText THEN
SetDialogItemText(itemHandle, topText)
END;
IF (currentItem <> ignoreProgressBar) & (maxItem <> ignoreProgressBar) THEN
BEGIN { Display the progress bar }
GetDialogItem(messageDialog, iProgBar, itemType, itemHandle, progressBox);
IF progressBox.bottom > messageDialog^.portRect.bottom - 5 THEN
maxItem:= 0;
GetDialogItem(messageDialog, iProgButton, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
IF controlHandle(itemHandle)^^.contrlVis <> 255 THEN
IF itemBox.right > progressBox.right THEN
progressBox.right:= itemBox.right; { If button invisible, enlarge progress box }
progProgressBar(progressBox, currentItem, maxItem)
END;
IF bottomText <> null THEN { Write the bottom text }
BEGIN
GetDialogItem(messageDialog, iProgBotText, itemType, itemHandle, itemBox);
GetDialogItemText(itemHandle, oldText);
IF bottomText <> oldText THEN
SetDialogItemText(itemHandle, bottomText)
END;
cancelled:= doProgressEvent(messageDialog, menuSelection, manageTheCursor);
{$IFC application}
{ Dim button if in background }
GetDialogItem(messageDialog, iProgButton, itemType, itemHandle, itemBox);
IF dlogItemIsCtrl(itemType, itemHandle) THEN
IF controlHandle(itemHandle)^^.contrlVis <> 0 THEN { Itıs not invisible }
IF (controlHandle(itemHandle)^^.contrlHilite = 255) & NOT inBackground THEN
hiliteControl(controlHandle(itemHandle), 0)
ELSE IF (controlHandle(itemHandle)^^.contrlHilite <> 255) & inBackground THEN
hiliteControl(controlHandle(itemHandle), 255);
{$ENDC}
setPort(oldPort)
END;
progChangeMessage:= NOT cancelled
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progDisplayMsgWindow (storage: ptr; windowType: integer; {}
VAR position: point; windowTitle: str255; iconID: integer; topText: str255; {}
noOfLines, buttonName: integer; useProgressBar, useProgressText, {}
manageTheCursor: boolean): dialogPtr;
{ Sets up and displays a working message dialog. Pass a pre-declared pointer (as follows): }
{ var workingStorage: dialogRecord; }
{ }
{ theMessage:= progDisplayMsgWindow(@workingStorage, }
{ Also pass a constant defining the type of window you require: movableDBoxProc }
{ and noGrowDocProc are the most likely candidates, or dBoxProc if you donıt want }
{ the user to move the dialog. Pass the top-left position of the dialog, or (0, 0) to use }
{ the default position (see the progRemoveMessage routine, below, for more info); }
{ you should note the value of the position field after returning from this function, }
{ since it may have been adjusted so the dialog fits on the current screenif the }
{ value returned when you close the dialog is different from this position, you }
{ should save that final position in your preferences file (if any). Also pass a title for }
{ the window (if any); the ID of the icon to display, or the constant animate to }
{ automatically handle animated icons; pass the text for the message itself and the }
{ number of lines to allow for top messages (or 0 to allow 2 lines: the minimum), one }
{ of noButton, useCancel, useStop or useQuit constants for the button name (or you }
{ can add your own strings to the relevant STR# resource and use one of them }
{ instead)if you specify noButton, the button will be hidden and the remainder of }
{ the dialog adjusted accordingly (e.g. the progress bar extended or the dialog }
{ shrunken); and also whether or not to display a graphic progress bar, to allow room }
{ for some text below the progress bar and to manage the cursor shape (i.e. keep }
{ cursor as a watch until a mouse down occurs, then change to an arrow). Several }
{ constants are defined to use for these parameters. Returns a pointer to the dialog }
{ for use with progChangeMessage and progRemoveMessage. Note: make sure you }
{ initialise the global variable inBackground (to false) when your application starts }
{ upnon-applications donıt need to worry about this. Also, note: before calling this }
{ routine, you should call the progSetColour procedure (above) to set the colour to }
{ use in the progress bar (you can call that routine even if running on a non-colour }
{ QD machine). Failure to do so will result in unpredictable results on colour }
{ machines. Non-applications should not call progSetColour howeverthe progress }
{ bar will use a default colour. }
{ Old version written by David Sinclair, 21 March 1991; bottom text option added }
{ 22 September 1991; multiple button names option, window title & auto re-positioning }
{ added 8-9 November 1991; cursor management switch added 24 November 1991; icon }
{ not shown yet option added 8 December 1991; dlogExpandingText support added 11 }
{ December 1991; specifying the window type option added 23 January 1992. }
CONST
margin = 15; { Need to allow for width of dialog frame }
TYPE
dialogTemplatePtr = ^dialogTemplate;
dialogTemplateHandle = ^dialogTemplatePtr;
VAR
DLOGHndl: dialogTemplateHandle;
theDialog: dialogPtr;
response: longint;
theButtonName, tempText: str255;
index, itemType: integer;
itemHandle: handle;
itemBox: rect;
totalItems: integer;
ignored: boolean;
oldPos, widthAndHeight: point;
BEGIN
setCursor(getCursor(watchCursor)^^);
IF windowType = movableDBoxProc THEN { Use noGrowDocProc if pre-System 7 }
IF gestalt(gestaltSystemVersion, response) = noErr THEN
IF loWord(response) < $0700 THEN
windowType:= noGrowDocProc
ELSE
ELSE
windowType:= noGrowDocProc;
DLOGHndl:= dialogTemplateHandle(getResource('DLOG', progressDialogID));
IF DLOGHndl <> NIL THEN
DLOGHndl^^.procID:= windowType; { Set the window type }
theDialog:= getNewDialog(progressDialogID, storage, pointer(-1));
IF (resError <> noErr) | (theDialog = NIL) THEN { Major problem! }
resReallyBadError
ELSE
BEGIN
setWTitle(theDialog, windowTitle);
setPort(theDialog);
IF (position.v = 0) & (position.h = 0) THEN
localToGlobal(position); { Convert to glob coords, i.t.o. theDialog }
WITH position, globals.qd.screenbits.bounds DO { Make sure it fits on the current screen }
BEGIN
widthAndHeight:= theDialog^.portRect.botRight; { PortRect is local }
IF v + widthAndHeight.v > bottom THEN { Check bottom & right }
v:= bottom - (widthAndHeight.v + margin);
IF h + widthAndHeight.h > right THEN
h:= right - (widthAndHeight.h + margin);
IF v - margin * 2 < top THEN { Check top & left }
v:= top + margin * 3;
IF h < left THEN
h:= left + margin;
moveWindow(theDialog, h, v, false)
END;
GetDialogItem(theDialog, iProgTopText, itemType, itemHandle, itemBox);
IF noOfLines > 2 THEN { Expand the top text if need more }
BEGIN
tempText:= 'X';
FOR index:= 2 TO noOfLines DO
tempText:= concat(returnChar, tempText);
SetDialogItemText(itemHandle, tempText);
dlogExpandingText(theDialog)
END;
SetDialogItemText(itemHandle, topText);
grafInstallIcon(theDialog, iProgIcon, iconID); { Set the correct icon }
GetDialogItem(theDialog, iProgButton, itemType, itemHandle, itemBox);
IF buttonName = noButton THEN
BEGIN { Hide the button }
hideControl(controlHandle(itemHandle));
IF NOT useProgressBar & NOT useProgressText THEN
theDialog^.portRect.bottom:= theDialog^.portRect.bottom - (itemBox.bottom - itemBox.top)
END
ELSE
BEGIN { Set button name }
getIndString(theButtonName, buttonStringsID, buttonName);
IF theButtonName <> null THEN
SetControlTitle(controlHandle(itemHandle), theButtonName);
hiliteControl(controlHandle(itemHandle), 0)
END;
IF useProgressBar THEN
totalItems:= 10
ELSE
totalItems:= ignoreProgressBar;
IF NOT useProgressText THEN
BEGIN
GetDialogItem(theDialog, iProgBotText, itemType, itemHandle, itemBox);
theDialog^.portRect.bottom:= theDialog^.portRect.bottom - (itemBox.bottom - itemBox.top)
END;
dlogNotifyForAttention;
showWindow(theDialog);
setPort(theDialog);
beginUpdate(theDialog);
drawDialog(theDialog);
endUpdate(theDialog);
ignored:= False;
ignored:= progChangeMessage(theDialog, ignored, response, iconID, topText, null, 0, totalItems, manageTheCursor);
IF manageTheCursor THEN
setCursor(getCursor(watchCursor)^^)
ELSE
initCursor;
progDisplayMsgWindow:= theDialog
END
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progDisplayMessage (storage: ptr; VAR position: point; {}
windowTitle: str255; iconID: integer; topText: str255; noOfLines, {}
buttonName: integer; useProgressBar, useProgressText, {}
manageTheCursor: boolean): dialogPtr;
{ Same as the above routine, but always uses the movable modal dialog if under System }
{ 7.0 or higher, or a standard window if prior to that. See the above routine for details. }
{ Original version written by David Sinclair, 21 March 1991; this patch routine added }
{ 23 January 1992. }
BEGIN
progDisplayMessage:= progDisplayMsgWindow(storage, movableDBoxProc, position, windowTitle, iconID, topText, noOfLines, buttonName, useProgressBar, useProgressText, manageTheCursor)
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progRemoveMessage (messageDialog: dialogPtr): point;
{ Removes the progress dialog once you have finished with it. You will need to call this }
{ routine even if the dialog was cancelled. Returns the top-left co-ordinate of the dialog }
{ as the user left it. You should remember this point and pass it to progDisplayMessage }
{ next time, so the dialog comes up in the same place as before. }
{ Written by David Sinclair, 21 March 1991; return value added 8 November 1991. }
VAR
thePt: point;
BEGIN
IF messageDialog <> NIL THEN
BEGIN
thePt:= messageDialog^.portRect.topLeft;
localToGlobal(thePt);
closeDialog(messageDialog)
END
ELSE
BEGIN
thePt.h:= 0;
thePt.v:= 0
END;
progRemoveMessage:= thePt
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
FUNCTION progGetBottomTextWidth (messageDialog: dialogPtr): integer;
{ Returns the width in pixels of the text field below the progress bar, for use by }
{ strEllipsis to fit text into the space. }
{ Written by David Sinclair, 26 October 1991. }
VAR
itemType: integer;
itemHandle: handle;
itemBox: rect;
BEGIN
GetDialogItem(messageDialog, iProgBotText, itemType, itemHandle, itemBox);
progGetBottomTextWidth:= itemBox.right - itemBox.left
END;
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------}
END.