/// <summary> /// Applies layout changes to a given box and its children. /// </summary> public override void ApplyHorizontalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level) { var node = level.BranchRoot; if (node.AssistantsRoot != null) { LayoutAlgorithm.HorizontalLayout(state, node.AssistantsRoot); } for (var i = 0; i < node.State.NumberOfSiblings; i++) { var child = node.Children[i]; // re-enter layout algorithm for child branch LayoutAlgorithm.HorizontalLayout(state, child); } if (node.Level > 0 && node.ChildCount > 0) { var rect = node.State; var leftmost = node.Children[0].State.CenterH; var rightmost = node.Children[node.State.NumberOfSiblings - 1].State.CenterH; var desiredCenter = node.State.NumberOfSiblings == 1 || ParentAlignment == BranchParentAlignment.Center ? leftmost + (rightmost - leftmost) / 2 : ParentAlignment == BranchParentAlignment.Left ? leftmost + ChildConnectorHookLength : rightmost - ChildConnectorHookLength; var center = rect.CenterH; var diff = center - desiredCenter; LayoutAlgorithm.MoveChildrenOnly(state, level, diff); // vertical connector from parent var verticalSpacer = node.Children[node.State.NumberOfSiblings]; verticalSpacer.State.AdjustSpacer( center - ParentConnectorShield / 2, rect.Bottom, ParentConnectorShield, node.Children[0].State.SiblingsRowV.From - rect.Bottom); state.MergeSpacer(verticalSpacer); // horizontal protector var firstInRow = node.Children[0].State; var horizontalSpacer = node.Children[node.State.NumberOfSiblings + 1]; horizontalSpacer.State.AdjustSpacer( firstInRow.Left, firstInRow.SiblingsRowV.From - ParentChildSpacing, node.Children[node.State.NumberOfSiblings - 1].State.Right - firstInRow.Left, ParentChildSpacing); state.MergeSpacer(horizontalSpacer); } }
/// <summary> /// Applies layout changes to a given box and its children. /// </summary> public override void ApplyHorizontalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level) { var node = level.BranchRoot; var nodeState = node.State; if (node.AssistantsRoot != null) { LayoutAlgorithm.HorizontalLayout(state, node.AssistantsRoot); } // first, perform horizontal layout for every node in this column for (var row = 0; row < nodeState.NumberOfSiblings; row++) { var child = node.Children[row]; // re-enter layout algorithm for child branch // siblings are guaranteed not to offend each other LayoutAlgorithm.HorizontalLayout(state, child); } // now align the column var edges = LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateColumn(node)); if (node.Level > 0 && node.ChildCount > 0) { var rect = node.State; double diff; if (ParentAlignment == BranchParentAlignment.Left) { var desiredLeft = rect.CenterH + ParentConnectorShield / 2; diff = desiredLeft - edges.From; } else if (ParentAlignment == BranchParentAlignment.Right) { var desiredRight = rect.CenterH - ParentConnectorShield / 2; diff = desiredRight - edges.To; } else { throw new InvalidOperationException("Invalid ParentAlignment setting"); } // vertical connector from parent LayoutAlgorithm.MoveChildrenOnly(state, level, diff); // spacer for the vertical carrier var verticalSpacer = node.Level > 0 ? node.Children[node.ChildCount - 1] : null; if (verticalSpacer != null) { var spacerTop = node.State.Bottom; var spacerBottom = node.Children[node.ChildCount - 2].State.Bottom; verticalSpacer.State.AdjustSpacer( rect.CenterH - ParentConnectorShield / 2, spacerTop, ParentConnectorShield, spacerBottom - spacerTop); state.MergeSpacer(verticalSpacer); } } }
/// <summary> /// Applies layout changes to a given box and its children. /// </summary> public override void ApplyHorizontalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level) { var node = level.BranchRoot; if (node.State.NumberOfSiblings <= MaxSiblingsPerRow) { // fall back to linear layout, only have one row of boxes base.ApplyHorizontalLayout(state, level); return; } if (node.AssistantsRoot != null) { LayoutAlgorithm.HorizontalLayout(state, node.AssistantsRoot); } for (var col = 0; col < node.State.NumberOfSiblingColumns; col++) { // first, perform horizontal layout for every node in this column for (var row = 0; row < node.State.NumberOfSiblingRows; row++) { var ix = row * node.State.NumberOfSiblingColumns + col; if (ix >= node.State.NumberOfSiblings) { break; } var child = node.Children[ix]; // re-enter layout algorithm for child branch LayoutAlgorithm.HorizontalLayout(state, child); } LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateColumn(node, col)); } // now align children under parent var rect = node.State; var spacer = node.Children[node.State.NumberOfSiblingColumns / 2]; var desiredCenter = spacer.State.CenterH; var diff = rect.CenterH - desiredCenter; LayoutAlgorithm.MoveChildrenOnly(state, level, diff); // vertical connector from parent var verticalSpacer = node.Children[node.State.NumberOfSiblings]; verticalSpacer.State.AdjustSpacer( rect.CenterH - ParentConnectorShield / 2, rect.Bottom, ParentConnectorShield, node.Children[0].State.SiblingsRowV.From - rect.Bottom); state.MergeSpacer(verticalSpacer); // horizontal row carrier protectors var spacing = ParentChildSpacing; for (var firstInRowIndex = 0; firstInRowIndex < node.State.NumberOfSiblings; firstInRowIndex += node.State.NumberOfSiblingColumns) { var firstInRow = node.Children[firstInRowIndex].State; var lastInRow = node.Children[Math.Min(firstInRowIndex + node.State.NumberOfSiblingColumns - 1, node.State.NumberOfSiblings - 1)].State; var horizontalSpacer = node.Children[1 + node.State.NumberOfSiblings + firstInRowIndex / node.State.NumberOfSiblingColumns]; var width = lastInRow.Right >= verticalSpacer.State.Right ? lastInRow.Right - firstInRow.Left : // extend protector at least to the central carrier verticalSpacer.State.Right - firstInRow.Left; horizontalSpacer.State.AdjustSpacer( firstInRow.Left, firstInRow.SiblingsRowV.From - spacing, width, spacing); state.MergeSpacer(horizontalSpacer); spacing = SiblingSpacing; } }
/// <summary> /// Applies layout changes to a given box and its children. /// </summary> public override void ApplyHorizontalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level) { var node = level.BranchRoot; if (node.State.NumberOfSiblings <= MaxGroups * 2) { base.ApplyHorizontalLayout(state, level); return; } if (node.Level == 0) { node.State.SiblingsRowV = new Dimensions(node.State.Top, node.State.Bottom); } if (node.AssistantsRoot != null) { LayoutAlgorithm.HorizontalLayout(state, node.AssistantsRoot); } var adapter = new SingleFishboneLayoutAdapter(node); while (adapter.NextGroup()) { LayoutAlgorithm.HorizontalLayout(state, adapter.SpecialRoot); } var rect = node.State; // now align child nodes under the parent if (node.Level > 0) { double diff; if (node.State.NumberOfSiblingColumns > 1) { var leftCarrier = node.Children[node.State.NumberOfSiblings + 1].State.CenterH; var rightCarrier = node.Children[node.State.NumberOfSiblings + node.State.NumberOfSiblingColumns].State.CenterH; var desiredCenter = node.State.NumberOfSiblings == 1 || ParentAlignment == BranchParentAlignment.Center ? leftCarrier + (rightCarrier - leftCarrier) / 2 : ParentAlignment == BranchParentAlignment.Left ? leftCarrier + ChildConnectorHookLength : rightCarrier - ChildConnectorHookLength; //var desiredCenter = (leftCarrier + rightCarrier)/2.0; diff = rect.CenterH - desiredCenter; } else { var carrier = node.Children[1 + node.State.NumberOfSiblings].State.CenterH; var desiredCenter = rect.CenterH; diff = desiredCenter - carrier; } LayoutAlgorithm.MoveChildrenOnly(state, level, diff); } if (node.Level > 0) { // vertical connector from parent var ix = node.State.NumberOfSiblings; var verticalSpacer = node.Children[ix]; verticalSpacer.State.AdjustSpacer( rect.CenterH - ParentConnectorShield / 2, rect.Bottom, ParentConnectorShield, node.Children[0].State.SiblingsRowV.From - rect.Bottom); state.MergeSpacer(verticalSpacer); ix++; // vertical carriers already merged in ix += node.State.NumberOfSiblingColumns; if (node.State.NumberOfSiblingColumns > 1) { // have a horizontal carrier var horizontalSpacer = node.Children[ix]; var leftmost = node.Children[node.State.NumberOfSiblings + 1].State.TopLeft; var rightmost = node.Children[ix - 1].State.Right; horizontalSpacer.State.AdjustSpacer( leftmost.X, leftmost.Y - ParentChildSpacing, rightmost - leftmost.X, ParentChildSpacing); state.MergeSpacer(horizontalSpacer); } } }