DIRECTORY ImagerBox, ImagerTransformation, TreeGrapher, Vector2 USING [VEC]; TreeGrapherImpl: CEDAR PROGRAM IMPORTS ImagerBox, ImagerTransformation EXPORTS TreeGrapher ~ BEGIN OPEN TreeGrapher; Box: TYPE ~ ImagerBox.Box; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; PostOrder: PROC [node: Node, each: PROC [Node]] = { FOR tail: LIST OF Node ¬ node.children, tail.rest UNTIL tail = NIL DO PostOrder[tail.first, each]; ENDLOOP; each[node]; }; ForwardT: PROC [lp: LayoutParameters] RETURNS [Transformation] ~ { RETURN [ImagerTransformation.XYToSF[[ slow: SELECT lp.descendantDirection FROM $N => up, $E => right, $S => down, $W => left, ENDCASE => ERROR, fast: SELECT lp.siblingDirection FROM $N => up, $E => right, $S => down, $W => left, ENDCASE => ERROR], 0, 0]] }; XFormBox: PROC [t: Transformation, box: Box] RETURNS [Box] ~ { RETURN [ImagerBox.BoxFromRectangle[ImagerTransformation.TransformRectangle[t, ImagerBox.RectangleFromBox[box]]]]; }; DoLayout: PUBLIC PROC [root: Node, lp: LayoutParameters] = { forward: Transformation ~ ForwardT[lp]; reverse: Transformation ~ ImagerTransformation.Invert[forward]; Pass1Each: PROC [node: Node] = { bounds: Box ~ node.class.bounds[node]; nodeBox: Box ¬ XFormBox[forward, bounds]; childrenSum: REAL ¬ 0.0; childrenMin: REAL ¬ 1.0E+30; FOR tail: LIST OF Node ¬ node.children, tail.rest UNTIL tail = NIL DO childrenSum ¬ childrenSum + (tail.first.layout.treeBox.ymax-tail.first.layout.treeBox.ymin); IF tail.rest # NIL THEN childrenSum ¬ childrenSum + lp.siblingPad; childrenMin ¬ MIN[childrenMin, tail.first.layout.treeBox.xmin]; ENDLOOP; { childrenDelta: REAL ¬ nodeBox.xmax + lp.descendantPad - childrenMin; s: REAL ¬ 0.5*((nodeBox.ymax+nodeBox.ymin)-childrenSum); FOR tail: LIST OF Node ¬ node.children, tail.rest UNTIL tail = NIL DO s ¬ s + (tail.first.layout.treeBox.ymax-tail.first.layout.treeBox.ymin); tail.first.layout.origin ¬ [childrenDelta, s-tail.first.layout.treeBox.ymax]; IF tail.rest # NIL THEN s ¬ s + lp.siblingPad; ENDLOOP; }; { treeBox: Box ¬ nodeBox; FOR tail: LIST OF Node ¬ node.children, tail.rest UNTIL tail = NIL DO origin: VEC ~ tail.first.layout.origin; treeBox.xmin ¬ MIN[treeBox.xmin, tail.first.layout.treeBox.xmin + origin.x]; treeBox.xmax ¬ MAX[treeBox.xmax, tail.first.layout.treeBox.xmax + origin.x]; treeBox.ymin ¬ MIN[treeBox.ymin, tail.first.layout.treeBox.ymin + origin.y]; treeBox.ymax ¬ MAX[treeBox.ymax, tail.first.layout.treeBox.ymax + origin.y]; ENDLOOP; node.layout ¬ NEW[LayoutRep ¬ [origin: [0.0, 0.0], bounds: bounds, treeBox: treeBox]]; }; }; Pass2: PROC [node: Node] = { FOR tail: LIST OF Node ¬ node.children, tail.rest UNTIL tail = NIL DO tail.first.layout.origin.x ¬ tail.first.layout.origin.x + node.layout.origin.x; tail.first.layout.origin.y ¬ tail.first.layout.origin.y + node.layout.origin.y; Pass2[tail.first]; ENDLOOP; node.layout.origin ¬ ImagerTransformation.TransformVec[reverse, node.layout.origin]; node.layout.treeBox ¬ XFormBox[reverse, node.layout.treeBox]; }; Pass3Each: PROC [node: Node] = { o: VEC ~ node.layout.origin; b: Box ~ node.layout.treeBox; node.layout.treeBox ¬ [xmin: b.xmin+o.x, ymin: b.ymin+o.y, xmax: b.xmax+o.x, ymax: b.ymax+o.y]; }; PostOrder[root, Pass1Each]; Pass2[root]; PostOrder[root, Pass3Each]; }; Resolve: PUBLIC PROC [root: Node, p: VEC] RETURNS [Node] = { b: Box ~ root.layout.bounds; IF ( (p.x-root.layout.origin.x) IN [b.xmin..b.xmax] AND (p.y-root.layout.origin.y) IN [b.ymin..b.ymax]) THEN RETURN [root]; FOR tail: LIST OF Node ¬ root.children, tail.rest UNTIL tail = NIL DO IF ( p.x IN [tail.first.layout.treeBox.xmin..tail.first.layout.treeBox.xmax] AND p.y IN [tail.first.layout.treeBox.ymin..tail.first.layout.treeBox.ymax] ) THEN { n: Node ¬ Resolve[tail.first, p]; IF n # NIL THEN RETURN [n]; }; ENDLOOP; RETURN [NIL] }; DefaultAttachmentPoint: PUBLIC PROC [self: Node, direction: Direction] RETURNS [VEC] ~ { b: Box ~ self.layout.bounds; SELECT direction FROM $E => RETURN [[b.xmax, 0.5*(b.ymax+b.ymin)]]; $W => RETURN [[b.xmin, 0.5*(b.ymax+b.ymin)]]; $N => RETURN [[0.5*(b.xmax+b.xmin), b.ymax]]; $S => RETURN [[0.5*(b.xmax+b.xmin), b.ymin]]; ENDCASE => ERROR; }; END. ˆ TreeGrapherImpl.mesa Copyright Σ 1990, 1991 by Xerox Corporation. All rights reserved. Michael Plass, July 13, 1990 5:10 pm PDT Κ•NewlineDelimiter –(cedarcode) style™šœ™Jšœ Οeœ7™BJ™(—Icode˜šΟk ˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœžœžœ˜K˜—KšΟnœžœž˜Kšžœ ˜'Kšžœ ˜šœžœžœ ˜K˜Kšœžœ˜Kšžœžœ žœ˜šœžœ'˜;K˜—šŸ œžœžœ ˜3š žœžœžœ!žœžœž˜EKšœ˜Kšžœ˜—Kšœ ˜ Kšœ˜K˜—šŸœžœžœ˜Bšžœ˜%Kš œžœžœ0žœžœ˜iKš œžœžœ0žœžœ ˜n—Kšœ˜—šŸœžœžœ ˜>Kšžœk˜qKšœ˜K˜—šŸœžœžœ'˜