コード例 #1
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level)
        {
            var node = level.BranchRoot;

            if (node.State.NumberOfSiblings <= MaxGroups * 2)
            {
                base.ApplyVerticalLayout(state, level);
                return;
            }

            if (node.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(node.State.Top, node.State.Bottom);
            }

            if (node.AssistantsRoot != null)
            {
                // assistants root has to be initialized with main node's exterior
                node.AssistantsRoot.State.CopyExteriorFrom(node.State);
                LayoutAlgorithm.VerticalLayout(state, node.AssistantsRoot);
            }

            var adapter = new SingleFishboneLayoutAdapter(node);

            while (adapter.NextGroup())
            {
                LayoutAlgorithm.VerticalLayout(state, adapter.SpecialRoot);
            }
        }
コード例 #2
0
        /// <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);
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Pops a box from current layout stack, thus getting higher out from layout hierarchy.
        /// Automatically merges popped <see cref="Boundary"/> into the current level.
        /// </summary>
        public void PopLayoutLevel()
        {
            var innerLevel = m_layoutStack.Pop();

            BoundaryChanged?.Invoke(this, new BoundaryChangedEventArgs(innerLevel.Boundary, innerLevel, this));

            // if this was not the root, merge boundaries into current level
            if (m_layoutStack.Count > 0)
            {
                var higherLevel = m_layoutStack.Peek();

                switch (CurrentOperation)
                {
                case Operation.VerticalLayout:
                    higherLevel.Boundary.VerticalMergeFrom(innerLevel.Boundary);
                    higherLevel.BranchRoot.State.BranchExterior = higherLevel.Boundary.BoundingRect;
                    break;

                case Operation.HorizontalLayout:
                {
                    // do not apply overlap adjustment for assistant branch, they are always above regular children
                    if (higherLevel.BranchRoot.AssistantsRoot != innerLevel.BranchRoot)
                    {
                        var strategy = higherLevel.BranchRoot.State.RequireLayoutStrategy();

                        var overlap = higherLevel.Boundary.ComputeOverlap(
                            innerLevel.Boundary, strategy.SiblingSpacing, Diagram.LayoutSettings.BranchSpacing);

                        if (overlap > 0)
                        {
                            LayoutAlgorithm.MoveBranch(this, innerLevel, overlap);
                            BoundaryChanged?.Invoke(this, new BoundaryChangedEventArgs(innerLevel.Boundary, innerLevel, this));
                        }
                    }
                    higherLevel.Boundary.MergeFrom(innerLevel.Boundary);

                    // Do not update branch vertical measurements from the boundary, because boundary adds children one-by-one.
                    // If we take it from boundary, then branch vertical measurement will be incorrect until all children are laid out horizontally,
                    // and this temporarily incorrect state will break those algorithms that need to know combined branch height.
                    higherLevel.BranchRoot.State.BranchExterior = new Rect(
                        higherLevel.Boundary.BoundingRect.Left,
                        higherLevel.BranchRoot.State.BranchExterior.Top,
                        higherLevel.Boundary.BoundingRect.Size.Width,
                        higherLevel.BranchRoot.State.BranchExterior.Size.Height);
                }
                break;

                default:
                    throw new InvalidOperationException(
                              "This operation can only be invoked when performing vertical or horizontal layouts");
                }

                BoundaryChanged?.Invoke(this, new BoundaryChangedEventArgs(higherLevel.Boundary, higherLevel, this));
            }

            // return boundary to the pool
            m_pooledBoundaries.Push(innerLevel.Boundary);
        }
コード例 #4
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level)
        {
            var node = level.BranchRoot;

            if (node.Level == 0)
            {
                throw new InvalidOperationException("Should never be invoked on root node");
            }

            var prevRowBottom = node.State.SiblingsRowV.To;

            var maxOnLeft = MaxOnLeft(node);

            for (var i = 0; i < maxOnLeft; i++)
            {
                var spacing = i == 0 ? ParentChildSpacing : SiblingSpacing;

                var child = node.Children[i];
                var frame = child.State;
                frame.MoveTo(frame.Left, prevRowBottom + spacing);

                var rowExterior = new Dimensions(frame.Top, frame.Bottom);

                var i2 = i + maxOnLeft;
                if (i2 < node.State.NumberOfSiblings)
                {
                    var child2 = node.Children[i2];
                    var frame2 = child2.State;
                    frame2.MoveTo(frame2.Left, prevRowBottom + spacing);

                    if (frame2.Bottom > frame.Bottom)
                    {
                        frame.MoveTo(frame.Left, frame2.CenterV - frame.Size.Height / 2);
                    }
                    else if (frame2.Bottom < frame.Bottom)
                    {
                        frame2.MoveTo(frame2.Left, frame.CenterV - frame2.Size.Height / 2);
                    }

                    frame2.BranchExterior = new Rect(frame2.TopLeft, frame2.Size);
                    rowExterior          += new Dimensions(frame2.Top, frame2.Bottom);

                    frame2.SiblingsRowV = rowExterior;
                    LayoutAlgorithm.VerticalLayout(state, child2);
                    prevRowBottom = frame2.BranchExterior.Bottom;
                }

                frame.BranchExterior = new Rect(frame.TopLeft, frame.Size);
                frame.SiblingsRowV   = rowExterior;
                LayoutAlgorithm.VerticalLayout(state, child);
                prevRowBottom = Math.Max(prevRowBottom, frame.BranchExterior.Bottom);
            }
        }
コード例 #5
0
        /// <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);
            }
        }
コード例 #6
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level)
        {
            var node = level.BranchRoot;

            if (node.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(
                    node.State.Top,
                    node.State.Bottom);
            }

            if (node.AssistantsRoot != null)
            {
                // assistants root has to be initialized with main node's exterior
                node.AssistantsRoot.State.CopyExteriorFrom(node.State);
                LayoutAlgorithm.VerticalLayout(state, node.AssistantsRoot);
            }

            if (node.State.NumberOfSiblings == 0)
            {
                return;
            }

            var siblingsRowExterior = Dimensions.MinMax();

            var top = node.AssistantsRoot == null
                ? node.State.SiblingsRowV.To + ParentChildSpacing
                : node.State.BranchExterior.Bottom + ParentChildSpacing;

            for (var i = 0; i < node.State.NumberOfSiblings; i++)
            {
                var child = node.Children[i];
                var rect  = child.State;

                child.State.MoveTo(0, top);
                child.State.BranchExterior = new Rect(child.State.TopLeft, child.State.Size);

                siblingsRowExterior += new Dimensions(top, top + rect.Size.Height);
            }

            siblingsRowExterior = new Dimensions(siblingsRowExterior.From, siblingsRowExterior.To);

            for (var i = 0; i < node.State.NumberOfSiblings; i++)
            {
                var child = node.Children[i];
                child.State.SiblingsRowV = siblingsRowExterior;

                // re-enter layout algorithm for child branch
                LayoutAlgorithm.VerticalLayout(state, child);
            }
        }
コード例 #7
0
            public override void ApplyHorizontalLayout(LayoutState state, [NotNull] LayoutState.LayoutLevel level)
            {
                if (level.BranchRoot != SpecialRoot)
                {
                    throw new InvalidOperationException("Wrong root node received");
                }

                var left            = true;
                var countOnThisSide = 0;

                for (var i = 0; i < Iterator.Count; i++)
                {
                    var child = SpecialRoot.Children[i];
                    LayoutAlgorithm.HorizontalLayout(state, child);

                    // we go top-bottom to layout left side of the group,
                    // then add a carrier protector
                    // then top-bottom to fill right side of the group
                    if (++countOnThisSide == Iterator.MaxOnLeft)
                    {
                        if (left)
                        {
                            // horizontally align children in left pillar
                            LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateSiblings(0, Iterator.MaxOnLeft));

                            left            = false;
                            countOnThisSide = 0;

                            var rightmost = double.MinValue;
                            for (var k = 0; k < i; k++)
                            {
                                rightmost = Math.Max(rightmost, SpecialRoot.Children[k].State.BranchExterior.Right);
                            }

                            rightmost = Math.Max(rightmost, child.State.Right);

                            // integrate protector for group's vertical carrier
                            var spacer = SpecialRoot.Children[SpecialRoot.State.NumberOfSiblings];

                            spacer.State.AdjustSpacer(
                                rightmost, SpecialRoot.Children[0].State.SiblingsRowV.From,
                                SiblingSpacing, child.State.SiblingsRowV.To - SpecialRoot.Children[0].State.SiblingsRowV.From);
                            level.Boundary.MergeFrom(spacer);
                        }
                    }
                }
                // horizontally align children in right pillar
                LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateSiblings(Iterator.MaxOnLeft, Iterator.Count));
            }
コード例 #8
0
            public override void ApplyVerticalLayout(LayoutState state, [NotNull] LayoutState.LayoutLevel level)
            {
                var prevRowBottom =
                    RealRoot.AssistantsRoot?.State.BranchExterior.Bottom
                    ?? SpecialRoot.State.SiblingsRowV.To;

                for (var i = 0; i < Iterator.MaxOnLeft; i++)
                {
                    var spacing = i == 0 ? ParentChildSpacing : SiblingSpacing;

                    var child = SpecialRoot.Children[i];
                    var frame = child.State;
                    frame.MoveTo(frame.Left, prevRowBottom + spacing);

                    var rowExterior = new Dimensions(frame.Top, frame.Bottom);

                    var i2 = i + Iterator.MaxOnLeft;
                    if (i2 < Iterator.Count)
                    {
                        var child2 = SpecialRoot.Children[i2];
                        var frame2 = child2.State;
                        frame2.MoveTo(frame2.Left, prevRowBottom + spacing);

                        if (frame2.Bottom > frame.Bottom)
                        {
                            frame.MoveTo(frame.Left, frame2.CenterV - frame.Size.Height / 2);
                        }
                        else if (frame2.Bottom < frame.Bottom)
                        {
                            frame2.MoveTo(frame2.Left, frame.CenterV - frame2.Size.Height / 2);
                        }

                        frame2.BranchExterior = new Rect(frame2.TopLeft, frame2.Size);
                        rowExterior          += new Dimensions(frame2.Top, frame2.Bottom);

                        frame2.SiblingsRowV = rowExterior;
                        LayoutAlgorithm.VerticalLayout(state, child2);
                        prevRowBottom = frame2.BranchExterior.Bottom;
                    }

                    frame.BranchExterior = new Rect(frame.TopLeft, frame.Size);
                    frame.SiblingsRowV   = rowExterior;
                    LayoutAlgorithm.VerticalLayout(state, child);
                    prevRowBottom = Math.Max(prevRowBottom, frame.BranchExterior.Bottom);
                }
            }
コード例 #9
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level)
        {
            var node = level.BranchRoot;

            if (node.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(node.State.Top, node.State.Bottom);
            }

            if (node.AssistantsRoot != null)
            {
                // assistants root has to be initialized with main node's exterior
                node.AssistantsRoot.State.CopyExteriorFrom(node.State);
                LayoutAlgorithm.VerticalLayout(state, node.AssistantsRoot);
            }

            var prevRowExterior = new Dimensions(
                node.State.SiblingsRowV.From,
                node.AssistantsRoot == null
                ? node.State.SiblingsRowV.To
                : node.State.BranchExterior.Bottom);

            for (var row = 0; row < node.State.NumberOfSiblings; row++)
            {
                // first, compute
                var child = node.Children[row];
                var rect  = child.State;

                var top = prevRowExterior.To + (row == 0 ? ParentChildSpacing : SiblingSpacing);
                child.State.MoveTo(rect.Left, top);
                child.State.BranchExterior = new Rect(child.State.TopLeft, child.State.Size);

                var rowExterior = new Dimensions(top, top + rect.Size.Height);

                child = node.Children[row];
                child.State.SiblingsRowV = rowExterior;

                // re-enter layout algorithm for child branch
                LayoutAlgorithm.VerticalLayout(state, child);

                var childBranchBottom = child.State.BranchExterior.Bottom;

                prevRowExterior = new Dimensions(rowExterior.From, Math.Max(childBranchBottom, rowExterior.To));
            }
        }
コード例 #10
0
        /// <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;

            foreach (var child in node.Children)
            {
                // re-enter layout algorithm for child branch
                LayoutAlgorithm.HorizontalLayout(state, child);
            }

            if (node.ChildCount > 0)
            {
                if (Orientation == StackOrientation.SingleRowHorizontal)
                {
                    // now auto-extend or contract the parent box
                    var width = node.Children[node.State.NumberOfSiblings - 1].State.Right - node.Children[0].State.Left;
                    node.State.Size = new Size(Math.Max(node.State.Size.Width, width), node.State.Size.Height);

                    // now position children under the parent
                    var center        = (node.Children[0].State.Left + node.Children[node.ChildCount - 1].State.Right) / 2;
                    var desiredCenter = node.State.CenterH;
                    var diff          = desiredCenter - center;
                    LayoutAlgorithm.MoveChildrenOnly(state, level, diff);
                }
                else if (Orientation == StackOrientation.SingleColumnVertical)
                {
                    LayoutAlgorithm.AlignHorizontalCenters(state, level, node.Children);

                    // now position children under the parent
                    var center        = node.Children[0].State.CenterH;
                    var desiredCenter = node.State.CenterH;
                    var diff          = desiredCenter - center;
                    LayoutAlgorithm.MoveChildrenOnly(state, level, diff);
                }
            }
        }
コード例 #11
0
        /// <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.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(node.State.Top, node.State.Bottom);
            }

            var left            = true;
            var countOnThisSide = 0;
            var maxOnLeft       = MaxOnLeft(node);

            for (var i = 0; i < node.State.NumberOfSiblings; i++)
            {
                var child = node.Children[i];
                LayoutAlgorithm.HorizontalLayout(state, child);

                // we go top-bottom to layout left side of the group,
                // then add a carrier protector
                // then top-bottom to fill right side of the group
                if (++countOnThisSide == maxOnLeft)
                {
                    if (left)
                    {
                        // horizontally align children in left pillar
                        LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateSiblings(node, 0, maxOnLeft));

                        left            = false;
                        countOnThisSide = 0;

                        var rightmost = double.MinValue;
                        for (var k = 0; k <= i; k++)
                        {
                            rightmost = Math.Max(rightmost, node.Children[k].State.BranchExterior.Right);
                        }

                        // vertical spacer does not have to be extended to the bottom of the lowest branch,
                        // unless the lowest branch on the right side has some children and is expanded
                        if (node.State.NumberOfSiblings % 2 != 0)
                        {
                            rightmost = Math.Max(rightmost, child.State.Right);
                        }
                        else
                        {
                            var opposite = node.Children[node.State.NumberOfSiblings - 1];
                            if (opposite.Element.IsCollapsed || opposite.ChildCount == 0)
                            {
                                rightmost = Math.Max(rightmost, child.State.Right);
                            }
                            else
                            {
                                rightmost = Math.Max(rightmost, child.State.BranchExterior.Right);
                            }
                        }

                        // integrate protector for group's vertical carrier
                        // it must prevent boxes on the right side from overlapping the middle vertical connector,
                        // so protector's height must be set to height of this entire assistant branch
                        var spacer = node.Children[node.State.NumberOfSiblings];
                        spacer.State.AdjustSpacer(
                            rightmost,
                            node.State.Bottom,
                            ParentConnectorShield,
                            node.State.BranchExterior.Bottom - node.State.Bottom
                            );
                        level.Boundary.MergeFrom(spacer);
                    }
                }
            }

            // horizontally align children in right pillar
            LayoutAlgorithm.AlignHorizontalCenters(state, level, EnumerateSiblings(node, maxOnLeft, node.State.NumberOfSiblings));

            // align children under parent
            if (node.Level > 0 && node.State.NumberOfSiblings > 0)
            {
                double diff;
                var    carrier       = node.Children[node.State.NumberOfSiblings].State.CenterH;
                var    desiredCenter = node.State.CenterH;
                diff = desiredCenter - carrier;
                LayoutAlgorithm.MoveChildrenOnly(state, level, diff);
            }
        }
コード例 #12
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([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.ApplyVerticalLayout(state, level);
                return;
            }

            if (node.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(node.State.Top, node.State.Bottom);
            }

            if (node.AssistantsRoot != null)
            {
                // assistants root has to be initialized with main node's exterior
                node.AssistantsRoot.State.CopyExteriorFrom(node.State);
                LayoutAlgorithm.VerticalLayout(state, node.AssistantsRoot);
            }

            var prevRowExterior = new Dimensions(
                node.State.SiblingsRowV.From,
                node.AssistantsRoot == null
                ? node.State.SiblingsRowV.To
                : node.State.BranchExterior.Bottom);

            for (var row = 0; row < node.State.NumberOfSiblingRows; row++)
            {
                var siblingsRowExterior = Dimensions.MinMax();

                var spacing = row == 0 ? ParentChildSpacing : SiblingSpacing;

                // first, compute
                var from = row * node.State.NumberOfSiblingColumns;
                var to   = Math.Min(from + node.State.NumberOfSiblingColumns, node.State.NumberOfSiblings);
                for (var i = from; i < to; i++)
                {
                    var child = node.Children[i];
                    if (child.Element.IsSpecial)
                    {
                        // skip vertical spacers for now
                        continue;
                    }

                    var rect = child.State;

                    var top = prevRowExterior.To + spacing;
                    child.State.MoveTo(rect.Left, top);
                    child.State.BranchExterior = new Rect(child.State.TopLeft, child.State.Size);

                    siblingsRowExterior += new Dimensions(top, top + rect.Size.Height);
                }

                siblingsRowExterior = new Dimensions(siblingsRowExterior.From, siblingsRowExterior.To);

                var siblingsBottom = double.MinValue;
                for (var i = from; i < to; i++)
                {
                    var child = node.Children[i];
                    child.State.SiblingsRowV = siblingsRowExterior;

                    // re-enter layout algorithm for child branch
                    LayoutAlgorithm.VerticalLayout(state, child);

                    siblingsBottom = Math.Max(siblingsBottom, child.State.BranchExterior.Bottom);
                }

                prevRowExterior = new Dimensions(siblingsRowExterior.From, Math.Max(siblingsBottom, siblingsRowExterior.To));

                // now assign size to the vertical spacer, if any
                var spacerIndex = from + node.State.NumberOfSiblingColumns / 2;
                if (spacerIndex < node.State.NumberOfSiblings)
                {
                    // in the last row, spacer should only extend to the siblings row bottom,
                    // because main vertical carrier does not go below last row
                    // and thus cannot conflict with branches of children of the last row
                    var spacerBottom = row == node.State.NumberOfSiblingRows - 1
                        ? node.Children[spacerIndex - 1].State.SiblingsRowV.To
                        : prevRowExterior.To;

                    var spacer = node.Children[spacerIndex].State;
                    spacer.AdjustSpacer(
                        0, prevRowExterior.From,
                        ParentConnectorShield, spacerBottom - prevRowExterior.From);
                }
            }
        }
コード例 #13
0
        /// <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;
            }
        }
コード例 #14
0
        /// <summary>
        /// Applies layout changes to a given box and its children.
        /// </summary>
        public override void ApplyVerticalLayout([NotNull] LayoutState state, [NotNull] LayoutState.LayoutLevel level)
        {
            var node = level.BranchRoot;

            if (node.Level == 0)
            {
                node.State.SiblingsRowV = new Dimensions(
                    node.State.Top,
                    node.State.Bottom);
            }

            if (node.State.NumberOfSiblings == 0)
            {
                return;
            }

            var siblingsRowExterior = Dimensions.MinMax();

            if (Orientation == StackOrientation.SingleRowHorizontal)
            {
                var top = node.AssistantsRoot == null
                    ? node.State.SiblingsRowV.To + ParentChildSpacing
                    : node.State.BranchExterior.Bottom + ParentChildSpacing;

                for (var i = 0; i < node.State.NumberOfSiblings; i++)
                {
                    var child = node.Children[i];
                    var rect  = child.State;

                    child.State.MoveTo(0, top);
                    child.State.BranchExterior = new Rect(child.State.TopLeft, child.State.Size);

                    siblingsRowExterior += new Dimensions(top, top + rect.Size.Height);
                }

                siblingsRowExterior = new Dimensions(siblingsRowExterior.From, siblingsRowExterior.To);

                for (var i = 0; i < node.State.NumberOfSiblings; i++)
                {
                    var child = node.Children[i];
                    child.State.SiblingsRowV = siblingsRowExterior;

                    // re-enter layout algorithm for child branch
                    LayoutAlgorithm.VerticalLayout(state, child);
                }
            }
            else if (Orientation == StackOrientation.SingleColumnVertical)
            {
                var prevRowExterior = new Dimensions(
                    node.State.SiblingsRowV.From,
                    node.State.SiblingsRowV.To);

                for (var row = 0; row < node.State.NumberOfSiblings; row++)
                {
                    // first, compute
                    var child = node.Children[row];
                    var rect  = child.State;

                    var top = prevRowExterior.To + (row == 0 ? ParentChildSpacing : SiblingSpacing);
                    child.State.MoveTo(rect.Left, top);
                    child.State.BranchExterior = new Rect(child.State.TopLeft, child.State.Size);

                    var rowExterior = new Dimensions(top, top + rect.Size.Height);

                    child = node.Children[row];
                    child.State.SiblingsRowV = rowExterior;

                    // re-enter layout algorithm for child branch
                    LayoutAlgorithm.VerticalLayout(state, child);

                    var childBranchBottom = child.State.BranchExterior.Bottom;

                    prevRowExterior = new Dimensions(rowExterior.From, Math.Max(childBranchBottom, rowExterior.To));
                }
            }
        }
コード例 #15
0
        /// <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);
                }
            }
        }