223 lines
5.7 KiB
Go
223 lines
5.7 KiB
Go
package termboxUtil
|
|
|
|
import (
|
|
"github.com/nsf/termbox-go"
|
|
)
|
|
|
|
// Menu is a menu with a list of options
|
|
type Menu struct {
|
|
title string
|
|
options []string
|
|
// If height is -1, then it is adaptive to the menu
|
|
x, y, width, height int
|
|
optionsDisabled []bool
|
|
optionsHelp []string
|
|
showHelp bool
|
|
cursor int
|
|
bg, fg termbox.Attribute
|
|
selectedBg, selectedFg termbox.Attribute
|
|
disabledBg, disabledFg termbox.Attribute
|
|
isDone bool
|
|
selectedOption int
|
|
bordered bool
|
|
hasFocus bool
|
|
}
|
|
|
|
// CreateMenu Creates a menu with the specified attributes
|
|
func CreateMenu(title string, options []string, x, y, width, height int, fg, bg termbox.Attribute) *Menu {
|
|
i := Menu{title: title, options: options, x: x, y: y, width: width, height: height, fg: fg, bg: bg}
|
|
for len(i.optionsDisabled) < len(i.options) {
|
|
i.optionsDisabled = append(i.optionsDisabled, false)
|
|
}
|
|
i.selectedFg = i.bg
|
|
i.selectedBg = i.fg
|
|
i.disabledFg = i.bg
|
|
i.disabledBg = i.bg
|
|
return &i
|
|
}
|
|
|
|
// GetTitle returns the current title of the menu
|
|
func (i *Menu) GetTitle() string { return i.title }
|
|
|
|
// SetTitle sets the current title of the menu to s
|
|
func (i *Menu) SetTitle(s string) *Menu {
|
|
i.title = s
|
|
return i
|
|
}
|
|
|
|
// GetOptions returns the current options of the menu
|
|
func (i *Menu) GetOptions() []string {
|
|
return i.options
|
|
}
|
|
|
|
// SetOptions set the menu's options to opts
|
|
func (i *Menu) SetOptions(opts []string) *Menu {
|
|
i.options = opts
|
|
return i
|
|
}
|
|
|
|
// SetOptionDisabled sets an option in the menu to disabled
|
|
func (i *Menu) SetOptionDisabled(idx int) *Menu {
|
|
if idx > 0 && idx < len(i.options) {
|
|
i.optionsDisabled[idx] = true
|
|
}
|
|
return i
|
|
}
|
|
|
|
// SetOptionEnabled sets an option to enabled
|
|
func (i *Menu) SetOptionEnabled(idx int) *Menu {
|
|
if idx >= 0 && idx < len(i.options) {
|
|
i.optionsDisabled[idx] = false
|
|
}
|
|
return i
|
|
}
|
|
|
|
// GetX returns the current x coordinate of the menu
|
|
func (i *Menu) GetX() int { return i.x }
|
|
|
|
// SetX sets the current x coordinate of the menu to x
|
|
func (i *Menu) SetX(x int) *Menu {
|
|
i.x = x
|
|
return i
|
|
}
|
|
|
|
// GetY returns the current y coordinate of the menu
|
|
func (i *Menu) GetY() int { return i.y }
|
|
|
|
// SetY sets the current y coordinate of the menu to y
|
|
func (i *Menu) SetY(y int) *Menu {
|
|
i.y = y
|
|
return i
|
|
}
|
|
|
|
// GetWidth returns the current width of the menu
|
|
func (i *Menu) GetWidth() int { return i.width }
|
|
|
|
// SetWidth sets the current menu width to width
|
|
func (i *Menu) SetWidth(width int) *Menu {
|
|
i.width = width
|
|
return i
|
|
}
|
|
|
|
// GetHeight returns the current height of the menu
|
|
func (i *Menu) GetHeight() int { return i.height }
|
|
|
|
// SetHeight set the height of the menu to height
|
|
func (i *Menu) SetHeight(height int) *Menu {
|
|
i.height = height
|
|
return i
|
|
}
|
|
|
|
// HelpIsShown returns true or false if the help is displayed
|
|
func (i *Menu) HelpIsShown() bool { return i.showHelp }
|
|
|
|
// ShowHelp sets whether or not to display the help text
|
|
func (i *Menu) ShowHelp(b bool) *Menu {
|
|
i.showHelp = b
|
|
return i
|
|
}
|
|
|
|
// GetBackground returns the current background color
|
|
func (i *Menu) GetBackground() termbox.Attribute { return i.bg }
|
|
|
|
// SetBackground sets the background color to bg
|
|
func (i *Menu) SetBackground(bg termbox.Attribute) *Menu {
|
|
i.bg = bg
|
|
return i
|
|
}
|
|
|
|
// GetForeground returns the current foreground color
|
|
func (i *Menu) GetForeground() termbox.Attribute { return i.fg }
|
|
|
|
// SetForeground sets the current foreground color to fg
|
|
func (i *Menu) SetForeground(fg termbox.Attribute) *Menu {
|
|
i.fg = fg
|
|
return i
|
|
}
|
|
|
|
// IsDone returns whether the user has answered the modal
|
|
func (i *Menu) IsDone() bool { return i.isDone }
|
|
|
|
// SetDone sets whether the modal has completed it's purpose
|
|
func (i *Menu) SetDone(b bool) *Menu {
|
|
i.isDone = b
|
|
return i
|
|
}
|
|
|
|
// IsBordered returns true or false if this menu has a border
|
|
func (i *Menu) IsBordered() bool { return i.bordered }
|
|
|
|
// SetBordered sets whether we render a border around the menu
|
|
func (i *Menu) SetBordered(b bool) *Menu {
|
|
i.bordered = b
|
|
return i
|
|
}
|
|
|
|
// HandleKeyPress handles the termbox event and returns whether it was consumed
|
|
func (i *Menu) HandleKeyPress(event termbox.Event) bool {
|
|
if i.hasFocus {
|
|
if event.Key == termbox.KeyEnter {
|
|
i.isDone = true
|
|
return true
|
|
}
|
|
switch event.Key {
|
|
case termbox.KeyArrowUp:
|
|
if i.selectedOption > 0 {
|
|
i.selectedOption--
|
|
return true
|
|
}
|
|
case termbox.KeyArrowDown:
|
|
if i.selectedOption < len(i.options) {
|
|
i.selectedOption++
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Draw draws the modal
|
|
func (i *Menu) Draw() {
|
|
// First blank out the area we'll be putting the menu
|
|
FillWithChar(' ', i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
|
// Now draw the border
|
|
optionStartX := i.x
|
|
optionStartY := i.y
|
|
optionWidth := i.width
|
|
optionHeight := i.height
|
|
if optionHeight == -1 {
|
|
optionHeight = len(i.options)
|
|
}
|
|
if i.bordered {
|
|
if i.height == -1 {
|
|
DrawBorder(i.x, i.y, i.x+i.width, i.y+optionHeight+1, i.fg, i.bg)
|
|
} else {
|
|
DrawBorder(i.x, i.y, i.x+i.width, i.y+optionHeight, i.fg, i.bg)
|
|
}
|
|
optionStartX = i.x + 1
|
|
optionStartY = i.y + 1
|
|
optionWidth = i.width - 2
|
|
}
|
|
|
|
// The title
|
|
if i.title != "" {
|
|
DrawStringAtPoint(AlignText(i.title, optionWidth, AlignCenter), optionStartX, optionStartY, i.fg, i.bg)
|
|
optionStartY++
|
|
if i.bordered {
|
|
FillWithChar('-', optionStartX, optionStartY, optionWidth, optionStartY, i.fg, i.bg)
|
|
optionStartY++
|
|
}
|
|
}
|
|
|
|
// Print the options
|
|
for idx, opt := range i.options {
|
|
if i.optionsDisabled[idx] {
|
|
DrawStringAtPoint(opt, optionStartX, optionStartY, i.disabledFg, i.disabledBg)
|
|
} else if i.selectedOption == idx {
|
|
DrawStringAtPoint(opt, optionStartX, optionStartY, i.selectedFg, i.selectedBg)
|
|
} else {
|
|
DrawStringAtPoint(opt, optionStartX, optionStartY, i.fg, i.bg)
|
|
}
|
|
}
|
|
}
|