{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} { } { 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: 8­11 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: 8­9 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: 24­25 Jan 1992 Moved inBackground into a global variable } { and dimmed the button when in the } { background. } { 2.4: 25­27 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: 12­13 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 & 14­15 & 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, 12­13 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 screen‹if 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 } { up‹non-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 however‹the 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.