Handle events before executing queued updates
This commit is contained in:
parent
fa31102abf
commit
79a35fe4de
|
@ -1,3 +1,6 @@
|
|||
v1.5.2 (WIP)
|
||||
- Handle events before executing queued updates
|
||||
|
||||
v1.5.1 (2020-11-05)
|
||||
- Add FocusManager
|
||||
- Add Slider
|
||||
|
|
9
FORK.md
9
FORK.md
|
@ -28,11 +28,10 @@ maintainers and allowing code changes which may be outside of tview's scope.
|
|||
|
||||
## Primitive methods do not return the primitive they belong to
|
||||
|
||||
When chaining multiple method calls on a primitive together, application
|
||||
developers might accidentally end the chain with a different return type than
|
||||
the first method call. This could result in unexpected return types. For
|
||||
example, ending a chain with `SetTitle` would result in a `Box` rather than the
|
||||
original primitive.
|
||||
When chaining multiple primitive method calls together, application developers
|
||||
might accidentally end the chain with a different return type than the first
|
||||
method call. This could result in unexpected return types. For example, ending
|
||||
a chain with `SetTitle` would result in a `Box` rather than the original primitive.
|
||||
|
||||
## cview is [thread-safe](https://docs.rocketnine.space/gitlab.com/tslocum/cview/#hdr-Concurrency)
|
||||
|
||||
|
|
174
application.go
174
application.go
|
@ -354,97 +354,109 @@ func (a *Application) Run() error {
|
|||
}
|
||||
}()
|
||||
|
||||
handle := func(event interface{}) {
|
||||
a.RLock()
|
||||
p := a.focus
|
||||
inputCapture := a.inputCapture
|
||||
screen := a.screen
|
||||
a.RUnlock()
|
||||
|
||||
switch event := event.(type) {
|
||||
case *tcell.EventKey:
|
||||
// Intercept keys.
|
||||
if inputCapture != nil {
|
||||
event = inputCapture(event)
|
||||
if event == nil {
|
||||
a.draw()
|
||||
return // Don't forward event.
|
||||
}
|
||||
}
|
||||
|
||||
// Ctrl-C closes the application.
|
||||
if event.Key() == tcell.KeyCtrlC {
|
||||
a.Stop()
|
||||
return
|
||||
}
|
||||
|
||||
// Pass other key events to the currently focused primitive.
|
||||
if p != nil {
|
||||
if handler := p.InputHandler(); handler != nil {
|
||||
handler(event, func(p Primitive) {
|
||||
a.SetFocus(p)
|
||||
})
|
||||
a.draw()
|
||||
}
|
||||
}
|
||||
case *tcell.EventResize:
|
||||
// Throttle resize events.
|
||||
if time.Since(a.lastResize) < resizeEventThrottle {
|
||||
// Stop timer
|
||||
if a.throttleResize != nil && !a.throttleResize.Stop() {
|
||||
select {
|
||||
case <-a.throttleResize.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
event := event // Capture
|
||||
|
||||
// Start timer
|
||||
a.throttleResize = time.AfterFunc(resizeEventThrottle, func() {
|
||||
a.events <- event
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
a.lastResize = time.Now()
|
||||
|
||||
if screen == nil {
|
||||
return
|
||||
}
|
||||
|
||||
screen.Clear()
|
||||
a.width, a.height = event.Size()
|
||||
|
||||
// Call afterResize handler if there is one.
|
||||
if a.afterResize != nil {
|
||||
a.afterResize(a.width, a.height)
|
||||
}
|
||||
|
||||
a.draw()
|
||||
case *tcell.EventMouse:
|
||||
consumed, isMouseDownAction := a.fireMouseActions(event)
|
||||
if consumed {
|
||||
a.draw()
|
||||
}
|
||||
a.lastMouseButtons = event.Buttons()
|
||||
if isMouseDownAction {
|
||||
a.mouseDownX, a.mouseDownY = event.Position()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start event loop.
|
||||
EventLoop:
|
||||
for {
|
||||
// Handle events before executing updates
|
||||
select {
|
||||
case event := <-a.events:
|
||||
if event == nil {
|
||||
break EventLoop
|
||||
}
|
||||
handle(event)
|
||||
continue
|
||||
default:
|
||||
}
|
||||
|
||||
a.RLock()
|
||||
p := a.focus
|
||||
inputCapture := a.inputCapture
|
||||
screen := a.screen
|
||||
a.RUnlock()
|
||||
|
||||
switch event := event.(type) {
|
||||
case *tcell.EventKey:
|
||||
// Intercept keys.
|
||||
if inputCapture != nil {
|
||||
event = inputCapture(event)
|
||||
if event == nil {
|
||||
a.draw()
|
||||
continue // Don't forward event.
|
||||
}
|
||||
}
|
||||
|
||||
// Ctrl-C closes the application.
|
||||
if event.Key() == tcell.KeyCtrlC {
|
||||
a.Stop()
|
||||
continue
|
||||
}
|
||||
|
||||
// Pass other key events to the currently focused primitive.
|
||||
if p != nil {
|
||||
if handler := p.InputHandler(); handler != nil {
|
||||
handler(event, func(p Primitive) {
|
||||
a.SetFocus(p)
|
||||
})
|
||||
a.draw()
|
||||
}
|
||||
}
|
||||
case *tcell.EventResize:
|
||||
// Throttle resize events.
|
||||
if time.Since(a.lastResize) < resizeEventThrottle {
|
||||
// Stop timer
|
||||
if a.throttleResize != nil && !a.throttleResize.Stop() {
|
||||
select {
|
||||
case <-a.throttleResize.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
event := event // Capture
|
||||
|
||||
// Start timer
|
||||
a.throttleResize = time.AfterFunc(resizeEventThrottle, func() {
|
||||
a.events <- event
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
a.lastResize = time.Now()
|
||||
|
||||
if screen == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
screen.Clear()
|
||||
a.width, a.height = event.Size()
|
||||
|
||||
// Call afterResize handler if there is one.
|
||||
if a.afterResize != nil {
|
||||
a.afterResize(a.width, a.height)
|
||||
}
|
||||
|
||||
a.draw()
|
||||
case *tcell.EventMouse:
|
||||
consumed, isMouseDownAction := a.fireMouseActions(event)
|
||||
if consumed {
|
||||
a.draw()
|
||||
}
|
||||
a.lastMouseButtons = event.Buttons()
|
||||
if isMouseDownAction {
|
||||
a.mouseDownX, a.mouseDownY = event.Position()
|
||||
}
|
||||
select {
|
||||
case event := <-a.events:
|
||||
if event == nil {
|
||||
break EventLoop
|
||||
}
|
||||
|
||||
// If we have updates, now is the time to execute them.
|
||||
case updater := <-a.updates:
|
||||
updater()
|
||||
handle(event)
|
||||
case update := <-a.updates:
|
||||
update()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue