void TabView::UpdateTabWidths()

in dev/TabView/TabView.cpp [955:1123]


void TabView::UpdateTabWidths(bool shouldUpdateWidths, bool fillAllAvailableSpace)
{
    double tabWidth = std::numeric_limits<double>::quiet_NaN();

    if (auto&& tabGrid = m_tabContainerGrid.get())
    {
        // Add up width taken by custom content and + button
        double widthTaken = 0.0;
        if (auto&& leftContentColumn = m_leftContentColumn.get())
        {
            widthTaken += leftContentColumn.ActualWidth();
        }
        if (auto&& addButtonColumn = m_addButtonColumn.get())
        {
            widthTaken += addButtonColumn.ActualWidth();
        }
        if (auto&& rightContentColumn = m_rightContentColumn.get())
        {
            if (auto&& rightContentPresenter = m_rightContentPresenter.get())
            {
                const winrt::Size rightContentSize = rightContentPresenter.DesiredSize();
                rightContentColumn.MinWidth(rightContentSize.Width);
                widthTaken += rightContentSize.Width;
            }
        }

        if (auto&& tabColumn = m_tabColumn.get())
        {
            // Note: can be infinite
            const auto availableWidth = previousAvailableSize.Width - widthTaken;

            // Size can be 0 when window is first created; in that case, skip calculations; we'll get a new size soon
            if (availableWidth > 0)
            {
                if (TabWidthMode() == winrt::TabViewWidthMode::Equal)
                {

                    auto const minTabWidth = unbox_value<double>(SharedHelpers::FindInApplicationResources(c_tabViewItemMinWidthName, box_value(c_tabMinimumWidth)));
                    auto const maxTabWidth = unbox_value<double>(SharedHelpers::FindInApplicationResources(c_tabViewItemMaxWidthName, box_value(c_tabMaximumWidth)));

                    // If we should fill all of the available space, use scrollviewer dimensions
                    auto const padding = Padding();

                    double headerWidth = 0.0;
                    double footerWidth = 0.0;
                    if (auto&& itemsPresenter = m_itemsPresenter.get())
                    {
                        if (auto const header = itemsPresenter.Header().try_as<winrt::FrameworkElement>())
                        {
                            headerWidth = header.ActualWidth();
                        }
                        if (auto const footer = itemsPresenter.Footer().try_as<winrt::FrameworkElement>())
                        {
                            footerWidth = footer.ActualWidth();
                        }
                    }

                    if (fillAllAvailableSpace)
                    {
                        // Calculate the proportional width of each tab given the width of the ScrollViewer.
                        auto const tabWidthForScroller = (availableWidth - (padding.Left + padding.Right + headerWidth + footerWidth)) / (double)(TabItems().Size());
                        tabWidth = std::clamp(tabWidthForScroller, minTabWidth, maxTabWidth);
                    }
                    else
                    {
                        double availableTabViewSpace = (tabColumn.ActualWidth() - (padding.Left + padding.Right + headerWidth + footerWidth));
                        if (const auto increaseButton = m_scrollIncreaseButton.get())
                        {
                            if (increaseButton.Visibility() == winrt::Visibility::Visible)
                            {
                                availableTabViewSpace -= increaseButton.ActualWidth();
                            }
                        }

                        if (const auto decreaseButton = m_scrollDecreaseButton.get())
                        {
                            if (decreaseButton.Visibility() == winrt::Visibility::Visible)
                            {
                                availableTabViewSpace -= decreaseButton.ActualWidth();
                            }
                        }

                        // Use current size to update items to fill the currently occupied space
                        auto const tabWidthUnclamped = availableTabViewSpace / (double)(TabItems().Size());
                        tabWidth = std::clamp(tabWidthUnclamped, minTabWidth, maxTabWidth);
                    }


                    // Size tab column to needed size
                    tabColumn.MaxWidth(availableWidth + headerWidth + footerWidth);
                    auto requiredWidth = tabWidth * TabItems().Size() + headerWidth + footerWidth;
                    if (requiredWidth > availableWidth - (padding.Left + padding.Right))
                    {
                        tabColumn.Width(winrt::GridLengthHelper::FromPixels(availableWidth));
                        if (auto&& listview = m_listView.get())
                        {
                            winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Visible);
                            UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
                        }
                    }
                    else
                    {
                        tabColumn.Width(winrt::GridLengthHelper::FromValueAndType(1.0, winrt::GridUnitType::Auto));
                        if (auto&& listview = m_listView.get())
                        {
                            if (shouldUpdateWidths && fillAllAvailableSpace)
                            {
                                winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Hidden);
                            }
                            else
                            {
                                if (auto&& decreaseButton = m_scrollDecreaseButton.get())
                                {
                                    decreaseButton.IsEnabled(false);
                                }
                                if (auto&& increaseButton = m_scrollIncreaseButton.get())
                                {
                                    increaseButton.IsEnabled(false);
                                }
                            }
                        }
                    }
                }
                else
                {
                    // Case: TabWidthMode "Compact" or "FitToContent"
                    tabColumn.MaxWidth(availableWidth);
                    tabColumn.Width(winrt::GridLengthHelper::FromValueAndType(1.0, winrt::GridUnitType::Auto));
                    if (auto&& listview = m_listView.get())
                    {
                        listview.MaxWidth(availableWidth);

                        // Calculate if the scroll buttons should be visible.
                        if (auto&& itemsPresenter = m_itemsPresenter.get())
                        {
                            const auto visible = itemsPresenter.ActualWidth() > availableWidth;
                            winrt::FxScrollViewer::SetHorizontalScrollBarVisibility(listview, visible
                                ? winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Visible
                                : winrt::Windows::UI::Xaml::Controls::ScrollBarVisibility::Hidden);
                            if (visible)
                            {
                                UpdateScrollViewerDecreaseAndIncreaseButtonsViewState();
                            }
                        }
                    }
                }
            }
        }
    }


    if (shouldUpdateWidths || TabWidthMode() != winrt::TabViewWidthMode::Equal)
    {
        for (auto item : TabItems())
        {
            // Set the calculated width on each tab.
            auto tvi = item.try_as<winrt::TabViewItem>();
            if (!tvi)
            {
                tvi = ContainerFromItem(item).as<winrt::TabViewItem>();
            }

            if (tvi)
            {
                tvi.Width(tabWidth);
            }
        }
    }
}