mirror of
https://github.com/jroimartin/gocui.git
synced 2025-04-24 13:48:51 +08:00
Initial commit
This commit is contained in:
commit
58bbbb3d53
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.swp
|
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
||||
GOCUI - Go Console User Interface
|
||||
=================================
|
||||
|
||||
WIP
|
153
gui.go
Normal file
153
gui.go
Normal file
@ -0,0 +1,153 @@
|
||||
package gocui
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/jroimartin/termbox-go"
|
||||
)
|
||||
|
||||
var ErrorQuit = errors.New("quit")
|
||||
|
||||
const (
|
||||
RuneCornerTopLeft = '┌'
|
||||
RuneCornerTopRight = '┐'
|
||||
RuneCornerBottomLeft = '└'
|
||||
RuneCornerBottomRight = '┘'
|
||||
RuneEdgeVertical = '│'
|
||||
RuneEdgeHorizontal = '─'
|
||||
RuneIntersection = '┼'
|
||||
RuneIntersectionLeft = '├'
|
||||
RuneIntersectionRight = '┤'
|
||||
RuneIntersectionTop = '┬'
|
||||
RuneIntersectionBottom = '┴'
|
||||
RuneTriangleLeft = '◄'
|
||||
RuneTriangleRight = '►'
|
||||
RuneArrowLeft = '←'
|
||||
RuneArrowRight = '→'
|
||||
)
|
||||
|
||||
type Gui struct {
|
||||
events chan termbox.Event
|
||||
views []*View
|
||||
currentView *View
|
||||
}
|
||||
|
||||
func NewGui() (g *Gui) {
|
||||
return &Gui{}
|
||||
}
|
||||
|
||||
func (g *Gui) Init() (err error) {
|
||||
g.events = make(chan termbox.Event, 20)
|
||||
return termbox.Init()
|
||||
}
|
||||
|
||||
func (g *Gui) Close() {
|
||||
termbox.Close()
|
||||
}
|
||||
|
||||
func (g *Gui) Size() (x, y int) {
|
||||
return termbox.Size()
|
||||
}
|
||||
|
||||
func (g *Gui) AddView(x0, y0, x1, y1 int) (v *View, err error) {
|
||||
maxX, maxY := termbox.Size()
|
||||
|
||||
if x0 < 0 || y0 < 0 || x1 < 0 || y1 < 0 ||
|
||||
x0 > maxX || y0 > maxY || x1 > maxX || y1 > maxY {
|
||||
return nil, errors.New("Invalid coordinates")
|
||||
}
|
||||
v = NewView(x0, y0, x1, y1)
|
||||
g.views = append(g.views, v)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (g *Gui) MainLoop() (err error) {
|
||||
go func() {
|
||||
for {
|
||||
g.events <- termbox.PollEvent()
|
||||
}
|
||||
}()
|
||||
|
||||
if err := g.resize(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.draw(); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: Set initial cursor position
|
||||
//termbox.SetCursor(10, 10)
|
||||
termbox.Flush()
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev := <-g.events:
|
||||
if err := g.handleEvent(&ev); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.consumeevents(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.draw(); err != nil {
|
||||
return err
|
||||
}
|
||||
termbox.Flush()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Gui) consumeevents() (err error) {
|
||||
for {
|
||||
select {
|
||||
case ev := <-g.events:
|
||||
if err := g.handleEvent(&ev); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gui) handleEvent(ev *termbox.Event) (err error) {
|
||||
switch ev.Type {
|
||||
case termbox.EventKey:
|
||||
return g.onKey(ev)
|
||||
case termbox.EventResize:
|
||||
return g.resize()
|
||||
case termbox.EventError:
|
||||
return ev.Err
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Gui) draw() (err error) {
|
||||
for _, v := range g.views {
|
||||
if err := v.Draw(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (g *Gui) resize() (err error) {
|
||||
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
|
||||
for _, v := range g.views {
|
||||
if err := v.Resize(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (g *Gui) onKey(ev *termbox.Event) (err error) {
|
||||
switch ev.Key {
|
||||
case termbox.KeyCtrlC:
|
||||
return ErrorQuit
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
53
view.go
Normal file
53
view.go
Normal file
@ -0,0 +1,53 @@
|
||||
package gocui
|
||||
|
||||
import (
|
||||
"github.com/jroimartin/termbox-go"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
x0, y0, x1, y1 int
|
||||
cx, cy int
|
||||
BgColor, FgColor termbox.Attribute
|
||||
SelBgColor, SelFgColor termbox.Attribute
|
||||
}
|
||||
|
||||
func NewView(x0, y0, x1, y1 int) (v *View) {
|
||||
return &View{x0: x0, y0: y0, x1: x1, y1: y1,
|
||||
BgColor: termbox.ColorBlack, FgColor: termbox.ColorWhite,
|
||||
SelBgColor: termbox.ColorBlack, SelFgColor: termbox.ColorWhite}
|
||||
}
|
||||
|
||||
func (v *View) SetCell(x, y int, ch rune) {
|
||||
var bgColor, fgColor termbox.Attribute
|
||||
|
||||
if y == v.cy {
|
||||
bgColor = v.SelBgColor
|
||||
fgColor = v.SelFgColor
|
||||
} else {
|
||||
bgColor = v.BgColor
|
||||
fgColor = v.FgColor
|
||||
}
|
||||
termbox.SetCell(x, y, ch, fgColor, bgColor)
|
||||
}
|
||||
|
||||
func (v *View) Draw() (err error) {
|
||||
//maxX, maxY := termbox.Size()
|
||||
v.SetCell(v.x0, v.y0, RuneCornerTopLeft)
|
||||
v.SetCell(v.x1, v.y0, RuneCornerTopRight)
|
||||
v.SetCell(v.x0, v.y1, RuneCornerBottomLeft)
|
||||
v.SetCell(v.x1, v.y1, RuneCornerBottomRight)
|
||||
for x := v.x0 + 1; x < v.x1; x++ {
|
||||
v.SetCell(x, v.y0, RuneEdgeHorizontal)
|
||||
v.SetCell(x, v.y1, RuneEdgeHorizontal)
|
||||
}
|
||||
for y := v.y0 + 1; y < v.y1; y++ {
|
||||
v.SetCell(v.x0, y, RuneEdgeVertical)
|
||||
v.SetCell(v.x1, y, RuneEdgeVertical)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *View) Resize() (err error) {
|
||||
//TODO
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user