diff --git a/_examples/barchart.go b/_examples/barchart.go index 7b1f900..7d8f8e3 100644 --- a/_examples/barchart.go +++ b/_examples/barchart.go @@ -27,9 +27,11 @@ func main() { ui.Render(bc) - ui.Handle("q", "", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/dashboard.go b/_examples/dashboard.go index 8a2aac3..15ec065 100644 --- a/_examples/dashboard.go +++ b/_examples/dashboard.go @@ -20,27 +20,20 @@ func main() { } defer ui.Close() - p := ui.NewPar(":PRESS q TO QUIT DEMO") + p := ui.NewPar("PRESS q TO QUIT DEMO") p.Height = 3 p.Width = 50 p.TextFgColor = ui.ColorWhite p.BorderLabel = "Text Box" p.BorderFg = ui.ColorCyan - pTicker := time.NewTicker(time.Second) - pTickerCount := 1 - go func() { - for { - if pTickerCount%2 == 0 { - p.TextFgColor = ui.ColorRed - } else { - p.TextFgColor = ui.ColorWhite - } - - pTickerCount++ - <-pTicker.C + updateP := func(count int) { + if count%2 == 0 { + p.TextFgColor = ui.ColorRed + } else { + p.TextFgColor = ui.ColorWhite } - }() + } listData := []string{"[0] gizak/termui", "[1] editbox.go", "[2] interrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"} @@ -147,20 +140,18 @@ func main() { ui.Render(p, l, g, sls, lc, bc, lc2, p2) } - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - drawTicker := time.NewTicker(time.Second) - drawTickerCount := 1 - go func() { - for { - draw(drawTickerCount) - - drawTickerCount++ - <-drawTicker.C + tickerCount := 1 + for { + select { + case e := <-ui.PollEvent(): + switch e.ID { + case "q", "": + return + } + case <-time.NewTicker(time.Second).C: + updateP(tickerCount) + draw(tickerCount) + tickerCount++ } - }() - - ui.Loop() + } } diff --git a/_examples/gauge.go b/_examples/gauge.go index 64bb5ea..6983ffe 100644 --- a/_examples/gauge.go +++ b/_examples/gauge.go @@ -74,9 +74,11 @@ func main() { ui.Render(g0, g1, g2, g3, g4) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/grid.go b/_examples/grid.go index ab1fa1e..e45df1b 100644 --- a/_examples/grid.go +++ b/_examples/grid.go @@ -95,37 +95,31 @@ func main() { ui.Render(ui.Body) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - drawTicker := time.NewTicker(time.Second) - drawTickerCount := 1 - go func() { - for { - if drawTickerCount > 103 { - ui.StopLoop() + tickerCount := 1 + for { + select { + case e := <-ui.PollEvent(): + switch e.ID { + case "q", "": + return + case "": + payload := e.Payload.(ui.Resize) + ui.Body.Width = payload.Width + ui.Body.Align() + ui.Clear() + ui.Render(ui.Body) + } + case <-time.NewTicker(time.Second).C: + if tickerCount > 103 { return } for _, g := range gs { g.Percent = (g.Percent + 3) % 100 } - sp.Lines[0].Data = spdata[:100+drawTickerCount] - lc.Data["default"] = sinps[2*drawTickerCount:] + sp.Lines[0].Data = spdata[:100+tickerCount] + lc.Data["default"] = sinps[2*tickerCount:] ui.Render(ui.Body) - - drawTickerCount++ - <-drawTicker.C + tickerCount++ } - }() - - ui.Handle("", func(e ui.Event) { - payload := e.Payload.(ui.Resize) - ui.Body.Width = payload.Width - ui.Body.Align() - ui.Clear() - ui.Render(ui.Body) - }) - - ui.Loop() + } } diff --git a/_examples/linechart.go b/_examples/linechart.go index 806c42d..ead1800 100644 --- a/_examples/linechart.go +++ b/_examples/linechart.go @@ -66,9 +66,11 @@ func main() { ui.Render(lc0, lc1, lc2) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/list.go b/_examples/list.go index 808d290..544ec9e 100644 --- a/_examples/list.go +++ b/_examples/list.go @@ -35,9 +35,11 @@ func main() { ui.Render(ls) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/mbarchart.go b/_examples/mbarchart.go index 8388099..63ed11e 100644 --- a/_examples/mbarchart.go +++ b/_examples/mbarchart.go @@ -44,10 +44,11 @@ func main() { ui.Render(bc) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() - + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/par.go b/_examples/par.go index c68196b..70c3021 100644 --- a/_examples/par.go +++ b/_examples/par.go @@ -42,10 +42,11 @@ func main() { ui.Render(par0, par1, par2, par3) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() - + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/piechart.go b/_examples/piechart.go index ae870f4..fa18af2 100644 --- a/_examples/piechart.go +++ b/_examples/piechart.go @@ -40,21 +40,7 @@ func main() { return fmt.Sprintf("%.02f", v) } - drawTicker := time.NewTicker(time.Second) - drawTickerCount := 1 - go func() { - for { - if run { - pc.Data, pc.Offset = randomDataAndOffset() - ui.Render(pc) - } - - drawTickerCount++ - <-drawTicker.C - } - }() - - ui.Handle("s", func(ui.Event) { + pause := func() { run = !run if run { pc.BorderLabel = "Pie Chart" @@ -62,13 +48,24 @@ func main() { pc.BorderLabel = "Pie Chart (Stopped)" } ui.Render(pc) - }) - - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) + } ui.Render(pc) - ui.Loop() + for { + select { + case e := <-ui.PollEvent(): + switch e.ID { + case "q", "": + return + case "s": + pause() + } + case <-time.NewTicker(time.Second).C: + if run { + pc.Data, pc.Offset = randomDataAndOffset() + ui.Render(pc) + } + } + } } diff --git a/_examples/sparklines.go b/_examples/sparklines.go index 0c0c578..b806085 100644 --- a/_examples/sparklines.go +++ b/_examples/sparklines.go @@ -59,9 +59,11 @@ func main() { ui.Render(spls0, spls1, spls2) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/table.go b/_examples/table.go index 59679df..bdef09a 100644 --- a/_examples/table.go +++ b/_examples/table.go @@ -53,9 +53,11 @@ func main() { ui.Render(table2) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/_examples/tabs.go b/_examples/tabs.go index 3e68e22..ec693e5 100644 --- a/_examples/tabs.go +++ b/_examples/tabs.go @@ -18,14 +18,14 @@ func main() { } defer ui.Close() - header := ui.NewPar("Press q to quit, Press j or k to switch tabs") + header := ui.NewPar("Press q to quit, Press h or l to switch tabs") header.Height = 1 header.Width = 50 header.Border = false header.TextBgColor = ui.ColorBlue tab1 := extra.NewTab("pierwszy") - par2 := ui.NewPar("Press q to quit\nPress j or k to switch tabs\n") + par2 := ui.NewPar("Press q to quit\nPress h or l to switch tabs\n") par2.Height = 5 par2.Width = 37 par2.Y = 0 @@ -61,21 +61,19 @@ func main() { ui.Render(header, tabpane) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Handle("j", func(ui.Event) { - tabpane.SetActiveLeft() - ui.Clear() - ui.Render(header, tabpane) - }) - - ui.Handle("k", func(ui.Event) { - tabpane.SetActiveRight() - ui.Clear() - ui.Render(header, tabpane) - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + case "h": + tabpane.SetActiveLeft() + ui.Clear() + ui.Render(header, tabpane) + case "l": + tabpane.SetActiveRight() + ui.Clear() + ui.Render(header, tabpane) + } + } } diff --git a/_examples/theme.go b/_examples/theme.go index 8c02edb..4253b8b 100644 --- a/_examples/theme.go +++ b/_examples/theme.go @@ -138,20 +138,17 @@ func main() { ui.Render(p, list, g, sp, lc, bc, lc1, p1) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - drawTicker := time.NewTicker(time.Second) - drawTickerCount := 1 - go func() { - for { - draw(drawTickerCount) - - drawTickerCount++ - <-drawTicker.C + tickerCount := 1 + for { + select { + case e := <-ui.PollEvent(): + switch e.ID { + case "q", "": + return + } + case <-time.NewTicker(time.Second).C: + draw(tickerCount) + tickerCount++ } - }() - - ui.Loop() + } } diff --git a/_examples/ttop.go b/_examples/ttop.go index 3440651..a5d99b8 100644 --- a/_examples/ttop.go +++ b/_examples/ttop.go @@ -284,7 +284,7 @@ func main() { termWidth := 70 - header := ui.NewPar("Press q to quit, Press j or k to switch tabs") + header := ui.NewPar("Press q to quit, Press h or l to switch tabs") header.Height = 1 header.Width = 50 header.Border = false @@ -334,24 +334,21 @@ func main() { ui.Render(header, tabpane) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Handle("j", func(ui.Event) { - tabpane.SetActiveLeft() - ui.Render(header, tabpane) - }) - - ui.Handle("k", func(ui.Event) { - tabpane.SetActiveRight() - ui.Render(header, tabpane) - }) - - drawTicker := time.NewTicker(time.Second) - drawTickerCount := 1 - go func() { - for { + tickerCount := 1 + for { + select { + case e := <-ui.PollEvent(): + switch e.ID { + case "q", "": + return + case "h": + tabpane.SetActiveLeft() + ui.Render(header, tabpane) + case "l": + tabpane.SetActiveRight() + ui.Render(header, tabpane) + } + case <-time.NewTicker(time.Second).C: cs, errcs := getCpusStatsMap() if errcs != nil { panic(errcs) @@ -365,11 +362,7 @@ func main() { } memTabElems.Update(ms) ui.Render(header, tabpane) - - drawTickerCount++ - <-drawTicker.C + tickerCount++ } - }() - - ui.Loop() + } } diff --git a/_examples/wrapper.go b/_examples/wrapper.go index 40158cb..ed15f61 100644 --- a/_examples/wrapper.go +++ b/_examples/wrapper.go @@ -24,13 +24,14 @@ func main() { p.TextFgColor = ui.ColorWhite p.BorderLabel = "Text Box with Wrapping" p.BorderFg = ui.ColorCyan - //p.Border = false ui.Render(p) - ui.Handle("q", func(ui.Event) { - ui.StopLoop() - }) - - ui.Loop() + for { + e := <-ui.PollEvent() + switch e.ID { + case "q", "": + return + } + } } diff --git a/events.go b/events.go index 9806e0f..87d1816 100644 --- a/events.go +++ b/events.go @@ -6,13 +6,12 @@ package termui import ( "strconv" - "sync" tb "github.com/nsf/termbox-go" ) /* -Here's the list of events which can be assigned handlers using Handle(): +List of events: mouse events: @@ -26,9 +25,6 @@ Here's the list of events which can be assigned handlers using Handle(): > etc terminal events: - meta events: - - */ type EventType int @@ -39,22 +35,6 @@ const ( ResizeEvent ) -type eventStream struct { - sync.RWMutex - handlers map[string]func(Event) - stopLoop chan bool - eventQueue chan tb.Event // list of events from termbox - hook func(Event) -} - -var defaultES = eventStream{ - handlers: make(map[string]func(Event)), - stopLoop: make(chan bool, 1), - eventQueue: make(chan tb.Event), - hook: DefaultHandler, -} - -// Event contains an ID used for Handle() and an optional payload. type Event struct { Type EventType ID string @@ -74,74 +54,15 @@ type Resize struct { Height int } -// handleEvent calls the approriate callback function if there is one. -func handleEvent(e Event) { - if val, ok := defaultES.handlers[e.ID]; ok { - val(e) - } - switch e.Type { - case KeyboardEvent: - if val, ok := defaultES.handlers[""]; ok { - val(e) - } - case MouseEvent: - if val, ok := defaultES.handlers[""]; ok { - val(e) - } - } -} +var pollingChannels [](chan Event) -// Loop gets events from termbox and passes them off to handleEvent. -// Stops when StopLoop is called. -func Loop() { +// PollEvent gets events from termbox, converts them, then sends them to each of its channels. +func PollEvent() <-chan Event { + ch := make(chan Event) go func() { - for { - defaultES.eventQueue <- tb.PollEvent() - } + ch <- convertTermboxEvent(tb.PollEvent()) }() - - for { - select { - case <-defaultES.stopLoop: - return - case e := <-defaultES.eventQueue: - ne := convertTermboxEvent(e) - defaultES.RLock() - handleEvent(ne) - defaultES.hook(ne) - defaultES.RUnlock() - } - } -} - -// StopLoop stops the event loop. -func StopLoop() { - defaultES.stopLoop <- true -} - -// Handle assigns event names to their handlers. Takes a string, strings, or a slice of strings, and a function. -func Handle(things ...interface{}) { - function := things[len(things)-1].(func(Event)) - for _, thing := range things { - if value, ok := thing.(string); ok { - defaultES.Lock() - defaultES.handlers[value] = function - defaultES.Unlock() - } - if value, ok := thing.([]string); ok { - defaultES.Lock() - for _, name := range value { - defaultES.handlers[name] = function - } - defaultES.Unlock() - } - } -} - -func EventHook(f func(Event)) { - defaultES.Lock() - defaultES.hook = f - defaultES.Unlock() + return ch } // convertTermboxKeyboardEvent converts a termbox keyboard event to a more friendly string format. @@ -232,13 +153,15 @@ func convertTermboxEvent(e tb.Event) Event { panic(e.Err) } + var event Event + switch e.Type { case tb.EventKey: - return convertTermboxKeyboardEvent(e) + event = convertTermboxKeyboardEvent(e) case tb.EventMouse: - return convertTermboxMouseEvent(e) + event = convertTermboxMouseEvent(e) case tb.EventResize: - return Event{ + event = Event{ Type: ResizeEvent, ID: "", Payload: Resize{ @@ -248,20 +171,5 @@ func convertTermboxEvent(e tb.Event) Event { } } - return Event{} -} - -var DefaultHandler = func(e Event) { -} - -func ResetHandlers() { - defaultES.Lock() - defaultES.handlers = make(map[string]func(Event)) - defaultES.Unlock() -} - -func ResetHandler(handle string) { - defaultES.Lock() - delete(defaultES.handlers, handle) - defaultES.Unlock() + return event } diff --git a/render.go b/render.go index 99f34bb..6847253 100644 --- a/render.go +++ b/render.go @@ -38,13 +38,16 @@ func Init() error { Body.BgColor = ThemeAttr("bg") Body.Width = TermWidth() - Handle("", func(e Event) { - payload := e.Payload.(Resize) - Body.Width = payload.Width - }) + // resizeCh := Handle("") + // go func() { + // for e := range resizeCh { + // payload := e.Payload.(Resize) + // Body.Width = payload.Width + // } + // }() - DefaultWgtMgr = NewWgtMgr() - EventHook(DefaultWgtMgr.WgtHandlersHook()) + // DefaultWgtMgr = NewWgtMgr() + // EventHook(DefaultWgtMgr.WgtHandlersHook()) go func() { for bs := range renderJobs {