예제 #1
0
        public static Size Measure(IStackPanel panel, Size availableSize)
        {
            var spacing         = panel is IStackPanelAdvanced advanced ? advanced.Spacing : 0.0;
            var orientation     = panel.Orientation;
            var childConstraint = availableSize.AsOriented(orientation).ChangeDirect(double.PositiveInfinity);
            var result          = new OrientedSize(orientation);
            var elementsCount   = panel.Elements.Count;
            var spacingSize     = new OrientedSize().ChangeDirect(spacing);

            for (var index = 0; index < elementsCount; index++)
            {
                var child = panel.Elements[index];

                child.Measure(childConstraint.Size);

                result = result.StackSize(child.DesiredSize);

                if (index + 1 < elementsCount)
                {
                    result = result.StackSize(spacingSize);
                }
            }

            return(result.Size);
        }
            public VirtualMeasureContext(VirtualUnitStackPanelLayout layout, Size availableSize)
            {
                Layout = layout;

                Orientation = layout.Orientation;

                var canScrollDirect   = Orientation == Orientation.Vertical ? layout.CanVerticallyScroll : layout.CanHorizontallyScroll;
                var canScrollIndirect = Orientation == Orientation.Vertical ? layout.CanHorizontallyScroll : layout.CanVerticallyScroll;

                LeadingElements  = layout.Panel.LeadingElements;
                TrailingElements = layout.Panel.TrailingElements;

                SourceCount = layout.ItemsCount + (LeadingElements?.Count ?? 0) + (TrailingElements?.Count ?? 0);

                OrientedResult       = new OrientedSize(Orientation);
                OrientedLeadingSize  = new OrientedSize(Orientation);
                OrientedTrailingSize = new OrientedSize(Orientation);
                OrientedAvailable    = availableSize.AsOriented(Orientation);
                OffsetElementIndex   = layout.CalcFirstVisibleIndex(layout.Offset);
                OrientedConstraint   = new OrientedSize(Orientation)
                                       .ChangeDirect(canScrollDirect ? double.PositiveInfinity : OrientedAvailable.Direct)
                                       .ChangeIndirect(canScrollIndirect ? double.PositiveInfinity : OrientedAvailable.Indirect);

                LastIndex          = -1;
                FirstIndex         = -1;
                FirstVisibleIndex  = -1;
                LastVisibleIndex   = -1;
                LeadingCacheCount  = 0;
                TrailingCacheCount = 0;
            }
예제 #3
0
        internal static Rect FillRectIndirect(this FrameworkElement fre, Orientation orientation, Size availableSize)
        {
            if (!fre.ShouldFill(orientation))
            {
                return(fre.DesiredSize.Rect());
            }

            var orientedSize = fre.DesiredSize.AsOriented(orientation);

            orientedSize.Indirect = availableSize.AsOriented(orientation).Indirect;

            return(orientedSize.Size.Rect());
        }
예제 #4
0
        private Size MeasureCoreImpl(Size availableSize)
        {
            var flexPanel         = Panel;
            var orientation       = flexPanel.Orientation;
            var availableOriented = availableSize.AsOriented(orientation);
            var children          = flexPanel.Elements;
            var visibility        = VisibilityArrayPool.GetArray(children.Count);

            _measureInfinite = availableOriented.Direct.IsPositiveInfinity();

            // First measure pass
            try
            {
                // Cache children visibility
                for (var index = 0; index < children.Count; index++)
                {
                    visibility[index] = children[index].Visibility;
                }

                var result = MeasureImpl(availableOriented.Size, out var isOverflowedChanged);
                var childVisibilityChanged = false;

                // Check children visibility changes
                if (isOverflowedChanged == false)
                {
                    var count = Math.Min(children.Count, visibility.Length);

                    for (var index = 0; index < count; index++)
                    {
                        childVisibilityChanged = visibility[index] != children[index].Visibility;

                        if (childVisibilityChanged)
                        {
                            break;
                        }
                    }
                }

                // Second measure pass
                if (isOverflowedChanged || childVisibilityChanged)
                {
                    result = MeasureImpl(availableOriented.Size, out isOverflowedChanged);
                }

                return(result.AsOriented(orientation).Size);
            }
            finally
            {
                VisibilityArrayPool.ReleaseArray(visibility);
            }
        }
예제 #5
0
        public static Size Arrange(IStackPanel panel, Size finalSize)
        {
            var spacing       = panel is IStackPanelAdvanced advanced ? advanced.Spacing : 0.0;
            var orientation   = panel.Orientation;
            var offset        = new OrientedPoint(orientation);
            var finalOriented = finalSize.AsOriented(orientation);

            foreach (var child in panel.Elements)
            {
                var size = child.DesiredSize.AsOriented(orientation);

                size.Indirect = finalOriented.Indirect;

                var rect = new Rect(offset.Point, size.Size);

                child.Arrange(rect);
                offset.Direct += size.Direct + spacing;
            }

            return(finalSize);
        }
예제 #6
0
        private Size MeasureImpl(Size availableSize, out bool overflowChanged)
        {
            overflowChanged = false;

            var children      = Panel.Elements;
            var orientation   = Panel.Orientation;
            var childrenCount = children.Count;

            if (childrenCount == 0)
            {
                return(XamlConstants.ZeroSize);
            }

            var useLayoutRounding = Panel.UseLayoutRounding;

            FlexElements.UseLayoutRounding = useLayoutRounding;

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

            var spacing           = GetRoundSpacing(Panel.Spacing, useLayoutRounding);
            var availableOriented = availableSize.AsOriented(orientation);

            // First measure
            var desiredOriented = MeasureItems(availableSize, out var desiredFixed, out _);

            // Stretch
            desiredOriented.Direct = Stretch(FlexElements, spacing, availableOriented.Direct, false);

            // Final measure
            desiredOriented = FinalMeasureItems(availableOriented, spacing, false);

            // Overflow
            var visibleSize = ProcessSpacingAndOverflow(spacing, desiredOriented, availableOriented, out overflowChanged);

            // Return
            return(GetFinalMeasureSize(availableOriented.Clamp(desiredFixed, XamlConstants.InfiniteSize.AsOriented(orientation)), desiredOriented, visibleSize).Size);
        }
예제 #7
0
        private Vector CalcBringIntoViewOffset(int index, BringIntoViewMode mode, Size viewport, Size extent, Vector offset)
        {
            if (index < 0 || index >= ItemsCount)
            {
                return(offset);
            }

            var orientation      = Orientation;
            var orientedViewPort = viewport.AsOriented(orientation);
            var orientedExtent   = extent.AsOriented(orientation);
            var orientedOffset   = offset.AsOriented(orientation);
            var orientedViewer   = new OrientedScrollView(orientation, orientedViewPort.Direct, orientedExtent.Direct,
                                                          orientedOffset.Direct);

            orientedViewer.Offset = orientedViewer.Offset - index > 0.0 || mode == BringIntoViewMode.Top
                                ? index
                                : index - orientedViewer.Viewport + 1.0;

            orientedOffset.Direct = orientedViewer.Offset;

            return(orientedOffset.Vector);
        }
예제 #8
0
        protected override Size ArrangeCore(Size finalSize)
        {
            var orientation   = Orientation;
            var offset        = new OrientedPoint(orientation);
            var finalOriented = finalSize.AsOriented(orientation);

            offset.Direct -= _preCacheDelta;

            foreach (UIElement child in Children)
            {
                var size = child.DesiredSize.AsOriented(orientation);

                size.Indirect = finalOriented.Indirect;

                var rect = new Rect(offset.Point, size.Size);

                ArrangeChild(child, rect);

                offset.Direct += size.Direct;
            }

            return(finalSize);
        }
예제 #9
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);
            }
        }
예제 #10
0
        private OrientedSize MeasureItems(Size availableSize, out OrientedSize fixedSize, out OrientedSize flexibleSize)
        {
            var stretch              = Panel.Stretch;
            var orientation          = Panel.Orientation;
            var children             = Panel.Elements;
            var childrenCount        = children.Count;
            var oriented             = availableSize.AsOriented(orientation);
            var fixedChildConstraint = oriented.Clone.ChangeDirect(double.PositiveInfinity);
            var starChildConstraint  = oriented.Clone.ChangeDirect(0);
            var fixedResult          = new OrientedSize(orientation);
            var starValue            = 0.0;

            FlexElements.EnsureCount(childrenCount);

            for (var index = 0; index < childrenCount; index++)
            {
                var flexElement = Panel.GetFlexElement(children[index]).WithOrientation(orientation);

                if (flexElement.IsStar)
                {
                    starValue += flexElement.Length.Value;
                }

                FlexElements[index] = flexElement;
            }

            // None Stretch
            if (stretch == FlexStretch.None)
            {
                for (var index = 0; index < childrenCount; index++)
                {
                    var flexElement     = FlexElements[index];
                    var child           = children[index];
                    var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint);

                    // Stack child size
                    var size = MeasureChild(child, childConstraint);

                    flexElement         = flexElement.WithUIElement(child, orientation);
                    size.Direct         = flexElement.DesiredLength;
                    fixedResult         = fixedResult.StackSize(size);
                    FlexElements[index] = flexElement;
                }

                fixedSize    = fixedResult;
                flexibleSize = new OrientedSize(orientation);

                return(fixedResult);
            }

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

                if (flexElement.IsStar)
                {
                    continue;
                }

                var child           = children[index];
                var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint);

                // Stack child size
                var size = MeasureChild(child, childConstraint);

                flexElement         = flexElement.WithUIElement(child, orientation);
                size.Direct         = flexElement.DesiredLength;
                fixedResult         = fixedResult.StackSize(size);
                FlexElements[index] = flexElement;
            }

            fixedSize    = fixedResult;
            flexibleSize = new OrientedSize(orientation);
            starChildConstraint.ChangeDirect(FlexUtils.CalcStarValue(oriented.Direct, fixedResult.Direct, starValue));

            // Star size children
            var flexibleResult = new OrientedSize(orientation);

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

                if (flexElement.IsFixed)
                {
                    continue;
                }

                var child           = children[index];
                var childConstraint = GetChildConstraint(flexElement, fixedChildConstraint, starChildConstraint);

                // Stack child size
                var size = MeasureChild(child, childConstraint);

                flexElement         = flexElement.WithUIElement(child, orientation);
                size.Direct         = flexElement.DesiredLength;
                flexibleResult      = flexibleResult.StackSize(size);
                FlexElements[index] = flexElement.WithUIElement(child, orientation);
            }

            flexibleSize = flexibleResult;

            return(fixedResult.StackSize(flexibleResult));
        }
예제 #11
0
 public static OrientedSize WrapSize(this OrientedSize self, Size itemSize)
 {
     return(self.WrapSize(itemSize.AsOriented(self.Orientation)));
 }