Skip to content

Instantly share code, notes, and snippets.

@purplemonkeymad
Created April 8, 2019 17:18
Show Gist options
  • Select an option

  • Save purplemonkeymad/98ee05f4701246b454b16ab9ff542d98 to your computer and use it in GitHub Desktop.

Select an option

Save purplemonkeymad/98ee05f4701246b454b16ab9ff542d98 to your computer and use it in GitHub Desktop.
Arrow key menu.
function Draw-Menu {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[pscustomobject]$menuState
)
begin {
}
process {
if ($menuState.Items.count -eq 0){
return
}
# start draw
[System.Console]::CursorTop = $menuState.CursorTop
[System.Console]::CursorLeft = 0 # start on the left
Write-Verbose ([System.Console]::CursorTop)
$row = 1
$column = 1
$index = 0
foreach ($item in $menuState.Items){
if ($index -eq $menuState.Selected){
Write-Host -BackgroundColor ([system.console]::ForegroundColor) -ForegroundColor ([System.Console]::BackgroundColor) -NoNewline (
$item.PadRight($menuState.ColumnWidth)
)
} else {
Write-Host -BackgroundColor ([system.console]::BackgroundColor) -ForegroundColor ([System.Console]::ForegroundColor) -NoNewline (
$item.PadRight($menuState.ColumnWidth)
)
}
$column++
$index++
if ($column -gt $menuState.Columns){
$row++
$column = 1
Write-Host ''
}
}
Write-Verbose ([System.Console]::CursorTop)
}
end {
}
}
function Show-ChoiceConsoleMenu {
[CmdletBinding()]
param (
[String[]]$ItemList
)
begin {
# create a state object with defaults
$MenuState = New-Object pscustomobject -Property @{
CursorTop = [System.Console]::CursorTop
Selected = 0
Columns = 1
ColumnWidth = [System.Console]::BufferWidth # default
Items = $ItemList
Rows = 0 #never used but might be nice to have
}
# calculate display grid.
$ItemMaxLength = 0
foreach ( $Item in $ItemList){
$ItemMaxLength = [math]::Max($Item.length,$ItemMaxLength)
}
$ItemMaxLength++ # create a single char buffer between columns
if ($ItemMaxLength -lt [System.Console]::BufferWidth){
$MenuState.ColumnWidth = $ItemMaxLength
}
$MenuState.Columns = [int]([Math]::Max(
[Math]::Floor( ( [System.Console]::BufferWidth / $ItemMaxLength ) )
, 1 ) )
$MenuState.Rows = [int][Math]::Ceiling( ($ItemList.Count / $MenuState.Columns) )
if ( [System.Console]::CursorTop + $MenuState.Rows -ge [System.Console]::BufferHeight ) {
if ((Read-Host "No enough buffer to show menu, clear screen? (Y/n)") -match '[nN][oO]?'){
Write-Warning "Console Buffer full, menu will act funny."
} else {
Clear-Host
}
$MenuState.Cursortop = [System.Console]::CursorTop
}
}
process {
# main iteraction loop
[System.console]::CursorVisible=$false
do {
Draw-Menu $MenuState
Write-Verbose $MenuState.Selected
$CursorBottom = [System.Console]::CursorTop
$MenuKey = [System.Console]::ReadKey($true)
$MenuState = Update-MenuStateByKey -MenuState $MenuState -Key $MenuKey.Key
} while ($MenuKey.Key -ne [System.ConsoleKey]::Enter -and $MenuKey.Key -ne [System.ConsoleKey]::Escape)
# clear menu
$RowsToClear = $CursorBottom - $MenuState.CursorTop +1
[System.Console]::CursorTop = $MenuState.CursorTop
[System.Console]::CursorLeft = 0
for ($ClearRow=0;$ClearRow -lt $RowsToClear;$ClearRow++){
Write-Host (''.PadRight( [System.Console]::BufferWidth, [char]160 ) ) #nbsp
}
# move cursor back to top, to stop big gap
[System.Console]::CursorTop = $MenuState.CursorTop
[System.console]::CursorVisible=$true
}
end {
if ($MenuKey.Key -eq [System.ConsoleKey]::Enter) {
return $ItemList[$MenuState.Selected]
}
}
}
function Update-MenuStateByKey {
[CmdletBinding()]
param (
[pscustomobject]$MenuState,
[System.ConsoleKey]$Key
)
begin {
}
process {
Write-Verbose $Key
switch ($Key){
([System.ConsoleKey]::RightArrow) {
$MenuState.Selected = $MenuState.Selected + 1
}
([System.ConsoleKey]::LeftArrow) {
$MenuState.Selected = $MenuState.Selected - 1
}
([System.ConsoleKey]::UpArrow) {
$MenuState.Selected = $MenuState.Selected - $MenuState.Columns
}
([System.ConsoleKey]::DownArrow) {
$MenuState.Selected = $MenuState.Selected + $MenuState.Columns
}
}
# now do some bad value correcting
if ($MenuState.Selected -gt ($MenuState.Items.Count -1 )){
$MenuState.Selected = $MenuState.Items.Count -1 #count is 1 indexed
}
if ($MenuState.Selected -lt 0){
$MenuState.Selected = 0
}
}
end {
return $MenuState
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment