Private/Interactive/Show-TBMenuArrowMultiSelect.ps1
|
function Show-TBMenuArrowMultiSelect { <# .SYNOPSIS Arrow-key multi-select menu for PS 7+ interactive terminals. .DESCRIPTION Renders menu items with checkboxes inside a box. Arrow keys move the highlight, Space toggles selection, A toggles all, Enter confirms the checked items, and Escape returns Back. .PARAMETER Title The menu title displayed above the items. .PARAMETER Options Array of option display strings. .PARAMETER IncludeBack If specified, Escape returns 'Back'. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Title, [Parameter(Mandatory = $true)] [string[]]$Options, [Parameter()] [switch]$IncludeBack ) $palette = Get-TBColorPalette $esc = [char]27 $reset = "${esc}[0m" $innerWidth = Get-TBConsoleInnerWidth $border = ([char]0x2502) # Title inside box continuation $titlePadded = (' {0}' -f $Title).PadRight($innerWidth) Write-Host (' {0}{1}{2}{3}{4}{5}{6}' -f $palette.Surface, $border, $palette.Teal, $palette.Bold, $titlePadded, $reset, ('{0}{1}{2}' -f $palette.Surface, $border, $reset)) $titleUnderline = (' {0}' -f ('-' * $Title.Length)).PadRight($innerWidth) Write-Host (' {0}{1}{2}{3}{4}{5}' -f $palette.Surface, $border, $palette.Dim, $titleUnderline, $reset, ('{0}{1}{2}' -f $palette.Surface, $border, $reset)) $anchorTop = [Console]::CursorTop $selectedIndex = 0 $itemCount = $Options.Count $checked = [bool[]]::new($itemCount) try { try { [Console]::CursorVisible = $false } catch { } # Initial render Render-TBMenuBox -Items $Options -SelectedIndex $selectedIndex -AnchorTop $anchorTop ` -Checked $checked -IncludeBack:$IncludeBack -MultiSelect while ($true) { $key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') switch ($key.VirtualKeyCode) { 38 { # Up arrow if ($selectedIndex -gt 0) { $selectedIndex-- } else { $selectedIndex = $itemCount - 1 } Render-TBMenuBox -Items $Options -SelectedIndex $selectedIndex -AnchorTop $anchorTop ` -Checked $checked -IncludeBack:$IncludeBack -MultiSelect } 40 { # Down arrow if ($selectedIndex -lt ($itemCount - 1)) { $selectedIndex++ } else { $selectedIndex = 0 } Render-TBMenuBox -Items $Options -SelectedIndex $selectedIndex -AnchorTop $anchorTop ` -Checked $checked -IncludeBack:$IncludeBack -MultiSelect } 32 { # Space - toggle checkbox $checked[$selectedIndex] = -not $checked[$selectedIndex] Render-TBMenuBox -Items $Options -SelectedIndex $selectedIndex -AnchorTop $anchorTop ` -Checked $checked -IncludeBack:$IncludeBack -MultiSelect } 13 { # Enter - confirm $result = @() for ($i = 0; $i -lt $itemCount; $i++) { if ($checked[$i]) { $result += $i } } if ($result.Count -gt 0) { return $result } # If nothing checked, do nothing (require at least one selection) } 27 { # Escape if ($IncludeBack) { return 'Back' } } 65 { # A key - toggle all $allChecked = $true for ($i = 0; $i -lt $itemCount; $i++) { if (-not $checked[$i]) { $allChecked = $false break } } $newState = -not $allChecked for ($i = 0; $i -lt $itemCount; $i++) { $checked[$i] = $newState } Render-TBMenuBox -Items $Options -SelectedIndex $selectedIndex -AnchorTop $anchorTop ` -Checked $checked -IncludeBack:$IncludeBack -MultiSelect } } } } finally { try { [Console]::CursorVisible = $true } catch { } } } |