Browse Source

Just some stuff

master
Brian Buller 3 years ago
parent
commit
c168c0df31
  1. 4
      termbox-test/main.go
  2. 8
      termbox_alertmodal.go
  3. 20
      termbox_asciiart.go
  4. 59
      termbox_button.go
  5. 5
      termbox_confirmmodal.go
  6. 165
      termbox_dropmenu.go
  7. 218
      termbox_frame.go
  8. 210
      termbox_inputfield.go
  9. 209
      termbox_inputmodal.go
  10. 116
      termbox_label.go
  11. 425
      termbox_menu.go
  12. 178
      termbox_progressbar.go
  13. 127
      termbox_scrollframe.go
  14. 88
      termbox_util.go

4
termbox-test/main.go

@ -5,7 +5,7 @@ import (
"strconv"
"syscall"
"gogs.bullercodeworks.com/brian/termbox-util"
"github.com/br0xen/termbox-util"
"github.com/nsf/termbox-go"
)
@ -115,4 +115,4 @@ func handleEvent(event termbox.Event) bool {
}
frame.GetActiveControl().SetFgColor(termbox.ColorGreen)
return true
}
}

8
termbox_alertmodal.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 }

20
termbox_asciiart.go

@ -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

@ -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)
}

5
termbox_confirmmodal.go

@ -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?"
}

165
termbox_dropmenu.go

@ -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

@ -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])
}
}

210
termbox_inputfield.go

@ -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)
}
}

209
termbox_inputmodal.go

@ -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)
}
</