commit 58bbbb3d5360411b4d82ccf8b7655261a3b4b05e Author: Roi Martin (@nibble_ds) Date: Fri Dec 27 21:36:26 2013 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..35ed57a --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +GOCUI - Go Console User Interface +================================= + +WIP diff --git a/gui.go b/gui.go new file mode 100644 index 0000000..58e4ae2 --- /dev/null +++ b/gui.go @@ -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 + } + +} diff --git a/view.go b/view.go new file mode 100644 index 0000000..e403bee --- /dev/null +++ b/view.go @@ -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 +}