Gumby.ListBox.psm1
using module ScrollView class LBItemBase { [string] Name() { throw "abstract" } [object] Value() { throw "abstract" } [void] OnSelected() {} [void] OnDeselected() {} } class StringLBItem : LBItemBase { StringLBItem([string] $value) { $this._value = $value } [string] Name() { return $this._value } [string] Value() { return $this._value } hidden [string] $_value } class ListBox : ScrollView { ListBox( [int] $left, [int] $top, [int] $width, [int] $height, [System.ConsoleColor] $foregroundColor = $Global:Host.UI.RawUI.BackgroundColor, [System.ConsoleColor] $backgroundColor = $Global:Host.UI.RawUI.ForegroundColor ) : base($left, $top, $width, $height, $foregroundColor, $backgroundColor) { } ListBox( [System.Collections.IEnumerable] $items, [System.Reflection.TypeInfo] $lbItemType, [int] $left, [int] $top, [int] $width, [int] $height, [System.ConsoleColor] $foregroundColor = $Global:Host.UI.RawUI.BackgroundColor, [System.ConsoleColor] $backgroundColor = $Global:Host.UI.RawUI.ForegroundColor ) : base($left, $top, $width, $height, $foregroundColor, $backgroundColor) { $lbItems = [System.Collections.Generic.List`1[LBItemBase]]::new() foreach ($item in $items) { $lbItems.Add($lbItemType::new($item)) | Out-Null } $this.InitializeItems($lbItems) } hidden [void] InitializeItems([System.Collections.Generic.IEnumerable`1[LBItemBase]] $lbItems) { foreach ($lbItem in $lbItems) { [void]($this._items.Add($lbItem)) $this.AddLine($this.GetItemLabel($lbItem), $this.ForegroundColor(), $this.BackgroundColor()) } if ($this.ItemCount() -gt 0) { $this.SelectItem(0) } } [int] ItemCount() { return $this._items.Count } [void] AddItem([object] $item) { [void]($this._items.Add($item)) $this.AddLine($this.GetItemLabel($item), $this.ForegroundColor(), $this.BackgroundColor()) } [void] InsertItem([int] $index, [object] $item) { if ($this._selectedIndex -ne -1) { if ($index -le $this._selectedIndex) { ++$this._selectedIndex } } $this._items.Insert($index, $item) $this.InsertLine($index, $this.GetItemLabel($item), $this.ForegroundColor(), $this.BackgroundColor()) } [LBItemBase] GetItem([int] $index) { return $this._items[$index] } [void] RemoveItem([int] $index) { if ($this._selectedIndex -ne -1) { if ($index -lt $this._selectedIndex) { --$this._selectedIndex } elseif ($index -eq $this._selectedIndex) { $this._selectedIndex = -1 } } $this._items.RemoveAt($index) $this.RemoveLine($index) } [void] SelectItem([int] $index) { if ($index -ge 0) { if ($index -ne $this._selectedIndex) { if ($this._selectedIndex -ge 0) { # deselect currently selected item $this.GetLine($this._selectedIndex).ForegroundColor = $this.ForegroundColor() $this.GetLine($this._selectedIndex).BackgroundColor = $this.BackgroundColor() $this._items[$this._selectedIndex].OnDeselected() } # select new item $this.GetLine($index).ForegroundColor = $this.BackgroundColor() $this.GetLine($index).BackgroundColor = $this.ForegroundColor() $this._selectedIndex = $index $this._items[$this._selectedIndex].OnSelected() } } else { # removing selection if ($this._selectedIndex -ge 0) { # deselect currently selected item $this.GetLine($this._selectedIndex).ForegroundColor = $this.ForegroundColor() $this.GetLine($this._selectedIndex).BackgroundColor = $this.BackgroundColor() $this._items[$this._selectedIndex].OnDeselected() } $this._selectedIndex = -1 # normalizing to -1 } } [int] SelectedIndex() { return $this._selectedIndex } [LBItemBase] SelectedItem() { return $this._items[$this._selectedIndex] } hidden DrawClientArea() { ([ScrollView]$this).DrawClientArea() $si = if ($this._items.Count -gt 0) { $this._selectedIndex + 1 } else { 0 } $this.WriteStatusBar("$si/$($this._items.Count)") } hidden [void] OnKey([System.ConsoleKeyInfo] $key) { #[Log]::Comment("SVListBox.OnKey: Key=$($key.Key), Modifiers=$($key.Modifiers)") switch ($key.Key) { ([ConsoleKey]::DownArrow) { $this.MoveSelectionDown() } ([ConsoleKey]::UpArrow) { $this.MoveSelectionUp() } default { ([ScrollView]$this).OnKey($key) } } } hidden [void] MoveSelectionDown() { if ($this._items.Count -eq 0) { # empty list return } if ($this._selectedIndex -eq ($this._items.Count - 1)) { # at end of list, no change return } if (($this._selectedIndex - $this.FirstRowInView) -ge ($this.ClientHeight() - 1)) { # last line in view is selected, scroll up one line $this.ScrollAreaVertically(0, $this.ClientHeight() - 2, -1) ++$this.FirstRowInView } $previouslySelectedIndex = $this._selectedIndex $this.SelectItem($this._selectedIndex + 1) $this.DrawLine($this._selectedIndex) $this.DrawLine($previouslySelectedIndex) $this.WriteStatusBar("$($this._selectedIndex + 1)/$($this._items.Count)") } hidden [void] MoveSelectionUp() { if ($this._selectedIndex -eq 0) { # at start of list, no change # also handles empty list return } if ($this._selectedIndex -eq $this.FirstRowInView) { # first line in view is selected, scroll down one line $this.ScrollAreaVertically(1, $this.ClientHeight() - 2, 1) --$this.FirstRowInView } $previouslySelectedIndex = $this._selectedIndex $this.SelectItem($this._selectedIndex - 1) $this.DrawLine($this._selectedIndex) $this.DrawLine($previouslySelectedIndex) $this.WriteStatusBar("$($this._selectedIndex + 1)/$($this._items.Count)") } hidden [string] GetItemLabel([object]$item) { return $item.Name() } hidden [System.Collections.ICollection] $_items = ([System.Collections.ArrayList]::new()) hidden [int] $_selectedIndex = -1 } |