TweetFollow Us on Twitter

Fancy Dialogs
Volume Number:7
Issue Number:6
Column Tag:MacOOPs!

Related Info: Dialog Manager Standard File

Fancy Modal Dialogs

By Thomas Engel, Loma Linda, CA

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

[Thomas Engel is a practicing anesthesiologist. He has been writing computer simulations in physics, biology and physiology since 1975 and programming the Macintosh since 1986.]

Introduction

Most Macintosh programs use modal dialogs to convey information and get user input. Whenever you pick an About , Open , Save As , Page Setup or Print menu item you see a modal dialog. Error alerts and status messages are also forms of modal dialogs. The Dialog Manager handles events for each dialog separately from the application’s main event loop. Because the events are handled separately, the programmer must duplicate event loop code or rely on the Dialog Manager’s default behavior. Dialogs also have several unique features that require special consideration.

The Dialog Manager’s default behavior is not complete and does not provide many standard Macintosh user interface features or subtle nuances. Many applications do not provide these either. Although printer drivers and Standard File take care of most details for their dialogs, you are on your own for any others. Object-oriented programming can provide these features in a consistent way, with a minimum of programming effort.

This article discusses some fine points of programming modal dialogs for the Macintosh and presents a complete modal dialog class, subclasses and resources for six useful dialogs and a short program to demonstrate each dialog. The dialog class is written in Object Pascal with THINK Pascal 3.0, and should be portable to other environments.

Dialog Basics

A dialog is a specialized window managed by the Dialog Manager. A dialog is accessed by a DialogPtr like a window is accessed with a WindowPtr. The corresponding DialogPeek is a pointer to a DialogRecord. To access the DialogRecord fields, typecast the DialogPtr variable to a DialogPeek like this:

{1}

var
 toolboxDialog: DialogPtr;
 editItem: Integer;

editItem := DialogPeek(toolboxDialog)^.editField
 + 1;

The dialog record contains a WindowRecord and additional fields, including a handle to the dialog’s item list. A dialog is usually created from a “DLOG” resource; its items are created from a “DITL” resource. These resources contain templates for the dialog and its items and are created with a resource editing program like ResEdit.

The item list handle contains data for the dialog items. Dialog items include controls like buttons, check boxes, and radio buttons; static and editable text fields; icons; QuickDraw pictures and user items. The item list keeps an Integer item type, item Rect and a Handle for each item. The contents of the handle depends on the item’s type. Control items have a ControlHandle, text items have a handle to the text characters, an icon item has a handle to its icon, a picture item has a PicHandle, and each user item has a ProcPtr stored in place of its item handle.

To use a modal dialog, first create it with the toolbox routine GetNewDialog and set up its user items and fill in default values for text fields if necessary. Then repeat calls to ModalDialog to handle update, activate and user generated events until ModalDialog returns with an acceptable item hit. Then call DisposDialog. Here is an example:

{2}

var
 toolboxDialog: DialogPtr;
 itemHit: Integer;

toolboxDialog:= GetNewDialog(DialogID, nil, WindowPtr(-1));
{ Set user items and fill in text items. }
ShowWindow(toolboxDialog);
InitCursor;
repeat
 ModalDialog(@Filter, itemHit);
until (itemHit = OK) or (itemHit = Cancel);
DisposDialog(toolboxDialog);

The dialog manager provides two ways to modify the behavior of Modal Dialogs: an event filter procedure can intercept events for special handling and a user item procedure can draw a special dialog item.

A filter procedure gets each event from the Dialog Manager along with the item hit. The filter procedure returns true if it handles the event or false for the Dialog Manager to handle it. The filter procedure can change the event or item hit before returning to the Dialog Manager. An event filter procedure looks like this:

{3}

function Filter( toolboxDialog: DialogPtr;
 var theEvent: EventRecord;
 var itemHit: Integer): Boolean;

A user item procedure draws the item. The dialog manager calls it automatically for update events. If you want something to happen when the user clicks in a user item, you must handle that with the event filter procedure. (See Tech Note 34, User Items in Dialogs.) A user item procedure looks like this:

{4}

procedure User(toolboxDialog: DialogPtr;
 var itemHit: Integer);

Use GetDItem, SetDItem and a typecast to store a pointer to the user procedure in the item list before calling ModalDialog.

{5}

var
 itemType: Integer;
 itemRect: Rect;
 itemHandle: Handle;

GetDItem(toolboxDialog, theItem, itemType,
 itemRect, itemHandle);
SetDItem(toolboxDialog, theItem, itemType,
 itemRect, Handle(@User));

Standard File uses special user items and an event filter procedure for its scrolling file list and folder hierarchy pop-up menu in Open (SFGetFile) and Save As (SFPutFile) dialogs.

Aesthetics

The Dialog Manager’s default behavior includes drawing the dialog items in response to update events, hit testing items, highlighting buttons and selecting the first item if the user presses the return key. Apple recommends additional standard behavior that the Dialog Manager doesn’t handle.

A dialog should be centered near the top of the main screen (the one with the menu bar). Because the Macintosh supports a variety of screens with different sizes, this feature requires calculation of the dialog’s position at run time.

The dialog should draw an outline 3 pixels wide around the default button to indicate which button is the default. Apple recommends making a user item to do this, but this makes changing the default button awkward. Alternatively, a filter procedure can take over update events to draw the outline and any other embellishments along with the dialog items.

When the user presses the return key or enter key the default button should be selected; when the user presses command-period the cancel button should be selected. The dialog should highlight the button for a fraction of a second to give the user feedback about the keyboard selection instead of just disappearing with no other indication of the action. Turn the button’s highlight off before dismissing the dialog. This is similar to the blinking of menu items with mouse selection.

Radio buttons are grouped in sets; when the user selects one, the others in the set should be deselected. This may be done in a filter procedure or the repeat until loop that calls ModalDialog.

The dialog should select all the text of the default edit text field when the dialog is first shown. This tells the user where any typing will go and lets the user quickly replace the entire item’s text by only typing. The dialog should support Cut, Copy, Paste and Clear command key equivalents for edit text. The dialog should select all of the text in the next edit text field when the user presses the tab key and all of the text in the previous field when the user presses shift-tab. The dialog should also show the I-beam cursor when the cursor is over the current edit text item.

Because each dialog has different items, each usually requires its own special event filter and user items. These procedures are usually specific to the dialog and cannot be reused easily. Object-oriented programming provides a way to organize these general dialog features in one place and create specialized dialogs without rewriting all the code.

Dialog Class

An object has a type called its class. Each object is allocated with the built-in procedure New and is referred to by a reference variable. Classes are similar to records and are declared as types with the keyword object. The class defines instance variables (data) and methods (procedures and functions). Instance variables are like fields in a record.

A class may be declared as a subclass of a previously defined class; the previously defined class is its superclass. A subclass inherits all the instance variables and methods of its superclass and can add more instance fields and methods. The subclass can also modify the action of a method by overriding it. The new subclass method can call the superclass method with the keyword inherited. This article presents a general modal dialog class called TDialog and subclasses for several specific dialogs.

The TDialog class handles almost all of the features common to modal dialogs. To use TDialog, write a subclass for a specific dialog. The subclass will inherit basic and fancy dialog behavior from TDialog.

TDialog defines instance variables for its DialogPtr, DialogPeek and item count; its default item, cancel item and default text item; and the set of items that dismiss the dialog. This is its declaration:

{6}

type
 DialogItemSet = set of 1..255;

 TDialog = object
 toolboxDialog: DialogPtr;
 toolboxDPeek: DialogPeek;
 itemCount: Integer;
 defaultItem, cancelItem, defaultText: Integer;
 dismissSet: DialogItemSet;
 procedure IDialog(dialogID: Integer;
 default, cancel, text: Integer;
 dismiss: DialogItemSet; centered: Boolean);
 procedure Free;
 procedure Center;
 function Show: Integer;
 procedure Hide;
 function EventFilter( var theEvent: EventRecord;
 var itemHit: Integer): Boolean;
 procedure FixCursor;
 procedure Command(ch: Char; var itemHit: Integer);
 procedure Hit(var itemHit: Integer);
 procedure Draw;
 procedure DrawDefault;
 procedure DrawBox(itemSet: DialogItemSet;
 margin, thickness: Integer);
 procedure DrawTitleBox( itemSet: DialogItemSet;
 margin, thickness: Integer; title: Str255);
 procedure FlashItem(item: Integer);
 function GetText(item: Integer): Str255;
 procedure SetText(item: Integer; text: Str255);
 function GetInteger(item: Integer): Longint;
 procedure SetInteger(item: Integer; value: Longint);
 function GetReal(item: Integer): Extended;
 procedure SetReal(item: Integer;
 value: Extended; places: Integer);
 function GetControlValue( item: Integer): Integer;
 procedure SetControlValue(item: Integer; value: Integer);
 function GetControlTitle( item: Integer): Str255;
 procedure SetControlTitle(item: Integer; title: Str255);
 function GetRadioItem(
 radioSet: DialogItemSet): Integer;
 procedure SetRadioItem( radioSet: DialogItemSet;
 itemSelected: Integer);
 procedure SetIcon(item: Integer; iconID: Integer);
 procedure SetPicture(item: Integer; pictureID: Integer);
 procedure SetUserItem(item: Integer; userProc: ProcPtr);
 end;

Methods

The methods for TDialog do almost all of the work of managing modal dialogs.

TDialog.IDialog initializes the dialog. It accepts parameters for the DLOG template ID, default item (enter key, return key), cancel item (command-period), default text item, and the set of items that dismiss the dialog. If centered is true, the dialog will be centered on the main screen, otherwise it will remain in the position specified in the DLOG template. Each subclass of TDialog should know all of these parameters and pass them to IDialog.

TDialog.Free calls DisposDialog to release the dialog resources and then DisposHandle(Handle(self)).

TDialog.Center centers the dialog on the main screen.

TDialog.Show shows the dialog on the screen and calls ModalDialog to get dialog events. TDialog.Show calls TDialog.Hit for each item hit; when the user hits an item in the dismiss set, TDialog.Show returns with the item number.

Override TDialog.Hit to handle special items. TDialog.Hit can call TDialog.SetRadioItem to select the appropriate radio button. The default TDialog.Hit does nothing.

TDialog.EventFilter handles events for the dialog. It is called by DialogFilter. DialogFilter is a global procedure passed to ModalDialog because methods may not be passed as parameters. TDialog.EventFilter handles default, cancel and tab keys and update events. It calls TDialog.FixCursor to change the cursor, TDialog.Command for keyboard commands and TDialog.Draw to draw the dialog. TDialog.EventFilter returns true if it handled the event, and false to let the dialog manager handle it.

TDialog.FixCursor changes the shape of the cursor based on its location. The default method checks to see if the cursor is over the current edit text item; if it is, the method changes the cursor to the I-beam, otherwise it calls InitCursor.

TDialog.GetText and TDialog.SetText get and set the item text by calling the toolbox routines GetIText and SetIText. TDialog.SetText will select all the text if it changes the current edit text item. TDialog.GetInteger, TDialog.SetInteger, TDialog.GetReal and TDialog.SetReal are based on these calls.

Override TDialog.Draw to draw anything not drawn by the Dialog Manager. The default version calls TDialog.DrawDefault to draw a three pixel wide outline around the default button. You can also call TDialog.DrawBox to draw a box around any set of items. TDialog.DrawTitleBox draws the box with a title. These methods work correctly even if you later change the position or size of the dialog items. TDialog.Draw is called for every update event the dialog receives.

TDialog.Command handles keyboard commands. The default version calls the toolbox routines DlgCut, DlgCopy, DlgPaste and DlgClear. Override this method to add other keyboard commands.

TDialog.GetControlTitle, TDialog.SetControlTitle, TDialog.GetControlValue and TDialog.SetControlValue manage control items. Use these methods to change button titles and values.

Radio groups are handled by item number in sets. TDialog.SetRadioItem highlights the selected radio button and sets the highlight of the other buttons in the set to off. TDialog.GetRadioItem gets the item number of the highlighted radio button. These methods call TDialog.GetControlValue and TDialog.SetControlValue.

TDialog.FlashItem highlights a button for a few ticks to provide user feedback on the item selected with the keyboard.

TDialog.SetIcon and TDialog.SetPicture set dialog icon and picture items from resources. Neither of these methods release the memory used by a replaced icon or picture.

The Specifics

The THINK Pascal project document is “Dialog Project” and resources are in “Dialogs.rsrc.” A SADerez version of the resources is in the file “Dialogs.r”. The dialog project consists of three source code files: global declarations and variables are in the file “DialogGlobals.p”, the methods for TDialog and its subclasses are in “TDialog.p” and a short main program to display each dialog is in the file “Test Dialogs.p”.See figure 1.

Figure 1

DialogGlobals.p defines six subclasses of TDialog. Each of them inherits most of its features from TDialog. These subclasses serve as examples of customizing TDialog and are useful by themselves. The six subclasses are TAboutDialog, TMessageDialog, TStringDialog, TYesNoDialog, TYesNoCancelDialog, TFontSizeDialog and TMarginsDialog.

TAboutDialog shows an About box with the free memory in K bytes. TMessageDialog shows a message string to the user. TYesNoDialog and TYesNoCancelDialog ask the user a question, and TStringDialog gets a string from the user. TFontSizeDialog lets the user enter a font size, and TMarginsDialog gets page margins from the user. TStringDialog, TFontSizeDialog and TMarginsDialog each have GetData and SetData methods to handle all the user data at one time.

TMarginsDialog is the most complicated class. It contains edit text fields for the top, bottom, left and right margins expressed as real numbers and a radio button set for the unit of measure. TMarginsDialog.Draw calls TDialog.DrawTitleBox to frame the radio button set. See figure 2.

Figure 2

Create a dialog object with the built-in procedure New, call its initialization method and then its Show method. When you are done with the dialog dispose of it by calling its Free method. Here is an example:

{7}

var
 theDialog: TMessageDialog;
 itemHit: Integer;

New(theDialog);
theDialog.IMessageDialog(‘Hi there!’, NoteIcon);
itemHit := theDialog.Show;
theDialog.Free;

Improvements

Make your own dialogs by defining subclasses to TDialog or one of its subclasses. Your subclass will use a different dialog template resource ID and may have new specialized methods.

You may improve your dialog class by adding routines to manage scrolling lists or pop-up menus (pop-up menus may be easier when Apple releases a standard Pop-up CDEF). Override TDialog.Filter to handle mouse down events for these items. The event filter method may be improved to handle cancel commands on international keyboards. (See Tech Note 263, International Canceling.)

You may add methods for entry validation. You may also override TDialog.Filter or TDialog.FixCursor to do animation in the dialog. These methods are called each time the dialog gets an event.

If you are already using a class hierarchy, you can make TDialog a subclass of a basic class like TObject. Change TDialog.Free to call inherited Free instead of DisposHandle(Handle(self)).

Further Reading

Apple Computer. Inside Macintosh, Volumes 1-5. Reading, Massachusetts, Addison-Wesley Publishing Company, Inc., 1986. The primary reference for Macintosh programming.

Apple Computer. ResEdit Reference. Reading, Massachusetts, Addison-Wesley Publishing Company, Inc., 1990. Information on editing DLOG and DITL resources.

Chernicoff, S. Macintosh Revealed, Volumes 1-4. Carmel, Indiana, Hayden Books, 1990. An excellent introduction to programming the Macintosh with Pascal.

Knaster, S. Macintosh Programming Secrets. Reading, Massachusetts, Addison-Wesley Publishing Company, Inc., 1988. Contains a discussion on customizing dialogs.

Symantec Corporation. THINK Pascal Object-oriented Programming Manual. Cupertino, California, Symantec Corporation, 1990. Contains an excellent explanation of object-oriented programming with Object Pascal.

Listing: DialogGlobals.p

{ Written by Thomas Engel, M.D. }
{ Copyright © 1991 MacTutor. }

unit Globals;

interface

const

 { Special Characters. }

 EnterCh = Chr(3);
 BackSpaceCh = Chr(8);
 TabCh = Chr(9);
 ReturnCh = Chr(13);

 { Dialog resource IDs. }

 AboutID = 128;
 MessageID = 129;
 StringID = 130;
 YesNoID = 131;
 YesNoCancelID = 132;
 FontSizeID = 133;
 PageMarginsID = 134;

 { Dialog item numbers. }

 OKButton = 1;
 CancelButton = 2;
 YesButton = 1;
 NoButton = 3;

 { Miscellaneous. }

 ControlOn = 1;
 ControlOff = 0;
 ControlActive = 0;
 ControlInactive = 255;
 FlashTicks = 10;
 AfterTicks = 2;
 IBeamID = 1;
 WatchID = 4;

type
 IntegerPtr = ^Integer;
 IntegerHandle = ^IntegerPtr;
 LongintPtr = ^Longint;
 LongintHandle = ^LongintPtr;

 MeasureOption = (inches, cm, points);

 MarginRecord = record
 left, top, right, bottom: Single;
 measure: MeasureOption;
 end;

 DialogItemSet = set of 0..255;

 TDialog = object
 toolboxDialog: DialogPtr;
 toolboxDPeek: DialogPeek;
 itemCount: Integer;
 defaultItem, cancelItem,
 defaultText: Integer;
 dismissSet: DialogItemSet;
 procedure IDialog(dialogID: Integer;
 default, cancel, text: Integer;
 dismiss: DialogItemSet; centered: Boolean);
 procedure Free;
 procedure Center;
 function Show: Integer;
 procedure Hide;
 function EventFilter(
 var theEvent: EventRecord;
 var itemHit: Integer): Boolean;
 procedure FixCursor;
 procedure Command(ch: Char;
 var itemHit: Integer);
 procedure Hit(var itemHit: Integer);
 procedure Draw;
 procedure DrawDefault;
 procedure DrawBox(itemSet: DialogItemSet;
 margin, thickness: Integer);
 procedure DrawTitleBox(
 itemSet: DialogItemSet;
 margin, thickness: Integer; title: Str255);
 procedure FlashItem(item: Integer);
 function GetText(item: Integer): Str255;
 procedure SetText(item: Integer;
 text: Str255);
 function GetInteger(item: Integer): Longint;
 procedure SetInteger(item: Integer;
 value: Longint);
 function GetReal(item: Integer): Extended;
 procedure SetReal(item: Integer;
 value: Extended; places: Integer);
 function GetControlValue(
 item: Integer): Integer;
 procedure SetControlValue(item: Integer;
 value: Integer);
 function GetControlTitle(
 item: Integer): Str255;
 procedure SetControlTitle(
 item: Integer; title: Str255);
 function GetRadioItem(
 radioSet: DialogItemSet): Integer;
 procedure SetRadioItem(
 radioSet: DialogItemSet;
 itemSelected: Integer);
 procedure SetIcon(item: Integer;
 iconID: Integer);
 procedure SetPicture(item: Integer;
 pictureID: Integer);
 procedure SetUserItem(item: Integer;
 userProc: ProcPtr);
 end;

 TAboutDialog = object(TDialog)
 procedure IAboutDialog;
 function Show: Integer;
 override;
 end;

 TMessageDialog = object(TDialog)
 procedure IMessageDialog(message: Str255;
 iconID: Integer);
 procedure SetMessage(message: Str255);
 end;

 TStringDialog = object(TDialog)
 procedure IStringDialog(
 prompt, default: Str255);
 procedure SetData(prompt, default: Str255);
 procedure GetData(var response: Str255);
 end;

 TYesNoDialog = object(TDialog)
 procedure IYesNoDialog(
 prompt: Str255; default: Integer);
 procedure SetPrompt(prompt: Str255);
 end;

 TYesNoCancelDialog = object(TDialog)
 procedure IYesNoCancelDialog(prompt: Str255;
 default: Integer);
 procedure SetPrompt(prompt: Str255);
 end;

 TMarginsDialog = object(TDialog)
 measureSet: DialogItemSet;
 procedure IMarginsDialog(
 defaultMargins: MarginRecord);
 procedure Draw;
 override;
 procedure Hit(var itemHit: Integer);
 override;
 procedure SetData(newMargins: MarginRecord);
 procedure GetData(
 var theMargins: MarginRecord);
 end;

 TFontSizeDialog = object(TDialog)
 procedure IFontSizeDialog(
 defaultSize: Integer);
 procedure SetData(fontSize: Integer);
 procedure GetData(var fontSize: Integer);
 end;

var
 IBeam, Watch: CursHandle;

procedure ShowAbout;
procedure ShowMessage(message: Str255);
function YesNoDialog(prompt: Str255;
 defaultButton: Integer): Integer;
function YesNoCancelDialog(prompt: Str255;
 defaultButton: Integer): Integer;
function StringDialog(prompt: Str255;
 var response: Str255): Boolean;
function FontSizeDialog(
 var fontSize: Integer): Boolean;
function MarginsDialog(
 var margins: MarginRecord): Boolean;

implementation

procedure ShowAbout;

{ Show the application About  dialog. }

 var
 theDialog: TAboutDialog;
 theItem: Integer;

begin
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IAboutDialog;
 theItem := theDialog.Show;
 theDialog.Free
 end
end;

 procedure ShowMessage(message: Str255);

{ Show the message dialog. }

 var
 theDialog: TMessageDialog;
 theItem: Integer;

begin
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IMessageDialog(message, 1);
 theItem := theDialog.Show;
 theDialog.Free
 end
end;

function YesNoDialog(prompt: Str255; defaultButton: Integer): Integer;

{ Ask a yes or no question. }

 var
 theDialog: TYesNoDialog;

begin
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IYesNoDialog(prompt,
 defaultButton);
 YesNoDialog := theDialog.Show;
 theDialog.Free
 end
end;

function YesNoCancelDialog(prompt: Str255; defaultButton: Integer): Integer;

{ Ask a yes, no or cancel question. }

 var
 theDialog: TYesNoCancelDialog;

begin
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IYesNoCancelDialog(prompt,
 defaultButton);
 YesNoCancelDialog := theDialog.Show;
 theDialog.Free
 end
end;

function StringDialog(prompt: Str255; var response: Str255): Boolean;

{ Get a string from the user. }

 var
 theDialog: TStringDialog;
 theItem: Integer;

begin
 StringDialog := false;
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IStringDialog(prompt, response);
 theItem := theDialog.Show;
 if theItem = OKButton then
 begin
 theDialog.GetData(response);
 StringDialog := true
 end;
 theDialog.Free
 end
end;

function FontSizeDialog(var fontSize: Integer): Boolean;

{ Get new font size. }

 var
 theDialog: TFontSizeDialog;
 theItem: Integer;

begin
 FontSizeDialog := false;
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IFontSizeDialog(fontSize);
 theItem := theDialog.Show;
 if theItem = OKButton then
 begin
 theDialog.GetData(fontSize);
 FontSizeDialog := true
 end;
 theDialog.Free
 end
end;

function MarginsDialog(var margins: MarginRecord): Boolean;

{ Get new page margins. }

 var
 theDialog: TMarginsDialog;
 theItem: Integer;

begin
 MarginsDialog := false;
 New(theDialog);
 if theDialog <> nil then
 begin
 theDialog.IMarginsDialog(margins);
 theItem := theDialog.Show;
 if theItem = OKButton then
 begin
 theDialog.GetData(margins);
 MarginsDialog := true
 end;
 theDialog.Free
 end;
end;

end.
Listing: TDialog.p

{ Written by Thomas Engel, M.D. }
{ Copyright © 1991 MacTutor. }

unit TDialog;

interface

uses
 SANE, Globals;

function DialogFilter(toolboxDialog: DialogPtr; var theEvent: EventRecord; 
var itemHit: Integer): Boolean;

implementation

function DialogFilter(toolboxDialog: DialogPtr; var theEvent: EventRecord; 
var itemHit: Integer): Boolean;

{ Dialog filter function. }

 var
 theDialog: TDialog;

begin
 theDialog := TDialog(
 DialogPeek(toolboxDialog)^.window.refCon);
 DialogFilter := theDialog.EventFilter(theEvent,
 itemHit)
end;

procedure TDialog.IDialog(dialogID: Integer;
 default, cancel, text: Integer;
 dismiss: DialogItemSet; centered: Boolean);

{ Initialize dialog. }

begin
 defaultItem := default;
 cancelItem := cancel;
 defaultText := text;
 dismissSet := dismiss;
 itemCount := 0;
 toolboxDialog := GetNewDialog(dialogID, nil,
 pointer(-1));
 toolboxDPeek := DialogPeek(toolboxDialog);
 if toolboxDialog <> nil then
 begin
 toolboxDPeek^.window.refCon :=
 Longint(self);
 itemCount :=
 IntegerHandle(toolboxDPeek^.items)^^ + 1
 end;
 if centered then
 Center
end;

procedure TDialog.Free;

{ Free memory used by this object. }

begin
 if toolboxDialog <> nil then
 DisposDialog(toolboxDialog);
 HUnlock(Handle(self));
 DisposHandle(Handle(self))
end;

procedure TDialog.Center;

{ Center the dialog on the main screen. }

 var
 width, height: Integer;

begin
 if toolboxDialog <> nil then
 begin
 with toolboxDialog^.portRect do
 begin
 width := right - left;
 height := bottom - top
 end;
 with ScreenBits.bounds do
 MoveWindow(toolboxDialog,
 left + (right - left - width) div 2,
 top + (bottom - top - height) div 3,
 false)
 end
end;

function TDialog.Show: Integer;

{ Show the dialog. }

 var
 itemHit: Integer;

begin
 Show := 0;
 if toolboxDialog <> nil then
 begin
 if defaultText > 0 then
 SelIText(toolboxDialog, defaultText, 0,
 32767);
 ShowWindow(toolboxDialog);
 InitCursor;
 repeat
 ModalDialog(@DialogFilter, itemHit);
 if itemHit > 0 then
 Hit(itemHit);
 until (itemHit > 0) and
 (itemHit in dismissSet);
 Show := itemHit
 end
end;

procedure TDialog.Hide;

{ Hide the dialog. }

begin
 if toolboxDialog <> nil then
 HideWindow(toolboxDialog);
end;

function TDialog.EventFilter(var theEvent: EventRecord; var itemHit: 
Integer): Boolean;

{ Dialog event filter. }

 var
 savePort: GrafPtr;
 ch: Char;
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;
 editItem: Integer;

begin

 { Save current port. }

 GetPort(savePort);
 SetPort(toolboxDialog);

 { Fix cursor. }

 FixCursor;

 { Check the event. }

 case theEvent.what of

 keyDown, autoKey: 
 begin
 ch := Chr(BitAnd(theEvent.message,
 CharCodeMask));

   { Handle default item. }

 if (ch in [ReturnCh, EnterCh]) and
 (defaultItem > 0) then
 begin
 FlashItem(defaultItem);
 itemHit := defaultItem;
 EventFilter := true
 end

 { Handle cancel item. }

 else if (BitAnd(theEvent.modifiers,
 CmdKey) <> 0) and (ch in ['.']) and
 (cancelItem > 0) then
 begin
 FlashItem(cancelItem);
 itemHit := cancelItem;
 EventFilter := true
 end

 { Handle tab key. }

 else if (ch in [TabCh]) and
 (toolboxDPeek^.editField <> -1) then
 begin
 if BitAnd(theEvent.modifiers,
 ShiftKey) <> 0 then
 begin

 { Find previous edit item. }

 editItem := toolboxDPeek^.editField
 + 1;
 repeat
 if editItem = 1 then
 editItem := itemCount
 else
 editItem := editItem - 1;
 GetDItem(toolboxDialog, editItem,
 itemType, itemHandle,
 itemRect);
 until itemType = editText;
 end
 else
 begin

 { Find next edit item. }

 editItem := toolboxDPeek^.editField
 + 1;
 repeat
 if editItem = itemCount then
 editItem := 1
 else
 editItem := editItem + 1;
 GetDItem(toolboxDialog, editItem,
 itemType, itemHandle,
 itemRect);
 until itemType = editText
 end;

 { Select the edit field. }

 SelIText(toolboxDialog, editItem, 0,
 32767);
 itemHit := editItem;
 EventFilter := true
 end

 { Handle keyboard commands. }

 else if BitAnd(theEvent.modifiers,
 CmdKey) <> 0 then
 begin
 Command(ch, itemHit);
 EventFilter := true
 end

 { Handle other typing. }

 else
 EventFilter := false
 end;

 updateEvt: 
 begin
 BeginUpdate(toolboxDialog);
 UpdtDialog(toolboxDialog,
 toolboxDialog^.visRgn);
 Draw;
 EndUpdate(toolboxDialog);
 EventFilter := true
 end;

 otherwise
 EventFilter := false
 end;

 { Restore port. }

 SetPort(savePort)
end;

procedure TDialog.FixCursor;

{ Fix the cursor. }

 var
 localMouse: Point;
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 if toolboxDPeek^.editField <> -1 then
 begin
 GetMouse(localMouse);
 GetDItem(toolboxDialog,
 toolboxDPeek^.editField + 1, itemType,
 itemHandle, itemRect);
 if PtInRect(localMouse, itemRect) then
 SetCursor(IBeam^^)
 else
 InitCursor
 end
end;

procedure TDialog.Command(ch: Char;
 var itemHit: Integer);

{ Handle keyboard command. }

begin
 if toolboxDPeek^.editField <> -1 then
 begin
 if ch in ['X', 'x'] then
 begin
 DlgCut(toolboxDialog);
 itemHit := toolboxDPeek^.editField + 1
 end
 else if ch in ['C', 'c'] then
 begin
 DlgCopy(toolboxDialog);
 itemHit := toolboxDPeek^.editField + 1
 end
 else if ch in ['V', 'v'] then
 begin
 DlgPaste(toolboxDialog);
 itemHit := toolboxDPeek^.editField + 1
 end
 else if ch in ['B', 'b'] then
 begin
 DlgDelete(toolboxDialog);
 itemHit := toolboxDPeek^.editField + 1
 end
 end
end;

procedure TDialog.Hit(var itemHit: Integer);

{ Special handling for item hit. }

begin
end;

procedure TDialog.Draw;

{ Draw extra dialog embellishments. }

begin
 DrawDefault;
end;

procedure TDialog.DrawDefault;

{ Outline the default button. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect, outlineRect: Rect;

begin
 if defaultItem > 0 then
 begin
 GetDItem(toolboxDialog, defaultItem,
 itemType, itemHandle, itemRect);
 outlineRect := itemRect;
 InsetRect(outlineRect, -4, -4);
 PenSize(3, 3);
 FrameRoundRect(outlineRect, 16, 16);
 PenNormal
 end
end;

procedure TDialog.DrawBox(itemSet: DialogItemSet; margin, thickness: 
Integer);

{ Draw a box around a set of dialog items. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect, boxRect: Rect;
 item: Integer;

begin

 { Get the enclosing rectangle. }

 SetRect(boxRect, 0, 0, 0, 0);
 for item := 1 to itemCount do
 if item in itemSet then
 begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if EmptyRect(boxRect) then
 boxRect := itemRect
 else
 UnionRect(boxRect, ItemRect, boxRect)
 end;

 { Draw the box. }

 if not EmptyRect(boxRect) then
 begin
 InsetRect(boxRect, -(margin + thickness),
 -(margin + thickness));
 PenSize(thickness, thickness);
 FrameRect(boxRect);
 PenNormal
 end
end;

procedure TDialog.DrawTitleBox(
 itemSet: DialogItemSet;
 margin, thickness: Integer; title: Str255);

{ Draws a box around a set of dialog items. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect, boxRect: Rect;
 item: Integer;
 theInfo: FontInfo;

begin

 { Get the enclosing rectangle. }

 SetRect(boxRect, 0, 0, 0, 0);
 for item := 1 to itemCount do
 if item in itemSet then
 begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if EmptyRect(boxRect) then
 boxRect := itemRect
 else
 UnionRect(boxRect, ItemRect, boxRect)
 end;

 { Draw the box and the title. }

 if not EmptyRect(boxRect) then
 begin
 GetFontInfo(theInfo);
 with boxRect, theInfo do
 begin
 left := left - margin - thickness;
 top := top - descent - margin -
 thickness;
 right := right + margin;
 bottom := bottom + margin;
 PenSize(thickness, thickness);
 MoveTo(left, top);
 Line(margin + 2, 0);
 Move(thickness + 1,
 (ascent + descent) div 2 - descent);
 DrawString(title);
 Move(1, -((ascent + descent) div 2 -
 descent));
 LineTo(right, top);
 LineTo(right, top);
 LineTo(right, bottom);
 LineTo(left, bottom);
 LineTo(left, top);
 PenNormal
 end
 end
end;

TDialog.FlashItem(item: Integer);

{ Hilight the dialog item for a few ticks. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;
 finalTicks: Longint;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, ctrlItem) <> 0 then
 begin
 HiliteControl(ControlHandle(itemHandle),
 ControlOn);
 Delay(FlashTicks, finalTicks);
 HiliteControl(ControlHandle(itemHandle),
 ControlOff);
 Delay(AfterTicks, finalTicks)
 end
end;

function TDialog.GetText(
 item: Integer): Str255;

{ Get the dialog item text string. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;
 text: Str255;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, statText + editText) <> 0
 then
 GetIText(itemHandle, text)
 else
 text := '';
 GetText := text
end;

procedure TDialog.SetText(item: Integer;
 text: Str255);

{ Set the dialog item text string. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, statText + editText) <> 0
 then
 begin
 SetIText(itemHandle, text);
 if toolboxDPeek^.editField + 1 = item then
 SelIText(toolboxDialog, item, 0, 32767);
 end
end;

function TDialog.GetInteger(
 item: Integer): Longint;

{ Get an integer value from the item text. }

 var
 text: Str255;
 value: Longint;

begin
 text := GetText(item);
 StringToNum(text, value);
 GetInteger := value
end;

procedure TDialog.SetInteger(item: Integer;
 value: Longint);

{ Set the item text string to represent an integer. }

 var
 text: Str255;

begin
 NumToString(value, text);
 SetText(item, text)
end;

function TDialog.GetReal(
 item: Integer): Extended;

{ Get a real value from the item text. }

 var
 text: Str255;
 value: Extended;

begin
 text := GetText(item);
 value := Str2Num(text);
 GetReal := value
end;

procedure TDialog.SetReal(item: Integer;
 value: Extended; places: Integer);

{ Set the item text string to represent a real number. }

 var
 format: DecForm;
 text: DecStr;

begin
 SetRound(ToNearest);
 format.style := FixedDecimal;
 format.digits := places;
 Num2Str(format, value, text);
 SetText(item, text)
end;

function TDialog.GetControlValue(
 item: Integer): Integer;

{ Get the control value. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;
 value: Integer;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, ctrlItem) <> 0 then
 value := GetCtlValue(
 ControlHandle(itemHandle))
 else
 value := 0;
 GetControlValue := value
end;

procedure TDialog.SetControlValue(
 item: Integer; value: Integer);

{ Set the control value. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, ctrlItem) <> 0 then
 SetCtlValue(ControlHandle(itemHandle), value)
end;

function TDialog.GetControlTitle(
 item: Integer): Str255;

{ Get the control title. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;
 title: Str255;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, ctrlItem) <> 0 then
 GetCTitle(ControlHandle(itemHandle), title)
 else
 title := '';
 GetControlTitle := title
end;

procedure TDialog.SetControlTitle(
 item: Integer; title: Str255);

{ Set the control title. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, ctrlItem) <> 0 then
 SetCTitle(ControlHandle(itemHandle), title)
end;

function TDialog.GetRadioItem(
 radioSet: DialogItemSet): Integer;

{ Get the selected radio button. }

 var
 item, value: Integer;
 itemSelected: Integer;

begin
 itemSelected := 0;
 item := 1;
 while (itemSelected = 0) and
 (item <= itemCount) do
 begin
 if item in radioSet then
 if GetControlValue(item) = ControlOn then
 itemSelected := item;
 item := item + 1
 end;
 GetRadioItem := itemSelected
end;

procedure TDialog.SetRadioItem(
 radioSet: DialogItemSet;
 itemSelected: Integer);

{ Set the selected radio button. }

 var
 item: Integer;

begin
 if itemSelected in radioSet then
 for item := 1 to itemCount do
 if item in radioSet then
 if item = itemSelected then
 SetControlValue(item, ControlOn)
 else
 SetControlValue(item, ControlOff)
end;

procedure TDialog.SetIcon(item: Integer;
 iconID: Integer);

{ Set icon item. }

 var
 theIcon: Handle;
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 theIcon := GetIcon(iconID);
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if (BitAnd(itemType, iconItem) <> 0) and
 (theIcon <> nil) then
 SetDItem(toolboxDialog, item, itemType,
 Handle(theIcon), itemRect)
end;

procedure TDialog.SetPicture(item: Integer;
 pictureID: Integer);

{ Set picture item. }

 var
 thePicture: PicHandle;
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 thePicture := GetPicture(pictureID);
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if (BitAnd(itemType, picItem) <> 0) and
 (thePicture <> nil) then
 SetDItem(toolboxDialog, item, itemType,
 Handle(thePicture), itemRect)
end;

procedure TDialog.SetUserItem(item: Integer;
 userProc: ProcPtr);

{ Set the dialog user item procedure. }

 var
 itemType: Integer;
 itemHandle: Handle;
 itemRect: Rect;

begin
 GetDItem(toolboxDialog, item, itemType,
 itemHandle, itemRect);
 if BitAnd(itemType, userItem) <> 0 then
 SetDItem(toolboxDialog, item, itemType,
 Handle(userProc), itemRect)
end;

procedure TAboutDialog.IAboutDialog;

{ Initialize about dialog. }

begin
 IDialog(AboutID, OKButton, 0, 0, [OKButton], true)
end;

function TAboutDialog.Show: Integer;

{ Show about dialog. }

 var
 s: Str255;

begin
 NumToString(MaxBlock div 1024, s);
 s := Concat(s, 'K ', GetText(3));
 SetText(3, s);
 Show := inherited Show
end;

procedure TMessageDialog.IMessageDialog(
 message: Str255; iconID: Integer);

{ Initialize message dialog. }

begin
 IDialog(MessageID, OKButton, 0, 0, [OKButton],true);
 SetIcon(2, iconID);
 SetMessage(message)
end;

procedure TMessageDialog.SetMessage(message: Str255);
{Set message text string. }
begin
 SetText(3, message)
end;

procedure TStringDialog.IStringDialog(
 prompt, default: Str255);
{ Initialize string dialog. }
begin
 IDialog(StringID, OKButton, CancelButton, 4,
 [OKButton, CancelButton], true);
 SetData(prompt, default)
end;

procedure TStringDialog.SetData(prompt,default: Str255);
{ Set prompt and default text strings. }
begin
 SetText(3, prompt);
 SetText(4, default)
end;

procedure TStringDialog.GetData(
 var response: Str255);
{ Get string. }
begin
 response := GetText(4)
end;

procedure TYesNoDialog.IYesNoDialog(
 prompt: Str255; default: Integer);

{ Initialize Yes/No dialog. }

begin
 IDialog(YesNoID, default, 0, 0,
 [YesButton, NoButton], true);
 SetPrompt(prompt)
end;

procedure TYesNoDialog.SetPrompt(
 prompt: Str255);

{ Set prompt text string. }

begin
 SetText(2, prompt)
end;

procedure TYesNoCancelDialog.IYesNoCancelDialog(
 prompt: Str255; default: Integer);

{ Initialize Yes/No/Cancel dialog. }

begin
 IDialog(YesNoCancelID, default, CancelButton,
 0, [YesButton, NoButton, CancelButton],
 true);
 SetPrompt(prompt)
end;

procedure TYesNoCancelDialog.SetPrompt(
 prompt: Str255);

{ Set prompt text string. }

begin
 SetText(4, prompt)
end;

procedure TMarginsDialog.IMarginsDialog(
 defaultMargins: MarginRecord);
{ Initialize page margins dialog. }
begin
 IDialog(PageMarginsID, OKButton, CancelButton,
 5, [OKButton, CancelButton], true);
 measureSet := [12, 13, 14];
 SetData(defaultMargins)
end;

procedure TMarginsDialog.Draw;
{ Draw. }
begin
 DrawTitleBox(measureSet, 3, 1, 'Measure');
 DrawDefault
end;

procedure TMarginsDialog.Hit(var itemHit: Integer);
{ Item hit. }
 var
 oldItem: Integer;
 factor: Extended;
 places: Integer;

begin
 if itemHit in measureSet then
 begin

 { Convert margin values to new units. }

 oldItem := GetRadioItem(measureSet);
 if oldItem <> itemHit then
 begin
 if (oldItem = 12) and
 (itemHit = 13) then
 begin

 { Inches to cm. }

 factor := 2.54;
 places := 2
 end
 else if (oldItem = 12) and
 (itemHit = 14) then
 begin

 { Inches to points. }

 factor := 72.0;
 places := 0
 end
 else if (oldItem = 13) and
 (itemHit = 12) then
 begin

 { Cm to inches. }

 factor := 1.0 / 2.54;
 places := 2
 end
 else if (oldItem = 13) and
 (itemHit = 14) then
 begin

 { cm to points. }

 factor := 1.0 / 2.54 * 72.0;
 places := 0
 end
 else if (oldItem = 14) and
 (itemHit = 12) then
 begin

 { Points to inches. }

 factor := 1.0 / 72.0;
 places := 2
 end
 else if (oldItem = 14) and
 (itemHit = 13) then
 begin

 { Points to cm. }
 factor := 1.0 / 72.0 * 2.54;
 places := 2
 end;

 SetReal(5, GetReal(5) * factor, places);
 SetReal(7, GetReal(7) * factor, places);
 SetReal(9, GetReal(9) * factor, places);
 SetReal(11, GetReal(11) * factor,
 places);
 end;
 SetRadioItem(measureSet, itemHit)
 end
end;

procedure TMarginsDialog.SetData(newMargins: MarginRecord);
{ Set the page margin values. }
 var
 places: Integer;

begin
 case newMargins.measure of

 inches: 
 begin
 SetRadioItem(measureSet, 12);
 places := 2
 end;

 cm: 
 begin
 SetRadioItem(measureSet, 13);
 places := 2
 end;

 points: 
 begin
 SetRadioItem(measureSet, 14);
 places := 0
 end;

 end;
 SetReal(5, newMargins.top, places);
 SetReal(7, newMargins.bottom, places);
 SetReal(9, newMargins.left, places);
 SetReal(11, newMargins.right, places)
end;

procedure TMarginsDialog.GetData(var theMargins: MarginRecord);
{ Get the page margin values. }
begin
 case GetRadioItem(measureSet) of
 12: 
 theMargins.measure := inches;
 13: 
 theMargins.measure := cm;
 14: 
 theMargins.measure := points;
 end;
 theMargins.top := GetReal(5);
 theMargins.bottom := GetReal(7);
 theMargins.left := GetReal(9);
 theMargins.right := GetReal(11)
end;

procedure TFontSizeDialog.IFontSizeDialog(defaultSize: Integer);
{ Initialize font size dialog. }
begin
 IDialog(FontSizeID, OKButton, CancelButton, 4,
 [OKButton, CancelButton], true);
 SetData(defaultSize)
end;

procedure TFontSizeDialog.SetData(fontSize: Integer);
{ Set the font size. }
begin
 SetInteger(4, fontSize)
end;

procedure TFontSizeDialog.GetData(var fontSize: Integer);
{ Get the font size. }
begin
 fontSize := GetInteger(4)
end;

end.
Listing: Test Dialogs.p

{ Written by Thomas Engel, M.D. }
{ Copyright © 1991 MacTutor. }
{$I-}
program TestDialogs;
uses
 Globals, TDialog;
var
 theButton: Integer;
 response: Str255;
 fontSize: Integer;
 margins: MarginRecord;
 confirmed: Boolean;

begin
 { Initialize system. }
 MaxApplZone;
 MoreMasters;
 InitGraf(@thePort);
 InitFonts;
 InitWindows;
 InitMenus;
 TEInit;
 InitDialogs(nil);
 InitCursor;
 FlushEvents(EveryEvent, 0);
 IBeam := GetCursor(IBeamID);
 Watch := GetCursor(WatchID);

 { Test each dialog. }
 ShowAbout;
 ShowMessage('This is a message.');

 theButton := YesNoDialog(
 'This is the prompt. (Yes)', YesButton);
 theButton := YesNoCancelDialog(
 'This is the prompt. (Cancel)',
 CancelButton);

 response := 'This is the default text.';
 confirmed := StringDialog('This is the prompt.', response);

 fontSize := 12;
 confirmed := FontSizeDialog(fontSize);

 margins.measure := inches;
 margins.top := 1.0;
 margins.bottom := 1.5;
 margins.left := 1.25;
 margins.right := 1.25;
 confirmed := MarginsDialog(margins);
end.
Listing: Dialogs.r

resource 'DITL' (128, "About", purgeable, preload) {
 { /* array DITLarray: 4 elements */
 /* [1] */
 {111, 201, 130, 266},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {15, 15, 47, 265},
 StaticText {
 disabled,
 "Dialog Test Application\nVersion 1.0\n"
 },
 /* [3] */
 {113, 15, 129, 182},
 StaticText {
 disabled,
 "bytes free."
 },
 /* [4] */
 {52, 15, 97, 265},
 StaticText {
 disabled,
 "Copyright © 1991 MacTutor.\nAll rights re"
 "served."
 }
 }
};

resource 'DITL' (129, "Message", purgeable, preload) {
 { /* array DITLarray: 3 elements */
 /* [1] */
 {98, 311, 117, 376},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {10, 10, 42, 42},
 Icon {
 disabled,
 1
 },
 /* [3] */
 {20, 52, 84, 375},
 StaticText {
 disabled,
 "^0\n^1\n^2\n^3"
 }
 }
};

resource 'DITL' (130, "Get String", purgeable, preload) {
 { /* array DITLarray: 4 elements */
 /* [1] */
 {74, 206, 93, 271},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {74, 281, 93, 346},
 Button {
 enabled,
 "Cancel"
 },
 /* [3] */
 {15, 15, 31, 345},
 StaticText {
 disabled,
 "Prompt?"
 },
 /* [4] */
 {38, 18, 54, 342},
 EditText {
 enabled,
 "Default"
 }
 }
};

resource 'DITL' (131, "Yes/No", purgeable, preload) {
 { /* array DITLarray: 3 elements */
 /* [1] */
 {77, 206, 96, 271},
 Button {
 enabled,
 "Yes"
 },
 /* [2] */
 {15, 15, 63, 345},
 StaticText {
 disabled,
 "^0"
 },
 /* [3] */
 {77, 281, 96, 346},
 Button {
 enabled,
 "No"
 }
 }
};

resource 'DITL' (132, "Yes/No/Cancel", purgeable, preload) {
 { /* array DITLarray: 4 elements */
 /* [1] */
 {77, 131, 96, 196},
 Button {
 enabled,
 "Yes"
 },
 /* [2] */
 {77, 281, 96, 346},
 Button {
 enabled,
 "Cancel"
 },
 /* [3] */
 {77, 206, 96, 271},
 Button {
 enabled,
 "No"
 },
 /* [4] */
 {15, 15, 63, 345},
 StaticText {
 disabled,
 "^0"
 }
 }
};

resource 'DITL' (133, "Font Size", purgeable, preload) {
 { /* array DITLarray: 4 elements */
 /* [1] */
 {74, 66, 93, 131},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {74, 141, 93, 206},
 Button {
 enabled,
 "Cancel"
 },
 /* [3] */
 {35, 21, 51, 121},
 StaticText {
 disabled,
 "New font size:"
 },
 /* [4] */
 {35, 138, 51, 173},
 EditText {
 enabled,
 "12"
 }
 }
};

resource 'DITL' (134, "Page Margins", purgeable, preload) {
 { /* array DITLarray: 14 elements */
 /* [1] */
 {171, 186, 190, 251},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {171, 261, 190, 326},
 Button {
 enabled,
 "Cancel"
 },
 /* [3] */
 {15, 15, 31, 325},
 StaticText {
 disabled,
 "New page margins:"
 },
 /* [4] */
 {40, 16, 56, 72},
 StaticText {
 disabled,
 "Top"
 },
 /* [5] */
 {40, 80, 56, 120},
 EditText {
 enabled,
 "1.25"
 },
 /* [6] */
 {64, 16, 80, 72},
 StaticText {
 disabled,
 "Bottom"
 },
 /* [7] */
 {64, 80, 80, 120},
 EditText {
 enabled,
 "1.25"
 },
 /* [8] */
 {40, 168, 56, 224},
 StaticText {
 disabled,
 "Left"
 },
 /* [9] */
 {40, 232, 56, 272},
 EditText {
 enabled,
 "1.25"
 },
 /* [10] */
 {64, 168, 80, 224},
 StaticText {
 disabled,
 "Right"
 },
 /* [11] */
 {64, 232, 80, 272},
 EditText {
 enabled,
 "1.25"
 },
 /* [12] */
 {104, 56, 120, 184},
 RadioButton {
 enabled,
 "inches"
 },
 /* [13] */
 {120, 56, 136, 184},
 RadioButton {
 enabled,
 "centimeters"
 },
 /* [14] */
 {136, 56, 152, 184},
 RadioButton {
 enabled,
 "points"
 }
 }
};

resource 'DLOG' (128, "About", purgeable, preload) {
 {83, 116, 227, 396},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 128,
 "About Dialog"
};

resource 'DLOG' (129, "Message", purgeable, preload) {
 {88, 61, 219, 451},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 129,
 "Show Message"
};

resource 'DLOG' (130, "Get String", purgeable, preload) {
 {98, 76, 205, 436},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 130,
 "Ask String"
};

resource 'DLOG' (131, "Yes/No", purgeable, preload) {
 {96, 76, 206, 436},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 131,
 "Ask Yes/No"
};

resource 'DLOG' (132, "Yes/No/Cancel", purgeable, preload) {
 {96, 76, 206, 436},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 132,
 "Ask Yes/No/Cancel"
};

resource 'DLOG' (133, "Font Size", purgeable, preload) {
 {98, 146, 205, 366},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 133,
 "Ask Font Size"
};

resource 'DLOG' (134, "Page Margins", purgeable, preload) {
 {52, 86, 254, 426},
 dBoxProc,
 invisible,
 noGoAway,
 0x0,
 134,
 "Page Margin Dialog"
};

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Parallels Desktop 13.0.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
Mellel 4.0.0 - The word processor for sc...
Mellel is the leading word processor for OS X and has been widely considered the industry standard for long form documents since its inception. Mellel focuses on writers and scholars for technical... Read more
Backblaze 5.0.0.116 - Online backup serv...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
EtreCheck 3.4.4 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
Luminar 1.2.1 - Powerful, adaptive, conf...
Luminar is the new full-featured image editor that adapts to the way you edit photos. Over 300 essential tools to fix, edit, and enhance your photos with comfort. The future of photo editing is here... Read more
GarageSale 7.0.8 - Create outstanding eB...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
Adobe Muse CC 2017 2017.1.0 - Design and...
Muse CC 2017 is available as part of Adobe Creative Cloud for as little as $14.99/month (or $9.99/month if you're a previous Muse customer). Adobe Muse 2017 enables designers to create websites as... Read more
1Password 6.8.1 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Luminar 1.2.1 - Powerful, adaptive, conf...
Luminar is the new full-featured image editor that adapts to the way you edit photos. Over 300 essential tools to fix, edit, and enhance your photos with comfort. The future of photo editing is here... Read more
1Password 6.8.1 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more

Radiation City (Games)
Radiation City 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Radiation City Welcome to the world of Radiation City where a great survival adventure awaits you! | Read more »
The best deals on the App Store this wee...
The summer is drawing quickly to a close, but luckily there's a game for every season. It's an excellent week for some bargain shopping if that's what you're after. There are some big names and indie darlings in this week's roundup. It's a great... | Read more »
KORG iMono/Poly (Music)
KORG iMono/Poly 1.0.0 Device: iOS Universal Category: Music Price: $19.99, Version: 1.0.0 (iTunes) Description: *** Special Sale for a limited time to celebrate the debut of KORG iMono/Poly (33% OFF) until Sep 30! *** Reviving a... | Read more »
Super Phantom Cat 2 beginner's guid...
Super Phantom Cat 2 presents a whole new world of fun platforming challenges and perplexing puzzles. It's a well-designed platformer with a bright, neon aesthetic that brings the genre up to date. [Read more] | Read more »
Shadow Fight 2 Special Edition (Games)
Shadow Fight 2 Special Edition 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: ** New story chapter! **** No Ads! **** No energy! ** The best fighting series on mobile has returned and... | Read more »
4 RPGs like Final Fantasy XV that deserv...
Square Enix announced another Final Fantasy XV spin-off today - Final Fantasy XV Pocket Edition. This mobile, episodic version of the hit RPG gives the game a chibi-fied makeover. The first episode will be free, followed by 9 more premium episodes... | Read more »
Guild sieges and soul gems in latest upd...
Webzen’s MU Origin hit app stores last year, giving fans of fantasy hack-n-slash MMOs like Diablo a new fix to fixate on. This latest update introduces a competitive guild battle, a fresh dungeon challenge, a mini-game and some elemental gems to... | Read more »
Little Red Lie (Games)
Little Red Lie 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ARE YOU MORE AFRAID OF POVERTY THAN DEATH? Little Red Lie is a narrative-focused, interactive fiction experience that reduces... | Read more »
You can now apply to be Clash of Clans...
Earlier this month, word got out that the Builder, the trusty handiman who tirelessly built every single building inevery singleClash of Clansbase had called it quits. Sick of seeing his work destroyed endless, the Builder has set out for our world... | Read more »
Meshi Quest beginner's guide - how...
Meshi Quest is Square Enix's newest free-to-play release, and it's a real charmer. You start off as the head of a sushi restaurant, upgrading your food and equipment as you serve visitors heaping helpings of your delicious meals. As you progress,... | Read more »

Price Scanner via MacPrices.net

Low Cost Subscription Graphics App Alternativ...
I’m not a fan of the subscription software model, I don’t use any subscription apps. Used to be that you paid your license fee and the app was yours to use indefinitely, or until one opted for a paid... Read more
Clearance 2016 13-inch MacBook Airs, Apple re...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is free: – 13″ 1.6GHz/8GB/128GB MacBook Air: $... Read more
2017 13-inch MacBook Airs on sale for $100 of...
B&H Photo new 2017 13″ MacBook Airs on sale today for $100 off MSRP, starting at $899: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off MSRP – 13″ 1.8GHz/256GB MacBook Air (MQD42LL/A... Read more
Sale! 13-inch 2.3GHz MacBook Pros for $100 of...
B&H Photo has 13″ 2.3GHz MacBook Pros in stock today and on sale for $100 off MSRP including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook Pro (MPXQ2LL... Read more
2016 MacBook Pros, Apple refurbished, availab...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available starting at $1189. An Apple one-year warranty is included with each model, and shipping is free: – 15″ 2.7GHz Touch Bar Space... Read more
Apple offers Certified Refurbished iPhone 6s...
Apple has Certified Refurbished unlocked iPhone 6s’s and 6s Plus’s available starting at $449. An Apple one-year warranty is included with each phone, and shipping is free: – 16GB iPhone 6s: $449, $... Read more
Apple offers Certified Refurbished Pencils fo...
Apple has Certified Refurbished Apple Pencils available for $85 including free shipping. Their price is $14 off MSRP, and it’s the lowest price available for a Pencil. Read more
2016 15-inch 2.6GHz Touch Bar MacBook Pro ava...
B&H Photo has clearance 2016 15″ 2.6GHz MacBook Pros in stock today and on sale for $500 off original MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: – 15″ 2.6GHz Touch... Read more
21-inch 2.3GHz iMac on sale for $999, save $1...
Amazon has the new 2017 21″ 2.3GHz iMac (MMQA2LL/A) in stock and on sale for $999.99 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
Free Instant Translator 2.0 App For iOS Relea...
Mobile application development company, Neoappz has announced the release and immediate availability of Instant Translator 2.0 for iOS devices. Instant Translator is a user-friendly application which... Read more

Jobs Board

*Apple* Solutions Consultant - Apple Inc. (U...
Job Summary As an Apple Solutions Consultant, you'll be the link between our future customers and our products. You'll showcase your entrepreneurial spirit as you Read more
*Apple* Solutions Consultant - Apple Inc. (U...
…about helping others on a team while also delighting customers? As an Apple Solutions Consultant (ASC), you will discover customers needs and help connect them Read more
Sr. Software Engineer, Core Services, *Apple...
…part of the server team that powers various features within the App Store, Apple Music, iBooks, iTunes, and Podcasts. You will be working cross functionally with Read more
SW Engineer *Apple* TV Frameworks - Apple I...
Job Summary The Apple TV team is looking for a software engineer to join us as we work to define the future of the tvOS platform. Key Qualifications You're Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.