DIRECTORY Abutters, Atom, Imager, MessageWindow, MJSContainers, MJSContainersExtras, Process, Rope, ViewerClasses, ViewerLocks, ViewerOps; AbuttersImpl: CEDAR MONITOR LOCKS a USING a: Abutter IMPORTS Atom, MessageWindow, MJSContainers, MJSContainersExtras, Process, Rope, ViewerLocks, ViewerOps EXPORTS Abutters = {OPEN Abutters; Abutter: TYPE = REF AbutterRep; AbutterRep: PUBLIC TYPE = MONITORED RECORD [ class: AbutterClass, v: Viewer, tracked: Size _ [], cr: CompiledRules _ ALL[NIL], queue: Queue _ ALL[NIL], sizeSetters: ARRAY Axis OF NodeList _ ALL[NIL], clientData: REF ANY ]; Axis: TYPE = {horizontal, vertical}; Size: TYPE = RECORD [cw, ch: INTEGER _ 0]; CompiledRules: TYPE = ARRAY Edge OF RootNode; Queue: TYPE = ARRAY Edge OF NodeList; NodeList: TYPE = LIST OF Node; Node: TYPE = REF NodeRep; ChildNodeList: TYPE = LIST OF ChildNode; ChildNode: TYPE = REF NodeRep[child]; RootNode: TYPE = REF NodeRep[root]; NodeRep: TYPE = RECORD [ e: Edge, scheduled, setSize: BOOL _ FALSE, spaceAfter: INTEGER _ 0, successors: ChildNodeList _ NIL, predecessor: Node _ NIL, variant: SELECT kind: * FROM root => [], child => [ v: Viewer, spaceBefore: INTEGER, stretch: BOOL, tracked: Box _ [], opposite: ChildNode _ NIL ], ENDCASE ]; Box: TYPE = RECORD [wx, wy, ww, wh: INTEGER _ 0]; axisKeys: ARRAY Axis OF ATOM = [ horizontal: $horizontalAbutterNode, vertical: $verticalAbutterNode ]; edgeKeys: ARRAY Edge OF ATOM = [$left, $right, $top, $bottom]; oppositeEdge: ARRAY Edge OF Edge = [ left: right, right: left, top: bottom, bottom: top]; esgn: ARRAY Edge OF [-1 .. 1] = [ left: 1, right: -1, top: 1, bottom: -1]; Next: ARRAY Edge OF Edge; edgeAxis: ARRAY Edge OF Axis = [ left: horizontal, right: horizontal, top: vertical, bottom: vertical]; classProp: ATOM _ Atom.MakeAtom["Mike Spreitzer @ April 24, 1986 10:29:33 pm PST"]; RegisterClass: PUBLIC PROC [viewerFlavor: ATOM, class: AbutterClassPrivate] RETURNS [same: ATOM] = { mjsClass: MJSContainers.MJSContainerClass = NEW [MJSContainers.MJSContainerClassRep _ [ paint: Paint, destroy: class.destroy, copy: class.copy, set: class.set, get: class.get, init: Init, save: class.save, caption: class.caption, adjust: NoteSizeChanged, childAdjust: NoteAbutterChildSize, menu: class.menu, icon: class.icon]]; MJSContainers.RegisterClass[same _ viewerFlavor, mjsClass]; Atom.PutProp[atom: viewerFlavor, prop: classProp, val: NEW [AbutterClassPrivate _ class]]; }; GetClass: PUBLIC PROC [viewerFlavor: ATOM] RETURNS [class: AbutterClass] = { class _ NARROW[Atom.GetProp[viewerFlavor, classProp]]; }; vanilla: PUBLIC ATOM _ RegisterClass[ $VanillaAbutter, [save: Save]]; Create: PUBLIC PROC [viewerFlavor: ATOM, info: ViewerClasses.ViewerRec _ [], paint: BOOL _ TRUE] RETURNS [abutter: Abutter] = { realFlavor: ATOM = IF viewerFlavor # NIL THEN viewerFlavor ELSE vanilla; class: AbutterClass = GetClass[realFlavor]; info.data _ abutter _ NEW [AbutterRep _ [class: class, clientData: info.data]]; abutter.cr[left] _ NEW [NodeRep.root _ [e: left, variant: root[] ]]; abutter.cr[right] _ NEW [NodeRep.root _ [e: right, variant: root[] ]]; abutter.cr[top] _ NEW [NodeRep.root _ [e: top, variant: root[] ]]; abutter.cr[bottom] _ NEW [NodeRep.root _ [e: bottom, variant: root[] ]]; IF MJSContainers.Create[realFlavor, info, paint] # abutter.v THEN ERROR; }; Init: PROC [self: Viewer] --ViewerClasses.InitProc-- = { a: Abutter = NARROW[MJSContainers.GetClientData[self]]; a.v _ self; IF a.class.init # NIL THEN a.class.init[self]; }; Save: PROC [self: Viewer, force: BOOL _ FALSE] --ViewerOps.SaveProc-- = { a: Abutter = NARROW[MJSContainers.GetClientData[self]]; FOR v: Viewer _ self.child, v.sibling UNTIL v = NIL DO IF force THEN -- Copied from part of ViewerOpsImplB.SaveAllEdits-- { IF (v.newVersion OR v.newFile) AND v.class.save # NIL THEN v.class.save[v, force ! ANY => CONTINUE]; v.newVersion _ v.newFile _ FALSE; IF v.icon=dirtyDocument THEN v.icon _ document; IF v.link#NIL THEN FOR t: Viewer _ v.link, t.link UNTIL t=v DO t.newVersion _ t.newFile _ FALSE; ENDLOOP; } ELSE { ViewerOps.SaveViewer[v]; }; ENDLOOP; }; Paint: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL _ FALSE] --ViewerClasses.PaintProc-- = { a: Abutter = NARROW[MJSContainers.GetClientData[self]]; Inner: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; CheckUnion: INTERNAL PROC [nl: ChildNodeList] = { FOR nl _ nl, nl.rest WHILE nl # NIL DO n: ChildNode _ nl.first; SELECT n.e FROM left, right => IF n.v.ww # n.tracked.ww OR n.v.wx # n.tracked.wx THEN Sched[a, n]; top, bottom => IF n.v.wh # n.tracked.wh OR n.v.wy # n.tracked.wy THEN Sched[a, n]; ENDCASE => ERROR; CheckUnion[n.successors]; ENDLOOP; }; [] _ CheckEdges[a]; FOR e: Edge IN Edge DO CheckUnion[a.cr[e].successors] ENDLOOP; IF quit _ (a.queue # ALL[NIL]) THEN TRUSTED {Process.Detach[FORK DeQueue[a, TRUE, TRUE, TRUE, FALSE]]}; }; Inner[a]; }; NoteSizeChanged: PROC [self: Viewer] RETURNS [adjusted: BOOL _ FALSE] --ViewerClasses.AdjustProc-- = { a: Abutter _ NARROW[MJSContainers.GetClientData[self]]; Inner: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; [] _ CheckEdges[a]}; viewerToPaint: Viewer; paintColumn: BOOL; Inner[a]; [viewerToPaint, paintColumn] _ ReallyDeQueue[a, FALSE, FALSE, TRUE, TRUE]; adjusted _ viewerToPaint # NIL OR paintColumn; }; NoteAbutterChildSize: PROC [parent, child: Viewer] RETURNS [viewerToPaint: Viewer _ NIL, paintColumn: BOOL _ FALSE] --MJSContainers.ChildAdjustProc-- = { a: Abutter = QuaAbutter[parent]; WithLock: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; FOR axis: Axis IN Axis DO n: ChildNode = Find[child, axis]; IF n # NIL AND n.tracked # [child.wx, child.wy, child.wh, child.ww] THEN Sched[a, n]; ENDLOOP; FOR edge: Edge IN Edge DO n: ChildNode = EdgeFind[child, edge]; IF n # NIL AND n.tracked # [child.wx, child.wy, child.wh, child.ww] THEN Sched[a, n]; ENDLOOP; }; WithLock[a]; [viewerToPaint, paintColumn] _ ReallyDeQueue[a, FALSE, FALSE, FALSE, FALSE]; }; CheckEdges: INTERNAL PROC [a: Abutter] RETURNS [diff: BOOL] = { diff _ FALSE; IF a.v.cw # a.tracked.cw THEN {Sched[a, a.cr[right]]; diff _ TRUE}; IF a.v.ch # a.tracked.ch THEN {Sched[a, a.cr[bottom]]; diff _ TRUE}; }; Sched: INTERNAL PROC [a: Abutter, n: Node] = { Mark: PROC [n: Node] = { n.scheduled _ TRUE; FOR nl: ChildNodeList _ n.successors, nl.rest WHILE nl # NIL DO Mark[nl.first]; ENDLOOP; }; IF n.scheduled THEN RETURN; a.queue[n.e] _ CONS[n, a.queue[n.e]]; Mark[n]; }; DeQueue: PROC [a: Abutter, mayPaint, mustPaint, paintIfResize, forkSelfOps: BOOL] = {[] _ ReallyDeQueue[a, mayPaint, mustPaint, paintIfResize, forkSelfOps]}; ReallyDeQueue: PROC [a: Abutter, mayPaint, mustPaint, paintIfResize, forkSelfOps: BOOL] RETURNS [viewerToPaint: Viewer, paintColumn: BOOL] = { WithViewerLock: PROC = {[viewerToPaint, paintColumn] _ DeQueueWithAbutterLock[a, mayPaint, mustPaint, paintIfResize, forkSelfOps]}; IF forkSelfOps OR a.sizeSetters = ALL[NIL] OR a.v.iconic THEN ViewerLocks.CallUnderWriteLock[WithViewerLock, a.v] ELSE ViewerLocks.CallUnderColumnLock[WithViewerLock, a.v.column]; }; itLimit: INTEGER _ 20; DeQueueWithAbutterLock: PROC [a: Abutter, mayPaint, mustPaint, paintIfResize, forkSelfOps: BOOL] RETURNS [viewerToPaint: Viewer _ NIL, paintColumn: BOOL _ FALSE] = { moveSelf: BOOL _ FALSE; selfWidth, selfHeight: INTEGER; WithLock: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; Adjust: INTERNAL PROC [n: ChildNode, org: INTEGER] = { near: INTEGER _ org + esgn[n.e]*n.spaceBefore; far: INTEGER; To: INTERNAL PROC [x, y, w, h: INTEGER] = { ow: INTEGER _ n.v.ww; oh: INTEGER _ n.v.wh; dw: BOOL _ w # ow; dh: BOOL _ h # oh; diff--erence on other axis--: BOOL; axis: Axis; on: Node _ NIL; viewerToPaint _ a.v; ViewerOps.MoveViewer[n.v, x, y, w, h, FALSE]; SELECT n.e FROM left, right => {diff _ n.v.wh # oh; axis _ vertical}; top, bottom => {diff _ n.v.ww # ow; axis _ horizontal}; ENDCASE => ERROR; IF diff AND (on _ Find[n.v, axis]) # NIL THEN Sched[a, on]; }; d: INTEGER; IF n.stretch AND n.successors # NIL THEN ERROR; n.scheduled _ FALSE; SELECT n.e FROM left => IF (d _ near - n.v.wx) # 0 THEN { IF n.stretch THEN To[near, n.v.wy, n.v.ww-d, n.v.wh] ELSE To[near, n.v.wy, n.v.ww, n.v.wh]}; right => IF (d _ near - (n.v.wx+n.v.ww)) # 0 THEN { IF n.stretch THEN To[n.v.wx, n.v.wy, n.v.ww+d, n.v.wh] ELSE To[n.v.wx+d, n.v.wy, n.v.ww, n.v.wh]}; top => IF (d _ near - n.v.wy) # 0 THEN { IF n.stretch THEN To[n.v.wx, near, n.v.ww, n.v.wh-d] ELSE To[n.v.wx, near, n.v.ww, n.v.wh]}; bottom => IF (d _ near - (n.v.wy+n.v.wh)) # 0 THEN { IF n.stretch THEN To[n.v.wx, n.v.wy, n.v.ww, n.v.wh+d] ELSE To[n.v.wx, n.v.wy+d, n.v.ww, n.v.wh]}; ENDCASE => ERROR; n.tracked _ [n.v.wx, n.v.wy, n.v.ww, n.v.wh]; IF n.opposite # NIL THEN {o: ChildNode _ n.opposite; IF o.v # n.v THEN ERROR; o.tracked _ n.tracked; }; far _ SELECT n.e FROM left => n.v.wx+n.v.ww, right => n.v.wx, top => n.v.wy+n.v.wh, bottom => n.v.wy, ENDCASE => ERROR; FOR succs: ChildNodeList _ n.successors, succs.rest WHILE succs # NIL DO Adjust[succs.first, far]; ENDLOOP; }; empties: [0 .. 4] _ 0; itCount: INTEGER _ 0; scroll: INTEGER = MJSContainers.ScrollOffset[a.v]; hscroll: INTEGER ~ MJSContainersExtras.HScrollOffset[a.v]; rootOrgs: ARRAY Edge OF INTEGER = [ left: 0 + hscroll, right: a.v.cw + hscroll, top: 0 + scroll, bottom: a.v.ch + scroll]; FOR e: Edge _ FIRST[Edge], Next[e] WHILE empties < 4 DO IF itLimit <= (itCount _ itCount + 1) THEN { TRUSTED {Process.Detach[FORK TooMany[a]]}; EXIT; }; IF a.queue[e] # NIL THEN { rootOrg: INTEGER = rootOrgs[e]; nl: NodeList _ a.queue[e]; a.queue[e] _ NIL; empties _ 0; FOR nl _ nl, nl.rest WHILE nl # NIL DO n: Node = nl.first; IF n.e # e THEN ERROR; IF n.scheduled THEN { WITH n SELECT FROM cn: ChildNode => { org: INTEGER _ WITH cn.predecessor SELECT FROM rn: RootNode => rootOrg, cn: ChildNode => SELECT e FROM left => cn.v.wx+cn.v.ww, right => cn.v.wx, top => cn.v.wy+cn.v.wh, bottom => cn.v.wy, ENDCASE => ERROR, ENDCASE => ERROR; Adjust[cn, org]; }; rn: RootNode => { SELECT e FROM left, top => NULL; right => a.tracked.cw _ a.v.cw; bottom => a.tracked.ch _ a.v.ch; ENDCASE => ERROR; n.scheduled _ FALSE; FOR cnl: ChildNodeList _ n.successors, cnl.rest WHILE cnl # NIL DO Adjust[cnl.first, rootOrg]; ENDLOOP; }; ENDCASE => ERROR; }; ENDLOOP; } ELSE { empties _ empties + 1 }; ENDLOOP; IF a.sizeSetters # ALL[NIL] THEN { goalSizes: ARRAY Axis OF INTEGER _ [a.v.cw, a.v.ch]; outerSizes: ARRAY Axis OF INTEGER; FOR axis: Axis IN Axis DO IF a.sizeSetters[axis] # NIL THEN { goal: INTEGER _ 0; FOR nl: NodeList _ a.sizeSetters[axis], nl.rest WHILE nl # NIL DO n: Node = nl.first; ro: INTEGER = rootOrgs[n.e]; size: INTEGER = SELECT n.e FROM left => WITH n SELECT FROM rn: RootNode => rn.spaceAfter, cn: ChildNode => cn.v.wx+cn.v.ww+cn.spaceAfter - ro, ENDCASE => ERROR, right => WITH n SELECT FROM rn: RootNode => rn.spaceAfter, cn: ChildNode => ro - cn.v.wx + cn.spaceAfter, ENDCASE => ERROR, top => WITH n SELECT FROM rn: RootNode => rn.spaceAfter, cn: ChildNode => cn.v.wy+cn.v.wh+cn.spaceAfter - ro, ENDCASE => ERROR, bottom => WITH n SELECT FROM rn: RootNode => rn.spaceAfter, cn: ChildNode => ro - cn.v.wy + cn.spaceAfter, ENDCASE => ERROR, ENDCASE => ERROR; goal _ MAX[goal, size]; ENDLOOP; goalSizes[axis] _ goal; }; ENDLOOP; outerSizes[horizontal] _ goalSizes[horizontal] + a.v.ww - a.v.cw; outerSizes[vertical] _ goalSizes[vertical] + a.v.wh - a.v.ch; SELECT a.v.parent FROM =NIL => IF resized _ outerSizes[vertical] # a.v.openHeight THEN { a.v.openHeight _ outerSizes[vertical]; paintColumn _ TRUE; viewerToPaint _ NIL; }; #NIL => IF resized _ outerSizes # [a.v.ww, a.v.wh] THEN { IF forkSelfOps THEN TRUSTED { Process.Detach[FORK MoveChild[a.v, [a.v.wx, a.v.wy, outerSizes[horizontal], outerSizes[vertical]], paintIfResize]]; IF paintIfResize THEN {paintColumn _ FALSE; viewerToPaint _ NIL}; } ELSE { moveSelf _ TRUE; selfWidth _ outerSizes[horizontal]; selfHeight _ outerSizes[vertical]; }; }; ENDCASE => ERROR; }; }; resized: BOOL _ FALSE; IF mustPaint AND NOT mayPaint THEN ERROR; IF mayPaint AND NOT paintIfResize THEN ERROR; WithLock[a]; IF moveSelf THEN { viewerToPaintBecauseOfNote: Viewer; ViewerOps.MoveViewer[a.v, a.v.wx, a.v.wy, selfWidth, selfHeight, FALSE]; viewerToPaint _ a.v.parent; [viewerToPaintBecauseOfNote, paintColumn] _ MJSContainers.NoteChildSize[a.v]; IF viewerToPaintBecauseOfNote # NIL THEN viewerToPaint _ viewerToPaintBecauseOfNote; }; IF (mayPaint OR (paintIfResize AND resized)) AND (mustPaint OR paintColumn OR viewerToPaint # NIL) THEN { IF paintColumn THEN { IF forkSelfOps THEN TRUSTED {Process.Detach[FORK ViewerOps.ComputeColumn[a.v.column, TRUE]]} ELSE ViewerOps.ComputeColumn[a.v.column, TRUE]; mustPaint _ paintColumn _ FALSE; viewerToPaint _ NIL; }; IF mustPaint AND viewerToPaint = NIL THEN viewerToPaint _ a.v; IF viewerToPaint # NIL THEN { IF forkSelfOps THEN TRUSTED {Process.Detach[FORK ViewerOps.PaintViewer[viewerToPaint, all]]} ELSE ViewerOps.PaintViewer[viewerToPaint, all]; viewerToPaint _ NIL; }; }; }; MoveChild: PROC [v: Viewer, to: Box, paint: BOOL] = { paintViewer: Viewer; paintColumn: BOOL; ViewerOps.MoveViewer[v, to.wx, to.wy, to.ww, to.wh, FALSE]; [paintViewer, paintColumn] _ MJSContainers.NoteChildSize[v]; IF paint AND NOT (paintViewer # NIL OR paintColumn) THEN paintViewer _ v.parent; IF paint THEN { IF paintColumn THEN ViewerOps.ComputeColumn[v.column, TRUE] ELSE ViewerOps.PaintViewer[paintViewer, all]; }; }; TooMany: PROC [a: Abutter] = { MessageWindow.Append[ message: Rope.Cat["Too many iterations solving layout of ", a.v.name], clearFirst: TRUE]; }; QuaViewer: PUBLIC PROC [a: Abutter] RETURNS [v: Viewer] = {v _ a.v}; QuaAbutter: PUBLIC PROC [v: Viewer] RETURNS [a: Abutter] = {a _ NARROW[MJSContainers.GetClientData[v]]}; ViewerIsAbutter: PUBLIC PROC [v: Viewer] RETURNS [b: BOOL] = { data: REF ANY; IF NOT MJSContainers.IsMJSContainer[v] THEN RETURN[FALSE]; data _ MJSContainers.GetClientData[v]; b _ data # NIL AND ISTYPE[data, Abutter]}; IsAbutter: PUBLIC PROC [ra: REF ANY] RETURNS [b: BOOL] = {b _ ra # NIL AND ISTYPE[ra, Abutter]}; Narrow: PUBLIC PROC [ra: REF ANY] RETURNS [a: Abutter] = {a _ NARROW[ra]}; GetClientData: PUBLIC PROC [a: Abutter] RETURNS [cd: REF ANY] = { cd _ a.clientData; }; GetClientDataFromViewer: PUBLIC PROC [v: Viewer] RETURNS [cd: REF ANY] = { cd _ QuaAbutter[v].clientData; }; ScrollOffset: PUBLIC PROC [a: Abutter] RETURNS [offTop: INTEGER] = {offTop _ MJSContainers.ScrollOffset[a.v]}; HScrollOffset: PUBLIC PROC [a: Abutter] RETURNS [offLeft: INTEGER] = {offLeft _ MJSContainersExtras.HScrollOffset[a.v]}; SetLayout: PUBLIC PROC [a: Abutter, rules: Rules, paint: BOOL _ TRUE] = { WithLock: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; DoSeries: INTERNAL PROC [e: Edge, s: Series, parent: Node] = { FOR sl: LIST OF SeriesElement _ s.rigid, sl.rest WHILE sl # NIL DO parent _ AddChild[a, parent, sl.first.viewer, e, sl.first.spaceBefore, FALSE]; ENDLOOP; WITH s SELECT FROM x: Series[none] => IF x.setParentSize THEN MakeSizeSetter[a, parent, edgeAxis[e], x.spaceAfter]; x: Series[parallel] => { FOR sl: Parallel _ x.p, sl.rest WHILE sl # NIL DO DoSeries[e, sl.first, parent]; ENDLOOP; }; x: Series[stretch] => parent _ AddChild[a, parent, x.se.viewer, e, x.se.spaceBefore, TRUE]; ENDCASE => ERROR; }; a.sizeSetters _ ALL[NIL]; a.queue _ ALL[NIL]; FOR e: Edge IN Edge DO Forget[a.cr[e].successors]; a.cr[e].successors _ NIL; ENDLOOP; FOR e: Edge IN Edge DO DoSeries[e, rules[e], a.cr[e]] ENDLOOP; }; WithLock[a]; DeQueue[a, paint, paint, paint, FALSE]; }; Forget: INTERNAL PROC [nl: ChildNodeList] = { FOR nl _ nl, nl.rest WHILE nl # NIL DO v: Viewer = nl.first.v; FOR axis: Axis IN Axis DO ViewerOps.AddProp[v, axisKeys[axis], NIL]; ENDLOOP; FOR edge: Edge IN Edge DO ViewerOps.AddProp[v, edgeKeys[edge], NIL]; ENDLOOP; Forget[nl.first.successors]; ENDLOOP; }; MakeSizeSetter: INTERNAL PROC [a: Abutter, n: Node, axis: Axis, spaceAfter: INTEGER] = { n.setSize _ TRUE; n.spaceAfter _ spaceAfter; a.sizeSetters[axis] _ CONS[n, a.sizeSetters[axis]]; }; SetSizeBy: PUBLIC PROC [a: Abutter, child: Viewer, edge: Edge, space: INTEGER _ 0, paint: BOOL _ TRUE] = { WithLock: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; axis: Axis = edgeAxis[edge]; n: Node = SELECT child FROM =parentSide => a.cr[edge], #parentSide => Find[child, axis], ENDCASE => ERROR; MakeSizeSetter[a, n, axis, space]; }; WithLock[a]; DeQueue[a, paint, paint, paint, FALSE]; }; AddChild: INTERNAL PROC [a: Abutter, parent: Node, v: Viewer, e: Edge, space: INTEGER, stretch: BOOL] RETURNS [child: ChildNode] = { axis: Axis _ edgeAxis[e]; opp: ChildNode _ IF stretch THEN EdgeFind[v, oppositeEdge[e]] ELSE NIL; IF Find[v, axis] # NIL THEN ERROR; IF EdgeFind[v, e] # NIL THEN ERROR; child _ NEW [NodeRep.child _ [ e: e, scheduled: parent.scheduled, predecessor: parent, variant: child[ v: v, spaceBefore: space, stretch: stretch, tracked: [0, 0, 0, 0], opposite: opp ] ]]; IF opp # NIL THEN { IF opp.opposite # NIL THEN ERROR; opp.opposite _ child}; parent.successors _ CONS[child, parent.successors]; Sched[a, child]; SELECT stretch FROM FALSE => ViewerOps.AddProp[v, axisKeys[axis], child]; TRUE => ViewerOps.AddProp[v, edgeKeys[e], child]; ENDCASE => ERROR; }; Find: INTERNAL PROC [v: Viewer, axis: Axis] RETURNS [n: ChildNode] = {n _ NARROW[ViewerOps.FetchProp[v, axisKeys[axis]]]}; EdgeFind: INTERNAL PROC [v: Viewer, e: Edge] RETURNS [n: ChildNode] = {n _ NARROW[ViewerOps.FetchProp[v, edgeKeys[e]]]}; Abut: PUBLIC PROC [a: Abutter, child1, child2: Viewer, edge: Edge, space: INTEGER _ 0, stretch: BOOL _ FALSE, paint: BOOL _ TRUE] = { WithLock: ENTRY PROC [a: Abutter] = { ENABLE UNWIND => NULL; parent: Node = SELECT child1 FROM =parentSide => a.cr[edge], #parentSide => Find[child1, edgeAxis[edge]], ENDCASE => ERROR; IF parent = NIL THEN ERROR; [] _ AddChild[a, parent, child2, edge, space, stretch]; }; WithLock[a]; DeQueue[a, paint, paint, paint, FALSE]; }; parentSide: PUBLIC Viewer _ NEW [ViewerClasses.ViewerRec]; Start: PROC = { FOR e: Edge IN [FIRST[Edge] .. LAST[Edge]) DO Next[e] _ e.SUCC; ENDLOOP; Next[LAST[Edge]] _ FIRST[Edge]; }; Start[]; }. ¦AbuttersImpl.Mesa Eric Nickell April 16, 1986 5:07:31 pm PST Pier, May 23, 1985 3:05:08 pm PDT Mike Spreitzer August 27, 1986 5:44:51 pm PDT Eric Nickell, August 28, 1986 5:37:08 am PDT INVARIANT cn.scheduled iff we're planning to consider moving/stretching n. n.scheduled iff n reachable from a.queue. n.scheduled if n.predecessor.scheduled. a.tracked describes shape to which a last layed out. cn.tracked describes where cn last put. An Abutter's Viewer LOCKs are never requested inside its Abutter LOCK. Viewers restrictions: In a PaintProc, we can't reposition any viewers; we can only paint. In v's AdjustProc, we can reposition v's children, but can't mess with v. Κ– "cedar" style˜code™K™*K™!K™-K™,—K˜KšΟk œ˜ŠK˜šΠbx œœ˜Kšœœ ˜Kšœ_˜fKšœ ˜™ K™@Kšœ)™)K™'Kšœ4™4K™'—K˜K™FK™™K™CK™I—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˜ Kšœ œ˜Kšœ œ˜K˜Kšœ˜K˜—Kš˜—K˜—K˜Kšœœœœ˜1K˜šœ œœœ˜ Kšœ#˜#Kšœ˜K˜—K˜Kšœ œœœ"˜>šœœœ ˜$K˜ K˜ K˜ K˜ —K˜šœœœ˜!K˜K˜ K˜K˜ —K˜Kšœœœ˜šœ œœ ˜ K˜K˜K˜K˜—K˜Kšœ œD˜SK˜š Οn œœœœœœ˜dšœ,œ(˜WK˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜ K˜Kšœ˜Kšœ˜K˜"Kšœ˜Kšœ˜—Kšœ;˜;Kšœ7œ ˜ZK˜—K˜š Ÿœœœœœ˜LKšœœ(˜6K˜—K˜šœ œœ˜%Kšœ˜K˜—K˜šŸœœœœ-œœœ˜Kš œ œœœœœ ˜HKšœ+˜+Kšœœ6˜OKšœœ.˜DKšœœ/˜FKšœœ-˜BKšœœ0˜HKšœ;œœ˜HK˜—K˜•StartOfExpansion -- [self: ViewerClasses.Viewer]šŸœœΟcœ˜8Kšœ œ$˜7K˜ Kšœœœ˜.K˜—K˜š Ÿœœœœ œ˜IKšœ œ$˜7šœ#œœ˜6šœ˜šœ 4œ˜;š œœ œœ˜:Kšœœœ˜)—Kšœœ˜!Kšœœ˜/š œœœœœ˜>Kšœœ˜!Kšœ˜—K˜—šœ˜K˜K˜——Kšœ˜—K˜—K˜šŸœœ6œœ œœœœ œ˜“Kšœ œ$˜7šŸœœœ˜"Kšœœœ˜šŸ œœœ˜1šœœœ˜&Kšœ˜šœ˜Kšœœœœ ˜RKšœœœœ ˜RKšœœ˜—Kšœ˜Kšœ˜—K˜—K˜Kšœ œœ œ˜>Kšœœœœœœ œœœœ˜gK˜—K˜ K˜—K˜š Ÿœœœ œœ œ˜fKšœ œ$˜7šŸœœœ˜"Kšœœœ˜Kšœ˜—K˜Kšœ œ˜K˜ Kš œ0œœœœ˜JKšœœœ ˜.K˜—K˜šŸœœœœœœ !œ˜™K˜ šŸœœœ˜%Kšœœœ˜šœ œ˜K˜!Kšœœœ6œ ˜UKšœ˜—šœ œ˜Kšœ%˜%Kšœœœ6œ ˜UKšœ˜—K˜—K˜ Kš œ0œœœœ˜LK˜—K˜š Ÿ œœœœœ˜?Kšœœ˜ Kšœœ œ˜CKšœœ!œ˜DK˜—K˜šŸœœœ˜.šŸœœ˜Kšœœ˜šœ+œœ˜?K˜Kšœ˜—K˜—Kšœ œœ˜Kšœœ˜%K˜K˜—K˜šŸœœ?œ˜SKšœI˜I—K˜š Ÿ œœ?œœ&œ˜ŽKšŸœœo˜ƒKšœ œœœœ œ5œ=˜³K˜—K˜Kšœ œ˜K˜šŸœœ?œœœœœ˜₯Kšœ œœ˜Kšœœ˜šŸœœœ˜%Kšœœœ˜šŸœœœœ˜6Kšœœ!˜.Kšœœ˜ šŸœœœœ˜+Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœœ ˜Kšœ œœ˜#K˜ Kšœ œ˜Kšœ˜Kšœ&œ˜-šœ˜Kšœ5˜5Kšœ7˜7Kšœœ˜—Kšœœœœ˜;K˜—Kšœœ˜ Kš œ œœœœ˜/Kšœœ˜šœ˜šœœœ˜)šœ ˜ Kšœ#˜'Kšœ#˜'——šœ œ"œ˜3šœ ˜ Kšœ%˜)Kšœ'˜+——šœœœ˜(šœ ˜ Kšœ#˜'Kšœ#˜'——šœ œ"œ˜4šœ ˜ Kšœ%˜)Kšœ'˜+——Kšœœ˜—K˜-šœœœ˜4Kšœ œœ˜K˜K˜—šœœ˜K˜K˜K˜K˜Kšœœ˜—šœ1œ œ˜HK˜Kšœ˜—K˜—K˜Kšœ œ˜Kšœœ#˜2Kšœ œ*˜:šœ œœœ˜#K˜K˜K˜K˜—šœ œœ ˜7šœ$œ˜,Kšœœ˜*Kšœ˜K˜—šœœœ˜Kšœ œ˜K˜Kšœ œ˜K˜ šœœœ˜&K˜Kšœ œœ˜šœ œ˜šœœ˜šœ˜šœœœœ˜.Kšœ˜šœœ˜K˜K˜K˜K˜Kšœœ˜—Kšœœ˜—Kšœ˜Kšœ˜—˜šœ˜ Kšœ œ˜K˜K˜ Kšœœ˜—Kšœœ˜šœ-œœ˜BKšœ˜Kšœ˜—K˜—Kšœœ˜—K˜—Kšœ˜—K˜—šœ˜K˜K˜—Kšœ˜—šœœœœ˜"Kšœ œœœ˜4Kšœ œœœ˜"šœ œ˜šœœœ˜#Kšœœ˜šœ-œœ˜AK˜Kšœœ˜šœœœ˜šœœœ˜K˜K˜4Kšœœ˜—šœ œœ˜K˜K˜.Kšœœ˜—šœœœ˜K˜K˜4Kšœœ˜—šœ œœ˜K˜K˜.Kšœœ˜—Kšœœ˜—Kšœœ ˜Kšœ˜—K˜K˜—Kšœ˜—KšœA˜AKšœ=˜=šœ ˜šœœœ1œ˜AKšœ&˜&Kšœœ˜Kšœœ˜K˜—šœœœ)œ˜9šœ œœ˜Kšœœ`˜sKšœœœœ˜AKšœ˜—šœ˜Kšœ œ˜Kšœ#˜#Kšœ"˜"Kšœ˜—K˜—Kšœœ˜—K˜—K˜—Kšœ œœ˜Kš œ œœ œœ˜)Kš œ œœœœ˜-K˜ šœ œ˜K˜#KšœAœ˜HKšœ˜KšœM˜MKšœœœ,˜TK˜—šœ œœ œ œ œœœ˜išœ œ˜Kšœ œœœ%œœ%œ˜ŒKšœœ˜ Kšœœ˜K˜—Kšœ œœœ˜>šœœœ˜Kš œ œœœ-œ+˜ŒKšœœ˜K˜—Kšœ˜—K˜—K˜šŸ œœœ˜5K˜Kšœ œ˜Kšœ4œ˜;Kšœ<˜Kšœœœ˜Kš œœ!œœœ˜:Kšœ&˜&Kšœ œœœ˜*—K˜šŸ œœœœœœœ˜8Kšœ œœœ˜'—š Ÿœœœœœœ˜8Kšœœ˜—K˜š Ÿ œœœœœœ˜AK˜K˜—K˜š Ÿœœœ œœœ˜JKšœ˜K˜—K˜š Ÿ œœœœ œ˜BKšœ+˜+—K˜š Ÿ œœœœ œ˜DKšœ3˜3—K˜š Ÿ œœœ#œœ˜IšŸœœœ˜%Kšœœœ˜šŸœœœ'˜>š œœœ"œœ˜BKšœGœ˜NKšœ˜—šœœ˜Kšœœœ6˜`šœ˜šœœœ˜1K˜Kšœ˜—K˜—KšœUœ˜[Kšœœ˜—K˜—Kšœœœ˜Kšœ œœ˜šœ œ˜Kšœ˜Kšœœ˜Kšœ˜—Kšœ œœ œ˜>K˜—K˜ Kšœ œ˜'K˜—K˜šŸœœœ˜-šœœœ˜&K˜šœ œ˜Kšœ%œ˜*Kšœ˜—šœ œ˜Kšœ%œ˜*Kšœ˜—Kšœ˜Kšœ˜—K˜—K˜šŸœœœ/œ˜XKšœ œ˜K˜Kšœœ˜3K˜—K˜š Ÿ œœœ0œ œœ˜jšŸœœœ˜%Kšœœœ˜K˜šœ œ˜Kšœ˜Kšœ!˜!Kšœœ˜—Kšœ"˜"K˜—K˜ Kšœ œ˜'K˜—K˜š Ÿœœœ7œ œœ˜„Kšœ˜Kš œœ œœœ˜GKšœœœœ˜"Kšœœœœ˜#šœœ˜Kšœ˜Kšœ˜Kšœ˜˜K˜Kšœ˜K˜K˜K˜ K˜—K˜—šœœœ˜Kšœœœœ˜!K˜—Kšœœ˜3K˜šœ ˜Kšœ0˜5Kšœ-˜1Kšœœ˜—K˜—K˜šŸœœœœ˜DKšœœ*˜5—K˜šŸœœœœ˜EKšœœ'˜2—K˜šŸœœœ9œœœ œœ˜…šŸœœœ˜%Kšœœœ˜šœœ˜!Kšœ˜Kšœ,˜,Kšœœ˜—Kšœ œœœ˜K˜7K˜—K˜ Kšœ œ˜'K˜Kšœ œ œ˜:—K˜šŸœœ˜š œ œœ œ˜-Kšœ œ˜Kšœ˜—Kšœœ œ˜K˜—K˜K˜K˜K˜——…—F²bt