Пример #1
0
        private OrientedSize ProcessSpacingAndOverflow(double spacing, OrientedSize desiredOriented, OrientedSize availableOriented, out bool isHiddenChanged)
        {
            var childrenCount = Panel.Elements.Count;
            var orientation   = Panel.Orientation;

            var target = availableOriented.Direct;

            isHiddenChanged = false;

            // Current length is greater than available and we have no possibility to stretch down -> mark elements as hidden
            var current = 0.0;
            var visible = 0.0;

            var hasHiddenChildren    = false;
            var visibleChildrenCount = 0;

            if (desiredOriented.Direct.IsGreaterThan(availableOriented.Direct))
            {
                var stretchOverflow = FlexElementCollection.Mount(FlexElements.Capacity);

                try
                {
                    // Process Pinned Flexible
                    for (var index = 0; index < childrenCount; index++)
                    {
                        var flexElement = FlexElements[index];

                        if (CanPinStretch(flexElement) == false)
                        {
                            continue;
                        }

                        flexElement.StretchDirection = FlexStretchDirection.Shrink;

                        stretchOverflow.Add(flexElement);

                        Panel.SetIsHidden(Panel.Elements[index], false);
                    }

                    // Process Pinned
                    for (var index = 0; index < childrenCount; index++)
                    {
                        var child = Panel.Elements[index];

                        if (child.Visibility == Visibility.Collapsed)
                        {
                            continue;
                        }

                        var flexElement = FlexElements[index];

                        if (CanPin(flexElement) == false)
                        {
                            continue;
                        }

                        current += flexElement.ActualLength;
                        current += spacing;

                        visible = current;

                        Panel.SetIsHidden(Panel.Elements[index], false);
                    }

                    // Process Hide
                    for (var index = 0; index < childrenCount; index++)
                    {
                        var child = Panel.Elements[index];

                        if (child.Visibility == Visibility.Collapsed)
                        {
                            continue;
                        }

                        visibleChildrenCount++;

                        var flexElement = FlexElements[index];

                        if (CanPin(flexElement))
                        {
                            continue;
                        }

                        current += flexElement.ActualLength;

                        if (CanHide(flexElement) == false)
                        {
                            isHiddenChanged |= Panel.GetIsHidden(child);
                            Panel.SetIsHidden(child, false);

                            current += spacing;

                            visible = current;
                            continue;
                        }

                        var isOverflowed = current.IsGreaterThan(target, XamlConstants.LayoutComparisonPrecision);

                        current += spacing;

                        if (isOverflowed == false)
                        {
                            visible = current;
                        }

                        isHiddenChanged   |= Panel.GetIsHidden(child) != isOverflowed;
                        hasHiddenChildren |= isOverflowed;

                        Panel.SetIsHidden(child, isOverflowed);
                    }

                    if (visibleChildrenCount > 0)
                    {
                        visible = visible - spacing;
                    }

                    Panel.HasHiddenChildren = hasHiddenChildren;

                    // Stretch Pinned
                    if (visible.IsGreaterThan(availableOriented.Direct) && stretchOverflow.Count > 0)
                    {
                        var currentPinStretch = stretchOverflow.Actual;
                        var pinStretchTarget  = (currentPinStretch - (visible - availableOriented.Direct)).Clamp(0, availableOriented.Direct);
                        var pinStretchDesired = stretchOverflow.Stretch(FlexStretch.Fill, pinStretchTarget, FlexDistributor.Equalizer);

                        if (pinStretchDesired < currentPinStretch)
                        {
                            var pinStretchIndex = 0;

                            for (var index = 0; index < childrenCount; index++)
                            {
                                var flexElement = FlexElements[index];

                                if (CanPinStretch(flexElement))
                                {
                                    FlexElements[index] = stretchOverflow[pinStretchIndex++].WithStretchDirection(FlexStretchDirection.Shrink).WithMaxLength(flexElement.ActualLength);
                                }
                                else
                                {
                                    FlexElements[index] = FlexElements[index].WithStretchDirection(FlexStretchDirection.Shrink).WithShrinkPriority(short.MaxValue);
                                }
                            }

                            FinalMeasureItems(availableOriented, spacing, true);

                            return(OrientedSize.Create(orientation, availableOriented.Direct, desiredOriented.Indirect));
                        }
                    }
                }
                finally
                {
                    FlexElementCollection.Release(stretchOverflow);
                }

                return(OrientedSize.Create(orientation, visible.Clamp(0, availableOriented.Direct), desiredOriented.Indirect));
            }

            for (var index = 0; index < childrenCount; index++)
            {
                var flexElement = FlexElements[index];
                var child       = Panel.Elements[index];

                if (child.Visibility == Visibility.Collapsed)
                {
                    continue;
                }

                visibleChildrenCount++;

                current += flexElement.ActualLength;
                current += spacing;

                Panel.SetIsHidden(Panel.Elements[index], false);
            }

            Panel.HasHiddenChildren = false;
            visible = Math.Max(0, current);

            if (visibleChildrenCount > 0)
            {
                visible = visible - spacing;
            }

            return(OrientedSize.Create(orientation, visible.Clamp(0, availableOriented.Direct), desiredOriented.Indirect));
        }
Пример #2
0
        private Size ArrangeCoreImpl(Size finalSize)
        {
            var flexPanel         = Panel;
            var flexPanelEx       = Panel as IFlexPanelEx;
            var allowMeasure      = flexPanelEx?.AllowMeasureInArrange ?? false;
            var orientation       = flexPanel.Orientation;
            var useLayoutRounding = flexPanel.UseLayoutRounding;
            var spacing           = GetRoundSpacing(flexPanel.Spacing, useLayoutRounding);

            for (var index = 0; index < flexPanel.Elements.Count; index++)
            {
                FlexElements[index] = FlexElements[index].WithUIElement(flexPanel.Elements[index], orientation);
            }

            var currentFlexElements = FlexElementCollection.Mount(FlexElements.Capacity);

            try
            {
                FlexElements.CopyTo(currentFlexElements);

                while (true)
                {
                    var nextArrangePass    = false;
                    var size               = new OrientedSize(orientation);
                    var spacingDelta       = 0.0;
                    var finalOriented      = finalSize.AsOriented(orientation);
                    var finalIndirect      = finalOriented.Indirect;
                    var currentPoint       = new OrientedPoint(orientation);
                    var childFinalOriented = new OrientedSize(orientation);

                    // Stretch
                    Stretch(currentFlexElements, spacing, finalOriented.Direct, true);

                    for (var index = 0; index < flexPanel.Elements.Count; index++)
                    {
                        var child       = flexPanel.Elements[index];
                        var flexElement = currentFlexElements[index];

                        if (child.Visibility == Visibility.Collapsed)
                        {
                            continue;
                        }

                        if (flexPanel.GetIsHidden(child))
                        {
                            child.Arrange(XamlConstants.ZeroRect);
                            flexElement.ActualLength   = 0.0;
                            currentFlexElements[index] = flexElement;

                            continue;
                        }

                        var desiredOriented = child.DesiredSize.AsOriented(orientation);

                        childFinalOriented.Direct   = flexElement.ActualLength;
                        childFinalOriented.Indirect = Math.Max(finalIndirect, desiredOriented.Indirect);

                        // Arrange Child
                        var rect = new Rect(XamlConstants.ZeroPoint, childFinalOriented.Size).Offset(currentPoint);

                        if (useLayoutRounding)
                        {
                            rect = rect.LayoutRound(RoundingMode.MidPointFromZero);
                        }

                        if (_measureInfinite && allowMeasure && desiredOriented.Direct.IsGreaterThan(childFinalOriented.Direct))
                        {
                            var remeasureOriented = desiredOriented;

                            remeasureOriented.ChangeDirect(childFinalOriented.Direct);

                            child.Measure(remeasureOriented.Size);
                        }

                        child.Arrange(rect);

                        var arrangeSize = GetActualArrangeSize(child);

                        if (arrangeSize.IsEmpty == false)
                        {
                            rect.Width  = arrangeSize.Width;
                            rect.Height = arrangeSize.Height;
                        }

                        var finalChildDirect = rect.Size().AsOriented(orientation).Direct;

                        if (IsArrangeFixed(flexElement) == false && finalChildDirect.IsLessThan(childFinalOriented.Direct))
                        {
                            var length = finalChildDirect;

                            flexElement.SetLengths(length, length, length, length);
                            currentFlexElements[index] = flexElement;
                            nextArrangePass            = true;

                            break;
                        }

                        if (useLayoutRounding)
                        {
                            var rectSize = rect.Size().AsOriented(orientation);

                            flexElement.ActualLength = rectSize.Direct;
                            currentPoint.Direct      = Math.Max(0, (currentPoint.Direct + rectSize.Direct + spacing).LayoutRound(orientation, RoundingMode.MidPointFromZero));
                        }
                        else
                        {
                            var rectSize = rect.Size().AsOriented(orientation);

                            flexElement.ActualLength = rectSize.Direct;
                            currentPoint.Direct      = Math.Max(0, currentPoint.Direct + rectSize.Direct + spacing);
                        }

                        currentFlexElements[index] = flexElement;

                        spacingDelta += spacing;

                        size = size.StackSize(childFinalOriented);
                    }

                    if (nextArrangePass)
                    {
                        continue;
                    }

                    if (spacingDelta.Equals(0.0) == false)
                    {
                        size.Direct = Math.Max(0, size.Direct + spacingDelta - spacing);
                    }

                    var result = finalSize;

                    if (orientation == Orientation.Horizontal)
                    {
                        result.Width = flexPanel.ShouldFill(Orientation.Horizontal) ? finalSize.Width : Math.Min(finalSize.Width, size.Width);
                    }
                    else
                    {
                        result.Height = flexPanel.ShouldFill(Orientation.Vertical) ? finalSize.Height : Math.Min(finalSize.Height, size.Height);
                    }

                    return(result);
                }
            }
            finally
            {
                FlexElementCollection.Release(currentFlexElements);
            }
        }