about summary refs log tree commit diff stats
path: root/lib/ui
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ui')
-rw-r--r--lib/ui/borders.go16
-rw-r--r--lib/ui/context.go86
-rw-r--r--lib/ui/fill.go4
-rw-r--r--lib/ui/interactive.go6
-rw-r--r--lib/ui/stack.go9
-rw-r--r--lib/ui/tab.go19
-rw-r--r--lib/ui/text.go18
-rw-r--r--lib/ui/ui.go48
8 files changed, 105 insertions, 101 deletions
diff --git a/lib/ui/borders.go b/lib/ui/borders.go
index 08071ad..38b35fd 100644
--- a/lib/ui/borders.go
+++ b/lib/ui/borders.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 const (
@@ -45,27 +45,23 @@ func (bordered *Bordered) Draw(ctx *Context) {
 	y := 0
 	width := ctx.Width()
 	height := ctx.Height()
-	cell := tb.Cell{
-		Ch: ' ',
-		Fg: tb.ColorBlack,
-		Bg: tb.ColorWhite,
-	}
+	style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
 	if bordered.borders&BORDER_LEFT != 0 {
-		ctx.Fill(0, 0, 1, ctx.Height(), cell)
+		ctx.Fill(0, 0, 1, ctx.Height(), ' ', style)
 		x += 1
 		width -= 1
 	}
 	if bordered.borders&BORDER_TOP != 0 {
-		ctx.Fill(0, 0, ctx.Width(), 1, cell)
+		ctx.Fill(0, 0, ctx.Width(), 1, ' ', style)
 		y += 1
 		height -= 1
 	}
 	if bordered.borders&BORDER_RIGHT != 0 {
-		ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), cell)
+		ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), ' ', style)
 		width -= 1
 	}
 	if bordered.borders&BORDER_BOTTOM != 0 {
-		ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, cell)
+		ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, ' ', style)
 		height -= 1
 	}
 	subctx := ctx.Subcontext(x, y, width, height)
diff --git a/lib/ui/context.go b/lib/ui/context.go
index ca3f452..8031689 100644
--- a/lib/ui/context.go
+++ b/lib/ui/context.go
@@ -4,73 +4,77 @@ import (
 	"fmt"
 
 	"github.com/mattn/go-runewidth"
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
+	"github.com/gdamore/tcell/views"
 )
 
 // A context allows you to draw in a sub-region of the terminal
 type Context struct {
-	x      int
-	y      int
-	width  int
-	height int
+	viewport *views.ViewPort
 }
 
 func (ctx *Context) X() int {
-	return ctx.x
+	x, _, _, _ := ctx.viewport.GetPhysical()
+	return x
 }
 
 func (ctx *Context) Y() int {
-	return ctx.y
+	_, y, _, _ := ctx.viewport.GetPhysical()
+	return y
 }
 
 func (ctx *Context) Width() int {
-	return ctx.width
+	width, _ := ctx.viewport.Size()
+	return width
 }
 
 func (ctx *Context) Height() int {
-	return ctx.height
+	_, height := ctx.viewport.Size()
+	return height
 }
 
-func NewContext(width, height int) *Context {
-	return &Context{0, 0, width, height}
+func NewContext(width, height int, screen tcell.Screen) *Context {
+	vp := views.NewViewPort(screen, 0, 0, width, height)
+	return &Context{vp}
 }
 
 func (ctx *Context) Subcontext(x, y, width, height int) *Context {
-	if x+width > ctx.width || y+height > ctx.height {
-		panic(fmt.Errorf("Attempted to create context larger than parent"))
+	vp_width, vp_height := ctx.viewport.Size()
+	if (x < 0 || y < 0) {
+		panic(fmt.Errorf("Attempted to create context with negative offset"))
 	}
-	return &Context{
-		x:      ctx.x + x,
-		y:      ctx.y + y,
-		width:  width,
-		height: height,
+	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)
+	return &Context{vp}
 }
 
-func (ctx *Context) SetCell(x, y int, ch rune, fg, bg tb.Attribute) {
-	if x >= ctx.width || y >= ctx.height {
+func (ctx *Context) SetCell(x, y int, ch rune, style tcell.Style) {
+	width, height := ctx.viewport.Size()
+	if x >= width || y >= height {
 		panic(fmt.Errorf("Attempted to draw outside of context"))
 	}
-	tb.SetCell(ctx.x+x, ctx.y+y, ch, fg, bg)
+	crunes := []rune{}
+	ctx.viewport.SetContent(x, y, ch, crunes, style)
 }
 
-func (ctx *Context) Printf(x, y int, ref tb.Cell,
+func (ctx *Context) Printf(x, y int, style tcell.Style,
 	format string, a ...interface{}) int {
+	width, height := ctx.viewport.Size()
 
-	if x >= ctx.width || y >= ctx.height {
+	if x >= width || y >= height {
 		panic(fmt.Errorf("Attempted to draw outside of context"))
 	}
 
 	str := fmt.Sprintf(format, a...)
 
-	x += ctx.x
-	y += ctx.y
 	old_x := x
 
 	newline := func() bool {
 		x = old_x
 		y++
-		return y < ctx.height
+		return y < height
 	}
 	for _, ch := range str {
 		if str == " こんにちは " {
@@ -84,9 +88,10 @@ func (ctx *Context) Printf(x, y int, ref tb.Cell,
 		case '\r':
 			x = old_x
 		default:
-			tb.SetCell(x, y, ch, ref.Fg, ref.Bg)
+			crunes := []rune{}
+			ctx.viewport.SetContent(x, y, ch, crunes, style)
 			x += runewidth.RuneWidth(ch)
-			if x == old_x+ctx.width {
+			if x == old_x + width {
 				if !newline() {
 					return runewidth.StringWidth(str)
 				}
@@ -97,13 +102,20 @@ func (ctx *Context) Printf(x, y int, ref tb.Cell,
 	return runewidth.StringWidth(str)
 }
 
-func (ctx *Context) Fill(x, y, width, height int, ref tb.Cell) {
-	_x := x
-	_y := y
-	for ; y < _y+height && y < ctx.height; y++ {
-		for ; x < _x+width && x < ctx.width; x++ {
-			ctx.SetCell(x, y, ref.Ch, ref.Fg, ref.Bg)
-		}
-		x = _x
-	}
+//func (ctx *Context) Screen() tcell.Screen {
+//	return ctx.screen
+//}
+
+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) {
+	// FIXME: Cursor needs to be set on tcell.Screen, or layout has to
+	// provide a CellModel
+	// cv := views.NewCellView()
+	// cv.Init()
+	// cv.SetView(ctx.viewport)
+	// cv.SetCursor(x, y)
 }
diff --git a/lib/ui/fill.go b/lib/ui/fill.go
index 3c6f0a5..4d36478 100644
--- a/lib/ui/fill.go
+++ b/lib/ui/fill.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Fill rune
@@ -13,7 +13,7 @@ func NewFill(f rune) Fill {
 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)
+			ctx.SetCell(x, y, rune(f), tcell.StyleDefault)
 		}
 	}
 }
diff --git a/lib/ui/interactive.go b/lib/ui/interactive.go
index efab828..2d4f099 100644
--- a/lib/ui/interactive.go
+++ b/lib/ui/interactive.go
@@ -1,17 +1,17 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Interactive interface {
 	// Returns true if the event was handled by this component
-	Event(event tb.Event) bool
+	Event(event tcell.Event) bool
 }
 
 type Simulator interface {
 	// Queues up the given input events for simulation
-	Simulate(events []tb.Event)
+	Simulate(events []tcell.Event)
 }
 
 type DrawableInteractive interface {
diff --git a/lib/ui/stack.go b/lib/ui/stack.go
index 9f81db8..3c66f5a 100644
--- a/lib/ui/stack.go
+++ b/lib/ui/stack.go
@@ -3,7 +3,7 @@ package ui
 import (
 	"fmt"
 
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Stack struct {
@@ -29,12 +29,7 @@ func (stack *Stack) Draw(ctx *Context) {
 	if len(stack.children) > 0 {
 		stack.Peek().Draw(ctx)
 	} else {
-		cell := tb.Cell{
-			Fg: tb.ColorDefault,
-			Bg: tb.ColorDefault,
-			Ch: ' ',
-		}
-		ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
+		ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
 	}
 }
 
diff --git a/lib/ui/tab.go b/lib/ui/tab.go
index e6a8aa5..d0635c7 100644
--- a/lib/ui/tab.go
+++ b/lib/ui/tab.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Tabs struct {
@@ -72,21 +72,14 @@ func (tabs *Tabs) Select(index int) {
 func (strip *TabStrip) Draw(ctx *Context) {
 	x := 0
 	for i, tab := range strip.Tabs {
-		cell := tb.Cell{
-			Fg: tb.ColorBlack,
-			Bg: tb.ColorWhite,
-		}
+		style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
 		if strip.Selected == i {
-			cell.Fg = tb.ColorDefault
-			cell.Bg = tb.ColorDefault
+			style = style.Reverse(true)
 		}
-		x += ctx.Printf(x, 0, cell, " %s ", tab.Name)
-	}
-	cell := tb.Cell{
-		Fg: tb.ColorBlack,
-		Bg: tb.ColorWhite,
+		x += ctx.Printf(x, 0, style, " %s ", tab.Name)
 	}
-	ctx.Fill(x, 0, ctx.Width()-x, 1, cell)
+	style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
+	ctx.Fill(x, 0, ctx.Width()-x, 1, ' ', style)
 }
 
 func (strip *TabStrip) Invalidate() {
diff --git a/lib/ui/text.go b/lib/ui/text.go
index 6164837..e2e218c 100644
--- a/lib/ui/text.go
+++ b/lib/ui/text.go
@@ -2,7 +2,7 @@ package ui
 
 import (
 	"github.com/mattn/go-runewidth"
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 const (
@@ -14,8 +14,8 @@ const (
 type Text struct {
 	text         string
 	strategy     uint
-	fg           tb.Attribute
-	bg           tb.Attribute
+	fg           tcell.Color
+	bg           tcell.Color
 	onInvalidate func(d Drawable)
 }
 
@@ -35,7 +35,7 @@ func (t *Text) Strategy(strategy uint) *Text {
 	return t
 }
 
-func (t *Text) Color(fg tb.Attribute, bg tb.Attribute) *Text {
+func (t *Text) Color(fg tcell.Color, bg tcell.Color) *Text {
 	t.fg = fg
 	t.bg = bg
 	t.Invalidate()
@@ -44,11 +44,6 @@ func (t *Text) Color(fg tb.Attribute, bg tb.Attribute) *Text {
 
 func (t *Text) Draw(ctx *Context) {
 	size := runewidth.StringWidth(t.text)
-	cell := tb.Cell{
-		Ch: ' ',
-		Fg: t.fg,
-		Bg: t.bg,
-	}
 	x := 0
 	if t.strategy == TEXT_CENTER {
 		x = (ctx.Width() - size) / 2
@@ -56,8 +51,9 @@ func (t *Text) Draw(ctx *Context) {
 	if t.strategy == TEXT_RIGHT {
 		x = ctx.Width() - size
 	}
-	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
-	ctx.Printf(x, 0, cell, "%s", t.text)
+	style := tcell.StyleDefault.Background(t.bg).Foreground(t.fg)
+	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style)
+	ctx.Printf(x, 0, style, t.text)
 }
 
 func (t *Text) OnInvalidate(onInvalidate func(d Drawable)) {
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index e9b4e9b..d3eacf2 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 
 	"git.sr.ht/~sircmpwn/aerc2/config"
 )
@@ -10,30 +10,41 @@ type UI struct {
 	Exit    bool
 	Content DrawableInteractive
 	ctx     *Context
+	screen  tcell.Screen
 
-	tbEvents      chan tb.Event
+	tcEvents      chan tcell.Event
 	invalidations chan interface{}
 }
 
 func Initialize(conf *config.AercConfig,
 	content DrawableInteractive) (*UI, error) {
 
-	if err := tb.Init(); err != nil {
+	screen, err := tcell.NewScreen()
+	if err != nil {
 		return nil, err
 	}
-	width, height := tb.Size()
+
+	if err = screen.Init(); err != nil {
+		return nil, err
+	}
+
+	screen.Clear()
+	screen.HideCursor()
+
+	width, height := screen.Size()
+
 	state := UI{
 		Content: content,
-		ctx:     NewContext(width, height),
+		ctx:     NewContext(width, height, screen),
+		screen:  screen,
 
-		tbEvents:      make(chan tb.Event, 10),
+		tcEvents:      make(chan tcell.Event, 10),
 		invalidations: make(chan interface{}),
 	}
-	tb.SetInputMode(tb.InputEsc | tb.InputMouse)
-	tb.SetOutputMode(tb.Output256)
+	//tb.SetOutputMode(tb.Output256)
 	go (func() {
 		for !state.Exit {
-			state.tbEvents <- tb.PollEvent()
+			state.tcEvents <- screen.PollEvent()
 		}
 	})()
 	go (func() { state.invalidations <- nil })()
@@ -44,27 +55,28 @@ func Initialize(conf *config.AercConfig,
 }
 
 func (state *UI) Close() {
-	tb.Close()
+	state.screen.Fini()
 }
 
 func (state *UI) Tick() bool {
 	select {
-	case event := <-state.tbEvents:
-		switch event.Type {
-		case tb.EventKey:
+	case event := <-state.tcEvents:
+		switch event := event.(type) {
+		case *tcell.EventKey:
 			// TODO: temporary
-			if event.Key == tb.KeyEsc {
+			if event.Key() == tcell.KeyEsc {
 				state.Exit = true
 			}
-		case tb.EventResize:
-			tb.Clear(tb.ColorDefault, tb.ColorDefault)
-			state.ctx = NewContext(event.Width, event.Height)
+		case *tcell.EventResize:
+			state.screen.Clear()
+			width, height := event.Size()
+			state.ctx = NewContext(width, height, state.screen)
 			state.Content.Invalidate()
 		}
 		state.Content.Event(event)
 	case <-state.invalidations:
 		state.Content.Draw(state.ctx)
-		tb.Flush()
+		state.screen.Show()
 	default:
 		return false
 	}