DIRECTORY AMBridge, AMEvents, AMMiniModel, AMTypes, Buttons, Containers, Icons, IO, Labels, Menus, MessageWindow, Process, Real, Rope, Rules, SafeStorage, TiogaOps, TIPUser, TypeProps, VFonts, ViewerOps, ViewerTools, ViewerClasses, ViewRec, ViewRecInsides, WorldVM; ViewRecOther: CEDAR MONITOR IMPORTS AMBridge, AMEvents, AMMiniModel, AMTypes, Buttons, IO, Labels, MessageWindow, Process, Rope, SafeStorage, TiogaOps, TypeProps, VO:ViewerOps, VT:ViewerTools, ViewRec, ViewRecInsides, WorldVM EXPORTS ViewRec, ViewRecInsides = BEGIN OPEN ViewRecInsides; NotAnAggregate: PUBLIC ERROR = CODE; NoSelectedProc: PUBLIC ERROR = CODE; BadID: PUBLIC ERROR [id: ViewRec.Id] = CODE; NotFound: PUBLIC ERROR [name: ViewRec.Path] = CODE; Event: TYPE = {Call, Return, Abort, Edit}; Pending: TYPE = RECORD [f: FinishProc _ NIL, data: REF ANY _ NIL]; FinishProc: TYPE = ViewRec.FinishProc; all: PUBLIC REF ANY _ NEW [REAL _ 47]; transitions: ARRAY GregState OF ARRAY Event OF GregState; nvDocFmt, nvcDocFmt: ROPE; procDoc, selDoc, butDoc: ROPE _ NIL; doitDocFmt: ARRAY BOOLEAN OF ROPE _ ALL[NIL]; abortDocFmt: ROPE _ NIL; toFinish: Pending; experimental: BOOLEAN _ FALSE; clearMessagePlace: PUBLIC ROPE _ "flush here"; mwTotal: ROPE _ ""; Recognize: PUBLIC PROC [t: Type, specials: RList, onlyRecognize: BOOLEAN, specs: BindingList, createOptions: CreateOptions] RETURNS [recognized: BOOLEAN, handler, handlerData: REF ANY] = BEGIN TryRecognizers: PROC [rl: RList] RETURNS [found: BOOLEAN] = BEGIN WHILE rl # NIL DO [found, handler, handlerData] _ rl.first[t: t, onlyRecognize: onlyRecognize, specs: specs, createOptions: createOptions]; IF found THEN {recognized _ TRUE; RETURN}; rl _ rl.rest; ENDLOOP; found _ FALSE; END; gt: Type; tc: AMTypes.Class; IF TryRecognizers[specials] THEN RETURN; IF TryRecognizers[befores[EquivalenceClass]] THEN RETURN; IF TryRecognizers[NARROW[TypeProps.Get[type: t, key: ecHandlerProp]]] THEN RETURN; IF TryRecognizers[befores[StripSubranges]] THEN RETURN; gt _ AMTypes.GroundStar[t]; IF TryRecognizers[NARROW[TypeProps.Get[type: gt, key: gtHandlerProp]]] THEN RETURN; IF TryRecognizers[befores[TypeClass]] THEN RETURN; tc _ AMTypes.TypeClass[gt]; IF TryRecognizers[classRecers[tc]] THEN RETURN; IF TryRecognizers[afterAlls] THEN RETURN; recognized _ FALSE; END; SelectBindings: PUBLIC PROC [bl: BindingList, name: ROPE, pos: INT] RETURNS [sublist, altSublist: BindingList, val: TypedVariable, found, visible, editable, dontAssign: BOOLEAN, notifies: NotifyList, recers: RList] = BEGIN sublist _ altSublist _ NIL; found _ dontAssign _ FALSE; visible _ editable _ TRUE; notifies _ NIL; recers _ NIL; FOR bl _ bl, bl.rest WHILE bl # NIL DO IF bl.first.name = all THEN NULL ELSE WITH bl.first.name SELECT FROM r: ROPE => IF NOT r.Equal[name] THEN LOOP; i: Int => IF i^ # pos THEN LOOP; rt: REF TEXT => IF NOT Rope.FromRefText[rt].Equal[name] THEN LOOP; ENDCASE => ERROR BadID[bl.first.name]; WITH bl.first SELECT FROM v: Binding[Value] => {val _ v.val; visible _ visible AND v.visible; editable _ editable AND v.editable; dontAssign _ dontAssign OR v.dontAssign; found _ TRUE}; n: Binding[Notify] => notifies _ CONS[[n.notify, n.clientData], notifies]; r: Binding[TryRecognizer] => recers _ CONS[r.recognizer, recers]; g: Binding[Group] => {sublist _ BindingListAppend[g.sublist, sublist]; altSublist _ BindingListAppend[g.altSublist, altSublist]}; ENDCASE => ERROR; ENDLOOP; saver _ recers; --make sure GC don't take it END; saver: RList _ NIL; --to combat UNSAFEty of long REF-containing arg/return record BindingListAppend: PUBLIC PROC [a, b: BindingList] RETURNS [c: BindingList] = BEGIN IF a = NIL THEN RETURN [b]; c _ a; WHILE a.rest # NIL DO a _ a.rest ENDLOOP; a.rest _ b; END; GetEltHandle: PUBLIC PROC [rv: RecordViewer, name: ViewRec.Path] RETURNS [eh: REF ANY] = BEGIN d: Data _ RVToData[rv]; e: Data _ NIL; cd: ComplexData _ NIL; IF name = NIL THEN ERROR NotFound[name]; DO ed: EltData _ NIL; IF cd # NIL THEN BEGIN IF cd.handler.elementGiver # NIL THEN ed _ NARROW[cd.handler.elementGiver[agg: cd.var, which: name.first, handlerData: cd.handlerData, clientData: cd.clientData]]; END ELSE BEGIN IF ed = NIL AND e # NIL THEN ed _ Find[e, name.first]; IF ed = NIL AND d # NIL THEN ed _ Find[d, name.first]; END; IF ed = NIL THEN ERROR NotFound[name]; name _ name.rest; IF name = NIL THEN RETURN [ed]; WITH ed SELECT FROM pd: ProcData => {d _ pd.argRV; e _ pd.retRV; cd _ NIL}; x: ComplexData => {d _ e _ NIL; cd _ x}; ENDCASE => ERROR NotFound[name]; ENDLOOP; END; Find: PROC [d: Data, name: REF ANY] RETURNS [ed: EltData] = BEGIN idx: INT _ 1; WITH name SELECT FROM r: ROPE => FOR ed _ d.first, ed.next WHILE ed # NIL DO IF r.Equal[ed.name] THEN RETURN [ed]; ENDLOOP; rt: REF TEXT => BEGIN r: ROPE _ Rope.FromRefText[rt]; FOR ed _ d.first, ed.next WHILE ed # NIL DO IF r.Equal[ed.name] THEN RETURN [ed]; ENDLOOP; END; ri: REF INT => IF ri^ > 0 THEN BEGIN FOR ed _ d.first, ed.next WHILE ed # NIL DO IF idx = ri^ THEN RETURN [ed]; idx _ idx + 1; ENDLOOP; END ELSE IF ri^ < 0 THEN BEGIN FOR ed _ d.last, ed.prev WHILE ed # NIL DO IF idx = -ri^ THEN RETURN [ed]; idx _ idx + 1; ENDLOOP; END ELSE ERROR BadID[name]; ENDCASE => ERROR BadID[name]; RETURN [NIL]; END; Open: PROC [ed: EltData] = BEGIN ed.opened _ TRUE; ShowState[ed]; END; DeOpen: PROC [ed: EltData] = BEGIN ed.opened _ FALSE; ShowState[ed]; END; Poke: PROC [ed: EltData, how: Event] = BEGIN WITH ed SELECT FROM pd: ProcData => BEGIN oldState: GregState _ pd.gregState; pd.gregState _ transitions[pd.gregState][how]; IF pd.gregState # oldState AND pd.stateLabel # NIL THEN Labels.Set[pd.stateLabel, StateToRope[pd.gregState]]; END; ENDCASE => BEGIN IF ed.parent.edParent # NIL THEN Poke[ed.parent.edParent, how]; END; END; StateToRope: PROC [s: GregState] RETURNS [ROPE] = {RETURN [SELECT s FROM Other => "", Dispatched => "working", DispatchedAndEdited => "working on old", Returned => "done", Aborted => "aborted", ENDCASE => ERROR]}; FinishPendingBusiness: PUBLIC PROC RETURNS [okToProceed: BOOLEAN] = BEGIN IF toFinish.f # NIL THEN okToProceed _ toFinish.f[toFinish.data] ELSE okToProceed _ TRUE; END; SetPendingBusiness: PUBLIC PROC [proc: FinishProc _ NIL, data: REF ANY _ NIL] = {toFinish _ [proc, data]}; ShowState: PUBLIC PROC [ed: EltData, paint: BOOLEAN _ TRUE] = BEGIN style: ATOM; b: Buttons.Button; WITH ed SELECT FROM pd: ProcData => BEGIN b _ pd.container; style _ IF pd.running THEN nameStyles.running ELSE IF pd.parent.highlightSelectedProc AND pd.parent.curProc = pd THEN nameStyles.beingShown ELSE nameStyles.quiescent; END; sd: SimpleData => BEGIN b _ sd.nameButton; style _ IF NOT sd.variable THEN nameStyles.invariant ELSE IF sd.opened THEN nameStyles.opened ELSE nameStyles.quiescent; END; ENDCASE => ERROR; Buttons.SetDisplayStyle[b, style, paint]; END; SendMsg: PROC [rv: Data, to: ROPE] = BEGIN old: ROPE; FOR rv _ rv, rv.rvParent WHILE rv # NIL DO IF rv.feedBack # NIL THEN EXIT; ENDLOOP; IF (IF rv = NIL THEN TRUE ELSE rv.feedBack = NIL OR rv.v.destroyed) THEN BEGIN IF to=clearMessagePlace THEN to _ "" ELSE BEGIN IF mwTotal.Length[] > 0 THEN to _ mwTotal.Cat["; ", to]; END; MessageWindow.Append[message: mwTotal _ to, clearFirst: TRUE]; RETURN; END; IF to = clearMessagePlace THEN {VT.SetContents[rv.feedBack, ""]; RETURN}; old _ VT.GetContents[rv.feedBack]; IF old.Length[] > 0 THEN to _ old.Cat["; ", to]; VT.SetContents[rv.feedBack, to]; END; SetMsg: PROC [ed: EltData, to: ROPE] = BEGIN SendMsg[IF ed = NIL THEN NIL ELSE ed.parent, to]; END; DisplayMessage: PUBLIC PROC [rv: RecordViewer, msg: ROPE] = BEGIN d: Data _ RVToData[rv]; SendMsg[d, msg]; END; Scream: PROC [msg: ROPE] = BEGIN MessageWindow.Append[msg, TRUE]; MessageWindow.Blink[]; END; Runnable: ENTRY PROC [ed: EltData] RETURNS [BOOLEAN] = BEGIN pd: ProcData _ NARROW[ed]; IF pd.parent.exclusiveProcs AND pd.parent.runCount > 0 THEN RETURN [FALSE]; IF pd.runningProcess # NIL THEN RETURN [FALSE]; pd.parent.runningProcs _ CONS[pd, pd.parent.runningProcs]; pd.parent.runCount _ pd.parent.runCount + 1; RETURN [pd.running _ TRUE]; END; UnRun: ENTRY PROC [ed: EltData] = BEGIN ENABLE UNWIND => NULL; pd: ProcData _ NARROW[ed]; pd.runningProcess _ NIL; IF pd.parent.runningProcs.first = pd THEN pd.parent.runningProcs _ pd.parent.runningProcs.rest ELSE BEGIN procs: LIST OF ProcData; FOR procs _ pd.parent.runningProcs, procs.rest WHILE procs.rest.first # pd DO NULL ENDLOOP; procs.rest _ procs.rest.rest; END; pd.running _ FALSE; pd.parent.runCount _ pd.parent.runCount - 1; pd.userAbort _ 0; END; GetARunner: PROC [asAny: REF ANY] RETURNS [runner: ProcData] = BEGIN d: Data; IF ISTYPE[asAny, ProcData] THEN RETURN [NARROW[asAny]]; d _ RVToData[ViewRec.NarrowToRV[asAny]]; IF d.runningProcs = NIL THEN RETURN [NIL]; runner _ d.runningProcs.first; END; ProcessAbort: PUBLIC ENTRY PROC [who: REF ANY] RETURNS [found: BOOLEAN] = BEGIN pd: ProcData _ GetARunner[who]; IF pd = NIL THEN RETURN [FALSE]; IF NOT pd.running THEN RETURN [FALSE]; TRUSTED {Process.Abort[LOOPHOLE[pd.runningProcess, UNSPECIFIED]]}; RETURN [TRUE]; END; TestAndMaybeResetUserAbort: PUBLIC ENTRY PROC [who: REF ANY, threshold: CARDINAL] RETURNS [abort: CARDINAL --will be 0 or >= threshold--] = BEGIN pd: ProcData _ GetARunner[who]; IF pd = NIL THEN RETURN [0]; IF pd.userAbort >= threshold THEN BEGIN abort _ pd.userAbort; pd.userAbort _ 0; END ELSE abort _ 0; END; TestUserAbort: PUBLIC ENTRY PROC [who: REF ANY] RETURNS [abort: CARDINAL] = BEGIN pd: ProcData _ GetARunner[who]; IF pd = NIL THEN RETURN [0]; abort _ pd.userAbort; END; SetUserAbort: PUBLIC ENTRY PROC [who: REF ANY, newLevel: CARDINAL _ 100] = BEGIN pd: ProcData _ GetARunner[who]; IF pd = NIL THEN RETURN; pd.userAbort _ newLevel; END; IncrementUserAbortBy: PROC [pd: ProcData, deltaLevel: INTEGER] = BEGIN old: CARDINAL _ pd.userAbort; pd.userAbort _ INT[MAX[MIN[INT[deltaLevel] + pd.userAbort, LAST[CARDINAL]], 0]]; SetMsg[pd, IF old = pd.userAbort THEN "UserAbort pegged" ELSE IF deltaLevel > 0 THEN IO.PutFR["UserAbort incremented to %g", IO.card[pd.userAbort]] ELSE IF pd.userAbort > 0 THEN IO.PutFR["UserAbort decremented to %g", IO.card[pd.userAbort]] ELSE "UserAbort cancelled"]; END; IncrementUserAbort: PUBLIC PROC [who: REF ANY, deltaLevel: INTEGER] = BEGIN pd: ProcData _ GetARunner[who]; IF pd = NIL THEN RETURN; pd.userAbort _ INT[MAX[MIN[INT[deltaLevel] + pd.userAbort, LAST[CARDINAL]], 0]]; END; CallClient: PROC [pd: ProcData] = BEGIN event: Event _ Return; ok: BOOLEAN _ TRUE; ans: TypedVariable; IF pd = NIL THEN ERROR; IF pd.parent = NIL THEN ERROR; TRUSTED { Process.SetPriority[Process.priorityNormal]; ans _ AMEvents.Apply[control: pd.proc, args: pd.domainInst ! ABORTED => BEGIN SetMsg[pd, "Aborted"]; event _ Abort; ok _ FALSE; CONTINUE; END; UNWIND => BEGIN SetMsg[pd, "Unwound"]; UnRun[pd]; ShowState[pd]; END]; }; IF ok AND pd.hasRet THEN AMTypes.Assign[pd.retInst, ans]; UnRun[pd]; Poke[pd, event]; ShowState[pd]; END; ProcButtonProc: PUBLIC Menus.ClickProc = BEGIN pd: ProcData _ NARROW[clientData]; old: ProcData _ pd.parent.curProc; new: ProcData _ pd; SetMsg[pd, clearMessagePlace]; IF NOT FinishPendingBusiness[] THEN RETURN; IF control THEN BEGIN SetMsg[pd, IF pd.hasDom OR pd.hasRet THEN procDoc ELSE IF pd.parent.holdOff THEN selDoc ELSE butDoc]; RETURN; END; IF old # new THEN BEGIN IF (IF old # NIL THEN old.argret # NIL ELSE FALSE) THEN BEGIN VO.MoveViewer[viewer: old.argret, x: nowhere, y: 0, w: old.argret.ww, h: old.argret.wh, paint: new.argret = NIL]; old.argsShown _ FALSE; END; IF new.argret # NIL THEN BEGIN VO.MoveViewer[viewer: new.argret, x: 0, y: 0, w: new.argret.ww, h: new.argret.wh]; new.argsShown _ TRUE; END; pd.parent.curProc _ new; IF old # NIL THEN ShowState[old]; ShowState[new]; END; IF shift THEN BEGIN SELECT mouseButton FROM red => {IncrementUserAbortBy[pd, 100]; IF pd.userAbort >= 300 THEN [] _ ProcessAbort[pd.parent.asRV]}; blue => IncrementUserAbortBy[pd, -100]; yellow => SetMsg[pd, IO.PutFR[abortDocFmt, IO.card[pd.userAbort]]]; ENDCASE => ERROR; END ELSE IF pd.parent.holdOff THEN NULL ELSE IF NOT (pd.hasDom OR pd.hasRet) THEN TryToCall[pd]; END; TryToCall: PROC [pd: ProcData] = TRUSTED BEGIN IF AMBridge.TVToProc[pd.proc] = NIL THEN SetMsg[pd, "Procedure Unbound!"] ELSE IF Runnable[pd] THEN BEGIN Poke[pd, Call]; ShowState[pd]; Process.Detach[pd.runningProcess _ FORK CallClient[pd]]; END ELSE SetMsg[pd, "Busy"]; END; InnerProcButtonProc: PUBLIC Menus.ClickProc = BEGIN pd: ProcData _ NARROW[clientData]; SetMsg[pd, clearMessagePlace]; IF pd = NIL THEN {SetMsg[pd, "InnerProcButtonProc invoked on NIL ProcData!"]; RETURN}; IF NOT FinishPendingBusiness[] THEN RETURN; IF control THEN BEGIN SetMsg[pd, IO.PutFR[doitDocFmt[pd.hasDom], IO.rope[pd.name]]]; END ELSE TryToCall[pd]; END; ProcUpdate: PUBLIC UpdateProc = BEGIN pd: ProcData _ NARROW[ed]; IF pd.argsShown THEN BEGIN IF pd.hasDom THEN SampleData[pd.argRV]; IF pd.hasRet THEN SampleData[pd.retRV]; END; END; CallSelectedProc: PUBLIC PROC [in: RecordViewer] RETURNS [refused: BOOLEAN] = TRUSTED BEGIN d: Data; IF in = NIL THEN RETURN [TRUE]; d _ RVToData[in]; IF (refused _ NOT FinishPendingBusiness[]) THEN RETURN; IF d.curProc = NIL THEN ERROR NoSelectedProc[]; IF AMBridge.TVToProc[d.curProc.proc] = NIL THEN RETURN [TRUE]; IF (refused _ NOT Runnable[d.curProc]) THEN RETURN; Poke[d.curProc, Call]; ShowState[d.curProc]; Process.Detach[d.curProc.runningProcess _ FORK CallClient[d.curProc]]; END; NotherElt: PROC [ed: EltData, forward, mustBeMutable: BOOLEAN] RETURNS [new: SimpleData] = BEGIN Next: PROC [ed: EltData] RETURNS [fd: EltData] = BEGIN WHILE TRUE DO v: Viewer; IF ed = NIL THEN RETURN [NIL]; fd _ IF forward THEN ed.next ELSE ed.prev; IF fd # NIL THEN RETURN; v _ ed.parent.v; IF (ed _ ed.parent.edParent) = NIL THEN BEGIN FOR v _ v.parent, v.parent WHILE v # NIL DO ed _ NARROW[VO.FetchProp[viewer: v, prop: $EltData]]; IF ed # NIL THEN EXIT; ENDLOOP; END; ENDLOOP; END; starting: BOOLEAN _ TRUE; WHILE TRUE DO IF ed = NIL THEN RETURN [NIL]; WITH ed SELECT FROM sd: SimpleData => IF starting THEN {starting _ FALSE; ed _ Next[ed]} ELSE IF ed.variable OR NOT mustBeMutable THEN RETURN [sd] ELSE ed _ Next[ed]; cd: ComplexData => ed _ IF cd.handler.elementGiver = NIL THEN Next[ed] ELSE NARROW[cd.handler.elementGiver[agg: ed, which: NEW [INT _ IF forward THEN 1 ELSE -1], handlerData: cd.handlerData, clientData: cd.clientData]]; pd: ProcData => ed _ Next[ed]; ENDCASE => ERROR; ENDLOOP; END; TiogaDoit: TiogaOps.CommandProc = BEGIN eda: REF ANY _ VO.FetchProp[viewer: viewer, prop: $EltData]; ed: EltData; IF (IF eda = NIL THEN TRUE ELSE NOT ISTYPE[eda, EltData]) THEN RETURN [recordAtom: FALSE, quit: FALSE]; recordAtom _ FALSE; quit _ TRUE; ed _ NARROW[eda]; SetMsg[ed, clearMessagePlace]; IF NOT FinishPendingBusiness[] THEN RETURN; IF ed.parent.toButt.button # NIL THEN TRUSTED {Process.Detach[FORK CallToDo[ed]]}; END; CallToDo: PROC [ed: EltData] = BEGIN TRUSTED {Process.SetPriority[Process.priorityNormal]}; PushButton[ed.parent.toButt !ABORTED => BEGIN SetMsg[ed, "Aborted"]; CONTINUE END]; END; PushButton: PROC [bc: ButtonClick] = BEGIN coords: TIPUser.TIPScreenCoords _ NEW [TIPUser.TIPScreenCoordsRec _ [mouseX: 1, mouseY: 1, color: bc.button.column = color]]; l: LIST OF REF ANY _ LIST[$Hit]; l _ CONS[SELECT bc.mouseButton FROM red => $Red, yellow => $Yellow, blue => $Blue, ENDCASE => ERROR, l]; IF bc.shift THEN l _ CONS[$Shift, l]; IF bc.control THEN l _ CONS[$Control, l]; l _ CONS[coords, CONS[$Mark, l]]; bc.button.class.notify[self: bc.button, input: l]; END; TiogaClose: TiogaOps.CommandProc = BEGIN eda: REF ANY _ VO.FetchProp[viewer: viewer, prop: $EltData]; ed: EltData; IF (IF eda = NIL THEN TRUE ELSE NOT ISTYPE[eda, EltData]) THEN RETURN [recordAtom: FALSE, quit: FALSE]; recordAtom _ FALSE; quit _ TRUE; ed _ NARROW[eda]; SetMsg[ed, clearMessagePlace]; [] _ FinishPendingBusiness[]; END; TiogaNext: TiogaOps.CommandProc = BEGIN eda: REF ANY _ VO.FetchProp[viewer: viewer, prop: $EltData]; ed: EltData; ned: SimpleData; IF (IF eda = NIL THEN TRUE ELSE NOT ISTYPE[eda, EltData]) THEN RETURN [recordAtom: FALSE, quit: FALSE]; recordAtom _ FALSE; quit _ TRUE; ed _ NARROW[eda]; SetMsg[ed, clearMessagePlace]; IF NOT FinishPendingBusiness[] THEN RETURN; ned _ NotherElt[ed, TRUE, TRUE]; IF ned = NIL THEN SetMsg[ed, "Ran off end!"] ELSE BEGIN Open[ned]; VT.EnableUserEdits[ned.valueText]; VT.SetSelection[ned.valueText]; toFinish _ [FinishNV, ned]; END; END; TiogaPrev: TiogaOps.CommandProc = BEGIN eda: REF ANY _ VO.FetchProp[viewer: viewer, prop: $EltData]; ed: EltData; ned: SimpleData; IF (IF eda = NIL THEN TRUE ELSE NOT ISTYPE[eda, EltData]) THEN RETURN [recordAtom: FALSE, quit: FALSE]; recordAtom _ FALSE; quit _ TRUE; ed _ NARROW[eda]; SetMsg[ed, clearMessagePlace]; IF NOT FinishPendingBusiness[] THEN RETURN; ned _ NotherElt[ed, FALSE, TRUE]; IF ned = NIL THEN SetMsg[ed, "Ran off end!"] ELSE BEGIN Open[ned]; VT.EnableUserEdits[ned.valueText]; VT.SetSelection[ned.valueText]; toFinish _ [FinishNV, ned]; END; END; TiogaGiveUp: TiogaOps.CommandProc = BEGIN eda: REF ANY _ VO.FetchProp[viewer: viewer, prop: $EltData]; sd: SimpleData; IF (IF eda = NIL THEN TRUE ELSE NOT ISTYPE[eda, SimpleData]) THEN RETURN [recordAtom: FALSE, quit: FALSE]; recordAtom _ FALSE; quit _ TRUE; sd _ NARROW[eda]; SetMsg[sd, clearMessagePlace]; IF NOT sd.opened THEN ERROR; SetMsg[sd, "OK, I give up!"]; VT.InhibitUserEdits[sd.valueText]; DeOpen[sd]; VT.SetContents[sd.valueText, sd.ToRope[sd]]; toFinish _ [NIL, NIL]; END; NVButtonProc: PUBLIC Menus.ClickProc = BEGIN sd: SimpleData _ NARROW[clientData]; SetMsg[sd, clearMessagePlace]; IF NOT FinishPendingBusiness[] THEN RETURN; IF control THEN SetMsg[sd, IF shift THEN sd.typeDoc ELSE IF NOT sd.variable THEN IO.PutFR[nvcDocFmt, IO.rope[sd.typeDoc]] ELSE WITH sd SELECT FROM sd: SimpleData => IO.PutFR[nvDocFmt, IO.rope[sd.handler.blueDoc], IO.rope[sd.typeDoc]], ENDCASE => ERROR] ELSE IF sd.variable THEN SELECT mouseButton FROM red => BEGIN IF shift THEN SetMsg[sd, "Don't do that"] ELSE BEGIN Open[sd]; VT.EnableUserEdits[sd.valueText]; VT.SetSelection[sd.valueText]; toFinish _ [FinishNV, sd]; END; END; yellow => BEGIN IF shift THEN SetMsg[sd, "Don't do that"] ELSE [] _ Try[sd, VT.GetSelectionContents[], FALSE]; END; blue => WITH sd SELECT FROM sd: SimpleData => BEGIN new: TypedVariable; msg: ROPE; IF sd.handler.Butt = NIL THEN SetMsg[sd, "No meaning for NotCtl Right clicking that screen button (Ctl click it for help)."] ELSE BEGIN [new, msg] _ sd.handler.Butt[sd.var, sd.targType, sd.handler, sd.handlerData, shift]; IF msg # NIL THEN SetMsg[sd, msg]; IF msg = NIL THEN BEGIN AMTypes.Assign[sd.var, new]; ShowRight[sd]; Poke[sd, Edit]; FOR nl: NotifyList _ sd.notifyRequests, nl.rest WHILE nl # NIL DO nl.first.proc[nl.first.clientData]; ENDLOOP; END; END; END; ENDCASE => SetMsg[sd, "No meaning for NotCtl Right clicking that screen button (Ctl click it for help)."]; ENDCASE => ERROR ELSE SetMsg[sd, "You can't change that."]; END; ShowRight: ENTRY PROCEDURE [sd: SimpleData] = BEGIN AMTypes.Assign[sd.old, sd.var]; IF sd.valueText # NIL THEN VT.SetContents[sd.valueText, sd.ToRope[sd]]; END; FinishNV: FinishProc = BEGIN sd: SimpleData _ NARROW[data]; [] _ Try[sd, VT.GetContents[sd.valueText], TRUE]; okToProceed _ TRUE; VT.InhibitUserEdits[sd.valueText]; DeOpen[sd]; toFinish _ [NIL, NIL]; END; Try: PROC [sd: SimpleData, asRope: ROPE, mightNeedRefresh: BOOLEAN] RETURNS [success: BOOLEAN] = BEGIN Quick: ENTRY PROC RETURNS [success: BOOLEAN] = BEGIN IF (success _ sd.AssignRope[sd, asRope]) THEN BEGIN AMTypes.Assign[sd.old, sd.var]; IF sd.valueText # NIL THEN VT.SetContents[sd.valueText, sd.ToRope[sd]]; END ELSE BEGIN IF mightNeedRefresh AND sd.valueText # NIL THEN VT.SetContents[sd.valueText, sd.ToRope[sd]]; END; END; IF (success _ Quick[]) THEN BEGIN Poke[sd, Edit]; FOR nl: NotifyList _ sd.notifyRequests, nl.rest WHILE nl # NIL DO nl.first.proc[nl.first.clientData]; ENDLOOP; END ELSE BEGIN SetMsg[sd, Rope.Cat["Parse failed; please use a valid character string for a ", sd.typeDoc]]; END; END; SetRope: PUBLIC PROC [sd: SimpleData, to: ROPE, paint: BOOLEAN _ TRUE] = {IF NOT sd.destroyed THEN VT.SetContents[viewer: sd.valueText, contents: to, paint: paint]}; UpdateNV: PUBLIC ENTRY UpdateProc = BEGIN sd: SimpleData _ NARROW[ed]; IF (IF AMTypes.TVEqual[sd.old, sd.var] THEN always ELSE TRUE) THEN BEGIN AMTypes.Assign[sd.old, sd.var]; SetRope[sd, sd.ToRope[sd]]; END; END; UpdateComplex: PUBLIC UpdateProc = BEGIN News: ENTRY PROC RETURNS [news: BOOLEAN] = {IF (news _ NOT AMTypes.TVEqual[ed.old, ed.var]) THEN AMTypes.Assign[ed.old, ed.var]}; IF (IF NOT ed.sampleable THEN FALSE ELSE IF News[] THEN TRUE ELSE always) THEN BEGIN cd: ComplexData _ NARROW[ed]; cd.handler.updater[tv: cd.var, v: cd.container, handlerData: cd.handlerData, clientData: cd.clientData]; END; END; SimpleToRope: PUBLIC ToRopeProc = BEGIN sd: SimpleData _ NARROW[ed]; asRope _ sd.handler.UnParse[sd.var, sd.targType, sd.handlerData]; END; SimpleAssignRope: PUBLIC AssignRopeProc = BEGIN sd: SimpleData _ NARROW[ed]; IF NOT (success _ sd.handler.Parse[asRope, sd.wideAsTV, sd.targType, sd.handlerData]) THEN RETURN; AMTypes.Assign[sd.var, AMTypes.Coerce[sd.wideAsTV, sd.targType ! AMTypes.Error => {success _ FALSE; CONTINUE}]]; END; BindAllOfATypeFromTVs: PUBLIC PROC [aggType, eltType: Type, name: ROPE _ NIL, b: Binding] RETURNS [bl: BindingList] = BEGIN NameTest: PROC [i: CARDINAL] RETURNS [BOOLEAN] = {RETURN [IF name = NIL OR recClass = sequence OR recClass = array THEN TRUE ELSE name.Equal[AMTypes.IndexToName[aggType, i]]]}; recClass: AMTypes.Class _ AMTypes.TypeClass[aggType]; len: CARDINAL; SELECT recClass FROM record, structure => len _ AMTypes.NComponents[aggType]; sequence, array => len _ 1; ENDCASE => ERROR NotAnAggregate[]; bl _ NIL; FOR i: CARDINAL IN [1 .. len] DO id: Id; eType, cType: Type; SELECT recClass FROM record, structure => BEGIN id _ NEW [INT _ i]; eType _ AMTypes.IndexToType[aggType, i]; END; sequence, array => BEGIN id _ all; eType _ AMTypes.Range[aggType]; END; ENDCASE => ERROR; cType _ AMTypes.UnderType[eType]; IF SafeStorage.EquivalentTypes[cType, eltType] AND NameTest[i] THEN {b.name _ id; bl _ CONS[b, bl]} ELSE SELECT AMTypes.TypeClass[cType] FROM procedure => BEGIN domType: Type _ AMTypes.Domain[cType]; rangeType: Type _ AMTypes.Range[cType]; argBL, retBL: BindingList; SELECT AMTypes.TypeClass[domType] FROM nil => argBL _ NIL; record, structure => argBL _ BindAllOfATypeFromTVs[domType, eltType, name, b]; ENDCASE => ERROR; SELECT AMTypes.TypeClass[rangeType] FROM nil => retBL _ NIL; record, structure => retBL _ BindAllOfATypeFromTVs[rangeType, eltType, 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 _ BindAllOfATypeFromTVs[cType, eltType, name, b]; IF subList # NIL THEN bl _ CONS[[id, Group[subList]], bl]; END; ENDCASE; ENDLOOP; END; BindAllOfATypeFromRefs: PUBLIC PROC [rec, handle: REF ANY, name: ROPE, visible, editable, dontAssign: BOOLEAN _ FALSE] RETURNS [BindingList] = TRUSTED BEGIN handleAsTV: TypedVariable _ AMBridge.TVForReferent[handle]; RETURN [BindAllOfATypeFromTVs[ aggType: AMTypes.UnderType[ AMTypes.TVType[ AMBridge.TVForReferent[ rec]]], eltType: AMTypes.TVType[handleAsTV], name: name, b: [name: NIL, it: Value[val: handleAsTV, visible: visible, editable: editable, dontAssign: dontAssign]]]]; END; ViewRef: PUBLIC PROC [agg: REF ANY, specs: 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] = TRUSTED BEGIN RETURN [ViewRec.ViewTV[agg: AMBridge.TVForReferent[agg], specs: specs, label: label, otherStuff: otherStuff, toButt: toButt, parent: parent, asElement: asElement, sample: sample, createOptions: createOptions, viewerInit: viewerInit, paint: paint]]; END; ViewInterface: PUBLIC PROC [name: ROPE, specs: BindingList _ NIL, label: 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 [RecordViewer] = TRUSTED BEGIN RETURN [ViewRec.ViewTV[agg: AMMiniModel.GetInterfaceRecord[name, WorldVM.LocalWorld[]], specs: specs, label: label, otherStuff: otherStuff, toButt: toButt, parent: parent, asElement: asElement, sample: sample, createOptions: createOptions, viewerInit: viewerInit, paint: paint]]; END; ViewSelf: PUBLIC PROC = TRUSTED BEGIN ift: Type _ AMTypes.TVType[AMMiniModel.GetInterfaceRecord["ViewRec", WorldVM.LocalWorld[]]]; [] _ ViewInterface[name: "ViewRec", specs: BindAllOfATypeFromTVs[ift, CODE[BOOLEAN], "iconic", [name: NIL, it: Value[val: AMBridge.TVForReferent[NEW [BOOLEAN _ FALSE]], visible: TRUE, editable: TRUE]]], createOptions: [doAllRecords: TRUE], viewerInit: [name: "ViewRec", iconic: FALSE, column: right]]; END; Help: PUBLIC PROC = BEGIN [] _ VT.MakeNewTextViewer[info: [name: "ViewRec.doc", file: "ViewRec.doc", iconic: FALSE]]; END; DestroyEltViewer: PUBLIC ENTRY ViewerClasses.DestroyProc = BEGIN ed: EltData _ NARROW[self.data]; ed.destroyed _ TRUE; END; Setup: PROC = BEGIN nvDocFmt _ "Red => Open this component for editing, Yellow => Take current Tioga Selection, and try to use it, %gControl Shift Red, Yellow, or Blue => Gives the following description of what this should be: \"%g\""; nvcDocFmt _ "Control Shift Red, Yellow, or Blue => Gives the following description of what this should be: \"%g\""; procDoc _ "Hitting me in any way will cause this PROCEDURE's Arguments and Results to be displayed; also: Shift Left will increment abort urgency by 100 (and do a Process.Abort if it goes over 299). Shift Middle will display the abort urgency. Shift Right will decrement abort urgency by 100."; selDoc _ "Hitting me in any way selects this PROCEDURE; also Shift Left will increment abort urgency by 100 (and do a Process.Abort if it goes over 299). Shift Middle will display the abort urgency. Shift Right will decrement abort urgency by 100."; butDoc _ "Not-Shifted Left, Middle, or Right will invoke this PROCEDURE. Shift Left will increment abort urgency by 100 (and do a Process.Abort if it goes over 299). Shift Middle will display abort urgency. Shift Right will decrement abort urgency by 100."; doitDocFmt[FALSE] _ "Hitting me will invoke %g (it takes no arguments)"; doitDocFmt[TRUE] _ "Hitting me will invoke %g with the given arguments"; abortDocFmt _ "Abort Urgency is %g"; transitions _ [ Other: [Edit: Other, Call: Dispatched, Return: Other, Abort: Other], Dispatched: [Edit: DispatchedAndEdited, Call: Dispatched, Return: Returned, Abort: Aborted], DispatchedAndEdited: [Edit: DispatchedAndEdited, Call: Dispatched, Return: Other, Abort: Other], Returned: [Edit: Other, Call: Dispatched, Return: Other, Abort: Other], Aborted: [Edit: Other, Call: Dispatched, Return: Other, Abort: Other]]; TiogaOps.RegisterCommand[name: $NextPlaceholder, proc: TiogaNext]; TiogaOps.RegisterCommand[name: $PreviousPlaceholder, proc: TiogaPrev]; TiogaOps.RegisterCommand[name: $CtrlPrevPlaceholder, proc: TiogaGiveUp]; TiogaOps.RegisterCommand[name: $CtrlNextPlaceholder, proc: TiogaClose]; TiogaOps.RegisterCommand[name: $InsertLineBreak, proc: TiogaClose]; TiogaOps.RegisterCommand[name: $Break, proc: TiogaDoit]; END; Setup[]; END. RFILE: ViewRecOther.Mesa last edited by Spreitzer December 12, 1983 8:29 pm Ê';˜Jšœ™Jšœ2™2J˜codešÏk ˜ KšœFœ·˜ÿK˜—šÐbx œœ˜Kšœ4œJœ œ.˜ÅKšœ˜!—K˜Kšœœ˜K˜Kšœœœœ˜$Kšœœœœ˜$Kšœœœœ˜,Kšœ œœœ˜3K˜Kšœœ˜*K˜Kš œ œœœœœœ˜BKšœ œ˜&K˜Kš œœœœœœ˜&K˜Kš œ œ œœœ ˜9Kšœœ˜Kšœœœ˜$Kš œ œœœœœœ˜-Kšœ œœ˜K˜Kšœœœ˜Kšœœœ˜.Kšœ œ˜K˜šÏn œœœ+œ4œœœœ˜ºKš˜šŸœœ œ œ˜;Kš˜šœœ˜Kšœy˜yKšœœœœ˜*K˜ Kšœ˜—Kšœœ˜Kšœ˜—K˜K˜ K˜K˜Kšœœœ˜(K˜Kšœ+œœ˜9K˜Kšœœ.œœ˜RK˜Kšœ)œœ˜7K˜K˜Kšœœ/œœ˜SK˜Kšœ$œœ˜2K˜K˜Kšœ!œœ˜/K˜Kšœœœ˜)K˜Kšœ œ˜Kšœ˜—K˜šŸœœœœœœ^œ(˜ØKš˜Kšœœ˜Kšœœ˜Kšœœ˜Kšœ œ˜Kšœ œ˜ šœœœ˜&Kšœœ˜ šœœœ˜#Kš œœœœœœ˜*Kšœ œ œœ˜ Kš œœœœœ"œœ˜BKšœœ˜&—šœ œ˜šœ"˜"Kšœœ ˜ Kšœœ ˜#Kšœœ˜(Kšœœ˜—Kšœ!œ%˜JKšœ&œ˜A˜FK˜:—Kšœœ˜—Kšœ˜—KšœÏc˜,Kšœ˜—K˜Kšœœ =˜QK˜šŸœœœœ˜MKš˜Kšœœœœ˜K˜Kšœ œœ œ˜)K˜ Kšœ˜—K˜š Ÿ œœœ(œœœ˜XKš˜K˜Kšœ œ˜Kšœœ˜Kšœœœœ˜(š˜Kšœœ˜šœœ˜Kš˜Kšœœœœr˜£Kš˜—šœ˜ Kš œœœœœ˜6Kš œœœœœ˜6Kšœ˜—Kšœœœœ˜&K˜Kšœœœœ˜šœœ˜Kšœ2œ˜7Kšœœ ˜(Kšœœ˜ —Kšœ˜—Kšœ˜—K˜š Ÿœœœœœ˜;Kš˜Kšœœ˜ šœœ˜š œœœœœ˜6Kšœœœ˜%Kšœ˜—šœœœ˜Kšœœ˜šœœœ˜+Kšœœœ˜%Kšœ˜—Kšœ˜—šœœœ˜šœ ˜Kš˜šœœœ˜+Kšœ œœ˜Kšœ˜Kšœ˜—Kš˜—šœœ ˜Kš˜šœœœ˜*Kšœ œœ˜Kšœ˜Kšœ˜—Kš˜—Kšœœ ˜—Kšœœ ˜—Kšœœ˜ Kšœ˜—K˜šŸœœ˜Kš˜Kšœ œ˜K˜Kšœ˜K˜—šŸœœ˜Kš˜Kšœ œ˜K˜Kšœ˜K˜—šŸœœ˜&Kš˜šœœ˜šœ˜K˜#K˜.šœœœ˜7K˜5—Kšœ˜—šœ˜šœœ˜ K˜—Kšœ˜——Kšœ˜K˜—šŸ œœœœ˜1šœœœ˜K˜ K˜K˜(K˜K˜Kšœœ˜K˜——š Ÿœœœœœ˜CKš˜šœœ˜K˜'—Kšœœ˜Kšœ˜K˜—šŸœœœœœœœ˜OK˜—K˜š Ÿ œœœœœ˜=Kš˜Kšœœ˜ K˜šœœ˜˜Kš˜K˜Kšœœ œ˜-šœœ ˜'Kšœœ˜5—Kšœ˜Kšœ˜—˜Kš˜K˜šœœœ œ˜4Kšœœ œ˜(Kšœ˜—Kšœ˜—Kšœœ˜—K˜)Kšœ˜K˜—šŸœœœ˜$Kš˜Kšœœ˜ šœœœ˜*Kšœœœœ˜Kšœ˜—šœœœœœœœœ˜HKš˜Kšœœ˜$šœ˜ Kšœœ˜8Kšœ˜—Kšœ8œ˜>Kšœ˜Kšœ˜—Kšœœœœ˜IKšœœ˜"K˜0Kšœ˜ Kšœ˜K˜—šŸœœœ˜&Kš˜Kš œœœœœœ˜1Kšœ˜K˜—šŸœœœœ˜;Kš˜K˜K˜Kšœ˜K˜—šŸœœœ˜Kš˜Kšœœ˜ K˜Kšœ˜K˜—š Ÿœœœœœ˜6Kš˜Kšœœ˜Kš œœœœœ˜KKš œœœœœ˜/Kšœœ˜:Kšœ,˜,Kšœœ˜Kšœ˜K˜—šŸœœœ˜!Kšœœœœ˜Kšœœ˜Kšœœ˜Kšœ#œ5˜^šœ˜ Kšœœœ ˜Kš œ,œœœœ˜[K˜Kšœ˜—Kšœ œ˜K˜,Kšœ˜Kšœ˜—K˜š Ÿ œœ œœœ˜>Kš˜K˜Kš œœœœœ ˜7Kšœ(˜(Kš œœœœœ˜*K˜Kšœ˜—K˜šŸ œœœœœœœ œ˜IKš˜K˜Kš œœœœœ˜ Kš œœ œœœ˜&Kšœœ œ˜BKšœœ˜Kšœ˜—K˜šŸœœœœœœ œœ œ œ˜‹Kš˜K˜Kšœœœœ˜šœ˜!Kš˜Kšœ˜Kšœ˜Kš˜—Kšœ ˜Kšœ˜—K˜šŸ œœœœœœœ œ˜KKš˜K˜Kšœœœœ˜Kšœ˜Kšœ˜—K˜šŸ œœœœœœ œ ˜JKš˜K˜Kšœœœœ˜Kšœ˜Kšœ˜—K˜šŸœœœ˜@Kš˜Kšœœ˜Kš œœœœœœœ˜P˜ Kšœœ˜-Kš œœœœ&œ˜ZKš œœœœ&œ˜\Kšœ˜—Kšœ˜—K˜š Ÿœœœœœœ˜EKš˜K˜Kšœœœœ˜Kš œœœœœœœ˜PKšœ˜—K˜šŸ œœ˜!Kš˜K˜Kšœœœ˜K˜Kšœœœœ˜Kšœ œœœ˜šœ˜ Kšœ,˜,˜<šœ˜ Kš˜K˜Kšœœ˜Kšœ˜ Kšœ˜—šœ˜ Kš˜K˜K˜ Kšœ˜Kšœ˜——K˜—Kšœœ œ!˜9K˜ K˜K˜Kšœ˜K˜—šŸœœ˜(Kš˜Kšœœ ˜"K˜"K˜Kšœ˜Kšœœœœ˜+šœ ˜Kš˜Kšœ œ œ œœœœœ ˜eKšœ˜Kšœ˜—šœ ˜Kš˜šœœœœœœœ˜7Kš˜šœ1˜3Kšœ8œ˜=—Kšœœ˜Kšœ˜—šœœ˜Kš˜šœ+˜-K˜$—Kšœœ˜Kšœ˜—K˜Kšœœœ˜!K˜Kšœ˜—šœ˜ Kš˜šœ ˜Kšœ'œœ$˜fKšœ'˜'Kšœœœ˜CKšœœ˜—Kš˜—Kšœœœ˜#Kš œœœ œ œ˜8Kšœ˜K˜—šŸ œœ˜(Kš˜Kšœœœ!˜Išœœœ˜K˜K˜Kšœ#œ˜8Kš˜—Kšœ˜Kšœ˜K˜—šŸœœ˜-Kš˜Kšœœ ˜"Kšœ˜Kšœœœ>œ˜VKšœœœœ˜+šœ ˜Kš˜Kšœ œœ˜>Kš˜—Kšœ˜Kšœ˜—K˜šŸ œœ ˜Kš˜Kšœœ˜šœ˜Kš˜Kšœ œ˜'Kšœ œ˜'Kšœ˜—Kšœ˜K˜—š Ÿœœœœ œ˜UKš˜K˜Kš œœœœœ˜K˜Kšœ œœœ˜7Kšœ œœœ˜/Kš œ%œœœœ˜>Kšœ œœœ˜3K˜K˜Kšœ*œ˜FKšœ˜K˜—šŸ œœ'œœ˜ZKš˜šŸœœœ˜0Kš˜šœœ˜ K˜ Kš œœœœœ˜Kšœœ œ œ ˜*Kšœœœœ˜Kšœ˜šœœœ˜-šœœœ˜+Kšœœœ'˜5Kšœœœœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ œœ˜šœœ˜ Kš œœœœœ˜šœœ˜šœœ œ œ˜DKš œœ œœœœ˜9Kšœ˜—Kšœœœœ œœ)œœœ œœ?˜ÛK˜Kšœœ˜—Kšœ˜—Kšœ˜—K˜šŸ œ˜!Kš˜Kšœœœœ+˜