DIRECTORY AMBridge, AMTypes, Atom, Buttons, Containers, Icons, IO, Labels, List, MJSContainers, PrintTV, ProcessProps, Real, Rope, Rules, TypeProps, VFonts, ViewerClasses, ViewerOps, ViewerTools, ViewRec, ViewRecInsides; ViewRecCreate: CEDAR PROGRAM IMPORTS AMBridge, AMTypes, Atom, Buttons, Containers, Icons, IO, Labels, List, MJSContainers, PrintTV, ProcessProps, Real, Rope, Rules, TypeProps, VO: ViewerOps, VF:VFonts, VT:ViewerTools, ViewRec, ViewRecInsides EXPORTS ViewRec, ViewRecInsides = BEGIN OPEN ViewRecInsides; AlreadyHandled: PUBLIC ERROR = CODE; RecordViewer: TYPE = REF RecordViewerRep; RecordViewerRep: PUBLIC TYPE = RECORD [data: Data]; nameStyles: PUBLIC NameStyles; myIconFlavors: ARRAY [0..2] OF Icons.IconFlavor; ecHandlerProp: PUBLIC ATOM _ Atom.MakeAtom["Mike Spreitzer December 12, 1983 6:16 pm"]; gtHandlerProp: PUBLIC ATOM _ Atom.MakeAtom["Mike Spreitzer December 12, 1983 6:17 pm"]; befores: PUBLIC ARRAY Reductions OF RList _ ALL[NIL]; afterAlls: PUBLIC RList _ NIL; classRecers: PUBLIC ARRAY AMTypes.Class OF RList _ ALL[NIL]; evClass: ViewerClasses.ViewerClass; rvClass: MJSContainers.MJSContainerClass; 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: ATOM _ IF reductions = StripSubranges THEN gtHandlerProp ELSE ecHandlerProp; rl: RList _ NARROW[TypeProps.Get[type: type, key: hp]]; rl _ AddToList[rl, r, end]; TypeProps.Put[type: type, key: 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 index: TypedVariable; len: CARDINAL; vt, ut: Type; tc: AMTypes.Class _ AMTypes.TypeClass[type]; SELECT tc FROM record, structure => BEGIN len _ AMTypes.NComponents[type]; END; sequence => BEGIN index _ AMTypes.First[AMTypes.TVType[AMTypes.Tag[obj]]]; len _ AMTypes.Length[obj]; vt _ AMTypes.Range[type]; ut _ AMTypes.GroundStar[vt]; END; array => BEGIN dt: Type _ AMTypes.Domain[type]; index _ AMTypes.First[dt]; len _ NElts[dt]; END; ENDCASE => ERROR NotAnAggregate; FOR i: CARDINAL IN [1 .. len] DO var, val: TypedVariable; name: ROPE; sublist: BindingList; inList, dontAssign: BOOLEAN; SELECT tc FROM record, structure => BEGIN var _ AMTypes.IndexToTV[obj, i]; vt _ AMTypes.IndexToType[type, i]; ut _ AMTypes.GroundStar[vt]; name _ AMTypes.IndexToName[type, i]; END; sequence, array => BEGIN s: IO.STREAM _ IO.ROS[]; IF i > 1 THEN index _ AMTypes.Next[index]; var _ AMTypes.Apply[mapper: obj, arg: index]; PrintTV.Print[index, s]; name _ s.RopeFromROS[]; END; ENDCASE => ERROR; [sublist, , val, inList, , , dontAssign, ,] _ SelectBindings[bl, name, i]; IF inList THEN BEGIN IF NOT dontAssign THEN BEGIN c: TypedVariable; c _ AMTypes.Coerce[val, vt]; AMTypes.Assign[var, val]; END; END ELSE IF sublist # NIL THEN SELECT AMTypes.TypeClass[ut] FROM record, structure, sequence, array => DoBindings[var, ut, sublist]; ENDCASE => ERROR; ENDLOOP; END; 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; GetName: PUBLIC PROC [tv: TypedVariable] RETURNS [name: ROPE] = BEGIN type: Type _ AMTypes.UnderType[AMTypes.TVType[tv]]; class: AMTypes.Class _ AMTypes.TypeClass[type]; name _ NIL; SELECT class FROM record, structure => BEGIN ok: BOOLEAN _ TRUE; index: CARDINAL; index _ AMTypes.NameToIndex[type, "name" !AMTypes.Error => {ok _ FALSE; CONTINUE}]; IF ok THEN BEGIN nameTV: TypedVariable _ AMTypes.IndexToTV[tv, index]; name _ AMTypes.TVToName[nameTV !AMTypes.Error => {ok _ FALSE; CONTINUE}]; IF NOT ok THEN name _ NIL; END; END; ENDCASE; END; ViewTV: PUBLIC PROC [agg: TypedVariable, specs: ViewRec.BindingList _ NIL, label: Rope.ROPE _ NIL, otherStuff: OtherStuffProc _ NIL, toButt: ButtonClick _ [], parent: RecordViewer _ NIL, asElement: EltHandle _ NIL, sample: 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; dt: Type _ AMTypes.Domain[pt]; rt: Type _ AMTypes.Range[pt]; pco.feedBackHeight _ 0; pco.mayInitiateRelayout _ FALSE; pd.name _ name; pd.domainInst _ AMTypes.New[dt]; IF hasDom THEN FillInDefaultFields[pd.domainInst, dt]; pd.sampleable _ FALSE; pd.var _ pd.old _ NIL; 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, scrollable: TRUE, border: FALSE, wx: nowhere, ww: d.argContainer.cw, wh: 10]]; d.argretScrollDiffX _ pd.argret.ww - pd.argret.cw; IF NOT createOptions.holdOff THEN BEGIN pd.doitButton _ Buttons.Create[paint: FALSE, font: ViewRec.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: ViewRec.RightFont[createOptions.stateFont], info: [parent: pd.argret, border: createOptions.bordState, wx: pd.doitButton.wx + pd.doitButton.ww + createOptions.hSep, name: "working on old"]]; Labels.Set[label: pd.stateLabel, value: "", paint: FALSE]; END; pd.container _ Buttons.Create[paint: FALSE, font: ViewRec.RightFont[IF hasDom OR hasRange THEN createOptions.preProcFont ELSE createOptions.immProcFont], proc: ProcButtonProc, clientData: pd, info: [parent: d.eltsContainer, name: name, border: IF hasDom OR hasRange THEN createOptions.bordPreProcs ELSE createOptions.bordImmProcs]]; IF hasDom THEN BEGIN pd.argRV _ ViewTV[agg: pd.domainInst, specs: argSpecs, toButt: [pd.doitButton], parent: rv, sample: FALSE, createOptions: pco, viewerInit: [parent: pd.argret, wy: 0, ww: pd.argret.cw, border: FALSE, scrollable: FALSE], paint: FALSE].data; pd.argRV.edParent _ pd; 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 pd.rule _ Rules.Create[paint: FALSE, info: [parent: pd.argret, wx: 0, wy: 0, ww: 1023, wh: 1, border: FALSE]]; END; pd.retRV _ ViewTV[agg: pd.retInst, specs: retSpecs, parent: rv, sample: FALSE, createOptions: pco, viewerInit: [parent: pd.argret, ww: pd.argret.cw, wy: 0, border: FALSE, scrollable: FALSE], paint: FALSE].data; pd.retRV.edParent _ pd; END; IF pd.hasRet OR hasDom THEN BEGIN FinishProc[pd, d]; argH _ MAX[argH, pd.argret.wh]; argretWidth _ MAX[argretWidth, pd.argret.ww]; argumentive _ TRUE; END ELSE BEGIN VO.DestroyViewer[viewer: pd.argret, paint: FALSE]; pd.argret _ NIL; END; RETURN [pd.container]; END; NewSimple: PROC [tt, wt: Type, sv: TypedVariable, handler: SimpleHandler, name: ROPE, editable: BOOLEAN, notifies: NotifyList, handlerData: REF ANY] RETURNS [v: Viewer] = BEGIN mx, diff: INTEGER; askLines: REAL; sd: SimpleData _ NEW [EltDataRec[Simple]]; ut: Type _ AMTypes.UnderType[tt]; sd.container _ v _ VO.CreateViewer[flavor: $EltViewer, paint: FALSE, info: [parent: d.eltsContainer, name: name, data: sd, ww: 20, wh: 20, border: createOptions.bordElts]]; diff _ v.ww - v.cw; sd.name _ name; sd.var _ sv; sd.sampleable _ TRUE; sd.old _ AMTypes.Copy[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; sd.typeDoc _ TellType[tt, ut]; sd.parent _ d; sd.prev _ d.last; d.last _ sd; sd.update _ UpdateNV; sd.nameButton _ Buttons.Create[paint: FALSE, proc: NVButtonProc, clientData: sd, info: [parent: v, name: name.Concat[":"], border: FALSE, wy: MAX[createOptions.vStilts, 0]], font: ViewRec.RightFont[createOptions.nameFont]]; mx _ sd.nameButton.wx + sd.nameButton.ww + createOptions.nvSep; [sd.askW, askLines] _ handler.Max[sv, tt, handlerData]; sd.valueText _ VO.CreateViewer[flavor: $Text, paint: FALSE, info: [parent: v, border: FALSE, scrollable: askLines > 1, wx: mx, wy: MAX[-createOptions.vStilts, 0], ww: MIN[sd.askW + createOptions.hPad, placing.targetWidth - diff - mx], wh: Real.RoundI[askLines*VF.FontHeight[]+createOptions.vPad] ]]; VO.AddProp[viewer: sd.valueText, prop: $EltData, val: sd]; VT.InhibitUserEdits[sd.valueText]; VO.MoveViewer[viewer: v, x: v.wx, y: v.wy, w: diff + sd.valueText.wx + sd.valueText.ww, h: (v.wh - v.ch) + MAX[ sd.nameButton.wy+sd.nameButton.wh, sd.valueText.wy + sd.valueText.wh], paint: FALSE]; SetRope[sd, SimpleToRope[sd], FALSE]; ShowState[sd, FALSE]; END; TellType: PROC [tt, ut: Type] RETURNS [td: ROPE] = BEGIN t2: ROPE; s: IO.STREAM _ IO.ROS[]; PrintTV.PrintType[tt, s]; td _ s.RopeFromROS[]; IF AMTypes.TypeClass[tt] # definition THEN RETURN; s _ IO.ROS[]; PrintTV.PrintType[ut, s]; t2 _ s.RopeFromROS[]; IF NOT Rope.Equal[td, t2] THEN td _ td.Cat["=", t2]; END; NewComplex: PROC [tt, ut: Type, cv: TypedVariable, handler: ComplexHandler, name: ROPE, bindings: BindingList, editable: BOOLEAN, notifies: NotifyList, handlerData: REF ANY] RETURNS [v: Viewer] = BEGIN cd: ComplexData _ NEW [EltDataRec[Complex]]; cco: CreateOptions _ createOptions; cco.feedBackHeight _ 0; cco.mayInitiateRelayout _ FALSE; cd.name _ name; cd.handler _ handler; cd.handlerData _ handlerData; [v, cd.clientData, cd.sampleable] _ handler.producer[cv, [main: d.eltsContainer, for: rv, maxWidth: placing.targetWidth, name: name, thisElement: cd, createOptions: cco, notifies: notifies, bindings: bindings, toButt: toButt], handlerData]; cd.container _ v; IF v = NIL THEN RETURN; VO.AddProp[viewer: v, prop: $EltData, val: cd]; cd.sampleable _ cd.sampleable AND handler.updater # NIL; cd.update _ UpdateComplex; cd.var _ cv; IF cd.sampleable THEN cd.old _ AMTypes.Copy[cd.var] ELSE cd.old _ NIL; cd.notifyRequests _ notifies; cd.variable _ editable AND AMTypes.TVStatus[cv] = mutable; cd.typeDoc _ TellType[tt, ut]; cd.parent _ d; cd.prev _ d.last; d.last _ cd; END; aggsType: Type _ AMTypes.UnderType[AMTypes.TVType[agg]]; aggsClass: AMTypes.Class _ AMTypes.TypeClass[aggsType]; len: CARDINAL; placing: Placing _ NEW [PlacingRep _ [createOptions.hSep, createOptions.vSep, 0, 0]]; argH: INTEGER _ 0; argretWidth: INTEGER _ 0; argumentive: BOOLEAN _ FALSE; d: Data _ NEW [DataRec _ []]; index: TypedVariable; rv _ NEW [RecordViewerRep _ [d]]; d.asRV _ rv; viewerInit.data _ d; d.wdir _ NARROW[List.Assoc[key: $WorkingDirectory, aList: ProcessProps.GetPropList[]]]; d.toButt _ toButt; d.edParent _ NARROW[asElement]; d.exclusiveProcs _ createOptions.exclusiveProcs; d.holdOff _ createOptions.holdOff; d.highlightSelectedProc _ createOptions.highlightSelectedProc; d.relayoutable _ createOptions.relayoutable; d.mayInitiateRelayout _ createOptions.mayInitiateRelayout; d.hSep _ createOptions.hSep; d.vSep _ createOptions.vSep; d.nvSep _ createOptions.nvSep; d.hPad _ createOptions.hPad; d.maxEltsHeight _ createOptions.maxEltsHeight; d.minFeedBackWidth _ createOptions.minFeedBackWidth; d.feedBackHeight _ createOptions.feedBackHeight; SELECT aggsClass FROM record, structure, sequence, array => NULL; ENDCASE => ERROR ViewRec.NotAnAggregate; IF viewerInit.name = NIL THEN viewerInit.name _ GetName[agg]; d.targetWidth _ viewerInit.ww; IF viewerInit.parent = NIL THEN viewerInit.ww _ 0; IF viewerInit.icon = unInit THEN viewerInit.icon _ myIconFlavors[ SELECT VF.StringWidth[viewerInit.name] FROM < 75 => 0, < 150 => 1, ENDCASE => 2]; d.v _ MJSContainers.Create[viewerFlavor: $RecordViewer, paint: FALSE, info: viewerInit]; d.outerScrollDiffX _ d.v.ww - d.v.cw; d.eltsContainer _ Containers.Create[paint: FALSE, info: [parent: d.v, border: FALSE, scrollable: TRUE, ww: d.v.cw, wh: 10, name: "Elements"]]; d.eltsScrollDiffX _ d.eltsContainer.ww - d.eltsContainer.cw; d.targetWidth _ IF d.v.parent = NIL AND NOT d.v.iconic THEN d.v.ww ELSE IF d.targetWidth # 0 THEN d.targetWidth ELSE createOptions.defaultTargetWidth; placing.targetWidth _ d.targetWidth - (d.outerScrollDiffX + d.eltsScrollDiffX); d.argContainer _ Containers.Create[paint: FALSE, info: [parent: d.v, wx: 0, wy: 0, ww: (d.targetWidth - d.outerScrollDiffX), wh: 10, border: FALSE, scrollable: FALSE, name: "Preparations"]]; d.prepsDiffX _ d.argContainer.ww - d.argContainer.cw; d.maxArgretHeight _ createOptions.maxArgsHeight - (d.argContainer.wh - d.argContainer.ch); 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[placing, d.label _ Labels.Create[paint: FALSE, info: [name: label, parent: d.eltsContainer, border: FALSE], font: ViewRec.RightFont[createOptions.labelFont] ]]; placing.forceNewRow _ d.loneLabel _ fnr; END; IF otherStuff # NIL THEN BEGIN stuff: LIST OF Viewer _ d.otherStuff _ otherStuff[d.eltsContainer]; WHILE stuff # NIL DO Place[placing, stuff.first]; stuff _ stuff.rest ENDLOOP; END; SELECT aggsClass FROM record, structure => len _ AMTypes.NComponents[aggsType]; sequence => BEGIN tag: TypedVariable _ AMTypes.Tag[agg]; index _ AMTypes.First[AMTypes.TVType[tag]]; len _ AMTypes.Length[agg]; END; array => BEGIN dt: Type _ AMTypes.Domain[aggsType]; index _ AMTypes.First[dt]; len _ NElts[dt]; END; ENDCASE => ERROR; FOR i: CARDINAL IN [1..len] DO GetComponent: PROC = {SELECT aggsClass FROM record, structure => BEGIN v _ AMTypes.IndexToTV[agg, i]; name _ AMTypes.IndexToName[aggsType, i]; END; sequence, array => BEGIN s: IO.STREAM _ IO.ROS[]; IF i > 1 THEN {IF (index _ AMTypes.Next[index]) = NIL THEN ERROR}; v _ AMTypes.Apply[mapper: agg, arg: index]; PrintTV.Print[index, s]; name _ s.RopeFromROS[]; END; ENDCASE => ERROR}; v: TypedVariable; iType: Type; cType: Type; cClass: AMTypes.Class; name: ROPE; val: TypedVariable; sublist, altSublist: BindingList; inList, visible, editable, dontAssign: BOOLEAN; notifies: NotifyList; recers: RList; GetComponent[]; IF v = NIL THEN LOOP; IF name.Length[] = 0 THEN name _ "anonymous"; iType _ AMTypes.TVType[v]; cType _ AMTypes.GroundStar[iType]; cClass _ AMTypes.TypeClass[cType]; [sublist, altSublist, val, inList, visible, editable, dontAssign, notifies, recers] _ SelectBindings[specs, name, i]; IF inList THEN BEGIN IF NOT dontAssign THEN BEGIN c: TypedVariable; c _ AMTypes.Coerce[val, iType]; AMTypes.Assign[v, c]; END; 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, specs: sublist, createOptions: createOptions]; IF recognized THEN WITH handler SELECT FROM sh: SimpleHandler => BEGIN Place[placing, NewSimple[iType, cType, v, sh, name, editable, notifies, handlerData]]; END; ch: ComplexHandler => BEGIN sv: Viewer _ NewComplex[iType, AMTypes.UnderType[iType], v, ch, name, sublist, editable, notifies, handlerData]; IF sv # NIL THEN Place[placing, sv]; END; ENDCASE => ERROR ELSE SELECT cClass FROM procedure => BEGIN ok, hasDom, hasRange: BOOLEAN; [ok, hasDom, hasRange] _ OKProc[cType, sublist, altSublist, createOptions]; IF ok THEN Place[placing, 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; IF argumentive THEN BEGIN d.rule1 _ Rules.Create[paint: FALSE, info: [parent: d.v, wx: 0, wy: 0, ww: 1023, wh: 1, border: FALSE]]; END ELSE BEGIN VO.DestroyViewer[viewer: d.argContainer, paint: FALSE]; d.argContainer _ NIL; END; IF createOptions.feedBackHeight > 0 THEN BEGIN d.rule2 _ Rules.Create[paint: FALSE, info: [parent: d.v, wx: 0, wy: 0, wh: 1, ww: 1023, border: FALSE]]; d.feedBack _ VT.MakeNewTextViewer[paint: FALSE, info: [ parent: d.v, name: "FeedBack", border: FALSE, wx: 0, wy: 0, ww: 50, wh: 20]]; VT.InhibitUserEdits[d.feedBack]; MJSContainers.ChildYBound[d.v, d.feedBack]; END ELSE d.feedBack _ NIL; d.rvParent _ IF parent # NIL THEN parent.data ELSE NIL; FinishRV[placing, d, argH, argretWidth, argumentive, paint]; IF sample THEN roots _ CONS[d, roots]; END; NoticeRecordViewerSizeChange: MJSContainers.SizeChangeNotifyProc--PROC [container: MJSContainer, cw, ch: BOOLEAN] RETURNS [paint: BOOLEAN _ TRUE]-- = BEGIN d: Data _ NARROW[MJSContainers.GetClientData[container]]; IF paint _ (cw AND NOT container.iconic AND d.mayInitiateRelayout AND d.relayoutable) THEN ReLayout[d.asRV, container.ww, FALSE]; END; Placing: TYPE = REF PlacingRep; PlacingRep: TYPE = RECORD [ hSep, vSep, targetWidth, offset--stupid fucking containers--: INTEGER, bottomY, bottomRightX, rightX, rowH: INTEGER _ 0, forceNewRow: BOOLEAN _ FALSE]; Place: PROC [p: Placing, v: Viewer] = BEGIN dx: INTEGER _ IF p.bottomRightX # 0 THEN p.hSep ELSE 0; IF p.forceNewRow OR (v.ww + dx + p.bottomRightX > p.targetWidth) THEN BEGIN p.rightX _ MAX[p.rightX, p.bottomRightX]; p.bottomY _ p.bottomY + p.rowH + (IF p.rightX > 0 THEN p.vSep ELSE 0); p.rowH _ dx _ p.bottomRightX _ 0; END; VO.MoveViewer[viewer: v, x: p.bottomRightX + dx, y: p.bottomY+p.offset, w: v.ww, h: v.wh, paint: FALSE]; p.bottomRightX _ v.wx+v.ww; p.rowH _ MAX[p.rowH, v.wh]; p.forceNewRow _ FALSE; END; ReLayout: PUBLIC PROC [rv: RecordViewer, targetWidth: INTEGER _ 0, paint: BOOLEAN] = BEGIN d: Data _ RVToData[rv]; placing: Placing; argH: INTEGER _ 0; argretWidth: INTEGER _ 0; argumentive: BOOLEAN _ FALSE; IF NOT d.relayoutable THEN RETURN; IF targetWidth = 0 THEN targetWidth _ d.v.ww; IF d.targetWidth = targetWidth THEN RETURN; d.targetWidth _ targetWidth; TRUSTED {placing _ NEW [PlacingRep _ [d.hSep, d.vSep, d.targetWidth - (d.outerScrollDiffX + d.eltsScrollDiffX), Containers.ScrollOffset[d.eltsContainer]]]}; IF d.label # NIL THEN Place[placing, d.label]; IF d.loneLabel THEN placing.forceNewRow _ TRUE; FOR stuff: LIST OF Viewer _ d.otherStuff, stuff.rest WHILE stuff # NIL DO Place[placing, stuff.first]; ENDLOOP; FOR ed: EltData _ d.first, ed.next WHILE ed # NIL DO WITH ed SELECT FROM cd: ComplexData => BEGIN IF cd.handler.relayouter # NIL THEN cd.handler.relayouter[cd.container, placing.targetWidth, cd.handlerData, cd.clientData]; END; sd: SimpleData => BEGIN v: Viewer _ sd.container; diff: INTEGER _ v.ww - v.cw; mx: INTEGER _ sd.nameButton.wx + sd.nameButton.ww + d.nvSep; textTarget: INTEGER _ MIN[sd.askW + d.hPad, placing.targetWidth - diff - mx]; IF sd.valueText.ww # textTarget THEN BEGIN VO.MoveViewer[viewer: sd.valueText, x: sd.valueText.wx, y: sd.valueText.wy, w: textTarget, h: sd.valueText.wh, paint: FALSE]; VO.MoveViewer[viewer: v, x: v.wx, y: v.wy, w: diff + sd.valueText.wx + sd.valueText.ww, h: v.wh, paint: FALSE]; END; END; pd: ProcData => BEGIN Do: PROC [subData: Data] = {IF subData # NIL THEN ReLayout[subData.asRV, d.targetWidth - (d.outerScrollDiffX + d.prepsDiffX + d.argretScrollDiffX), FALSE]}; Do[pd.argRV]; Do[pd.retRV]; IF pd.argRV # NIL OR pd.retRV # NIL THEN BEGIN FinishProc[pd, d]; argH _ MAX[argH, pd.argret.wh]; argretWidth _ MAX[argretWidth, pd.argret.ww]; argumentive _ TRUE; END; END; ENDCASE; Place[placing, ed.container]; ENDLOOP; FinishRV[placing, d, argH, argretWidth, argumentive, paint]; END; FinishRV: PROC [placing: Placing, d: Data, argH, argretWidth: INTEGER, argumentive, paint: BOOLEAN] = BEGIN desiredEltsHeight: INTEGER; offset: INTEGER _ MJSContainers.ScrollOffset[d.v]; oldScroll: BOOLEAN _ d.eltsContainer.scrollable; placing.bottomY _ placing.bottomY + placing.rowH; placing.rightX _ MAX[placing.rightX, placing.bottomRightX]; desiredEltsHeight _ placing.bottomY + d.eltsContainer.wh - d.eltsContainer.ch; IF desiredEltsHeight > d.maxEltsHeight THEN {desiredEltsHeight _ d.maxEltsHeight; d.eltsContainer.scrollable _ TRUE} ELSE d.eltsContainer.scrollable _ FALSE; VO.MoveViewer[viewer: d.eltsContainer, paint: FALSE, x: d.eltsContainer.wx, y: d.eltsContainer.wy, w: placing.rightX + d.eltsContainer.ww - d.eltsContainer.cw, h: desiredEltsHeight]; IF d.eltsContainer.scrollable # oldScroll THEN VO.MoveViewer[ viewer: d.eltsContainer, paint: FALSE, x: d.eltsContainer.wx, y: d.eltsContainer.wy, w: placing.rightX + d.eltsContainer.ww - d.eltsContainer.cw, h: desiredEltsHeight]; placing.bottomY _ d.eltsContainer.wy + d.eltsContainer.wh; placing.rightX _ d.eltsContainer.wx + d.eltsContainer.ww; IF argumentive THEN BEGIN desiredArgsHeight: INT _ argH + d.argContainer.wh - d.argContainer.ch; VO.MoveViewer[viewer: d.rule1, x: 0, y: placing.bottomY + d.vSep, w: d.rule1.ww, h: d.rule1.wh, paint: FALSE]; d.argPlace _ (d.rule1.wy - offset) + d.rule1.wh + d.vSep; VO.MoveViewer[viewer: d.argContainer, paint: FALSE, x: 0, y: d.argPlace + offset, w: argretWidth + d.argContainer.ww - d.argContainer.cw, h: desiredArgsHeight]; placing.bottomY _ d.argContainer.wy + d.argContainer.wh; placing.rightX _ MAX[placing.rightX, d.argContainer.wx + d.argContainer.ww]; END; IF d.feedBackHeight > 0 THEN BEGIN VO.MoveViewer[viewer: d.rule2, x: 0, y: placing.bottomY + d.vSep, w: d.rule2.ww, h: d.rule2.wh, paint: FALSE]; VO.MoveViewer[viewer: d.feedBack, x: 0, y: d.rule2.wy + d.rule2.wh + d.vSep, w: MAX[d.minFeedBackWidth, d.targetWidth - d.outerScrollDiffX], h: d.feedBackHeight, paint: FALSE]; placing.rightX _ MAX[placing.rightX, d.feedBack.wx + d.feedBack.ww]; placing.bottomY _ d.feedBack.wy + d.feedBack.wh; END; placing.bottomY _ placing.bottomY - offset; IF d.v.parent = NIL THEN BEGIN IF placing.bottomY < 650 --don't confuse Viewers!-- THEN VO.SetOpenHeight[d.v, placing.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) + placing.rightX, h: (d.v.wh - d.v.ch) + placing.bottomY, paint: paint]; END; END; FinishProc: PROC [pd: ProcData, d: Data] = BEGIN offset: INTEGER; by: INTEGER; rx: INTEGER _ 0; desiredArgretHeight: INT; oldScroll: BOOLEAN _ pd.argret.scrollable; TRUSTED {by _ offset _ Containers.ScrollOffset[pd.argret]}; IF pd.stateLabel # NIL THEN BEGIN by _ MAX[pd.doitButton.wy + pd.doitButton.wh, pd.stateLabel.wy + pd.stateLabel.wh]; rx _ pd.stateLabel.wx + pd.stateLabel.ww; END; IF pd.argRV # NIL THEN BEGIN VO.MoveViewer[viewer: pd.argRV.v, x: 0, y: by + d.vSep, w: pd.argRV.v.ww, h: pd.argRV.v.wh, paint: FALSE]; rx _ MAX[rx, pd.argRV.v.wx + pd.argRV.v.ww]; by _ pd.argRV.v.wy + pd.argRV.v.wh; END; IF pd.rule # NIL THEN BEGIN VO.MoveViewer[viewer: pd.rule, x: 0, y: by + d.vSep, w: pd.rule.ww, h: pd.rule.wh]; by _ pd.rule.wy + pd.rule.wh; END; IF pd.retRV # NIL THEN BEGIN VO.MoveViewer[viewer: pd.retRV.v, x: 0, y: by + d.vSep, w: pd.retRV.v.ww, h: pd.retRV.v.wh, paint: FALSE]; rx _ MAX[rx, pd.retRV.v.wx + pd.retRV.v.ww]; by _ pd.retRV.v.wy + pd.retRV.v.wh; END; by _ by - offset; desiredArgretHeight _ by + pd.argret.wh - pd.argret.ch; IF desiredArgretHeight > d.maxArgretHeight THEN {desiredArgretHeight _ d.maxArgretHeight; pd.argret.scrollable _ TRUE} ELSE pd.argret.scrollable _ FALSE; VO.MoveViewer[viewer: pd.argret, paint: FALSE, x: pd.argret.wx, y: 0, w: rx + pd.argret.ww - pd.argret.cw, h: desiredArgretHeight]; IF oldScroll # pd.argret.scrollable THEN VO.MoveViewer[ viewer: pd.argret, paint: FALSE, x: pd.argret.wx, y: 0, w: rx + pd.argret.ww - pd.argret.cw, h: desiredArgretHeight]; END; BindAllOfANameFromRef: PUBLIC PROC [agInst: REF ANY, name: ROPE, val: REF ANY, visible, editable, dontAssign: BOOLEAN _ FALSE] RETURNS [bl: BindingList] = TRUSTED BEGIN asTV: TypedVariable _ AMBridge.TVForReferent[val]; b: Binding _ [name: NIL, it: Value[val: asTV, visible: visible, editable: editable, dontAssign: dontAssign]]; bl _ BindAllOfANameInType[AMTypes.UnderType[AMTypes.TVType[AMBridge.TVForReferent[agInst]]], name, b]; END; BindAllOfANameInType: PUBLIC PROC [agType: Type, name: ROPE, b: Binding] RETURNS [bl: BindingList] = BEGIN agClass: AMTypes.Class _ AMTypes.TypeClass[agType]; len: CARDINAL; SELECT agClass FROM record, structure => len _ AMTypes.NComponents[agType]; sequence, array => len _ 1; ENDCASE => ERROR NotAnAggregate[]; bl _ NIL; FOR i: CARDINAL IN [1 .. len] DO id: Id; eType, euType: Type; eClass: AMTypes.Class; SELECT agClass FROM record, structure => BEGIN eName: ROPE; b.name _ id _ NEW [INT _ i]; eType _ AMTypes.IndexToType[agType, i]; eName _ AMTypes.IndexToName[agType, i]; IF name.Equal[eName] THEN bl _ CONS[b, bl]; END; sequence, array => BEGIN id _ ViewRec.all; eType _ AMTypes.Range[agType]; END; ENDCASE => ERROR; eClass _ AMTypes.TypeClass[euType _ AMTypes.UnderType[eType]]; SELECT eClass FROM procedure => BEGIN domType: Type _ AMTypes.Domain[euType]; rangeType: Type _ AMTypes.Range[euType]; argBL, retBL: BindingList; SELECT AMTypes.TypeClass[domType] FROM nil => argBL _ NIL; record, structure => argBL _ BindAllOfANameInType[domType, name, b]; ENDCASE => ERROR; SELECT AMTypes.TypeClass[rangeType] FROM nil => retBL _ NIL; record, structure => retBL _ BindAllOfANameInType[rangeType, name, b]; ENDCASE => ERROR; IF argBL # NIL OR retBL # NIL THEN bl _ CONS[[id, Group[argBL, retBL]], bl]; END; record, structure, sequence, array => BEGIN subList: BindingList _ BindAllOfANameInType[euType, name, b]; IF subList # NIL THEN bl _ CONS[[id, Group[subList]], bl]; END; ENDCASE; ENDLOOP; END; NElts: PROC [dt: Type] RETURNS [LONG CARDINAL] = TRUSTED BEGIN RETURN [(1+AMBridge.TVToLC[AMTypes.Last[dt]]) - AMBridge.TVToLC[AMTypes.First[dt]]]; END; RVQuaViewer: PUBLIC PROC [rv: RecordViewer] RETURNS [Viewer] = {RETURN [rv.data.v]}; ViewerIsRV: PUBLIC PROC [v: Viewer] RETURNS [BOOLEAN] = BEGIN cd: REF ANY; IF NOT MJSContainers.IsMJSContainer[v] THEN RETURN [FALSE]; cd _ MJSContainers.GetClientData[v]; RETURN [cd # NIL AND ISTYPE[cd, Data]]; END; ViewerQuaRV: PUBLIC PROC [v: Viewer] RETURNS [RecordViewer] = BEGIN cd: REF ANY; IF NOT MJSContainers.IsMJSContainer[v] THEN RETURN [NIL]; cd _ MJSContainers.GetClientData[v]; IF cd = NIL OR NOT ISTYPE[cd, Data] THEN RETURN [NIL]; RETURN [NARROW[cd, Data].asRV]; END; NarrowToRV: PUBLIC PROC [x: REF ANY] RETURNS [RecordViewer] = {RETURN [NARROW[x]]}; RVToData: PUBLIC PROC [rv: RecordViewer] RETURNS [Data] = {RETURN [rv.data]}; Setup: PROC = BEGIN myIconFlavors[0] _ Icons.NewIconFromFile["ViewRec.Icons", 0]; myIconFlavors[1] _ Icons.NewIconFromFile["ViewRec.Icons", 1]; myIconFlavors[2] _ Icons.NewIconFromFile["ViewRec.Icons", 2]; evClass _ NEW [ViewerClasses.ViewerClassRec _ [ flavor: $EltViewer, destroy: DestroyEltViewer, coordSys: top]]; VO.RegisterViewerClass[$EltViewer, evClass]; rvClass _ NEW [MJSContainers.MJSContainerClassRep _ [ NoteSizeChanged: NoticeRecordViewerSizeChange]]; MJSContainers.RegisterClass[$RecordViewer, rvClass]; nameStyles _ [quiescent: $BlackOnWhite, opened: $WhiteOnBlack, running: $WhiteOnBlack, invariant: $BlackOnGrey, beingShown: $BlackOnGrey]; END; Setup[]; END. €FILE: ViewRecCreate last edited by Spreitzer December 12, 1983 8:29 pm Last Edited by: Maxwell, November 16, 1982 3:29 pm ΚΪ˜Jšœ™Jšœ2™2Jšœ2™2J˜codešΟk œ6œ›˜άK˜—šΠbx œœ˜Kš œ6œTœ œ œ%˜ΤKšœ˜!K˜—Kšœœ˜K˜KšΟbœœœœ˜$K˜Kšœœœ˜)Kšœœœœ˜3K˜K˜Kšœ œ ˜K˜Kšœœœ˜0K˜Kšœœœ=˜WKšœœœ=˜WKš œ œœ œ œœ˜5Kšœ œ œ˜Kš œ œœœ œœ˜˜>K˜,K˜:K˜K˜Kšœ˜Kšœ˜Kšœ.˜.Kšœ4˜4Kšœ0˜0šœ ˜Kšœ&œ˜+Kšœœ˜(—Kšœœœ ˜=K˜Kšœœœ˜2šœ˜ šœ ˜ šœœ˜+Kšœ ˜ Kšœ ˜ Kšœ˜———Kšœ?œ˜XKšœ%˜%Kšœ+œœœ)˜ŽKšœ<˜<šœ˜Kš œœœœ œ˜2Kšœœœ˜,Kšœ"˜&—KšœO˜Ošœ*œ˜0šœS˜SKšœœœ˜9——Kšœ5˜5KšœZ˜Zšœ˜Kš˜Kšœœœ˜šœ'˜-Kš˜K˜.Kšœœ˜ Kšœ˜—šœ.œ˜4Kšœ5œ˜Kšœœ˜"Kš˜—šœ˜ šœ.˜0Kšœ&˜&K˜'K˜—Kšœ˜—Kšœ˜—K˜š  œœ˜*Kš˜Kšœœ˜Kšœœ˜ Kšœœ˜Kšœœ˜Kšœ œ˜*Kšœ4˜;šœœ˜Kš˜KšœœK˜SKšœ)˜)Kšœ˜—šœ œ˜Kš˜Kšœaœ˜jKšœœ$˜,K˜#Kšœ˜—šœ œ˜Kš˜KšœQ˜SKšœ˜Kšœ˜—šœ œ˜Kš˜Kšœaœ˜jKšœœ$˜,K˜#Kšœ˜—K˜Kšœ7˜7šœ)˜/KšœAœ˜F—Kšœœ˜"šœ&œ˜.K˜K˜$K˜—šœ"œœ ˜7Kšœœ˜ K˜K˜$K˜—Kšœ˜—K˜š œœœ œœœœœ!œœœ˜’Kš˜K˜2KšœœV˜mK˜fKšœ˜—K˜š  œœœœœ˜dKš˜K˜3Kšœœ˜šœ ˜K˜7K˜Kšœœ˜"—Kšœœ˜ šœœœ ˜ K˜K˜K˜šœ ˜šœ˜Kšœœ˜ Kšœœœ˜K˜'K˜'Kšœœœ˜+Kšœ˜—šœ˜K˜K˜Kšœ˜—Kšœœ˜—K˜>šœ˜šœ ˜K˜'K˜(K˜šœ˜&Kšœœ˜K˜DKšœœ˜—šœ˜(Kšœœ˜K˜FKšœœ˜—Kš œ œœ œœœ ˜LKšœ˜—šœ&˜+K˜=Kšœ œœœ˜:Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—K˜š  œœ œœœ˜8Kš˜KšœN˜TKšœ˜—K˜š  œœœœ ˜>Kšœœ˜K˜—š   œœœ œœ˜7Kš˜Kšœœœ˜ Kš œœ!œœœ˜;K˜$Kšœœœœ ˜'Kšœ˜K˜—š  œœœ œ˜=Kš˜Kšœœœ˜ Kš œœ!œœœ˜9K˜$Kšœœœœœ œœœ˜6Kšœœ˜Kšœ˜—K˜š   œœœœœœ˜=Kšœœœœ˜—K˜š œœœœ ˜9Kšœœ ˜K˜—š œœ˜ Kš˜Kšœ=˜=Kšœ=˜=Kšœ=˜=šœ œ"˜/K˜K˜K˜—Kšœ*˜,šœ œ(˜5Kšœ0˜0—K˜4˜'K˜.K˜3—Kšœ˜K˜—K˜K˜Kšœ˜K˜—…—mŒh