diff options
author | Tim Culverhouse <tim@timculverhouse.com> | 2024-02-12 06:26:16 -0600 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-02-12 13:48:44 +0100 |
commit | 787cfbd9a90a26072a8dd61a28eca11dd6e20c04 (patch) | |
tree | b64f887898c810e3de9a9b4dd9c2bc0317cf7902 /lib | |
parent | 63b9706441719b53b3504733c51c2387fce9019d (diff) | |
download | aerc-787cfbd9a90a26072a8dd61a28eca11dd6e20c04.tar.gz |
ui: remove screen and viewports
Remove references to tcell.Screen or views.Viewports. Convert Contexts
and the core UI struct to use Vaxis objects only.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ui/context.go | 89 | ||||
-rw-r--r-- | lib/ui/textinput.go | 4 | ||||
-rw-r--r-- | lib/ui/ui.go | 49 |
3 files changed, 73 insertions, 69 deletions
diff --git a/lib/ui/context.go b/lib/ui/context.go index 39933fa3..10089179 100644 --- a/lib/ui/context.go +++ b/lib/ui/context.go @@ -6,35 +6,22 @@ import ( "git.sr.ht/~rjarry/aerc/lib/parse" "git.sr.ht/~rockorager/vaxis" "github.com/gdamore/tcell/v2" - "github.com/gdamore/tcell/v2/views" ) // A context allows you to draw in a sub-region of the terminal type Context struct { - screen tcell.Screen - viewport *views.ViewPort window vaxis.Window x, y int onPopover func(*Popover) } -func (ctx *Context) X() int { - x, _, _, _ := ctx.viewport.GetPhysical() - return x -} - -func (ctx *Context) Y() int { - _, y, _, _ := ctx.viewport.GetPhysical() - return y -} - func (ctx *Context) Width() int { - width, _ := ctx.viewport.Size() + width, _ := ctx.window.Size() return width } func (ctx *Context) Height() int { - _, height := ctx.viewport.Size() + _, height := ctx.window.Size() return height } @@ -43,39 +30,37 @@ func (ctx *Context) Window() vaxis.Window { return ctx.window } -func NewContext(width, height int, screen tcell.Screen, p func(*Popover)) *Context { - vp := views.NewViewPort(screen, 0, 0, width, height) - win := screen.Vaxis().Window() - return &Context{screen, vp, win, 0, 0, p} +func NewContext(width, height int, vx *vaxis.Vaxis, p func(*Popover)) *Context { + win := vx.Window() + return &Context{win, 0, 0, p} } func (ctx *Context) Subcontext(x, y, width, height int) *Context { - vp_width, vp_height := ctx.viewport.Size() if x < 0 || y < 0 { panic(fmt.Errorf("Attempted to create context with negative offset")) } - if x+width > vp_width || y+height > vp_height { - panic(fmt.Errorf("Attempted to create context larger than parent")) - } - vp := views.NewViewPort(ctx.viewport, x, y, width, height) win := ctx.window.New(x, y, width, height) - return &Context{ctx.screen, vp, win, ctx.x + x, ctx.y + y, ctx.onPopover} + return &Context{win, x, y, ctx.onPopover} } func (ctx *Context) SetCell(x, y int, ch rune, style tcell.Style) { - width, height := ctx.viewport.Size() + width, height := ctx.window.Size() if x >= width || y >= height { // no-op when dims are inadequate return } - crunes := []rune{} - ctx.viewport.SetContent(x, y, ch, crunes, style) + ctx.window.SetCell(x, y, vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: string(ch), + }, + Style: tcell.VaxisStyle(style), + }) } func (ctx *Context) Printf(x, y int, style tcell.Style, format string, a ...interface{}, ) int { - width, height := ctx.viewport.Size() + width, height := ctx.window.Size() if x >= width || y >= height { // no-op when dims are inadequate @@ -103,8 +88,13 @@ func (ctx *Context) Printf(x, y int, style tcell.Style, case '\r': x = old_x default: - crunes := []rune{} - ctx.viewport.SetContent(x, y, sr.Value, crunes, sr.Style) + ctx.window.SetCell(x, y, vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: string(sr.Value), + Width: sr.Width, + }, + Style: tcell.VaxisStyle(sr.Style), + }) x += sr.Width if x == old_x+width { if !newline() { @@ -118,20 +108,22 @@ func (ctx *Context) Printf(x, y int, style tcell.Style, } func (ctx *Context) Fill(x, y, width, height int, rune rune, style tcell.Style) { - vp := views.NewViewPort(ctx.viewport, x, y, width, height) - vp.Fill(rune, style) -} - -func (ctx *Context) SetCursor(x, y int) { - ctx.screen.ShowCursor(ctx.x+x, ctx.y+y) + win := ctx.window.New(x, y, width, height) + win.Fill(vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: string(rune), + Width: 1, + }, + Style: tcell.VaxisStyle(style), + }) } -func (ctx *Context) SetCursorStyle(cs tcell.CursorStyle) { - ctx.screen.SetCursorStyle(cs) +func (ctx *Context) SetCursor(x, y int, style vaxis.CursorStyle) { + ctx.window.ShowCursor(x, y, style) } func (ctx *Context) HideCursor() { - ctx.screen.HideCursor() + ctx.window.Vx.HideCursor() } func (ctx *Context) Popover(x, y, width, height int, d Drawable) { @@ -144,10 +136,19 @@ func (ctx *Context) Popover(x, y, width, height int, d Drawable) { }) } -func (ctx *Context) View() *views.ViewPort { - return ctx.viewport +// SetContent is used to update the content of the Surface at the given +// location. +func (ctx *Context) SetContent(x int, y int, ch rune, comb []rune, style tcell.Style) { + g := []rune{ch} + g = append(g, comb...) + ctx.window.SetCell(x, y, vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: string(g), + }, + Style: tcell.VaxisStyle(style), + }) } -func (ctx *Context) Show() { - ctx.screen.Show() +func (ctx *Context) Size() (int, int) { + return ctx.window.Size() } diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go index 0bdcd435..107d354c 100644 --- a/lib/ui/textinput.go +++ b/lib/ui/textinput.go @@ -120,7 +120,7 @@ func (ti *TextInput) Draw(ctx *Context) { } cells := runewidth.StringWidth(string(text[:sindex]) + ti.prompt) if ti.focus { - ctx.SetCursor(cells, 0) + ctx.SetCursor(cells, 0, vaxis.CursorDefault) ti.drawPopover(ctx) } } @@ -163,7 +163,7 @@ func (ti *TextInput) Focus(focus bool) { ti.focus = focus if focus && ti.ctx != nil { cells := runewidth.StringWidth(string(ti.text[:ti.index])) - ti.ctx.SetCursor(cells+1, 0) + ti.ctx.SetCursor(cells+1, 0, vaxis.CursorDefault) } else if !focus && ti.ctx != nil { ti.ctx.HideCursor() } diff --git a/lib/ui/ui.go b/lib/ui/ui.go index e13f4f5c..02e945c0 100644 --- a/lib/ui/ui.go +++ b/lib/ui/ui.go @@ -7,14 +7,15 @@ import ( "syscall" "git.sr.ht/~rjarry/aerc/config" + "git.sr.ht/~rjarry/aerc/log" "git.sr.ht/~rockorager/vaxis" "github.com/gdamore/tcell/v2" ) // Use unbuffered channels (always blocking unless somebody can read -// immediately) We are merely using this as a proxy to tcell screen internal -// event channel. -var Events = make(chan tcell.Event) +// immediately) We are merely using this as a proxy to the internal vaxis event +// channel. +var Events = make(chan vaxis.Event) var Quit = make(chan struct{}) @@ -40,7 +41,7 @@ func Invalidate() { var state struct { content DrawableInteractive ctx *Context - screen tcell.Screen + vx *vaxis.Vaxis popover *Popover dirty uint32 // == 1 if render has been queued in Redraw channel // == 1 if suspend is pending @@ -60,15 +61,16 @@ func Initialize(content DrawableInteractive) error { return err } - screen.Clear() - screen.HideCursor() - screen.EnablePaste() + vx := screen.Vaxis() - width, height := screen.Size() + vx.Window().Clear() + vx.HideCursor() + + width, height := vx.Window().Size() state.content = content - state.screen = screen - state.ctx = NewContext(width, height, state.screen, onPopover) + state.vx = vx + state.ctx = NewContext(width, height, state.vx, onPopover) Invalidate() if beeper, ok := content.(DrawableInteractiveBeeper); ok { @@ -76,7 +78,12 @@ func Initialize(content DrawableInteractive) error { } content.Focus(true) - go state.screen.ChannelEvents(Events, Quit) + go func() { + defer log.PanicHandler() + for event := range vx.Events() { + Events <- tcell.TcellEvent(event) + } + }() return nil } @@ -100,7 +107,7 @@ func QueueSuspend() { func Suspend() error { var err error if atomic.SwapUint32(&state.suspending, 0) != 0 { - err = state.screen.Suspend() + err = state.vx.Suspend() if err == nil { sigcont := make(chan os.Signal, 1) signal.Notify(sigcont, syscall.SIGCONT) @@ -109,21 +116,21 @@ func Suspend() error { <-sigcont } signal.Reset(syscall.SIGCONT) - err = state.screen.Resume() + err = state.vx.Resume() state.content.Draw(state.ctx) - state.screen.Show() + state.vx.Render() } } return err } func Close() { - state.screen.Fini() + state.vx.Close() } func Render() { if atomic.SwapUint32(&state.dirty, 0) != 0 { - state.screen.Clear() + state.vx.Window().Clear() // reset popover for the next Draw state.popover = nil state.content.Draw(state.ctx) @@ -131,19 +138,15 @@ func Render() { // if the Draw resulted in a popover, draw it state.popover.Draw(state.ctx) } - state.screen.Show() + state.vx.Render() } } -func EnableMouse() { - state.screen.EnableMouse() -} - func HandleEvent(event vaxis.Event) { if event, ok := event.(*tcell.EventResize); ok { - state.screen.Clear() + state.vx.Window().Clear() width, height := event.Size() - state.ctx = NewContext(width, height, state.screen, onPopover) + state.ctx = NewContext(width, height, state.vx, onPopover) Invalidate() } if event, ok := event.(tcell.VaxisEvent); ok { |