TweetFollow Us on Twitter

Linking Text
Volume Number:7
Issue Number:11
Column Tag:MacOOPs!

Related Info: TextEdit Edition Manager

Linking Text Objects

By Scott Steketee, Philadelphia, PA

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

TLinkItem: A MacApp class to link the content of text objects

“An injury to one is an injury to all.”

[Scott Steketee, a former teacher, has been programming the Apple II for many years, and is now adapting his popular GradeBook Deluxe program for the Macintosh.]

Introduction

This article presents a MacApp class which allows several TEditText or TStaticText objects to be linked, so that they always show the same contents, even while one is being edited. It also presents a subclass of TEditText which is capable of controlling such a link, and explains how to create subclasses of other objects so that they too can control and be controlled by the link. The objects which share the same text can be in the same or different windows, and there can be any number of such objects.

Macintosh applications frequently provide several different ways of viewing or changing some item of data. In a spreadsheet, for instance, the item may appear in a grid cell and in a separate formula bar where it can be edited. In a color program, the percentage of red may appear both in numeric form and as the position of a slider. In a database, the user may be entering data in a special record entry dialog, while the data appears in a second window as a row in a grid and in still another as an item in a report. In my own application (a teacher’s gradebook program), the teacher can enter information about a student in either a dialog window or a grade entry window; if both windows are open at the same time, changes in one should be immediately reflected in the other.

MacApp provides a good environment in which to construct this capability. The strength of MacApp, as an object programming system combined with a large Mac-specific class library, lies in the programmer’s ability to re-use the classes already provided, and to create new classes by modifying the existing ones. This strength shows up well here; the entire unit requires only one new class and relatively minor changes to three existing classes.

Publishers and Subscribers

For the remainder of this article, the objects that initiate the updating process by sending update information to the link are called publishers, and objects that accept and display update information from the link are called subscribers. The function of the link is to accept information from a publisher, and to forward the information to all the appropriate subscribers. Any object can function as a publisher by calling the appropriate method of the link. The present unit allows TStaticText, TEditText and TTEView objects to function as subscribers; other classes can be added by overriding the appropriate method.

A publisher which provides a visual representation of the data is usually also a subscriber, so that if any other publisher changes the data, the first publisher will get the updated information and be able to change its own visual representation of the data. On the other hand, a subscriber which only displays data and doesn’t change it will not be a publisher.

The unit ULinkItem provides the links between publishers and subscribers, and allows TEditText items to publish their data while the user is entering it. This unit allows all the subscribers to be updated each time the user changes the data, either by typing a character or by performing some other editing action. An application could provide several TEditText objects which can be used to enter data; as the data changes, the link updates the subscribing views in real time. The unit allows TEditText, TStaticText and TTEView objects to function as subscribers, with no limit to the number of subscribers which can be linked to the same item of data. (Of course, if you’re simultaneously updating a dozen objects on the screen with every character typed, things could get a little slow ) The classes that can function as subscribers can easily be extended to include your own custom classes. Such subscribers might be grids or lists showing text, or they could be objects capable of showing some other, non-text representation of the data.

Implementing the Links

One new class (TLinkItem) is defined to serve as the repository for one item of data and to keep track of the subscribers that display the data. Three other classes are modified (TEditText, TDialogView, and TDialogTEView) so that a TEditText object can function as a publisher while it is being edited. When the user edits such a TEditText object on the screen, the object publishes each change by forwarding it to the corresponding link item, which in turn forwards the change to all its subscribers.

The first object, TLinkItem, is fairly straight-forward. It requires three fields. The field fText stores the data, and fLinks is a list of all the subscribers. A third field, fUpdating, is set to TRUE whenever the item is in the process of informing its subscribers of a change. (This field is used to avoid the situation in which the link informs a subscriber of a change, and the subscriber, not knowing who sent the message, sends a message right back to inform the link that it has been changed, and the link then starts all over again informing subscribers )

There are five important methods of TLinkItem, in addition to the usual initialization, Free, and Fields methods. AddLink adds an object to the list of subscribers, and RemoveLink removes an object from the list. GetText supplies the current value of the link’s text data. SetText changes the text (usually but not necessarily as a result of the user’s typing) and initiates an update of all the subscribers. Finally, UpdatedLink sends the changed text to one single subscriber. This method knows how to update TEditText, TStaticText and TTEView objects; it must be overridden in order to allow updating of other kinds of objects.

Modifying TEditText

The rest of the unit is devoted to modifying TEditText objects so they can initiate and receive updates. It would be nice if we could modify only the TEditText class, but TEditText depends rather closely on three other classes for its behavior, and two of these three classes need to be modified.

(One of the principles of good object programming is to minimize the connections between different objects. To the extent possible, each object should stand on its own, with its methods and data as little as possible dependent on other objects. MacApp tries to meet this objective, but doesn’t succeed very well in the case of TEditText. It requires close and complex cooperation of four objects--the TEditText, a TDialogView, a TScroller, and a TDialogTEView--just to edit some text.)

The main change to TEditText itself is that SetText must check to see if it’s publishing to a TLinkItem, and if so pass the new text to the link.

TDialogTEView must also be sub-classed. This class is used in editing: when the TEditText is clicked on, a TDialogTEView is installed to handle the actual editing. Two of the methods must be overridden. First, InstallEditText is overridden so that when the view is installed in the TEditText, it is linked to the same item as the TEditText is. Second, all the changes to the text must be caught and relayed back to the TLinkItem. These changes include the typing of characters and the edit menu commands Cut, Paste and Clear. Fortunately, all these editing changes call SynchView to update the display, so SynchView is overridden so that it also updates the text in the TLinkItem.

Finally, TDialogView must also be subclassed, so that when it creates the TDialogTEView which later gets installed in the TEditText to handle editing, it creates our new-style TDialogTEView which knows how to handle links, instead of the old style that doesn’t.

The Source Code

The source code includes five files. Files ULinkItem.p and ULinkItem.inc1.p are the interface and implementation respectively for the classes described in the article. ULinkDemo.p, ULinkDemo.inc1.p, and MLinkDemo.p are the Pascal source files for a demonstration program which allows you to create a multitude of windows with linked EditText items. Finally, LinkDemo.r is the resource file for the demonstration program.

The program has been tested with MacApp 2.0 under both MPW Pascal and Think Pascal. (To run under Think Pascal, the interface and implementation of each unit must be combined into a single file using Think’s Source Converter.)

Extending the Unit

To extend this unit so that a link can forward data to other types of subscribers, you need only override the UpdatedLink procedure. This procedure checks to see if the subscriber currently being updated is one that it knows how to handle. If it is, the procedure takes whatever update action is appropriate and returns TRUE; otherwise it calls INHERITED UpdatedLink. Here is a template:

{1}

FUNCTION TMyLink.UpdatedLink
 (subscriber: TObject; theText: str255): BOOLEAN; OVERRIDE;
 { Update the subscribers we know how to do }
 { & return TRUE; Otherwise call inherited  }
 { UpdatedLink.                             }
 BEGIN
 IF Member (subscriber, TMyObject)
 THEN   { this is my type of subscriber }
 BEGIN
 { Set the text or take some other appropriate                 
 action---e.g., 
 TMyObject(subscriber).SetText (theText); }
 UpdatedLink := TRUE;
 END
 ELSE
 { this is not my type of subscriber, }
 { so find someone else to update it. }
 UpdatedLink := INHERITED UpdatedLink 
 (subscriber, theText);
 END;

If you are defining a class with the capability of subscribing to a link, it’s probably best to rely on the link to store the text data, and not to store a copy locally in the object. This finesses the problem of data integrity: the conflict in which the subscriber’s locally stored data doesn’t match the link’s data cannot arise. If there is a local copy of the data (as is the case with TEditText and TStaticText), it’s important to guarantee the integrity of the data. One approach is to make sure that any change to the local copy of the data is immediately sent to the link to be published. The other approach is to ensure that the link is the only object that ever sends new data to your object. If any other object wants to change your object’s data, it needs to do so by updating the link to which your object subscribes.

Besides being easy to extend this unit to allow it to automatically update other kinds of subscribers when the text in the TLinkItem changes, it would also be fairly easy to modify the unit so that the shared data is some other kind of information--numerical data, for instance. This would be a natural way to link a number in a text edit box with some other visual display--the position of a slider or dial, for instance.

Another possible extension to this capability of linking different items within an application is the capability of linking items from different applications. An interface between this unit and Apple’s IAC (Inter-Application Communications) facilities would be a natural. Attention, MacApp hackers! Who can give us some useful IAC capabilities?

Finally, if there’s interest, I’ll write a future column or two on a flexible approach to linking a two-dimensional view (i.e., a TGridView) with a two-dimensional data structure (a two-dimensional dynamic array based on TDynamicArray).

{2}

{=========== File ULinkItem.p ===========}
UNIT ULinkItem;
INTERFACE
USES
 UMacApp, UTEView, UDialog, UGridView,
 Fonts, ToolUtils;

TYPE
 TLinkItem = OBJECT (TObject)
 fText: StringHandle;{ the data itself }
 fLinks:TList;     { list of subscribers }
 fUpdating: BOOLEAN;
 { don’t respond to call-backs while }
 { I’m sending update messages to my }
 { subscribers.                      }
 PROCEDURE TLinkItem.ILinkItem
 (theText: str255);
 PROCEDURE TLinkItem.Free; OVERRIDE;
 FUNCTION  TLinkItem.UpdatedLink 
 (theSubscriber: TObject;
 theText: str255): BOOLEAN;
 PROCEDURE TLinkItem.SetText (theText: str255;
 thePublisher: TObject);
 PROCEDURE TLinkItem.GetText
 (VAR theText: str255);
 PROCEDURE TLinkItem.AddLink
 (theSubscriber: TObject);
 PROCEDURE TLinkItem.RemoveLink 
 (theSubscriber: TObject);
 PROCEDURE TLinkItem.Fields (
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER));
 OVERRIDE;
 END;
 
 TLinkEditText = OBJECT (TEditText)
 fLink: TLinkItem;
 PROCEDURE TLinkEditText.ILinkEditText
 (itsSuperView: TView;
 itsLocation, itsSize: VPoint;
 itsMaxChars: INTEGER;
 itsLink: TLinkItem);
 PROCEDURE TLinkEditText.Free; OVERRIDE;
 PROCEDURE TLinkEditText.SetText
 (theText: Str255; redraw: BOOLEAN); 
 OVERRIDE;
 PROCEDURE TLinkEditText.Fields (
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER));
 OVERRIDE;
 END;
 
 TLinkDialogTEView = OBJECT (TDialogTEView)
 fLink: TLinkItem;
 { the item, if any, the TEView }
 { is linked to                 }
 PROCEDURE TLinkDialogTEView.IDialogTEView 
 (itsDocument: TDocument;
 itsSuperView: TView;
 itsLocation,  itsSize: VPoint; 
 itsHDeterminer,
 itsVDeterminer: SizeDeterminer;
 itsInset: Rect;
 itsTextStyle: TextStyle; 
 itsJustification: INTEGER;
 itsStyleType, itsAutoWrap: BOOLEAN);  OVERRIDE;
 PROCEDURE TLinkDialogTEView.SynchView
 (redraw: BOOLEAN); OVERRIDE;
 PROCEDURE TLinkDialogTEView.InstallEditText 
 (theEditText: TEditText;
 selectChars: BOOLEAN); OVERRIDE;
 PROCEDURE TLinkDialogTEView.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER));
 OVERRIDE;
 END;

 TLinkDialogView = OBJECT (TDialogView)
 FUNCTION TLinkDialogView.MakeTEView:
 TDialogTEView; OVERRIDE;
 PROCEDURE TLinkDialogView.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER));
 OVERRIDE;
 END;
 
IMPLEMENTATION
 {$I ULinkItem.inc1.p}
END { UNIT ULinkItem }.

{======== File ULinkItem.inc1.p =========}
CONST kSizeJump = 8;
 { don’t resize the handle every time }
 { a char is added!                   }

{------------  T L i n k I t e m  ------------}
{$S LnkItmOpen}
PROCEDURE TLinkItem.ILinkItem (theText: str255);
 BEGIN
 fText := NewString (theText);
 fLinks := NewList;
 fUpdating := FALSE;
 END { TLinkItem.ILinkItem };
 
{$S LnkItmClose}
PROCEDURE TLinkItem.Free; OVERRIDE;
 BEGIN
 DisposIfHandle (fText);   { free the text }
 fLinks.Free;      { free the list items }
 INHERITED Free; { and free the object itself }
 END { TLinkItem.Free };
 
{$S LnkItmRes}
FUNCTION TLinkItem.UpdatedLink
 (theSubscriber: TObject; theText: str255):              BOOLEAN;
 { Updates the links it can & returns TRUE.    }
 { Ignores those it can’t & returns FALSE.     }
 { Override this method to provide the ability }
 { to update other types of objects.           }
 BEGIN
 UpdatedLink := TRUE;
 IF Member (theSubscriber, TStaticText) THEN
 { I know how to do static & edit texts }
 TStaticText(theSubscriber).SetText
 (theText, kRedraw)
 ELSE IF Member (theSubscriber, TTEView) THEN
 { I can also do TTEViews }
 WITH TTEView (theSubscriber) DO
 BEGIN
 SetText (theText);
 ForceRedraw;
 END
 ELSE { I don’t know how to do this object }
 UpdatedLink := FALSE;
 END { TLinkItem.UpdatedLink };

{$S LnkItmRes}
PROCEDURE TLinkItem.SetText
 (theText: str255; thePublisher: TObject);
 { Sets the text for the item and for each of }
 { the linked objects. thePublisher is the    }
 { object which originated the change; it’s   }
 { assumed to have updated itself.            }
 VAR  newSize: INTEGER;
 
 PROCEDURE FixText (theSubscriber: TObject);
 BEGIN
 IF theSubscriber <> thePublisher THEN
 IF NOT UpdatedLink (theSubscriber, theText) 
 THEN
 {$IFC qDebug}
 Writeln (‘Nobody handled link update for ‘, 
 theText);
 {$ENDC}
 END { FixText };
 
 BEGIN { TLinkItem.SetText }
 IF NOT fUpdating & (theText <> fText^^) THEN
 BEGIN
 fUpdating := TRUE;
 newSize := Length (theText) + 1;
 { need 1 extra byte for the length }
 IF Odd (newSize)
 THEN newSize := newSize + 1;
 IF GetHandleSize (Handle (fText)) < newSize
 THEN SetHandleSize (Handle (fText),
 newSize + kSizeJump);
 FailMemError;
 BlockMove (@theText, Ptr (fText^), newSize);
 fLinks.Each (FixText);
 fUpdating := FALSE;
 END;
 END { TLinkItem.SetText };
 
{$S LnkItmRes}
PROCEDURE TLinkItem.GetText (VAR theText: str255);
 BEGIN
 theText := fText^^;
 END { TLinkItem.AddLink };
 
{$S LnkItmRes}
PROCEDURE TLinkItem.AddLink(theSubscriber: TObject);
 { adds the subscriber to the list, }
 { and sends the current data back. }
 VAR theIndex: ArrayIndex;
 theText: str255;
 BEGIN
 theIndex := fLinks.GetSameItemNo 
 (theSubscriber);
 { add it only if it’s not already there! }
 IF theIndex = kEmptyIndex THEN
 BEGIN
 fLinks.InsertLast (theSubscriber);
 GetText (theText);
 IF NOT UpdatedLink (theSubscriber, theText) 
 THEN
 {$IFC qDebug}
 Writeln (
 ‘Nobody handled link update in AddLink for ‘,                 
 theText);
 {$ENDC}
 END;
 END { TLinkItem.AddLink };
 
{$S LnkItmRes}
PROCEDURE TLinkItem.RemoveLink
 (theSubscriber: TObject);
 VAR theIndex: ArrayIndex;
 BEGIN
 theIndex := fLinks.GetSameItemNo 
 (theSubscriber);
 If theIndex > kEmptyIndex
 THEN fLinks.AtDelete (theIndex);
 END { TLinkItem.RemoveLink };
 
{$S LnkItmFields}
PROCEDURE TLinkItem.Fields (
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER)); 
 OVERRIDE;
 BEGIN
 DoToField(‘TLinkItem’, NIL, bClass);
 DoToField(‘fText’, @fText, bString);
 DoToField(‘fLinks’, @fLinks, bObject);
 INHERITED Fields(DoToField);
 END { TLinkItem.Fields };

{------------ TLinkEditText ------------------}
{$S LnkItmOpen}
PROCEDURE TLinkEditText.ILinkEditText
 (itsSuperView: TView;
 itsLocation, itsSize: VPoint; 
 itsMaxChars: INTEGER; 
 itsLink: TLinkItem);
 VAR theText: str255;
 BEGIN
 IEditText (itsSuperView, itsLocation, itsSize, 
 itsMaxChars);
 fLink := itsLink;
 IF fLink <> NIL THEN
 fLink.AddLink (SELF);
 END { TLinkEditText.ILinkEditText };

{$S LnkItmClose}
PROCEDURE TLinkEditText.Free; OVERRIDE;
 BEGIN
 { If I’m a publisher, I may also be a   }
 { subscriber. Try to remove myself from }
 { the list of subscribers.              }
 IF fLink <> NIL THEN
 fLink.RemoveLink (SELF);
 INHERITED Free;
 END { TLinkEditText.Free };
 
{$S LnkItmRes}
PROCEDURE TLinkEditText.SetText 
 (theText: Str255;
 redraw: BOOLEAN);
 OVERRIDE;
 VAR  currentText: Str255;
 area: Rect;
 BEGIN
 IF fLink <> NIL THEN
 fLink.SetText (theText, SELF);
 INHERITED SetText(theText, redraw);
 END { TLinkEditText.SetText };

{$S LnkItmFields}
PROCEDURE TLinkEditText.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER)); 
 OVERRIDE;
 BEGIN
 DoToField(‘TLinkEditText’, NIL, bClass);
 DoToField(‘fLink’, @fLink, bObject);
 INHERITED Fields(DoToField);
 END { TLinkEditText.Fields };

{------------ TLinkDialogTEView ----------------}
{$S LnkItmOpen}
PROCEDURE TLinkDialogTEView.IDialogTEView
 (itsDocument: TDocument;
 itsSuperView: TView;
 itsLocation, itsSize: VPoint;
 itsHDeterminer, 
 itsVDeterminer: SizeDeterminer;
 itsInset: Rect;
 itsTextStyle: TextStyle;
 itsJustification: INTEGER;
 itsStyleType, itsAutoWrap: BOOLEAN);  OVERRIDE;
 BEGIN
 fLink := NIL;
 INHERITED IDialogTEView (itsDocument, 
 itsSuperView, itsLocation, itsSize, 
 itsHDeterminer, itsVDeterminer, 
 itsInset, itsTextStyle, 
 itsJustification,  itsStyleType, 
 itsAutoWrap)
 END { TLinkDialogTEView.IDialogTEView };

{$S LnkItmRes}
PROCEDURE TLinkDialogTEView.SynchView
 (redraw: BOOLEAN); OVERRIDE;
 { If I’m a publisher, get & publish my text, }
 { so the link can update the other displays. }
 VAR theText:    str255;
 theTextHdl:Handle;
 nChars:INTEGER;
 BEGIN
 INHERITED SynchView (redraw);
 IF fLink <> NIL THEN
 BEGIN
 theTextHdl := ExtractText;
 nChars := Min(GetHandleSize (theTextHdl), 255);
 {$Push} {$R-}
 theText[0] := Chr (nChars);
 {$Pop}
 BlockMove (Ptr (theTextHdl^), @theText [1], 
 nChars);
 fLink.SetText (theText, SELF);
 END;
 END { TLinkDialogTEView.SynchView };
 
{$S ARes}
PROCEDURE TLinkDialogTEView.InstallEditText 
 (theEditText: TEditText;
 selectChars: BOOLEAN); OVERRIDE;
 { When I install myself in an EditText, I }
 { must use the EditText’s LinkItem as my own. }
 VAR theText: Str255;
 BEGIN
 IF fLink <> NIL THEN
 BEGIN
 fLink.RemoveLink (SELF);
 fLink := NIL;
 END;
 IF (theEditText <> NIL)
 & Member (theEditText, TLinkEditText) 
 THEN fLink := TLinkEditText 
 (theEditText).fLink;
 IF fLink <> NIL THEN
 fLink.AddLink (SELF);
 INHERITED InstallEditText
 (theEditText, selectChars);
 END { TLinkDialogTEView.InstallEditText };

{$S LnkItmFields}
PROCEDURE TLinkDialogTEView.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER)); 
 OVERRIDE;
 BEGIN
 DoToField(‘TLinkDialogTEView’, NIL, bClass);
 DoToField(‘fLink’, @fLink, bObject);
 INHERITED Fields(DoToField);
 END { TLinkDialogTEView.Fields };

{------------ TLinkDialogView ----------------}
{$S LnkItmOpen}
FUNCTION TLinkDialogView.MakeTEView: TDialogTEView; OVERRIDE;
 VAR aDialogTEView:TLinkDialogTEView;
 BEGIN
 New(aDialogTEView);
 FailNIL(aDialogTEView);
 aDialogTEView.IDialogTEView (NIL, NIL,
 gZeroVPt, gZeroVPt,
 sizeRelSuperView, sizeVariable, 
 gZeroRect, gSystemStyle, teJustSystem, 
 kWithoutStyle, False);
 aDialogTEView.fMinAhead := 1;
 MakeTEView := aDialogTEView;
 END { TLinkDialogView.MakeTEView };

{$S LnkItmFields}
PROCEDURE TLinkDialogView.Fields(  
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER)); 
 OVERRIDE;
 BEGIN
 DoToField(‘TLinkDialogView’, NIL, bClass);
 INHERITED Fields(DoToField);
 END { TLinkDialogView.Fields };


{========== File ULinkDemo.p ============}
UNIT ULinkDemo;
INTERFACE
USES
 UMacApp, UTEView, UDialog,
 Fonts, ToolUtils, 
 ULinkItem;
TYPE
 TLinkApplication= OBJECT (TApplication)
 fItem1, fItem2: TLinkItem;
 PROCEDURE TLinkApplication.ILinkApplication
 (itsMainFileType: OSType);
 { Initializes the application and globals. }
 FUNCTION TLinkApplication.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand; 
 OVERRIDE;
 PROCEDURE TLinkApplication.DoSetupMenus; 
 OVERRIDE;
 PROCEDURE TLinkApplication.Fields(
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER));
 OVERRIDE;
 END;
IMPLEMENTATION
 {$I ULinkDemo.inc1.p}
END.

{======= File ULinkDemo.inc1.p ==========}
CONST
 cMakeWindow   = 1001;
{-------------- TLinkApplication ----------------}
{$S AInit}
PROCEDURE TLinkApplication.ILinkApplication 
 (itsMainFileType: OSType);
 VAR anItem: TLinkItem;
 BEGIN
 gAlwaysTrackCursor := TRUE;
 IApplication(itsMainFileType);
 { Suppress creation of new document at launch }
 fLaunchWithNewDocument := FALSE;
 NEW (anItem);
 FailNIL (anItem);
 fItem1 := anItem;
 fItem1.ILinkItem (‘an Item’);
 NEW (anItem);
 FailNIL (anItem);
 fItem2 := anItem;
 fItem2.ILinkItem (‘another Item’);
 END;

{$S ASelCommand}
FUNCTION TLinkApplication.DoMenuCommand
 (aCmdNumber: CmdNumber): TCommand;

 PROCEDURE MakeWindow;
 VAR  itsLocation: VPoint;
 itsSize: VPoint;
 ts: TextStyle;
 aWindow: TWindow;
 aDialogView: TLinkDialogView;
 anEditView: TLinkEditText;
 BEGIN
 NEW(aDialogView);
 FailNIL(aDialogView);
 SetVPt(itsSize, 250, 130);
 aDialogView.IDialogView(NIL, NIL, gZeroVPt, 
 itsSize, SizeFixed, SizeFixed,
 kNoIdentifier, kNoIdentifier);

 aWindow := NewSimpleWindow (aCmdNumber, 
 TRUE, TRUE, NIL, aDialogView);
 aWindow.fFreeOnClosing := TRUE;
 aWindow.SimpleStagger(kStdStaggerAmount, 
 kStdStaggerAmount, gStdStaggerCount);

 { make two edit texts linked to item1 }
 NEW(anEditView);
 FailNIL(anEditView);
 SetVPt(itsLocation, 10, 20);
 SetVPt(itsSize, 100, 22);
 anEditView.ILinkEditText(aDialogView, 
 itsLocation, itsSize, 255, fItem1);
 SetTextStyle(ts, applFont, [], 12, gRGBBlack);
 anEditView.InstallTextStyle(ts, kDontRedraw);
 anEditView.SetJustification(teJustSystem, 
 kDontRedraw);

 NEW(anEditView);
 FailNIL(anEditView);
 SetVPt(itsLocation, 120, 20);
 SetVPt(itsSize, 100, 22);
 anEditView.ILinkEditText(aDialogView, 
 itsLocation, itsSize, 255, fItem1);
 SetTextStyle(ts, applFont, [], 12, gRGBBlack);
 anEditView.InstallTextStyle(ts, kDontRedraw);
 anEditView.SetJustification(teJustRight, kDontRedraw);

 { make an edit text linked to item2 }
 NEW(anEditView);
 FailNIL(anEditView);
 SetVPt(itsLocation, 120, 60);
 SetVPt(itsSize, 100, 22);
 anEditView.ILinkEditText(aDialogView, 
 itsLocation, itsSize, 255, fItem2);
 SetTextStyle(ts, applFont, [], 12, gRGBBlack);
 anEditView.InstallTextStyle(ts, kDontRedraw);
 anEditView.SetJustification(teJustSystem, 
 kDontRedraw);
 
 { make a fourth, unlinked EditText }
 NEW(anEditView);
 FailNIL(anEditView);
 SetVPt(itsLocation, 120, 100);
 SetVPt(itsSize, 100, 22);
 anEditView.ILinkEditText(aDialogView, 
 itsLocation, itsSize, 255, NIL);
 SetTextStyle(ts, applFont, [], 12, gRGBBlack);
 anEditView.InstallTextStyle(ts, kDontRedraw);
 anEditView.SetJustification(teJustRight, 
 kDontRedraw);
 anEditView.SetText(‘unlinked’, kDontRedraw);
 
 aWindow.Open;
 END { MakeWindow };

 BEGIN { DoMenuCommand }
 DoMenuCommand := NIL;
 CASE aCmdNumber OF
 cMakeWindow:  MakeWindow;
 OTHERWISEDoMenuCommand := 
 INHERITED DoMenuCommand(aCmdNumber);
 END { CASE };
 END { DoMenuCommand };


{$S ARes}
PROCEDURE TLinkApplication.DoSetupMenus; 
 OVERRIDE;
 BEGIN
 INHERITED DoSetupMenus;
 Enable(cMakeWindow, TRUE);
 END;

{$S AFields}
PROCEDURE TLinkApplication.Fields( 
 PROCEDURE DoToField(fieldName: Str255;
 fieldAddr: Ptr;
 fieldType: INTEGER)); 
 OVERRIDE;
 BEGIN
 DoToField(‘TLinkApplication’, NIL, bClass);
 INHERITED Fields(DoToField);
 END { TLinkApplication.Fields };

{========== File MLinkDemo.p ============}
PROGRAM LinkDemo;
  {$MC68020-}  
  {$MC68881-}
 { The main program must be universal code }
 USES
 UMacApp, UTEView, UDialog,
 ULinkItem, ULinkDemo;
 VAR
 gLinkApplication: TLinkApplication; BEGIN
 InitToolBox;
 IF ValidateConfiguration(gConfiguration) THEN     
 { Make sure we can run }
 BEGIN
 { Continue with remainder of initialization }
 InitUMacApp(8);
 InitUTEView;
 InitUDialog;

 New(gLinkApplication);
 FailNil(gLinkApplication);
 gLinkApplication.ILinkApplication (‘????’);       gLinkApplication.Run;
 END
 ELSE
 StdAlert(phUnsupportedConfiguration);
 END.

{========== File LinkDemo.r ============}
/* Note: .rsrc files have been changed to .r.o, */
/* as per Tech Note #280. */
#ifndef __TYPES.R__
#include “Types.r”
#endif

#ifndef __MacAppTypes__
#include “MacAppTypes.r”
#endif

#if qTemplateViews
#ifndef __ViewTypes__
#include “ViewTypes.r”
#endif
#endif

#if qDebug
include “Debug.r.o”;
#endif
include “MacApp.r.o”;
include “Dialog.r.o”;

include $$Shell(“ObjApp”)”LinkDemo” ‘CODE’;

/* Command numbers */
#define cNewWindow 1001

resource ‘seg!’ (256, purgeable) {
 {   “GOpen”;
 “GClose”;
 “GNonRes”;
 “GSelCommand”;
 “GDoCommand”
 }
};

resource ‘SIZE’ (-1) {
 dontSaveScreen,
 acceptSuspendResumeEvents,
 enableOptionSwitch,
 canBackground,
 MultiFinderAware,
 backgroundAndForeground,
 dontGetFrontClicks,
 ignoreChildDiedEvents,
 is32BitCompatible,
 reserved, reserved, reserved, reserved, 
 reserved, reserved, reserved,
#if qDebug
 500 * 1024, 400 * 1024
#else
 290 * 1024, 218 * 1024
#endif
};

resource ‘DITL’ (phAboutApp, purgeable) {
  {
/* [1] */ {160, 182, 180, 262}, Button { enabled, “OK” };
/* [2] */ {8, 70, 152, 316}, StaticText { disabled, 
 “This program demonstrates simultaneous updating of several TextEdits.” 

 “\n\nThis program was written for MacTutor by Scott Steketee “
 “with MacApp® © 1985-1990 Apple Computer, Inc.”};
/* [3] */ {10, 20, 42, 52}, Icon { disabled, 1 }
 }
};

resource ‘ALRT’ (1000, purgeable) {
 {44, 48, 130, 358},
 1000,
 { OK, visible, sound1,
 OK, visible, sound1,
 OK, visible, sound1,
 OK, visible, sound1
 }
};

include “Defaults.r.o”  ‘ALRT’ (phAboutApp); // Grab the default about 
box

include “Defaults.r.o” ‘cmnu’ (mApple);// Grab the default Apple menu

resource ‘cmnu’ (mFile) {
 mFile,
 textMenuProc,
 0x7FFFFBBB,
 enabled,
 “File”,
  { “Quit”, noIcon, “Q”,  noMark, plain, cQuit }
};

include “Defaults.r.o” ‘cmnu’ (mEdit); // Grab the default Edit menus

resource ‘cmnu’ (4) {
 4,
 textMenuProc,
 0x7FFFFFBD,
 enabled,
 “LinkDemo”,
  {“New Window”, noIcon, noKey, noMark, plain, cNewWindow;}
};

include “Defaults.r.o” ‘cmnu’ (mBuzzwords);  // Get the default buzzwords 
menu


resource ‘MBAR’ (kMBarDisplayed) { 
 {mApple; mFile; mEdit; 4} };

/***********************************/
/* Views by procedure      */
/***********************************/
resource ‘WIND’ (cNewWindow, purgeable) {
 {50, 20, 200, 300}, zoomDocProc, invisible, goAway, 0x0, “Window”
};

type ‘SS11’ as ‘STR ‘;
resource ‘SS11’ (0,
#if qNames
“Signature”,
#endif
 purgeable) {
 “Application created by MacApp®”
};

resource ‘BNDL’ (128,
#if qNames
“Bundle”,
#endif
 purgeable) {
 ‘SS11’,
 0,
 { ‘ICN#’,
 { 0, 128, },
 ‘FREF’,
 { 0, 128, }
 }
};

include “Defaults.r.o”  ‘STR#’ (kDefaultCredits);        // Grab the 
default credits

// Get the default MacApp® application icon and necessary bundling rsrcs
include “Defaults.r.o”  ‘FREF’ (128);
include “Defaults.r.o”  ‘ICN#’ (128);

// Get the default Version resources
include “Defaults.r.o”  ‘vers’ (1);
 // Application or file specific
include “Defaults.r.o”  ‘vers’ (2);
 // Overall package
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Ableton Live 10.1.1 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
BetterTouchTool 3.202 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Fission 2.4.6 - Streamlined audio editor...
Fission can crop and trim audio, paste in or join files, or just rapidly split one long file into many. It's streamlined for fast editing. Plus, it works without the quality loss caused by other... Read more
Drama 1.0.27 - Prototyping, animation...
Drama's handy 3-in-1 functionality uniquely integrates design, animation and prototyping into a single familiar tool. No more frustrating switching between apps or learning new stuff. And by... Read more
Adobe Lightroom Classic CC 8.4.1 - Impor...
Adobe Lightroom Classic is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Adobe Lightroom Classic CC (was Adobe... Read more
iExplorer 4.3.2 - View and transfer file...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
Adobe After Effects CC 2018 16.1.3 - Cre...
After Effects CC 2018 is available as part of Adobe Creative Cloud for $52.99/month (or $20.99/month for a single app license). The new, more connected After Effects CC 2018 can make the impossible... Read more
Adobe Audition CC 2019 12.1.4 - Professi...
Audition CC 2019 is available as part of Adobe Creative Cloud for as little as $20.99/month (or $9.99/month if you're a previous Audition customer). Adobe Audition CC 2019 empowers you to create and... Read more
Adobe Premiere Pro CC 2019 13.1.5 - Digi...
Premiere Pro CC 2019 is available as part of Adobe Creative Cloud for as little as $52.99/month. The price on display is a price for annual by-monthly plan for Adobe Premiere Pro only Adobe Premiere... Read more
Navicat Premium Essentials 12.1.25 - Pro...
Navicat Premium Essentials is a compact version of Navicat which provides basic and necessary features you will need to perform simple administration on a database. It supports the latest features... Read more

Latest Forum Discussions

See All

Marvel Strike Force is adding Agent Coul...
Marvel Strike Force, the popular squad-based RPG, is set to receive a bunch of new content over the next few weeks. [Read more] | Read more »
Lots of premium games are going free (so...
You may have seen over the past couple weeks a that a bunch of premium games have suddenly become free. This isn’t a mistake, nor is it some last hurrah before Apple Arcade hits, and it’s important to know that these games aren’t actually becoming... | Read more »
Yoozoo Games launches Saint Seiya Awaken...
If you’re into your anime, you’ve probably seen or heard of Saint Seiya. Based on a shonen manga by Masami Kurumada, the series was massively popular in the 1980s – especially in its native Japan. Since then, it’s grown into a franchise of all... | Read more »
Five Nights at Freddy's AR: Special...
Five Nights at Freddy's AR: Special Delivery is a terrifying new nightmare from developer Illumix. Last week, FNAF fans were sent into a frenzy by a short teaser for what we now know to be Special Delivery. Those in the comments were quick to... | Read more »
Rush Rally 3's new live events are...
Last week, Rush Rally 3 got updated with live events, and it’s one of the best things to happen to racing games on mobile. Prior to this update, the game already had multiplayer, but live events are more convenient in the sense that it’s somewhat... | Read more »
Why your free-to-play racer sucks
It’s been this way for a while now, but playing Hot Wheels Infinite Loop really highlights a big issue with free-to-play mobile racing games: They suck. It doesn’t matter if you’re trying going for realism, cart racing, or arcade nonsense, they’re... | Read more »
Steam Link Spotlight - The Banner Saga 3
Steam Link Spotlight is a new feature where we take a look at PC games that play exceptionally well using the Steam Link app. Our last entry talked about Terry Cavanaugh’s incredible Dicey Dungeons. Read about how it’s a great mobile experience... | Read more »
Combo Quest (Games)
Combo Quest 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Combo Quest is an epic, time tap role-playing adventure. In this unique masterpiece, you are a knight on a heroic quest to retrieve... | Read more »
Hero Emblems (Games)
Hero Emblems 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ** 25% OFF for a limited time to celebrate the release ** ** Note for iPhone 6 user: If it doesn't run fullscreen on your device... | Read more »
Puzzle Blitz (Games)
Puzzle Blitz 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Puzzle Blitz is a frantic puzzle solving race against the clock! Solve as many puzzles as you can, before time runs out! You have... | Read more »

Price Scanner via MacPrices.net

4-core and 6-core 2018 Mac minis available at...
Apple has Certified Refurbished 2018 Mac minis available on their online store for $120-$170 off the cost of new models. Each mini comes with a new outer case plus a standard Apple one-year warranty... Read more
$250 prepaid Visa card with any Apple iPhone,...
Xfinity Mobile will include a free $250 prepaid Visa card with the purchase of any new iPhone, new line activation, and transfer of phone number to Xfinity Mobile. Offer is valid through October 27,... Read more
Sprint is offering the 64GB Apple iPhone 11 P...
Sprint has the new 64GB iPhone 11 Pro available for $12.50 per month for new customers with an eligible trade-in in of iPhone 7 or newer. That’s down from their standard monthly lease of $41.67. The... Read more
Final week: Apple’s 2019 Back to School Promo...
Purchase a new Mac using Apple’s Education discount, and take up to $400 off MSRP. All teachers, students, and staff of any educational institution with a .edu email address qualify for the discount... Read more
Save $30 on Apple’s AirPods at these reseller...
Amazon is offering discounts on new 2019 Apple AirPods ranging up to $30 off MSRP as part of their Labor Day sale. Shipping is free: – AirPods with Charging Case: $144.95 $15 off MSRP – AirPods with... Read more
Preorder your Apple Watch Series 5 today at A...
Amazon has Apple Watch Series 5 GPS models available for preorder and on sale today for $15 off Apple’s MSRP. Shipping is free and starts on September 20th: – 40mm Apple Watch Series 5 GPS: $384.99 $... Read more
21″ iMacs on sale for $100 off Apple’s MSRP,...
B&H Photo has new 21″ Apple iMacs on sale for $100 off MSRP with models available starting at $999. These are the same iMacs offered by Apple in their retail and online stores. Overnight shipping... Read more
2018 4 and 6-Core Mac minis on sale today for...
Apple resellers are offering new 2018 4-Core and 6-Core Mac minis for $100-$150 off MSRP for a limited time. B&H Photo has the new 2018 4-Core and 6-Core Mac minis on sale for up to $150 off... Read more
Save $150-$250 on 10.2″ WiFi + Cellular iPads...
Verizon is offering $150-$250 discounts on Apple’s new 10.2″ WiFi + Cellular iPad with service. Buy the iPad itself and save $150. Save $250 on the purchase of an iPad along with an iPhone. The fine... Read more
Apple continues to offer 13″ 2.3GHz Dual-Core...
Apple has Certified Refurbished 2017 13″ 2.3GHz Dual-Core non-Touch Bar MacBook Pros available starting at $1019. An standard Apple one-year warranty is included with each model, outer cases are new... Read more

Jobs Board

*Apple* Mobility Pro - Best Buy (United Stat...
**719499BR** **Job Title:** Apple Mobility Pro **Job Category:** Store Associates **Location Number:** 001266-Charleston-Store **Job Description:** At Best Buy, our Read more
Best Buy *Apple* Computing Master - Best Bu...
**733266BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000144-Union City-Store **Job Description:** **What does a Read more
Best Buy *Apple* Computing Master - Best Bu...
**730765BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000565-St Petersburg-Store **Job Description:** **What does Read more
*Apple* Mobile Master - Best Buy (United Sta...
**725617BR** **Job Title:** Apple Mobile Master **Job Category:** Store Associates **Location Number:** 001095-Chesterfield-Store **Job Description:** **What does a Read more
Student Employment (Blue *Apple* Cafe) Spri...
Student Employment (Blue Apple Cafe) Spring 2019 Penn State University Campus/Location: Penn State Brandywine Campus City: Media, PA Date Announced: 12/20/2018 Date Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.