aboutsummaryrefslogtreecommitdiff
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
}