Beispiel #1
0
        /// <inheritdoc />
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (Children.Count > 0)
            {
                var parentMeasure  = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
                var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
                var paddingStart   = new UvMeasure(Orientation, Padding.Left, Padding.Top);
                var paddingEnd     = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
                var position       = new UvMeasure(Orientation, Padding.Left, Padding.Top);

                double currentV = 0;
                void Arrange(UIElement child, bool isLast = false)
                {
                    var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);

                    if (desiredMeasure.U == 0)
                    {
                        return; // if an item is collapsed, avoid adding the spacing
                    }

                    if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
                    {
                        // next row!
                        position.U  = paddingStart.U;
                        position.V += currentV + spacingMeasure.V;
                        currentV    = 0;
                    }

                    // Stretch the last item to fill the available space
                    if (isLast)
                    {
                        desiredMeasure.U = parentMeasure.U - position.U;
                    }

                    // place the item
                    if (Orientation == Orientation.Horizontal)
                    {
                        child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V));
                    }
                    else
                    {
                        child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U));
                    }

                    // adjust the location for the next items
                    position.U += desiredMeasure.U + spacingMeasure.U;
                    currentV    = Math.Max(desiredMeasure.V, currentV);
                }

                var lastIndex = Children.Count - 1;
                for (var i = 0; i < lastIndex; i++)
                {
                    Arrange(Children[i]);
                }

                Arrange(Children[lastIndex], StretchChild == StretchChild.Last);
            }

            return(finalSize);
        }
Beispiel #2
0
        /// <inheritdoc />
        protected override Size ArrangeOverride(Size finalSize)
        {
            var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
            var position      = UvMeasure.Zero;

            double currentV = 0;

            foreach (var child in Children)
            {
                var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
                if ((desiredMeasure.U + position.U) > parentMeasure.U)
                {
                    // next row!
                    position.U  = 0;
                    position.V += currentV;
                    currentV    = 0;
                }

                // Place the item
                if (Orientation == Orientation.Horizontal)
                {
                    child.Arrange(new Rect(position.U, position.V, child.DesiredSize.Width, child.DesiredSize.Height));
                }
                else
                {
                    child.Arrange(new Rect(position.V, position.U, child.DesiredSize.Width, child.DesiredSize.Height));
                }

                // adjust the location for the next items
                position.U += desiredMeasure.U;
                currentV    = Math.Max(desiredMeasure.V, currentV);
            }

            return(finalSize);
        }
Beispiel #3
0
        /// <inheritdoc />
        protected override Size MeasureOverride(Size availableSize)
        {
            availableSize.Width  = availableSize.Width - Padding.Left - Padding.Right;
            availableSize.Height = availableSize.Height - Padding.Top - Padding.Bottom;
            var totalMeasure   = UvMeasure.Zero;
            var parentMeasure  = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
            var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var lineMeasure    = UvMeasure.Zero;

            foreach (var child in Children)
            {
                child.Measure(availableSize);

                var currentMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);

                if (parentMeasure.U >= currentMeasure.U + lineMeasure.U + spacingMeasure.U)
                {
                    lineMeasure.U += currentMeasure.U + spacingMeasure.U;
                    lineMeasure.V  = Math.Max(lineMeasure.V, currentMeasure.V);
                }
                else
                {
                    // new line should be added
                    // to get the max U to provide it correctly to ui width ex: ---| or -----|
                    totalMeasure.U  = Math.Max(lineMeasure.U, totalMeasure.U);
                    totalMeasure.V += lineMeasure.V + spacingMeasure.V;

                    // if the next new row still can handle more controls
                    if (parentMeasure.U > currentMeasure.U)
                    {
                        // set lineMeasure initial values to the currentMeasure to be calculated later on the new loop
                        lineMeasure = currentMeasure;
                    }

                    // the control will take one row alone
                    else
                    {
                        // validate the new control measures
                        totalMeasure.U  = Math.Max(currentMeasure.U, totalMeasure.U);
                        totalMeasure.V += currentMeasure.V;

                        // add new empty line
                        lineMeasure = UvMeasure.Zero;
                    }
                }
            }

            // update value with the last line
            // if the the last loop is(parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it
            // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
            // for the last condition it is zeros so adding it will make no difference
            // this way is faster than an if condition in every loop for checking the last item
            totalMeasure.U  = Math.Max(lineMeasure.U, totalMeasure.U);
            totalMeasure.V += lineMeasure.V;

            totalMeasure.U = Math.Ceiling(totalMeasure.U);

            return(Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U));
        }
Beispiel #4
0
 public void Add(UvMeasure position, UvMeasure size)
 {
     ChildrenRects.Add(new UvRect {
         Position = position, Size = size
     });
     Size = new UvMeasure
     {
         U = position.U + size.U,
         V = Math.Max(Size.V, size.V),
     };
 }
        internal void SetOrientation(Orientation orientation)
        {
            foreach (var item in _items.Where(i => i.Measure.HasValue))
            {
                UvMeasure measure = item.Measure.Value;
                double    v       = measure.V;
                measure.V     = measure.U;
                measure.U     = v;
                item.Measure  = measure;
                item.Position = null;
            }

            Orientation = orientation;
            AvailableU  = 0;
        }
Beispiel #6
0
        /// <inheritdoc />
        protected override Size ArrangeOverride(Size finalSize)
        {
            var parentMeasure  = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
            var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var paddingStart   = new UvMeasure(Orientation, Padding.Left, Padding.Top);
            var paddingEnd     = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
            var position       = new UvMeasure(Orientation, Padding.Left, Padding.Top);

            double currentV = 0;

            foreach (var child in Children)
            {
                var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
                if (desiredMeasure.U == 0)
                {
                    continue; // if an item is collapsed, avoid adding the spacing
                }

                if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
                {
                    // next row!
                    position.U  = paddingStart.U;
                    position.V += currentV + spacingMeasure.V;
                    currentV    = 0;
                }

                // place the item
                if (Orientation == Orientation.Horizontal)
                {
                    child.Arrange(new Rect(position.U, position.V, child.DesiredSize.Width, child.DesiredSize.Height));
                }
                else
                {
                    child.Arrange(new Rect(position.V, position.U, child.DesiredSize.Width, child.DesiredSize.Height));
                }

                // adjust the location for the next items
                position.U += desiredMeasure.U + spacingMeasure.U;
                currentV    = Math.Max(desiredMeasure.V, currentV);
            }

            return(finalSize);
        }
Beispiel #7
0
 public Row(List <UvRect> childrenRects, UvMeasure size)
 {
     ChildrenRects = childrenRects;
     Size          = size;
 }
Beispiel #8
0
 public UvMeasure Add(UvMeasure measure)
 => Add(measure.U, measure.V);
Beispiel #9
0
        private Size UpdateRows(Size availableSize)
        {
            _rows.Clear();

            var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top);
            var paddingEnd   = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);

            if (Children.Count == 0)
            {
                var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation);
                return(emptySize);
            }

            var parentMeasure  = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
            var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var position       = new UvMeasure(Orientation, Padding.Left, Padding.Top);

            var currentRow   = new Row(new List <UvRect>(), default);
            var finalMeasure = new UvMeasure(Orientation, width: 0.0, height: 0.0);

            void Arrange(UIElement child, bool isLast = false)
            {
                if (child.Visibility == Visibility.Collapsed)
                {
                    return; // if an item is collapsed, avoid adding the spacing
                }

                var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize);

                if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
                {
                    // next row!
                    position.U  = paddingStart.U;
                    position.V += currentRow.Size.V + spacingMeasure.V;

                    _rows.Add(currentRow);
                    currentRow = new Row(new List <UvRect>(), default);
                }

                // Stretch the last item to fill the available space
                if (isLast)
                {
                    desiredMeasure.U = parentMeasure.U - position.U;
                }

                currentRow.Add(position, desiredMeasure);

                // adjust the location for the next items
                position.U    += desiredMeasure.U + spacingMeasure.U;
                finalMeasure.U = Math.Max(finalMeasure.U, position.U);
            }

            var lastIndex = Children.Count - 1;

            for (var i = 0; i < lastIndex; i++)
            {
                Arrange(Children[i]);
            }

            Arrange(Children[lastIndex], StretchChild == StretchChild.Last);
            if (currentRow.ChildrenRects.Count > 0)
            {
                _rows.Add(currentRow);
            }

            if (_rows.Count == 0)
            {
                var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation);
                return(emptySize);
            }

            // Get max V here before computing final rect
            var lastRowRect = _rows.Last().Rect;

            finalMeasure.V = lastRowRect.Position.V + lastRowRect.Size.V;
            var finalRect = finalMeasure.Add(paddingEnd).ToSize(Orientation);

            return(finalRect);
        }
        /// <inheritdoc />
        protected override Size ArrangeOverride(VirtualizingLayoutContext context, Size finalSize)
        {
            if (context.ItemCount > 0)
            {
                var parentMeasure     = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
                var spacingMeasure    = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
                var realizationBounds = new UvBounds(Orientation, context.RealizationRect);

                var state = (WrapLayoutState)context.LayoutState;
                bool Arrange(WrapItem item, bool isLast = false)
                {
                    if (item.Measure.HasValue == false)
                    {
                        return(false);
                    }

                    if (item.Position == null)
                    {
                        return(false);
                    }

                    var desiredMeasure = item.Measure.Value;

                    if (desiredMeasure.U == 0)
                    {
                        return(true); // if an item is collapsed, avoid adding the spacing
                    }

                    UvMeasure position = item.Position.Value;

                    // Stretch the last item to fill the available space
                    if (isLast)
                    {
                        desiredMeasure.U = parentMeasure.U - position.U;
                    }

                    if (((position.V + desiredMeasure.V) >= realizationBounds.VMin) && (position.V <= realizationBounds.VMax))
                    {
                        // place the item
                        UIElement child = context.GetOrCreateElementAt(item.Index);
                        if (Orientation == Orientation.Horizontal)
                        {
                            child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V));
                        }
                        else
                        {
                            child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U));
                        }
                    }
                    else if (position.V > realizationBounds.VMax)
                    {
                        return(false);
                    }

                    return(true);
                }

                for (var i = 0; i < context.ItemCount; i++)
                {
                    bool continueArranging = Arrange(state.GetItemAt(i));
                    if (continueArranging == false)
                    {
                        break;
                    }
                }
            }

            return(finalSize);
        }
        /// <inheritdoc />
        protected override Size MeasureOverride(VirtualizingLayoutContext context, Size availableSize)
        {
            var totalMeasure      = UvMeasure.Zero;
            var parentMeasure     = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
            var spacingMeasure    = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var realizationBounds = new UvBounds(Orientation, context.RealizationRect);
            var position          = UvMeasure.Zero;

            var state = (WrapLayoutState)context.LayoutState;

            if (state.Orientation != Orientation)
            {
                state.SetOrientation(Orientation);
            }

            if (spacingMeasure.Equals(state.Spacing) == false)
            {
                state.ClearPositions();
                state.Spacing = spacingMeasure;
            }

            if (state.AvailableU != parentMeasure.U)
            {
                state.ClearPositions();
                state.AvailableU = parentMeasure.U;
            }

            double currentV = 0;

            for (int i = 0; i < context.ItemCount; i++)
            {
                bool     measured = false;
                WrapItem item     = state.GetItemAt(i);
                if (item.Measure == null)
                {
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(availableSize);
                    item.Measure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
                    measured     = true;
                }

                UvMeasure currentMeasure = item.Measure.Value;
                if (currentMeasure.U == 0)
                {
                    continue; // ignore collapsed items
                }

                if (item.Position == null)
                {
                    if (parentMeasure.U < position.U + currentMeasure.U)
                    {
                        // New Row
                        position.U  = 0;
                        position.V += currentV + spacingMeasure.V;
                        currentV    = 0;
                    }

                    item.Position = position;
                }

                position = item.Position.Value;

                double vEnd = position.V + currentMeasure.V;
                if (vEnd < realizationBounds.VMin)
                {
                    // Item is "above" the bounds
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }
                }
                else if (position.V > realizationBounds.VMax)
                {
                    // Item is "below" the bounds.
                    if (item.Element != null)
                    {
                        context.RecycleElement(item.Element);
                        item.Element = null;
                    }

                    // We don't need to measure anything below the bounds
                    break;
                }
                else if (measured == false)
                {
                    // Always measure elements that are within the bounds
                    item.Element = context.GetOrCreateElementAt(i);
                    item.Element.Measure(availableSize);

                    currentMeasure = new UvMeasure(Orientation, item.Element.DesiredSize.Width, item.Element.DesiredSize.Height);
                    if (currentMeasure.Equals(item.Measure) == false)
                    {
                        // this item changed size; we need to recalculate layout for everything after this
                        state.RemoveFromIndex(i + 1);
                        item.Measure = currentMeasure;

                        // did the change make it go into the new row?
                        if (parentMeasure.U < position.U + currentMeasure.U)
                        {
                            // New Row
                            position.U  = 0;
                            position.V += currentV + spacingMeasure.V;
                            currentV    = 0;
                        }

                        item.Position = position;
                    }
                }

                position.U += currentMeasure.U + spacingMeasure.U;
                currentV    = Math.Max(currentMeasure.V, currentV);
            }

            // update value with the last line
            // if the the last loop is(parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it
            // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
            // for the last condition it is zeros so adding it will make no difference
            // this way is faster than an if condition in every loop for checking the last item
            totalMeasure.U = parentMeasure.U;

            // Propagating an infinite size causes a crash. This can happen if the parent is scrollable and infinite in the opposite
            // axis to the panel. Clearing to zero prevents the crash.
            // This is likely an incorrect use of the control by the developer, however we need stability here so setting a default that wont crash.
            if (double.IsInfinity(totalMeasure.U))
            {
                totalMeasure.U = 0.0;
            }

            totalMeasure.V = state.GetHeight();

            totalMeasure.U = Math.Ceiling(totalMeasure.U);
            return(Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U));
        }