From d03ef8f013f2dcf7944f420f532a03252505f047 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 1 May 2015 22:15:36 -0500 Subject: [PATCH] Initial Commit --- termbox-test/main.go | 78 ++++++++++++++++++++++++ termbox_inputfield.go | 113 +++++++++++++++++++++++++++++++++++ termbox_inputmodal.go | 134 ++++++++++++++++++++++++++++++++++++++++++ termbox_util.go | 57 ++++++++++++++++++ 4 files changed, 382 insertions(+) create mode 100644 termbox-test/main.go create mode 100644 termbox_inputfield.go create mode 100644 termbox_inputmodal.go create mode 100644 termbox_util.go diff --git a/termbox-test/main.go b/termbox-test/main.go new file mode 100644 index 0000000..abc2368 --- /dev/null +++ b/termbox-test/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "github.com/nsf/termbox-go" + "gogs.bullercodeworks.com/brian/termbox-util" + "os" + "syscall" +) + +var keep_running bool + +func main() { + keep_running = true + err := termbox.Init() + if err != nil { + panic(err) + } + defer termbox.Close() + termbox.SetOutputMode(termbox.Output256) + mainLoop() +} + +var input *termbox_util.InputField + +//var input *termbox_util.InputModal + +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-(mw/2), h-(mh/2) + mw, mh := w/4, 2 + mx, my := (w/2)-(mw/2), (h/2)-(mh/2) + // input = termbox_util.CreateInputModal("Test Input", mx, my, mw, mh, termbox.ColorWhite, termbox.ColorBlack) + input = termbox_util.CreateInputField(mx, my, mw, mh, termbox.ColorWhite, termbox.ColorBlack) + input.SetBordered(true) + } + input.Draw() +} + +func handleKeyEvent(event termbox.Event) bool { + if event.Key == termbox.KeyEsc { + return false + } else { + input.HandleKeyPress(event) + } + return true +} + +func mainLoop() { + layoutAndDrawScreen() + for { + event := termbox.PollEvent() + if event.Type == termbox.EventKey { + if event.Key == termbox.KeyCtrlZ { + process, _ := os.FindProcess(os.Getpid()) + termbox.Close() + process.Signal(syscall.SIGSTOP) + termbox.Init() + } + keep_running = handleKeyEvent(event) + if !keep_running { + break + } + layoutAndDrawScreen() + } + if event.Type == termbox.EventResize { + layoutAndDrawScreen() + } + } +} \ No newline at end of file diff --git a/termbox_inputfield.go b/termbox_inputfield.go new file mode 100644 index 0000000..f551c97 --- /dev/null +++ b/termbox_inputfield.go @@ -0,0 +1,113 @@ +package termbox_util + +import ( + "fmt" + "github.com/nsf/termbox-go" +) + +type InputField struct { + value string + x, y, width, height int + cursor int + fg, bg termbox.Attribute + bordered bool +} + +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} + return &i +} + +func (i *InputField) GetValue() string { return i.value } +func (i *InputField) SetValue(s string) *InputField { + i.value = s + return i +} + +func (i *InputField) GetX() int { return i.x } +func (i *InputField) SetX(x int) *InputField { + i.x = x + return i +} + +func (i *InputField) GetY() int { return i.y } +func (i *InputField) SetY(y int) *InputField { + i.y = y + return i +} + +func (i *InputField) GetWidth() int { return i.width } +func (i *InputField) SetWidth(w int) *InputField { + i.width = w + return i +} + +func (i *InputField) GetHeight() int { return i.height } +func (i *InputField) SetHeight(h int) *InputField { + i.height = h + return i +} + +func (i *InputField) IsBordered() bool { return i.bordered } +func (i *InputField) SetBordered(b bool) *InputField { + i.bordered = b + return i +} + +func (i *InputField) HandleKeyPress(event termbox.Event) bool { + if event.Key == termbox.KeyEnter { + // Done editing + } else if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 { + 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 { + i.cursor -= 1 + } + } else if event.Key == termbox.KeyArrowRight { + if i.cursor < 0 { + i.cursor += 1 + } + } else { + if i.cursor+len(i.value) == 0 { + i.value = fmt.Sprintf("%s%s", string(event.Ch), i.value) + } else if i.cursor == 0 { + i.value = fmt.Sprintf("%s%s", i.value, string(event.Ch)) + } else { + str_pt_1 := i.value + str_pt_2 := i.value + i.value = fmt.Sprintf("%s%s%s", str_pt_1, string(event.Ch), str_pt_2) + } + } + return true +} + +func (i *InputField) Draw() { + if i.bordered { + DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg) + } + + var str_pt_1, str_pt_2 string + var cursor_rune rune + if len(i.value) > 0 { + if i.cursor+len(i.value) == 0 { + str_pt_1 = "" + str_pt_2 = i.value[1:] + cursor_rune = rune(i.value[1]) + } else if i.cursor == 0 { + str_pt_1 = i.value + str_pt_2 = "" + cursor_rune = ' ' + } else { + str_pt_1 = i.value[:(len(i.value) + i.cursor)] + str_pt_2 = i.value[(len(i.value)+i.cursor)+1:] + cursor_rune = rune(i.value[len(i.value)+i.cursor]) + } + } else { + str_pt_1, str_pt_2, cursor_rune = "", "", ' ' + } + x, y := DrawStringAtPoint(str_pt_1, i.x+1, i.y+1, i.fg, i.bg) + termbox.SetCell(x, y, cursor_rune, i.bg, i.fg) + DrawStringAtPoint(str_pt_2, x+1, y, i.fg, i.bg) +} diff --git a/termbox_inputmodal.go b/termbox_inputmodal.go new file mode 100644 index 0000000..6aa80e4 --- /dev/null +++ b/termbox_inputmodal.go @@ -0,0 +1,134 @@ +package termbox_util + +import ( + "github.com/nsf/termbox-go" +) + +type InputModal struct { + title string + text string + value string + x, y, width, height int + show_help bool + cursor int + bg, fg termbox.Attribute +} + +func CreateInputModal(text string, x, y, width, height int, fg, bg termbox.Attribute) *InputModal { + i := InputModal{text: text, x: x, y: y, width: width, height: height, fg: fg, bg: bg} + return &i +} + +func (i *InputModal) GetTitle() string { return i.title } +func (i *InputModal) SetTitle(s string) *InputModal { + i.title = s + return i +} + +func (i *InputModal) GetText() string { return i.text } +func (i *InputModal) SetText(s string) *InputModal { + i.text = s + return i +} + +func (i *InputModal) GetValue() string { return i.value } +func (i *InputModal) SetValue(s string) *InputModal { + i.value = s + return i +} + +func (i *InputModal) GetX() int { return i.x } +func (i *InputModal) SetX(x int) *InputModal { + i.x = x + return i +} +func (i *InputModal) GetY() int { return i.y } +func (i *InputModal) SetY(y int) *InputModal { + i.y = y + return i +} + +func (i *InputModal) GetWidth() int { return i.width } +func (i *InputModal) SetWidth(width int) *InputModal { + i.width = width + return i +} + +func (i *InputModal) GetHeight() int { return i.height } +func (i *InputModal) SetHeight(height int) *InputModal { + i.height = height + return i +} + +func (i *InputModal) HelpIsShown() bool { return i.show_help } +func (i *InputModal) ShowHelp(b bool) *InputModal { + i.show_help = b + return i +} + +func (i *InputModal) GetCursorPos() int { return i.cursor } +func (i *InputModal) SetCursorPos(c int) *InputModal { + i.cursor = c + return i +} +func (i *InputModal) MoveCursorLeft() *InputModal { + if len(i.value)+(i.GetCursorPos()) > 0 { + i.cursor = i.GetCursorPos() - 1 + } + return i +} +func (i *InputModal) MoveCursorRight() *InputModal { + if i.GetCursorPos() < 0 { + i.cursor = i.GetCursorPos() + 1 + } + return i +} + +func (i *InputModal) GetBackground() termbox.Attribute { return i.bg } +func (i *InputModal) SetBackground(bg termbox.Attribute) *InputModal { + i.bg = bg + return i +} + +func (i *InputModal) GetForeground() termbox.Attribute { return i.fg } +func (i *InputModal) SetForeground(fg termbox.Attribute) *InputModal { + i.fg = fg + return i +} + +func (i *InputModal) HandleKeyPress(event termbox.Event) bool { + if event.Key == termbox.KeyEnter { + // Done editing + } else if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 { + i.value = i.value[:len(i.value)-1] + i.cursor -= 1 + } else { + i.value += string(event.Ch) + i.cursor += 1 + } + return true +} +func (i *InputModal) Draw() { + // First blank out the area we'll be putting the modal + FillWithChar(' ', i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg) + // Now draw the border + DrawBorder(i.x, i.y, i.x+i.width, i.y+i.height, i.fg, i.bg) + + DrawBorder(i.x+2, i.y+2, i.x+i.width-2, i.y+4, i.fg, i.bg) + // TODO: Output Cursor at appropriate spot + var output_string_1, output_string_2 string + var cursor_rune rune + if len(i.value) > 0 { + output_string_1 = i.value[:(len(i.value) - 1 + i.cursor)] + output_string_2 = i.value[(len(i.value) - 1 + i.cursor):] + cursor_rune = ' ' + } else { + output_string_1 = "" + output_string_2 = "" + cursor_rune = ' ' + } + + DrawStringAtPoint(output_string_1, i.x+3, i.y+3, i.fg, i.bg) + termbox.SetCell(i.x+len(output_string_1), i.y+3, cursor_rune, i.bg, i.fg) + DrawStringAtPoint(output_string_2, i.x+3+len(output_string_1)+1, i.y+3, i.fg, i.bg) +} diff --git a/termbox_util.go b/termbox_util.go new file mode 100644 index 0000000..3f6c25b --- /dev/null +++ b/termbox_util.go @@ -0,0 +1,57 @@ +package termbox_util + +import ( + "fmt" + "github.com/nsf/termbox-go" + "strings" +) + +type TextAlignment int + +const ( + ALIGN_LEFT = iota + ALIGN_CENTER + ALIGN_RIGHT +) + +/* Basic Output Helpers */ +func DrawStringAtPoint(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) (int, int) { + x_pos := x + for _, runeValue := range str { + termbox.SetCell(x_pos, y, runeValue, fg, bg) + x_pos++ + } + return x_pos, y +} + +func FillWithChar(r rune, x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute) { + for xx := x1; xx <= x2; xx++ { + for yx := y1; yx <= y2; yx++ { + termbox.SetCell(xx, yx, r, fg, bg) + } + } +} + +func DrawBorder(x1, y1, x2, y2 int, fg termbox.Attribute, bg termbox.Attribute) { + FillWithChar('|', x1, y1, x1, y2, fg, bg) + FillWithChar('|', x2, y1, x2, y2, fg, bg) + FillWithChar('-', x1, y1, x2, y1, fg, bg) + FillWithChar('-', x1, y2, x2, y2, fg, bg) +} + +func AlignText(txt string, width int, align TextAlignment) string { + num_spaces := width - len(txt) + switch align { + case ALIGN_CENTER: + return fmt.Sprintf("%s%s%s", + strings.Repeat(" ", num_spaces/2), + txt, strings.Repeat(" ", num_spaces/2), + ) + case ALIGN_RIGHT: + return fmt.Sprintf("%s%s", strings.Repeat(" ", num_spaces), txt) + default: + return fmt.Sprintf("%s%s", txt, strings.Repeat(" ", num_spaces)) + } +} + +/* More advanced things are in their respective files*/