mirror of
https://github.com/br0xen/termbox-util.git
synced 2024-11-22 21:43:14 +00:00
Added a few more controls
* Menus! * Progress bars! * Ascii Art!
This commit is contained in:
parent
5390cfa85a
commit
55e193ace2
109
termbox_asciiart.go
Normal file
109
termbox_asciiart.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package termboxUtil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ASCIIArt is a []string with more functions
|
||||||
|
type ASCIIArt struct {
|
||||||
|
contents []string
|
||||||
|
x, y int
|
||||||
|
bg, fg termbox.Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateASCIIArt Create an ASCII art object from a string slice
|
||||||
|
func CreateASCIIArt(c []string, x, y int, fg, bg termbox.Attribute) *ASCIIArt {
|
||||||
|
i := ASCIIArt{contents: c, x: x, y: y, fg: fg, bg: bg}
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetX Return the x position of the modal
|
||||||
|
func (i *ASCIIArt) GetX() int { return i.x }
|
||||||
|
|
||||||
|
// SetX set the x position of the modal to x
|
||||||
|
func (i *ASCIIArt) SetX(x int) *ASCIIArt {
|
||||||
|
i.x = x
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetY Return the y position of the modal
|
||||||
|
func (i *ASCIIArt) GetY() int { return i.y }
|
||||||
|
|
||||||
|
// SetY Set the y position of the modal to y
|
||||||
|
func (i *ASCIIArt) SetY(y int) *ASCIIArt {
|
||||||
|
i.y = y
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight Returns the number of strings in the contents slice
|
||||||
|
func (i *ASCIIArt) GetHeight() int {
|
||||||
|
return len(i.contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContents Sets the contents of i to c
|
||||||
|
func (i *ASCIIArt) SetContents(c []string) *ASCIIArt {
|
||||||
|
i.contents = c
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContents returns the ascii art
|
||||||
|
func (i *ASCIIArt) GetContents() []string {
|
||||||
|
return i.contents
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContentLine Sets a specific line of the contents to s
|
||||||
|
func (i *ASCIIArt) SetContentLine(s string, idx int) *ASCIIArt {
|
||||||
|
if idx >= 0 && idx < len(i.contents) {
|
||||||
|
i.contents[idx] = s
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBackground Return the current background color of the modal
|
||||||
|
func (i *ASCIIArt) GetBackground() termbox.Attribute { return i.bg }
|
||||||
|
|
||||||
|
// SetBackground Set the current background color to bg
|
||||||
|
func (i *ASCIIArt) SetBackground(bg termbox.Attribute) *ASCIIArt {
|
||||||
|
i.bg = bg
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForeground Return the current foreground color
|
||||||
|
func (i *ASCIIArt) GetForeground() termbox.Attribute { return i.fg }
|
||||||
|
|
||||||
|
// SetForeground Set the foreground color to fg
|
||||||
|
func (i *ASCIIArt) SetForeground(fg termbox.Attribute) *ASCIIArt {
|
||||||
|
i.fg = fg
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align Align the Ascii art over width width with alignment a
|
||||||
|
func (i *ASCIIArt) Align(a TextAlignment, width int) *ASCIIArt {
|
||||||
|
// First get the width of the longest string in the slice
|
||||||
|
var newContents []string
|
||||||
|
incomingLength := 0
|
||||||
|
for _, line := range i.contents {
|
||||||
|
if len(line) > incomingLength {
|
||||||
|
incomingLength = len(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, line := range i.contents {
|
||||||
|
newContents = append(newContents, AlignText(AlignText(line, incomingLength, AlignLeft), width, a))
|
||||||
|
}
|
||||||
|
i.contents = newContents
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleKeyPress accepts the termbox event and returns whether it was consumed
|
||||||
|
func (i *ASCIIArt) HandleKeyPress(event termbox.Event) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw outputs the input field on the screen
|
||||||
|
func (i *ASCIIArt) Draw() {
|
||||||
|
drawX, drawY := i.x, i.y
|
||||||
|
for _, line := range i.contents {
|
||||||
|
DrawStringAtPoint(line, drawX, drawY, i.fg, i.bg)
|
||||||
|
drawY++
|
||||||
|
}
|
||||||
|
}
|
395
termbox_menu.go
Normal file
395
termbox_menu.go
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
package termboxUtil
|
||||||
|
|
||||||
|
import "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
// Menu is a menu with a list of options
|
||||||
|
type Menu struct {
|
||||||
|
title string
|
||||||
|
options []MenuOption
|
||||||
|
// If height is -1, then it is adaptive to the menu
|
||||||
|
x, y, width, height int
|
||||||
|
showHelp bool
|
||||||
|
cursor int
|
||||||
|
bg, fg termbox.Attribute
|
||||||
|
selectedBg, selectedFg termbox.Attribute
|
||||||
|
disabledBg, disabledFg termbox.Attribute
|
||||||
|
isDone bool
|
||||||
|
bordered bool
|
||||||
|
vimMode 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,
|
||||||
|
x: x, y: y, width: width, height: height,
|
||||||
|
fg: fg, bg: bg, selectedFg: bg, selectedBg: fg,
|
||||||
|
disabledFg: bg, disabledBg: bg,
|
||||||
|
}
|
||||||
|
for _, line := range options {
|
||||||
|
i.options = append(i.options, MenuOption{text: line})
|
||||||
|
}
|
||||||
|
if len(i.options) > 0 {
|
||||||
|
i.SetSelectedOption(&i.options[0])
|
||||||
|
}
|
||||||
|
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() []MenuOption {
|
||||||
|
return i.options
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOptions set the menu's options to opts
|
||||||
|
func (i *Menu) SetOptions(opts []MenuOption) *Menu {
|
||||||
|
i.options = opts
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOptionsFromStrings sets the options of this menu from a slice of strings
|
||||||
|
func (i *Menu) SetOptionsFromStrings(opts []string) *Menu {
|
||||||
|
var newOpts []MenuOption
|
||||||
|
for _, v := range opts {
|
||||||
|
newOpts = append(newOpts, *CreateOptionFromText(v))
|
||||||
|
}
|
||||||
|
return i.SetOptions(newOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelectedOption returns the current selected option
|
||||||
|
func (i *Menu) GetSelectedOption() *MenuOption {
|
||||||
|
idx := i.GetSelectedIndex()
|
||||||
|
if idx != -1 {
|
||||||
|
return &i.options[idx]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOptionFromIndex Returns the
|
||||||
|
func (i *Menu) GetOptionFromIndex(idx int) *MenuOption {
|
||||||
|
if idx >= 0 && idx < len(i.options) {
|
||||||
|
return &i.options[idx]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOptionFromText Returns the first option with the text v
|
||||||
|
func (i *Menu) GetOptionFromText(v string) *MenuOption {
|
||||||
|
for idx := range i.options {
|
||||||
|
testOption := &i.options[idx]
|
||||||
|
if testOption.GetText() == v {
|
||||||
|
return testOption
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSelectedIndex returns the index of the selected option
|
||||||
|
// Returns -1 if nothing is selected
|
||||||
|
func (i *Menu) GetSelectedIndex() int {
|
||||||
|
for idx := range i.options {
|
||||||
|
if i.options[idx].IsSelected() {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSelectedOption sets the current selected option to v (if it's valid)
|
||||||
|
func (i *Menu) SetSelectedOption(v *MenuOption) *Menu {
|
||||||
|
for idx := range i.options {
|
||||||
|
if &i.options[idx] == v {
|
||||||
|
i.options[idx].Select()
|
||||||
|
} else {
|
||||||
|
i.options[idx].Unselect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPrevOption Decrements the selected option (if it can)
|
||||||
|
func (i *Menu) SelectPrevOption() *Menu {
|
||||||
|
idx := i.GetSelectedIndex()
|
||||||
|
for idx >= 0 {
|
||||||
|
idx--
|
||||||
|
testOption := i.GetOptionFromIndex(idx)
|
||||||
|
if testOption != nil && !testOption.IsDisabled() {
|
||||||
|
i.SetSelectedOption(testOption)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectNextOption Increments the selected option (if it can)
|
||||||
|
func (i *Menu) SelectNextOption() *Menu {
|
||||||
|
idx := i.GetSelectedIndex()
|
||||||
|
for idx < len(i.options) {
|
||||||
|
idx++
|
||||||
|
testOption := i.GetOptionFromIndex(idx)
|
||||||
|
if testOption != nil && !testOption.IsDisabled() {
|
||||||
|
i.SetSelectedOption(testOption)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOptionDisabled Disables the specified option
|
||||||
|
func (i *Menu) SetOptionDisabled(idx int) {
|
||||||
|
if len(i.options) > idx {
|
||||||
|
i.GetOptionFromIndex(idx).Disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOptionEnabled Enables the specified option
|
||||||
|
func (i *Menu) SetOptionEnabled(idx int) {
|
||||||
|
if len(i.options) > idx {
|
||||||
|
i.GetOptionFromIndex(idx).Enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableVimMode Enables h,j,k,l navigation
|
||||||
|
func (i *Menu) EnableVimMode() *Menu {
|
||||||
|
i.vimMode = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableVimMode Disables h,j,k,l navigation
|
||||||
|
func (i *Menu) DisableVimMode() *Menu {
|
||||||
|
i.vimMode = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleKeyPress handles the termbox event and returns whether it was consumed
|
||||||
|
func (i *Menu) HandleKeyPress(event termbox.Event) bool {
|
||||||
|
if event.Key == termbox.KeyEnter {
|
||||||
|
i.isDone = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
currentIdx := i.GetSelectedIndex()
|
||||||
|
switch event.Key {
|
||||||
|
case termbox.KeyArrowUp:
|
||||||
|
i.SelectPrevOption()
|
||||||
|
case termbox.KeyArrowDown:
|
||||||
|
i.SelectNextOption()
|
||||||
|
}
|
||||||
|
if i.vimMode {
|
||||||
|
switch event.Ch {
|
||||||
|
case 'j':
|
||||||
|
i.SelectNextOption()
|
||||||
|
case 'k':
|
||||||
|
i.SelectPrevOption()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i.GetSelectedIndex() != currentIdx {
|
||||||
|
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 - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if len(i.options) > 0 {
|
||||||
|
for idx := range i.options {
|
||||||
|
currOpt := &i.options[idx]
|
||||||
|
if currOpt.IsDisabled() {
|
||||||
|
DrawStringAtPoint(currOpt.GetText(), optionStartX, optionStartY, i.disabledFg, i.disabledBg)
|
||||||
|
} else if i.GetSelectedOption() == currOpt {
|
||||||
|
DrawStringAtPoint(AlignText(currOpt.GetText(), optionWidth, AlignLeft), optionStartX, optionStartY, i.selectedFg, i.selectedBg)
|
||||||
|
} else {
|
||||||
|
DrawStringAtPoint(currOpt.GetText(), optionStartX, optionStartY, i.fg, i.bg)
|
||||||
|
}
|
||||||
|
optionStartY++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MenuOption Struct & methods */
|
||||||
|
|
||||||
|
// MenuOption An option in the menu
|
||||||
|
type MenuOption struct {
|
||||||
|
text string
|
||||||
|
selected bool
|
||||||
|
disabled bool
|
||||||
|
helpText string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptionFromText just returns a MenuOption object
|
||||||
|
// That only has it's text value set.
|
||||||
|
func CreateOptionFromText(s string) *MenuOption {
|
||||||
|
return &MenuOption{text: s}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetText Sets the text for this option
|
||||||
|
func (i *MenuOption) SetText(s string) *MenuOption {
|
||||||
|
i.text = s
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetText Returns the text for this option
|
||||||
|
func (i *MenuOption) GetText() string { return i.text }
|
||||||
|
|
||||||
|
// Disable Sets this option to disabled
|
||||||
|
func (i *MenuOption) Disable() *MenuOption {
|
||||||
|
i.disabled = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable Sets this option to enabled
|
||||||
|
func (i *MenuOption) Enable() *MenuOption {
|
||||||
|
i.disabled = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDisabled returns whether this option is enabled
|
||||||
|
func (i *MenuOption) IsDisabled() bool {
|
||||||
|
return i.disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSelected Returns whether this option is selected
|
||||||
|
func (i *MenuOption) IsSelected() bool {
|
||||||
|
return i.selected
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select Sets this option to selected
|
||||||
|
func (i *MenuOption) Select() *MenuOption {
|
||||||
|
i.selected = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unselect Sets this option to not selected
|
||||||
|
func (i *MenuOption) Unselect() *MenuOption {
|
||||||
|
i.selected = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHelpText Sets this option's help text to s
|
||||||
|
func (i *MenuOption) SetHelpText(s string) *MenuOption {
|
||||||
|
i.helpText = s
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHelpText Returns the help text for this option
|
||||||
|
func (i *MenuOption) GetHelpText() string { return i.helpText }
|
224
termbox_progressbar.go
Normal file
224
termbox_progressbar.go
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
package termboxUtil
|
||||||
|
|
||||||
|
import "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
// ProgressBar Just contains the data needed to display a progress bar
|
||||||
|
type ProgressBar struct {
|
||||||
|
total int
|
||||||
|
progress int
|
||||||
|
allowOverflow bool
|
||||||
|
allowUnderflow bool
|
||||||
|
fullChar rune
|
||||||
|
emptyChar rune
|
||||||
|
bordered bool
|
||||||
|
alignment TextAlignment
|
||||||
|
|
||||||
|
x, y int
|
||||||
|
width, height int
|
||||||
|
bg, fg termbox.Attribute
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProgressBar Create a progress bar object
|
||||||
|
func CreateProgressBar(tot, x, y int, fg, bg termbox.Attribute) *ProgressBar {
|
||||||
|
i := ProgressBar{total: tot,
|
||||||
|
fullChar: '#', emptyChar: ' ',
|
||||||
|
x: x, y: y, height: 1, width: 10,
|
||||||
|
bordered: true, fg: fg, bg: bg,
|
||||||
|
alignment: AlignLeft,
|
||||||
|
}
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProgress returns the curret progress value
|
||||||
|
func (i *ProgressBar) GetProgress() int {
|
||||||
|
return i.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProgress sets the current progress of the bar
|
||||||
|
func (i *ProgressBar) SetProgress(p int) *ProgressBar {
|
||||||
|
if (p <= i.total || i.allowOverflow) || (p >= 0 || i.allowUnderflow) {
|
||||||
|
i.progress = p
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncrProgress increments the current progress of the bar
|
||||||
|
func (i *ProgressBar) IncrProgress() *ProgressBar {
|
||||||
|
if i.progress < i.total || i.allowOverflow {
|
||||||
|
i.progress++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecrProgress decrements the current progress of the bar
|
||||||
|
func (i *ProgressBar) DecrProgress() *ProgressBar {
|
||||||
|
if i.progress > 0 || i.allowUnderflow {
|
||||||
|
i.progress--
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPercent returns the percent full of the bar
|
||||||
|
func (i *ProgressBar) GetPercent() int {
|
||||||
|
return int(float64(i.progress) / float64(i.total) * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableOverflow Tells the progress bar that it can go over the total
|
||||||
|
func (i *ProgressBar) EnableOverflow() *ProgressBar {
|
||||||
|
i.allowOverflow = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableOverflow Tells the progress bar that it can NOT go over the total
|
||||||
|
func (i *ProgressBar) DisableOverflow() *ProgressBar {
|
||||||
|
i.allowOverflow = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableUnderflow Tells the progress bar that it can go below zero
|
||||||
|
func (i *ProgressBar) EnableUnderflow() *ProgressBar {
|
||||||
|
i.allowUnderflow = true
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableUnderflow Tells the progress bar that it can NOT go below zero
|
||||||
|
func (i *ProgressBar) DisableUnderflow() *ProgressBar {
|
||||||
|
i.allowUnderflow = false
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFullChar returns the rune used for 'full'
|
||||||
|
func (i *ProgressBar) GetFullChar() rune {
|
||||||
|
return i.fullChar
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFullChar sets the rune used for 'full'
|
||||||
|
func (i *ProgressBar) SetFullChar(f rune) *ProgressBar {
|
||||||
|
i.fullChar = f
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEmptyChar gets the rune used for 'empty'
|
||||||
|
func (i *ProgressBar) GetEmptyChar() rune {
|
||||||
|
return i.emptyChar
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmptyChar sets the rune used for 'empty'
|
||||||
|
func (i *ProgressBar) SetEmptyChar(f rune) *ProgressBar {
|
||||||
|
i.emptyChar = f
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetX Return the x position of the Progress Bar
|
||||||
|
func (i *ProgressBar) GetX() int { return i.x }
|
||||||
|
|
||||||
|
// SetX set the x position of the ProgressBar to x
|
||||||
|
func (i *ProgressBar) SetX(x int) *ProgressBar {
|
||||||
|
i.x = x
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetY Return the y position of the ProgressBar
|
||||||
|
func (i *ProgressBar) GetY() int { return i.y }
|
||||||
|
|
||||||
|
// SetY Set the y position of the ProgressBar to y
|
||||||
|
func (i *ProgressBar) SetY(y int) *ProgressBar {
|
||||||
|
i.y = y
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight returns the height of the progress bar
|
||||||
|
// Defaults to 1 (3 if bordered)
|
||||||
|
func (i *ProgressBar) GetHeight() int {
|
||||||
|
return i.height
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHeight Sets the height of the progress bar
|
||||||
|
func (i *ProgressBar) SetHeight(h int) *ProgressBar {
|
||||||
|
i.height = h
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidth returns the width of the progress bar
|
||||||
|
func (i *ProgressBar) GetWidth() int {
|
||||||
|
return i.width
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWidth Sets the width of the progress bar
|
||||||
|
func (i *ProgressBar) SetWidth(w int) *ProgressBar {
|
||||||
|
i.width = w
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBackground Return the current background color of the modal
|
||||||
|
func (i *ProgressBar) GetBackground() termbox.Attribute { return i.bg }
|
||||||
|
|
||||||
|
// SetBackground Set the current background color to bg
|
||||||
|
func (i *ProgressBar) SetBackground(bg termbox.Attribute) *ProgressBar {
|
||||||
|
i.bg = bg
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForeground Return the current foreground color
|
||||||
|
func (i *ProgressBar) GetForeground() termbox.Attribute { return i.fg }
|
||||||
|
|
||||||
|
// SetForeground Set the foreground color to fg
|
||||||
|
func (i *ProgressBar) SetForeground(fg termbox.Attribute) *ProgressBar {
|
||||||
|
i.fg = fg
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align Tells which direction the progress bar empties
|
||||||
|
func (i *ProgressBar) Align(a TextAlignment) *ProgressBar {
|
||||||
|
i.alignment = a
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleKeyPress accepts the termbox event and returns whether it was consumed
|
||||||
|
func (i *ProgressBar) HandleKeyPress(event termbox.Event) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw outputs the input field on the screen
|
||||||
|
func (i *ProgressBar) Draw() {
|
||||||
|
// For now, just draw a [#### ] bar
|
||||||
|
// TODO: make this more advanced
|
||||||
|
drawX, drawY := i.x, i.y
|
||||||
|
fillWidth, fillHeight := i.width-2, i.height
|
||||||
|
DrawStringAtPoint("[", drawX, drawY, i.fg, i.bg)
|
||||||
|
numFull := int(float64(fillWidth) * float64(i.progress) / float64(i.total))
|
||||||
|
FillWithChar(i.fullChar, drawX+1, drawY, drawX+1+numFull, drawY+(fillHeight-1), i.fg, i.bg)
|
||||||
|
DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg)
|
||||||
|
|
||||||
|
/*
|
||||||
|
drawX, drawY := i.x, i.y
|
||||||
|
drawWidth, drawHeight := i.width, i.height
|
||||||
|
if i.bordered {
|
||||||
|
if i.height == 1 && i.width > 2 {
|
||||||
|
// Just using [ & ] for the border
|
||||||
|
DrawStringAtPoint("[", drawX, drawY, i.fg, i.bg)
|
||||||
|
DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg)
|
||||||
|
drawX++
|
||||||
|
drawWidth -= 2
|
||||||
|
} else if i.height >= 3 {
|
||||||
|
DrawBorder(drawX, drawY, drawX+i.width, drawY+i.height, i.fg, i.bg)
|
||||||
|
drawX++
|
||||||
|
drawY++
|
||||||
|
drawWidth -= 2
|
||||||
|
drawHeight -= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out how many chars are full
|
||||||
|
numFull := drawWidth * (i.progress / i.total)
|
||||||
|
switch i.alignment {
|
||||||
|
case AlignRight: // TODO: Fill from right to left
|
||||||
|
case AlignCenter: // TODO: Fill from middle out
|
||||||
|
default: // Fill from left to right
|
||||||
|
FillWithChar(i.fullChar, drawX, drawY, drawX+numFull, drawY+(drawHeight-1), i.fg, i.bg)
|
||||||
|
if numFull < drawWidth {
|
||||||
|
FillWithChar(i.emptyChar, drawX+numFull, drawY, drawX+drawWidth-1, drawY+(drawHeight-1), i.fg, i.bg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -42,16 +42,16 @@ func FillWithChar(r rune, x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.A
|
|||||||
|
|
||||||
// DrawBorder Draw a border around the area inside x1,y1 -> x2, y2
|
// DrawBorder Draw a border around the area inside x1,y1 -> x2, y2
|
||||||
func DrawBorder(x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute) {
|
func DrawBorder(x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute) {
|
||||||
termbox.SetCell(x1, y1, '┌', fg, bg)
|
termbox.SetCell(x1, y1, '+', fg, bg)
|
||||||
FillWithChar('─', x1+1, y1, x2-1, y1, fg, bg)
|
FillWithChar('-', x1+1, y1, x2-1, y1, fg, bg)
|
||||||
termbox.SetCell(x2, y1, '┐', fg, bg)
|
termbox.SetCell(x2, y1, '+', fg, bg)
|
||||||
|
|
||||||
FillWithChar('|', x1, y1+1, x1, y2-1, fg, bg)
|
FillWithChar('|', x1, y1+1, x1, y2-1, fg, bg)
|
||||||
FillWithChar('|', x2, y1+1, x2, y2-1, fg, bg)
|
FillWithChar('|', x2, y1+1, x2, y2-1, fg, bg)
|
||||||
|
|
||||||
termbox.SetCell(x1, y2, '└', fg, bg)
|
termbox.SetCell(x1, y2, '+', fg, bg)
|
||||||
FillWithChar('─', x1+1, y2, x2-1, y2, fg, bg)
|
FillWithChar('-', x1+1, y2, x2-1, y2, fg, bg)
|
||||||
termbox.SetCell(x2, y2, '┘', fg, bg)
|
termbox.SetCell(x2, y2, '+', fg, bg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlignText Aligns the text txt within width characters using the specified alignment
|
// AlignText Aligns the text txt within width characters using the specified alignment
|
||||||
@ -69,7 +69,10 @@ func AlignText(txt string, width int, align TextAlignment) string {
|
|||||||
case AlignRight:
|
case AlignRight:
|
||||||
return fmt.Sprintf("%s%s", strings.Repeat(" ", numSpaces), txt)
|
return fmt.Sprintf("%s%s", strings.Repeat(" ", numSpaces), txt)
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", numSpaces))
|
if numSpaces >= 0 {
|
||||||
|
return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", numSpaces))
|
||||||
|
}
|
||||||
|
return txt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user