/* File: DialogUtilities.c Copyright 1993 by Adobe Systems, Inc. C source file for plug-in dialog utilities. */ #include #include #include #include #include "DialogUtilities.h" #include "PITypes.h" #include "PIGeneral.h" /*****************************************************************************/ typedef struct QDVars { char privates[76]; long randSeed; BitMap screenBits; Cursor arrow; Pattern dkGray; Pattern ltGray; Pattern gray; Pattern black; Pattern white; GrafPtr thePort; } QDVars; /*****************************************************************************/ /* The following routine locates the QuickDraw globals. */ static QDVars *GetQDVars (void) { return (QDVars *) ((* (char **) SetCurrentA5 ()) - (sizeof (QDVars) - sizeof (GrafPtr))); } /*****************************************************************************/ /* Set the cursor to the arrow cursor. */ void SetArrowCursor () { QDVars *qd = GetQDVars (); SetCursor (&(qd->arrow)); } /*****************************************************************************/ /* Centers a dialog template 1/3 of the way down on the main screen. */ void CenterDialog (DialogTHndl dt) { #define menuHeight 20 Rect r; short width; short height; QDVars *qd = GetQDVars (); width = qd->screenBits.bounds.right; height = qd->screenBits.bounds.bottom; r = (**dt).boundsRect; OffsetRect (&r, -r.left, -r.top); OffsetRect (&r, (width - r.right) / 2, (height - r.bottom - menuHeight) / 3 + menuHeight); (**dt).boundsRect = r; #undef menuHeight } /*****************************************************************************/ /* Test for Adobe Moveable Modal Dialog if running System 6 */ void SetUpMoveableModal (DialogTHndl dt, OSType hostSig) { long response; if (Gestalt (gestaltSystemVersion, &response) != noErr) response = 0; if (response < 0x0700) { /* Prior to System 7... */ Handle windRes = nil; /* We don't have to release the resource, because opening the dialog will do the right thing with it if it exists. */ if (hostSig == '8BIM') windRes = GetResource ('WDEF', PSmovableDBoxProc/16); if (windRes != NULL) (*dt)->procID = PSmovableDBoxProc; else (*dt)->procID = dBoxProc; /* not moveable, sorry */ } } /*****************************************************************************/ typedef struct ModalData { long oldRefCon; ModalFilterProcPtr filter; ProcessEventProc processEvent; } ModalData; /*****************************************************************************/ /* Some handy ASCII values for keystrokes */ #define RETURN 0x0D #define ENTER 0x03 #define PERIOD '.' #define ESCAPE 0x1B /*****************************************************************************/ /* Event filter to allow movable modal dialogs. */ static pascal Boolean DialogFilter (DialogPtr dp, EventRecord *event, short *item) { Boolean result = FALSE; ModalData *data = (ModalData *) GetWRefCon (dp); if (data->filter) { SetWRefCon (dp, data->oldRefCon); result = (*data->filter) (dp, event, item); data->oldRefCon = GetWRefCon (dp); SetWRefCon (dp, (long) data); if (result) return TRUE; } if (event->what == mouseDown) { /* We have to do window-dragging ourselves */ Point pt = event->where; WindowPtr window; if (FindWindow (pt, &window) == inDrag && window == dp) { Rect bounds = (*GetGrayRgn())->rgnBBox; InsetRect (&bounds, 4, 4); DragWindow (window, pt, &bounds); event->what = nullEvent; } } else if (event->what == keyDown) { /* We have to do button key-equivalents ourselves, now, too */ char ch = event->message & charCodeMask; if (ch == RETURN || ch == ENTER) { *item = ok; FlashDialogButton (dp, ok); result = TRUE; } else if (ch == ESCAPE || (ch == PERIOD && (event->modifiers & cmdKey))) { *item = cancel; FlashDialogButton (dp, cancel); result = TRUE; } } else if (event->what == updateEvt || event->what == activateEvt) { /* Pass updates and activates out to the host */ if (data->processEvent && (event->message != ((long) dp))) (*data->processEvent) (event); } else if (event->what == nullEvent) { /* Let the host idle */ if (data->processEvent) (*data->processEvent) (event); } return result; } /*****************************************************************************/ #ifdef __powerc RoutineDescriptor DialogFilterRDS = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterProcInfo, &DialogFilter); #define DialogFilterRD (&DialogFilterRDS) #else #define DialogFilterRD (&DialogFilter) #endif /*****************************************************************************/ void MoveableModalDialog (DialogPtr dp, ProcessEventProc processEvent, ModalFilterProcPtr filter, short *item) { ModalData data; data.oldRefCon = GetWRefCon (dp); data.filter = filter; data.processEvent = processEvent; SetWRefCon (dp, (long) &data); ModalDialog (DialogFilterRD, item); SetWRefCon (dp, data.oldRefCon); } /*****************************************************************************/ short ShowAlert (short alertID) { Handle alertHandle; short result; alertHandle = GetResource ('ALRT', alertID); HNoPurge (alertHandle); CenterDialog ((DialogTHndl) alertHandle); result = Alert (alertID, nil); HPurge (alertHandle); return result; } /*****************************************************************************/ void ShowAbout (short dialogID) { short item; DialogPtr dp; DialogTHndl dt; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); SetArrowCursor (); ModalDialog (nil, &item); DisposDialog (dp); HPurge ((Handle) dt); } /*****************************************************************************/ /* UserItem to outline the OK button in a dialog box. */ static pascal void OutlineOK (DialogPtr dp, short item) { PenState originalPenState; Rect r; Handle h; short itemType; GetPenState (&originalPenState); item = ok; GetDItem (dp, item, &itemType, &h, &r); PenNormal (); PenSize (3, 3); InsetRect (&r, -4, -4); FrameRoundRect (&r, 16, 16); SetPenState (&originalPenState); } /*****************************************************************************/ #ifdef __powerc RoutineDescriptor OutlineOKRDS = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, &OutlineOK); #define OutlineOKRD (&OutlineOKRDS) #else #define OutlineOKRD (&OutlineOK) #endif /*****************************************************************************/ void SetOutlineOKHook (DialogPtr dp, short hookItem) { short itemType; Rect r; Handle h; GetDItem (dp, hookItem, &itemType, &h , &r); SetDItem (dp, hookItem, itemType, (Handle) OutlineOKRD, &r); } /*****************************************************************************/ /* UserItem to outline a button group box, except for top text */ static pascal void OutlineGroup (DialogPtr dp, short item) { Rect r, rText; Handle h; short itemType; PenState originalPenState; GetPenState (&originalPenState); GetDItem (dp, item+1, &itemType, &h, &rText); /* bounds of surrounding text */ GetDItem (dp, item, &itemType, &h, &r); /* the group box */ PenNormal (); PenSize (1, 1); MoveTo (rText.right, r.top); LineTo (r.right, r.top); LineTo (r.right, r.bottom); LineTo (r.left, r.bottom); LineTo (r.left, r.top); LineTo (rText.left, r.top); SetPenState (&originalPenState); } /*****************************************************************************/ #ifdef __powerc RoutineDescriptor OutlineGroupRDS = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, &OutlineGroup); #define OutlineGroupRD (&OutlineGroupRDS) #else #define OutlineGroupRD (&OutlineGroup) #endif /*****************************************************************************/ /* The following routine sets a user item to be a group box. It expects the next item to be the title for the group box. */ void SetOutlineGroup (DialogPtr dp, short groupItem) { short itemType; Rect r; Handle h; GetDItem (dp, groupItem, &itemType, &h , &r); SetDItem (dp, groupItem, itemType, (Handle) OutlineGroupRD, &r); } /*****************************************************************************/ /* The following routine selects an edit text item. */ void SelectTextItem (DialogPtr dp, short item) { SelIText (dp, item, 0, 32767); } /*****************************************************************************/ /* The following routine sets the text of a text item. */ void StuffText (DialogPtr dp, short item, Str255 text) { Rect r; short itemType; Handle textHdl; GetDItem (dp, item, &itemType, &textHdl, &r); SetIText (textHdl, text); } /*****************************************************************************/ /* The following routine extracts the text of a text item. */ void FetchText (DialogPtr dp, short item, Str255 text) { Rect r; short itemType; Handle textHdl; GetDItem (dp, item, &itemType, &textHdl, &r); GetIText (textHdl, text); } /*****************************************************************************/ /* The following routine stuffs a numeric value into a text field. */ void StuffNumber (DialogPtr dp, short item, long value) { Str255 s; NumToString (value, s); StuffText (dp, item, s); } /*****************************************************************************/ Boolean StringToNumber (Str255 s, long *value) { short i; short j; long x; Boolean negative = FALSE; Boolean isNumber = TRUE; Boolean trailingBlanks = FALSE; for (i = 1, j = 0; i <= Length (s) && isNumber; ++i) { if (j == 0 && s [i] == ' ') ; /* Do nothing: Leading blanks */ else if (j > 0 && s [i] == ' ') trailingBlanks = TRUE; else if (trailingBlanks && s [i] != ' ') isNumber = FALSE; else if (j == 0 && !negative && s [i] == '-') negative = TRUE; else if (s [i] < '0' || s [i] > '9') isNumber = FALSE; else s [++j] = s [i]; } if (j == 0) isNumber = FALSE; else s [0] = (char) j; if (isNumber) { if (j <= 9) StringToNum (s, &x); else x = 0x7FFFFFFF; if (negative) x = -x; *value = x; } return isNumber; } /*****************************************************************************/ /* Here is the corresponding routine to retrieve the value from a text field. It will do range checking and validate that it has been handed a number. If it has not been handed a number, it brings up an appropriate error dialog, inserts an appropriately pinned value, and selects the item. It returns TRUE iff it gets a valid value in the field. */ Boolean FetchNumber (DialogPtr dp, short item, long min, long max, long *value) { #define badNumberID 16990 #define outOfRangeID 16991 Str255 s; long x; Boolean notANumber; FetchText (dp, item, s); notANumber = !StringToNumber (s, &x); if (notANumber || x < min || x > max) { Str255 minText; Str255 maxText; NumToString (min, minText); NumToString (max, maxText); ParamText (minText, maxText, nil, nil); (void) ShowAlert (notANumber ? badNumberID : outOfRangeID); if (!notANumber) { x = (x < min ? min : max); StuffNumber (dp, item, x); } SelectTextItem (dp, item); return FALSE; } else { *value = x; return TRUE; } #undef badNumberID #undef outOfRangeID } /*****************************************************************************/ /* Set the state of a check box (or radio button). */ void SetCheckBoxState (DialogPtr dp, short item, Boolean checkIt) { Rect r; Handle ctl; short itemType; short oldValue, newValue; GetDItem (dp, item, &itemType, &ctl, &r); oldValue = GetCtlValue ((ControlHandle) ctl); newValue = checkIt ? 1 : 0; if (oldValue != newValue) SetCtlValue ((ControlHandle) ctl, newValue); } /*****************************************************************************/ /* Determine the state of a check box (or radio button). */ Boolean GetCheckBoxState (DialogPtr dp, short item) { Rect r; Handle ctl; short itemType; short oldValue; GetDItem (dp, item, &itemType, &ctl, &r); oldValue = GetCtlValue ((ControlHandle) ctl); return (oldValue != 0); } /*****************************************************************************/ /* Set a radio group (from first to last item) to reflect the selection. */ void SetRadioGroupState (DialogPtr dp, short first, short last, short item) { short i; for (i = first; i <= last; ++i) SetCheckBoxState (dp, i, i == item); } /*****************************************************************************/ /* Get the selected radio button in a group. */ short GetRadioGroupState (DialogPtr dp, short first, short last) { short i; for (i = first; i <= last; ++i) if (GetCheckBoxState (dp, i)) return i; return 0; } /*****************************************************************************/ /* Utility routine to disable a control. */ void DisableControl (DialogPtr dp, short item) { Rect r; Handle ctl; short itemType; short oldValue; GetDItem (dp, item, &itemType, &ctl, &r); itemType |= itemDisable; oldValue = GetCtlValue ((ControlHandle) ctl); if (oldValue != 0) SetCtlValue ((ControlHandle) ctl, 0); HiliteControl ((ControlHandle) ctl, 255); SetDItem (dp, item, itemType, ctl, &r); } /*****************************************************************************/ /* Utility routine to enable a control. */ void EnableControl (DialogPtr dp, short item) { Rect r; Handle ctl; short itemType; GetDItem (dp, item, &itemType, &ctl, &r); itemType &= ~itemDisable; HiliteControl ((ControlHandle) ctl, 0); SetDItem (dp, item, itemType, ctl, &r); } /*****************************************************************************/ /* Utility routine to invalidate an item. */ void InvalItem (DialogPtr dp, short item) { Rect r; Handle h; short itemType; GrafPtr oldPort; GetDItem (dp, item, &itemType, &h, &r); GetPort (&oldPort); SetPort (dp); InvalRect (&r); SetPort (oldPort); } /*****************************************************************************/ /* Little routine to flash a button set off by a keystroke. */ void FlashDialogButton (DialogPtr dp, short item) { short itemType; Handle h; Rect r; GetDItem (dp, item, &itemType, &h, &r); if (itemType == (ctrlItem + btnCtrl)) { long ignore; HiliteControl ((ControlHandle) h, 1); Delay (5, &ignore); HiliteControl ((ControlHandle) h, 0); } } /*****************************************************************************/