Make termbox event loop async
This commit is contained in:
parent
db1b2cd53f
commit
77a0f68758
5 changed files with 126 additions and 18 deletions
|
@ -14,6 +14,11 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
_ui, err := ui.Initialize(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer _ui.Close()
|
||||||
var workers []worker.Worker
|
var workers []worker.Worker
|
||||||
for _, account := range conf.Accounts {
|
for _, account := range conf.Accounts {
|
||||||
work, err := worker.NewWorker(account.Source)
|
work, err := worker.NewWorker(account.Source)
|
||||||
|
@ -23,12 +28,8 @@ func main() {
|
||||||
go work.Run()
|
go work.Run()
|
||||||
work.PostAction(types.Configure{Config: account})
|
work.PostAction(types.Configure{Config: account})
|
||||||
workers = append(workers, work)
|
workers = append(workers, work)
|
||||||
|
_ui.AddTab(ui.NewAccountTab(&account, &work))
|
||||||
}
|
}
|
||||||
_ui, err := ui.Initialize(conf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer _ui.Close()
|
|
||||||
for !_ui.Exit {
|
for !_ui.Exit {
|
||||||
activity := false
|
activity := false
|
||||||
for _, worker := range workers {
|
for _, worker := range workers {
|
||||||
|
|
41
ui/account.go
Normal file
41
ui/account.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
tb "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
"git.sr.ht/~sircmpwn/aerc2/config"
|
||||||
|
"git.sr.ht/~sircmpwn/aerc2/worker"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountTab struct {
|
||||||
|
Config *config.AccountConfig
|
||||||
|
Worker *worker.Worker
|
||||||
|
Parent *UIState
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccountTab(conf *config.AccountConfig, work *worker.Worker) *AccountTab {
|
||||||
|
return &AccountTab{
|
||||||
|
Config: conf,
|
||||||
|
Worker: work,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acc *AccountTab) Name() string {
|
||||||
|
return acc.Config.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acc *AccountTab) Invalid() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acc *AccountTab) SetParent(parent *UIState) {
|
||||||
|
acc.Parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (acc *AccountTab) Render(at Geometry) {
|
||||||
|
cell := tb.Cell{
|
||||||
|
Fg: tb.ColorDefault,
|
||||||
|
Bg: tb.ColorDefault,
|
||||||
|
}
|
||||||
|
TPrintf(&at, cell, "%s", acc.Name())
|
||||||
|
}
|
21
ui/helpers.go
Normal file
21
ui/helpers.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
tb "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TPrintf(geo *Geometry, ref tb.Cell, format string, a ...interface{}) {
|
||||||
|
str := fmt.Sprintf(format, a...)
|
||||||
|
_geo := *geo
|
||||||
|
for _, ch := range str {
|
||||||
|
tb.SetCell(geo.Col, geo.Row, ch, ref.Fg, ref.Bg)
|
||||||
|
geo.Col++
|
||||||
|
if geo.Col == _geo.Col+geo.Width {
|
||||||
|
// TODO: Abort when out of room?
|
||||||
|
geo.Col = _geo.Col
|
||||||
|
geo.Row++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
ui/render.go
53
ui/render.go
|
@ -8,15 +8,21 @@ import (
|
||||||
|
|
||||||
func Initialize(conf *config.AercConfig) (*UIState, error) {
|
func Initialize(conf *config.AercConfig) (*UIState, error) {
|
||||||
state := UIState{
|
state := UIState{
|
||||||
|
Config: conf,
|
||||||
InvalidPanes: InvalidateAll,
|
InvalidPanes: InvalidateAll,
|
||||||
Tabs: make([]AercTab, len(conf.Accounts)),
|
|
||||||
|
tbEvents: make(chan tb.Event, 10),
|
||||||
}
|
}
|
||||||
// TODO: Initialize each tab to a mailbox tab
|
|
||||||
if err := tb.Init(); err != nil {
|
if err := tb.Init(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tb.SetInputMode(tb.InputEsc | tb.InputMouse)
|
tb.SetInputMode(tb.InputEsc | tb.InputMouse)
|
||||||
tb.SetOutputMode(tb.Output256)
|
tb.SetOutputMode(tb.Output256)
|
||||||
|
go (func() {
|
||||||
|
for !state.Exit {
|
||||||
|
state.tbEvents <- tb.PollEvent()
|
||||||
|
}
|
||||||
|
})()
|
||||||
return &state, nil
|
return &state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,21 +30,50 @@ func (state *UIState) Close() {
|
||||||
tb.Close()
|
tb.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (state *UIState) AddTab(tab AercTab) {
|
||||||
|
state.Tabs = append(state.Tabs, tab)
|
||||||
|
}
|
||||||
|
|
||||||
func (state *UIState) Invalidate(what uint) {
|
func (state *UIState) Invalidate(what uint) {
|
||||||
state.InvalidPanes |= what
|
state.InvalidPanes |= what
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (state *UIState) calcGeometries() {
|
||||||
|
width, height := tb.Size()
|
||||||
|
// TODO: more
|
||||||
|
state.Panes.TabView = Geometry{
|
||||||
|
Row: 0,
|
||||||
|
Col: 0,
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (state *UIState) Tick() bool {
|
func (state *UIState) Tick() bool {
|
||||||
switch e := tb.PollEvent(); e.Type {
|
select {
|
||||||
case tb.EventKey:
|
case event := <-state.tbEvents:
|
||||||
if e.Key == tb.KeyEsc {
|
switch event.Type {
|
||||||
state.Exit = true
|
case tb.EventKey:
|
||||||
|
if event.Key == tb.KeyEsc {
|
||||||
|
state.Exit = true
|
||||||
|
}
|
||||||
|
case tb.EventResize:
|
||||||
|
state.Invalidate(InvalidateAll)
|
||||||
}
|
}
|
||||||
case tb.EventResize:
|
default:
|
||||||
state.Invalidate(InvalidateAll)
|
// no-op
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if state.InvalidPanes != 0 {
|
if state.InvalidPanes != 0 {
|
||||||
// TODO: re-render
|
if state.InvalidPanes&InvalidateAll == InvalidateAll {
|
||||||
|
tb.Clear(tb.ColorDefault, tb.ColorDefault)
|
||||||
|
state.calcGeometries()
|
||||||
|
}
|
||||||
|
if state.InvalidPanes&InvalidateTabs != 0 {
|
||||||
|
tab := state.Tabs[state.SelectedTab]
|
||||||
|
tab.Render(state.Panes.TabView)
|
||||||
|
}
|
||||||
|
tb.Flush()
|
||||||
state.InvalidPanes = 0
|
state.InvalidPanes = 0
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
18
ui/types.go
18
ui/types.go
|
@ -1,5 +1,11 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
tb "github.com/nsf/termbox-go"
|
||||||
|
|
||||||
|
"git.sr.ht/~sircmpwn/aerc2/config"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Valid = 0
|
Valid = 0
|
||||||
InvalidateTabs = 1 << iota
|
InvalidateTabs = 1 << iota
|
||||||
|
@ -12,19 +18,21 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Geometry struct {
|
type Geometry struct {
|
||||||
row int
|
Row int
|
||||||
col int
|
Col int
|
||||||
width int
|
Width int
|
||||||
height int
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
type AercTab interface {
|
type AercTab interface {
|
||||||
Name() string
|
Name() string
|
||||||
Invalid() bool
|
Invalid() bool
|
||||||
Render(at Geometry)
|
Render(at Geometry)
|
||||||
|
SetParent(parent *UIState)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UIState struct {
|
type UIState struct {
|
||||||
|
Config *config.AercConfig
|
||||||
Exit bool
|
Exit bool
|
||||||
InvalidPanes uint
|
InvalidPanes uint
|
||||||
|
|
||||||
|
@ -44,4 +52,6 @@ type UIState struct {
|
||||||
Index int
|
Index int
|
||||||
Scroll int
|
Scroll int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tbEvents chan tb.Event
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue