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;
};