Example #1
0
        /// <summary>
        /// Push a new box onto the layout stack, thus getting deeper into layout hierarchy.
        /// Automatically allocates a Bondary object from pool.
        /// </summary>
        public LayoutLevel PushLayoutLevel([NotNull] BoxTree.Node node)
        {
            if (m_pooledBoundaries.Count == 0)
            {
                m_pooledBoundaries.Push(new Boundary());
            }

            var boundary = m_pooledBoundaries.Pop();

            switch (CurrentOperation)
            {
            case Operation.VerticalLayout:
                boundary.Prepare(node);
                break;

            case Operation.HorizontalLayout:
                boundary.PrepareForHorizontalLayout(node);
                break;

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

            var result = new LayoutLevel(node, boundary);

            m_layoutStack.Push(result);

            BoundaryChanged?.Invoke(this, new BoundaryChangedEventArgs(boundary, result, this));

            return(result);
        }
Example #2
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);
        }
Example #3
0
        /// <summary>
        /// Merges a provided spacer box into the current branch boundary.
        /// </summary>
        public void MergeSpacer([NotNull] BoxTree.Node spacer)
        {
            if (CurrentOperation != Operation.HorizontalLayout)
            {
                throw new InvalidOperationException("Spacers can only be merged during horizontal layout");
            }

            if (m_layoutStack.Count == 0)
            {
                throw new InvalidOperationException("Cannot merge spacers at top nesting level");
            }

            var level = m_layoutStack.Peek();

            level.Boundary.MergeFrom(spacer);

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