January 93 - Customizing Views
Customizing Views
Angelika Peter
If you want to have subclasses of TView with additional fields, you face the problem that you can't initialize them from a 'View' resource if you want to use ViewEdit (or AdLib). With MacApp 2 style views it was relatively easy to derez the view resources, once the hierarchy was stable, and to maintain them as Rez sources.
With MacApp 3 style views, this becomes substantially more difficult. Not really impossible, but awkward enough to make me look for a workaround. Here it is:
THE SOLUTION
One of the (many) really good things about the new view format is the field fUserArea.
I am using it as a resource ID. The view subclass then reads a resource of a certain type with this ID and initializes its additional fields from this resource. Each subclass knows which resource type it has to use. Of course it is possible to have several levels of subclassing too. In this case every subclass would need it's own resource type.
All this happens in DoPostCreate, but one could probably do it in ReadFields if it is important that the fields are initialized before the DoPostCreate phase.
It is easy to maintain these resources either with ResEdit using own templates or with Rez, whichever is more convenient. And you have the additional advantage that the resources can be shared among several views.
AN EXAMPLE
My example is a TEditText subclass, used to enter numeric values. It is very much based on the old TExtendedText class from one of the MacApp 2 Goodies disks.
I want to initialize not only minimum and maximum from the resource but also the initial value, the precision and how it should behave when dimmed and whether to use scientific format.
The Pascal type template for the resource looks like this:
ExtTextDescribitor = RECORD
minimum: LongInt;
maximum: LongInt;
divisor: Integer;
precision: Integer;
maxMagnitude: Integer;
hideTextWhenDimmed: Integer; { 0 for false, <> 0 for true }
initialValue: Str255
END;
ExtTextDescribitorPtr = ^ExtTextDescribitor;
ExtTextDescribitorHandle = ^ExtTextDescribitorPtr;
The corresponding Rez template is:
type 'ExTx' {
longint; /* minimum value */
longint; /* maximum value */
integer; /* divisor (for minimum and maximum) */
integer; /* precision */
integer kNeverScientific=32000, kForceScientific=-1;
integer kShowTextWhenDimmed=0, kHideTextWhenDimmed =1;
pstring; /* initial value */
};
DoPostCreate would always look something like this:
PROCEDURE TExtendedText.DoPostCreate(itsDocument: TDocument);
OVERRIDE;
VAR
itsDescribitor: Handle;
fi: FailInfo;
PROCEDURE HdlDoPostCreate(error: OSErr; message: LongInt);
BEGIN
SELF.Free
END;
BEGIN { DoPostCreate }
INHERITED DoPostCreate(itsDocument);
IF fUserArea <> 0 THEN
BEGIN
CatchFailures(fi, HdlDoPostCreate);
{ !!! use your resource type here !!! }
itsDescribitor := GetResource('foo ', fUserArea));
FailNILResource(itsDescribitor);
HLock(Handle(itsDescribitor)); { to make WITH safe }
Success(fi);
WITH MyDescribitorTypeHandle(itsDescribitor)^^ DO
BEGIN
{ initialize your fields }
END; { with }
ReleaseResource(itsDescribitor)
END { if fUserArea… }
END; { DoPostCreate }
Initializing the fields is straightforward:
WITH itsDescribitor^^ DO
BEGIN
fPrecision := precision; { digits after decimal point }
fMaxMagnitude := maxMagnitude; { when to use scientific format }
fHideTextWhenDimmed := hideTextWhenDimmed <> 0;
IF minimum = - maxLongInt THEN {to be able to express ±∞}
fMinimum := - inf
ELSE
fMinimum := minimum / divisor; {for fractional minimum}
IF maximum = maxLongInt THEN
fMaximum := + inf
ELSE
fMaximum := maximum / divisor; {for fractional maximum}
fValue := initialValue;
SELF.SetModifiedText(initialValue, kRedraw)
END; { with }