aerc/lib/ui/ui.go
Jeffas 3b09c07e7a Add clickable tabs
This introduces a new interface `Clickable`. I'd imagine this would be
implemented for most widgets eventually and would allow for programs run
in the terminal to also have their mouse events forwarded to them.

For the tabs it was relatively simple to check that the position of the
click is within the boxes for the tabs. For other components I'd imagine
that some state representing their currently drawn bounding box would be
useful.
2019-07-11 19:45:53 -04:00

100 lines
1.7 KiB
Go

package ui
import (
"sync/atomic"
"github.com/gdamore/tcell"
"git.sr.ht/~sircmpwn/aerc/config"
)
type UI struct {
Content DrawableInteractive
exit atomic.Value // bool
ctx *Context
screen tcell.Screen
tcEvents chan tcell.Event
invalid int32 // access via atomic
}
func Initialize(conf *config.AercConfig,
content DrawableInteractive) (*UI, error) {
screen, err := tcell.NewScreen()
if err != nil {
return nil, err
}
if err = screen.Init(); err != nil {
return nil, err
}
screen.Clear()
screen.HideCursor()
screen.EnableMouse()
width, height := screen.Size()
state := UI{
Content: content,
ctx: NewContext(width, height, screen),
screen: screen,
tcEvents: make(chan tcell.Event, 10),
}
state.exit.Store(false)
go func() {
for !state.ShouldExit() {
state.tcEvents <- screen.PollEvent()
}
}()
state.invalid = 1
content.OnInvalidate(func(_ Drawable) {
atomic.StoreInt32(&state.invalid, 1)
})
content.Focus(true)
return &state, nil
}
func (state *UI) ShouldExit() bool {
return state.exit.Load().(bool)
}
func (state *UI) Exit() {
state.exit.Store(true)
}
func (state *UI) Close() {
state.screen.Fini()
}
func (state *UI) Tick() bool {
more := false
select {
case event := <-state.tcEvents:
switch event := event.(type) {
case *tcell.EventResize:
state.screen.Clear()
width, height := event.Size()
state.ctx = NewContext(width, height, state.screen)
state.Content.Invalidate()
}
state.Content.Event(event)
more = true
default:
}
wasInvalid := atomic.SwapInt32(&state.invalid, 0)
if wasInvalid != 0 {
state.Content.Draw(state.ctx)
state.screen.Show()
more = true
}
return more
}