private/Controls/New-ColumnVisibilityPopup.ps1

function New-ColumnVisibilityPopup {
    <#
    .SYNOPSIS
        Creates a popup button for toggling DataGrid column visibility.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Windows.Controls.DataGrid]$DataGrid,

        [Parameter(Mandatory)]
        [string[]]$DefaultProperties,

        [Parameter(Mandatory)]
        [string[]]$AllProperties,

        [string[]]$PopulatedProperties
    )

    $colors = Get-ThemeColors

    $colButton = [System.Windows.Controls.Button]@{
        Content = [System.Windows.Controls.TextBlock]@{
            Text       = [PsUi.ModuleContext]::GetIcon('AllApps')
            FontFamily = [System.Windows.Media.FontFamily]::new('Segoe MDL2 Assets')
        }
        Padding = 0
        Width   = 32
        Height  = 32
        ToolTip = 'Show/Hide Columns'
        Margin  = [System.Windows.Thickness]::new(0, 0, 4, 0)
    }
    Set-ButtonStyle -Button $colButton -IconOnly

    $popup = [System.Windows.Controls.Primitives.Popup]@{
        PlacementTarget    = $colButton
        Placement          = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
        StaysOpen          = $false
        AllowsTransparency = $true
    }

    $popupBorder = [System.Windows.Controls.Border]@{
        Background      = ConvertTo-UiBrush $colors.ControlBg
        BorderBrush     = ConvertTo-UiBrush $colors.Border
        BorderThickness = [System.Windows.Thickness]::new(1)
        Padding         = [System.Windows.Thickness]::new(8)
        CornerRadius    = [System.Windows.CornerRadius]::new(4)
        Tag             = 'PopupBorder'
        MaxHeight       = 400
        Effect          = [System.Windows.Media.Effects.DropShadowEffect]@{
            BlurRadius  = 10
            ShadowDepth = 2
            Opacity     = 0.3
        }
    }

    $scrollViewer = [System.Windows.Controls.ScrollViewer]@{
        VerticalScrollBarVisibility   = 'Auto'
        HorizontalScrollBarVisibility = 'Disabled'
    }

    $checkStack = [System.Windows.Controls.StackPanel]@{
        Orientation = 'Vertical'
    }

    $headerLabel = [System.Windows.Controls.TextBlock]@{
        Text       = 'Visible Columns'
        FontWeight = [System.Windows.FontWeights]::SemiBold
        FontSize   = 12
        Foreground = ConvertTo-UiBrush $colors.ControlFg
        Margin     = [System.Windows.Thickness]::new(0, 0, 0, 8)
    }
    [void]$checkStack.Children.Add($headerLabel)

    # Select All / Unselect All / Default Only buttons
    $buttonPanel = [System.Windows.Controls.StackPanel]@{
        Orientation = 'Horizontal'
        Margin      = [System.Windows.Thickness]::new(0, 0, 0, 4)
    }

    $selectAllBtn = [System.Windows.Controls.Button]@{
        Content = 'All'
        FontSize = 11
        Padding = [System.Windows.Thickness]::new(6, 2, 6, 2)
        Margin  = [System.Windows.Thickness]::new(0, 0, 4, 0)
        ToolTip = 'Show all columns'
    }
    Set-ButtonStyle -Button $selectAllBtn

    $unselectAllBtn = [System.Windows.Controls.Button]@{
        Content = 'None'
        FontSize = 11
        Padding = [System.Windows.Thickness]::new(6, 2, 6, 2)
        Margin  = [System.Windows.Thickness]::new(0, 0, 4, 0)
        ToolTip = 'Hide all columns (except primary)'
    }
    Set-ButtonStyle -Button $unselectAllBtn

    $defaultOnlyBtn = [System.Windows.Controls.Button]@{
        Content = 'Default'
        FontSize = 11
        Padding = [System.Windows.Thickness]::new(6, 2, 6, 2)
        Margin  = [System.Windows.Thickness]::new(0, 0, 4, 0)
        ToolTip = 'Show only default columns'
    }
    Set-ButtonStyle -Button $defaultOnlyBtn

    $populatedBtn = [System.Windows.Controls.Button]@{
        Content = 'Has Data'
        FontSize = 11
        Padding = [System.Windows.Thickness]::new(6, 2, 6, 2)
        ToolTip = 'Show only columns with values'
    }
    Set-ButtonStyle -Button $populatedBtn

    [void]$buttonPanel.Children.Add($selectAllBtn)
    [void]$buttonPanel.Children.Add($unselectAllBtn)
    [void]$buttonPanel.Children.Add($defaultOnlyBtn)
    [void]$buttonPanel.Children.Add($populatedBtn)
    [void]$checkStack.Children.Add($buttonPanel)

    $separator = [System.Windows.Controls.Border]@{
        Height     = 1
        Background = ConvertTo-UiBrush $colors.Border
        Margin     = [System.Windows.Thickness]::new(0, 4, 0, 8)
    }
    [void]$checkStack.Children.Add($separator)

    # Track all checkboxes for Select All / Unselect All
    $allCheckboxes = [System.Collections.Generic.List[System.Windows.Controls.CheckBox]]::new()

    # Create checkbox for each property
    $isFirst = $true
    foreach ($propName in $AllProperties) {
        $checkBox = [System.Windows.Controls.CheckBox]@{
            Content    = $propName
            FontSize   = 12
            Foreground = ConvertTo-UiBrush $colors.ControlFg
            Margin     = [System.Windows.Thickness]::new(0, 2, 0, 2)
            MinWidth   = 150
        }

        # Default properties are shown initially; others start hidden
        $isDefault = $DefaultProperties -contains $propName

        # Sync checkbox state with actual column visibility
        $isVisible = $true
        foreach ($col in $DataGrid.Columns) {
            if ($col.Header -eq $propName) {
                $isVisible = ($col.Visibility -eq [System.Windows.Visibility]::Visible)
                break
            }
        }
        $checkBox.IsChecked = $isVisible

        # Store property name AND default state in tag for the event handlers
        $checkBox.Tag = @{ Name = $propName; IsDefault = $isDefault }

        # First property cannot be unchecked
        if ($isFirst) {
            $checkBox.IsEnabled = $false
            $checkBox.IsChecked = $true
            $checkBox.ToolTip   = 'Primary column cannot be hidden'
            $isFirst            = $false
        }
        else { [void]$allCheckboxes.Add($checkBox) }

        # Wire up the checked/unchecked events
        $checkBox.Add_Checked({
            $propertyName = $this.Tag.Name
            foreach ($col in $DataGrid.Columns) {
                if ($col.Header -eq $propertyName) {
                    $col.Visibility = [System.Windows.Visibility]::Visible
                    break
                }
            }
        }.GetNewClosure())

        $checkBox.Add_Unchecked({
            $propertyName = $this.Tag.Name
            foreach ($col in $DataGrid.Columns) {
                if ($col.Header -eq $propertyName) {
                    $col.Visibility = [System.Windows.Visibility]::Collapsed
                    break
                }
            }
        }.GetNewClosure())

        Set-CheckBoxStyle -CheckBox $checkBox
        [void]$checkStack.Children.Add($checkBox)
    }

    # Wire up Select All button
    $selectAllBtn.Add_Click({
        foreach ($checkbox in $allCheckboxes) {
            $checkbox.IsChecked = $true
        }
    }.GetNewClosure())

    # Wire up Unselect All button
    $unselectAllBtn.Add_Click({
        foreach ($checkbox in $allCheckboxes) {
            $checkbox.IsChecked = $false
        }
    }.GetNewClosure())

    # Wire up Default Only button
    $defaultOnlyBtn.Add_Click({
        foreach ($checkbox in $allCheckboxes) {
            $checkbox.IsChecked = $checkbox.Tag.IsDefault
        }
    }.GetNewClosure())

    # Wire up Has Data button - uses pre-computed populated properties for instant response
    $populatedSet = [System.Collections.Generic.HashSet[string]]::new(
        [string[]]$PopulatedProperties,
        [System.StringComparer]::OrdinalIgnoreCase
    )
    $populatedBtn.Add_Click({
        foreach ($checkbox in $allCheckboxes) {
            $propName = $checkbox.Tag.Name
            $checkbox.IsChecked = $populatedSet.Contains($propName)
        }
    }.GetNewClosure())

    $scrollViewer.Content = $checkStack
    $popupBorder.Child = $scrollViewer
    $popup.Child = $popupBorder
    $colButton.Tag = $popup

    $colButton.Add_Click({
        try { $popup.IsOpen = !$popup.IsOpen }
        catch {
            Write-Verbose "Failed to toggle popup: $_"
        }
    }.GetNewClosure())

    return @{ Button = $colButton; Popup = $popup }
}