1
0
mirror of https://github.com/br0xen/termbox-util.git synced 2024-11-22 13:33:15 +00:00

Syncing Repos

This commit is contained in:
Brian Buller 2016-02-09 10:21:57 -06:00
parent c19e371390
commit 062c970c0d
14 changed files with 1231 additions and 302 deletions

1
termbox-test/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
termbox-test

View File

@ -1,17 +1,21 @@
package main package main
import ( import (
"fmt"
"github.com/nsf/termbox-go"
"gogs.bullercodeworks.com/brian/termbox-util"
"os" "os"
"strconv"
"syscall" "syscall"
"gogs.bullercodeworks.com/brian/termbox-util"
"github.com/nsf/termbox-go"
) )
var keep_running bool var keepRunning bool
var initialized bool
var frame *termboxUtil.Frame
func main() { func main() {
keep_running = true keepRunning = true
err := termbox.Init() err := termbox.Init()
if err != nil { if err != nil {
panic(err) panic(err)
@ -21,82 +25,7 @@ func main() {
mainLoop() mainLoop()
} }
//var input *termbox_util.InputField
var input *termbox_util.InputModal
var new_key, new_val string
var mode string
var drawY int
var added_stuff []string
func layoutAndDrawScreen() {
termbox.Clear(0, termbox.ColorBlack)
drawScreen()
termbox.Flush()
}
func drawScreen() {
w, h := termbox.Size()
termbox_util.DrawStringAtPoint(termbox_util.AlignText("Termbox Utility Test", w, termbox_util.ALIGN_CENTER), 0, 0, termbox.ColorWhite, termbox.ColorRed)
if input == nil {
mw, mh := w/4, h/4
mx, my := (w/2)-(mw/2), (h/2)-(mh/2)
input = termbox_util.CreateInputModal("", mx, my, mw, mh, termbox.ColorWhite, termbox.ColorBlack)
input.Clear()
}
if mode == "bucket" {
if input.IsDone() {
added_stuff = append(added_stuff, fmt.Sprintf("New Bucket %s", input.GetValue()))
input.Clear()
mode = ""
} else {
input.Draw()
}
} else if mode == "pair" {
if input.IsDone() {
if new_key == "" {
new_key = input.GetValue()
input.Clear()
input.SetTitle("Pair Value")
} else {
added_stuff = append(added_stuff, fmt.Sprintf("New Pair %s => %s", new_key, input.GetValue()))
mode = ""
input.Clear()
}
}
if mode == "pair" && !input.IsDone() {
input.Draw()
}
}
if mode == "" {
for i := range added_stuff {
termbox_util.DrawStringAtPoint(added_stuff[i], 1, 3+i, termbox.ColorWhite, termbox.ColorRed)
}
}
}
func handleKeyEvent(event termbox.Event) bool {
if event.Key == termbox.KeyEsc {
return false
} else if event.Key == termbox.KeyCtrlB {
mode = "bucket"
new_key = ""
new_val = ""
input.Clear()
input.SetTitle("Bucket Name")
} else if event.Key == termbox.KeyCtrlP {
mode = "pair"
new_key = ""
new_val = ""
input.Clear()
input.SetTitle("Pair Key")
} else {
input.HandleKeyPress(event)
}
return true
}
func mainLoop() { func mainLoop() {
added_stuff = append(added_stuff, "Ctrl+B = Add Bucket; Ctrl+P = Add Pair")
layoutAndDrawScreen() layoutAndDrawScreen()
for { for {
event := termbox.PollEvent() event := termbox.PollEvent()
@ -106,9 +35,12 @@ func mainLoop() {
termbox.Close() termbox.Close()
process.Signal(syscall.SIGSTOP) process.Signal(syscall.SIGSTOP)
termbox.Init() termbox.Init()
} else if event.Key == termbox.KeyCtrlC {
termbox.Close()
os.Exit(0)
} }
keep_running = handleKeyEvent(event) keepRunning = handleEvent(event)
if !keep_running { if !keepRunning {
break break
} }
layoutAndDrawScreen() layoutAndDrawScreen()
@ -118,3 +50,69 @@ func mainLoop() {
} }
} }
} }
func layoutAndDrawScreen() {
w, h := termbox.Size()
if !initialized {
fg, bg := termbox.ColorWhite, termbox.ColorBlack
frame = termboxUtil.CreateFrame(1, 1, w-3, h-3, termbox.ColorWhite, termbox.ColorBlack)
/*
frame.AddControl(termboxUtil.CreateASCIIArt([]string{
"/" + strings.Repeat("=====", 5) + "\\",
"|" + strings.Repeat(".oOo.", 5) + "|",
"\\" + strings.Repeat("=====", 5) + "/",
}, 1, frame.GetBottomY()+1, fg, bg))
frame.AddControl(termboxUtil.CreateAlertModal("AlertModal", 1, 1, w-5, 6, termbox.ColorGreen, bg))
frame.AddControl(termboxUtil.CreateConfirmModal("ConfirmModal", 1, frame.GetBottomY()+1, w-5, 7, fg, bg))
frame.AddControl(termboxUtil.CreateInputModal("InputModal", 1, frame.GetBottomY()+1, w-5, 7, fg, bg))
*/
frame.AddControl(termboxUtil.CreateDropMenu("Add Control", []string{
"AlertModal",
"ASCIIArt",
"ConfirmModal",
"DropMenu",
"Frame",
"InputField",
"InputModal",
"Label",
"Menu",
"ProgressBar",
"ScrollFrame",
},
1, frame.GetBottomY()+1, w-5, 7, fg, bg, termbox.ColorBlack, termbox.ColorGreen))
frame.GetLastControl().SetBordered(true)
frame.SetActiveFlag(true)
initialized = true
}
termbox.Clear(0, termbox.ColorBlack)
drawScreen()
termboxUtil.DrawStringAtPoint(strconv.Itoa(frame.GetBottomY()), 0, h-1, termbox.ColorWhite, termbox.ColorBlack)
termbox.Flush()
}
func drawScreen() {
frame.Draw()
}
func handleEvent(event termbox.Event) bool {
frame.HandleEvent(event)
for _, k := range frame.GetControls() {
switch v := k.(type) {
case *termboxUtil.DropMenu:
if v.IsDone() {
}
case *termboxUtil.AlertModal:
if v.IsDone() {
v.SetText("Finished")
}
case *termboxUtil.ConfirmModal:
if v.IsDone() {
v.SetText("Finished")
}
}
k.SetFgColor(termbox.ColorWhite)
}
frame.GetActiveControl().SetFgColor(termbox.ColorGreen)
return true
}

View File

@ -6,6 +6,7 @@ import (
// AlertModal is a modal with yes/no (or similar) buttons // AlertModal is a modal with yes/no (or similar) buttons
type AlertModal struct { type AlertModal struct {
id string
title string title string
text string text string
x, y, width, height int x, y, width, height int
@ -16,18 +17,29 @@ type AlertModal struct {
accepted bool accepted bool
value string value string
isVisible bool isVisible bool
bordered bool
tabSkip bool
active bool
} }
// CreateAlertModal Creates a confirmation modal with the specified attributes // CreateAlertModal Creates a confirmation modal with the specified attributes
func CreateAlertModal(title string, x, y, width, height int, fg, bg termbox.Attribute) *AlertModal { 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} i := AlertModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, bordered: true}
if i.title == "" && i.text == "" { if i.title == "" {
i.title = "Alert!" i.title = "Alert!"
} }
i.showHelp = true i.showHelp = true
return &i return &i
} }
// GetID returns this control's ID
func (i *AlertModal) GetID() string { return i.id }
// SetID sets this control's ID
func (i *AlertModal) SetID(newID string) {
i.id = newID
}
// GetTitle returns the current title of the modal // GetTitle returns the current title of the modal
func (i *AlertModal) GetTitle() string { return i.title } func (i *AlertModal) GetTitle() string { return i.title }
@ -44,38 +56,74 @@ func (i *AlertModal) SetText(s string) {
i.text = s i.text = s
} }
// GetX returns the current x coordinate of the modal // GetX returns the current x coordinate of the control
func (i *AlertModal) GetX() int { return i.x } func (i *AlertModal) GetX() int { return i.x }
// SetX sets the current x coordinate of the modal to x // SetX sets the current x coordinate of the control to x
func (i *AlertModal) SetX(x int) { func (i *AlertModal) SetX(x int) {
i.x = x i.x = x
} }
// GetY returns the current y coordinate of the modal // GetY returns the current y coordinate of the control
func (i *AlertModal) GetY() int { return i.y } func (i *AlertModal) GetY() int { return i.y }
// SetY sets the current y coordinate of the modal to y // SetY sets the current y coordinate of the control to y
func (i *AlertModal) SetY(y int) { func (i *AlertModal) SetY(y int) {
i.y = y i.y = y
} }
// GetWidth returns the current width of the modal // GetWidth returns the current width of the control
func (i *AlertModal) GetWidth() int { return i.width } func (i *AlertModal) GetWidth() int { return i.width }
// SetWidth sets the current modal width to width // SetWidth sets the current control width to width
func (i *AlertModal) SetWidth(width int) { func (i *AlertModal) SetWidth(width int) {
i.width = width i.width = width
} }
// GetHeight returns the current height of the modal // GetHeight returns the current height of the control
func (i *AlertModal) GetHeight() int { return i.height } func (i *AlertModal) GetHeight() int { return i.height }
// SetHeight set the height of the modal to height // SetHeight set the height of the control to height
func (i *AlertModal) SetHeight(height int) { func (i *AlertModal) SetHeight(height int) {
i.height = height i.height = height
} }
// GetFgColor returns the foreground color
func (i *AlertModal) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *AlertModal) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *AlertModal) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *AlertModal) SetBgColor(bg termbox.Attribute) {
i.bg = bg
}
// IsBordered returns whether this control is bordered or not
func (i *AlertModal) IsBordered() bool {
return i.bordered
}
// SetBordered sets whether we render a border around the frame
func (i *AlertModal) SetBordered(b bool) {
i.bordered = b
}
// IsTabSkipped returns whether this control has it's tabskip flag set
func (i *AlertModal) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *AlertModal) SetTabSkip(b bool) {
i.tabSkip = b
}
// HelpIsShown returns true or false if the help is displayed // HelpIsShown returns true or false if the help is displayed
func (i *AlertModal) HelpIsShown() bool { return i.showHelp } func (i *AlertModal) HelpIsShown() bool { return i.showHelp }
@ -129,11 +177,21 @@ func (i *AlertModal) Clear() {
i.isDone = false i.isDone = false
} }
// HandleKeyPress handles the termbox event and returns whether it was consumed // SetActiveFlag sets this control's active flag
func (i *AlertModal) HandleKeyPress(event termbox.Event) bool { func (i *AlertModal) SetActiveFlag(b bool) {
if event.Key == termbox.KeyEnter { i.active = b
i.isDone = true }
return true
// IsActive returns whether this control is active
func (i *AlertModal) IsActive() bool { return i.active }
// HandleEvent handles the termbox event and returns whether it was consumed
func (i *AlertModal) HandleEvent(event termbox.Event) bool {
if !i.active {
if event.Key == termbox.KeyEnter {
i.isDone = true
return true
}
} }
return false return false
} }
@ -155,7 +213,6 @@ func (i *AlertModal) Draw() {
} }
if i.text != "" { if i.text != "" {
DrawStringAtPoint(i.text, i.x+1, nextY, i.fg, i.bg) DrawStringAtPoint(i.text, i.x+1, nextY, i.fg, i.bg)
nextY++
} }
nextY += 2 nextY += 2
if i.showHelp { if i.showHelp {

View File

@ -8,17 +8,37 @@ import (
// ASCIIArt is a []string with more functions // ASCIIArt is a []string with more functions
type ASCIIArt struct { type ASCIIArt struct {
id string
contents []string contents []string
x, y int x, y int
bg, fg termbox.Attribute bg, fg termbox.Attribute
bordered bool
tabSkip bool
active bool
} }
// CreateASCIIArt Create an ASCII art object from a string slice // CreateASCIIArt Create an ASCII art object from a string slice
func CreateASCIIArt(c []string, x, y int, fg, bg termbox.Attribute) *ASCIIArt { func CreateASCIIArt(c []string, x, y int, fg, bg termbox.Attribute) *ASCIIArt {
i := ASCIIArt{contents: c, x: x, y: y, fg: fg, bg: bg} i := ASCIIArt{contents: c, x: x, y: y, fg: fg, bg: bg, bordered: false, tabSkip: true}
return &i return &i
} }
// SetActiveFlag sets this control's active flag
func (i *ASCIIArt) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *ASCIIArt) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *ASCIIArt) GetID() string { return i.id }
// SetID sets this control's ID
func (i *ASCIIArt) SetID(newID string) {
i.id = newID
}
// GetX Return the x position of the modal // GetX Return the x position of the modal
func (i *ASCIIArt) GetX() int { return i.x } func (i *ASCIIArt) GetX() int { return i.x }
@ -93,20 +113,20 @@ func (i *ASCIIArt) SetContentLine(s string, idx int) {
} }
} }
// GetBackground Return the current background color of the modal // GetFgColor returns the foreground color
func (i *ASCIIArt) GetBackground() termbox.Attribute { return i.bg } func (i *ASCIIArt) GetFgColor() termbox.Attribute { return i.fg }
// SetBackground Set the current background color to bg // SetFgColor sets the foreground color
func (i *ASCIIArt) SetBackground(bg termbox.Attribute) { func (i *ASCIIArt) SetFgColor(fg termbox.Attribute) {
i.bg = bg i.fg = fg
} }
// GetForeground Return the current foreground color // GetBgColor returns the background color
func (i *ASCIIArt) GetForeground() termbox.Attribute { return i.fg } func (i *ASCIIArt) GetBgColor() termbox.Attribute { return i.bg }
// SetForeground Set the foreground color to fg // SetBgColor sets the current background color
func (i *ASCIIArt) SetForeground(fg termbox.Attribute) { func (i *ASCIIArt) SetBgColor(bg termbox.Attribute) {
i.fg = fg i.bg = bg
} }
// Align Align the Ascii art over width width with alignment a // Align Align the Ascii art over width width with alignment a
@ -125,8 +145,28 @@ func (i *ASCIIArt) Align(a TextAlignment, width int) {
i.contents = newContents i.contents = newContents
} }
// HandleKeyPress accepts the termbox event and returns whether it was consumed // IsBordered returns whether this modal is bordered or not
func (i *ASCIIArt) HandleKeyPress(event termbox.Event) bool { func (i *ASCIIArt) IsBordered() bool {
return i.bordered
}
// SetBordered sets whether we render a border around the frame
func (i *ASCIIArt) SetBordered(b bool) {
i.bordered = b
}
// IsTabSkipped returns whether this modal has it's tabskip flag set
func (i *ASCIIArt) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *ASCIIArt) SetTabSkip(b bool) {
i.tabSkip = b
}
// HandleEvent accepts the termbox event and returns whether it was consumed
func (i *ASCIIArt) HandleEvent(event termbox.Event) bool {
return false return false
} }

View File

@ -6,6 +6,7 @@ import (
// ConfirmModal is a modal with yes/no (or similar) buttons // ConfirmModal is a modal with yes/no (or similar) buttons
type ConfirmModal struct { type ConfirmModal struct {
id string
title string title string
text string text string
x, y, width, height int x, y, width, height int
@ -16,6 +17,9 @@ type ConfirmModal struct {
accepted bool accepted bool
value string value string
isVisible bool isVisible bool
bordered bool
tabSkip bool
active bool
} }
// CreateConfirmModal Creates a confirmation modal with the specified attributes // CreateConfirmModal Creates a confirmation modal with the specified attributes
@ -28,6 +32,22 @@ func CreateConfirmModal(title string, x, y, width, height int, fg, bg termbox.At
return &i return &i
} }
// SetActiveFlag sets this control's active flag
func (i *ConfirmModal) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *ConfirmModal) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *ConfirmModal) GetID() string { return i.id }
// SetID sets this control's ID
func (i *ConfirmModal) SetID(newID string) {
i.id = newID
}
// GetTitle returns the current title of the modal // GetTitle returns the current title of the modal
func (i *ConfirmModal) GetTitle() string { return i.title } func (i *ConfirmModal) GetTitle() string { return i.title }
@ -84,20 +104,20 @@ func (i *ConfirmModal) ShowHelp(b bool) {
i.showHelp = b i.showHelp = b
} }
// GetBackground returns the current background color // GetFgColor returns the foreground color
func (i *ConfirmModal) GetBackground() termbox.Attribute { return i.bg } func (i *ConfirmModal) GetFgColor() termbox.Attribute { return i.fg }
// SetBackground sets the background color to bg // SetFgColor sets the foreground color
func (i *ConfirmModal) SetBackground(bg termbox.Attribute) { func (i *ConfirmModal) SetFgColor(fg termbox.Attribute) {
i.bg = bg i.fg = fg
} }
// GetForeground returns the current foreground color // GetBgColor returns the background color
func (i *ConfirmModal) GetForeground() termbox.Attribute { return i.fg } func (i *ConfirmModal) GetBgColor() termbox.Attribute { return i.bg }
// SetForeground sets the current foreground color to fg // SetBgColor sets the current background color
func (i *ConfirmModal) SetForeground(fg termbox.Attribute) { func (i *ConfirmModal) SetBgColor(bg termbox.Attribute) {
i.fg = fg i.bg = bg
} }
// IsDone returns whether the user has answered the modal // IsDone returns whether the user has answered the modal
@ -129,16 +149,38 @@ func (i *ConfirmModal) Clear() {
i.isDone = false i.isDone = false
} }
// HandleKeyPress handles the termbox event and returns whether it was consumed // IsBordered returns whether this modal is bordered or not
func (i *ConfirmModal) HandleKeyPress(event termbox.Event) bool { func (i *ConfirmModal) IsBordered() bool {
if event.Ch == 'Y' || event.Ch == 'y' { return i.bordered
i.accepted = true }
i.isDone = true
return true // SetBordered sets whether we render a border around the frame
} else if event.Ch == 'N' || event.Ch == 'n' { func (i *ConfirmModal) SetBordered(b bool) {
i.accepted = false i.bordered = b
i.isDone = true }
return true
// IsTabSkipped returns whether this modal has it's tabskip flag set
func (i *ConfirmModal) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *ConfirmModal) SetTabSkip(b bool) {
i.tabSkip = b
}
// HandleEvent handles the termbox event and returns whether it was consumed
func (i *ConfirmModal) HandleEvent(event termbox.Event) bool {
if i.active {
if event.Ch == 'Y' || event.Ch == 'y' {
i.accepted = true
i.isDone = true
return true
} else if event.Ch == 'N' || event.Ch == 'n' {
i.accepted = false
i.isDone = true
return true
}
} }
return false return false
} }
@ -160,7 +202,6 @@ func (i *ConfirmModal) Draw() {
} }
if i.text != "" { if i.text != "" {
DrawStringAtPoint(i.text, i.x+1, nextY, i.fg, i.bg) DrawStringAtPoint(i.text, i.x+1, nextY, i.fg, i.bg)
nextY++
} }
nextY += 2 nextY += 2
if i.showHelp { if i.showHelp {

190
termbox_dropmenu.go Normal file
View File

@ -0,0 +1,190 @@
package termboxUtil
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
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{
title: title,
x: x, y: y, width: width, height: height,
fg: fg, bg: bg,
selectedFg: fg, selectedBg: bg,
}
i.menu = CreateMenu("", options, x, y+2, width, height, fg, bg)
return &i
}
// GetID returns this control's ID
func (i *DropMenu) GetID() string { return i.id }
// SetID sets this control's ID
func (i *DropMenu) SetID(newID string) {
i.id = newID
}
// GetTitle returns the current title of the menu
func (i *DropMenu) GetTitle() string { return i.title }
// SetTitle sets the current title of the menu to s
func (i *DropMenu) SetTitle(s string) {
i.title = s
}
// GetMenu returns the menu for this dropmenu
func (i *DropMenu) GetMenu() *Menu {
return i.menu
}
// GetX returns the current x coordinate of the menu
func (i *DropMenu) GetX() int { return i.x }
// SetX sets the current x coordinate of the menu to x
func (i *DropMenu) SetX(x int) {
i.x = x
}
// GetY returns the current y coordinate of the menu
func (i *DropMenu) GetY() int { return i.y }
// SetY sets the current y coordinate of the menu to y
func (i *DropMenu) SetY(y int) {
i.y = y
}
// GetWidth returns the current width of the menu
func (i *DropMenu) GetWidth() int { return i.width }
// SetWidth sets the current menu width to width
func (i *DropMenu) SetWidth(width int) {
i.width = width
}
// GetHeight returns the current height of the menu
func (i *DropMenu) GetHeight() int { return i.height }
// SetHeight set the height of the menu to height
func (i *DropMenu) SetHeight(height int) {
i.height = height
}
// GetFgColor returns the foreground color
func (i *DropMenu) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *DropMenu) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *DropMenu) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *DropMenu) SetBgColor(bg termbox.Attribute) {
i.bg = bg
}
// IsBordered returns the bordered flag
func (i *DropMenu) IsBordered() bool { return i.bordered }
// SetBordered sets the bordered flag
func (i *DropMenu) SetBordered(b bool) {
i.bordered = b
i.menu.SetBordered(b)
}
// IsDone returns whether the user has answered the modal
func (i *DropMenu) IsDone() bool { return i.menu.isDone }
// SetDone sets whether the modal has completed it's purpose
func (i *DropMenu) SetDone(b bool) {
i.menu.isDone = b
}
// IsTabSkipped returns whether this modal has it's tabskip flag set
func (i *DropMenu) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *DropMenu) SetTabSkip(b bool) {
i.tabSkip = b
}
// SetActiveFlag sets the dropmenu active flag
func (i *DropMenu) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether the DropMenu is active
func (i *DropMenu) IsActive() bool {
return i.active
}
// ShowMenu tells the menu to draw the options
func (i *DropMenu) ShowMenu() {
i.showMenu = true
i.menuSelected = true
}
// HideMenu tells the menu to hide the options
func (i *DropMenu) HideMenu() {
i.showMenu = false
i.menuSelected = false
}
// HandleEvent handles the termbox event and returns whether it was consumed
func (i *DropMenu) HandleEvent(event termbox.Event) bool {
if i.active {
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
} else {
if i.menu.HandleEvent(event) {
if i.menu.IsDone() {
i.HideMenu()
}
return true
}
}
} else {
i.ShowMenu()
return true
}
}
return false
}
// Draw draws the menu
func (i *DropMenu) Draw() {
// The title
ttlFg, ttlBg := i.fg, i.bg
if i.active && !i.menuSelected {
ttlFg, ttlBg = i.selectedFg, i.selectedBg
}
ttlTxt := i.title
if i.showMenu {
ttlTxt = ttlTxt + "-Showing Menu"
}
DrawStringAtPoint(AlignText(i.title, i.width, AlignLeft), i.x, i.y, ttlFg, ttlBg)
if i.showMenu {
i.menu.Draw()
}
}

213
termbox_frame.go Normal file
View File

@ -0,0 +1,213 @@
package termboxUtil
import "github.com/nsf/termbox-go"
// Frame is a frame for holding other elements
// It manages it's own x/y, tab index
type Frame struct {
id string
x, y, width, height int
tabIdx int
fg, bg termbox.Attribute
bordered bool
controls []termboxControl
tabSkip bool
active bool
}
// 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
}
// SetActiveFlag sets this control's active flag
func (i *Frame) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *Frame) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *Frame) GetID() string { return i.id }
// SetID sets this control's ID
func (i *Frame) SetID(newID string) {
i.id = newID
}
// GetX returns the x position of the frame
func (i *Frame) GetX() int { return i.x }
// SetX sets the x position of the frame
func (i *Frame) SetX(x int) {
i.x = x
}
// GetY returns the y position of the frame
func (i *Frame) GetY() int { return i.y }
// SetY sets the y position of the frame
func (i *Frame) SetY(y int) {
i.y = y
}
// GetWidth returns the current width of the frame
func (i *Frame) GetWidth() int { return i.width }
// SetWidth sets the current width of the frame
func (i *Frame) SetWidth(w int) {
i.width = w
}
// GetHeight returns the current height of the frame
func (i *Frame) GetHeight() int { return i.height }
// SetHeight sets the current height of the frame
func (i *Frame) SetHeight(h int) {
i.height = h
}
// GetFgColor returns the foreground color
func (i *Frame) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *Frame) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *Frame) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *Frame) SetBgColor(bg termbox.Attribute) {
i.bg = bg
}
// IsBordered returns true or false if this frame has a border
func (i *Frame) IsBordered() bool { return i.bordered }
// SetBordered sets whether we render a border around the frame
func (i *Frame) SetBordered(b bool) {
i.bordered = b
}
// IsTabSkipped returns whether this modal has it's tabskip flag set
func (i *Frame) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *Frame) SetTabSkip(b bool) {
i.tabSkip = b
}
// AddControl adds a control to the frame
func (i *Frame) AddControl(t termboxControl) {
i.controls = append(i.controls, t)
}
// GetActiveControl returns the control at tabIdx
func (i *Frame) GetActiveControl() termboxControl {
if len(i.controls) >= i.tabIdx {
return i.controls[i.tabIdx]
}
return nil
}
// GetControls returns a slice of all controls
func (i *Frame) GetControls() []termboxControl {
return i.controls
}
// GetControl returns the control at index i
func (i *Frame) GetControl(idx int) termboxControl {
if len(i.controls) >= idx {
return i.controls[idx]
}
return nil
}
// GetControlCount returns the number of controls contained
func (i *Frame) GetControlCount() int {
return len(i.controls)
}
// GetLastControl returns the last control contained
func (i *Frame) GetLastControl() termboxControl {
return i.controls[len(i.controls)-1]
}
// DrawControl figures out the relative position of the control,
// sets it, draws it, then resets it.
func (i *Frame) DrawControl(t termboxControl) {
ctlX, ctlY := t.GetX(), t.GetY()
t.SetX((i.GetX() + ctlX))
t.SetY((i.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 {
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()
}
}
return ret
}
// HandleEvent accepts the termbox event and returns whether it was consumed
func (i *Frame) HandleEvent(event termbox.Event) bool {
if i.active {
if event.Key == termbox.KeyTab {
i.FindNextTabStop()
return true
}
return i.controls[i.tabIdx].HandleEvent(event)
}
return false
}
// 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 {
break
}
}
for idx := range i.controls {
i.controls[idx].SetActiveFlag(idx == i.tabIdx)
}
return i.tabIdx != startTab
}
// 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)
maxWidth--
maxHeight--
x++
y++
startX++
startY++
}
for idx := range i.controls {
i.DrawControl(i.controls[idx])
}
}

View File

@ -4,6 +4,7 @@ import "github.com/nsf/termbox-go"
// InputField is a field for inputting text // InputField is a field for inputting text
type InputField struct { type InputField struct {
id string
value string value string
x, y, width, height int x, y, width, height int
cursor int cursor int
@ -11,14 +12,32 @@ type InputField struct {
bordered bool bordered bool
wrap bool wrap bool
multiline bool multiline bool
tabSkip bool
active bool
} }
// CreateInputField creates an input field at x, y that is w by h // 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 { 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} i := InputField{x: x, y: y, width: w, height: h, fg: fg, bg: bg, active: true}
return &i return &i
} }
// SetActiveFlag sets this control's active flag
func (i *InputField) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *InputField) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *InputField) GetID() string { return i.id }
// SetID sets this control's ID
func (i *InputField) SetID(newID string) {
i.id = newID
}
// GetValue gets the current text that is in the InputField // GetValue gets the current text that is in the InputField
func (i *InputField) GetValue() string { return i.value } func (i *InputField) GetValue() string { return i.value }
@ -59,6 +78,22 @@ func (i *InputField) SetHeight(h int) {
i.height = h i.height = h
} }
// GetFgColor returns the foreground color
func (i *InputField) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *InputField) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *InputField) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *InputField) SetBgColor(bg termbox.Attribute) {
i.bg = bg
}
// IsBordered returns true or false if this input field has a border // IsBordered returns true or false if this input field has a border
func (i *InputField) IsBordered() bool { return i.bordered } func (i *InputField) IsBordered() bool { return i.bordered }
@ -67,6 +102,16 @@ func (i *InputField) SetBordered(b bool) {
i.bordered = b i.bordered = b
} }
// IsTabSkipped returns whether this modal has it's tabskip flag set
func (i *InputField) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *InputField) SetTabSkip(b bool) {
i.tabSkip = b
}
// DoesWrap returns true or false if this input field wraps text // DoesWrap returns true or false if this input field wraps text
func (i *InputField) DoesWrap() bool { return i.wrap } func (i *InputField) DoesWrap() bool { return i.wrap }
@ -83,55 +128,58 @@ func (i *InputField) SetMultiline(b bool) {
i.multiline = b i.multiline = b
} }
// HandleKeyPress accepts the termbox event and returns whether it was consumed // HandleEvent accepts the termbox event and returns whether it was consumed
func (i *InputField) HandleKeyPress(event termbox.Event) bool { func (i *InputField) HandleEvent(event termbox.Event) bool {
if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 { if i.active {
if len(i.value) > 0 { if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 {
i.value = i.value[:len(i.value)-1] if len(i.value) > 0 {
} i.value = i.value[:len(i.value)-1]
} else if event.Key == termbox.KeyArrowLeft { }
if i.cursor+len(i.value) > 0 { } else if event.Key == termbox.KeyArrowLeft {
i.cursor-- if i.cursor+len(i.value) > 0 {
} i.cursor--
} else if event.Key == termbox.KeyArrowRight { }
if i.cursor < 0 { } else if event.Key == termbox.KeyArrowRight {
i.cursor++ if i.cursor < 0 {
} i.cursor++
} else if event.Key == termbox.KeyCtrlU { }
// Ctrl+U Clears the Input (before the cursor) } else if event.Key == termbox.KeyCtrlU {
i.value = i.value[i.cursor:] // Ctrl+U Clears the Input (before the cursor)
} else { i.value = i.value[i.cursor:]
// Get the rune to add to our value. Space and Tab are special cases where } else {
// we can't use the event's rune directly // Get the rune to add to our value. Space and Tab are special cases where
var ch string // we can't use the event's rune directly
switch event.Key { var ch string
case termbox.KeySpace: switch event.Key {
ch = " " case termbox.KeySpace:
case termbox.KeyTab: ch = " "
ch = "\t" case termbox.KeyTab:
/* Multiline is disabled right now ch = "\t"
case termbox.KeyEnter: /* Multiline is disabled right now
if i.multiline { case termbox.KeyEnter:
ch = "\n" if i.multiline {
ch = "\n"
}
*/
default:
if KeyIsAlphaNumeric(event) || KeyIsSymbol(event) {
ch = string(event.Ch)
} }
*/ }
default:
if KeyIsAlphaNumeric(event) || KeyIsSymbol(event) { if i.cursor+len(i.value) == 0 {
ch = string(event.Ch) i.value = string(ch) + i.value
} else if i.cursor == 0 {
i.value = i.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
} }
} }
return true
if i.cursor+len(i.value) == 0 {
i.value = string(ch) + i.value
} else if i.cursor == 0 {
i.value = i.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
}
} }
return true return false
} }
// Draw outputs the input field on the screen // Draw outputs the input field on the screen
@ -190,7 +238,11 @@ func (i *InputField) Draw() {
y++ y++
x = startX x = startX
} }
termbox.SetCell(x, y, cursorRune, i.bg, i.fg) if i.active {
termbox.SetCell(x, y, cursorRune, i.bg, i.fg)
} else {
termbox.SetCell(x, y, cursorRune, i.fg, i.bg)
}
x++ x++
if len(strPt2) > 0 { if len(strPt2) > 0 {
lenLeft := maxWidth - len(strPt1) - 1 lenLeft := maxWidth - len(strPt1) - 1
@ -219,7 +271,11 @@ func (i *InputField) Draw() {
} }
} }
x, y = DrawStringAtPoint(strPt1, i.x+1, i.y+1, i.fg, i.bg) x, y = DrawStringAtPoint(strPt1, i.x+1, i.y+1, i.fg, i.bg)
termbox.SetCell(x, y, cursorRune, i.bg, i.fg) if i.active {
termbox.SetCell(x, y, cursorRune, i.bg, i.fg)
} else {
termbox.SetCell(x, y, cursorRune, i.fg, i.bg)
}
DrawStringAtPoint(strPt2, x+1, y, i.fg, i.bg) DrawStringAtPoint(strPt2, x+1, y, i.fg, i.bg)
} }
} }

View File

@ -6,6 +6,7 @@ import (
// InputModal A modal for text input // InputModal A modal for text input
type InputModal struct { type InputModal struct {
id string
title string title string
text string text string
input *InputField input *InputField
@ -15,18 +16,37 @@ type InputModal struct {
bg, fg termbox.Attribute bg, fg termbox.Attribute
isDone bool isDone bool
isVisible bool isVisible bool
bordered bool
tabSkip bool
active bool
} }
// CreateInputModal Create an input modal with the given attributes // CreateInputModal Create an input modal with the given attributes
func CreateInputModal(title string, x, y, width, height int, fg, bg termbox.Attribute) *InputModal { 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} i := InputModal{title: title, x: x, y: y, width: width, height: height, fg: fg, bg: bg, bordered: true}
i.input = CreateInputField(i.x+1, i.y+3, i.width-2, 2, i.fg, i.bg) i.input = CreateInputField(i.x+2, i.y+3, i.width-2, 2, i.fg, i.bg)
i.showHelp = true i.showHelp = true
i.input.bordered = true i.input.bordered = true
i.isVisible = true i.isVisible = true
return &i return &i
} }
// SetActiveFlag sets this control's active flag
func (i *InputModal) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *InputModal) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *InputModal) GetID() string { return i.id }
// SetID sets this control's ID
func (i *InputModal) SetID(newID string) {
i.id = newID
}
// GetTitle Return the title of the modal // GetTitle Return the title of the modal
func (i *InputModal) GetTitle() string { return i.title } func (i *InputModal) GetTitle() string { return i.title }
@ -75,6 +95,26 @@ func (i *InputModal) SetHeight(height int) {
i.height = height i.height = height
} }
// IsBordered returns whether this control is bordered or not
func (i *InputModal) IsBordered() bool {
return i.bordered
}
// SetBordered sets whether we render a border around the frame
func (i *InputModal) SetBordered(b bool) {
i.bordered = b
}
// IsTabSkipped returns whether this control has it's tabskip flag set
func (i *InputModal) IsTabSkipped() bool {
return i.tabSkip
}
// SetTabSkip sets the tabskip flag for this control
func (i *InputModal) SetTabSkip(b bool) {
i.tabSkip = b
}
// HelpIsShown Returns whether the modal is showing it's help text or not // HelpIsShown Returns whether the modal is showing it's help text or not
func (i *InputModal) HelpIsShown() bool { return i.showHelp } func (i *InputModal) HelpIsShown() bool { return i.showHelp }
@ -83,20 +123,20 @@ func (i *InputModal) ShowHelp(b bool) {
i.showHelp = b i.showHelp = b
} }
// GetBackground Return the current background color of the modal // GetFgColor returns the foreground color
func (i *InputModal) GetBackground() termbox.Attribute { return i.bg } func (i *InputModal) GetFgColor() termbox.Attribute { return i.fg }
// SetBackground Set the current background color to bg // SetFgColor sets the foreground color
func (i *InputModal) SetBackground(bg termbox.Attribute) { func (i *InputModal) SetFgColor(fg termbox.Attribute) {
i.bg = bg i.fg = fg
} }
// GetForeground Return the current foreground color // GetBgColor returns the background color
func (i *InputModal) GetForeground() termbox.Attribute { return i.fg } func (i *InputModal) GetBgColor() termbox.Attribute { return i.bg }
// SetForeground Set the foreground color to fg // SetBgColor sets the current background color
func (i *InputModal) SetForeground(fg termbox.Attribute) { func (i *InputModal) SetBgColor(bg termbox.Attribute) {
i.fg = fg i.bg = bg
} }
// Show Sets the visibility flag to true // Show Sets the visibility flag to true
@ -141,14 +181,17 @@ func (i *InputModal) Clear() {
i.isVisible = false i.isVisible = false
} }
// HandleKeyPress Handle the termbox event, return true if it was consumed // HandleEvent Handle the termbox event, return true if it was consumed
func (i *InputModal) HandleKeyPress(event termbox.Event) bool { func (i *InputModal) HandleEvent(event termbox.Event) bool {
if event.Key == termbox.KeyEnter { if i.active {
// Done editing if event.Key == termbox.KeyEnter {
i.isDone = true // Done editing
return true i.isDone = true
return true
}
return i.input.HandleEvent(event)
} }
return i.input.HandleKeyPress(event) return false
} }
// Draw Draw the modal // Draw Draw the modal
@ -181,7 +224,9 @@ func (i *InputModal) Draw() {
helpX := (i.x + i.width - len(helpString)) - 1 helpX := (i.x + i.width - len(helpString)) - 1
DrawStringAtPoint(helpString, helpX, nextY, i.fg, i.bg) DrawStringAtPoint(helpString, helpX, nextY, i.fg, i.bg)
} }
// Now draw the border if i.bordered {
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg) // Now draw the border
DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
}
} }
} }

149
termbox_label.go Normal file
View File

@ -0,0 +1,149 @@
package termboxUtil
import "github.com/nsf/termbox-go"
// Label is a field for inputting text
type Label struct {
id string
value string
x, y, width, height int
cursor int
fg, bg 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
}
// SetActiveFlag sets this control's active flag
func (i *Label) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *Label) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *Label) GetID() string { return i.id }
// SetID sets this control's ID
func (i *Label) SetID(newID string) {
i.id = newID
}
// GetValue gets the current text that is in the Label
func (i *Label) GetValue() string { return i.value }
// SetValue sets the current text in the Label to s
func (i *Label) SetValue(s string) {
i.value = s
}
// GetX returns the x position of the input field
func (i *Label) GetX() int { return i.x }
// SetX sets the x position of the input field
func (i *Label) SetX(x int) {
i.x = x
}
// GetY returns the y position of the input field
func (i *Label) GetY() int { return i.y }
// SetY sets the y position of the input field
func (i *Label) SetY(y int) {
i.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
}
return len(i.value)
}
return i.width
}
// SetWidth sets the current width of the input field
func (i *Label) SetWidth(w int) {
i.width = w
}
// GetHeight returns the current height of the input field
func (i *Label) GetHeight() int { return i.height }
// SetHeight sets the current height of the input field
func (i *Label) SetHeight(h int) {
i.height = h
}
// GetFgColor returns the foreground color
func (i *Label) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *Label) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *Label) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *Label) SetBgColor(bg termbox.Attribute) {
i.bg = bg
}
// IsBordered returns true or false if this input field has a border
func (i *Label) IsBordered() bool { return i.bordered }
// SetBordered sets whether we render a border around the input field
func (i *Label) SetBordered(b bool) {
i.bordered = b
}
// DoesWrap returns true or false if this input field wraps text
func (i *Label) DoesWrap() bool { return i.wrap }
// SetWrap sets whether we wrap the text at width.
func (i *Label) SetWrap(b bool) {
i.wrap = b
}
// IsMultiline returns true or false if this field can have multiple lines
func (i *Label) IsMultiline() bool { return i.multiline }
// SetMultiline sets whether the field can have multiple lines
func (i *Label) SetMultiline(b bool) {
i.multiline = b
}
// HandleEvent accepts the termbox event and returns whether it was consumed
func (i *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)
maxWidth--
maxHeight--
x++
y++
startX++
startY++
}
DrawStringAtPoint(i.value, x, y, i.fg, i.bg)
}

View File

@ -1,9 +1,14 @@
package termboxUtil package termboxUtil
import "github.com/nsf/termbox-go" import (
"strings"
"github.com/nsf/termbox-go"
)
// Menu is a menu with a list of options // Menu is a menu with a list of options
type Menu struct { type Menu struct {
id string
title string title string
options []MenuOption options []MenuOption
// If height is -1, then it is adaptive to the menu // If height is -1, then it is adaptive to the menu
@ -16,6 +21,8 @@ type Menu struct {
isDone bool isDone bool
bordered bool bordered bool
vimMode bool vimMode bool
tabSkip bool
active bool
} }
// CreateMenu Creates a menu with the specified attributes // CreateMenu Creates a menu with the specified attributes
@ -35,6 +42,14 @@ func CreateMenu(title string, options []string, x, y, width, height int, fg, bg
return &i return &i
} }
// GetID returns this control's ID
func (i *Menu) GetID() string { return i.id }
// SetID sets this control's ID
func (i *Menu) SetID(newID string) {
i.id = newID
}
// GetTitle returns the current title of the menu // GetTitle returns the current title of the menu
func (i *Menu) GetTitle() string { return i.title } func (i *Menu) GetTitle() string { return i.title }
@ -193,20 +208,20 @@ func (i *Menu) ShowHelp(b bool) {
i.showHelp = b i.showHelp = b
} }
// GetBackground returns the current background color // GetFgColor returns the foreground color
func (i *Menu) GetBackground() termbox.Attribute { return i.bg } func (i *Menu) GetFgColor() termbox.Attribute { return i.fg }
// SetBackground sets the background color to bg // SetFgColor sets the foreground color
func (i *Menu) SetBackground(bg termbox.Attribute) { func (i *Menu) SetFgColor(fg termbox.Attribute) {
i.bg = bg i.fg = fg
} }
// GetForeground returns the current foreground color // GetBgColor returns the background color
func (i *Menu) GetForeground() termbox.Attribute { return i.fg } func (i *Menu) GetBgColor() termbox.Attribute { return i.bg }
// SetForeground sets the current foreground color to fg // SetBgColor sets the current background color
func (i *Menu) SetForeground(fg termbox.Attribute) { func (i *Menu) SetBgColor(bg termbox.Attribute) {
i.fg = fg i.bg = bg
} }
// IsDone returns whether the user has answered the modal // IsDone returns whether the user has answered the modal
@ -235,29 +250,39 @@ func (i *Menu) DisableVimMode() {
i.vimMode = false i.vimMode = false
} }
// HandleKeyPress handles the termbox event and returns whether it was consumed // SetActiveFlag sets this control's active flag
func (i *Menu) HandleKeyPress(event termbox.Event) bool { func (i *Menu) SetActiveFlag(b bool) {
if event.Key == termbox.KeyEnter || event.Key == termbox.KeySpace { i.active = b
i.isDone = true }
return true
} // IsActive returns whether this control is active
currentIdx := i.GetSelectedIndex() func (i *Menu) IsActive() bool { return i.active }
switch event.Key {
case termbox.KeyArrowUp: // HandleEvent handles the termbox event and returns whether it was consumed
i.SelectPrevOption() func (i *Menu) HandleEvent(event termbox.Event) bool {
case termbox.KeyArrowDown: if i.active {
i.SelectNextOption() if event.Key == termbox.KeyEnter || event.Key == termbox.KeySpace {
} i.isDone = true
if i.vimMode { return true
switch event.Ch { }
case 'j': currentIdx := i.GetSelectedIndex()
i.SelectNextOption() switch event.Key {
case 'k': case termbox.KeyArrowUp:
i.SelectPrevOption() i.SelectPrevOption()
case termbox.KeyArrowDown:
i.SelectNextOption()
}
if i.vimMode {
switch event.Ch {
case 'j':
i.SelectNextOption()
case 'k':
i.SelectPrevOption()
}
}
if i.GetSelectedIndex() != currentIdx {
return true
} }
}
if i.GetSelectedIndex() != currentIdx {
return true
} }
return false return false
} }
@ -325,16 +350,55 @@ func (i *Menu) Draw() {
} }
} }
} }
i.DrawOptions(optionStartX, optionStartY, optionHeight, optionWidth)
}
// DrawOptions draws the menu options at x, y
func (i *Menu) DrawOptions(x, y, h, w int) {
DrawStringAtPoint(strings.Repeat("-", w), x, y, i.disabledFg, i.disabledBg)
y++
if len(i.options) > 0 {
// If the currently selected option is disabled, move to the next
if i.GetSelectedOption().IsDisabled() {
i.SelectNextOption()
}
// Print the options
for idx := range i.options {
if i.GetSelectedIndex()-idx >= h-1 {
// Skip this one
continue
}
currOpt := &i.options[idx]
outTxt := currOpt.GetText()
if len(outTxt) >= i.width {
outTxt = outTxt[:i.width]
}
if currOpt.IsDisabled() {
DrawStringAtPoint(outTxt, x, y, i.disabledFg, i.disabledBg)
} else if i.GetSelectedOption() == currOpt {
DrawStringAtPoint(AlignText(outTxt, w, AlignLeft), x, y, i.selectedFg, i.selectedBg)
} else {
DrawStringAtPoint(outTxt, x, y, i.fg, i.bg)
}
y++
if y > i.y+h-1 {
break
}
}
}
} }
/* MenuOption Struct & methods */ /* MenuOption Struct & methods */
// MenuOption An option in the menu // MenuOption An option in the menu
type MenuOption struct { type MenuOption struct {
id string
text string text string
selected bool selected bool
disabled bool disabled bool
helpText string helpText string
subMenu []MenuOption
} }
// CreateOptionFromText just returns a MenuOption object // CreateOptionFromText just returns a MenuOption object
@ -388,3 +452,8 @@ func (i *MenuOption) SetHelpText(s string) {
// GetHelpText Returns the help text for this option // GetHelpText Returns the help text for this option
func (i *MenuOption) GetHelpText() string { return i.helpText } func (i *MenuOption) GetHelpText() string { return i.helpText }
// AddToSubMenu adds a slice of MenuOptions to this option
func (i *MenuOption) AddToSubMenu(sub *MenuOption) {
i.subMenu = append(i.subMenu, *sub)
}

View File

@ -4,6 +4,7 @@ import "github.com/nsf/termbox-go"
// ProgressBar Just contains the data needed to display a progress bar // ProgressBar Just contains the data needed to display a progress bar
type ProgressBar struct { type ProgressBar struct {
id string
total int total int
progress int progress int
allowOverflow bool allowOverflow bool
@ -17,6 +18,7 @@ type ProgressBar struct {
x, y int x, y int
width, height int width, height int
bg, fg termbox.Attribute bg, fg termbox.Attribute
active bool
} }
// CreateProgressBar Create a progress bar object // CreateProgressBar Create a progress bar object
@ -30,6 +32,22 @@ func CreateProgressBar(tot, x, y int, fg, bg termbox.Attribute) *ProgressBar {
return &i return &i
} }
// SetActiveFlag sets this control's active flag
func (i *ProgressBar) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *ProgressBar) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *ProgressBar) GetID() string { return i.id }
// SetID sets this control's ID
func (i *ProgressBar) SetID(newID string) {
i.id = newID
}
// GetProgress returns the curret progress value // GetProgress returns the curret progress value
func (i *ProgressBar) GetProgress() int { func (i *ProgressBar) GetProgress() int {
return i.progress return i.progress
@ -138,20 +156,20 @@ func (i *ProgressBar) SetWidth(w int) {
i.width = w i.width = w
} }
// GetBackground Return the current background color of the modal // GetFgColor returns the foreground color
func (i *ProgressBar) GetBackground() termbox.Attribute { return i.bg } func (i *ProgressBar) GetFgColor() termbox.Attribute { return i.fg }
// SetBackground Set the current background color to bg // SetFgColor sets the foreground color
func (i *ProgressBar) SetBackground(bg termbox.Attribute) { func (i *ProgressBar) SetFgColor(fg termbox.Attribute) {
i.bg = bg i.fg = fg
} }
// GetForeground Return the current foreground color // GetBgColor returns the background color
func (i *ProgressBar) GetForeground() termbox.Attribute { return i.fg } func (i *ProgressBar) GetBgColor() termbox.Attribute { return i.bg }
// SetForeground Set the foreground color to fg // SetBgColor sets the current background color
func (i *ProgressBar) SetForeground(fg termbox.Attribute) { func (i *ProgressBar) SetBgColor(bg termbox.Attribute) {
i.fg = fg i.bg = bg
} }
// Align Tells which direction the progress bar empties // Align Tells which direction the progress bar empties
@ -168,8 +186,8 @@ func (i *ProgressBar) SetColorized(c bool) {
i.colorized = c i.colorized = c
} }
// HandleKeyPress accepts the termbox event and returns whether it was consumed // HandleEvent accepts the termbox event and returns whether it was consumed
func (i *ProgressBar) HandleKeyPress(event termbox.Event) bool { func (i *ProgressBar) HandleEvent(event termbox.Event) bool {
return false return false
} }

View File

@ -5,12 +5,14 @@ import "github.com/nsf/termbox-go"
// ScrollFrame is a frame for holding other elements // ScrollFrame is a frame for holding other elements
// It manages it's own x/y, tab index // It manages it's own x/y, tab index
type ScrollFrame struct { type ScrollFrame struct {
id string
x, y, width, height int x, y, width, height int
scrollX, scrollY int scrollX, scrollY int
tabIdx int tabIdx int
fg, bg termbox.Attribute fg, bg termbox.Attribute
bordered bool bordered bool
controls []termboxControl controls []termboxControl
active bool
} }
// CreateScrollFrame creates Scrolling Frame at x, y that is w by h // CreateScrollFrame creates Scrolling Frame at x, y that is w by h
@ -19,92 +21,124 @@ func CreateScrollFrame(x, y, w, h int, fg, bg termbox.Attribute) *ScrollFrame {
return &s return &s
} }
// SetActiveFlag sets this control's active flag
func (i *ScrollFrame) SetActiveFlag(b bool) {
i.active = b
}
// IsActive returns whether this control is active
func (i *ScrollFrame) IsActive() bool { return i.active }
// GetID returns this control's ID
func (i *ScrollFrame) GetID() string { return i.id }
// SetID sets this control's ID
func (i *ScrollFrame) SetID(newID string) {
i.id = newID
}
// GetX returns the x position of the scroll frame // GetX returns the x position of the scroll frame
func (s *ScrollFrame) GetX() int { return s.x } func (i *ScrollFrame) GetX() int { return i.x }
// SetX sets the x position of the scroll frame // SetX sets the x position of the scroll frame
func (s *ScrollFrame) SetX(x int) { func (i *ScrollFrame) SetX(x int) {
s.x = x i.x = x
} }
// GetY returns the y position of the scroll frame // GetY returns the y position of the scroll frame
func (s *ScrollFrame) GetY() int { return s.y } func (i *ScrollFrame) GetY() int { return i.y }
// SetY sets the y position of the scroll frame // SetY sets the y position of the scroll frame
func (s *ScrollFrame) SetY(y int) { func (i *ScrollFrame) SetY(y int) {
s.y = y i.y = y
} }
// GetWidth returns the current width of the scroll frame // GetWidth returns the current width of the scroll frame
func (s *ScrollFrame) GetWidth() int { return s.width } func (i *ScrollFrame) GetWidth() int { return i.width }
// SetWidth sets the current width of the scroll frame // SetWidth sets the current width of the scroll frame
func (s *ScrollFrame) SetWidth(w int) { func (i *ScrollFrame) SetWidth(w int) {
s.width = w i.width = w
} }
// GetHeight returns the current height of the scroll frame // GetHeight returns the current height of the scroll frame
func (s *ScrollFrame) GetHeight() int { return s.height } func (i *ScrollFrame) GetHeight() int { return i.height }
// SetHeight sets the current height of the scroll frame // SetHeight sets the current height of the scroll frame
func (s *ScrollFrame) SetHeight(h int) { func (i *ScrollFrame) SetHeight(h int) {
s.height = h i.height = h
}
// GetFgColor returns the foreground color
func (i *ScrollFrame) GetFgColor() termbox.Attribute { return i.fg }
// SetFgColor sets the foreground color
func (i *ScrollFrame) SetFgColor(fg termbox.Attribute) {
i.fg = fg
}
// GetBgColor returns the background color
func (i *ScrollFrame) GetBgColor() termbox.Attribute { return i.bg }
// SetBgColor sets the current background color
func (i *ScrollFrame) SetBgColor(bg termbox.Attribute) {
i.bg = bg
} }
// IsBordered returns true or false if this scroll frame has a border // IsBordered returns true or false if this scroll frame has a border
func (s *ScrollFrame) IsBordered() bool { return s.bordered } func (i *ScrollFrame) IsBordered() bool { return i.bordered }
// SetBordered sets whether we render a border around the scroll frame // SetBordered sets whether we render a border around the scroll frame
func (s *ScrollFrame) SetBordered(b bool) { func (i *ScrollFrame) SetBordered(b bool) {
s.bordered = b i.bordered = b
} }
// GetScrollX returns the x distance scrolled // GetScrollX returns the x distance scrolled
func (s *ScrollFrame) GetScrollX() int { func (i *ScrollFrame) GetScrollX() int {
return s.scrollX return i.scrollX
} }
// GetScrollY returns the y distance scrolled // GetScrollY returns the y distance scrolled
func (s *ScrollFrame) GetScrollY() int { func (i *ScrollFrame) GetScrollY() int {
return s.scrollY return i.scrollY
} }
// ScrollDown scrolls the frame down // ScrollDown scrolls the frame down
func (s *ScrollFrame) ScrollDown() { func (i *ScrollFrame) ScrollDown() {
s.scrollY++ i.scrollY++
} }
// ScrollUp scrolls the frame up // ScrollUp scrolls the frame up
func (s *ScrollFrame) ScrollUp() { func (i *ScrollFrame) ScrollUp() {
if s.scrollY > 0 { if i.scrollY > 0 {
s.scrollY-- i.scrollY--
} }
} }
// ScrollLeft scrolls the frame left // ScrollLeft scrolls the frame left
func (s *ScrollFrame) ScrollLeft() { func (i *ScrollFrame) ScrollLeft() {
if s.scrollX > 0 { if i.scrollX > 0 {
s.scrollX-- i.scrollX--
} }
} }
// ScrollRight scrolls the frame right // ScrollRight scrolls the frame right
func (s *ScrollFrame) ScrollRight() { func (i *ScrollFrame) ScrollRight() {
s.scrollX++ i.scrollX++
} }
// AddControl adds a control to the frame // AddControl adds a control to the frame
func (s *ScrollFrame) AddControl(t termboxControl) { func (i *ScrollFrame) AddControl(t termboxControl) {
s.controls = append(s.controls, t) i.controls = append(i.controls, t)
} }
// DrawControl figures out the relative position of the control, // DrawControl figures out the relative position of the control,
// sets it, draws it, then resets it. // sets it, draws it, then resets it.
func (s *ScrollFrame) DrawControl(t termboxControl) { func (i *ScrollFrame) DrawControl(t termboxControl) {
if s.IsVisible(t) { if i.IsVisible(t) {
ctlX, ctlY := t.GetX(), t.GetY() ctlX, ctlY := t.GetX(), t.GetY()
t.SetX((s.GetX() + ctlX)) t.SetX((i.GetX() + ctlX))
t.SetY((s.GetY() + ctlY)) t.SetY((i.GetY() + ctlY))
t.Draw() t.Draw()
t.SetX(ctlX) t.SetX(ctlX)
t.SetY(ctlY) t.SetY(ctlY)
@ -113,35 +147,35 @@ func (s *ScrollFrame) DrawControl(t termboxControl) {
// IsVisible takes a Termbox Control and returns whether // IsVisible takes a Termbox Control and returns whether
// that control would be visible in the frame // that control would be visible in the frame
func (s *ScrollFrame) IsVisible(t termboxControl) bool { func (i *ScrollFrame) IsVisible(t termboxControl) bool {
// Check if any part of t should be visible // Check if any part of t should be visible
cX, cY := t.GetX(), t.GetY() cX, cY := t.GetX(), t.GetY()
if cX+t.GetWidth() >= s.scrollX && cX <= s.scrollX+s.width { if cX+t.GetWidth() >= i.scrollX && cX <= i.scrollX+i.width {
return cY+t.GetHeight() >= s.scrollY && cY <= s.scrollY+s.height return cY+t.GetHeight() >= i.scrollY && cY <= i.scrollY+i.height
} }
return false return false
} }
// HandleKeyPress accepts the termbox event and returns whether it was consumed // HandleEvent accepts the termbox event and returns whether it was consumed
func (s *ScrollFrame) HandleKeyPress(event termbox.Event) bool { func (i *ScrollFrame) HandleEvent(event termbox.Event) bool {
return false return false
} }
// DrawToStrings generates a slice of strings with what should // DrawToStrings generates a slice of strings with what should
// be drawn to the screen // be drawn to the screen
func (s *ScrollFrame) DrawToStrings() []string { func (i *ScrollFrame) DrawToStrings() []string {
return []string{} return []string{}
} }
// Draw outputs the Scoll Frame on the screen // Draw outputs the Scoll Frame on the screen
func (s *ScrollFrame) Draw() { func (i *ScrollFrame) Draw() {
maxWidth := s.width maxWidth := i.width
maxHeight := s.height maxHeight := i.height
x, y := s.x, s.y x, y := i.x, i.y
startX := s.x startX := i.x
startY := s.y startY := i.y
if s.bordered { if i.bordered {
DrawBorder(s.x, s.y, s.x+s.width, s.y+s.height, s.fg, s.bg) DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg)
maxWidth-- maxWidth--
maxHeight-- maxHeight--
x++ x++
@ -149,7 +183,7 @@ func (s *ScrollFrame) Draw() {
startX++ startX++
startY++ startY++
} }
for i := range s.controls { for idx := range i.controls {
s.DrawControl(s.controls[i]) i.DrawControl(i.controls[idx])
} }
} }

View File

@ -8,6 +8,7 @@ import (
) )
type termboxControl interface { type termboxControl interface {
GetID() string
GetX() int GetX() int
SetX(int) SetX(int)
GetY() int GetY() int
@ -16,7 +17,17 @@ type termboxControl interface {
SetWidth(int) SetWidth(int)
GetHeight() int GetHeight() int
SetHeight(int) SetHeight(int)
HandleKeyPress(termbox.Event) bool GetFgColor() termbox.Attribute
SetFgColor(termbox.Attribute)
GetBgColor() termbox.Attribute
SetBgColor(termbox.Attribute)
HandleEvent(termbox.Event) bool
IsBordered() bool
SetBordered(bool)
SetTabSkip(bool)
IsTabSkipped() bool
IsActive() bool
SetActiveFlag(bool)
Draw() Draw()
} }
@ -112,21 +123,28 @@ func DrawBorder(x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute)
// AlignText Aligns the text txt within width characters using the specified alignment // AlignText Aligns the text txt within width characters using the specified alignment
func AlignText(txt string, width int, align TextAlignment) string { func AlignText(txt string, width int, align TextAlignment) string {
return AlignTextWithFill(txt, width, align, ' ')
}
// AlignTextWithFill Aligns the text txt within width characters using the specified alignment
// filling any spaces with the 'fill' character
func AlignTextWithFill(txt string, width int, align TextAlignment, fill rune) string {
fillChar := string(fill)
numSpaces := width - len(txt) numSpaces := width - len(txt)
switch align { switch align {
case AlignCenter: case AlignCenter:
if numSpaces/2 > 0 { if numSpaces/2 > 0 {
return fmt.Sprintf("%s%s%s", return fmt.Sprintf("%s%s%s",
strings.Repeat(" ", numSpaces/2), strings.Repeat(fillChar, numSpaces/2),
txt, strings.Repeat(" ", numSpaces/2), txt, strings.Repeat(fillChar, numSpaces/2),
) )
} }
return txt return txt
case AlignRight: case AlignRight:
return fmt.Sprintf("%s%s", strings.Repeat(" ", numSpaces), txt) return fmt.Sprintf("%s%s", strings.Repeat(fillChar, numSpaces), txt)
default: default:
if numSpaces >= 0 { if numSpaces >= 0 {
return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", numSpaces)) return fmt.Sprintf("%s%s", txt, strings.Repeat(fillChar, numSpaces))
} }
return txt return txt
} }