TreeGrapherImpl.mesa
Copyright Ó 1990, 1991 by Xerox Corporation. All rights reserved.
Michael Plass, July 13, 1990 5:10 pm PDT
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.