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