Example #1
0
    private void ArrangeNodeVertically(RPNode node, Size finalSize)
    {
        if (node == null)
        {
            return;
        }

        if (!node.IsArrangedVertically())
        {
            // We must resolve dependencies first.
            ArrangeNodeVertically(node.m_leftOfNode, finalSize);
            ArrangeNodeVertically(node.m_aboveNode, finalSize);
            ArrangeNodeVertically(node.m_rightOfNode, finalSize);
            ArrangeNodeVertically(node.m_belowNode, finalSize);
            ArrangeNodeVertically(node.m_alignLeftWithNode, finalSize);
            ArrangeNodeVertically(node.m_alignTopWithNode, finalSize);
            ArrangeNodeVertically(node.m_alignRightWithNode, finalSize);
            ArrangeNodeVertically(node.m_alignBottomWithNode, finalSize);
            ArrangeNodeVertically(node.m_alignHorizontalCenterWithNode, finalSize);
            ArrangeNodeVertically(node.m_alignVerticalCenterWithNode, finalSize);

            double nodeMeasureRectY, nodeMeasureRectHeight;
            CalculateMeasureRectVertically(node, finalSize, out nodeMeasureRectY, out nodeMeasureRectHeight);
            node.m_measureRect.Y      = nodeMeasureRectY;
            node.m_measureRect.Height = nodeMeasureRectHeight;
            double nodeArrangeRectY, nodeArrangeRectHeight;
            CalculateArrangeRectVertically(node, out nodeArrangeRectY, out nodeArrangeRectHeight);
            node.m_arrangeRect.Y      = nodeArrangeRectY;
            node.m_arrangeRect.Height = nodeArrangeRectHeight;
            node.SetArrangedVertically(true);
        }
    }
Example #2
0
 internal void SetAlignBottomWithConstraint(RPNode neighbor)
 {
     if (neighbor != null)
     {
         m_alignBottomWithNode = neighbor;
         m_constraints        |= RPConstraints.AlignBottomWith;
     }
     else
     {
         m_alignBottomWithNode = null;
         m_constraints        &= ~RPConstraints.AlignBottomWith;
     }
 }
Example #3
0
 internal void SetBelowConstraint(RPNode neighbor)
 {
     if (neighbor != null)
     {
         m_belowNode    = neighbor;
         m_constraints |= RPConstraints.Below;
     }
     else
     {
         m_belowNode    = null;
         m_constraints &= ~RPConstraints.Below;
     }
 }
Example #4
0
 internal void SetRightOfConstraint(RPNode neighbor)
 {
     if (neighbor != null)
     {
         m_rightOfNode  = neighbor;
         m_constraints |= RPConstraints.RightOf;
     }
     else
     {
         m_rightOfNode  = null;
         m_constraints &= ~RPConstraints.RightOf;
     }
 }
Example #5
0
 internal void SetAboveConstraint(RPNode neighbor)
 {
     if (neighbor != null)
     {
         m_aboveNode    = neighbor;
         m_constraints |= RPConstraints.Above;
     }
     else
     {
         m_aboveNode    = null;
         m_constraints &= ~RPConstraints.Above;
     }
 }
Example #6
0
    void CalculateArrangeRectVertically(RPNode node, out double y, out double height)
    {
        Rect   measureRect   = node.m_measureRect;
        double desiredHeight = Math.Min(measureRect.Height, node.GetDesiredHeight());

        MUX_ASSERT(node.IsMeasured() && (measureRect.Height != double.PositiveInfinity));

        // The initial values correspond to the top corner, using the
        // desired size of element. If no attached properties were set,
        // this means that the element will default to the top corner of
        // the panel.
        y      = measureRect.Y;
        height = desiredHeight;

        if (node.IsTopAnchored())
        {
            if (node.IsBottomAnchored())
            {
                y      = measureRect.Y;
                height = measureRect.Height;
            }
            else
            {
                y      = measureRect.Y;
                height = desiredHeight;
            }
        }
        else if (node.IsBottomAnchored())
        {
            y      = measureRect.Y + measureRect.Height - desiredHeight;
            height = desiredHeight;
        }
        else if (node.IsVerticalCenterAnchored())
        {
            y      = measureRect.Y + (measureRect.Height / 2.0f) - (desiredHeight / 2.0f);
            height = desiredHeight;
        }
    }
Example #7
0
    void CalculateArrangeRectHorizontally(RPNode node, out double x, out double width)
    {
        Rect   measureRect  = node.m_measureRect;
        double desiredWidth = Math.Min(measureRect.Width, node.GetDesiredWidth());

        MUX_ASSERT(node.IsMeasured() && (measureRect.Width != double.PositiveInfinity));

        // The initial values correspond to the left corner, using the
        // desired size of element. If no attached properties were set,
        // this means that the element will default to the left corner of
        // the panel.
        x     = measureRect.X;
        width = desiredWidth;

        if (node.IsLeftAnchored())
        {
            if (node.IsRightAnchored())
            {
                x     = measureRect.X;
                width = measureRect.Width;
            }
            else
            {
                x     = measureRect.X;
                width = desiredWidth;
            }
        }
        else if (node.IsRightAnchored())
        {
            x     = measureRect.X + measureRect.Width - desiredWidth;
            width = desiredWidth;
        }
        else if (node.IsHorizontalCenterAnchored())
        {
            x     = measureRect.X + (measureRect.Width / 2.0f) - (desiredWidth / 2.0f);
            width = desiredWidth;
        }
    }
Example #8
0
    void AccumulateNegativeDesiredHeight(RPNode node, double y)
    {
        double initialY = y;
        bool   isVerticallyCenteredFromTop    = false;
        bool   isVerticallyCenteredFromBottom = false;

        MUX_ASSERT(node.IsMeasured());

        // If we are going in the negative direction, move the cursor
        // down by the desired height of the node with which we are
        // currently working and refresh the minimum negative value.
        y     -= node.GetDesiredHeight();
        m_minY = Math.Min(m_minY, y);

        if (node.IsAlignBottomWithPanel())
        {
            if (!m_isMinCapped)
            {
                m_minY        = y;
                m_isMinCapped = true;
            }
        }
        else if (node.IsAlignBottomWith())
        {
            // If the AlignBottomWithNode and AlignTopWithNode are the
            // same element, we can skip the former, since we will move
            // through the latter later.
            if (node.m_alignBottomWithNode != node.m_alignTopWithNode)
            {
                AccumulatePositiveDesiredHeight(node.m_alignBottomWithNode, y);
            }
        }
        else if (node.IsAlignVerticalCenterWith())
        {
            isVerticallyCenteredFromBottom = true;
        }
        else if (node.IsAbove())
        {
            AccumulateNegativeDesiredHeight(node.m_aboveNode, y);
        }

        if (node.IsAlignTopWithPanel())
        {
            if (m_isMaxCapped)
            {
                m_maxY = Math.Max(m_maxY, initialY);
            }
            else
            {
                m_maxY        = initialY;
                m_isMaxCapped = true;
            }
        }
        else if (node.IsAlignTopWith())
        {
            // If this element's top is aligned to some other element's
            // top, now we will be going in the negative direction to
            // that other element in order to continue the traversal of
            // the dependency chain. But first, since we arrived to the
            // node where we currently are by going in the negative
            // direction, that means that we have already moved the
            // cursor down to calculate the minimum negative value,
            // so we will use the initial value of Y.
            AccumulateNegativeDesiredHeight(node.m_alignTopWithNode, initialY);
        }
        else if (node.IsAlignVerticalCenterWith())
        {
            isVerticallyCenteredFromTop = true;
        }
        else if (node.IsBelow())
        {
            // If this element is below some other element, now we'll
            // be going in the positive direction to that other element
            // in order to continue the traversal of the dependency
            // chain. But first, since we arrived to the node where we
            // currently are by going in the negative direction, that
            // means that we have already moved the cursor down to
            // calculate the minimum negative value, so we will use
            // the initial value of Y.
            AccumulatePositiveDesiredHeight(node.m_belowNode, initialY);
        }

        if (isVerticallyCenteredFromTop && isVerticallyCenteredFromBottom)
        {
            double centerY = y + (node.GetDesiredHeight() / 2.0f);
            double edgeY   = centerY + (node.m_alignVerticalCenterWithNode.GetDesiredHeight() / 2.0f);
            m_maxY = Math.Max(m_maxY, edgeY);
            AccumulateNegativeDesiredHeight(node.m_alignVerticalCenterWithNode, edgeY);
        }
        else if (node.IsVerticalCenterAnchored())
        {
            // If this node is vertically anchored to the center, then it
            // means that it is the root of this dependency chain based on
            // the current definition of precedence for raints:
            // e.g. AlignTopWithPanel
            // > AlignTopWith
            // > Below
            // > AlignVerticalCenterWithPanel
            // Thus, we can report its height as twice the height of
            // either the difference from center to top or the difference
            // from center to bottom, whichever is the greatest.
            double centerY = y + (node.GetDesiredHeight() / 2.0f);
            double upper   = m_maxY - centerY;
            double lower   = centerY - m_minY;
            m_maxY = Math.Max(upper, lower) * 2.0f;
            m_minY = 0.0f;
        }
    }
Example #9
0
    private void AccumulateNegativeDesiredWidth(RPNode node, double x)
    {
        double initialX = x;
        bool   isHorizontallyCenteredFromLeft  = false;
        bool   isHorizontallyCenteredFromRight = false;

        MUX_ASSERT(node.IsMeasured());

        // If we are going in the negative direction, move the cursor
        // left by the desired width of the node with which we are
        // currently working and refresh the minimum negative value.
        x     -= node.GetDesiredWidth();
        m_minX = Math.Min(m_minX, x);

        if (node.IsAlignRightWithPanel())
        {
            if (!m_isMinCapped)
            {
                m_minX        = x;
                m_isMinCapped = true;
            }
        }
        else if (node.IsAlignRightWith())
        {
            // If the AlignRightWithNode and AlignLeftWithNode are the
            // same element, we can skip the former, since we will move
            // through the latter later.
            if (node.m_alignRightWithNode != node.m_alignLeftWithNode)
            {
                AccumulatePositiveDesiredWidth(node.m_alignRightWithNode, x);
            }
        }
        else if (node.IsAlignHorizontalCenterWith())
        {
            isHorizontallyCenteredFromRight = true;
        }
        else if (node.IsLeftOf())
        {
            AccumulateNegativeDesiredWidth(node.m_leftOfNode, x);
        }

        if (node.IsAlignLeftWithPanel())
        {
            if (m_isMaxCapped)
            {
                m_maxX = Math.Max(m_maxX, initialX);
            }
            else
            {
                m_maxX        = initialX;
                m_isMaxCapped = true;
            }
        }
        else if (node.IsAlignLeftWith())
        {
            // If this element's left is aligned to some other element's
            // left, now we will be going in the negative direction to
            // that other element in order to continue the traversal of
            // the dependency chain. But first, since we arrived to the
            // node where we currently are by going in the negative
            // direction, that means that we have already moved the
            // cursor left to calculate the minimum negative value,
            // so we will use the initial value of X.
            AccumulateNegativeDesiredWidth(node.m_alignLeftWithNode, initialX);
        }
        else if (node.IsAlignHorizontalCenterWith())
        {
            isHorizontallyCenteredFromLeft = true;
        }
        else if (node.IsRightOf())
        {
            // If this element is to the right of some other element,
            // now we will be going in the positive direction to that
            // other element in order to continue the traversal of the
            // dependency chain. But first, since we arrived to the
            // node where we currently are by going in the negative
            // direction, that means that we have already moved the
            // cursor left to calculate the minimum negative value, so
            // we will use the initial value of X.
            AccumulatePositiveDesiredWidth(node.m_rightOfNode, initialX);
        }

        if (isHorizontallyCenteredFromLeft && isHorizontallyCenteredFromRight)
        {
            double centerX = x + (node.GetDesiredWidth() / 2.0f);
            double edgeX   = centerX + (node.m_alignHorizontalCenterWithNode.GetDesiredWidth() / 2.0f);
            m_maxX = Math.Max(m_maxX, edgeX);
            AccumulateNegativeDesiredWidth(node.m_alignHorizontalCenterWithNode, edgeX);
        }
        else if (node.IsHorizontalCenterAnchored())
        {
            // If this node is horizontally anchored to the center, then it
            // means that it is the root of this dependency chain based on
            // the current definition of precedence for raints:
            // e.g. AlignLeftWithPanel
            // > AlignLeftWith
            // > RightOf
            // > AlignHorizontalCenterWithPanel
            // Thus, we can report its width as twice the width of
            // either the difference from center to left or the difference
            // from center to right, whichever is the greatest.
            double centerX = x + (node.GetDesiredWidth() / 2.0f);
            double upper   = m_maxX - centerX;
            double lower   = centerX - m_minX;
            m_maxX = Math.Max(upper, lower) * 2.0f;
            m_minX = 0.0f;
        }
    }
Example #10
0
    private void CalculateMeasureRectVertically(RPNode node, Size availableSize, out double y, out double height)
    {
        bool isVerticallyCenteredFromTop    = false;
        bool isVerticallyCenteredFromBottom = false;

        // The initial values correspond to the entire available space. In
        // other words, the edges of the element are aligned to the edges
        // of the panel by default. We will now rain each side of this
        // space as necessary.
        y      = 0.0f;
        height = availableSize.Height;

        // If we have infinite available height, then the Height of the
        // MeasureRect is also infinite; we do not have to rain it.
        if (availableSize.Height != double.PositiveInfinity)
        {
            // Constrain the top of the available space, i.e.
            // a) The child has its top edge aligned with the panel (default),
            // b) The child has its top edge aligned with the top edge of a sibling,
            // or c) The child is positioned to the below a sibling.
            //
            //  ================================== AlignTopWithPanel
            //  .................
            //
            //
            //
            //  --------;;=============;;--------- AlignTopWith
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //  --------.=============.--------- Below
            //                  .
            //                .:;:.
            //              .:;;;;;:.
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //
            //          ;;......:;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ........:
            //
            if (!node.IsAlignTopWithPanel())
            {
                if (node.IsAlignTopWith())
                {
                    RPNode alignTopWithNeighbor    = node.m_alignTopWithNode;
                    double restrictedVerticalSpace = alignTopWithNeighbor.m_arrangeRect.Y;

                    y       = restrictedVerticalSpace;
                    height -= restrictedVerticalSpace;
                }
                else if (node.IsAlignVerticalCenterWith())
                {
                    isVerticallyCenteredFromTop = true;
                }
                else if (node.IsBelow())
                {
                    RPNode belowNeighbor           = node.m_belowNode;
                    double restrictedVerticalSpace = belowNeighbor.m_arrangeRect.Y + belowNeighbor.m_arrangeRect.Height;

                    y       = restrictedVerticalSpace;
                    height -= restrictedVerticalSpace;
                }
            }

            // Constrain the bottom of the available space, i.e.
            // a) The child has its bottom edge aligned with the panel (default),
            // b) The child has its bottom edge aligned with the bottom edge of a sibling,
            // or c) The child is positioned to the above a sibling.
            //
            //          ;;......:;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ........:
            //
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //                ;;;;;
            //              ..;;;;;..
            //               '..:'
            //                 ':`
            //
            //  --------;;=============;;--------- Above
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //          ;;             ;;
            //  --------.=============.--------- AlignBottomWith
            //
            //
            //
            //  .................
            //  ================================== AlignBottomWithPanel
            //
            if (!node.IsAlignBottomWithPanel())
            {
                if (node.IsAlignBottomWith())
                {
                    RPNode alignBottomWithNeighbor = node.m_alignBottomWithNode;

                    height -= availableSize.Height - (alignBottomWithNeighbor.m_arrangeRect.Y + alignBottomWithNeighbor.m_arrangeRect.Height);
                }
                else if (node.IsAlignVerticalCenterWith())
                {
                    isVerticallyCenteredFromBottom = true;
                }
                else if (node.IsAbove())
                {
                    RPNode aboveNeighbor = node.m_aboveNode;

                    height -= availableSize.Height - aboveNeighbor.m_arrangeRect.Y;
                }
            }

            if (isVerticallyCenteredFromTop && isVerticallyCenteredFromBottom)
            {
                RPNode alignVerticalCenterWithNeighbor = node.m_alignVerticalCenterWithNode;
                double centerOfNeighbor = alignVerticalCenterWithNeighbor.m_arrangeRect.Y + (alignVerticalCenterWithNeighbor.m_arrangeRect.Height / 2.0f);
                height = Math.Min(centerOfNeighbor, availableSize.Height - centerOfNeighbor) * 2.0f;
                y      = centerOfNeighbor - (height / 2.0f);
            }
        }
    }
Example #11
0
    private void CalculateMeasureRectHorizontally(RPNode node, Size availableSize, out double x, out double width)
    {
        bool isHorizontallyCenteredFromLeft  = false;
        bool isHorizontallyCenteredFromRight = false;

        // The initial values correspond to the entire available space. In
        // other words, the edges of the element are aligned to the edges
        // of the panel by default. We will now rain each side of this
        // space as necessary.
        x     = 0.0f;
        width = availableSize.Width;

        // If we have infinite available width, then the Width of the
        // MeasureRect is also infinite; we do not have to rain it.
        if (availableSize.Width != double.PositiveInfinity)
        {
            // Constrain the left side of the available space, i.e.
            // a) The child has its left edge aligned with the panel (default),
            // b) The child has its left edge aligned with the left edge of a sibling,
            // or c) The child is positioned to the right of a sibling.
            //
            //  |;;                 |               |
            //  |;;                 |               |
            //  |;;                 |:::::::::::::::|                       ;;:::::::::::::;;
            //  |;;                 |;             ;|       .               ;;             ;;
            //  |;;                 |;             ;|     .;;............   ;;             ;;
            //  |;;                 |;             ;|   .;;;;::::::::::::   ;;             ;;
            //  |;;                 |;             ;|    ':;;::::::::::::   ;;             ;;
            //  |;;                 |;             ;|      ':               ;;             ;;
            //  |;;                 |:::::::::::::::|                       :::::::::::::::::
            //  |;;                 |               |
            //  |;;                 |               |
            //  AlignLeftWithPanel  AlignLeftWith   RightOf
            //
            if (!node.IsAlignLeftWithPanel())
            {
                if (node.IsAlignLeftWith())
                {
                    RPNode alignLeftWithNeighbor     = node.m_alignLeftWithNode;
                    double restrictedHorizontalSpace = alignLeftWithNeighbor.m_arrangeRect.X;

                    x      = restrictedHorizontalSpace;
                    width -= restrictedHorizontalSpace;
                }
                else if (node.IsAlignHorizontalCenterWith())
                {
                    isHorizontallyCenteredFromLeft = true;
                }
                else if (node.IsRightOf())
                {
                    RPNode rightOfNeighbor           = node.m_rightOfNode;
                    double restrictedHorizontalSpace = rightOfNeighbor.m_arrangeRect.X + rightOfNeighbor.m_arrangeRect.Width;

                    x      = restrictedHorizontalSpace;
                    width -= restrictedHorizontalSpace;
                }
            }

            // Constrain the right side of the available space, i.e.
            // a) The child has its right edge aligned with the panel (default),
            // b) The child has its right edge aligned with the right edge of a sibling,
            // or c) The child is positioned to the left of a sibling.
            //
            //                                          |               |                   ;;|
            //                                          |               |                   ;;|
            //  ;;:::::::::::::;;                       |;:::::::::::::;|                   ;;|
            //  ;;             ;;               .       |;             ;|                   ;;|
            //  ;;             ;;   ............;;.     |;             ;|                   ;;|
            //  ;;             ;;   ::::::::::::;;;;.   |;             ;|                   ;;|
            //  ;;             ;;   ::::::::::::;;:'    |;             ;|                   ;;|
            //  ;;             ;;               :'      |;             ;|                   ;;|
            //  :::::::::::::::::                       |:::::::::::::::|                   ;;|
            //                                          |               |                   ;;|
            //                                          |               |                   ;;|
            //                                          LeftOf          AlignRightWith      AlignRightWithPanel
            //
            if (!node.IsAlignRightWithPanel())
            {
                if (node.IsAlignRightWith())
                {
                    RPNode alignRightWithNeighbor = node.m_alignRightWithNode;

                    width -= availableSize.Width - (alignRightWithNeighbor.m_arrangeRect.X + alignRightWithNeighbor.m_arrangeRect.Width);
                }
                else if (node.IsAlignHorizontalCenterWith())
                {
                    isHorizontallyCenteredFromRight = true;
                }
                else if (node.IsLeftOf())
                {
                    RPNode leftOfNeighbor = node.m_leftOfNode;

                    width -= availableSize.Width - leftOfNeighbor.m_arrangeRect.X;
                }
            }

            if (isHorizontallyCenteredFromLeft && isHorizontallyCenteredFromRight)
            {
                RPNode alignHorizontalCenterWithNeighbor = node.m_alignHorizontalCenterWithNode;
                double centerOfNeighbor = alignHorizontalCenterWithNeighbor.m_arrangeRect.X + (alignHorizontalCenterWithNeighbor.m_arrangeRect.Width / 2.0f);
                width = Math.Min(centerOfNeighbor, availableSize.Width - centerOfNeighbor) * 2.0f;
                x     = centerOfNeighbor - (width / 2.0f);
            }
        }
    }
Example #12
0
    private void GetNodeByValue(
        object value,
        DependencyObject parent,
        Uno.UI.Xaml.Core.CoreServices core,
        out RPNode ppNode)
    {
        // Here we will have either a valueString which corresponds to the name
        // of the element we are looking for, or a valueObject of type UIElement
        // which is a direct reference to said element.
        if (value is string)
        {
            string name = null;
            if (value is string valueString)
            {
                name = valueString;
            }

            if (!string.IsNullOrEmpty(name))
            {
                foreach (RPNode node in m_nodes)
                {
                    if (name.Equals(node.GetName()))
                    {
                        ppNode = node;
                        return;
                    }
                }

                // If there is no match within the children, the target might
                // actually be a deferred element. If that's the case, we will
                // create a node for this deferred element and inject it into
                // the graph.
                // TODO Uno: We don't support a concept of deferred elements yet.
                //var deferredElement = core.GetDeferredElementIfExists(name, namescopeOwner, nameScopeType);

                //if (deferredElement && deferredElement.GetParent() == parent)
                //{
                //	*ppNode = &(*m_nodes.emplace_after(it, deferredElement));
                //	return S_OK;
                //}

                // If there is truly no matching node in the end, then we must
                // throw an InvalidOperationException. We will fail fast here
                // and let the CRelativePanel handle the rest.
                throw new InvalidOperationException("No matching node found");
            }
        }
        else
        {
            UIElement valueAsUIElement = null;
            if (value is UIElement)
            {
                valueAsUIElement = value as UIElement;
            }
            else if (value is ElementNameSubject elementNameSubject)             // TODO Uno specific: We get ElementNameSubject instead of string here
            {
                valueAsUIElement = elementNameSubject.ElementInstance as UIElement;
            }

            if (valueAsUIElement != null)
            {
                foreach (RPNode node in m_nodes)
                {
                    if (node.GetElement() == valueAsUIElement)
                    {
                        ppNode = node;
                        return;
                    }
                }

                // If there is no match, we must throw an InvalidOperationException.
                // We will fail fast here and let the CRelativePanel handle the rest.
                throw new InvalidOperationException("Node reference not found");
            }
        }

        ppNode = null;
        return;
    }
Example #13
0
    private void MeasureNode(RPNode node, Size availableSize)
    {
        if (node == null)
        {
            return;
        }

        if (node.IsPending())
        {
            // If the node is already in the process of being resolved
            // but we tried to resolve it again, that means we are in the
            // middle of circular dependency and we must throw an
            // InvalidOperationException. We will fail fast here and let
            // the CRelativePanel handle the rest.
            throw new InvalidOperationException("Circular dependency found in RelativePanel");
        }
        else if (node.IsUnresolved())
        {
            Size constrainedAvailableSize = new Size();

            // We must resolve the dependencies of this node first.
            // In the meantime, we will mark the state as pending.
            node.SetPending(true);

            MeasureNode(node.m_leftOfNode, availableSize);
            MeasureNode(node.m_aboveNode, availableSize);
            MeasureNode(node.m_rightOfNode, availableSize);
            MeasureNode(node.m_belowNode, availableSize);
            MeasureNode(node.m_alignLeftWithNode, availableSize);
            MeasureNode(node.m_alignTopWithNode, availableSize);
            MeasureNode(node.m_alignRightWithNode, availableSize);
            MeasureNode(node.m_alignBottomWithNode, availableSize);
            MeasureNode(node.m_alignHorizontalCenterWithNode, availableSize);
            MeasureNode(node.m_alignVerticalCenterWithNode, availableSize);

            node.SetPending(false);

            double nodeMeasureRectX, nodeMeasureRectWidth, nodeMeasureRectY, nodeMeasureRectHeight;
            CalculateMeasureRectHorizontally(node, availableSize, out nodeMeasureRectX, out nodeMeasureRectWidth);
            CalculateMeasureRectVertically(node, availableSize, out nodeMeasureRectY, out nodeMeasureRectHeight);
            node.m_measureRect.X      = nodeMeasureRectX;
            node.m_measureRect.Y      = nodeMeasureRectY;
            node.m_measureRect.Width  = nodeMeasureRectWidth;
            node.m_measureRect.Height = nodeMeasureRectHeight;

            constrainedAvailableSize.Width  = Math.Max(node.m_measureRect.Width, 0.0f);
            constrainedAvailableSize.Height = Math.Max(node.m_measureRect.Height, 0.0f);
            node.Measure(constrainedAvailableSize);
            node.SetMeasured(true);

            // (Pseudo-) Arranging against infinity does not make sense, so
            // we will skip the calculations of the ArrangeRects if
            // necessary. During the true arrange pass, we will be given a
            // non-infinite final size; we will do the necessary
            // calculations until then.
            if (availableSize.Width != double.PositiveInfinity)
            {
                double nodeArrangeRectX, nodeArrangeRectWidth;
                CalculateArrangeRectHorizontally(node, out nodeArrangeRectX, out nodeArrangeRectWidth);
                node.m_arrangeRect.X     = nodeArrangeRectX;
                node.m_arrangeRect.Width = nodeArrangeRectWidth;
                node.SetArrangedHorizontally(true);
            }

            if (availableSize.Height != double.PositiveInfinity)
            {
                double nodeArrangeRectY, nodeArrangeRectHeight;
                CalculateArrangeRectVertically(node, out nodeArrangeRectY, out nodeArrangeRectHeight);
                node.m_arrangeRect.Y      = nodeArrangeRectY;
                node.m_arrangeRect.Height = nodeArrangeRectHeight;
                node.SetArrangedVertically(true);
            }
        }
    }