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

Input Field still isn't where I want it.

Also added convenience functions to test if
termbox events are alpha/numeric/symbol
This commit is contained in:
Brian Buller 2016-01-13 21:17:08 -06:00
parent e93feb0dde
commit e843ea92b9
2 changed files with 174 additions and 65 deletions

View File

@ -1,7 +1,6 @@
package termboxUtil package termboxUtil
import ( import (
"fmt"
"strings" "strings"
"github.com/nsf/termbox-go" "github.com/nsf/termbox-go"
@ -15,6 +14,7 @@ type InputField struct {
fg, bg termbox.Attribute fg, bg termbox.Attribute
bordered bool bordered bool
wrap bool wrap bool
multiline 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
@ -81,12 +81,20 @@ func (i *InputField) SetBordered(b bool) *InputField {
func (i *InputField) DoesWrap() bool { return i.wrap } func (i *InputField) DoesWrap() bool { return i.wrap }
// SetWrap sets whether we wrap the text at width. // SetWrap sets whether we wrap the text at width.
// If 'wrap' is set, we automatically increase the height when we need to.
func (i *InputField) SetWrap(b bool) *InputField { func (i *InputField) SetWrap(b bool) *InputField {
i.wrap = b i.wrap = b
return i return i
} }
// IsMultiline returns true or false if this field can have multiple lines
func (i *InputField) IsMultiline() bool { return i.multiline }
// SetMultiline sets whether the field can have multiple lines
func (i *InputField) SetMultiline(b bool) *InputField {
i.multiline = b
return i
}
// HandleKeyPress accepts the termbox event and returns whether it was consumed // HandleKeyPress accepts the termbox event and returns whether it was consumed
func (i *InputField) HandleKeyPress(event termbox.Event) bool { func (i *InputField) HandleKeyPress(event termbox.Event) bool {
if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 { if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 {
@ -114,19 +122,23 @@ func (i *InputField) HandleKeyPress(event termbox.Event) bool {
case termbox.KeyTab: case termbox.KeyTab:
ch = "\t" ch = "\t"
case termbox.KeyEnter: case termbox.KeyEnter:
ch = "\n" if i.multiline {
ch = "\n"
}
default: default:
ch = string(event.Ch) if KeyIsAlphaNumeric(event) || KeyIsSymbol(event) {
ch = string(event.Ch)
}
} }
if i.cursor+len(i.value) == 0 { if i.cursor+len(i.value) == 0 {
i.value = fmt.Sprintf("%s%s", ch, i.value) i.value = string(ch) + i.value
} else if i.cursor == 0 { } else if i.cursor == 0 {
i.value = fmt.Sprintf("%s%s", i.value, ch) i.value = i.value + string(ch)
} else { } else {
strPt1 := i.value[:(len(i.value) + i.cursor)] strPt1 := i.value[:(len(i.value) + i.cursor)]
strPt2 := i.value[(len(i.value) + i.cursor):] strPt2 := i.value[(len(i.value) + i.cursor):]
i.value = fmt.Sprintf("%s%s%s", strPt1, ch, strPt2) i.value = strPt1 + string(ch) + strPt2
} }
} }
return true return true
@ -135,76 +147,142 @@ func (i *InputField) HandleKeyPress(event termbox.Event) bool {
// Draw outputs the input field on the screen // Draw outputs the input field on the screen
func (i *InputField) Draw() { func (i *InputField) Draw() {
maxWidth := i.width maxWidth := i.width
maxHeight := i.height
x, y := i.x, i.y x, y := i.x, i.y
startX := i.x startX := i.x
startY := i.y
if i.bordered { if i.bordered {
DrawBorder(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-- maxWidth--
maxHeight--
x++ x++
y++ y++
startX++ startX++
startY++
} }
var strPt1, strPt2 string var valSplit []string //, cursorLine []string
var cursorRune rune if i.multiline {
if len(i.value) > 0 { valSplit = strings.Split(i.value, "\n")
if i.cursor+len(i.value) == 0 {
strPt1 = ""
strPt2 = i.value[1:]
cursorRune = rune(i.value[0])
} else if i.cursor == 0 {
strPt1 = i.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])
}
} else { } else {
strPt1, strPt2, cursorRune = "", "", ' ' if i.wrap {
var j int
for j < len(i.value) {
l, h := j, j+i.width
//if l >= i.cursor && h <= i.cursor {
// cursorLine = append(cursorLine, i.value[l:i.cursor])
// cursorLine = append(cursorLine, i.value[i.cursor]...)
// cursorLine = append(cursorLine, i.value[i.cursor:h])
//} else {
valSplit = append(valSplit, i.value[l:h])
//}
j = h
}
}
} }
// strPt1, strPt2 = all of the text before, after the cursor for j := range valSplit {
// cursorRune is the rune on the cursor DrawStringAtPoint(valSplit[j], x, y+j, i.fg, i.bg)
if i.wrap { }
// Split the text into maxWidth chunks //var valSplit []string
for len(strPt1) > maxWidth { //|| nlCount > 0 { // if it's not multiline, new lines aren't allowed in the input
breakAt := maxWidth /*
DrawStringAtPoint(strPt1[:breakAt], x, y, i.fg, i.bg) multiSplit := strings.Split(i.value, "\n")
x = startX var cursCount int
y++ for j := range multiSplit {
strPt1 = strPt1[breakAt:] for k := range multiSplit[j] {
} if cursCount == i.cursor {
x, y = DrawStringAtPoint(strPt1, x, y, i.fg, i.bg) termbox.SetCell(x+k, y+j, rune(multiSplit[j][k]), i.fg, i.bg)
if maxWidth-len(strPt1) <= 0 { } else {
termbox.SetCell(x, y, cursorRune, i.bg, i.fg) termbox.SetCell(x+k, y+j, rune(multiSplit[j][k]), i.bg, i.fg)
}
if len(strPt2) > 0 {
if maxWidth-len(strPt1)-1 > 0 {
DrawStringAtPoint(strPt2[:(maxWidth-len(strPt1)-1)], x+1, y, i.fg, i.bg)
strPt2 = strPt2[(maxWidth - len(strPt1)):]
}
nlCount := strings.Count(strPt2, "\n")
for len(strPt2) > maxWidth || nlCount > 0 {
x, y = DrawStringAtPoint(strPt2[:maxWidth], x, y, i.fg, i.bg)
strPt2 = strPt2[maxWidth:]
}
x, y = DrawStringAtPoint(strPt2, x, y, i.fg, i.bg)
}
} else {
// Not wrapping, just adjust the viewport
for len(strPt1)+len(strPt2)+1 > maxWidth {
if len(strPt1) >= len(strPt2) {
if len(strPt1) == 0 {
break
} }
strPt1 = strPt1[1:] cursCount++
} else {
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.bg, i.fg) /*
DrawStringAtPoint(strPt2, x+1, y, i.fg, i.bg) if i.wrap {
} // Automatically wrap the text
for j := range multiSplit {
for len(multiSplit[j]) > maxWidth {
valSplit = append(valSplit, multiSplit[j][:maxWidth])
multiSplit[j] = multiSplit[j][maxWidth:]
}
}
} else {
valSplit = multiSplit
}
for j := range valSplit {
DrawStringAtPoint(valSplit[j], x, y+j, i.fg, i.bg)
}
/*
var strPt1, strPt2 string
var cursorRune rune
if len(i.value) > 0 {
if i.cursor+len(i.value) == 0 {
strPt1 = ""
strPt2 = i.value[1:]
cursorRune = rune(i.value[0])
} else if i.cursor == 0 {
strPt1 = i.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])
}
} else {
strPt1, strPt2, cursorRune = "", "", ' '
}
// strPt1, strPt2 = all of the text before, after the cursor
// cursorRune is the rune on the cursor
if i.wrap {
// Split the text into maxWidth chunks
for len(strPt1) > maxWidth {
breakAt := maxWidth
DrawStringAtPoint(strPt1[:breakAt], x, y, i.fg, i.bg)
x = startX
y++
strPt1 = strPt1[breakAt:]
}
x, y = DrawStringAtPoint(strPt1, x, y, i.fg, i.bg)
if x >= maxWidth {
y++
x = startX
}
termbox.SetCell(x, y, cursorRune, i.bg, i.fg)
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)
strPt2 = strPt2[lenLeft:]
}
for len(strPt2) > maxWidth {
breakAt := maxWidth
DrawStringAtPoint(strPt2[:breakAt], x, y, i.fg, i.bg)
x = startX
y++
strPt2 = strPt2[breakAt:]
}
x, y = DrawStringAtPoint(strPt2, x, y, i.fg, i.bg)
}
} else {
// Not wrapping, just adjust the viewport
for len(strPt1)+len(strPt2)+1 > maxWidth {
if len(strPt1) >= len(strPt2) {
if len(strPt1) == 0 {
break
}
strPt1 = strPt1[1:]
} else {
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.bg, i.fg)
DrawStringAtPoint(strPt2, x+1, y, i.fg, i.bg)
}
*/
} }

View File

@ -24,13 +24,44 @@ const (
// KeyIsAlphaNumeric Returns whether the termbox event is an // KeyIsAlphaNumeric Returns whether the termbox event is an
// Alpha-Numeric Key Press // Alpha-Numeric Key Press
func KeyIsAlphaNumeric(event termbox.Event) bool { func KeyIsAlphaNumeric(event termbox.Event) bool {
return KeyIsAlpha(event) || KeyIsNumeric(event)
}
// KeyIsAlpha Returns whether the termbox event is a
// alphabetic Key press
func KeyIsAlpha(event termbox.Event) bool {
k := event.Ch k := event.Ch
if (k >= 'a' && k <= 'z') || (k >= 'A' && k <= 'Z') || (k >= '0' && k <= '9') { if (k >= 'a' && k <= 'z') || (k >= 'A' && k <= 'Z') {
return true return true
} }
return false return false
} }
// KeyIsNumeric Returns whether the termbox event is a
// numeric Key press
func KeyIsNumeric(event termbox.Event) bool {
k := event.Ch
if k >= '0' && k <= '9' {
return true
}
return false
}
// KeyIsSymbol Returns whether the termbox event is a
// symbol Key press
func KeyIsSymbol(event termbox.Event) bool {
symbols := []rune{'!', '@', '#', '$', '%', '^', '&', '*',
'(', ')', '-', '_', '=', '+', '[', ']', '{', '}', '|',
';', ':', '"', '\'', ',', '<', '.', '>', '/', '?', '`', '~'}
k := event.Ch
for i := range symbols {
if k == symbols[i] {
return true
}
}
return false
}
/* Basic Output Helpers */ /* Basic Output Helpers */
// DrawStringAtPoint Draw a string of text at x, y with foreground color fg, background color bg // DrawStringAtPoint Draw a string of text at x, y with foreground color fg, background color bg