ViewTV:
PUBLIC
PROC [rec: TypedVariable,
specs: ViewRec.BindingList ← NIL,
label: Rope.ROPE ← NIL,
otherStuff: OtherStuffProc ← NIL,
toDo: DoitProc ← NIL,
toDoData: REF ANY ← NIL,
parent: RecordViewer ← NIL,
sample: BOOLEAN ← TRUE,
holdOff: BOOLEAN ← FALSE,
highlightSelectedProc: BOOLEAN ← TRUE,
createOptions: CreateOptions ← [],
viewerInit: ViewerClasses.ViewerRec ← [],
paint: BOOLEAN ← TRUE]
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: INTEGER ← IF 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: BOOLEAN ← FALSE;
argumentive: BOOLEAN ← FALSE;
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: BOOLEAN ← FALSE;
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;