FILE: ViewRecCreate
last edited by Spreitzer May 2, 1983 10:57 pm
Last Edited by: Maxwell, November 16, 1982 3:29 pm
DIRECTORY
AMTypes, Atom, RTMiniModel, BBApply, Rope, ViewerClasses, ViewerOps, ViewerTools, ViewRec, ViewRecInsides, VFonts, Buttons, Containers, Labels, Rules, Process, Convert, IO, Icons, Real, TIPUser;
ViewRecCreate: CEDAR PROGRAM
IMPORTS AMTypes, Atom, VO: ViewerOps, VF:VFonts, VT:ViewerTools, Containers, Buttons, Labels, Rope, Rules, IO, Icons, Real, ViewRec, ViewRecInsides
EXPORTS ViewRec, ViewRecInsides
SHARES Atom =
BEGIN OPEN ViewRecInsides;
AlreadyHandled: PUBLIC ERROR = CODE;
RecordViewer: TYPE = REF RecordViewerRep;
RecordViewerRep: PUBLIC TYPE = RECORD [data: Data];
nameStyles: PUBLIC NameStyles;
myIconFlavors: ARRAY BOOLEAN OF Icons.IconFlavor;
ecHandlerProp: PUBLIC ATOM ← Atom.Gensym[];
gtHandlerProp: PUBLIC ATOM ← Atom.Gensym[];
befores: PUBLIC ARRAY Reductions OF RList ← ALL[NIL];
afterAlls: PUBLIC RList ← NIL;
classRecers: PUBLIC ARRAY AMTypes.Class OF RList ← ALL[NIL];
evClass: ViewerClasses.ViewerClass;
RegisterRecognizerByType: PUBLIC PROC [r: Recognizer, end: AddPlace, type: Type--unreduced--, reductions: Reductions] =
BEGIN
IF reductions # EquivalenceClass THEN type ← AMTypes.GroundStar[type];
IF reductions = TypeClass THEN
BEGIN
tc: AMTypes.Class ← AMTypes.TypeClass[type];
classRecers[tc] ← AddToList[classRecers[tc], r, end];
END
ELSE BEGIN
hp: ATOMIF reductions = StripSubranges THEN gtHandlerProp ELSE ecHandlerProp;
rl: RList ← NARROW[Atom.TypeGetProp[type: type, prop: hp]];
rl ← AddToList[rl, r, end];
Atom.TypePutProp[type: type, prop: hp, val: rl];
END;
END;
RegisterRecognizerBeforeReductions: PUBLIC PROC [r: Recognizer, end: AddPlace, applyBefore: Reductions] =
BEGIN
befores[applyBefore] ← AddToList[befores[applyBefore], r, end];
END;
RegisterRecognizerToApplyAfterAll: PUBLIC PROC [r: Recognizer, end: AddPlace] =
BEGIN
afterAlls ← AddToList[afterAlls, r, end];
END;
AddToList: PROC [rl: RList, r: Recognizer, end: AddPlace] RETURNS [new: RList] =
BEGIN
IF end = Front THEN RETURN [CONS[r, rl]];
IF rl = NIL THEN RETURN [LIST[r]];
new ← rl;
WHILE rl.rest # NIL DO rl ← rl.rest ENDLOOP;
rl.rest ← LIST[r];
END;
DoBindings: PROC [obj: TypedVariable, type: Type, bl: BindingList] =
BEGIN
SELECT AMTypes.TypeClass[type] FROM
record, structure => NULL;
ENDCASE => ERROR;
FOR i: CARDINAL IN [1..AMTypes.NComponents[type]] DO
var: TypedVariable ← AMTypes.IndexToTV[obj, i];
vt: Type ← AMTypes.IndexToType[type, i];
ut: Type ← AMTypes.GroundStar[vt];
name: ROPE ← AMTypes.IndexToName[type, i];
val: TypedVariable;
sublist: BindingList;
inList: BOOLEAN;
[sublist, , val, inList, , , ,] ← SelectBindings[bl, name, i];
IF inList THEN
BEGIN
c: TypedVariable;
c ← AMTypes.Coerce[val, vt];
AMTypes.Assign[var, val];
END
ELSE IF sublist # NIL THEN SELECT AMTypes.TypeClass[ut] FROM
record, structure => DoBindings[var, ut, sublist];
ENDCASE => ERROR;
ENDLOOP;
END;
RightFont: PROC [f: VF.Font] RETURNS [rf: VF.Font] =
{RETURN [IF f = NIL THEN VF.defaultFont ELSE f]};
FillInDefaultFields: PROC [tv: TypedVariable, type: Type] =
BEGIN
n: CARDINAL ← AMTypes.NComponents[type];
FOR i: CARDINAL IN [1..n] DO
div: TypedVariable ← NIL;
div ← AMTypes.IndexToDefaultInitialValue[type, i !AMTypes.Error => {div ← NIL; CONTINUE}];
IF div # NIL THEN
BEGIN
field: TypedVariable ← AMTypes.IndexToTV[tv, i];
AMTypes.Assign[lhs: field, rhs: div];
END;
ENDLOOP;
END;
ViewTV: PUBLIC PROC [rec: TypedVariable,
specs: ViewRec.BindingList ← NIL,
label: Rope.ROPENIL,
otherStuff: OtherStuffProc ← NIL,
toDo: DoitProc ← NIL,
toDoData: REF ANYNIL,
parent: RecordViewer ← NIL,
sample: BOOLEANTRUE,
holdOff: BOOLEANFALSE,
highlightSelectedProc: BOOLEANTRUE,
createOptions: CreateOptions ← [],
viewerInit: ViewerClasses.ViewerRec ← [],
paint: BOOLEANTRUE]
RETURNS [rv: RecordViewer] =
BEGIN
NewProcedure: PROC [pt: Type, p: TypedVariable, name: ROPE, hasDom, hasRange: BOOLEAN, argSpecs, retSpecs: BindingList] RETURNS [Viewer] =
BEGIN
pd: ProcData ← NEW [EltDataRec[Proc]];
pco: CreateOptions ← createOptions;
by, rx: INTEGER ← 0;
dt: Type ← AMTypes.Domain[pt];
rt: Type ← AMTypes.Range[pt];
doitButton: Buttons.Button;
pco.feedBackHeight ← 0;
pd.name ← name;
pd.domainInst ← AMTypes.New[dt];
IF hasDom THEN FillInDefaultFields[pd.domainInst, dt];
pd.proc ← p;
pd.parent ← d;
pd.prev ← d.last;
d.last ← pd;
pd.variable ← FALSE;
pd.update ← ProcUpdate;
pd.hasDom ← hasDom;
pd.hasRet ← hasRange;
pd.argret ← Containers.Create[paint: FALSE,
info: [parent: d.argContainer, ww: targetWidth, wh: 10, border: FALSE,
scrollable: FALSE]];
IF NOT holdOff THEN
BEGIN
doitButton ← Buttons.Create[paint: FALSE,
font: RightFont[createOptions.doitFont],
proc: InnerProcButtonProc, clientData: pd,
info: [parent: pd.argret, border: createOptions.bordDoit,
name: Rope.Cat["Do ", name]] ];
pd.stateLabel ← Labels.Create[paint: FALSE,
font: RightFont[createOptions.stateFont],
info: [parent: pd.argret, border: createOptions.bordState,
wx: doitButton.wx + doitButton.ww + createOptions.hSep,
name: "working on old"]];
Labels.Set[label: pd.stateLabel, value: "", paint: FALSE];
by ← MAX[doitButton.wy + doitButton.wh, pd.stateLabel.wy + pd.stateLabel.wh] + createOptions.vSep;
rx ← MAX[rx, pd.stateLabel.wx + pd.stateLabel.ww];
END;
IF hasDom THEN
BEGIN
pd.argRV ← ViewTV[rec: pd.domainInst,
specs: argSpecs,
toDo: ProcDoit,
parent: rv, sample: FALSE,
createOptions: pco,
viewerInit: [parent: pd.argret,
wy: by,
ww: pd.argret.cw,
border: FALSE,
scrollable: FALSE],
paint: FALSE].data;
pd.argRV.edParent ← pd;
rx ← MAX[rx, pd.argRV.v.ww];
by ← pd.argRV.v.wy + pd.argRV.v.wh;
END
ELSE BEGIN
IF AMTypes.TypeClass[dt] # nil THEN
DoBindings[pd.domainInst, dt, argSpecs];
END;
pd.retInst ← AMTypes.New[rt];
IF pd.hasRet THEN
BEGIN
IF hasDom THEN BEGIN
[] ← Rules.Create[paint: FALSE,
info: [parent: pd.argret, wx: 0, wy: by+createOptions.vSep,
ww: 1023, wh: 1, border: FALSE]];
by ← by + 1 + 2*createOptions.vSep;
END;
pd.retRV ← ViewTV[rec: pd.retInst,
specs: retSpecs,
parent: rv, sample: FALSE,
createOptions: pco,
viewerInit: [parent: pd.argret,
ww: pd.argret.cw,
wy: by,
border: FALSE,
scrollable: FALSE],
paint: FALSE].data;
pd.retRV.edParent ← pd;
rx ← MAX[rx, pd.retRV.v.ww];
by ← pd.retRV.v.wy + pd.retRV.v.wh;
END;
IF pd.hasRet OR hasDom THEN BEGIN
VO.MoveViewer[viewer: pd.argret, paint: FALSE,
x: nowhere, y: 0,
w: pd.argret.ww,
h: by + pd.argret.wh - pd.argret.ch];
argH ← MAX[argH, pd.argret.wh];
rightX ← MAX[rightX, rx + pd.argret.ww - pd.argret.cw];
argumentive ← TRUE;
END
ELSE BEGIN
VO.DestroyViewer[viewer: pd.argret, paint: FALSE];
pd.argret ← NIL;
END;
pd.b ← Buttons.Create[paint: FALSE,
font: RightFont[createOptions.procFont],
proc: ProcButtonProc, clientData: pd,
info: [parent: d.v, name: name, border: createOptions.bordProcs]];
RETURN [pd.b];
END;
NewSimple: PROC [tt, wt: Type, sv: TypedVariable, handler: SimpleHandler, name: ROPE, editable: BOOLEAN, notifies: NotifyList, handlerData: REF ANY] RETURNS [v: Viewer] =
BEGIN
mx, askW: INTEGER;
askLines: REAL;
sd: SimpleData ← NEW [EltDataRec[Simple]];
ut: Type ← AMTypes.UnderType[tt];
tc: AMTypes.Class ← AMTypes.TypeClass[tt];
v ← VO.CreateViewer[flavor: $EltViewer, paint: FALSE,
info: [parent: d.v, name: name, data: sd, ww: 10, wh: 10, border: createOptions.bordElts]];
sd.name ← name;
sd.var ← sv;
sd.old ← AMTypes.New[tt];
AMTypes.Assign[sd.old, sd.var];
sd.handler ← handler;
sd.handlerData ← handlerData;
sd.wideAsTV ← AMTypes.New[wt];
sd.targType ← tt;
sd.variable ← editable AND AMTypes.TVStatus[sv] = mutable AND handler.Parse # NIL;
sd.notifyRequests ← notifies;
sd.ToRope ← SimpleToRope;
sd.AssignRope ← SimpleAssignRope;
IF tc # definition THEN sd.typeDoc ← IO.PutFR["%g", IO.type[tt]]
ELSE sd.typeDoc ← IO.PutFR["%g=%g", IO.type[tt], IO.type[ut]];
sd.parent ← d;
sd.prev ← d.last;
d.last ← sd;
sd.update ← UpdateNV;
sd.b ← Buttons.Create[paint: FALSE,
proc: NVButtonProc,
clientData: sd,
info: [parent: v, name: name.Concat[":"], border: FALSE,
wy: createOptions.vStilts],
font: RightFont[createOptions.nameFont]];
mx ← sd.b.wx + sd.b.ww + createOptions.nvSep;
[askW, askLines] ← handler.Max[sv, tt, handlerData];
sd.t ← VO.CreateViewer[flavor: $Text, paint: FALSE,
info: [parent: v, border: FALSE, scrollable: askLines > 1,
wx: sd.b.wx+sd.b.ww + createOptions.nvSep,
ww: MIN[askW + createOptions.hPad, targetWidth - mx],
wh: Real.RoundI[askLines*VF.FontHeight[]+createOptions.vPad] ]];
VO.AddProp[viewer: sd.t, prop: $EltData, val: sd];
VT.InhibitUserEdits[sd.t];
VO.MoveViewer[viewer: v, x: v.wx, y: v.wy, w: sd.t.wx+sd.t.ww, h: MAX[sd.b.wh+createOptions.vStilts, sd.t.wh], paint: FALSE];
VO.MoveViewer[viewer: sd.b, x: sd.b.wx, y: MAX[(v.wh - sd.b.wh)/2, createOptions.vStilts], w: sd.b.ww, h: sd.b.wh, paint: FALSE];
SetRope[sd, SimpleToRope[sd], FALSE];
ShowState[sd, FALSE];
END;
NewRecord: PROC [tt, rt: Type, r: TypedVariable, name: ROPE, bindings: BindingList, editable: BOOLEAN] RETURNS [v: Viewer] =
BEGIN
rd: RecordData ← NEW [EltDataRec[Record]];
tc: AMTypes.Class ← AMTypes.TypeClass[tt];
rco: CreateOptions ← createOptions;
mx: INTEGER;
v ← VO.CreateViewer[flavor: $EltViewer, paint: FALSE,
info: [parent: d.v, name: name, data: rd, ww: 10, wh: 10, border: createOptions.bordElts]];
rd.name ← name;
rd.update ← UpdateRecord;
rd.var ← r;
rd.old ← AMTypes.New[tt];
rd.variable ← editable AND AMTypes.TVStatus[r] = mutable;
rd.typeDoc ← IF tc # definition THEN IO.PutFR["%g", IO.type[tt]]
ELSE IO.PutFR["%g=%g", IO.type[tt], IO.type[rt]];
AMTypes.Assign[rd.old, rd.var];
rd.parent ← d;
rd.prev ← d.last;
d.last ← rd;
rd.b ← Buttons.Create[paint: FALSE,
proc: NVButtonProc,
clientData: rd,
info: [parent: v, name: name.Concat[":"], border: FALSE],
font: RightFont[createOptions.nameFont]];
rco.feedBackHeight ← 0;
mx ← rd.b.wx + rd.b.ww + createOptions.nvSep;
rd.d ← ViewTV[rec: r,
specs: bindings,
toDo: toDo,
parent: rv, sample: FALSE,
createOptions: rco,
viewerInit: [parent: v, border: createOptions.bordRecs,
wx: mx, wh: 10,
ww: MAX[targetWidth - mx, createOptions.minRecordWidth],
scrollable: FALSE],
paint: FALSE].data;
rd.d.edParent ← rd;
VO.MoveViewer[viewer: v, x: v.wx, y: v.wy, w: rd.d.v.wx+rd.d.v.ww,
h: MAX[rd.b.wh, rd.d.v.wh], paint: FALSE];
VO.MoveViewer[viewer: rd.b, x: rd.b.wx,
y: (v.ch - rd.b.wh)/2, w: rd.b.ww, h: rd.b.wh, paint: FALSE];
END;
NewComplex: PROC [tt, ut: Type, cv: TypedVariable, handler: ComplexHandler, name: ROPE, editable: BOOLEAN, notifies: NotifyList, handlerData: REF ANY] RETURNS [v: Viewer] =
BEGIN
cd: ComplexData ← NEW [EltDataRec[Complex]];
tc: AMTypes.Class ← AMTypes.TypeClass[tt];
cco: CreateOptions ← createOptions;
cco.feedBackHeight ← 0;
cd.name ← name;
cd.updater ← handler.updater;
cd.handlerData ← handlerData;
[v, cd.clientData] ← handler.producer[cv, [main: d.v, for: rv, name: name, createOptions: cco, notifies: notifies], handlerData];
cd.update ← UpdateComplex;
cd.var ← cv;
cd.old ← AMTypes.New[tt];
AMTypes.Assign[cd.old, cd.var];
cd.notifyRequests ← notifies;
cd.variable ← editable AND AMTypes.TVStatus[cv] = mutable;
cd.typeDoc ← IF tc # definition THEN IO.PutFR["%g", IO.type[tt]]
ELSE IO.PutFR["%g=%g", IO.type[tt], IO.type[ut]];
cd.parent ← d;
cd.prev ← d.last;
d.last ← cd;
END;
Place: PROC [v: Viewer] =
BEGIN
dx: INTEGERIF bottomRightX # 0 THEN createOptions.hSep ELSE 0;
IF forceNewRow OR (v.ww + dx + bottomRightX > targetWidth) THEN
BEGIN
rightX ← MAX[rightX, bottomRightX];
bottomY ← bottomY + rowH +
(IF rightX > 0 THEN createOptions.vSep ELSE 0);
rowH ← dx ← bottomRightX ← 0;
END;
VO.MoveViewer[viewer: v,
x: bottomRightX + dx, y: bottomY, w: v.ww, h: v.wh, paint: FALSE];
bottomRightX ← v.wx+v.ww;
rowH ← MAX[rowH, v.wh];
forceNewRow ← FALSE;
END;
recsType: Type ← AMTypes.UnderType[AMTypes.TVType[rec]];
len: CARDINAL;
bottomY, bottomRightX, rightX, rowH, argH: INTEGER ← 0;
forceNewRow: BOOLEANFALSE;
argumentive: BOOLEANFALSE;
targetWidth: INTEGER;
d: Data ← NEW [DataRec];
vParent: Viewer ← viewerInit.parent;
rv ← NEW [RecordViewerRep ← [d]];
d.asRV ← rv;
d.toDo ← toDo;
d.toDoData ← toDoData;
d.holdOff ← holdOff;
d.highlightSelectedProc ← highlightSelectedProc;
SELECT AMTypes.TypeClass[recsType] FROM
record, structure => NULL;
ENDCASE => ERROR ViewRec.NotARecord;
targetWidth ← viewerInit.ww;
IF vParent = NIL THEN viewerInit.ww ← 0;
IF viewerInit.icon = unInit THEN
viewerInit.icon ← myIconFlavors[VF.StringWidth[viewerInit.name] > 75];
d.v ← Containers.Create[paint: FALSE, info: viewerInit];
VO.AddProp[d.v, $RecordViewerData, rv];
targetWidth ←
IF targetWidth # 0 THEN
(IF vParent = NIL THEN targetWidth ELSE d.v.cw)
ELSE IF vParent = NIL AND NOT viewerInit.iconic THEN d.v.cw
ELSE createOptions.defaultTargetWidth;
d.argContainer ← Containers.Create[paint: FALSE,
info: [parent: d.v, wx: 0, wy: 0, ww: 10, wh: 10,
border: FALSE, scrollable: FALSE]];
IF label.Length[] > 0 THEN
BEGIN
fnr: BOOLEANFALSE;
IF label.Fetch[label.Length[] - 1] = '\n THEN
BEGIN
label ← label.Substr[len: label.Length[] - 1];
fnr ← TRUE;
END;
Place[Labels.Create[paint: FALSE,
info: [name: label, parent: d.v, border: FALSE],
font: RightFont[createOptions.labelFont] ]];
forceNewRow ← fnr;
END;
IF otherStuff # NIL THEN
BEGIN
stuff: LIST OF Viewer ← otherStuff[d.v];
WHILE stuff # NIL DO Place[stuff.first]; stuff ← stuff.rest ENDLOOP;
END;
len ← AMTypes.NComponents[recsType];
FOR i: CARDINAL IN [1..len] DO
v: TypedVariable ← AMTypes.IndexToTV[rec, i];
iType: Type ← AMTypes.TVType[v];
cType: Type ← AMTypes.GroundStar[iType];
cClass: AMTypes.Class ← AMTypes.TypeClass[cType];
name: ROPE ← AMTypes.IndexToName[recsType, i];
val: TypedVariable;
sublist, altSublist: BindingList;
inList, visible, editable: BOOLEAN;
notifies: NotifyList;
recers: RList;
IF v = NIL THEN LOOP;
IF name.Length[] = 0 THEN name ← "anonymous";
[sublist, altSublist, val, inList, visible, editable, notifies, recers] ← SelectBindings[specs, name, i];
IF inList THEN
BEGIN
c: TypedVariable;
c ← AMTypes.Coerce[val, iType];
AMTypes.Assign[v, c];
END;
IF NOT (inList AND NOT visible) THEN
BEGIN
recognized: BOOLEAN;
handler, handlerData: REF ANY;
[recognized, handler, handlerData] ← Recognize[t: iType, specials: recers, onlyRecognize: FALSE];
IF recognized
THEN WITH handler SELECT FROM
sh: SimpleHandler => BEGIN
Place[NewSimple[iType, cType, v, sh, name, editable, notifies, handlerData]];
END;
ch: ComplexHandler => BEGIN
Place[NewComplex[iType, AMTypes.UnderType[iType], v, ch, name, editable, notifies, handlerData]];
END;
ENDCASE => ERROR
ELSE SELECT cClass FROM
record, structure => BEGIN
ok: BOOLEAN;
presentable: CARDINAL;
[ok, presentable] ← SimpleEnough[cType, sublist, createOptions.doAllRecords];
IF ok AND presentable > 0 THEN Place[NewRecord[iType, cType, v, name, sublist, editable]];
END;
procedure => BEGIN
ok, hasDom, hasRange: BOOLEAN;
[ok, hasDom, hasRange] ← OKProc[cType, sublist, altSublist, createOptions.doAllRecords];
IF ok THEN Place[NewProcedure[cType, v, name, hasDom, hasRange, sublist, altSublist]];
END;
ENDCASE;
END;
ENDLOOP;
FOR e: EltData ← d.last, e.prev WHILE e # NIL DO
IF e.prev # NIL THEN e.prev.next ← e ELSE d.first ← e;
ENDLOOP;
bottomY ← bottomY + rowH;
IF argumentive THEN
BEGIN
[] ← Rules.Create[paint: FALSE,
info: [parent: d.v, wx: 0, wy: bottomY+createOptions.vSep,
ww: 1023, wh: 1, border: FALSE]];
d.argPlace ← bottomY + 1+2*createOptions.vSep;
VO.MoveViewer[viewer: d.argContainer, paint: FALSE,
x: 0, y: d.argPlace,
w: rightX + d.argContainer.ww - d.argContainer.cw,
h: argH + d.argContainer.wh - d.argContainer.ch];
bottomY ← d.argContainer.wy + d.argContainer.wh;
END
ELSE BEGIN
VO.DestroyViewer[viewer: d.argContainer, paint: FALSE];
d.argContainer ← NIL;
END;
IF createOptions.feedBackHeight > 0 THEN
BEGIN
fPlace: INTEGER ← bottomY + 1+2*createOptions.vSep;
[] ← Rules.Create[paint: FALSE,
info: [parent: d.v, wx: 0, wy: bottomY+createOptions.vSep,
wh: 1, ww: 1023, border: FALSE]];
d.feedBack ← VT.MakeNewTextViewer[paint: FALSE, info: [
parent: d.v, name: "FeedBack", border: FALSE,
wx: 0, wy: fPlace, ww: targetWidth, wh: createOptions.feedBackHeight]];
VT.InhibitUserEdits[d.feedBack];
bottomY ← fPlace + createOptions.feedBackHeight;
Containers.ChildYBound[d.v, d.feedBack];
Containers.ChildXBound[d.v, d.feedBack];
END
ELSE d.feedBack ← NIL;
d.rvParent ← IF parent # NIL THEN parent.data ELSE NIL;
IF vParent = NIL THEN
BEGIN
IF bottomY < 700 --don't confuse Viewers!-- THEN VO.SetOpenHeight[d.v, bottomY];
IF NOT paint THEN NULL
ELSE IF d.v.iconic THEN VO.PaintViewer[viewer: d.v, hint: all]
ELSE VO.ComputeColumn[d.v.column];
END
ELSE BEGIN
VO.MoveViewer[viewer: d.v, x: d.v.wx, y: d.v.wy,
w: (d.v.ww-d.v.cw)+MAX[rightX, bottomRightX],
h: (d.v.wh - d.v.ch) + bottomY,
paint: paint];
END;
IF sample THEN roots ← CONS[d, roots];
END;
RVQuaViewer: PUBLIC PROC [rv: RecordViewer] RETURNS [Viewer] =
{RETURN [rv.data.v]};
ViewerIsRV: PUBLIC PROC [v: Viewer] RETURNS [BOOLEAN] =
{RETURN [VO.FetchProp[v, $RecordViewerData] # NIL]};
ViewerQuaRV: PUBLIC PROC [v: Viewer] RETURNS [RecordViewer] =
{RETURN [NARROW[VO.FetchProp[v, $RecordViewerData]]]};
RVToData: PUBLIC PROC [rv: RecordViewer] RETURNS [Data] =
{RETURN [rv.data]};
Setup: PROC =
BEGIN
myIconFlavors[FALSE] ← Icons.NewIconFromFile["ViewRec.Icons", 0];
myIconFlavors[TRUE] ← Icons.NewIconFromFile["ViewRec.Icons", 1];
evClass ← NEW [ViewerClasses.ViewerClassRec ← [
flavor: $EltViewer,
destroy: DestroyEltViewer]];
VO.RegisterViewerClass[$EltViewer, evClass];
nameStyles ← [quiescent: $BlackOnWhite,
opened: $WhiteOnBlack, running: $WhiteOnBlack,
invariant: $BlackOnGrey, beingShown: $BlackOnGrey];
END;
Setup[];
END.