unit DialogSupport; { DialogSupport.p } { Taken from PixelTools:DialogSupport.c } { Converted: 15-Feb-91 thru 21-Feb-91 } { } { Support routines to display dialogs for NIH Image program } { New List support and hex routines added June, 1991 } interface uses QuickDraw, Printing, Palettes, Resources, Controls, Dialogs, Scrap, Lists, {} VDigitizerDefs, Globals, Utilities; const dsTopOffset = 40; type SliderInfo = record theDialog: DialogPtr; { the dialog } theSlider: ControlHandle; itemNumber: integer; { the number of the item (in dialog) } stepIncrement: integer; { control's value increment for one step } pageIncrement: integer; { control's value increment for one page } scrollTicks: integer; { number of ticks between scroll steps } nextScrollTime: longint; trackHook: ProcPtr; { routine to call when slider value changes } refCon: longint; { reserved for the user } minCtlValue: LongReal; { minimum value for slider control } maxCtlValue: LongReal; { maximum value for slider control } conversionFactor: LongReal; { factor for converting float to int } end; function DSAdjustBounds (boundsRect: Rect): Rect; function DSGetNewDialog (dialogID: Integer; dStorage: Ptr; behind: WindowPtr): DialogPtr; function DSEventFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: integer): Boolean; function DSGetDesk: Rect; function DSListFilterProc (Dlg: DialogPtr; var theEvent: EventRecord; var ItemHit: Integer): Boolean; procedure DSSetIRadio (D: DialogPtr; ItemNmbr: integer; RadioVal: Boolean); procedure DSSetIString (D: DialogPtr; ItemNmbr: integer; StrVal: Str255); procedure DSSetSliderInfo (var sliderI: SliderInfo; theDialog: DialogPtr; itemNumber: integer; stepIncrement: integer; pageIncrement: integer; scrollTicks: integer; trackHook: ProcPtr; refCon: longint; minCtlValue: LongReal; maxCtlValue: LongReal; conversionFactor: LongReal); procedure DSSliderToText (theDialog: DialogPtr; sliderH: ControlHandle; value: integer; valueItemNumber: longint); procedure DSSliderTrackAction (whichControl: ControlHandle; partCode: integer); procedure DSTextToSlider (theDialog: DialogPtr; sliderH: ControlHandle; valueItemNumber: integer); procedure DSTimeSliderToText (theDialog: DialogPtr; sliderH: ControlHandle; value: integer; valueItemNumber: longint); procedure DSTimeTextToSlider (theDialog: DialogPtr; sliderH: ControlHandle; valueItemNumber: integer); procedure HexToString (theNumber: LongInt; var theString: Str255; nDigits: Integer); implementation {----------------------------------------------- } { } { DSAdjustBounds-- } { } { Adjust the bounds rect of a dialog or alert template as follows: } { if the left corner is zero, the window is centered horizontally on } { the screen; if the top corner is zero, the window top is set to just } { below the menu bar. } { } { Arguments: } { boundsRect - the rect to adjust. } { } { Return: } { boundsRect - the adjusted rect. } { } {----------------------------------------------- } function DSAdjustBounds (boundsRect: Rect): Rect; var deskRect: Rect; begin { Get the desk rectangle } deskRect := DSGetDesk; { Adjust the horizontal coordinates. } if (boundsRect.left = 0) then begin boundsRect.left := (deskRect.left + deskRect.right - boundsRect.right) div 2; boundsRect.right := boundsRect.right + boundsRect.left; end; { Adjust the vertical coordinates. } if (boundsRect.top = 0) then begin boundsRect.top := deskRect.top + dsTopOffset; if ((boundsRect.top + boundsRect.bottom) > (deskRect.bottom - dsTopOffset)) then boundsRect.top := (deskRect.top + deskRect.bottom - boundsRect.bottom) div 2; boundsRect.bottom := boundsRect.top + boundsRect.bottom; end; DSAdjustBounds := boundsRect; end; {----------------------------------------------- } { } { DSGetNewDialog-- } { } { Refer to "Inside Macintosh" for a description of "GetNewDialog", } { which is identical this function with the exception that the } { dialog window position is adjusted (DSAdjustBounds.) } { } {----------------------------------------------- } function DSGetNewDialog (dialogID: Integer; dStorage: Ptr; behind: WindowPtr): DialogPtr; var dialog: DialogPtr; template: DialogTHndl; begin { Intialize the result . } dialog := nil; { Get the dialog template .if successful then.. . } template := DialogTHndl(GetResource('DLOG', dialogID)); if (template <> nil) then begin { Lock the template into memory .} MoveHHi(Handle(template)); HLock(Handle(template)); { Adjust the template's bounds rect . } template^^.boundsRect := DSAdjustBounds(template^^.boundsRect); { Build the dialog from the template . } dialog := GetNewDialog(dialogID, dStorage, behind); { Unlock the template . } HUnlock(Handle(template)); end; { Return the result code . } DSGetNewDialog := dialog; end; {----------------------------------------------- } { } { DSHandleSliderClick-- } { Handle a click in any part of a slider, according to which part } { of the slider was hit } { } { Returns TRUE if we handle the event, FALSE if we want ModalDialog } { do go ahead and do its thing with it } { } {----------------------------------------------- } function DSHandleSliderClick (whichControl: ControlHandle; whichPart: integer; where: Point; var itemHit: integer): Boolean; var SliderPtr: ^SliderInfo; {Pointer to a slider's info structure } myTrackControlProc: ControlActionUPP; begin ptr(SliderPtr) := ptr(GetControlReference(whichControl)); { For PPC: Get a routine descriptor for our track control proc so we can call it in a mixed mode environment. } myTrackControlProc := NewControlActionProc(@DSSliderTrackAction); if (whichPart = kControlDownButtonPart) or (whichPart = kControlUpButtonPart) or (whichPart = kControlPageDownPart) or (whichPart = kControlPageUpPart) then begin { the user clicked in the arrows or the trough - - track their actions } itemHit := TrackControl(whichControl, where, myTrackControlProc); DSHandleSliderClick := TRUE; end else { the user clicked in the "thumb ", or in some unkown part - - let ModalDialog process it normally } DSHandleSliderClick := FALSE; end; {----------------------------------------------- } { } { DSEventFilter } { } { This is a standard Dialog Filter Proc as described in Inside Macintosh. } { It performs additional processing such as default key processing and } { slider support. } { } {----------------------------------------------- } function DSEventFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: integer): Boolean; const keyCR = 13; keyENTER = 3; var oldPort: GrafPtr; where: Point; whichControl: ControlHandle; whichPart: integer; sliderI: SliderInfo; result: boolean; SliderPtr: ^SliderInfo; Bkey: SignedByte; itemType: integer; itemHandle: Handle; itemRect: Rect; theText: TEHandle; tick: longint; err: OSErr; begin { Initialize the completion status. } result := FALSE; { Save the current Grafport. } GetPort(oldPort); { Select the dialog's Grafport. } SetPort(theDialog); { Process the event according to event type } case theEvent.what of { Mouse Down event. } mouseDown: begin { The mouse was clicked in the dialog, see if the click was in a slider control. } where := theEvent.where; GlobalToLocal(where); whichPart := FindControl(where, theDialog, whichControl); if (whichPart >= kControlUpButtonPart) and (whichpart <= kControlIndicatorPart) then begin { Verify that this control is one of our sliders } ptr(SliderPtr) := ptr(GetControlReference(whichControl)); if (SliderPtr^.theSlider = whichControl) then result := DSHandleSliderClick(whichControl, whichPart, where, itemHit); end; end; { Key Down event. } keyDown: begin { Looking for or } Bkey := SignedByte(theEvent.message); if Bkey in [keyCR, keyENTER] then begin { If the default item is a control then ... } GetDialogItem(theDialog, DialogPeek(theDialog)^.aDefItem, itemType, itemHandle, itemRect); { Flash the control. } HiliteControl(ControlHandle(itemHandle), 1); Delay(6, tick); HiliteControl(ControlHandle(itemHandle), 0); { Signal dialog termination . } itemHit := DialogPeek(theDialog)^.aDefItem; result := TRUE; end { Looking for a Command Key } else if BAnd(theEvent.modifiers, cmdKey) <> 0 then begin theText := DialogPeek(theDialog)^.textH; if (DialogPeek(theDialog)^.editField >= 0) and (theText <> nil) then begin { Check for Cut Command } if (Bkey = SignedByte('x')) or (Bkey = SignedByte('X')) then begin { Make sure text is selected } if (theText^^.selEnd > theText^^.selStart) then begin { Clear the desk scrap. } err := ZeroScrap; { Perform the cut operation. } DialogCut(theDialog); { Update the desk scrap. } err := TEToScrap; end; end; { Check for Copy Command } if (Bkey = SignedByte('c')) or (Bkey = SignedByte('C')) then begin { Make sure text is selected } if (theText^^.selEnd > theText^^.selStart) then begin { Clear the desk scrap. } err := ZeroScrap; { Perform the copy operation. } DialogCopy(theDialog); { Update the desk scrap. } err := TEToScrap; end; end; { Check for Paste Command } if (Bkey = SignedByte('v')) or (Bkey = SignedByte('V')) then begin { Get the text from the desk scrap. } err := TEFromScrap; { Perform the paste operation. } DialogPaste(theDialog); end; { Disable dialog manager processing for this event and force a return to the application. } itemHit := DialogPeek(theDialog)^.editField + 1; result := TRUE; end; { If no command was decoded from the key then change the event to a null event } { so that the key stroke is ignored . } if (result <> true) then theEvent.what := nullEvent; end; end; { Auto Key event. } autoKey: begin end; { Window activate. } activateEvt: begin end; { Window update event. } updateEvt: begin end; { Any other eventÉ } otherwise { Restore the Grafport. } SetPort(oldPort); { Return the event status. } end; DSEventFilter := result; end; {----------------------------------------------- } { } { DSGetDesk-- } { } { Get the rectangle that encloses the desk top on the main screen. } { It is the boundary of the intersection of the main device's region } { and the desktop's (GrayRgn) region. } { } {----------------------------------------------- } function DSGetDesk: Rect; var deviceRect: Rect; deviceRgn, deskRgn: RgnHandle; devGDHdl: GDHandle; begin devGDHdl := GetMainDevice; deviceRect := devGDHdl^^.gdRect; deviceRgn := NewRgn; if (deviceRgn = nil) then DSGetDesk := deviceRect else begin RectRgn(deviceRgn, deviceRect); deskRgn := GetGrayRgn; SectRgn(deviceRgn, deskRgn, deviceRgn); DSGetDesk := deviceRgn^^.rgnBBox; DisposeRgn(deviceRgn); end; end; {----------------------------------------------- } { } { DSListFilterProc } { } { This is a standard List Manager Filter Proc. } { } {----------------------------------------------- } function DSListFilterProc (Dlg: DialogPtr; var theEvent: EventRecord; var ItemHit: Integer): Boolean; var where: Point; theList: ListHandle; rView: Rect; begin DSListFilterProc := false; where := theEvent.where; GlobalToLocal(where); theList := ListHandle(WindowPeek(Dlg)^.refCon); rView := theList^^.rView; rView.right := rView.right + 20; if theEvent.what = mouseDown then if PtInRect(where, rView) then if LClick(where, theEvent.modifiers, theList) then begin itemHit := 1; DSListFilterProc := true; end; end; {----------------------------------------------- } { } { DSSetIRadio-- } { Set the radio button value corresponding to a dialog item } { } {----------------------------------------------- } procedure DSSetIRadio (D: DialogPtr; ItemNmbr: integer; RadioVal: Boolean); var ItemType: integer; ItemHndl: Handle; ItemBox: Rect; begin GetDialogItem(D, ItemNmbr, ItemType, ItemHndl, ItemBox); SetControlValue(ControlHandle(ItemHndl), integer(RadioVal)); end; {----------------------------------------------- } { } { DSSetIString-- } { Set the string value corresponding to a dialog item } { } { NOTE: assumes that the item is either editable text, static text, } { or a control } { } {----------------------------------------------- } procedure DSSetIString (D: DialogPtr; ItemNmbr: integer; StrVal: Str255); var ItemType: integer; ItemHndl: Handle; ItemBox: Rect; begin GetDialogItem(D, ItemNmbr, ItemType, ItemHndl, ItemBox); if (BAnd(ItemType, ctrlItem) <> 0) then SetControlTitle(ControlHandle(ItemHndl), StrVal) else SetDialogItemText(ItemHndl, StrVal); end; {----------------------------------------------- } { } { DSTextToSlider-- } { Convert a new text value to a slider position } { } { DSSliderToText-- } { Convert a new slider position into an text value } { } {----------------------------------------------- } procedure DSTextToSlider (theDialog: DialogPtr; sliderH: ControlHandle; valueItemNumber: integer); var value: LongReal; temp: longint; begin value := GetDReal(theDialog, valueItemNumber); temp := round(1000 * value); SetControlValue(sliderH, integer(temp)); end; procedure DSSliderToText (theDialog: DialogPtr; sliderH: ControlHandle; value: integer; valueItemNumber: longint); var itemText: Str255; exposureTime: LongReal; begin { PStrPrintf ( itemText , "% .3f", ( float ) value / 1000.0 ); } itemText := StringOf(LongReal(value / 1000) : 5 : 3); SetDString(theDialog, valueItemNumber, itemText); SelectDialogItemText(theDialog, valueItemNumber, 0, gMaxInt); end; {----------------------------------------------- } { } { DSSetSliderInfo-- } { Attach a slider info structure to a particular slider and } { set all the fields in the info structure. } { } { NOTE: each slider must have its own slider info structure-- } { the info structures can't be shared } { } {----------------------------------------------- } procedure DSSetSliderInfo (var sliderI: SliderInfo; { the slider's info structure } theDialog: DialogPtr; { the dialog } itemNumber: integer; { the number of the item (in dialog) } stepIncrement: integer; { control's value increment for one step } pageIncrement: integer; { control's value increment for one page } scrollTicks: integer; { number of ticks between scroll steps } trackHook: ProcPtr; { routine to call when slider value changes } refCon: longint; { reserved for the user } minCtlValue: LongReal; { slider minimum value } maxCtlValue: LongReal; { slider maximum value } conversionFactor: LongReal); { factor for converting float value to int } var itemType: integer; itemBox: Rect; itemText: Str255; SliderH: ControlHandle; begin { get the slider's handle and set this slider info structure as its refCon } GetDialogItem(theDialog, itemNumber, itemType, handle(SliderH), itemBox); SetControlReference(SliderH, longint(@sliderI)); { set all the fields in the slider info structure } sliderI.theDialog := theDialog; sliderI.theSlider := SliderH; sliderI.itemNumber := itemNumber; if stepIncrement > 0 then sliderI.stepIncrement := stepIncrement else sliderI.stepIncrement := 1; if pageIncrement > 0 then sliderI.pageIncrement := pageIncrement else sliderI.pageIncrement := 10; if scrollTicks > 0 then sliderI.scrollTicks := scrollTicks else sliderI.scrollTicks := 8; sliderI.nextScrollTime := 0; sliderI.trackHook := trackHook; sliderI.refCon := refCon; sliderI.minCtlValue := minCtlValue; sliderI.maxCtlValue := maxCtlValue; sliderI.conversionFactor := conversionFactor; end; {----------------------------------------------- } { } { DSSliderTrackAction-- } { This is an action routine for TrackControl, handling tracking of } { a slider's arrow keys and page (trough) movements. } { } {----------------------------------------------- } procedure DSSliderTrackAction (whichControl: ControlHandle; partCode: integer); var value: integer; { the slider's current value } sliderI: SliderInfo; { the slider's info structure } tick: longint; { tock } oldValue, minValue, maxValue: integer; trackHook: ProcPtr; SliderPtr: ^SliderInfo; {Pointer to a slider's info structure } begin ptr(SliderPtr) := ptr(GetControlReference(whichControl)); { if the minimum time has not passed since the last time the slider was scrolled, } { just return (initially, nextScrollTime is zero, so the first scroll is immediate) } tick := TickCount; if (tick > SliderPtr^.nextScrollTime) then begin SliderPtr^.nextScrollTime := tick + SliderPtr^.scrollTicks; { fetch the slider's current value } value := GetControlValue(whichControl); oldvalue := value; { handle the click according to which part of the control was hit } case partCode of kControlDownButtonPart: value := value + SliderPtr^.stepIncrement; { the user clicked in the 'up' arrow-- increment by a step } kControlUpButtonPart: value := value - SliderPtr^.stepIncrement; { the user clicked in the 'down' arrow-- decrement by a step } kControlPageDownPart: value := value + SliderPtr^.pageIncrement; { the user clicked in the page up trough-- increment by a page } kControlPageUpPart: value := value - SliderPtr^.pageIncrement; { the user clicked in the page down trough-- decrement by a page } end; { make sure we don't take the slider's value past the "ends" } minValue := GetControlMinimum(whichControl); maxValue := GetControlMaximum(whichControl); if (value < minValue) then value := minValue; if (value > maxValue) then value := maxValue; { update the slider's value, and notify the hook routine that the value has changed } if (value <> oldValue) then begin SetControlValue(whichControl, value); if (SliderPtr^.trackHook = @DSSliderToText) then DSSliderToText(SliderPtr^.theDialog, whichControl, value, SliderPtr^.refCon) else if (SliderPtr^.trackHook = @DSTimeSliderToText) then DSTimeSliderToText(SliderPtr^.theDialog, whichControl, value, SliderPtr^.refCon); end; end; end; { End of SliderTrackAction } { DSTimeTextToSlider--} { Convert a new 'exposure time' text value to a slider position} procedure DSTimeTextToSlider (theDialog: DialogPtr; sliderH: ControlHandle; valueItemNumber: integer); var value: longint; exposureTime, conversionFactor: LongReal; SliderPtr: ^SliderInfo; {Pointer to a slider's info structure } begin ptr(SliderPtr) := ptr(GetControlReference(sliderH)); conversionFactor := SliderPtr^.conversionFactor; exposureTime := GetDReal(theDialog, valueItemNumber); value := longint(round(exposureTime / conversionFactor) - 32768); if value < -32768 then value := -32768 else if value > gMaxInt then value := gMaxInt; SetControlValue(sliderH, integer(value)); end; { DSTimeSliderToText--} { Convert a new slider position into an 'exposure time' text value} procedure DSTimeSliderToText (theDialog: DialogPtr; sliderH: ControlHandle; value: integer; valueItemNumber: longint); var itemText: Str255; exposureTime, conversionFactor: LongReal; SliderPtr: ^SliderInfo; {Pointer to a slider's info structure } begin ptr(SliderPtr) := ptr(GetControlReference(sliderH)); conversionFactor := SliderPtr^.conversionFactor; exposureTime := LongReal((longint(value) + 32768) * conversionFactor); itemText := StringOf(exposureTime : 8 : 3); SetDString(theDialog, valueItemNumber, itemText); SelectDialogItemText(theDialog, valueItemNumber, 0, gMaxInt); end; procedure HexToString; { (theNumber:LongInt; var theString:Str255; nDigits:Integer) } var str1, str2: Str255; theChar: char; digit: LongInt; i: Integer; begin str1 := ''; str2 := '0123456789ABCDEF'; nDigits := nDigits - 1; for i := 0 to nDigits do begin digit := BSR(theNumber, 4 * (nDigits - i)); digit := BAND(digit, $0000000F); str1 := concat(str1, str2[digit + 1]); end; theString := str1; end; end.