private Size MeasureHorizontal()

in tools/Explorer/TabControl/TabPanel.cs [171:291]


        private Size MeasureHorizontal(Size availableSize)
        {
            double maxChildWidthOrHeight = 0d;
            int childCount = InternalChildren.Count;
            EnsureChildRects();

            double extentWidth = 0d;
            double[] widths = new double[childCount];  // stores the widths of the items for use in the arrange pass

            for (int i = 0; i < childCount; i++)
            {
                if (!(InternalChildren[i] is TabItem tabItem)) 
                    return new Size();

                SetDimensions(tabItem);

                tabItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                ClearDimensions(tabItem);

                // calculate the maximum child height
                maxChildWidthOrHeight = Math.Max(maxChildWidthOrHeight, Math.Ceiling(tabItem.DesiredSize.Height));

                // calculate the child width while respecting the Maximum & Minimum width constraints
                widths[i] = Math.Min(MaximumChildWidth, Math.Max(MinimumChildWidth, Math.Ceiling(tabItem.DesiredSize.Width)));

                // determines how much horizontal space we require
                extentWidth += widths[i];
            }
            maxChildWidthOrHeight = Math.Max(MinimumChildHeight, Math.Min(MaximumChildHeight, maxChildWidthOrHeight));  // observe the constraints
            _extent = new Size(extentWidth, maxChildWidthOrHeight);

            bool flag = false;
            // 1). all the children fit into the available space using there desired widths
            if (extentWidth <= availableSize.Width)
            {
                _maxVisibleItems = childCount;
                FirstVisibleIndex = 0;

                double left = 0;
                for (int i = 0; i < childCount; i++)
                {
                    _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                    left += widths[i];

                    if (InternalChildren[i] is FrameworkElement child) 
                        child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                }

                CanScrollLeftOrUp = false;
                CanScrollRightOrDown = false;

                flag = true;
            }

            // 2). all the children fit in the available space if we reduce their widths to a uniform value 
            // while staying within the MinimumChildWidth and MaximumChildWidth constraints
            if (!flag)
            {
                // make sure the width is not greater than the MaximumChildWidth constraints
                double targetWidth = Math.Min(MaximumChildWidth, availableSize.Width / childCount);

                // target width applies now if whether we can fit all items in the available space or whether we are scrolling
                if (targetWidth >= MinimumChildWidth)
                {
                    _maxVisibleItems = childCount;
                    FirstVisibleIndex = 0;

                    extentWidth = 0;
                    double left = 0;

                    for (int i = 0; i < childCount; i++)
                    {
                        extentWidth += targetWidth;
                        widths[i] = targetWidth;
                        _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                        left += widths[i];

                        if (InternalChildren[i] is FrameworkElement child) 
                            child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                    }
                    _extent = new Size(extentWidth, maxChildWidthOrHeight);

                    flag = true;

                    CanScrollLeftOrUp = false;
                    CanScrollRightOrDown = false;
                }
            }

            // 3) we can not fit all the children in the viewport, so now we will enable scrolling/virtualizing items
            if (!flag)
            {
                _maxVisibleItems = (int)Math.Floor(_viewPort.Width / MinimumChildWidth);            // calculate how many visible children we can show at once
                if (_maxVisibleItems == 0)
                    _maxVisibleItems = 1;

                double targetWidth = availableSize.Width / _maxVisibleItems;                        // calculate the new target width
                FirstVisibleIndex = _firstVisibleIndex;

                extentWidth = 0;
                double left = 0;
                for (int i = 0; i < childCount; i++)
                {
                    extentWidth += targetWidth;
                    widths[i] = targetWidth;

                    _childRects[i] = new Rect(left, 0, widths[i], maxChildWidthOrHeight);
                    left += widths[i];

                    if (InternalChildren[i] is FrameworkElement child) 
                        child.Measure(new Size(widths[i], maxChildWidthOrHeight));
                }
                _extent = new Size(extentWidth, maxChildWidthOrHeight);

                CanScrollLeftOrUp = LastVisibleIndex < childCount - 1;
                CanScrollRightOrDown = FirstVisibleIndex > 0;
            }

            return new Size(double.IsInfinity(availableSize.Width) ? _extent.Width : availableSize.Width, maxChildWidthOrHeight);
        }