Пример #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);
        }
Пример #2
0
        /// <inheritdoc />
        protected override Size ArrangeOverride(Size finalSize)
        {
            var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
            var position      = new UvMeasure();

            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);
        }
        /// <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));
        }
 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),
     };
 }
Пример #5
0
        private RowOrColumnSizeWithCount ComputeRowOrColumnSize(UvMeasure availableSize, int startIndex, int?measuredRowOrColumnCount)    //Do not include padding. If measuredRowOrColumnCount not null, then it will use measuredRowOrColumnCounts as a tiebreaker in determining row or column allocation when within 1.1 view pixels of the max size.
        {
            if (startIndex < 0)
            {
                return(new RowOrColumnSizeWithCount()
                {
                    Count = 0, Size = new UvMeasure(Orientation, 0, 0)
                });
            }
            var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var size           = new UvMeasure(Orientation, 0, 0);
            int j            = 0;
            int visibleCount = 0;

            for (var i = startIndex; i < Children.Count; i++)
            {
                var        child      = Children[i];
                Visibility visibility = child.Visibility;
                if (visibility == Visibility.Collapsed)
                {
                    j++;
                    continue;
                }
                double spacingU = 0.0;
                if (visibleCount > 0)
                {
                    spacingU = spacingMeasure.U;
                }
                var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
                var newSizeU       = spacingU + desiredMeasure.U + size.U;
                if (visibleCount > 0 && size.U > 0 && ((measuredRowOrColumnCount != null && (newSizeU >= availableSize.U + 1.1 || (newSizeU + 1.1 > availableSize.U && j >= measuredRowOrColumnCount.Value))) || (measuredRowOrColumnCount == null && newSizeU > availableSize.U)))
                {
                    break;
                }
                size.U = newSizeU;
                size.V = Math.Max(desiredMeasure.V, size.V);
                j++;
                visibleCount++;
            }
            return(new RowOrColumnSizeWithCount()
            {
                Count = j, VisibleCount = visibleCount, Size = size
            });
        }
        /// <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 + 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);
        }
Пример #7
0
        private TotalSizeWithCount ComputeTotalSize(UvMeasure availableSize, bool useMeasuredRowOrColumnCounts)   //Do not include padding. If useMeasuredRowOrColumnCounts is true, then it will use measuredRowOrColumnCounts as a tiebreaker in determining row or column allocation when within 1.1 view pixels of the max size.
        {
            var        useMeasuredCounts = useMeasuredRowOrColumnCounts && measuredRowOrColumnCounts != null && measuredRowOrColumnCounts.Aggregate(0, (acc, val) => acc + val) == Children.Count;
            List <int> rowOrColumnCounts = new List <int>();
            int        visibleCount      = 0;
            var        spacingMeasure    = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
            var        size = new UvMeasure(Orientation, 0, 0);
            int        i    = 0;
            int        j    = 0;

            while (i < Children.Count)
            {
                int?measuredRowOrColumnCount = null;
                if (useMeasuredCounts && measuredRowOrColumnCounts != null && j < measuredRowOrColumnCounts.Count)
                {
                    measuredRowOrColumnCount = measuredRowOrColumnCounts[j];
                }
                var rowOrColumnSize = ComputeRowOrColumnSize(availableSize, i, measuredRowOrColumnCount);
                if (measuredRowOrColumnCount != null && rowOrColumnSize.Count != measuredRowOrColumnCount)
                {
                    useMeasuredCounts = false;
                }
                size.U = Math.Max(size.U, rowOrColumnSize.Size.U);
                if (i > 0)
                {
                    size.V += spacingMeasure.V;
                }
                size.V += rowOrColumnSize.Size.V;
                i      += Math.Max(rowOrColumnSize.Count, 1);
                j++;
                rowOrColumnCounts.Add(rowOrColumnSize.Count);
                visibleCount += rowOrColumnSize.VisibleCount;
            }
            return(new TotalSizeWithCount()
            {
                RowOrColumnCounts = rowOrColumnCounts, VisibleCount = visibleCount, Size = size
            });
        }
Пример #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="visibleTop"></param>
        /// <param name="visibleHeight"></param>
        /// <param name="parentWidth"></param>
        /// <param name="layoutChanged"></param>
        /// <param name="activeWindowScale"></param>
        /// <returns>Whether the range is updated</returns>
        bool UpdateActiveRange(double visibleTop, double visibleHeight, double parentWidth, bool layoutChanged, double activeWindowScale = 3)
        {
            var visibleCenter          = visibleTop + visibleHeight / 2.0;
            var halfVisibleWindowsSize = (activeWindowScale / 2.0) * visibleHeight;
            var activeTop    = visibleCenter - halfVisibleWindowsSize - RowHeight;
            var activeBottom = visibleCenter + halfVisibleWindowsSize;

            var oldFirst = FirstActive;
            var oldLast  = LastActive;

            FirstActive = -1;
            if (ItemsSource is IList)
            {
                if ((ItemsSource as IList).Count != 0)
                {
                    FirstActive = 0;
                }
                var position = new UvMeasure();
                foreach (var child in ItemsSource as IList)
                {
                    if (position.Y < activeTop) // Cannot see this row within active window
                    {
                        FirstActive = (ItemsSource as IList).IndexOf(child);
                    }
                    else // The FirstActive is found and confirmed
                    {
                        if (!layoutChanged && oldFirst == FirstActive)
                        {
                            // If the layout has not changed and we found that the top is unchanged,
                            // We immedately conclude that bottom is not changed too
                            return(false);
                        }
                    }

                    var childImage = (child as IJustifiedWrapPanelItem);
                    var childWidth = ScaledWidth(childImage, RowHeight);



                    bool newRow = position.X + childWidth > parentWidth && (position.Y != 0 || position.X != 0);
                    if (newRow)
                    {
                        // next row!
                        position.X  = childWidth;
                        position.Y += RowHeight;
                        if (position.Y > activeBottom) // Cannot see this row within active window
                        {
                            // Last row is the last active
                            LastActive = (ItemsSource as IList).IndexOf(child) - 1;
                            return(oldFirst != FirstActive || oldLast != LastActive);
                        }
                    }
                    else
                    {
                        // adjust the location for the next items
                        position.X += childWidth;
                    }
                }

                LastActive = (ItemsSource as IList).Count - 1;
            }
            else
            {
                FirstActive = LastActive = -1;
            }

            return(oldFirst != FirstActive || oldLast != LastActive);
        }
Пример #9
0
        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);
            UvMeasure availableSize  = parentMeasure;

            availableSize.U -= (paddingStart.U + paddingEnd.U);
            availableSize.V -= (paddingStart.V + paddingEnd.V);
            var    position  = new UvMeasure(Orientation, Padding.Left, Padding.Top);
            var    totalSize = ComputeTotalSize(availableSize, true);
            double desiredV  = new UvMeasure(Orientation, DesiredSize.Width, DesiredSize.Height).V;

            if (Orientation == Orientation.Horizontal)
            {
                if (VerticalContentAlignment == VerticalAlignment.Center || (VerticalContentAlignment == VerticalAlignment.Stretch && totalSize.VisibleCount <= 1))
                {
                    position.V = paddingStart.V + (parentMeasure.V - paddingStart.V - paddingEnd.V - totalSize.Size.V) / 2.0;
                }
                else if (VerticalContentAlignment == VerticalAlignment.Bottom)
                {
                    position.V = paddingStart.V + (parentMeasure.V - paddingStart.V - paddingEnd.V - totalSize.Size.V);
                }
                else if (VerticalContentAlignment == VerticalAlignment.Stretch && totalSize.VisibleCount > 1)
                {
                    spacingMeasure.V = (parentMeasure.V - paddingStart.V - paddingEnd.V - totalSize.Size.V) / ((double)(totalSize.VisibleCount - 1));
                }
            }
            else
            {
                if (HorizontalContentAlignment == HorizontalAlignment.Center || (HorizontalContentAlignment == HorizontalAlignment.Stretch && totalSize.VisibleCount <= 1))
                {
                    position.V = paddingStart.V + (parentMeasure.V - paddingStart.V - paddingEnd.V - totalSize.Size.V) / 2.0;
                }
                else if (HorizontalContentAlignment == HorizontalAlignment.Right)
                {
                    position.V = paddingStart.V + (parentMeasure.U - paddingStart.V - paddingEnd.V - totalSize.Size.V);
                }
                else if (HorizontalContentAlignment == HorizontalAlignment.Stretch && totalSize.VisibleCount > 1)
                {
                    spacingMeasure.V = (parentMeasure.V - paddingStart.V - paddingEnd.V - totalSize.Size.V) / ((double)(totalSize.VisibleCount - 1));
                }
            }
            int j = 0;
            int rowOrColumnCount = 0;
            RowOrColumnSizeWithCount rowOrColumnSize = new RowOrColumnSizeWithCount()
            {
                Count = 0, Size = new UvMeasure()
            };
            var correctedSpacingMeasure = spacingMeasure;

            for (var i = 0; i < Children.Count; i++)
            {
                var        child          = Children[i];
                Visibility visibility     = child.Visibility;
                var        desiredMeasure = visibility == Visibility.Visible ? new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height) : new UvMeasure(Orientation, 0, 0);
                if (j >= rowOrColumnSize.Count)
                {
                    correctedSpacingMeasure = spacingMeasure;
                    if (i > 0)
                    {
                        position.V += rowOrColumnSize.Size.V + correctedSpacingMeasure.V;
                    }
                    position.U      = paddingStart.U;
                    rowOrColumnSize = ComputeRowOrColumnSize(availableSize, i, measuredRowOrColumnCounts != null && rowOrColumnCount < measuredRowOrColumnCounts.Count ? (int?)measuredRowOrColumnCounts[rowOrColumnCount] : null);
                    rowOrColumnCount++;
                    j = 0;
                    if (Orientation == Orientation.Horizontal)
                    {
                        if (HorizontalContentAlignment == HorizontalAlignment.Center || (HorizontalContentAlignment == HorizontalAlignment.Stretch && rowOrColumnSize.VisibleCount <= 1))
                        {
                            position.U = paddingStart.U + (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U) / 2.0;
                        }
                        else if (HorizontalContentAlignment == HorizontalAlignment.Right)
                        {
                            position.U = paddingStart.U + (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U);
                        }
                        else if (HorizontalContentAlignment == HorizontalAlignment.Stretch && rowOrColumnSize.VisibleCount > 1)
                        {
                            correctedSpacingMeasure.U = (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U) / ((double)(rowOrColumnSize.VisibleCount - 1));
                        }
                    }
                    else
                    {
                        if (VerticalContentAlignment == VerticalAlignment.Center || (VerticalContentAlignment == VerticalAlignment.Stretch && rowOrColumnSize.VisibleCount <= 1))
                        {
                            position.U = paddingStart.U + (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U) / 2.0;
                        }
                        else if (VerticalContentAlignment == VerticalAlignment.Bottom)
                        {
                            position.U = paddingStart.U + (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U);
                        }
                        else if (VerticalContentAlignment == VerticalAlignment.Stretch && rowOrColumnSize.VisibleCount > 1)
                        {
                            correctedSpacingMeasure.U = (parentMeasure.U - paddingStart.U - paddingEnd.U - rowOrColumnSize.Size.U) / ((double)(rowOrColumnSize.VisibleCount - 1));
                        }
                    }
                }
                var correctedPosition = position;
                var correctedMeasure  = desiredMeasure;
                if (child is FrameworkElement frameworkChild)
                {
                    if (Orientation == Orientation.Horizontal)
                    {
                        if (frameworkChild.VerticalAlignment == VerticalAlignment.Center)
                        {
                            correctedPosition.V += (rowOrColumnSize.Size.V - desiredMeasure.V) / 2.0;
                        }
                        else if (frameworkChild.VerticalAlignment == VerticalAlignment.Bottom)
                        {
                            correctedPosition.V += (rowOrColumnSize.Size.V - desiredMeasure.V);
                        }
                        else if (frameworkChild.VerticalAlignment == VerticalAlignment.Stretch)
                        {
                            correctedMeasure.V = rowOrColumnSize.Size.V;
                        }
                    }
                    else
                    {
                        if (frameworkChild.HorizontalAlignment == HorizontalAlignment.Center || frameworkChild.HorizontalAlignment == HorizontalAlignment.Stretch)
                        {
                            correctedPosition.V += (rowOrColumnSize.Size.V - desiredMeasure.V) / 2.0;
                        }
                        else if (frameworkChild.HorizontalAlignment == HorizontalAlignment.Right)
                        {
                            correctedPosition.V += (rowOrColumnSize.Size.V - desiredMeasure.V);
                        }
                        else if (frameworkChild.HorizontalAlignment == HorizontalAlignment.Stretch)
                        {
                            correctedMeasure.V = rowOrColumnSize.Size.V;
                        }
                    }
                }
                child.Arrange(new Rect(correctedPosition.X, correctedPosition.Y, Math.Max(0.0, correctedMeasure.X), Math.Max(0.0, correctedMeasure.Y)));
                position.U += desiredMeasure.U;
                if (visibility != Visibility.Collapsed)
                {
                    position.U += correctedSpacingMeasure.U;
                }
                j++;
            }
            return(finalSize);
        }
        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)
            {
                var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize);

                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 += 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);
        }
Пример #11
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;

            void measure(UIElementCollection elementCollection)
            {
                foreach (UIElement child in elementCollection)
                {
                    if (child is FrameworkElement fe && fe.TemplateChild is Panel nestedPanel)
                    {
                        measure(nestedPanel.Children);
                        continue;
                    }

                    child.Measure(availableSize);
                    var currentMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
                    if (currentMeasure.U == 0)
                    {
                        continue; // ignore collapsed items
                    }

                    // if this is the first item, do not add spacing. Spacing is added to the "left"
                    double uChange = lineMeasure.U == 0
                        ? currentMeasure.U
                        : currentMeasure.U + spacingMeasure.U;
                    if (parentMeasure.U >= uChange + lineMeasure.U)
                    {
                        lineMeasure.U += uChange;
                        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;
                        }
                    }
                }
            }

            measure(Children);

            // 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));
        }
 public Row(List <UvRect> childrenRects, UvMeasure size)
 {
     ChildrenRects = childrenRects;
     Size          = size;
 }
 public UvMeasure Add(UvMeasure measure)
 => Add(measure.U, measure.V);