mirror of
https://github.com/br0xen/termbox-util.git
synced 2024-11-22 05:33:13 +00:00
Just some stuff
This commit is contained in:
parent
80b1bdea74
commit
c168c0df31
@ -5,7 +5,7 @@ import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"gogs.bullercodeworks.com/brian/termbox-util"
|
||||
"github.com/br0xen/termbox-util"
|
||||
|
||||
"github.com/nsf/termbox-go"
|
||||
)
|
||||
|
@ -13,17 +13,20 @@ type AlertModal struct {
|
||||
showHelp bool
|
||||
cursor int
|
||||
bg, fg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
isDone bool
|
||||
accepted bool
|
||||
value string
|
||||
isVisible bool
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateAlertModal Creates a confirmation modal with the specified attributes
|
||||
func CreateAlertModal(title string, x, y, width, height int, fg, bg termbox.Attribute) *AlertModal {
|
||||
i := AlertModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, bordered: true}
|
||||
i.activeFg, i.activeBg = fg, bg
|
||||
if i.title == "" {
|
||||
i.title = "Alert!"
|
||||
}
|
||||
@ -31,6 +34,11 @@ func CreateAlertModal(title string, x, y, width, height int, fg, bg termbox.Attr
|
||||
return &i
|
||||
}
|
||||
|
||||
func (i *AlertModal) SetActiveFgColor(fg termbox.Attribute) { i.activeFg = fg }
|
||||
func (i *AlertModal) SetActiveBgColor(bg termbox.Attribute) { i.activeBg = bg }
|
||||
func (i *AlertModal) SetActive(a bool) { i.active = a }
|
||||
func (i *AlertModal) IsActive() bool { return i.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *AlertModal) GetID() string { return i.id }
|
||||
|
||||
|
@ -8,17 +8,20 @@ import (
|
||||
|
||||
// ASCIIArt is a []string with more functions
|
||||
type ASCIIArt struct {
|
||||
id string
|
||||
contents []string
|
||||
x, y int
|
||||
bg, fg termbox.Attribute
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
id string
|
||||
contents []string
|
||||
x, y int
|
||||
bg, fg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// 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, bordered: false, tabSkip: true}
|
||||
i.activeFg, i.activeBg = fg, bg
|
||||
return &i
|
||||
}
|
||||
|
||||
@ -87,6 +90,11 @@ func (i *ASCIIArt) SetWidth(w int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ASCIIArt) SetActiveFgColor(fg termbox.Attribute) { i.activeFg = fg }
|
||||
func (i *ASCIIArt) SetActiveBgColor(bg termbox.Attribute) { i.activeBg = bg }
|
||||
func (i *ASCIIArt) SetActive(a bool) { i.active = a }
|
||||
func (i *ASCIIArt) IsActive() bool { return i.active }
|
||||
|
||||
// SetContents Sets the contents of i to c
|
||||
func (i *ASCIIArt) SetContents(c []string) {
|
||||
i.contents = c
|
||||
|
59
termbox_button.go
Normal file
59
termbox_button.go
Normal file
@ -0,0 +1,59 @@
|
||||
package termboxUtil
|
||||
|
||||
import termbox "github.com/nsf/termbox-go"
|
||||
|
||||
type Button struct {
|
||||
id string
|
||||
x, y, width, height int
|
||||
label string
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
active bool
|
||||
}
|
||||
|
||||
func CreateButton(x, y, w, h int, fg, bg termbox.Attribute) *Button {
|
||||
c := Button{
|
||||
x: x, y: y, width: w, height: h,
|
||||
fg: fg, bg: bg, activeFg: bg, activeBg: fg,
|
||||
bordered: true,
|
||||
tabSkip: true,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Button) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *Button) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *Button) SetActive(a bool) { c.active = a }
|
||||
func (c *Button) IsActive() bool { return c.active }
|
||||
func (c *Button) GetID() string { return c.id }
|
||||
func (c *Button) SetID(newID string) { c.id = newID }
|
||||
func (c *Button) GetX() int { return c.x }
|
||||
func (c *Button) SetX(x int) { c.x = x }
|
||||
func (c *Button) GetY() int { return c.y }
|
||||
func (c *Button) SetY(y int) { c.y = y }
|
||||
func (c *Button) GetWidth() int { return c.width }
|
||||
func (c *Button) SetWidth(w int) { c.width = w }
|
||||
func (c *Button) GetHeight() int { return c.height }
|
||||
func (c *Button) SetHeight(h int) { c.height = h }
|
||||
func (c *Button) GetFgColor() termbox.Attribute { return c.fg }
|
||||
func (c *Button) SetFgColor(fg termbox.Attribute) { c.fg = fg }
|
||||
func (c *Button) GetBgColor() termbox.Attribute { return c.bg }
|
||||
func (c *Button) SetBgColor(bg termbox.Attribute) { c.bg = bg }
|
||||
func (c *Button) IsBordered() bool { return c.bordered }
|
||||
func (c *Button) SetBordered(bordered bool) { c.bordered = bordered }
|
||||
func (c *Button) SetTabSkip(skip bool) { c.tabSkip = skip }
|
||||
func (c *Button) IsTabSkipped() bool { return c.tabSkip }
|
||||
func (c *Button) HandleEvent(e termbox.Event) bool {
|
||||
return false
|
||||
}
|
||||
func (c *Button) Draw() {
|
||||
stX, stY := c.x, c.y
|
||||
if c.bordered {
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, c.fg, c.bg)
|
||||
stX++
|
||||
stY++
|
||||
}
|
||||
DrawStringAtPoint(c.label, stX, stY, c.fg, c.bg)
|
||||
}
|
@ -12,7 +12,8 @@ type ConfirmModal struct {
|
||||
x, y, width, height int
|
||||
showHelp bool
|
||||
cursor int
|
||||
bg, fg termbox.Attribute
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
isDone bool
|
||||
accepted bool
|
||||
value string
|
||||
@ -23,7 +24,7 @@ type ConfirmModal struct {
|
||||
|
||||
// CreateConfirmModal Creates a confirmation modal with the specified attributes
|
||||
func CreateConfirmModal(title string, x, y, width, height int, fg, bg termbox.Attribute) *ConfirmModal {
|
||||
i := ConfirmModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg}
|
||||
i := ConfirmModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, activeFg: fg, activeBg: bg}
|
||||
if i.title == "" && i.text == "" {
|
||||
i.title = "Confirm?"
|
||||
}
|
||||
|
@ -4,174 +4,181 @@ import "github.com/nsf/termbox-go"
|
||||
|
||||
// DropMenu is a title that, when active drops a menu down
|
||||
type DropMenu struct {
|
||||
id string
|
||||
title string
|
||||
x, y, width, height int
|
||||
bg, fg termbox.Attribute
|
||||
selectedBg, selectedFg termbox.Attribute
|
||||
menu *Menu
|
||||
menuSelected bool
|
||||
showMenu bool
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
id string
|
||||
title string
|
||||
x, y, width, height int
|
||||
bg, fg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
cursorBg, cursorFg termbox.Attribute
|
||||
menu *Menu
|
||||
menuSelected bool
|
||||
showMenu bool
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateDropMenu Creates a menu with the specified attributes
|
||||
func CreateDropMenu(title string, options []string, x, y, width, height int, fg, bg, selectedFg, selectedBg termbox.Attribute) *DropMenu {
|
||||
i := DropMenu{
|
||||
func CreateDropMenu(title string, options []string, x, y, width, height int, fg, bg, cursorFg, cursorBg termbox.Attribute) *DropMenu {
|
||||
c := DropMenu{
|
||||
title: title,
|
||||
x: x, y: y, width: width, height: height,
|
||||
fg: fg, bg: bg,
|
||||
selectedFg: fg, selectedBg: bg,
|
||||
fg: fg, bg: bg, activeFg: fg, activeBg: bg,
|
||||
cursorFg: fg, cursorBg: bg,
|
||||
}
|
||||
i.menu = CreateMenu("", options, x, y+2, width, height, fg, bg)
|
||||
return &i
|
||||
c.menu = CreateMenu("", options, x, y+2, width, height, fg, bg)
|
||||
return &c
|
||||
}
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *DropMenu) GetID() string { return i.id }
|
||||
func (c *DropMenu) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *DropMenu) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *DropMenu) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
func (c *DropMenu) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *DropMenu) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *DropMenu) SetActive(a bool) { c.active = a }
|
||||
func (c *DropMenu) IsActive() bool { return c.active }
|
||||
|
||||
// GetTitle returns the current title of the menu
|
||||
func (i *DropMenu) GetTitle() string { return i.title }
|
||||
func (c *DropMenu) GetTitle() string { return c.title }
|
||||
|
||||
// SetTitle sets the current title of the menu to s
|
||||
func (i *DropMenu) SetTitle(s string) {
|
||||
i.title = s
|
||||
func (c *DropMenu) SetTitle(s string) {
|
||||
c.title = s
|
||||
}
|
||||
|
||||
// GetMenu returns the menu for this dropmenu
|
||||
func (i *DropMenu) GetMenu() *Menu {
|
||||
return i.menu
|
||||
func (c *DropMenu) GetMenu() *Menu {
|
||||
return c.menu
|
||||
}
|
||||
|
||||
// GetX returns the current x coordinate of the menu
|
||||
func (i *DropMenu) GetX() int { return i.x }
|
||||
func (c *DropMenu) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the current x coordinate of the menu to x
|
||||
func (i *DropMenu) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *DropMenu) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY returns the current y coordinate of the menu
|
||||
func (i *DropMenu) GetY() int { return i.y }
|
||||
func (c *DropMenu) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the current y coordinate of the menu to y
|
||||
func (i *DropMenu) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *DropMenu) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth returns the current width of the menu
|
||||
func (i *DropMenu) GetWidth() int { return i.width }
|
||||
func (c *DropMenu) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth sets the current menu width to width
|
||||
func (i *DropMenu) SetWidth(width int) {
|
||||
i.width = width
|
||||
func (c *DropMenu) SetWidth(width int) {
|
||||
c.width = width
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the menu
|
||||
func (i *DropMenu) GetHeight() int { return i.height }
|
||||
func (c *DropMenu) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight set the height of the menu to height
|
||||
func (i *DropMenu) SetHeight(height int) {
|
||||
i.height = height
|
||||
func (c *DropMenu) SetHeight(height int) {
|
||||
c.height = height
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *DropMenu) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *DropMenu) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *DropMenu) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *DropMenu) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *DropMenu) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *DropMenu) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *DropMenu) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *DropMenu) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// IsBordered returns the bordered flag
|
||||
func (i *DropMenu) IsBordered() bool { return i.bordered }
|
||||
func (c *DropMenu) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets the bordered flag
|
||||
func (i *DropMenu) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
i.menu.SetBordered(b)
|
||||
func (c *DropMenu) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
c.menu.SetBordered(b)
|
||||
}
|
||||
|
||||
// IsDone returns whether the user has answered the modal
|
||||
func (i *DropMenu) IsDone() bool { return i.menu.isDone }
|
||||
func (c *DropMenu) IsDone() bool { return c.menu.isDone }
|
||||
|
||||
// SetDone sets whether the modal has completed it's purpose
|
||||
func (i *DropMenu) SetDone(b bool) {
|
||||
i.menu.isDone = b
|
||||
func (c *DropMenu) SetDone(b bool) {
|
||||
c.menu.isDone = b
|
||||
}
|
||||
|
||||
// IsTabSkipped returns whether this modal has it's tabskip flag set
|
||||
func (i *DropMenu) IsTabSkipped() bool {
|
||||
return i.tabSkip
|
||||
func (c *DropMenu) IsTabSkipped() bool {
|
||||
return c.tabSkip
|
||||
}
|
||||
|
||||
// SetTabSkip sets the tabskip flag for this control
|
||||
func (i *DropMenu) SetTabSkip(b bool) {
|
||||
i.tabSkip = b
|
||||
func (c *DropMenu) SetTabSkip(b bool) {
|
||||
c.tabSkip = b
|
||||
}
|
||||
|
||||
// ShowMenu tells the menu to draw the options
|
||||
func (i *DropMenu) ShowMenu() {
|
||||
i.showMenu = true
|
||||
i.menuSelected = true
|
||||
func (c *DropMenu) ShowMenu() {
|
||||
c.showMenu = true
|
||||
c.menuSelected = true
|
||||
}
|
||||
|
||||
// HideMenu tells the menu to hide the options
|
||||
func (i *DropMenu) HideMenu() {
|
||||
i.showMenu = false
|
||||
i.menuSelected = false
|
||||
func (c *DropMenu) HideMenu() {
|
||||
c.showMenu = false
|
||||
c.menuSelected = false
|
||||
}
|
||||
|
||||
// HandleEvent handles the termbox event and returns whether it was consumed
|
||||
func (i *DropMenu) HandleEvent(event termbox.Event) bool {
|
||||
moveUp := (event.Key == termbox.KeyArrowUp || (i.menu.vimMode && event.Ch == 'k'))
|
||||
moveDown := (event.Key == termbox.KeyArrowDown || (i.menu.vimMode && event.Ch == 'j'))
|
||||
if i.menuSelected {
|
||||
selIdx := i.menu.GetSelectedIndex()
|
||||
if (moveUp && selIdx == 0) || (moveDown && selIdx == (len(i.menu.options)-1)) {
|
||||
i.menuSelected = false
|
||||
func (c *DropMenu) HandleEvent(event termbox.Event) bool {
|
||||
moveUp := (event.Key == termbox.KeyArrowUp || (c.menu.vimMode && event.Ch == 'k'))
|
||||
moveDown := (event.Key == termbox.KeyArrowDown || (c.menu.vimMode && event.Ch == 'j'))
|
||||
if c.menuSelected {
|
||||
selIdx := c.menu.GetSelectedIndex()
|
||||
if (moveUp && selIdx == 0) || (moveDown && selIdx == (len(c.menu.options)-1)) {
|
||||
c.menuSelected = false
|
||||
} else {
|
||||
if i.menu.HandleEvent(event) {
|
||||
if i.menu.IsDone() {
|
||||
i.HideMenu()
|
||||
if c.menu.HandleEvent(event) {
|
||||
if c.menu.IsDone() {
|
||||
c.HideMenu()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i.ShowMenu()
|
||||
c.ShowMenu()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Draw draws the menu
|
||||
func (i *DropMenu) Draw() {
|
||||
func (c *DropMenu) Draw() {
|
||||
// The title
|
||||
ttlFg, ttlBg := i.fg, i.bg
|
||||
if !i.menuSelected {
|
||||
ttlFg, ttlBg = i.selectedFg, i.selectedBg
|
||||
ttlFg, ttlBg := c.fg, c.bg
|
||||
if !c.menuSelected {
|
||||
ttlFg, ttlBg = c.cursorFg, c.cursorBg
|
||||
}
|
||||
ttlTxt := i.title
|
||||
if i.showMenu {
|
||||
ttlTxt := c.title
|
||||
if c.showMenu {
|
||||
ttlTxt = ttlTxt + "-Showing Menu"
|
||||
}
|
||||
DrawStringAtPoint(AlignText(i.title, i.width, AlignLeft), i.x, i.y, ttlFg, ttlBg)
|
||||
if i.showMenu {
|
||||
i.menu.Draw()
|
||||
DrawStringAtPoint(AlignText(c.title, c.width, AlignLeft), c.x, c.y, ttlFg, ttlBg)
|
||||
if c.showMenu {
|
||||
c.menu.Draw()
|
||||
}
|
||||
}
|
||||
|
218
termbox_frame.go
218
termbox_frame.go
@ -9,187 +9,252 @@ type Frame struct {
|
||||
x, y, width, height int
|
||||
tabIdx int
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
bordered bool
|
||||
controls []termboxControl
|
||||
tabSkip bool
|
||||
active bool
|
||||
title string
|
||||
}
|
||||
|
||||
// CreateFrame creates a Frame at x, y that is w by h
|
||||
func CreateFrame(x, y, w, h int, fg, bg termbox.Attribute) *Frame {
|
||||
s := Frame{x: x, y: y, width: w, height: h, fg: fg, bg: bg, bordered: true}
|
||||
return &s
|
||||
c := Frame{x: x, y: y, width: w, height: h,
|
||||
fg: fg, bg: bg, activeFg: fg, activeBg: bg,
|
||||
bordered: true,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Frame) SetTitle(title string) { c.title = title }
|
||||
|
||||
// Setting color attributes on a frame trickles down to its controls
|
||||
func (c *Frame) SetActiveFgColor(fg termbox.Attribute) {
|
||||
c.activeFg = fg
|
||||
for _, v := range c.controls {
|
||||
v.SetActiveFgColor(fg)
|
||||
}
|
||||
}
|
||||
func (c *Frame) SetActiveBgColor(bg termbox.Attribute) {
|
||||
c.activeBg = bg
|
||||
for _, v := range c.controls {
|
||||
v.SetActiveBgColor(bg)
|
||||
}
|
||||
}
|
||||
func (c *Frame) SetActive(a bool) {
|
||||
c.active = a
|
||||
for idx := range c.controls {
|
||||
if idx == c.tabIdx && a {
|
||||
c.controls[idx].SetActive(true)
|
||||
} else {
|
||||
c.controls[idx].SetActive(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
func (c *Frame) IsActive() bool { return c.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *Frame) GetID() string { return i.id }
|
||||
func (c *Frame) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *Frame) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *Frame) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
// GetX returns the x position of the frame
|
||||
func (i *Frame) GetX() int { return i.x }
|
||||
func (c *Frame) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the x position of the frame
|
||||
func (i *Frame) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *Frame) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY returns the y position of the frame
|
||||
func (i *Frame) GetY() int { return i.y }
|
||||
func (c *Frame) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the y position of the frame
|
||||
func (i *Frame) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *Frame) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth returns the current width of the frame
|
||||
func (i *Frame) GetWidth() int { return i.width }
|
||||
func (c *Frame) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth sets the current width of the frame
|
||||
func (i *Frame) SetWidth(w int) {
|
||||
i.width = w
|
||||
func (c *Frame) SetWidth(w int) {
|
||||
c.width = w
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the frame
|
||||
func (i *Frame) GetHeight() int { return i.height }
|
||||
func (c *Frame) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight sets the current height of the frame
|
||||
func (i *Frame) SetHeight(h int) {
|
||||
i.height = h
|
||||
func (c *Frame) SetHeight(h int) {
|
||||
c.height = h
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *Frame) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *Frame) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *Frame) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *Frame) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *Frame) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *Frame) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *Frame) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *Frame) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// IsBordered returns true or false if this frame has a border
|
||||
func (i *Frame) IsBordered() bool { return i.bordered }
|
||||
func (c *Frame) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets whether we render a border around the frame
|
||||
func (i *Frame) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *Frame) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// IsTabSkipped returns whether this modal has it's tabskip flag set
|
||||
func (i *Frame) IsTabSkipped() bool {
|
||||
return i.tabSkip
|
||||
func (c *Frame) IsTabSkipped() bool {
|
||||
return c.tabSkip
|
||||
}
|
||||
|
||||
// SetTabSkip sets the tabskip flag for this control
|
||||
func (i *Frame) SetTabSkip(b bool) {
|
||||
i.tabSkip = b
|
||||
func (c *Frame) SetTabSkip(b bool) {
|
||||
c.tabSkip = b
|
||||
}
|
||||
|
||||
// AddControl adds a control to the frame
|
||||
func (i *Frame) AddControl(t termboxControl) {
|
||||
i.controls = append(i.controls, t)
|
||||
func (c *Frame) AddControl(t termboxControl) {
|
||||
c.controls = append(c.controls, t)
|
||||
}
|
||||
|
||||
func (c *Frame) ResetTabIndex() {
|
||||
for k, v := range c.controls {
|
||||
if !v.IsTabSkipped() {
|
||||
c.tabIdx = k
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetActiveControl returns the control at tabIdx
|
||||
func (i *Frame) GetActiveControl() termboxControl {
|
||||
if len(i.controls) >= i.tabIdx {
|
||||
return i.controls[i.tabIdx]
|
||||
func (c *Frame) GetActiveControl() termboxControl {
|
||||
if len(c.controls) >= c.tabIdx {
|
||||
if c.controls[c.tabIdx].IsTabSkipped() {
|
||||
c.FindNextTabStop()
|
||||
}
|
||||
return c.controls[c.tabIdx]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetControls returns a slice of all controls
|
||||
func (i *Frame) GetControls() []termboxControl {
|
||||
return i.controls
|
||||
func (c *Frame) GetControls() []termboxControl {
|
||||
return c.controls
|
||||
}
|
||||
|
||||
// GetControl returns the control at index i
|
||||
func (i *Frame) GetControl(idx int) termboxControl {
|
||||
if len(i.controls) >= idx {
|
||||
return i.controls[idx]
|
||||
func (c *Frame) GetControl(idx int) termboxControl {
|
||||
if len(c.controls) >= idx {
|
||||
return c.controls[idx]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetControlCount returns the number of controls contained
|
||||
func (i *Frame) GetControlCount() int {
|
||||
return len(i.controls)
|
||||
func (c *Frame) GetControlCount() int {
|
||||
return len(c.controls)
|
||||
}
|
||||
|
||||
// GetLastControl returns the last control contained
|
||||
func (i *Frame) GetLastControl() termboxControl {
|
||||
return i.controls[len(i.controls)-1]
|
||||
func (c *Frame) GetLastControl() termboxControl {
|
||||
return c.controls[len(c.controls)-1]
|
||||
}
|
||||
|
||||
// RemoveAllControls clears the control slice
|
||||
func (i *Frame) RemoveAllControls() {
|
||||
i.controls = []termboxControl{}
|
||||
func (c *Frame) RemoveAllControls() {
|
||||
c.controls = []termboxControl{}
|
||||
}
|
||||
|
||||
// DrawControl figures out the relative position of the control,
|
||||
// sets it, draws it, then resets it.
|
||||
func (i *Frame) DrawControl(t termboxControl) {
|
||||
func (c *Frame) DrawControl(t termboxControl) {
|
||||
ctlX, ctlY := t.GetX(), t.GetY()
|
||||
t.SetX((i.GetX() + ctlX))
|
||||
t.SetY((i.GetY() + ctlY))
|
||||
t.SetX((c.GetX() + ctlX))
|
||||
t.SetY((c.GetY() + ctlY))
|
||||
t.Draw()
|
||||
t.SetX(ctlX)
|
||||
t.SetY(ctlY)
|
||||
}
|
||||
|
||||
// GetBottomY returns the y of the lowest control in the frame
|
||||
func (i *Frame) GetBottomY() int {
|
||||
func (c *Frame) GetBottomY() int {
|
||||
var ret int
|
||||
for idx := range i.controls {
|
||||
if i.controls[idx].GetY()+i.controls[idx].GetHeight() > ret {
|
||||
ret = i.controls[idx].GetY() + i.controls[idx].GetHeight()
|
||||
for idx := range c.controls {
|
||||
if c.controls[idx].GetY()+c.controls[idx].GetHeight() > ret {
|
||||
ret = c.controls[idx].GetY() + c.controls[idx].GetHeight()
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// HandleEvent accepts the termbox event and returns whether it was consumed
|
||||
func (i *Frame) HandleEvent(event termbox.Event) bool {
|
||||
func (c *Frame) HandleEvent(event termbox.Event) bool {
|
||||
if event.Key == termbox.KeyTab {
|
||||
i.FindNextTabStop()
|
||||
c.FindNextTabStop()
|
||||
return true
|
||||
}
|
||||
return i.controls[i.tabIdx].HandleEvent(event)
|
||||
return c.controls[c.tabIdx].HandleEvent(event)
|
||||
}
|
||||
|
||||
// FindNextTabStop finds the next control that can be tabbed to
|
||||
// A return of true means it found a different one than we started on.
|
||||
func (i *Frame) FindNextTabStop() bool {
|
||||
startTab := i.tabIdx
|
||||
i.tabIdx = (i.tabIdx + 1) % len(i.controls)
|
||||
for i.controls[i.tabIdx].IsTabSkipped() {
|
||||
i.tabIdx = (i.tabIdx + 1) % len(i.controls)
|
||||
if i.tabIdx == startTab {
|
||||
func (c *Frame) FindNextTabStop() bool {
|
||||
startTab := c.tabIdx
|
||||
c.tabIdx = (c.tabIdx + 1) % len(c.controls)
|
||||
for c.controls[c.tabIdx].IsTabSkipped() {
|
||||
c.tabIdx = (c.tabIdx + 1) % len(c.controls)
|
||||
if c.tabIdx == startTab {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i.tabIdx != startTab
|
||||
return c.tabIdx != startTab
|
||||
}
|
||||
|
||||
// IsOnLastControl returns true if the active control
|
||||
// is the last control that isn't tab skippable.
|
||||
func (c *Frame) IsOnLastControl() bool {
|
||||
for _, v := range c.controls[c.tabIdx+1:] {
|
||||
if !v.IsTabSkipped() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Draw outputs the Scoll Frame on the screen
|
||||
func (i *Frame) Draw() {
|
||||
maxWidth := i.width
|
||||
maxHeight := i.height
|
||||
x, y := i.x, i.y
|
||||
startX := i.x
|
||||
startY := i.y
|
||||
if i.bordered {
|
||||
FillWithChar(' ', i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
func (c *Frame) Draw() {
|
||||
maxWidth := c.width
|
||||
maxHeight := c.height
|
||||
x, y := c.x, c.y
|
||||
startX := c.x
|
||||
startY := c.y
|
||||
borderFg, borderBg := c.fg, c.bg
|
||||
if c.active {
|
||||
borderFg, borderBg = c.activeFg, c.activeBg
|
||||
}
|
||||
if c.bordered {
|
||||
// Clear the framed area
|
||||
FillWithChar(' ', c.x, c.y, c.x+c.width, c.y+c.height, borderFg, borderBg)
|
||||
if c.title == "" {
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, borderFg, borderBg)
|
||||
} else {
|
||||
DrawBorderWithTitle(c.x, c.y, c.x+c.width, c.y+c.height, " "+c.title+" ", borderFg, borderBg)
|
||||
}
|
||||
maxWidth--
|
||||
maxHeight--
|
||||
x++
|
||||
@ -197,7 +262,12 @@ func (i *Frame) Draw() {
|
||||
startX++
|
||||
startY++
|
||||
}
|
||||
for idx := range i.controls {
|
||||
i.DrawControl(i.controls[idx])
|
||||
for idx := range c.controls {
|
||||
if idx == c.tabIdx {
|
||||
c.controls[idx].SetActive(true)
|
||||
} else {
|
||||
c.controls[idx].SetActive(false)
|
||||
}
|
||||
c.DrawControl(c.controls[idx])
|
||||
}
|
||||
}
|
||||
|
@ -5,153 +5,164 @@ import "github.com/nsf/termbox-go"
|
||||
// InputField is a field for inputting text
|
||||
type InputField struct {
|
||||
id string
|
||||
title string
|
||||
value string
|
||||
x, y, width, height int
|
||||
cursor int
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
cursorFg, cursorBg termbox.Attribute
|
||||
bordered bool
|
||||
wrap bool
|
||||
multiline bool
|
||||
tabSkip bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateInputField creates an input field at x, y that is w by h
|
||||
func CreateInputField(x, y, w, h int, fg, bg termbox.Attribute) *InputField {
|
||||
i := InputField{x: x, y: y, width: w, height: h, fg: fg, bg: bg, cursorFg: bg, cursorBg: fg}
|
||||
return &i
|
||||
c := InputField{x: x, y: y, width: w, height: h,
|
||||
fg: fg, bg: bg, cursorFg: bg, cursorBg: fg, activeFg: fg, activeBg: bg,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *InputField) SetTitle(title string) { c.title = title }
|
||||
func (c *InputField) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *InputField) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *InputField) SetActive(a bool) { c.active = a }
|
||||
func (c *InputField) IsActive() bool { return c.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *InputField) GetID() string { return i.id }
|
||||
func (c *InputField) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *InputField) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *InputField) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
// GetValue gets the current text that is in the InputField
|
||||
func (i *InputField) GetValue() string { return i.value }
|
||||
func (c *InputField) GetValue() string { return c.value }
|
||||
|
||||
// SetValue sets the current text in the InputField to s
|
||||
func (i *InputField) SetValue(s string) {
|
||||
i.value = s
|
||||
func (c *InputField) SetValue(s string) {
|
||||
c.value = s
|
||||
}
|
||||
|
||||
// GetX returns the x position of the input field
|
||||
func (i *InputField) GetX() int { return i.x }
|
||||
func (c *InputField) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the x position of the input field
|
||||
func (i *InputField) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *InputField) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY returns the y position of the input field
|
||||
func (i *InputField) GetY() int { return i.y }
|
||||
func (c *InputField) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the y position of the input field
|
||||
func (i *InputField) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *InputField) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth returns the current width of the input field
|
||||
func (i *InputField) GetWidth() int { return i.width }
|
||||
func (c *InputField) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth sets the current width of the input field
|
||||
func (i *InputField) SetWidth(w int) {
|
||||
i.width = w
|
||||
func (c *InputField) SetWidth(w int) {
|
||||
c.width = w
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the input field
|
||||
func (i *InputField) GetHeight() int { return i.height }
|
||||
func (c *InputField) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight sets the current height of the input field
|
||||
func (i *InputField) SetHeight(h int) {
|
||||
i.height = h
|
||||
func (c *InputField) SetHeight(h int) {
|
||||
c.height = h
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *InputField) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *InputField) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *InputField) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *InputField) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *InputField) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *InputField) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *InputField) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *InputField) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
func (i *InputField) SetCursorFg(fg termbox.Attribute) {
|
||||
i.cursorFg = fg
|
||||
func (c *InputField) SetCursorFg(fg termbox.Attribute) {
|
||||
c.cursorFg = fg
|
||||
}
|
||||
func (i *InputField) GetCursorFg() termbox.Attribute { return i.cursorFg }
|
||||
func (c *InputField) GetCursorFg() termbox.Attribute { return c.cursorFg }
|
||||
|
||||
func (i *InputField) SetCursorBg(bg termbox.Attribute) {
|
||||
i.cursorBg = bg
|
||||
func (c *InputField) SetCursorBg(bg termbox.Attribute) {
|
||||
c.cursorBg = bg
|
||||
}
|
||||
func (i *InputField) GetCursorBg() termbox.Attribute { return i.cursorBg }
|
||||
func (c *InputField) GetCursorBg() termbox.Attribute { return c.cursorBg }
|
||||
|
||||
// IsBordered returns true or false if this input field has a border
|
||||
func (i *InputField) IsBordered() bool { return i.bordered }
|
||||
func (c *InputField) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets whether we render a border around the input field
|
||||
func (i *InputField) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *InputField) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// IsTabSkipped returns whether this modal has it's tabskip flag set
|
||||
func (i *InputField) IsTabSkipped() bool {
|
||||
return i.tabSkip
|
||||
func (c *InputField) IsTabSkipped() bool {
|
||||
return c.tabSkip
|
||||
}
|
||||
|
||||
// SetTabSkip sets the tabskip flag for this control
|
||||
func (i *InputField) SetTabSkip(b bool) {
|
||||
i.tabSkip = b
|
||||
func (c *InputField) SetTabSkip(b bool) {
|
||||
c.tabSkip = b
|
||||
}
|
||||
|
||||
// DoesWrap returns true or false if this input field wraps text
|
||||
func (i *InputField) DoesWrap() bool { return i.wrap }
|
||||
func (c *InputField) DoesWrap() bool { return c.wrap }
|
||||
|
||||
// SetWrap sets whether we wrap the text at width.
|
||||
func (i *InputField) SetWrap(b bool) {
|
||||
i.wrap = b
|
||||
func (c *InputField) SetWrap(b bool) {
|
||||
c.wrap = b
|
||||
}
|
||||
|
||||
// IsMultiline returns true or false if this field can have multiple lines
|
||||
func (i *InputField) IsMultiline() bool { return i.multiline }
|
||||
func (c *InputField) IsMultiline() bool { return c.multiline }
|
||||
|
||||
// SetMultiline sets whether the field can have multiple lines
|
||||
func (i *InputField) SetMultiline(b bool) {
|
||||
i.multiline = b
|
||||
func (c *InputField) SetMultiline(b bool) {
|
||||
c.multiline = b
|
||||
}
|
||||
|
||||
// HandleEvent accepts the termbox event and returns whether it was consumed
|
||||
func (i *InputField) HandleEvent(event termbox.Event) bool {
|
||||
func (c *InputField) HandleEvent(event termbox.Event) bool {
|
||||
if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 {
|
||||
if i.cursor+len(i.value) > 0 {
|
||||
crs := len(i.value)
|
||||
if i.cursor < 0 {
|
||||
crs = i.cursor + len(i.value)
|
||||
if c.cursor+len(c.value) > 0 {
|
||||
crs := len(c.value)
|
||||
if c.cursor < 0 {
|
||||
crs = c.cursor + len(c.value)
|
||||
}
|
||||
i.value = i.value[:crs-1] + i.value[crs:]
|
||||
//i.value = i.value[:len(i.value)-1]
|
||||
c.value = c.value[:crs-1] + c.value[crs:]
|
||||
//c.value = c.value[:len(c.value)-1]
|
||||
}
|
||||
} else if event.Key == termbox.KeyArrowLeft {
|
||||
if i.cursor+len(i.value) > 0 {
|
||||
i.cursor--
|
||||
if c.cursor+len(c.value) > 0 {
|
||||
c.cursor--
|
||||
}
|
||||
} else if event.Key == termbox.KeyArrowRight {
|
||||
if i.cursor < 0 {
|
||||
i.cursor++
|
||||
if c.cursor < 0 {
|
||||
c.cursor++
|
||||
}
|
||||
} else if event.Key == termbox.KeyCtrlU {
|
||||
// Ctrl+U Clears the Input (before the cursor)
|
||||
i.value = i.value[i.cursor+len(i.value):]
|
||||
c.value = c.value[c.cursor+len(c.value):]
|
||||
} else {
|
||||
// Get the rune to add to our value. Space and Tab are special cases where
|
||||
// we can't use the event's rune directly
|
||||
@ -162,7 +173,7 @@ func (i *InputField) HandleEvent(event termbox.Event) bool {
|
||||
case termbox.KeyTab:
|
||||
ch = "\t"
|
||||
case termbox.KeyEnter:
|
||||
if i.multiline {
|
||||
if c.multiline {
|
||||
ch = "\n"
|
||||
}
|
||||
default:
|
||||
@ -172,28 +183,32 @@ func (i *InputField) HandleEvent(event termbox.Event) bool {
|
||||
}
|
||||
|
||||
// TODO: Handle newlines
|
||||
if i.cursor+len(i.value) == 0 {
|
||||
i.value = string(ch) + i.value
|
||||
} else if i.cursor == 0 {
|
||||
i.value = i.value + string(ch)
|
||||
if c.cursor+len(c.value) == 0 {
|
||||
c.value = string(ch) + c.value
|
||||
} else if c.cursor == 0 {
|
||||
c.value = c.value + string(ch)
|
||||
} else {
|
||||
strPt1 := i.value[:(len(i.value) + i.cursor)]
|
||||
strPt2 := i.value[(len(i.value) + i.cursor):]
|
||||
i.value = strPt1 + string(ch) + strPt2
|
||||
strPt1 := c.value[:(len(c.value) + c.cursor)]
|
||||
strPt2 := c.value[(len(c.value) + c.cursor):]
|
||||
c.value = strPt1 + string(ch) + strPt2
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Draw outputs the input field on the screen
|
||||
func (i *InputField) Draw() {
|
||||
maxWidth := i.width
|
||||
maxHeight := i.height
|
||||
x, y := i.x, i.y
|
||||
startX := i.x
|
||||
startY := i.y
|
||||
if i.bordered {
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
func (c *InputField) Draw() {
|
||||
maxWidth := c.width
|
||||
maxHeight := c.height
|
||||
x, y := c.x, c.y
|
||||
startX := c.x
|
||||
startY := c.y
|
||||
useFg, useBg := c.fg, c.bg
|
||||
if c.active {
|
||||
useFg, useBg = c.activeFg, c.activeBg
|
||||
}
|
||||
if c.bordered {
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, useFg, useBg)
|
||||
maxWidth--
|
||||
maxHeight--
|
||||
x++
|
||||
@ -204,53 +219,60 @@ func (i *InputField) Draw() {
|
||||
|
||||
var strPt1, strPt2 string
|
||||
var cursorRune rune
|
||||
if len(i.value) > 0 {
|
||||
if i.cursor+len(i.value) == 0 {
|
||||
if len(c.value) > 0 {
|
||||
if c.cursor+len(c.value) == 0 {
|
||||
strPt1 = ""
|
||||
strPt2 = i.value[1:]
|
||||
cursorRune = rune(i.value[0])
|
||||
} else if i.cursor == 0 {
|
||||
strPt1 = i.value
|
||||
strPt2 = c.value[1:]
|
||||
cursorRune = rune(c.value[0])
|
||||
} else if c.cursor == 0 {
|
||||
strPt1 = c.value
|
||||
strPt2 = ""
|
||||
cursorRune = ' '
|
||||
} else {
|
||||
strPt1 = i.value[:(len(i.value) + i.cursor)]
|
||||
strPt2 = i.value[(len(i.value)+i.cursor)+1:]
|
||||
cursorRune = rune(i.value[len(i.value)+i.cursor])
|
||||
strPt1 = c.value[:(len(c.value) + c.cursor)]
|
||||
strPt2 = c.value[(len(c.value)+c.cursor)+1:]
|
||||
cursorRune = rune(c.value[len(c.value)+c.cursor])
|
||||
}
|
||||
} else {
|
||||
strPt1, strPt2, cursorRune = "", "", ' '
|
||||
}
|
||||
if i.wrap {
|
||||
if c.title != "" {
|
||||
if c.active {
|
||||
DrawStringAtPoint(c.title, x, y, c.activeFg, c.activeBg)
|
||||
} else {
|
||||
DrawStringAtPoint(c.title, x, y, useFg, useBg)
|
||||
}
|
||||
}
|
||||
if c.wrap {
|
||||
// Split the text into maxWidth chunks
|
||||
for len(strPt1) > maxWidth {
|
||||
breakAt := maxWidth
|
||||
DrawStringAtPoint(strPt1[:breakAt], x, y, i.fg, i.bg)
|
||||
DrawStringAtPoint(strPt1[:breakAt], x, y, useFg, useBg)
|
||||
x = startX
|
||||
y++
|
||||
strPt1 = strPt1[breakAt:]
|
||||
}
|
||||
x, y = DrawStringAtPoint(strPt1, x, y, i.fg, i.bg)
|
||||
x, y = DrawStringAtPoint(strPt1, x, y, useFg, useBg)
|
||||
if x >= maxWidth {
|
||||
y++
|
||||
x = startX
|
||||
}
|
||||
termbox.SetCell(x, y, cursorRune, i.cursorFg, i.cursorBg)
|
||||
termbox.SetCell(x, y, cursorRune, c.cursorFg, c.cursorBg)
|
||||
x++
|
||||
if len(strPt2) > 0 {
|
||||
lenLeft := maxWidth - len(strPt1) - 1
|
||||
if lenLeft > 0 && len(strPt2) > lenLeft {
|
||||
DrawStringAtPoint(strPt2[:lenLeft], x+1, y, i.fg, i.bg)
|
||||
DrawStringAtPoint(strPt2[:lenLeft], x+1, y, useFg, useBg)
|
||||
strPt2 = strPt2[lenLeft:]
|
||||
}
|
||||
for len(strPt2) > maxWidth {
|
||||
breakAt := maxWidth
|
||||
DrawStringAtPoint(strPt2[:breakAt], x, y, i.fg, i.bg)
|
||||
DrawStringAtPoint(strPt2[:breakAt], x, y, useFg, useBg)
|
||||
x = startX
|
||||
y++
|
||||
strPt2 = strPt2[breakAt:]
|
||||
}
|
||||
x, y = DrawStringAtPoint(strPt2, x, y, i.fg, i.bg)
|
||||
x, y = DrawStringAtPoint(strPt2, x, y, useFg, useBg)
|
||||
}
|
||||
} else {
|
||||
for len(strPt1)+len(strPt2)+1 > maxWidth {
|
||||
@ -263,8 +285,12 @@ func (i *InputField) Draw() {
|
||||
strPt2 = strPt2[:len(strPt2)-1]
|
||||
}
|
||||
}
|
||||
x, y = DrawStringAtPoint(strPt1, i.x+1, i.y+1, i.fg, i.bg)
|
||||
termbox.SetCell(x, y, cursorRune, i.cursorFg, i.cursorBg)
|
||||
DrawStringAtPoint(strPt2, x+1, y, i.fg, i.bg)
|
||||
x, y = DrawStringAtPoint(strPt1, c.x+len(c.title), c.y, useFg, useBg)
|
||||
if c.active {
|
||||
termbox.SetCell(x, y, cursorRune, c.cursorFg, c.cursorBg)
|
||||
} else {
|
||||
termbox.SetCell(x, y, cursorRune, useFg, useBg)
|
||||
}
|
||||
DrawStringAtPoint(strPt2, x+1, y, useFg, useBg)
|
||||
}
|
||||
}
|
||||
|
@ -14,244 +14,251 @@ type InputModal struct {
|
||||
showHelp bool
|
||||
cursor int
|
||||
bg, fg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
isDone bool
|
||||
isAccepted bool
|
||||
isVisible bool
|
||||
bordered bool
|
||||
tabSkip bool
|
||||
inputSelected bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateInputModal Create an input modal with the given attributes
|
||||
func CreateInputModal(title string, x, y, width, height int, fg, bg termbox.Attribute) *InputModal {
|
||||
i := InputModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, bordered: true}
|
||||
i.input = CreateInputField(i.x+2, i.y+3, i.width-2, 2, i.fg, i.bg)
|
||||
i.showHelp = true
|
||||
i.input.bordered = true
|
||||
i.isVisible = true
|
||||
i.inputSelected = true
|
||||
return &i
|
||||
c := InputModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, bordered: true}
|
||||
c.input = CreateInputField(c.x+2, c.y+3, c.width-2, 2, c.fg, c.bg)
|
||||
c.showHelp = true
|
||||
c.input.bordered = true
|
||||
c.isVisible = true
|
||||
c.inputSelected = true
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *InputModal) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *InputModal) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *InputModal) SetActive(a bool) { c.active = a }
|
||||
func (c *InputModal) IsActive() bool { return c.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *InputModal) GetID() string { return i.id }
|
||||
func (c *InputModal) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *InputModal) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *InputModal) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
// GetTitle Return the title of the modal
|
||||
func (i *InputModal) GetTitle() string { return i.title }
|
||||
func (c *InputModal) GetTitle() string { return c.title }
|
||||
|
||||
// SetTitle Sets the title of the modal to s
|
||||
func (i *InputModal) SetTitle(s string) {
|
||||
i.title = s
|
||||
func (c *InputModal) SetTitle(s string) {
|
||||
c.title = s
|
||||
}
|
||||
|
||||
// GetText Return the text of the modal
|
||||
func (i *InputModal) GetText() string { return i.text }
|
||||
func (c *InputModal) GetText() string { return c.text }
|
||||
|
||||
// SetText Set the text of the modal to s
|
||||
func (i *InputModal) SetText(s string) {
|
||||
i.text = s
|
||||
func (c *InputModal) SetText(s string) {
|
||||
c.text = s
|
||||
}
|
||||
|
||||
// GetX Return the x position of the modal
|
||||
func (i *InputModal) GetX() int { return i.x }
|
||||
func (c *InputModal) GetX() int { return c.x }
|
||||
|
||||
// SetX set the x position of the modal to x
|
||||
func (i *InputModal) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *InputModal) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY Return the y position of the modal
|
||||
func (i *InputModal) GetY() int { return i.y }
|
||||
func (c *InputModal) GetY() int { return c.y }
|
||||
|
||||
// SetY Set the y position of the modal to y
|
||||
func (i *InputModal) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *InputModal) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth Return the width of the modal
|
||||
func (i *InputModal) GetWidth() int { return i.width }
|
||||
func (c *InputModal) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth Set the width of the modal to width
|
||||
func (i *InputModal) SetWidth(width int) {
|
||||
i.width = width
|
||||
func (c *InputModal) SetWidth(width int) {
|
||||
c.width = width
|
||||
}
|
||||
|
||||
// GetHeight Return the height of the modal
|
||||
func (i *InputModal) GetHeight() int { return i.height }
|
||||
func (c *InputModal) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight Set the height of the modal to height
|
||||
func (i *InputModal) SetHeight(height int) {
|
||||
i.height = height
|
||||
func (c *InputModal) SetHeight(height int) {
|
||||
c.height = height
|
||||
}
|
||||
|
||||
// SetMultiline returns whether this is a multiline modal
|
||||
func (i *InputModal) SetMultiline(m bool) {
|
||||
i.input.multiline = m
|
||||
func (c *InputModal) SetMultiline(m bool) {
|
||||
c.input.multiline = m
|
||||
}
|
||||
|
||||
// IsMultiline returns whether this is a multiline modal
|
||||
func (i *InputModal) IsMultiline() bool {
|
||||
return i.input.multiline
|
||||
func (c *InputModal) IsMultiline() bool {
|
||||
return c.input.multiline
|
||||
}
|
||||
|
||||
// IsBordered returns whether this control is bordered or not
|
||||
func (i *InputModal) IsBordered() bool {
|
||||
return i.bordered
|
||||
func (c *InputModal) IsBordered() bool {
|
||||
return c.bordered
|
||||
}
|
||||
|
||||
// SetBordered sets whether we render a border around the frame
|
||||
func (i *InputModal) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *InputModal) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// IsTabSkipped returns whether this control has it's tabskip flag set
|
||||
func (i *InputModal) IsTabSkipped() bool {
|
||||
return i.tabSkip
|
||||
func (c *InputModal) IsTabSkipped() bool {
|
||||
return c.tabSkip
|
||||
}
|
||||
|
||||
// SetTabSkip sets the tabskip flag for this control
|
||||
func (i *InputModal) SetTabSkip(b bool) {
|
||||
i.tabSkip = b
|
||||
func (c *InputModal) SetTabSkip(b bool) {
|
||||
c.tabSkip = b
|
||||
}
|
||||
|
||||
// HelpIsShown Returns whether the modal is showing it's help text or not
|
||||
func (i *InputModal) HelpIsShown() bool { return i.showHelp }
|
||||
func (c *InputModal) HelpIsShown() bool { return c.showHelp }
|
||||
|
||||
// ShowHelp Set the "Show Help" flag
|
||||
func (i *InputModal) ShowHelp(b bool) {
|
||||
i.showHelp = b
|
||||
func (c *InputModal) ShowHelp(b bool) {
|
||||
c.showHelp = b
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *InputModal) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *InputModal) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *InputModal) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *InputModal) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *InputModal) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *InputModal) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *InputModal) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *InputModal) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// Show Sets the visibility flag to true
|
||||
func (i *InputModal) Show() {
|
||||
i.isVisible = true
|
||||
func (c *InputModal) Show() {
|
||||
c.isVisible = true
|
||||
}
|
||||
|
||||
// Hide Sets the visibility flag to false
|
||||
func (i *InputModal) Hide() {
|
||||
i.isVisible = false
|
||||
func (c *InputModal) Hide() {
|
||||
c.isVisible = false
|
||||
}
|
||||
|
||||
// IsVisible returns the isVisible flag
|
||||
func (i *InputModal) IsVisible() bool {
|
||||
return i.isVisible
|
||||
func (c *InputModal) IsVisible() bool {
|
||||
return c.isVisible
|
||||
}
|
||||
|
||||
// SetDone Sets the flag that tells whether this modal has completed it's purpose
|
||||
func (i *InputModal) SetDone(b bool) {
|
||||
i.isDone = b
|
||||
func (c *InputModal) SetDone(b bool) {
|
||||
c.isDone = b
|
||||
}
|
||||
|
||||
// IsDone Returns the "isDone" flag
|
||||
func (i *InputModal) IsDone() bool {
|
||||
return i.isDone
|
||||
func (c *InputModal) IsDone() bool {
|
||||
return c.isDone
|
||||
}
|
||||
|
||||
// IsAccepted Returns whether the modal has been accepted
|
||||
func (i *InputModal) IsAccepted() bool {
|
||||
return i.isAccepted
|
||||
func (c *InputModal) IsAccepted() bool {
|
||||
return c.isAccepted
|
||||
}
|
||||
|
||||
// GetValue Return the current value of the input
|
||||
func (i *InputModal) GetValue() string { return i.input.GetValue() }
|
||||
func (c *InputModal) GetValue() string { return c.input.GetValue() }
|
||||
|
||||
// SetValue Sets the value of the input to s
|
||||
func (i *InputModal) SetValue(s string) {
|
||||
i.input.SetValue(s)
|
||||
func (c *InputModal) SetValue(s string) {
|
||||
c.input.SetValue(s)
|
||||
}
|
||||
|
||||
// SetInputWrap sets whether the input field will wrap long text or not
|
||||
func (i *InputModal) SetInputWrap(b bool) {
|
||||
i.input.SetWrap(b)
|
||||
func (c *InputModal) SetInputWrap(b bool) {
|
||||
c.input.SetWrap(b)
|
||||
}
|
||||
|
||||
// Clear Resets all non-positional parameters of the modal
|
||||
func (i *InputModal) Clear() {
|
||||
i.title = ""
|
||||
i.text = ""
|
||||
i.input.SetValue("")
|
||||
i.isDone = false
|
||||
i.isVisible = false
|
||||
func (c *InputModal) Clear() {
|
||||
c.title = ""
|
||||
c.text = ""
|
||||
c.input.SetValue("")
|
||||
c.isDone = false
|
||||
c.isVisible = false
|
||||
}
|
||||
|
||||
// HandleEvent Handle the termbox event, return true if it was consumed
|
||||
func (i *InputModal) HandleEvent(event termbox.Event) bool {
|
||||
func (c *InputModal) HandleEvent(event termbox.Event) bool {
|
||||
if event.Key == termbox.KeyEnter {
|
||||
if !i.input.IsMultiline() || !i.inputSelected {
|
||||
if !c.input.IsMultiline() || !c.inputSelected {
|
||||
// Done editing
|
||||
i.isDone = true
|
||||
i.isAccepted = true
|
||||
c.isDone = true
|
||||
c.isAccepted = true
|
||||
} else {
|
||||
i.input.HandleEvent(event)
|
||||
c.input.HandleEvent(event)
|
||||
}
|
||||
return true
|
||||
} else if event.Key == termbox.KeyTab {
|
||||
if i.input.IsMultiline() {
|
||||
i.inputSelected = !i.inputSelected
|
||||
if c.input.IsMultiline() {
|
||||
c.inputSelected = !c.inputSelected
|
||||
}
|
||||
} else if event.Key == termbox.KeyEsc {
|
||||
// Done editing
|
||||
i.isDone = true
|
||||
i.isAccepted = false
|
||||
c.isDone = true
|
||||
c.isAccepted = false
|
||||
return true
|
||||
}
|
||||
return i.input.HandleEvent(event)
|
||||
return c.input.HandleEvent(event)
|
||||
}
|
||||
|
||||
// Draw Draw the modal
|
||||
func (i *InputModal) Draw() {
|
||||
if i.isVisible {
|
||||
func (c *InputModal) Draw() {
|
||||
if c.isVisible {
|
||||
// First blank out the area we'll be putting the modal
|
||||
FillWithChar(' ', i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
nextY := i.y + 1
|
||||
FillWithChar(' ', c.x, c.y, c.x+c.width, c.y+c.height, c.fg, c.bg)
|
||||
nextY := c.y + 1
|
||||
// The title
|
||||
if i.title != "" {
|
||||
if len(i.title) > i.width {
|
||||
diff := i.width - len(i.title)
|
||||
DrawStringAtPoint(i.title[:len(i.title)+diff-1], i.x+1, nextY, i.fg, i.bg)
|
||||
if c.title != "" {
|
||||
if len(c.title) > c.width {
|
||||
diff := c.width - len(c.title)
|
||||
DrawStringAtPoint(c.title[:len(c.title)+diff-1], c.x+1, nextY, c.fg, c.bg)
|
||||
} else {
|
||||
DrawStringAtPoint(i.title, i.x+1, nextY, i.fg, i.bg)
|
||||
DrawStringAtPoint(c.title, c.x+1, nextY, c.fg, c.bg)
|
||||
}
|
||||
nextY++
|
||||
FillWithChar('-', i.x+1, nextY, i.x+i.width-1, nextY, i.fg, i.bg)
|
||||
FillWithChar('-', c.x+1, nextY, c.x+c.width-1, nextY, c.fg, c.bg)
|
||||
nextY++
|
||||
}
|
||||
if i.text != "" {
|
||||
DrawStringAtPoint(i.text, i.x+1, nextY, i.fg, i.bg)
|
||||
if c.text != "" {
|
||||
DrawStringAtPoint(c.text, c.x+1, nextY, c.fg, c.bg)
|
||||
nextY++
|
||||
}
|
||||
i.input.SetY(nextY)
|
||||
i.input.Draw()
|
||||
c.input.SetY(nextY)
|
||||
c.input.Draw()
|
||||
nextY += 3
|
||||
if i.showHelp {
|
||||
if c.showHelp {
|
||||
helpString := " (ENTER) to Accept. (ESC) to Cancel. "
|
||||
helpX := (i.x + i.width - len(helpString)) - 1
|
||||
DrawStringAtPoint(helpString, helpX, nextY, i.fg, i.bg)
|
||||
helpX := (c.x + c.width - len(helpString)) - 1
|
||||
DrawStringAtPoint(helpString, helpX, nextY, c.fg, c.bg)
|
||||
}
|
||||
if i.bordered {
|
||||
if c.bordered {
|
||||
// Now draw the border
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, c.fg, c.bg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
116
termbox_label.go
116
termbox_label.go
@ -9,133 +9,133 @@ type Label struct {
|
||||
x, y, width, height int
|
||||
cursor int
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
bordered bool
|
||||
wrap bool
|
||||
multiline bool
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateLabel creates an input field at x, y that is w by h
|
||||
func CreateLabel(lbl string, x, y, w, h int, fg, bg termbox.Attribute) *Label {
|
||||
i := Label{value: lbl, x: x, y: y, width: w, height: h, fg: fg, bg: bg}
|
||||
return &i
|
||||
c := Label{
|
||||
value: lbl, x: x, y: y, width: w, height: h,
|
||||
fg: fg, bg: bg, activeFg: fg, activeBg: bg,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Label) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *Label) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *Label) SetActive(a bool) { c.active = a }
|
||||
func (c *Label) IsActive() bool { return c.active }
|
||||
|
||||
// IsTabSkipped is always true for a label
|
||||
func (i *Label) IsTabSkipped() bool {
|
||||
return true
|
||||
}
|
||||
func (c *Label) IsTabSkipped() bool { return true }
|
||||
|
||||
// This doesn't do anything for a label
|
||||
func (i *Label) SetTabSkip(b bool) {}
|
||||
func (c *Label) SetTabSkip(b bool) {}
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *Label) GetID() string { return i.id }
|
||||
func (c *Label) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *Label) SetID(newID string) {
|
||||
i.id = newID
|
||||
}
|
||||
func (c *Label) SetID(newID string) { c.id = newID }
|
||||
|
||||
// GetValue gets the current text that is in the Label
|
||||
func (i *Label) GetValue() string { return i.value }
|
||||
func (c *Label) GetValue() string { return c.value }
|
||||
|
||||
// SetValue sets the current text in the Label to s
|
||||
func (i *Label) SetValue(s string) {
|
||||
i.value = s
|
||||
}
|
||||
func (c *Label) SetValue(s string) { c.value = s }
|
||||
|
||||
// GetX returns the x position of the input field
|
||||
func (i *Label) GetX() int { return i.x }
|
||||
func (c *Label) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the x position of the input field
|
||||
func (i *Label) SetX(x int) {
|
||||
i.x = x
|
||||
}
|
||||
func (c *Label) SetX(x int) { c.x = x }
|
||||
|
||||
// GetY returns the y position of the input field
|
||||
func (i *Label) GetY() int { return i.y }
|
||||
func (c *Label) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the y position of the input field
|
||||
func (i *Label) SetY(y int) {
|
||||
i.y = y
|
||||
}
|
||||
func (c *Label) SetY(y int) { c.y = y }
|
||||
|
||||
// GetWidth returns the current width of the input field
|
||||
func (i *Label) GetWidth() int {
|
||||
if i.width == -1 {
|
||||
if i.bordered {
|
||||
return len(i.value) + 2
|
||||
func (c *Label) GetWidth() int {
|
||||
if c.width == -1 {
|
||||
if c.bordered {
|
||||
return len(c.value) + 2
|
||||
}
|
||||
return len(i.value)
|
||||
return len(c.value)
|
||||
}
|
||||
return i.width
|
||||
return c.width
|
||||
}
|
||||
|
||||
// SetWidth sets the current width of the input field
|
||||
func (i *Label) SetWidth(w int) {
|
||||
i.width = w
|
||||
func (c *Label) SetWidth(w int) {
|
||||
c.width = w
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the input field
|
||||
func (i *Label) GetHeight() int { return i.height }
|
||||
func (c *Label) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight sets the current height of the input field
|
||||
func (i *Label) SetHeight(h int) {
|
||||
i.height = h
|
||||
func (c *Label) SetHeight(h int) {
|
||||
c.height = h
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *Label) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *Label) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *Label) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *Label) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *Label) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *Label) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *Label) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *Label) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// IsBordered returns true or false if this input field has a border
|
||||
func (i *Label) IsBordered() bool { return i.bordered }
|
||||
func (c *Label) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets whether we render a border around the input field
|
||||
func (i *Label) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *Label) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// DoesWrap returns true or false if this input field wraps text
|
||||
func (i *Label) DoesWrap() bool { return i.wrap }
|
||||
func (c *Label) DoesWrap() bool { return c.wrap }
|
||||
|
||||
// SetWrap sets whether we wrap the text at width.
|
||||
func (i *Label) SetWrap(b bool) {
|
||||
i.wrap = b
|
||||
func (c *Label) SetWrap(b bool) {
|
||||
c.wrap = b
|
||||
}
|
||||
|
||||
// IsMultiline returns true or false if this field can have multiple lines
|
||||
func (i *Label) IsMultiline() bool { return i.multiline }
|
||||
func (c *Label) IsMultiline() bool { return c.multiline }
|
||||
|
||||
// SetMultiline sets whether the field can have multiple lines
|
||||
func (i *Label) SetMultiline(b bool) {
|
||||
i.multiline = b
|
||||
func (c *Label) SetMultiline(b bool) {
|
||||
c.multiline = b
|
||||
}
|
||||
|
||||
// HandleEvent accepts the termbox event and returns whether it was consumed
|
||||
func (i *Label) HandleEvent(event termbox.Event) bool { return false }
|
||||
func (c *Label) HandleEvent(event termbox.Event) bool { return false }
|
||||
|
||||
// Draw outputs the input field on the screen
|
||||
func (i *Label) Draw() {
|
||||
maxWidth := i.width
|
||||
maxHeight := i.height
|
||||
x, y := i.x, i.y
|
||||
startX := i.x
|
||||
startY := i.y
|
||||
if i.bordered {
|
||||
DrawBorder(i.x, i.y, i.x+i.GetWidth(), i.y+i.height, i.fg, i.bg)
|
||||
func (c *Label) Draw() {
|
||||
maxWidth := c.width
|
||||
maxHeight := c.height
|
||||
x, y := c.x, c.y
|
||||
startX := c.x
|
||||
startY := c.y
|
||||
if c.bordered {
|
||||
DrawBorder(c.x, c.y, c.x+c.GetWidth(), c.y+c.height, c.fg, c.bg)
|
||||
maxWidth--
|
||||
maxHeight--
|
||||
x++
|
||||
@ -144,5 +144,5 @@ func (i *Label) Draw() {
|
||||
startY++
|
||||
}
|
||||
|
||||
DrawStringAtPoint(i.value, x, y, i.fg, i.bg)
|
||||
DrawStringAtPoint(c.value, x, y, c.fg, c.bg)
|
||||
}
|
||||
|
431
termbox_menu.go
431
termbox_menu.go
@ -14,118 +14,134 @@ type Menu struct {
|
||||
bg, fg termbox.Attribute
|
||||
selectedBg, selectedFg termbox.Attribute
|
||||
disabledBg, disabledFg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
isDone bool
|
||||
bordered bool
|
||||
vimMode bool
|
||||
tabSkip bool
|
||||
active 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{
|
||||
c := Menu{
|
||||
title: title,
|
||||
x: x, y: y, width: width, height: height,
|
||||
fg: fg, bg: bg, selectedFg: bg, selectedBg: fg,
|
||||
disabledFg: bg, disabledBg: bg,
|
||||
activeFg: fg, activeBg: bg,
|
||||
bordered: true,
|
||||
}
|
||||
for _, line := range options {
|
||||
i.options = append(i.options, MenuOption{text: line})
|
||||
c.options = append(c.options, MenuOption{text: line})
|
||||
}
|
||||
if len(i.options) > 0 {
|
||||
i.SetSelectedOption(&i.options[0])
|
||||
if len(c.options) > 0 {
|
||||
c.SetSelectedOption(&c.options[0])
|
||||
}
|
||||
return &i
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Menu) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
|
||||
func (c *Menu) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
|
||||
func (c *Menu) SetActive(a bool) { c.active = a }
|
||||
|
||||
func (c *Menu) IsActive() bool { return c.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *Menu) GetID() string { return i.id }
|
||||
func (c *Menu) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *Menu) SetID(newID string) {
|
||||
i.id = newID
|
||||
}
|
||||
func (c *Menu) SetID(newID string) { c.id = newID }
|
||||
|
||||
// IsTabSkipped is always true for a label
|
||||
func (c *Menu) IsTabSkipped() bool { return true }
|
||||
|
||||
// This doesn't do anything for a label
|
||||
func (c *Menu) SetTabSkip(b bool) {}
|
||||
|
||||
// GetTitle returns the current title of the menu
|
||||
func (i *Menu) GetTitle() string { return i.title }
|
||||
func (c *Menu) GetTitle() string { return c.title }
|
||||
|
||||
// SetTitle sets the current title of the menu to s
|
||||
func (i *Menu) SetTitle(s string) {
|
||||
i.title = s
|
||||
func (c *Menu) SetTitle(s string) {
|
||||
c.title = s
|
||||
}
|
||||
|
||||
// GetOptions returns the current options of the menu
|
||||
func (i *Menu) GetOptions() []MenuOption {
|
||||
return i.options
|
||||
func (c *Menu) GetOptions() []MenuOption {
|
||||
return c.options
|
||||
}
|
||||
|
||||
// SetOptions set the menu's options to opts
|
||||
func (i *Menu) SetOptions(opts []MenuOption) {
|
||||
i.options = opts
|
||||
func (c *Menu) SetOptions(opts []MenuOption) {
|
||||
c.options = opts
|
||||
}
|
||||
|
||||
// SetOptionsFromStrings sets the options of this menu from a slice of strings
|
||||
func (i *Menu) SetOptionsFromStrings(opts []string) {
|
||||
func (c *Menu) SetOptionsFromStrings(opts []string) {
|
||||
var newOpts []MenuOption
|
||||
for _, v := range opts {
|
||||
newOpts = append(newOpts, *CreateOptionFromText(v))
|
||||
}
|
||||
i.SetOptions(newOpts)
|
||||
i.SetSelectedOption(i.GetOptionFromIndex(0))
|
||||
c.SetOptions(newOpts)
|
||||
c.SetSelectedOption(c.GetOptionFromIndex(0))
|
||||
}
|
||||
|
||||
// GetX returns the current x coordinate of the menu
|
||||
func (i *Menu) GetX() int { return i.x }
|
||||
func (c *Menu) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the current x coordinate of the menu to x
|
||||
func (i *Menu) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *Menu) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY returns the current y coordinate of the menu
|
||||
func (i *Menu) GetY() int { return i.y }
|
||||
func (c *Menu) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the current y coordinate of the menu to y
|
||||
func (i *Menu) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *Menu) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth returns the current width of the menu
|
||||
func (i *Menu) GetWidth() int { return i.width }
|
||||
func (c *Menu) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth sets the current menu width to width
|
||||
func (i *Menu) SetWidth(width int) {
|
||||
i.width = width
|
||||
func (c *Menu) SetWidth(width int) {
|
||||
c.width = width
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the menu
|
||||
func (i *Menu) GetHeight() int { return i.height }
|
||||
func (c *Menu) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight set the height of the menu to height
|
||||
func (i *Menu) SetHeight(height int) {
|
||||
i.height = height
|
||||
func (c *Menu) SetHeight(height int) {
|
||||
c.height = height
|
||||
}
|
||||
|
||||
// GetSelectedOption returns the current selected option
|
||||
func (i *Menu) GetSelectedOption() *MenuOption {
|
||||
idx := i.GetSelectedIndex()
|
||||
func (c *Menu) GetSelectedOption() *MenuOption {
|
||||
idx := c.GetSelectedIndex()
|
||||
if idx != -1 {
|
||||
return &i.options[idx]
|
||||
return &c.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]
|
||||
func (c *Menu) GetOptionFromIndex(idx int) *MenuOption {
|
||||
if idx >= 0 && idx < len(c.options) {
|
||||
return &c.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]
|
||||
func (c *Menu) GetOptionFromText(v string) *MenuOption {
|
||||
for idx := range c.options {
|
||||
testOption := &c.options[idx]
|
||||
if testOption.GetText() == v {
|
||||
return testOption
|
||||
}
|
||||
@ -135,9 +151,9 @@ func (i *Menu) GetOptionFromText(v string) *MenuOption {
|
||||
|
||||
// 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() {
|
||||
func (c *Menu) GetSelectedIndex() int {
|
||||
for idx := range c.options {
|
||||
if c.options[idx].IsSelected() {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
@ -145,267 +161,288 @@ func (i *Menu) GetSelectedIndex() int {
|
||||
}
|
||||
|
||||
// SetSelectedIndex sets the selection to setIdx
|
||||
func (i *Menu) SetSelectedIndex(idx int) {
|
||||
if len(i.options) > 0 {
|
||||
func (c *Menu) SetSelectedIndex(idx int) {
|
||||
if len(c.options) > 0 {
|
||||
if idx < 0 {
|
||||
idx = 0
|
||||
} else if idx >= len(i.options) {
|
||||
idx = len(i.options) - 1
|
||||
} else if idx >= len(c.options) {
|
||||
idx = len(c.options) - 1
|
||||
}
|
||||
i.SetSelectedOption(&i.options[idx])
|
||||
c.SetSelectedOption(&c.options[idx])
|
||||
}
|
||||
}
|
||||
|
||||
// SetSelectedOption sets the current selected option to v (if it's valid)
|
||||
func (i *Menu) SetSelectedOption(v *MenuOption) {
|
||||
for idx := range i.options {
|
||||
if &i.options[idx] == v {
|
||||
i.options[idx].Select()
|
||||
func (c *Menu) SetSelectedOption(v *MenuOption) {
|
||||
for idx := range c.options {
|
||||
if &c.options[idx] == v {
|
||||
c.options[idx].Select()
|
||||
} else {
|
||||
i.options[idx].Unselect()
|
||||
c.options[idx].Unselect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectPrevOption Decrements the selected option (if it can)
|
||||
func (i *Menu) SelectPrevOption() {
|
||||
idx := i.GetSelectedIndex()
|
||||
func (c *Menu) SelectPrevOption() {
|
||||
idx := c.GetSelectedIndex()
|
||||
for idx >= 0 {
|
||||
idx--
|
||||
testOption := i.GetOptionFromIndex(idx)
|
||||
testOption := c.GetOptionFromIndex(idx)
|
||||
if testOption != nil && !testOption.IsDisabled() {
|
||||
i.SetSelectedOption(testOption)
|
||||
c.SetSelectedOption(testOption)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectNextOption Increments the selected option (if it can)
|
||||
func (i *Menu) SelectNextOption() {
|
||||
idx := i.GetSelectedIndex()
|
||||
for idx < len(i.options) {
|
||||
func (c *Menu) SelectNextOption() {
|
||||
idx := c.GetSelectedIndex()
|
||||
for idx < len(c.options) {
|
||||
idx++
|
||||
testOption := i.GetOptionFromIndex(idx)
|
||||
testOption := c.GetOptionFromIndex(idx)
|
||||
if testOption != nil && !testOption.IsDisabled() {
|
||||
i.SetSelectedOption(testOption)
|
||||
c.SetSelectedOption(testOption)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SelectPageUpOption Goes up 'menu height' options
|
||||
func (i *Menu) SelectPageUpOption() {
|
||||
idx := i.GetSelectedIndex()
|
||||
idx -= i.height
|
||||
func (c *Menu) SelectPageUpOption() {
|
||||
idx := c.GetSelectedIndex()
|
||||
idx -= c.height
|
||||
if idx < 0 {
|
||||
idx = 0
|
||||
}
|
||||
i.SetSelectedIndex(idx)
|
||||
c.SetSelectedIndex(idx)
|
||||
return
|
||||
}
|
||||
|
||||
// SelectPageDownOption Goes down 'menu height' options
|
||||
func (i *Menu) SelectPageDownOption() {
|
||||
idx := i.GetSelectedIndex()
|
||||
idx += i.height
|
||||
if idx >= len(i.options) {
|
||||
idx = len(i.options) - 1
|
||||
func (c *Menu) SelectPageDownOption() {
|
||||
idx := c.GetSelectedIndex()
|
||||
idx += c.height
|
||||
if idx >= len(c.options) {
|
||||
idx = len(c.options) - 1
|
||||
}
|
||||
i.SetSelectedIndex(idx)
|
||||
c.SetSelectedIndex(idx)
|
||||
return
|
||||
}
|
||||
|
||||
// SelectFirstOption Goes to the top
|
||||
func (i *Menu) SelectFirstOption() {
|
||||
i.SetSelectedIndex(0)
|
||||
func (c *Menu) SelectFirstOption() {
|
||||
c.SetSelectedIndex(0)
|
||||
return
|
||||
}
|
||||
|
||||
// SelectLastOption Goes to the bottom
|
||||
func (i *Menu) SelectLastOption() {
|
||||
i.SetSelectedIndex(len(i.options) - 1)
|
||||
func (c *Menu) SelectLastOption() {
|
||||
c.SetSelectedIndex(len(c.options) - 1)
|
||||
return
|
||||
}
|
||||
|
||||
// SetOptionDisabled Disables the specified option
|
||||
func (i *Menu) SetOptionDisabled(idx int) {
|
||||
if len(i.options) > idx {
|
||||
i.GetOptionFromIndex(idx).Disable()
|
||||
func (c *Menu) SetOptionDisabled(idx int) {
|
||||
if len(c.options) > idx {
|
||||
c.GetOptionFromIndex(idx).Disable()
|
||||
}
|
||||
}
|
||||
|
||||
// SetOptionEnabled Enables the specified option
|
||||
func (i *Menu) SetOptionEnabled(idx int) {
|
||||
if len(i.options) > idx {
|
||||
i.GetOptionFromIndex(idx).Enable()
|
||||
func (c *Menu) SetOptionEnabled(idx int) {
|
||||
if len(c.options) > idx {
|
||||
c.GetOptionFromIndex(idx).Enable()
|
||||
}
|
||||
}
|
||||
|
||||
// HelpIsShown returns true or false if the help is displayed
|
||||
func (i *Menu) HelpIsShown() bool { return i.showHelp }
|
||||
func (c *Menu) HelpIsShown() bool { return c.showHelp }
|
||||
|
||||
// ShowHelp sets whether or not to display the help text
|
||||
func (i *Menu) ShowHelp(b bool) {
|
||||
i.showHelp = b
|
||||
func (c *Menu) ShowHelp(b bool) {
|
||||
c.showHelp = b
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *Menu) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *Menu) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *Menu) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *Menu) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *Menu) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *Menu) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *Menu) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *Menu) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// IsDone returns whether the user has answered the modal
|
||||
func (i *Menu) IsDone() bool { return i.isDone }
|
||||
func (c *Menu) IsDone() bool { return c.isDone }
|
||||
|
||||
// SetDone sets whether the modal has completed it's purpose
|
||||
func (i *Menu) SetDone(b bool) {
|
||||
i.isDone = b
|
||||
func (c *Menu) SetDone(b bool) {
|
||||
c.isDone = b
|
||||
}
|
||||
|
||||
// IsBordered returns true or false if this menu has a border
|
||||
func (i *Menu) IsBordered() bool { return i.bordered }
|
||||
func (c *Menu) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets whether we render a border around the menu
|
||||
func (i *Menu) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *Menu) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// EnableVimMode Enables h,j,k,l navigation
|
||||
func (i *Menu) EnableVimMode() {
|
||||
i.vimMode = true
|
||||
func (c *Menu) EnableVimMode() {
|
||||
c.vimMode = true
|
||||
}
|
||||
|
||||
// DisableVimMode Disables h,j,k,l navigation
|
||||
func (i *Menu) DisableVimMode() {
|
||||
i.vimMode = false
|
||||
func (c *Menu) DisableVimMode() {
|
||||
c.vimMode = false
|
||||
}
|
||||
|
||||
// HandleEvent handles the termbox event and returns whether it was consumed
|
||||
func (i *Menu) HandleEvent(event termbox.Event) bool {
|
||||
func (c *Menu) HandleEvent(event termbox.Event) bool {
|
||||
if event.Key == termbox.KeyEnter || event.Key == termbox.KeySpace {
|
||||
i.isDone = true
|
||||
c.isDone = true
|
||||
return true
|
||||
}
|
||||
currentIdx := i.GetSelectedIndex()
|
||||
currentIdx := c.GetSelectedIndex()
|
||||
switch event.Key {
|
||||
case termbox.KeyArrowUp:
|
||||
i.SelectPrevOption()
|
||||
c.SelectPrevOption()
|
||||
case termbox.KeyArrowDown:
|
||||
i.SelectNextOption()
|
||||
c.SelectNextOption()
|
||||
case termbox.KeyArrowLeft:
|
||||
i.SelectPageUpOption()
|
||||
c.SelectPageUpOption()
|
||||
case termbox.KeyArrowRight:
|
||||
i.SelectPageDownOption()
|
||||
c.SelectPageDownOption()
|
||||
}
|
||||
if i.vimMode {
|
||||
if c.vimMode {
|
||||
switch event.Ch {
|
||||
case 'j':
|
||||
i.SelectNextOption()
|
||||
c.SelectNextOption()
|
||||
case 'k':
|
||||
i.SelectPrevOption()
|
||||
c.SelectPrevOption()
|
||||
}
|
||||
if event.Key == termbox.KeyCtrlF {
|
||||
i.SelectPageDownOption()
|
||||
c.SelectPageDownOption()
|
||||
} else if event.Key == termbox.KeyCtrlB {
|
||||
i.SelectPageUpOption()
|
||||
c.SelectPageUpOption()
|
||||
}
|
||||
}
|
||||
if i.GetSelectedIndex() != currentIdx {
|
||||
if c.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)
|
||||
func (c *Menu) Draw() {
|
||||
useFg, useBg := c.fg, c.bg
|
||||
if c.active {
|
||||
useFg, useBg = c.activeFg, c.activeBg
|
||||
}
|
||||
if i.bordered {
|
||||
if i.height == -1 {
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+optionHeight+1, i.fg, i.bg)
|
||||
// First blank out the area we'll be putting the menu
|
||||
FillWithChar(' ', c.x, c.y, c.x+c.width, c.y+c.height, useFg, useBg)
|
||||
// Now draw the border
|
||||
optionStartX := c.x
|
||||
optionStartY := c.y
|
||||
optionWidth := c.width
|
||||
_ = optionWidth
|
||||
optionHeight := c.height
|
||||
if optionHeight == -1 {
|
||||
optionHeight = len(c.options)
|
||||
}
|
||||
if c.bordered {
|
||||
pct := float64(c.GetSelectedIndex()) / float64(len(c.options))
|
||||
if c.title == "" {
|
||||
if len(c.options) > c.height-2 {
|
||||
DrawBorderWithPct(c.x, c.y, c.x+c.width, c.y+c.height, pct, useFg, useBg)
|
||||
} else {
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, useFg, useBg)
|
||||
}
|
||||
} else {
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+optionHeight, i.fg, i.bg)
|
||||
if len(c.options) > c.height-2 {
|
||||
DrawBorderWithTitleAndPct(c.x, c.y, c.x+c.width, c.y+c.height, " "+c.title+" ", pct, useFg, useBg)
|
||||
} else {
|
||||
DrawBorderWithTitle(c.x, c.y, c.x+c.width, c.y+c.height, " "+c.title+" ", useFg, useBg)
|
||||
}
|
||||
}
|
||||
optionStartX = i.x + 1
|
||||
optionStartY = i.y + 1
|
||||
optionWidth = i.width - 1
|
||||
optionStartX = c.x + 1
|
||||
optionStartY = c.y + 1
|
||||
optionWidth = c.width - 1
|
||||
optionHeight -= 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++
|
||||
optionHeight--
|
||||
if len(c.options) > 0 {
|
||||
firstDispIdx := 0
|
||||
lastDispIdx := len(c.options) - 1
|
||||
if len(c.options) > c.height-2 {
|
||||
lastDispIdx = c.height - 2
|
||||
}
|
||||
optionHeight--
|
||||
}
|
||||
|
||||
if len(i.options) > 0 {
|
||||
// If the currently selected option is disabled, move to the next
|
||||
if i.GetSelectedOption().IsDisabled() {
|
||||
i.SelectNextOption()
|
||||
if c.GetSelectedIndex() > c.height-2 {
|
||||
firstDispIdx = c.GetSelectedIndex() - (c.height - 2)
|
||||
lastDispIdx = c.GetSelectedIndex()
|
||||
}
|
||||
|
||||
// Print the options
|
||||
bldHeight := (optionHeight / 2)
|
||||
startIdx := i.GetSelectedIndex()
|
||||
endIdx := i.GetSelectedIndex()
|
||||
for bldHeight > 0 && startIdx >= 1 {
|
||||
startIdx--
|
||||
bldHeight--
|
||||
}
|
||||
bldHeight += (optionHeight / 2)
|
||||
for bldHeight > 0 && endIdx < len(i.options) {
|
||||
endIdx++
|
||||
bldHeight--
|
||||
}
|
||||
|
||||
for idx := startIdx; idx < endIdx; idx++ { //i.options {
|
||||
if i.GetSelectedIndex()-idx >= optionHeight-1 {
|
||||
// Skip this one
|
||||
continue
|
||||
}
|
||||
currOpt := &i.options[idx]
|
||||
for idx := firstDispIdx; idx < lastDispIdx; idx++ {
|
||||
currOpt := &c.options[idx]
|
||||
outTxt := currOpt.GetText()
|
||||
if len(outTxt) >= i.width {
|
||||
outTxt = outTxt[:i.width]
|
||||
}
|
||||
if currOpt.IsDisabled() {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, i.disabledFg, i.disabledBg)
|
||||
} else if i.GetSelectedOption() == currOpt {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, i.selectedFg, i.selectedBg)
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, c.disabledFg, c.disabledBg)
|
||||
} else if c.GetSelectedOption() == currOpt {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, c.selectedFg, c.selectedBg)
|
||||
} else {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, i.fg, i.bg)
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, useFg, useBg)
|
||||
}
|
||||
optionStartY++
|
||||
if optionStartY > i.y+optionHeight-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Print the options
|
||||
bldHeight := (optionHeight / 2)
|
||||
startIdx := c.GetSelectedIndex()
|
||||
endIdx := c.GetSelectedIndex()
|
||||
for bldHeight > 0 && startIdx >= 1 {
|
||||
startIdx--
|
||||
bldHeight--
|
||||
}
|
||||
bldHeight += (optionHeight / 2)
|
||||
for bldHeight > 0 && endIdx < len(c.options) {
|
||||
endIdx++
|
||||
bldHeight--
|
||||
}
|
||||
|
||||
for idx := startIdx; idx < endIdx; idx++ {
|
||||
if c.GetSelectedIndex()-idx >= optionHeight-1 {
|
||||
// Skip this one
|
||||
continue
|
||||
}
|
||||
currOpt := &c.options[idx]
|
||||
outTxt := currOpt.GetText()
|
||||
if len(outTxt) >= c.width {
|
||||
outTxt = outTxt[:c.width]
|
||||
}
|
||||
if currOpt.IsDisabled() {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, c.disabledFg, c.disabledBg)
|
||||
} else if c.GetSelectedOption() == currOpt {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, c.selectedFg, c.selectedBg)
|
||||
} else {
|
||||
DrawStringAtPoint(outTxt, optionStartX, optionStartY, useFg, useBg)
|
||||
}
|
||||
optionStartY++
|
||||
if optionStartY > c.y+optionHeight-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* MenuOption Struct & methods */
|
||||
@ -427,52 +464,52 @@ func CreateOptionFromText(s string) *MenuOption {
|
||||
}
|
||||
|
||||
// SetText Sets the text for this option
|
||||
func (i *MenuOption) SetText(s string) {
|
||||
i.text = s
|
||||
func (c *MenuOption) SetText(s string) {
|
||||
c.text = s
|
||||
}
|
||||
|
||||
// GetText Returns the text for this option
|
||||
func (i *MenuOption) GetText() string { return i.text }
|
||||
func (c *MenuOption) GetText() string { return c.text }
|
||||
|
||||
// Disable Sets this option to disabled
|
||||
func (i *MenuOption) Disable() {
|
||||
i.disabled = true
|
||||
func (c *MenuOption) Disable() {
|
||||
c.disabled = true
|
||||
}
|
||||
|
||||
// Enable Sets this option to enabled
|
||||
func (i *MenuOption) Enable() {
|
||||
i.disabled = false
|
||||
func (c *MenuOption) Enable() {
|
||||
c.disabled = false
|
||||
}
|
||||
|
||||
// IsDisabled returns whether this option is enabled
|
||||
func (i *MenuOption) IsDisabled() bool {
|
||||
return i.disabled
|
||||
func (c *MenuOption) IsDisabled() bool {
|
||||
return c.disabled
|
||||
}
|
||||
|
||||
// IsSelected Returns whether this option is selected
|
||||
func (i *MenuOption) IsSelected() bool {
|
||||
return i.selected
|
||||
func (c *MenuOption) IsSelected() bool {
|
||||
return c.selected
|
||||
}
|
||||
|
||||
// Select Sets this option to selected
|
||||
func (i *MenuOption) Select() {
|
||||
i.selected = true
|
||||
func (c *MenuOption) Select() {
|
||||
c.selected = true
|
||||
}
|
||||
|
||||
// Unselect Sets this option to not selected
|
||||
func (i *MenuOption) Unselect() {
|
||||
i.selected = false
|
||||
func (c *MenuOption) Unselect() {
|
||||
c.selected = false
|
||||
}
|
||||
|
||||
// SetHelpText Sets this option's help text to s
|
||||
func (i *MenuOption) SetHelpText(s string) {
|
||||
i.helpText = s
|
||||
func (c *MenuOption) SetHelpText(s string) {
|
||||
c.helpText = s
|
||||
}
|
||||
|
||||
// GetHelpText Returns the help text for this option
|
||||
func (i *MenuOption) GetHelpText() string { return i.helpText }
|
||||
func (c *MenuOption) GetHelpText() string { return c.helpText }
|
||||
|
||||
// AddToSubMenu adds a slice of MenuOptions to this option
|
||||
func (i *MenuOption) AddToSubMenu(sub *MenuOption) {
|
||||
i.subMenu = append(i.subMenu, *sub)
|
||||
func (c *MenuOption) AddToSubMenu(sub *MenuOption) {
|
||||
c.subMenu = append(c.subMenu, *sub)
|
||||
}
|
||||
|
@ -15,157 +15,165 @@ type ProgressBar struct {
|
||||
alignment TextAlignment
|
||||
colorized bool
|
||||
|
||||
x, y int
|
||||
width, height int
|
||||
bg, fg termbox.Attribute
|
||||
x, y int
|
||||
width, height int
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateProgressBar Create a progress bar object
|
||||
func CreateProgressBar(tot, x, y int, fg, bg termbox.Attribute) *ProgressBar {
|
||||
i := ProgressBar{total: tot,
|
||||
c := ProgressBar{total: tot,
|
||||
fullChar: '#', emptyChar: ' ',
|
||||
x: x, y: y, height: 1, width: 10,
|
||||
bordered: true, fg: fg, bg: bg,
|
||||
activeFg: fg, activeBg: bg,
|
||||
alignment: AlignLeft,
|
||||
}
|
||||
return &i
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *ProgressBar) SetActiveFgColor(fg termbox.Attribute) { c.activeFg = fg }
|
||||
func (c *ProgressBar) SetActiveBgColor(bg termbox.Attribute) { c.activeBg = bg }
|
||||
func (c *ProgressBar) SetActive(a bool) { c.active = a }
|
||||
func (c *ProgressBar) IsActive() bool { return c.active }
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *ProgressBar) GetID() string { return i.id }
|
||||
func (c *ProgressBar) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *ProgressBar) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *ProgressBar) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
// GetProgress returns the curret progress value
|
||||
func (i *ProgressBar) GetProgress() int {
|
||||
return i.progress
|
||||
func (c *ProgressBar) GetProgress() int {
|
||||
return c.progress
|
||||
}
|
||||
|
||||
// SetProgress sets the current progress of the bar
|
||||
func (i *ProgressBar) SetProgress(p int) {
|
||||
if (p <= i.total || i.allowOverflow) || (p >= 0 || i.allowUnderflow) {
|
||||
i.progress = p
|
||||
func (c *ProgressBar) SetProgress(p int) {
|
||||
if (p <= c.total || c.allowOverflow) || (p >= 0 || c.allowUnderflow) {
|
||||
c.progress = p
|
||||
}
|
||||
}
|
||||
|
||||
// IncrProgress increments the current progress of the bar
|
||||
func (i *ProgressBar) IncrProgress() {
|
||||
if i.progress < i.total || i.allowOverflow {
|
||||
i.progress++
|
||||
func (c *ProgressBar) IncrProgress() {
|
||||
if c.progress < c.total || c.allowOverflow {
|
||||
c.progress++
|
||||
}
|
||||
}
|
||||
|
||||
// DecrProgress decrements the current progress of the bar
|
||||
func (i *ProgressBar) DecrProgress() {
|
||||
if i.progress > 0 || i.allowUnderflow {
|
||||
i.progress--
|
||||
func (c *ProgressBar) DecrProgress() {
|
||||
if c.progress > 0 || c.allowUnderflow {
|
||||
c.progress--
|
||||
}
|
||||
}
|
||||
|
||||
// GetPercent returns the percent full of the bar
|
||||
func (i *ProgressBar) GetPercent() int {
|
||||
return int(float64(i.progress) / float64(i.total) * 100)
|
||||
func (c *ProgressBar) GetPercent() int {
|
||||
return int(float64(c.progress) / float64(c.total) * 100)
|
||||
}
|
||||
|
||||
// EnableOverflow Tells the progress bar that it can go over the total
|
||||
func (i *ProgressBar) EnableOverflow() {
|
||||
i.allowOverflow = true
|
||||
func (c *ProgressBar) EnableOverflow() {
|
||||
c.allowOverflow = true
|
||||
}
|
||||
|
||||
// DisableOverflow Tells the progress bar that it can NOT go over the total
|
||||
func (i *ProgressBar) DisableOverflow() {
|
||||
i.allowOverflow = false
|
||||
func (c *ProgressBar) DisableOverflow() {
|
||||
c.allowOverflow = false
|
||||
}
|
||||
|
||||
// EnableUnderflow Tells the progress bar that it can go below zero
|
||||
func (i *ProgressBar) EnableUnderflow() {
|
||||
i.allowUnderflow = true
|
||||
func (c *ProgressBar) EnableUnderflow() {
|
||||
c.allowUnderflow = true
|
||||
}
|
||||
|
||||
// DisableUnderflow Tells the progress bar that it can NOT go below zero
|
||||
func (i *ProgressBar) DisableUnderflow() {
|
||||
i.allowUnderflow = false
|
||||
func (c *ProgressBar) DisableUnderflow() {
|
||||
c.allowUnderflow = false
|
||||
}
|
||||
|
||||
// GetFullChar returns the rune used for 'full'
|
||||
func (i *ProgressBar) GetFullChar() rune {
|
||||
return i.fullChar
|
||||
func (c *ProgressBar) GetFullChar() rune {
|
||||
return c.fullChar
|
||||
}
|
||||
|
||||
// SetFullChar sets the rune used for 'full'
|
||||
func (i *ProgressBar) SetFullChar(f rune) {
|
||||
i.fullChar = f
|
||||
func (c *ProgressBar) SetFullChar(f rune) {
|
||||
c.fullChar = f
|
||||
}
|
||||
|
||||
// GetEmptyChar gets the rune used for 'empty'
|
||||
func (i *ProgressBar) GetEmptyChar() rune {
|
||||
return i.emptyChar
|
||||
func (c *ProgressBar) GetEmptyChar() rune {
|
||||
return c.emptyChar
|
||||
}
|
||||
|
||||
// SetEmptyChar sets the rune used for 'empty'
|
||||
func (i *ProgressBar) SetEmptyChar(f rune) {
|
||||
i.emptyChar = f
|
||||
func (c *ProgressBar) SetEmptyChar(f rune) {
|
||||
c.emptyChar = f
|
||||
}
|
||||
|
||||
// GetX Return the x position of the Progress Bar
|
||||
func (i *ProgressBar) GetX() int { return i.x }
|
||||
func (c *ProgressBar) GetX() int { return c.x }
|
||||
|
||||
// SetX set the x position of the ProgressBar to x
|
||||
func (i *ProgressBar) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *ProgressBar) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY Return the y position of the ProgressBar
|
||||
func (i *ProgressBar) GetY() int { return i.y }
|
||||
func (c *ProgressBar) GetY() int { return c.y }
|
||||
|
||||
// SetY Set the y position of the ProgressBar to y
|
||||
func (i *ProgressBar) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *ProgressBar) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetHeight returns the height of the progress bar
|
||||
// Defaults to 1 (3 if bordered)
|
||||
func (i *ProgressBar) GetHeight() int {
|
||||
return i.height
|
||||
func (c *ProgressBar) GetHeight() int {
|
||||
return c.height
|
||||
}
|
||||
|
||||
// SetHeight Sets the height of the progress bar
|
||||
func (i *ProgressBar) SetHeight(h int) {
|
||||
i.height = h
|
||||
func (c *ProgressBar) SetHeight(h int) {
|
||||
c.height = h
|
||||
}
|
||||
|
||||
// GetWidth returns the width of the progress bar
|
||||
func (i *ProgressBar) GetWidth() int {
|
||||
return i.width
|
||||
func (c *ProgressBar) GetWidth() int {
|
||||
return c.width
|
||||
}
|
||||
|
||||
// SetWidth Sets the width of the progress bar
|
||||
func (i *ProgressBar) SetWidth(w int) {
|
||||
i.width = w
|
||||
func (c *ProgressBar) SetWidth(w int) {
|
||||
c.width = w
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *ProgressBar) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *ProgressBar) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *ProgressBar) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *ProgressBar) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *ProgressBar) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *ProgressBar) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *ProgressBar) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *ProgressBar) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// Align Tells which direction the progress bar empties
|
||||
func (i *ProgressBar) Align(a TextAlignment) {
|
||||
i.alignment = a
|
||||
func (c *ProgressBar) Align(a TextAlignment) {
|
||||
c.alignment = a
|
||||
}
|
||||
|
||||
// SetColorized sets whether the progress bar should be colored
|
||||
@ -173,48 +181,48 @@ func (i *ProgressBar) Align(a TextAlignment) {
|
||||
// 10% - Red
|
||||
// 50% - Yellow
|
||||
// 80% - Green
|
||||
func (i *ProgressBar) SetColorized(c bool) {
|
||||
i.colorized = c
|
||||
func (c *ProgressBar) SetColorized(color bool) {
|
||||
c.colorized = color
|
||||
}
|
||||
|
||||
// HandleEvent accepts the termbox event and returns whether it was consumed
|
||||
func (i *ProgressBar) HandleEvent(event termbox.Event) bool {
|
||||
func (c *ProgressBar) HandleEvent(event termbox.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Draw outputs the input field on the screen
|
||||
func (i *ProgressBar) Draw() {
|
||||
func (c *ProgressBar) Draw() {
|
||||
// For now, just draw a [#### ] bar
|
||||
// TODO: make this more advanced
|
||||
useFg := i.fg
|
||||
if i.colorized {
|
||||
if i.GetPercent() < 10 {
|
||||
useFg := c.fg
|
||||
if c.colorized {
|
||||
if c.GetPercent() < 10 {
|
||||
useFg = termbox.ColorRed
|
||||
} else if i.GetPercent() < 50 {
|
||||
} else if c.GetPercent() < 50 {
|
||||
useFg = termbox.ColorYellow
|
||||
} else {
|
||||
useFg = termbox.ColorGreen
|
||||
}
|
||||
}
|
||||
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), useFg, i.bg)
|
||||
DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg)
|
||||
drawX, drawY := c.x, c.y
|
||||
fillWidth, fillHeight := c.width-2, c.height
|
||||
DrawStringAtPoint("[", drawX, drawY, c.fg, c.bg)
|
||||
numFull := int(float64(fillWidth) * float64(c.progress) / float64(c.total))
|
||||
FillWithChar(c.fullChar, drawX+1, drawY, drawX+1+numFull, drawY+(fillHeight-1), useFg, c.bg)
|
||||
DrawStringAtPoint("]", drawX+c.width-1, drawY, c.fg, c.bg)
|
||||
|
||||
/*
|
||||
drawX, drawY := i.x, i.y
|
||||
drawWidth, drawHeight := i.width, i.height
|
||||
if i.bordered {
|
||||
if i.height == 1 && i.width > 2 {
|
||||
drawX, drawY := c.x, c.y
|
||||
drawWidth, drawHeight := c.width, c.height
|
||||
if c.bordered {
|
||||
if c.height == 1 && c.width > 2 {
|
||||
// Just using [ & ] for the border
|
||||
DrawStringAtPoint("[", drawX, drawY, i.fg, i.bg)
|
||||
DrawStringAtPoint("]", drawX+i.width-1, drawY, i.fg, i.bg)
|
||||
DrawStringAtPoint("[", drawX, drawY, c.fg, c.bg)
|
||||
DrawStringAtPoint("]", drawX+c.width-1, drawY, c.fg, c.bg)
|
||||
drawX++
|
||||
drawWidth -= 2
|
||||
} else if i.height >= 3 {
|
||||
DrawBorder(drawX, drawY, drawX+i.width, drawY+i.height, i.fg, i.bg)
|
||||
} else if c.height >= 3 {
|
||||
DrawBorder(drawX, drawY, drawX+c.width, drawY+c.height, c.fg, c.bg)
|
||||
drawX++
|
||||
drawY++
|
||||
drawWidth -= 2
|
||||
@ -223,14 +231,14 @@ func (i *ProgressBar) Draw() {
|
||||
}
|
||||
|
||||
// Figure out how many chars are full
|
||||
numFull := drawWidth * (i.progress / i.total)
|
||||
switch i.alignment {
|
||||
numFull := drawWidth * (c.progress / c.total)
|
||||
switch c.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)
|
||||
FillWithChar(c.fullChar, drawX, drawY, drawX+numFull, drawY+(drawHeight-1), c.fg, c.bg)
|
||||
if numFull < drawWidth {
|
||||
FillWithChar(i.emptyChar, drawX+numFull, drawY, drawX+drawWidth-1, drawY+(drawHeight-1), i.fg, i.bg)
|
||||
FillWithChar(c.emptyChar, drawX+numFull, drawY, drawX+drawWidth-1, drawY+(drawHeight-1), c.fg, c.bg)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -10,126 +10,131 @@ type ScrollFrame struct {
|
||||
scrollX, scrollY int
|
||||
tabIdx int
|
||||
fg, bg termbox.Attribute
|
||||
activeFg, activeBg termbox.Attribute
|
||||
bordered bool
|
||||
controls []termboxControl
|
||||
active bool
|
||||
}
|
||||
|
||||
// CreateScrollFrame creates Scrolling Frame at x, y that is w by h
|
||||
func CreateScrollFrame(x, y, w, h int, fg, bg termbox.Attribute) *ScrollFrame {
|
||||
s := ScrollFrame{x: x, y: y, width: w, height: h, fg: fg, bg: bg}
|
||||
return &s
|
||||
c := ScrollFrame{
|
||||
x: x, y: y, width: w, height: h,
|
||||
fg: fg, bg: bg, activeFg: fg, activeBg: bg,
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
// GetID returns this control's ID
|
||||
func (i *ScrollFrame) GetID() string { return i.id }
|
||||
func (c *ScrollFrame) GetID() string { return c.id }
|
||||
|
||||
// SetID sets this control's ID
|
||||
func (i *ScrollFrame) SetID(newID string) {
|
||||
i.id = newID
|
||||
func (c *ScrollFrame) SetID(newID string) {
|
||||
c.id = newID
|
||||
}
|
||||
|
||||
// GetX returns the x position of the scroll frame
|
||||
func (i *ScrollFrame) GetX() int { return i.x }
|
||||
func (c *ScrollFrame) GetX() int { return c.x }
|
||||
|
||||
// SetX sets the x position of the scroll frame
|
||||
func (i *ScrollFrame) SetX(x int) {
|
||||
i.x = x
|
||||
func (c *ScrollFrame) SetX(x int) {
|
||||
c.x = x
|
||||
}
|
||||
|
||||
// GetY returns the y position of the scroll frame
|
||||
func (i *ScrollFrame) GetY() int { return i.y }
|
||||
func (c *ScrollFrame) GetY() int { return c.y }
|
||||
|
||||
// SetY sets the y position of the scroll frame
|
||||
func (i *ScrollFrame) SetY(y int) {
|
||||
i.y = y
|
||||
func (c *ScrollFrame) SetY(y int) {
|
||||
c.y = y
|
||||
}
|
||||
|
||||
// GetWidth returns the current width of the scroll frame
|
||||
func (i *ScrollFrame) GetWidth() int { return i.width }
|
||||
func (c *ScrollFrame) GetWidth() int { return c.width }
|
||||
|
||||
// SetWidth sets the current width of the scroll frame
|
||||
func (i *ScrollFrame) SetWidth(w int) {
|
||||
i.width = w
|
||||
func (c *ScrollFrame) SetWidth(w int) {
|
||||
c.width = w
|
||||
}
|
||||
|
||||
// GetHeight returns the current height of the scroll frame
|
||||
func (i *ScrollFrame) GetHeight() int { return i.height }
|
||||
func (c *ScrollFrame) GetHeight() int { return c.height }
|
||||
|
||||
// SetHeight sets the current height of the scroll frame
|
||||
func (i *ScrollFrame) SetHeight(h int) {
|
||||
i.height = h
|
||||
func (c *ScrollFrame) SetHeight(h int) {
|
||||
c.height = h
|
||||
}
|
||||
|
||||
// GetFgColor returns the foreground color
|
||||
func (i *ScrollFrame) GetFgColor() termbox.Attribute { return i.fg }
|
||||
func (c *ScrollFrame) GetFgColor() termbox.Attribute { return c.fg }
|
||||
|
||||
// SetFgColor sets the foreground color
|
||||
func (i *ScrollFrame) SetFgColor(fg termbox.Attribute) {
|
||||
i.fg = fg
|
||||
func (c *ScrollFrame) SetFgColor(fg termbox.Attribute) {
|
||||
c.fg = fg
|
||||
}
|
||||
|
||||
// GetBgColor returns the background color
|
||||
func (i *ScrollFrame) GetBgColor() termbox.Attribute { return i.bg }
|
||||
func (c *ScrollFrame) GetBgColor() termbox.Attribute { return c.bg }
|
||||
|
||||
// SetBgColor sets the current background color
|
||||
func (i *ScrollFrame) SetBgColor(bg termbox.Attribute) {
|
||||
i.bg = bg
|
||||
func (c *ScrollFrame) SetBgColor(bg termbox.Attribute) {
|
||||
c.bg = bg
|
||||
}
|
||||
|
||||
// IsBordered returns true or false if this scroll frame has a border
|
||||
func (i *ScrollFrame) IsBordered() bool { return i.bordered }
|
||||
func (c *ScrollFrame) IsBordered() bool { return c.bordered }
|
||||
|
||||
// SetBordered sets whether we render a border around the scroll frame
|
||||
func (i *ScrollFrame) SetBordered(b bool) {
|
||||
i.bordered = b
|
||||
func (c *ScrollFrame) SetBordered(b bool) {
|
||||
c.bordered = b
|
||||
}
|
||||
|
||||
// GetScrollX returns the x distance scrolled
|
||||
func (i *ScrollFrame) GetScrollX() int {
|
||||
return i.scrollX
|
||||
func (c *ScrollFrame) GetScrollX() int {
|
||||
return c.scrollX
|
||||
}
|
||||
|
||||
// GetScrollY returns the y distance scrolled
|
||||
func (i *ScrollFrame) GetScrollY() int {
|
||||
return i.scrollY
|
||||
func (c *ScrollFrame) GetScrollY() int {
|
||||
return c.scrollY
|
||||
}
|
||||
|
||||
// ScrollDown scrolls the frame down
|
||||
func (i *ScrollFrame) ScrollDown() {
|
||||
i.scrollY++
|
||||
func (c *ScrollFrame) ScrollDown() {
|
||||
c.scrollY++
|
||||
}
|
||||
|
||||
// ScrollUp scrolls the frame up
|
||||
func (i *ScrollFrame) ScrollUp() {
|
||||
if i.scrollY > 0 {
|
||||
i.scrollY--
|
||||
func (c *ScrollFrame) ScrollUp() {
|
||||
if c.scrollY > 0 {
|
||||
c.scrollY--
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollLeft scrolls the frame left
|
||||
func (i *ScrollFrame) ScrollLeft() {
|
||||
if i.scrollX > 0 {
|
||||
i.scrollX--
|
||||
func (c *ScrollFrame) ScrollLeft() {
|
||||
if c.scrollX > 0 {
|
||||
c.scrollX--
|
||||
}
|
||||
}
|
||||
|
||||
// ScrollRight scrolls the frame right
|
||||
func (i *ScrollFrame) ScrollRight() {
|
||||
i.scrollX++
|
||||
func (c *ScrollFrame) ScrollRight() {
|
||||
c.scrollX++
|
||||
}
|
||||
|
||||
// AddControl adds a control to the frame
|
||||
func (i *ScrollFrame) AddControl(t termboxControl) {
|
||||
i.controls = append(i.controls, t)
|
||||
func (c *ScrollFrame) AddControl(t termboxControl) {
|
||||
c.controls = append(c.controls, t)
|
||||
}
|
||||
|
||||
// DrawControl figures out the relative position of the control,
|
||||
// sets it, draws it, then resets it.
|
||||
func (i *ScrollFrame) DrawControl(t termboxControl) {
|
||||
if i.IsVisible(t) {
|
||||
func (c *ScrollFrame) DrawControl(t termboxControl) {
|
||||
if c.IsVisible(t) {
|
||||
ctlX, ctlY := t.GetX(), t.GetY()
|
||||
t.SetX((i.GetX() + ctlX))
|
||||
t.SetY((i.GetY() + ctlY))
|
||||
t.SetX((c.GetX() + ctlX))
|
||||
t.SetY((c.GetY() + ctlY))
|
||||
t.Draw()
|
||||
t.SetX(ctlX)
|
||||
t.SetY(ctlY)
|
||||
@ -138,35 +143,35 @@ func (i *ScrollFrame) DrawControl(t termboxControl) {
|
||||
|
||||
// IsVisible takes a Termbox Control and returns whether
|
||||
// that control would be visible in the frame
|
||||
func (i *ScrollFrame) IsVisible(t termboxControl) bool {
|
||||
func (c *ScrollFrame) IsVisible(t termboxControl) bool {
|
||||
// Check if any part of t should be visible
|
||||
cX, cY := t.GetX(), t.GetY()
|
||||
if cX+t.GetWidth() >= i.scrollX && cX <= i.scrollX+i.width {
|
||||
return cY+t.GetHeight() >= i.scrollY && cY <= i.scrollY+i.height
|
||||
if cX+t.GetWidth() >= c.scrollX && cX <= c.scrollX+c.width {
|
||||
return cY+t.GetHeight() >= c.scrollY && cY <= c.scrollY+c.height
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HandleEvent accepts the termbox event and returns whether it was consumed
|
||||
func (i *ScrollFrame) HandleEvent(event termbox.Event) bool {
|
||||
func (c *ScrollFrame) HandleEvent(event termbox.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// DrawToStrings generates a slice of strings with what should
|
||||
// be drawn to the screen
|
||||
func (i *ScrollFrame) DrawToStrings() []string {
|
||||
func (c *ScrollFrame) DrawToStrings() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Draw outputs the Scoll Frame on the screen
|
||||
func (i *ScrollFrame) Draw() {
|
||||
maxWidth := i.width
|
||||
maxHeight := i.height
|
||||
x, y := i.x, i.y
|
||||
startX := i.x
|
||||
startY := i.y
|
||||
if i.bordered {
|
||||
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
|
||||
func (c *ScrollFrame) Draw() {
|
||||
maxWidth := c.width
|
||||
maxHeight := c.height
|
||||
x, y := c.x, c.y
|
||||
startX := c.x
|
||||
startY := c.y
|
||||
if c.bordered {
|
||||
DrawBorder(c.x, c.y, c.x+c.width, c.y+c.height, c.fg, c.bg)
|
||||
maxWidth--
|
||||
maxHeight--
|
||||
x++
|
||||
@ -174,7 +179,7 @@ func (i *ScrollFrame) Draw() {
|
||||
startX++
|
||||
startY++
|
||||
}
|
||||
for idx := range i.controls {
|
||||
i.DrawControl(i.controls[idx])
|
||||
for idx := range c.controls {
|
||||
c.DrawControl(c.controls[idx])
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package termboxUtil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -27,6 +28,10 @@ type termboxControl interface {
|
||||
SetTabSkip(bool)
|
||||
IsTabSkipped() bool
|
||||
Draw()
|
||||
SetActive(bool)
|
||||
IsActive() bool
|
||||
SetActiveFgColor(termbox.Attribute)
|
||||
SetActiveBgColor(termbox.Attribute)
|
||||
}
|
||||
|
||||
// TextAlignment is an int value for how we're aligning text
|
||||
@ -106,17 +111,67 @@ 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
|
||||
func DrawBorder(x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute) {
|
||||
termbox.SetCell(x1, y1, '+', fg, bg)
|
||||
FillWithChar('-', x1+1, y1, x2-1, y1, fg, bg)
|
||||
termbox.SetCell(x2, y1, '+', fg, bg)
|
||||
func DrawBorder(x1, y1, x2, y2 int, fg, bg termbox.Attribute) {
|
||||
termbox.SetCell(x1, y1, '╔', fg, bg)
|
||||
FillWithChar('═', x1+1, y1, x2-1, y1, fg, bg)
|
||||
termbox.SetCell(x2, y1, '╗', fg, bg)
|
||||
|
||||
FillWithChar('|', x1, y1+1, x1, y2-1, fg, bg)
|
||||
FillWithChar('|', x2, y1+1, x2, y2-1, fg, bg)
|
||||
FillWithChar('║', x1, y1+1, x1, y2-1, fg, bg)
|
||||
FillWithChar('║', x2, y1+1, x2, y2-1, fg, bg)
|
||||
|
||||
termbox.SetCell(x1, y2, '+', fg, bg)
|
||||
FillWithChar('-', x1+1, y2, x2-1, y2, fg, bg)
|
||||
termbox.SetCell(x2, y2, '+', fg, bg)
|
||||
termbox.SetCell(x1, y2, '╚', fg, bg)
|
||||
FillWithChar('═', x1+1, y2, x2-1, y2, fg, bg)
|
||||
termbox.SetCell(x2, y2, '╝', fg, bg)
|
||||
}
|
||||
|
||||
func DrawBorderWithPct(x1, y1, x2, y2 int, pct float64, fg, bg termbox.Attribute) {
|
||||
termbox.SetCell(x1, y1, '╔', fg, bg)
|
||||
|
||||
FillWithChar('═', x1+1, y1, x2-1, y1, fg, bg)
|
||||
termbox.SetCell(x2, y1, '╗', fg, bg)
|
||||
|
||||
FillWithChar('║', x1, y1+1, x1, y2-1, fg, bg)
|
||||
FillWithChar('║', x2, y1+1, x2, y2-1, fg, bg)
|
||||
// Now the percent indicator
|
||||
pctY := int(((float64(y2)-float64(y1)-2)*pct)+float64(y1)) + 1
|
||||
termbox.SetCell(x2, pctY, '▒', fg, bg)
|
||||
|
||||
termbox.SetCell(x1, y2, '╚', fg, bg)
|
||||
FillWithChar('═', x1+1, y2, x2-1, y2, fg, bg)
|
||||
termbox.SetCell(x2, y2, '╝', fg, bg)
|
||||
}
|
||||
|
||||
func DrawBorderWithTitle(x1, y1, x2, y2 int, title string, fg, bg termbox.Attribute) {
|
||||
termbox.SetCell(x1, y1, '╔', fg, bg)
|
||||
|
||||
DrawStringAtPoint(title, x1+1, y1, fg, bg)
|
||||
FillWithChar('═', x1+len(title)+1, y1, x2-1, y1, fg, bg)
|
||||
termbox.SetCell(x2, y1, '╗', fg, bg)
|
||||
|
||||
FillWithChar('║', x1, y1+1, x1, y2-1, fg, bg)
|
||||
FillWithChar('║', x2, y1+1, x2, y2-1, fg, bg)
|
||||
|
||||
termbox.SetCell(x1, y2, '╚', fg, bg)
|
||||
FillWithChar('═', x1+1, y2, x2-1, y2, fg, bg)
|
||||
termbox.SetCell(x2, y2, '╝', fg, bg)
|
||||
}
|
||||
|
||||
func DrawBorderWithTitleAndPct(x1, y1, x2, y2 int, title string, pct float64, fg, bg termbox.Attribute) {
|
||||
termbox.SetCell(x1, y1, '╔', fg, bg)
|
||||
|
||||
DrawStringAtPoint(title, x1+1, y1, fg, bg)
|
||||
FillWithChar('═', x1+len(title)+1, y1, x2-1, y1, fg, bg)
|
||||
termbox.SetCell(x2, y1, '╗', fg, bg)
|
||||
|
||||
FillWithChar('║', x1, y1+1, x1, y2-1, fg, bg)
|
||||
FillWithChar('║', x2, y1+1, x2, y2-1, fg, bg)
|
||||
// Now the percent indicator
|
||||
pctY := int(((float64(y2)-float64(y1)-2)*pct)+float64(y1)) + 1
|
||||
termbox.SetCell(x2, pctY, '▒', fg, bg)
|
||||
|
||||
termbox.SetCell(x1, y2, '╚', fg, bg)
|
||||
FillWithChar('═', x1+1, y2, x2-1, y2, fg, bg)
|
||||
termbox.SetCell(x2, y2, '╝', fg, bg)
|
||||
}
|
||||
|
||||
// AlignText Aligns the text txt within width characters using the specified alignment
|
||||
@ -148,4 +203,19 @@ func AlignTextWithFill(txt string, width int, align TextAlignment, fill rune) st
|
||||
}
|
||||
}
|
||||
|
||||
func ToLabel(c termboxControl) (*Label, error) {
|
||||
v, ok := c.(*Label)
|
||||
if ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, errors.New("Control isn't a Label")
|
||||
}
|
||||
func ToInputField(c termboxControl) (*InputField, error) {
|
||||
v, ok := c.(*InputField)
|
||||
if ok {
|
||||
return v, nil
|
||||
}
|
||||
return nil, errors.New("Control isn't an Input Field")
|
||||
}
|
||||
|
||||
/* More advanced things are in their respective files */
|
||||
|
Loading…
Reference in New Issue
Block a user