Pull main aerc UI into widget
This commit is contained in:
parent
a073d7613f
commit
cab3771e17
5 changed files with 130 additions and 83 deletions
|
@ -8,31 +8,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
tb "github.com/nsf/termbox-go"
|
||||
|
||||
"git.sr.ht/~sircmpwn/aerc2/config"
|
||||
libui "git.sr.ht/~sircmpwn/aerc2/lib/ui"
|
||||
"git.sr.ht/~sircmpwn/aerc2/widgets"
|
||||
)
|
||||
|
||||
type fill rune
|
||||
|
||||
func (f fill) Draw(ctx *libui.Context) {
|
||||
for x := 0; x < ctx.Width(); x += 1 {
|
||||
for y := 0; y < ctx.Height(); y += 1 {
|
||||
ctx.SetCell(x, y, rune(f), tb.ColorDefault, tb.ColorDefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f fill) OnInvalidate(callback func(d libui.Drawable)) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
func (f fill) Invalidate() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
func main() {
|
||||
var logOut io.Writer
|
||||
var logger *log.Logger
|
||||
|
@ -49,62 +30,12 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
tabs := libui.NewTabs()
|
||||
tabs.Add(fill('★'), "白い星")
|
||||
tabs.Add(fill('☆'), "empty stars")
|
||||
|
||||
grid := libui.NewGrid().Rows([]libui.GridSpec{
|
||||
libui.GridSpec{libui.SIZE_EXACT, 1},
|
||||
libui.GridSpec{libui.SIZE_WEIGHT, 1},
|
||||
libui.GridSpec{libui.SIZE_EXACT, 1},
|
||||
}).Columns([]libui.GridSpec{
|
||||
libui.GridSpec{libui.SIZE_EXACT, 20},
|
||||
libui.GridSpec{libui.SIZE_WEIGHT, 1},
|
||||
})
|
||||
|
||||
// TODO: move sidebar into tab content, probably
|
||||
grid.AddChild(libui.NewText("aerc").
|
||||
Strategy(libui.TEXT_CENTER).
|
||||
Color(tb.ColorBlack, tb.ColorWhite))
|
||||
// sidebar placeholder:
|
||||
grid.AddChild(libui.NewBordered(
|
||||
fill('.'), libui.BORDER_RIGHT)).At(1, 0).Span(2, 1)
|
||||
grid.AddChild(tabs.TabStrip).At(0, 1)
|
||||
grid.AddChild(tabs.TabContent).At(1, 1)
|
||||
|
||||
statusbar := libui.NewStack()
|
||||
grid.AddChild(statusbar).At(2, 1)
|
||||
|
||||
statusline := widgets.NewStatusLine()
|
||||
statusline.Push("test status!", 6*time.Second)
|
||||
statusline.Push("test error!", 3*time.Second).
|
||||
Color(tb.ColorRed, tb.ColorBlack)
|
||||
statusbar.Push(statusline)
|
||||
|
||||
exline := widgets.NewExLine(func(command string) {
|
||||
statusbar.Pop()
|
||||
logger.Printf("TODO: execute command: %s\n", command)
|
||||
}, func() {
|
||||
statusbar.Pop()
|
||||
})
|
||||
statusbar.Push(exline)
|
||||
|
||||
ui, err := libui.Initialize(conf, grid)
|
||||
ui, err := libui.Initialize(conf, widgets.NewAerc(logger))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer ui.Close()
|
||||
|
||||
// TODO: this should be a stack
|
||||
ui.AddInteractive(exline)
|
||||
|
||||
go (func() {
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
tabs.Select((tabs.Selected + 1) % 2)
|
||||
}
|
||||
})()
|
||||
|
||||
for !ui.Exit {
|
||||
if !ui.Tick() {
|
||||
// ~60 FPS
|
||||
|
|
27
lib/ui/fill.go
Normal file
27
lib/ui/fill.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
tb "github.com/nsf/termbox-go"
|
||||
)
|
||||
|
||||
type Fill rune
|
||||
|
||||
func NewFill(f rune) Fill {
|
||||
return Fill(f)
|
||||
}
|
||||
|
||||
func (f Fill) Draw(ctx *Context) {
|
||||
for x := 0; x < ctx.Width(); x += 1 {
|
||||
for y := 0; y < ctx.Height(); y += 1 {
|
||||
ctx.SetCell(x, y, rune(f), tb.ColorDefault, tb.ColorDefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f Fill) OnInvalidate(callback func(d Drawable)) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
func (f Fill) Invalidate() {
|
||||
// no-op
|
||||
}
|
|
@ -13,3 +13,8 @@ type Simulator interface {
|
|||
// Queues up the given input events for simulation
|
||||
Simulate(events []tb.Event)
|
||||
}
|
||||
|
||||
type DrawableInteractive interface {
|
||||
Drawable
|
||||
Interactive
|
||||
}
|
||||
|
|
19
lib/ui/ui.go
19
lib/ui/ui.go
|
@ -8,16 +8,16 @@ import (
|
|||
|
||||
type UI struct {
|
||||
Exit bool
|
||||
Content Drawable
|
||||
Content DrawableInteractive
|
||||
ctx *Context
|
||||
|
||||
interactive []Interactive
|
||||
|
||||
tbEvents chan tb.Event
|
||||
invalidations chan interface{}
|
||||
}
|
||||
|
||||
func Initialize(conf *config.AercConfig, content Drawable) (*UI, error) {
|
||||
func Initialize(conf *config.AercConfig,
|
||||
content DrawableInteractive) (*UI, error) {
|
||||
|
||||
if err := tb.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ func (state *UI) Tick() bool {
|
|||
case event := <-state.tbEvents:
|
||||
switch event.Type {
|
||||
case tb.EventKey:
|
||||
// TODO: temporary
|
||||
if event.Key == tb.KeyEsc {
|
||||
state.Exit = true
|
||||
}
|
||||
|
@ -60,11 +61,7 @@ func (state *UI) Tick() bool {
|
|||
state.ctx = NewContext(event.Width, event.Height)
|
||||
state.Content.Invalidate()
|
||||
}
|
||||
if state.interactive != nil {
|
||||
for _, i := range state.interactive {
|
||||
i.Event(event)
|
||||
}
|
||||
}
|
||||
state.Content.Event(event)
|
||||
case <-state.invalidations:
|
||||
state.Content.Draw(state.ctx)
|
||||
tb.Flush()
|
||||
|
@ -73,7 +70,3 @@ func (state *UI) Tick() bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (state *UI) AddInteractive(i Interactive) {
|
||||
state.interactive = append(state.interactive, i)
|
||||
}
|
||||
|
|
91
widgets/aerc.go
Normal file
91
widgets/aerc.go
Normal file
|
@ -0,0 +1,91 @@
|
|||
package widgets
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
tb "github.com/nsf/termbox-go"
|
||||
|
||||
libui "git.sr.ht/~sircmpwn/aerc2/lib/ui"
|
||||
)
|
||||
|
||||
type Aerc struct {
|
||||
grid *libui.Grid
|
||||
tabs *libui.Tabs
|
||||
statusbar *libui.Stack
|
||||
statusline *StatusLine
|
||||
interactive libui.Interactive
|
||||
}
|
||||
|
||||
func NewAerc(logger *log.Logger) *Aerc {
|
||||
tabs := libui.NewTabs()
|
||||
tabs.Add(libui.NewFill('★'), "白い星")
|
||||
tabs.Add(libui.NewFill('☆'), "empty stars")
|
||||
|
||||
grid := libui.NewGrid().Rows([]libui.GridSpec{
|
||||
libui.GridSpec{libui.SIZE_EXACT, 1},
|
||||
libui.GridSpec{libui.SIZE_WEIGHT, 1},
|
||||
libui.GridSpec{libui.SIZE_EXACT, 1},
|
||||
}).Columns([]libui.GridSpec{
|
||||
libui.GridSpec{libui.SIZE_EXACT, 20},
|
||||
libui.GridSpec{libui.SIZE_WEIGHT, 1},
|
||||
})
|
||||
|
||||
// TODO: move sidebar into tab content, probably
|
||||
grid.AddChild(libui.NewText("aerc").
|
||||
Strategy(libui.TEXT_CENTER).
|
||||
Color(tb.ColorBlack, tb.ColorWhite))
|
||||
// sidebar placeholder:
|
||||
grid.AddChild(libui.NewBordered(
|
||||
libui.NewFill('.'), libui.BORDER_RIGHT)).At(1, 0).Span(2, 1)
|
||||
grid.AddChild(tabs.TabStrip).At(0, 1)
|
||||
grid.AddChild(tabs.TabContent).At(1, 1)
|
||||
|
||||
statusbar := libui.NewStack()
|
||||
grid.AddChild(statusbar).At(2, 1)
|
||||
|
||||
statusline := NewStatusLine()
|
||||
statusline.Push("test status!", 6 * time.Second)
|
||||
statusline.Push("test error!", 3 * time.Second).
|
||||
Color(tb.ColorRed, tb.ColorBlack)
|
||||
statusbar.Push(statusline)
|
||||
|
||||
exline := NewExLine(func(command string) {
|
||||
statusbar.Pop()
|
||||
logger.Printf("TODO: execute command: %s\n", command)
|
||||
}, func() {
|
||||
statusbar.Pop()
|
||||
})
|
||||
statusbar.Push(exline)
|
||||
|
||||
go (func() {
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
tabs.Select((tabs.Selected + 1) % 2)
|
||||
}
|
||||
})()
|
||||
|
||||
return &Aerc{
|
||||
grid: grid,
|
||||
interactive: exline,
|
||||
statusbar: statusbar,
|
||||
statusline: statusline,
|
||||
tabs: tabs,
|
||||
}
|
||||
}
|
||||
|
||||
func (aerc *Aerc) OnInvalidate(onInvalidate func(d libui.Drawable)) {
|
||||
aerc.grid.OnInvalidate(onInvalidate)
|
||||
}
|
||||
|
||||
func (aerc *Aerc) Invalidate() {
|
||||
aerc.grid.Invalidate()
|
||||
}
|
||||
|
||||
func (aerc *Aerc) Draw(ctx *libui.Context) {
|
||||
aerc.grid.Draw(ctx)
|
||||
}
|
||||
|
||||
func (aerc *Aerc) Event(event tb.Event) bool {
|
||||
return aerc.interactive.Event(event)
|
||||
}
|
Loading…
Reference in a new issue