Rework events (again)

This commit is contained in:
Caleb Bassi 2018-11-28 18:19:34 -08:00
parent 4022fa43e0
commit ea15e228f4
17 changed files with 190 additions and 294 deletions

View File

@ -27,9 +27,11 @@ func main() {
ui.Render(bc) ui.Render(bc)
ui.Handle("q", "<Insert>", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -20,27 +20,20 @@ func main() {
} }
defer ui.Close() defer ui.Close()
p := ui.NewPar(":PRESS q TO QUIT DEMO") p := ui.NewPar("PRESS q TO QUIT DEMO")
p.Height = 3 p.Height = 3
p.Width = 50 p.Width = 50
p.TextFgColor = ui.ColorWhite p.TextFgColor = ui.ColorWhite
p.BorderLabel = "Text Box" p.BorderLabel = "Text Box"
p.BorderFg = ui.ColorCyan p.BorderFg = ui.ColorCyan
pTicker := time.NewTicker(time.Second) updateP := func(count int) {
pTickerCount := 1 if count%2 == 0 {
go func() { p.TextFgColor = ui.ColorRed
for { } else {
if pTickerCount%2 == 0 { p.TextFgColor = ui.ColorWhite
p.TextFgColor = ui.ColorRed
} else {
p.TextFgColor = ui.ColorWhite
}
pTickerCount++
<-pTicker.C
} }
}() }
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"} 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.Render(p, l, g, sls, lc, bc, lc2, p2)
} }
ui.Handle("q", func(ui.Event) { tickerCount := 1
ui.StopLoop() for {
}) select {
case e := <-ui.PollEvent():
drawTicker := time.NewTicker(time.Second) switch e.ID {
drawTickerCount := 1 case "q", "<C-c>":
go func() { return
for { }
draw(drawTickerCount) case <-time.NewTicker(time.Second).C:
updateP(tickerCount)
drawTickerCount++ draw(tickerCount)
<-drawTicker.C tickerCount++
} }
}() }
ui.Loop()
} }

View File

@ -74,9 +74,11 @@ func main() {
ui.Render(g0, g1, g2, g3, g4) ui.Render(g0, g1, g2, g3, g4)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -95,37 +95,31 @@ func main() {
ui.Render(ui.Body) ui.Render(ui.Body)
ui.Handle("q", func(ui.Event) { tickerCount := 1
ui.StopLoop() for {
}) select {
case e := <-ui.PollEvent():
drawTicker := time.NewTicker(time.Second) switch e.ID {
drawTickerCount := 1 case "q", "<C-c>":
go func() { return
for { case "<Resize>":
if drawTickerCount > 103 { payload := e.Payload.(ui.Resize)
ui.StopLoop() ui.Body.Width = payload.Width
ui.Body.Align()
ui.Clear()
ui.Render(ui.Body)
}
case <-time.NewTicker(time.Second).C:
if tickerCount > 103 {
return return
} }
for _, g := range gs { for _, g := range gs {
g.Percent = (g.Percent + 3) % 100 g.Percent = (g.Percent + 3) % 100
} }
sp.Lines[0].Data = spdata[:100+drawTickerCount] sp.Lines[0].Data = spdata[:100+tickerCount]
lc.Data["default"] = sinps[2*drawTickerCount:] lc.Data["default"] = sinps[2*tickerCount:]
ui.Render(ui.Body) ui.Render(ui.Body)
tickerCount++
drawTickerCount++
<-drawTicker.C
} }
}() }
ui.Handle("<Resize>", 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()
} }

View File

@ -66,9 +66,11 @@ func main() {
ui.Render(lc0, lc1, lc2) ui.Render(lc0, lc1, lc2)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -35,9 +35,11 @@ func main() {
ui.Render(ls) ui.Render(ls)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -44,10 +44,11 @@ func main() {
ui.Render(bc) ui.Render(bc)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -42,10 +42,11 @@ func main() {
ui.Render(par0, par1, par2, par3) ui.Render(par0, par1, par2, par3)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -40,21 +40,7 @@ func main() {
return fmt.Sprintf("%.02f", v) return fmt.Sprintf("%.02f", v)
} }
drawTicker := time.NewTicker(time.Second) pause := func() {
drawTickerCount := 1
go func() {
for {
if run {
pc.Data, pc.Offset = randomDataAndOffset()
ui.Render(pc)
}
drawTickerCount++
<-drawTicker.C
}
}()
ui.Handle("s", func(ui.Event) {
run = !run run = !run
if run { if run {
pc.BorderLabel = "Pie Chart" pc.BorderLabel = "Pie Chart"
@ -62,13 +48,24 @@ func main() {
pc.BorderLabel = "Pie Chart (Stopped)" pc.BorderLabel = "Pie Chart (Stopped)"
} }
ui.Render(pc) ui.Render(pc)
}) }
ui.Handle("q", func(ui.Event) {
ui.StopLoop()
})
ui.Render(pc) ui.Render(pc)
ui.Loop() for {
select {
case e := <-ui.PollEvent():
switch e.ID {
case "q", "<C-c>":
return
case "s":
pause()
}
case <-time.NewTicker(time.Second).C:
if run {
pc.Data, pc.Offset = randomDataAndOffset()
ui.Render(pc)
}
}
}
} }

View File

@ -59,9 +59,11 @@ func main() {
ui.Render(spls0, spls1, spls2) ui.Render(spls0, spls1, spls2)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -53,9 +53,11 @@ func main() {
ui.Render(table2) ui.Render(table2)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

View File

@ -18,14 +18,14 @@ func main() {
} }
defer ui.Close() 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.Height = 1
header.Width = 50 header.Width = 50
header.Border = false header.Border = false
header.TextBgColor = ui.ColorBlue header.TextBgColor = ui.ColorBlue
tab1 := extra.NewTab("pierwszy") 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.Height = 5
par2.Width = 37 par2.Width = 37
par2.Y = 0 par2.Y = 0
@ -61,21 +61,19 @@ func main() {
ui.Render(header, tabpane) ui.Render(header, tabpane)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Handle("j", func(ui.Event) { return
tabpane.SetActiveLeft() case "h":
ui.Clear() tabpane.SetActiveLeft()
ui.Render(header, tabpane) ui.Clear()
}) ui.Render(header, tabpane)
case "l":
ui.Handle("k", func(ui.Event) { tabpane.SetActiveRight()
tabpane.SetActiveRight() ui.Clear()
ui.Clear() ui.Render(header, tabpane)
ui.Render(header, tabpane) }
}) }
ui.Loop()
} }

View File

@ -138,20 +138,17 @@ func main() {
ui.Render(p, list, g, sp, lc, bc, lc1, p1) ui.Render(p, list, g, sp, lc, bc, lc1, p1)
ui.Handle("q", func(ui.Event) { tickerCount := 1
ui.StopLoop() for {
}) select {
case e := <-ui.PollEvent():
drawTicker := time.NewTicker(time.Second) switch e.ID {
drawTickerCount := 1 case "q", "<C-c>":
go func() { return
for { }
draw(drawTickerCount) case <-time.NewTicker(time.Second).C:
draw(tickerCount)
drawTickerCount++ tickerCount++
<-drawTicker.C
} }
}() }
ui.Loop()
} }

View File

@ -284,7 +284,7 @@ func main() {
termWidth := 70 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.Height = 1
header.Width = 50 header.Width = 50
header.Border = false header.Border = false
@ -334,24 +334,21 @@ func main() {
ui.Render(header, tabpane) ui.Render(header, tabpane)
ui.Handle("q", func(ui.Event) { tickerCount := 1
ui.StopLoop() for {
}) select {
case e := <-ui.PollEvent():
ui.Handle("j", func(ui.Event) { switch e.ID {
tabpane.SetActiveLeft() case "q", "<C-c>":
ui.Render(header, tabpane) return
}) case "h":
tabpane.SetActiveLeft()
ui.Handle("k", func(ui.Event) { ui.Render(header, tabpane)
tabpane.SetActiveRight() case "l":
ui.Render(header, tabpane) tabpane.SetActiveRight()
}) ui.Render(header, tabpane)
}
drawTicker := time.NewTicker(time.Second) case <-time.NewTicker(time.Second).C:
drawTickerCount := 1
go func() {
for {
cs, errcs := getCpusStatsMap() cs, errcs := getCpusStatsMap()
if errcs != nil { if errcs != nil {
panic(errcs) panic(errcs)
@ -365,11 +362,7 @@ func main() {
} }
memTabElems.Update(ms) memTabElems.Update(ms)
ui.Render(header, tabpane) ui.Render(header, tabpane)
tickerCount++
drawTickerCount++
<-drawTicker.C
} }
}() }
ui.Loop()
} }

View File

@ -24,13 +24,14 @@ func main() {
p.TextFgColor = ui.ColorWhite p.TextFgColor = ui.ColorWhite
p.BorderLabel = "Text Box with Wrapping" p.BorderLabel = "Text Box with Wrapping"
p.BorderFg = ui.ColorCyan p.BorderFg = ui.ColorCyan
//p.Border = false
ui.Render(p) ui.Render(p)
ui.Handle("q", func(ui.Event) { for {
ui.StopLoop() e := <-ui.PollEvent()
}) switch e.ID {
case "q", "<C-c>":
ui.Loop() return
}
}
} }

118
events.go
View File

@ -6,13 +6,12 @@ package termui
import ( import (
"strconv" "strconv"
"sync"
tb "github.com/nsf/termbox-go" tb "github.com/nsf/termbox-go"
) )
/* /*
Here's the list of events which can be assigned handlers using Handle(): List of events:
mouse events: mouse events:
<MouseLeft> <MouseRight> <MouseMiddle> <MouseLeft> <MouseRight> <MouseMiddle>
<MouseWheelUp> <MouseWheelDown> <MouseWheelUp> <MouseWheelDown>
@ -26,9 +25,6 @@ Here's the list of events which can be assigned handlers using Handle():
<C-<Space>> etc <C-<Space>> etc
terminal events: terminal events:
<Resize> <Resize>
meta events:
<Keyboard>
<Mouse>
*/ */
type EventType int type EventType int
@ -39,22 +35,6 @@ const (
ResizeEvent 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 Event struct {
Type EventType Type EventType
ID string ID string
@ -74,74 +54,15 @@ type Resize struct {
Height int Height int
} }
// handleEvent calls the approriate callback function if there is one. var pollingChannels [](chan Event)
func handleEvent(e Event) {
if val, ok := defaultES.handlers[e.ID]; ok {
val(e)
}
switch e.Type {
case KeyboardEvent:
if val, ok := defaultES.handlers["<Keyboard>"]; ok {
val(e)
}
case MouseEvent:
if val, ok := defaultES.handlers["<Mouse>"]; ok {
val(e)
}
}
}
// Loop gets events from termbox and passes them off to handleEvent. // PollEvent gets events from termbox, converts them, then sends them to each of its channels.
// Stops when StopLoop is called. func PollEvent() <-chan Event {
func Loop() { ch := make(chan Event)
go func() { go func() {
for { ch <- convertTermboxEvent(tb.PollEvent())
defaultES.eventQueue <- tb.PollEvent()
}
}() }()
return ch
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()
} }
// convertTermboxKeyboardEvent converts a termbox keyboard event to a more friendly string format. // 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) panic(e.Err)
} }
var event Event
switch e.Type { switch e.Type {
case tb.EventKey: case tb.EventKey:
return convertTermboxKeyboardEvent(e) event = convertTermboxKeyboardEvent(e)
case tb.EventMouse: case tb.EventMouse:
return convertTermboxMouseEvent(e) event = convertTermboxMouseEvent(e)
case tb.EventResize: case tb.EventResize:
return Event{ event = Event{
Type: ResizeEvent, Type: ResizeEvent,
ID: "<Resize>", ID: "<Resize>",
Payload: Resize{ Payload: Resize{
@ -248,20 +171,5 @@ func convertTermboxEvent(e tb.Event) Event {
} }
} }
return 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()
} }

View File

@ -38,13 +38,16 @@ func Init() error {
Body.BgColor = ThemeAttr("bg") Body.BgColor = ThemeAttr("bg")
Body.Width = TermWidth() Body.Width = TermWidth()
Handle("<Resize>", func(e Event) { // resizeCh := Handle("<Resize>")
payload := e.Payload.(Resize) // go func() {
Body.Width = payload.Width // for e := range resizeCh {
}) // payload := e.Payload.(Resize)
// Body.Width = payload.Width
// }
// }()
DefaultWgtMgr = NewWgtMgr() // DefaultWgtMgr = NewWgtMgr()
EventHook(DefaultWgtMgr.WgtHandlersHook()) // EventHook(DefaultWgtMgr.WgtHandlersHook())
go func() { go func() {
for bs := range renderJobs { for bs := range renderJobs {