Implemented a single-line text box. This implements many of the features missing from the text entry used in version 1.
This commit is contained in:
parent
6227b76b86
commit
e86cb4fd63
10
main.go
10
main.go
|
|
@ -12,17 +12,21 @@ func main() {
|
||||||
defer uiManager.Close()
|
defer uiManager.Close()
|
||||||
|
|
||||||
|
|
||||||
|
cmdText := &ui.TextEntry{ Prompt: "Enter: " }
|
||||||
|
|
||||||
statusLayout := &ui.VertLinearLayout{}
|
statusLayout := &ui.VertLinearLayout{}
|
||||||
statusLayout.Append(&ui.StatusBar{"Test", "Component"})
|
statusLayout.Append(&ui.StatusBar{"Test", "Component"})
|
||||||
statusLayout.Append(&ui.StatusBar{"Another", "Component"})
|
statusLayout.Append(cmdText)
|
||||||
statusLayout.Append(&ui.StatusBar{"Third", "Test"})
|
//statusLayout.Append(&ui.StatusBar{"Another", "Component"})
|
||||||
|
//statusLayout.Append(&ui.StatusBar{"Third", "Test"})
|
||||||
|
|
||||||
grid := ui.NewGrid(&ui.TestModel{})
|
grid := ui.NewGrid(&ui.TestModel{})
|
||||||
|
|
||||||
clientArea := &ui.RelativeLayout{ Client: grid, South: statusLayout }
|
clientArea := &ui.RelativeLayout{ Client: grid, South: statusLayout }
|
||||||
|
|
||||||
uiManager.SetRootComponent(clientArea)
|
uiManager.SetRootComponent(clientArea)
|
||||||
uiManager.SetFocusedComponent(grid)
|
//uiManager.SetFocusedComponent(grid)
|
||||||
|
uiManager.SetFocusedComponent(cmdText)
|
||||||
|
|
||||||
uiManager.Loop()
|
uiManager.Loop()
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,6 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
|
|
||||||
// The set of event types supported by the UI package.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// An interface of a UI component.
|
// An interface of a UI component.
|
||||||
type UiComponent interface {
|
type UiComponent interface {
|
||||||
|
|
||||||
|
|
@ -24,44 +19,5 @@ type UiComponent interface {
|
||||||
type FocusableComponent interface {
|
type FocusableComponent interface {
|
||||||
|
|
||||||
// Called when the component has focus and a key has been pressed
|
// Called when the component has focus and a key has been pressed
|
||||||
KeyPressed(key rune)
|
KeyPressed(key rune, mod int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// UI context.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// Status bar component
|
|
||||||
|
|
||||||
/*
|
|
||||||
type UiStatusBar struct {
|
|
||||||
left string // Left aligned string
|
|
||||||
right string // Right aligned string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Minimum dimensions
|
|
||||||
func (sbar *UiStatusBar) RequestDims() (int, int) {
|
|
||||||
return -1, 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status bar redraw
|
|
||||||
func (sbar *UiStatusBar) Redraw(x int, y int, w int, h int) {
|
|
||||||
leftLen := len(sbar.left)
|
|
||||||
rightLen := len(sbar.right)
|
|
||||||
rightPos := w - rightLen
|
|
||||||
|
|
||||||
for x1 := 0; x1 < w; x1++ {
|
|
||||||
var runeToPrint rune = ' '
|
|
||||||
if x1 < leftLen {
|
|
||||||
runeToPrint = rune(sbar.left[x1])
|
|
||||||
} else if x1 >= rightPos {
|
|
||||||
runeToPrint = rune(sbar.right[x1 - rightPos])
|
|
||||||
}
|
|
||||||
termbox.SetCell(x1, y, runeToPrint, termbox.AttrReverse, termbox.AttrReverse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -78,6 +78,13 @@ func (dc *DrawContext) DrawRuneWithAttrs(x, y int, ch rune, fa, ba Attribute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the position of the cursor
|
||||||
|
func (dc *DrawContext) SetCursorPosition(x, y int) {
|
||||||
|
if rx, ry, isWithinContext := dc.localPointToRealPoint(x, y); isWithinContext {
|
||||||
|
dc.driver.SetCursor(rx, ry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Converts a local point to a real point. If the point is within the context, also returns true
|
// Converts a local point to a real point. If the point is within the context, also returns true
|
||||||
func (dc *DrawContext) localPointToRealPoint(x, y int) (int, int, bool) {
|
func (dc *DrawContext) localPointToRealPoint(x, y int) (int, int, bool) {
|
||||||
rx, ry := x + dc.X, y + dc.Y
|
rx, ry := x + dc.X, y + dc.Y
|
||||||
|
|
|
||||||
66
ui/driver.go
66
ui/driver.go
|
|
@ -28,30 +28,7 @@ const (
|
||||||
|
|
||||||
// Special keys
|
// Special keys
|
||||||
const (
|
const (
|
||||||
KeyF1 rune = 0x8000 + iota
|
KeyCtrlSpace rune = 0x8000 + iota
|
||||||
KeyF2
|
|
||||||
KeyF3
|
|
||||||
KeyF4
|
|
||||||
KeyF5
|
|
||||||
KeyF6
|
|
||||||
KeyF7
|
|
||||||
KeyF8
|
|
||||||
KeyF9
|
|
||||||
KeyF10
|
|
||||||
KeyF11
|
|
||||||
KeyF12
|
|
||||||
KeyInsert
|
|
||||||
KeyDelete
|
|
||||||
KeyHome
|
|
||||||
KeyEnd
|
|
||||||
KeyPgup
|
|
||||||
KeyPgdn
|
|
||||||
KeyArrowUp
|
|
||||||
KeyArrowDown
|
|
||||||
KeyArrowLeft
|
|
||||||
KeyArrowRight
|
|
||||||
|
|
||||||
KeyCtrlSpace
|
|
||||||
KeyCtrlA
|
KeyCtrlA
|
||||||
KeyCtrlB
|
KeyCtrlB
|
||||||
KeyCtrlC
|
KeyCtrlC
|
||||||
|
|
@ -84,7 +61,33 @@ const (
|
||||||
KeyCtrl6
|
KeyCtrl6
|
||||||
KeyCtrl7
|
KeyCtrl7
|
||||||
KeyCtrl8
|
KeyCtrl8
|
||||||
KeySpace
|
|
||||||
|
KeyF1
|
||||||
|
KeyF2
|
||||||
|
KeyF3
|
||||||
|
KeyF4
|
||||||
|
KeyF5
|
||||||
|
KeyF6
|
||||||
|
KeyF7
|
||||||
|
KeyF8
|
||||||
|
KeyF9
|
||||||
|
KeyF10
|
||||||
|
KeyF11
|
||||||
|
KeyF12
|
||||||
|
KeyInsert
|
||||||
|
KeyDelete
|
||||||
|
KeyHome
|
||||||
|
KeyEnd
|
||||||
|
KeyPgup
|
||||||
|
KeyPgdn
|
||||||
|
KeyArrowUp
|
||||||
|
KeyArrowDown
|
||||||
|
KeyArrowLeft
|
||||||
|
KeyArrowRight
|
||||||
|
|
||||||
|
KeyBackspace = KeyCtrlH
|
||||||
|
KeyBackspace2 = KeyCtrl8
|
||||||
|
KeyEnter = KeyCtrlM
|
||||||
)
|
)
|
||||||
|
|
||||||
// The type of events supported by the driver
|
// The type of events supported by the driver
|
||||||
|
|
@ -96,13 +99,19 @@ const (
|
||||||
// Event when the window is resized
|
// Event when the window is resized
|
||||||
EventResize
|
EventResize
|
||||||
|
|
||||||
// Event indicating a key press. The key is set in Ch
|
// Event indicating a key press. The key is set in Ch and modifications
|
||||||
|
// are set in Or
|
||||||
EventKeyPress
|
EventKeyPress
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModKeyAlt int = (1 << iota)
|
||||||
|
)
|
||||||
|
|
||||||
// Data from an event callback.
|
// Data from an event callback.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Type EventType
|
Type EventType
|
||||||
|
Par int
|
||||||
Ch rune
|
Ch rune
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,6 +136,7 @@ type Driver interface {
|
||||||
|
|
||||||
// Wait for an event
|
// Wait for an event
|
||||||
WaitForEvent() Event
|
WaitForEvent() Event
|
||||||
}
|
|
||||||
|
|
||||||
//
|
// Move the position of the cursor
|
||||||
|
SetCursor(x, y int)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@ package ui
|
||||||
|
|
||||||
// The UI manager
|
// The UI manager
|
||||||
type Ui struct {
|
type Ui struct {
|
||||||
//grid *Grid
|
|
||||||
//statusBar *UiStatusBar
|
|
||||||
|
|
||||||
// The root component
|
// The root component
|
||||||
rootComponent UiComponent
|
rootComponent UiComponent
|
||||||
focusedComponent FocusableComponent
|
focusedComponent FocusableComponent
|
||||||
|
|
@ -31,22 +28,6 @@ func NewUI() (*Ui, error) {
|
||||||
drawContext := &DrawContext{ driver: driver }
|
drawContext := &DrawContext{ driver: driver }
|
||||||
ui := &Ui{ drawContext: drawContext, driver: driver }
|
ui := &Ui{ drawContext: drawContext, driver: driver }
|
||||||
|
|
||||||
/*
|
|
||||||
termboxError := termbox.Init()
|
|
||||||
|
|
||||||
if termboxError != nil {
|
|
||||||
return nil, termboxError
|
|
||||||
} else {
|
|
||||||
uiCtx := new(Ui) // &Ui{&UiStatusBar{"Hello", "World"}}
|
|
||||||
uiCtx.grid = NewGrid(&TestModel{})
|
|
||||||
uiCtx.statusBar = &UiStatusBar{"Hello", "World"}
|
|
||||||
return uiCtx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Workaround for bug in compiler
|
|
||||||
panic("Unreachable code")
|
|
||||||
return nil, nil
|
|
||||||
*/
|
|
||||||
return ui, nil
|
return ui, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,23 +65,6 @@ func (ui *Ui) Redraw() {
|
||||||
ui.driver.Sync()
|
ui.driver.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal redraw function which does not query the terminal size.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
func (ui *Ui) redrawInternal(width, height int) {
|
|
||||||
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
|
|
||||||
|
|
||||||
// TODO: This will eventually offload to UI "components"
|
|
||||||
ui.grid.Redraw(0, 0, width, height - 2)
|
|
||||||
|
|
||||||
// Draws the status bar
|
|
||||||
ui.statusBar.Redraw(0, height - 2, width, 2)
|
|
||||||
|
|
||||||
termbox.Flush()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Enter the UI loop
|
// Enter the UI loop
|
||||||
func (ui *Ui) Loop() {
|
func (ui *Ui) Loop() {
|
||||||
|
|
@ -111,38 +75,12 @@ func (ui *Ui) Loop() {
|
||||||
// TODO: If the event is a key-press, do something.
|
// TODO: If the event is a key-press, do something.
|
||||||
if event.Type == EventKeyPress {
|
if event.Type == EventKeyPress {
|
||||||
if ui.focusedComponent != nil {
|
if ui.focusedComponent != nil {
|
||||||
ui.focusedComponent.KeyPressed(event.Ch)
|
ui.focusedComponent.KeyPressed(event.Ch, event.Par)
|
||||||
}
|
}
|
||||||
} else if event.Type == EventResize {
|
} else if event.Type == EventResize {
|
||||||
|
|
||||||
// HACK: Find another way to refresh the size of the screen to prevent a full redraw.
|
// HACK: Find another way to refresh the size of the screen to prevent a full redraw.
|
||||||
ui.driver.Sync()
|
ui.driver.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if event.Type == termbox.EventResize {
|
|
||||||
ui.redrawInternal(event.Width, event.Height)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// !!TEMP!!
|
|
||||||
if (event.Ch == 'i') {
|
|
||||||
ui.grid.MoveBy(0, -1)
|
|
||||||
} else if (event.Ch == 'k') {
|
|
||||||
ui.grid.MoveBy(0, 1)
|
|
||||||
} else if (event.Ch == 'j') {
|
|
||||||
ui.grid.MoveBy(-1, 0)
|
|
||||||
} else if (event.Ch == 'l') {
|
|
||||||
ui.grid.MoveBy(1, 0)
|
|
||||||
} else {
|
|
||||||
return UiEvent{EventKeyPress, 0}
|
|
||||||
}
|
}
|
||||||
// !!END TEMP!!
|
|
||||||
|
|
||||||
ui.Redraw()
|
|
||||||
//return UiEvent{EventKeyPress, 0}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Workaround for bug in compiler
|
|
||||||
}
|
}
|
||||||
146
ui/stdcomps.go
146
ui/stdcomps.go
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
|
import "unicode"
|
||||||
|
|
||||||
// Status bar component. This component displays text on the left and right of it's
|
// Status bar component. This component displays text on the left and right of it's
|
||||||
// allocated space.
|
// allocated space.
|
||||||
|
|
@ -23,19 +24,134 @@ func (sbar *StatusBar) Redraw(context *DrawContext) {
|
||||||
context.HorizRule(0, ' ')
|
context.HorizRule(0, ' ')
|
||||||
context.Print(0, 0, sbar.Left)
|
context.Print(0, 0, sbar.Left)
|
||||||
context.PrintRight(context.W, 0, sbar.Right)
|
context.PrintRight(context.W, 0, sbar.Right)
|
||||||
/*
|
}
|
||||||
leftLen := len(sbar.left)
|
|
||||||
rightLen := len(sbar.right)
|
|
||||||
rightPos := w - rightLen
|
// A single-text entry component.
|
||||||
|
type TextEntry struct {
|
||||||
for x1 := 0; x1 < w; x1++ {
|
Prompt string
|
||||||
var runeToPrint rune = ' '
|
|
||||||
if x1 < leftLen {
|
value string
|
||||||
runeToPrint = rune(sbar.left[x1])
|
cursorOffset int
|
||||||
} else if x1 >= rightPos {
|
displayOffset int
|
||||||
runeToPrint = rune(sbar.right[x1 - rightPos])
|
}
|
||||||
}
|
|
||||||
termbox.SetCell(x1, y, runeToPrint, termbox.AttrReverse, termbox.AttrReverse)
|
func (te *TextEntry) Remeasure(w, h int) (int, int) {
|
||||||
}
|
return w, 1
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
func (te *TextEntry) Redraw(context *DrawContext) {
|
||||||
|
context.HorizRule(0, ' ')
|
||||||
|
valueOffsetX := 0
|
||||||
|
displayOffsetX := te.calculateDisplayOffset(context.W)
|
||||||
|
|
||||||
|
if te.Prompt != "" {
|
||||||
|
context.SetFgAttr(ColorDefault | AttrBold)
|
||||||
|
context.Print(0, 0, te.Prompt)
|
||||||
|
context.SetFgAttr(ColorDefault)
|
||||||
|
|
||||||
|
valueOffsetX = len(te.Prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Print(valueOffsetX, 0, te.value[displayOffsetX:intMin(displayOffsetX + context.W,len(te.value))])
|
||||||
|
context.SetCursorPosition(te.cursorOffset + valueOffsetX - displayOffsetX, 0)
|
||||||
|
|
||||||
|
//context.Print(0, 0, fmt.Sprintf("%d,%d", te.cursorOffset, displayOffsetX))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *TextEntry) calculateDisplayOffset(displayWidth int) int {
|
||||||
|
if te.Prompt != "" {
|
||||||
|
displayWidth -= len(te.Prompt)
|
||||||
|
}
|
||||||
|
virtualCursorOffset := te.cursorOffset - te.displayOffset
|
||||||
|
|
||||||
|
if virtualCursorOffset >= displayWidth {
|
||||||
|
te.displayOffset = te.cursorOffset - displayWidth + 10
|
||||||
|
} else if (virtualCursorOffset < 0) {
|
||||||
|
te.displayOffset = intMax(te.cursorOffset - displayWidth + 1, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return te.displayOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *TextEntry) KeyPressed(key rune, mod int) {
|
||||||
|
if (key >= ' ') && (key <= '~') {
|
||||||
|
te.insertRune(key)
|
||||||
|
} else if (key == KeyArrowLeft) {
|
||||||
|
te.moveCursorBy(-1)
|
||||||
|
} else if (key == KeyArrowRight) {
|
||||||
|
te.moveCursorBy(1)
|
||||||
|
} else if (key == KeyHome) {
|
||||||
|
te.moveCursorTo(0)
|
||||||
|
} else if (key == KeyEnd) {
|
||||||
|
te.moveCursorTo(len(te.value))
|
||||||
|
} else if (key == KeyBackspace) || (key == KeyBackspace2) {
|
||||||
|
if (mod & ModKeyAlt != 0) {
|
||||||
|
te.backspaceWhile(unicode.IsSpace)
|
||||||
|
te.backspaceWhile(func(r rune) bool { return !unicode.IsSpace(r) })
|
||||||
|
} else {
|
||||||
|
te.backspace()
|
||||||
|
}
|
||||||
|
} else if (key == KeyCtrlK) {
|
||||||
|
te.killLine()
|
||||||
|
} else if (key == KeyDelete) {
|
||||||
|
te.removeCharAtPos(te.cursorOffset)
|
||||||
|
} else if (key == KeyEnter) {
|
||||||
|
panic("Entered text: '" + te.value + "'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backspace
|
||||||
|
func (te *TextEntry) backspace() {
|
||||||
|
te.removeCharAtPos(te.cursorOffset - 1)
|
||||||
|
te.moveCursorBy(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backspace while the character underneith the cursor matches the guard
|
||||||
|
func (te *TextEntry) backspaceWhile(guard func(r rune) bool) {
|
||||||
|
for (te.cursorOffset > 0) {
|
||||||
|
ch := rune(te.value[te.cursorOffset - 1])
|
||||||
|
if guard(ch) {
|
||||||
|
te.backspace()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill the line. If the cursor is at the end of the line, kill to the start.
|
||||||
|
// Otherwise, trim the line.
|
||||||
|
func (te *TextEntry) killLine() {
|
||||||
|
if (te.cursorOffset < len(te.value)) {
|
||||||
|
te.value = te.value[:te.cursorOffset]
|
||||||
|
} else {
|
||||||
|
te.value = ""
|
||||||
|
te.cursorOffset = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserts a rune at the cursor position
|
||||||
|
func (te *TextEntry) insertRune(key rune) {
|
||||||
|
if (te.cursorOffset >= len(te.value)) {
|
||||||
|
te.value += string(key)
|
||||||
|
} else {
|
||||||
|
te.value = te.value[:te.cursorOffset] + string(key) + te.value[te.cursorOffset:]
|
||||||
|
}
|
||||||
|
te.moveCursorBy(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the character at a specific position
|
||||||
|
func (te *TextEntry) removeCharAtPos(pos int) {
|
||||||
|
if (pos >= 0) && (pos < len(te.value)) {
|
||||||
|
te.value = te.value[:pos] + te.value[pos+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the cursor
|
||||||
|
func (te *TextEntry) moveCursorBy(byX int) {
|
||||||
|
te.moveCursorTo(te.cursorOffset + byX)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *TextEntry) moveCursorTo(toX int) {
|
||||||
|
te.cursorOffset = intMinMax(toX, 0, len(te.value))
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,13 @@ type TermboxDriver struct {
|
||||||
|
|
||||||
// Initializes the driver. Returns an error if there was an error
|
// Initializes the driver. Returns an error if there was an error
|
||||||
func (td *TermboxDriver) Init() error {
|
func (td *TermboxDriver) Init() error {
|
||||||
return termbox.Init()
|
err := termbox.Init()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
termbox.SetInputMode(termbox.InputAlt)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closes the driver
|
// Closes the driver
|
||||||
|
|
@ -42,23 +48,35 @@ func (td *TermboxDriver) WaitForEvent() Event {
|
||||||
|
|
||||||
switch tev.Type {
|
switch tev.Type {
|
||||||
case termbox.EventResize:
|
case termbox.EventResize:
|
||||||
return Event{EventResize, 0}
|
return Event{EventResize, 0, 0}
|
||||||
case termbox.EventKey:
|
case termbox.EventKey:
|
||||||
|
mod := 0
|
||||||
|
if tev.Mod & termbox.ModAlt != 0 {
|
||||||
|
mod = ModKeyAlt
|
||||||
|
}
|
||||||
if tev.Ch != 0 {
|
if tev.Ch != 0 {
|
||||||
return Event{EventKeyPress, tev.Ch}
|
return Event{EventKeyPress, mod, tev.Ch}
|
||||||
} else if spec, hasSpec := termboxKeysToSpecialKeys[tev.Key] ; hasSpec {
|
} else if spec, hasSpec := termboxKeysToSpecialKeys[tev.Key] ; hasSpec {
|
||||||
return Event{EventKeyPress, spec}
|
return Event{EventKeyPress, mod, spec}
|
||||||
} else {
|
} else {
|
||||||
return Event{EventNone, 0}
|
return Event{EventNone, mod, 0}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return Event{EventNone, 0}
|
return Event{EventNone, 0, 0}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move the position of the cursor
|
||||||
|
func (td *TermboxDriver) SetCursor(x, y int) {
|
||||||
|
termbox.SetCursor(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Map from termbox Keys to driver key runes
|
// Map from termbox Keys to driver key runes
|
||||||
var termboxKeysToSpecialKeys = map[termbox.Key]rune {
|
var termboxKeysToSpecialKeys = map[termbox.Key]rune {
|
||||||
|
termbox.KeySpace: ' ',
|
||||||
|
|
||||||
termbox.KeyF1: KeyF1,
|
termbox.KeyF1: KeyF1,
|
||||||
termbox.KeyF2: KeyF2,
|
termbox.KeyF2: KeyF2,
|
||||||
termbox.KeyF3: KeyF3,
|
termbox.KeyF3: KeyF3,
|
||||||
|
|
@ -114,6 +132,5 @@ var termboxKeysToSpecialKeys = map[termbox.Key]rune {
|
||||||
termbox.KeyCtrl5: KeyCtrl5,
|
termbox.KeyCtrl5: KeyCtrl5,
|
||||||
termbox.KeyCtrl6: KeyCtrl6,
|
termbox.KeyCtrl6: KeyCtrl6,
|
||||||
termbox.KeyCtrl7: KeyCtrl7,
|
termbox.KeyCtrl7: KeyCtrl7,
|
||||||
termbox.KeySpace: KeySpace,
|
|
||||||
termbox.KeyCtrl8: KeyCtrl8,
|
termbox.KeyCtrl8: KeyCtrl8,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
ui/utils.go
20
ui/utils.go
|
|
@ -11,3 +11,23 @@ func intMax(x, y int) int {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the minimum value of either x or y.
|
||||||
|
func intMin(x, y int) int {
|
||||||
|
if (x > y) {
|
||||||
|
return y
|
||||||
|
} else {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the value capped between two limits.
|
||||||
|
func intMinMax(x, min, max int) int {
|
||||||
|
if (x < min) {
|
||||||
|
return min
|
||||||
|
} else if (x > max) {
|
||||||
|
return max
|
||||||
|
} else {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue