summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-02-26 22:54:39 -0500
committerDrew DeVault <sir@cmpwn.com>2018-02-26 22:54:39 -0500
commit1418e1b9dc41d8f69bccb8de0fe0f1fb6835ce11 (patch)
tree4ae8b3373fdadb6dd3e7b8c8789cf938522b8f8a /ui
parent661e3ec2a4dd97d4a8a8eab4f281b088770a6af2 (diff)
downloadaerc-1418e1b9dc41d8f69bccb8de0fe0f1fb6835ce11.zip
Split UI library and widgets
Diffstat (limited to 'ui')
-rw-r--r--ui/account.go.old97
-rw-r--r--ui/borders.go73
-rw-r--r--ui/context.go109
-rw-r--r--ui/drawable.go10
-rw-r--r--ui/exline.go127
-rw-r--r--ui/grid.go191
-rw-r--r--ui/interactive.go10
-rw-r--r--ui/tab.go115
-rw-r--r--ui/text.go71
-rw-r--r--ui/ui.go79
10 files changed, 0 insertions, 882 deletions
diff --git a/ui/account.go.old b/ui/account.go.old
deleted file mode 100644
index 393a47a..0000000
--- a/ui/account.go.old
+++ /dev/null
@@ -1,97 +0,0 @@
-package ui
-
-import (
- "log"
-
- tb "github.com/nsf/termbox-go"
-
- "git.sr.ht/~sircmpwn/aerc2/config"
- "git.sr.ht/~sircmpwn/aerc2/worker"
- "git.sr.ht/~sircmpwn/aerc2/worker/types"
-)
-
-type AccountTab struct {
- Config *config.AccountConfig
- Worker *types.Worker
- Parent *UIState
- logger *log.Logger
- counter int
-}
-
-func NewAccountTab(conf *config.AccountConfig,
- logger *log.Logger) (*AccountTab, error) {
-
- work, err := worker.NewWorker(conf.Source, logger)
- if err != nil {
- return nil, err
- }
- go work.Backend.Run()
- acc := &AccountTab{
- Config: conf,
- Worker: work,
- logger: logger,
- }
- acc.Worker.PostAction(&types.Configure{Config: conf}, nil)
- acc.Worker.PostAction(&types.Connect{}, func(msg types.WorkerMessage) {
- switch msg := msg.(type) {
- case *types.Done:
- acc.logger.Println("Connected.")
- acc.Worker.PostAction(&types.ListDirectories{}, nil)
- case *types.CertificateApprovalRequest:
- // TODO: Ask the user
- acc.logger.Println("Approving certificate")
- acc.Worker.PostAction(&types.ApproveCertificate{
- Message: types.RespondTo(msg),
- Approved: true,
- }, nil)
- default:
- acc.logger.Println("Connection failed.")
- }
- })
- return acc, nil
-}
-
-func (acc *AccountTab) Name() string {
- return acc.Config.Name
-}
-
-func (acc *AccountTab) SetParent(parent *UIState) {
- acc.Parent = parent
-}
-
-func (acc *AccountTab) Render(at Geometry) {
- cell := tb.Cell{
- Ch: ' ',
- Fg: tb.ColorDefault,
- Bg: tb.ColorDefault,
- }
- TFill(at, cell)
- TPrintf(&at, cell, "%s %d\n", acc.Name(), acc.counter)
- acc.counter++
- if acc.counter%10000 == 0 {
- acc.counter = 0
- }
- acc.Parent.InvalidateFrom(acc)
-}
-
-func (acc *AccountTab) GetChannel() chan types.WorkerMessage {
- return acc.Worker.Messages
-}
-
-func (acc *AccountTab) HandleMessage(msg types.WorkerMessage) {
- msg = acc.Worker.ProcessMessage(msg)
- switch msg := msg.(type) {
- case *types.Done:
- case *types.CertificateApprovalRequest:
- case *types.Unsupported:
- // no-op
- case *types.Error:
- acc.logger.Printf("Error: %v\n", msg.Error)
- case *types.Directory:
- acc.logger.Printf("Directory: %s\n", msg.Name)
- default:
- acc.Worker.PostAction(&types.Unsupported{
- Message: types.RespondTo(msg),
- }, nil)
- }
-}
diff --git a/ui/borders.go b/ui/borders.go
deleted file mode 100644
index 08071ad..0000000
--- a/ui/borders.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package ui
-
-import (
- tb "github.com/nsf/termbox-go"
-)
-
-const (
- BORDER_LEFT = 1 << iota
- BORDER_TOP = 1 << iota
- BORDER_RIGHT = 1 << iota
- BORDER_BOTTOM = 1 << iota
-)
-
-type Bordered struct {
- borders uint
- content Drawable
- onInvalidate func(d Drawable)
-}
-
-func NewBordered(content Drawable, borders uint) *Bordered {
- b := &Bordered{
- borders: borders,
- content: content,
- }
- content.OnInvalidate(b.contentInvalidated)
- return b
-}
-
-func (bordered *Bordered) contentInvalidated(d Drawable) {
- bordered.Invalidate()
-}
-
-func (bordered *Bordered) Invalidate() {
- if bordered.onInvalidate != nil {
- bordered.onInvalidate(bordered)
- }
-}
-
-func (bordered *Bordered) OnInvalidate(onInvalidate func(d Drawable)) {
- bordered.onInvalidate = onInvalidate
-}
-
-func (bordered *Bordered) Draw(ctx *Context) {
- x := 0
- y := 0
- width := ctx.Width()
- height := ctx.Height()
- cell := tb.Cell{
- Ch: ' ',
- Fg: tb.ColorBlack,
- Bg: tb.ColorWhite,
- }
- if bordered.borders&BORDER_LEFT != 0 {
- ctx.Fill(0, 0, 1, ctx.Height(), cell)
- x += 1
- width -= 1
- }
- if bordered.borders&BORDER_TOP != 0 {
- ctx.Fill(0, 0, ctx.Width(), 1, cell)
- y += 1
- height -= 1
- }
- if bordered.borders&BORDER_RIGHT != 0 {
- ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), cell)
- width -= 1
- }
- if bordered.borders&BORDER_BOTTOM != 0 {
- ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, cell)
- height -= 1
- }
- subctx := ctx.Subcontext(x, y, width, height)
- bordered.content.Draw(subctx)
-}
diff --git a/ui/context.go b/ui/context.go
deleted file mode 100644
index ca3f452..0000000
--- a/ui/context.go
+++ /dev/null
@@ -1,109 +0,0 @@
-package ui
-
-import (
- "fmt"
-
- "github.com/mattn/go-runewidth"
- tb "github.com/nsf/termbox-go"
-)
-
-// A context allows you to draw in a sub-region of the terminal
-type Context struct {
- x int
- y int
- width int
- height int
-}
-
-func (ctx *Context) X() int {
- return ctx.x
-}
-
-func (ctx *Context) Y() int {
- return ctx.y
-}
-
-func (ctx *Context) Width() int {
- return ctx.width
-}
-
-func (ctx *Context) Height() int {
- return ctx.height
-}
-
-func NewContext(width, height int) *Context {
- return &Context{0, 0, width, height}
-}
-
-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"))
- }
- return &Context{
- x: ctx.x + x,
- y: ctx.y + y,
- width: width,
- height: height,
- }
-}
-
-func (ctx *Context) SetCell(x, y int, ch rune, fg, bg tb.Attribute) {
- if x >= ctx.width || y >= ctx.height {
- panic(fmt.Errorf("Attempted to draw outside of context"))
- }
- tb.SetCell(ctx.x+x, ctx.y+y, ch, fg, bg)
-}
-
-func (ctx *Context) Printf(x, y int, ref tb.Cell,
- format string, a ...interface{}) int {
-
- if x >= ctx.width || y >= ctx.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
- }
- for _, ch := range str {
- if str == " こんにちは " {
- fmt.Printf("%c\n", ch)
- }
- switch ch {
- case '\n':
- if !newline() {
- return runewidth.StringWidth(str)
- }
- case '\r':
- x = old_x
- default:
- tb.SetCell(x, y, ch, ref.Fg, ref.Bg)
- x += runewidth.RuneWidth(ch)
- if x == old_x+ctx.width {
- if !newline() {
- return runewidth.StringWidth(str)
- }
- }
- }
- }
-
- 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
- }
-}
diff --git a/ui/drawable.go b/ui/drawable.go
deleted file mode 100644
index ef09451..0000000
--- a/ui/drawable.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package ui
-
-type Drawable interface {
- // Called when this renderable should draw itself
- Draw(ctx *Context)
- // Specifies a function to call when this cell needs to be redrawn
- OnInvalidate(callback func(d Drawable))
- // Invalidates the drawable
- Invalidate()
-}
diff --git a/ui/exline.go b/ui/exline.go
deleted file mode 100644
index a377cd7..0000000
--- a/ui/exline.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package ui
-
-import (
- tb "github.com/nsf/termbox-go"
-)
-
-// TODO: history
-// TODO: tab completion
-// TODO: commit
-// TODO: cancel (via esc/ctrl+c)
-// TODO: scrolling
-
-type ExLine struct {
- command *string
- commit func(cmd *string)
- index int
- scroll int
-
- onInvalidate func(d Drawable)
-}
-
-func NewExLine() *ExLine {
- cmd := ""
- return &ExLine{command: &cmd}
-}
-
-func (ex *ExLine) OnInvalidate(onInvalidate func(d Drawable)) {
- ex.onInvalidate = onInvalidate
-}
-
-func (ex *ExLine) Invalidate() {
- if ex.onInvalidate != nil {
- ex.onInvalidate(ex)
- }
-}
-
-func (ex *ExLine) Draw(ctx *Context) {
- cell := tb.Cell{
- Fg: tb.ColorDefault,
- Bg: tb.ColorDefault,
- Ch: ' ',
- }
- ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
- ctx.Printf(0, 0, cell, ":%s", *ex.command)
- tb.SetCursor(ctx.X()+ex.index-ex.scroll+1, ctx.Y())
-}
-
-func (ex *ExLine) insert(ch rune) {
- newCmd := (*ex.command)[:ex.index] + string(ch) + (*ex.command)[ex.index:]
- ex.command = &newCmd
- ex.index++
- ex.Invalidate()
-}
-
-func (ex *ExLine) deleteWord() {
- // TODO: Break on any of / " '
- if len(*ex.command) == 0 {
- return
- }
- i := ex.index - 1
- if (*ex.command)[i] == ' ' {
- i--
- }
- for ; i >= 0; i-- {
- if (*ex.command)[i] == ' ' {
- break
- }
- }
- newCmd := (*ex.command)[:i+1] + (*ex.command)[ex.index:]
- ex.command = &newCmd
- ex.index = i + 1
- ex.Invalidate()
-}
-
-func (ex *ExLine) deleteChar() {
- if len(*ex.command) > 0 && ex.index != len(*ex.command) {
- newCmd := (*ex.command)[:ex.index] + (*ex.command)[ex.index+1:]
- ex.command = &newCmd
- ex.Invalidate()
- }
-}
-
-func (ex *ExLine) backspace() {
- if len(*ex.command) > 0 && ex.index != 0 {
- newCmd := (*ex.command)[:ex.index-1] + (*ex.command)[ex.index:]
- ex.command = &newCmd
- ex.index--
- ex.Invalidate()
- }
-}
-
-func (ex *ExLine) Event(event tb.Event) bool {
- switch event.Type {
- case tb.EventKey:
- switch event.Key {
- case tb.KeySpace:
- ex.insert(' ')
- case tb.KeyBackspace, tb.KeyBackspace2:
- ex.backspace()
- case tb.KeyCtrlD, tb.KeyDelete:
- ex.deleteChar()
- case tb.KeyCtrlB, tb.KeyArrowLeft:
- if ex.index > 0 {
- ex.index--
- ex.Invalidate()
- }
- case tb.KeyCtrlF, tb.KeyArrowRight:
- if ex.index < len(*ex.command) {
- ex.index++
- ex.Invalidate()
- }
- case tb.KeyCtrlA, tb.KeyHome:
- ex.index = 0
- ex.Invalidate()
- case tb.KeyCtrlE, tb.KeyEnd:
- ex.index = len(*ex.command)
- ex.Invalidate()
- case tb.KeyCtrlW:
- ex.deleteWord()
- default:
- if event.Ch != 0 {
- ex.insert(event.Ch)
- }
- }
- }
- return true
-}
diff --git a/ui/grid.go b/ui/grid.go
deleted file mode 100644
index ede7d0c..0000000
--- a/ui/grid.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package ui
-
-import (
- "fmt"
- "math"
-)
-
-type Grid struct {
- rows []GridSpec
- rowLayout []gridLayout
- columns []GridSpec
- columnLayout []gridLayout
- Cells []*GridCell
- onInvalidate func(d Drawable)
- invalid bool
-}
-
-const (
- SIZE_EXACT = iota
- SIZE_WEIGHT = iota
-)
-
-// Specifies the layout of a single row or column
-type GridSpec struct {
- // One of SIZE_EXACT or SIZE_WEIGHT
- Strategy int
- // If Strategy = SIZE_EXACT, this is the number of cells this row/col shall
- // occupy. If SIZE_WEIGHT, the space left after all exact rows/cols are
- // measured is distributed amonst the remainder weighted by this value.
- Size int
-}
-
-// Used to cache layout of each row/column
-type gridLayout struct {
- Offset int
- Size int
-}
-
-type GridCell struct {
- Row int
- Column int
- RowSpan int
- ColSpan int
- Content Drawable
- invalid bool
-}
-
-func NewGrid() *Grid {
- return &Grid{invalid: true}
-}
-
-func (cell *GridCell) At(row, col int) *GridCell {
- cell.Row = row
- cell.Column = col
- return cell
-}
-
-func (cell *GridCell) Span(rows, cols int) *GridCell {
- cell.RowSpan = rows
- cell.ColSpan = cols
- return cell
-}
-
-func (grid *Grid) Rows(spec []GridSpec) *Grid {
- grid.rows = spec
- return grid
-}
-
-func (grid *Grid) Columns(spec []GridSpec) *Grid {
- grid.columns = spec
- return grid
-}
-
-func (grid *Grid) Draw(ctx *Context) {
- invalid := grid.invalid
- if invalid {
- grid.reflow(ctx)
- }
- for _, cell := range grid.Cells {
- if !cell.invalid && !invalid {
- continue
- }
- rows := grid.rowLayout[cell.Row : cell.Row+cell.RowSpan]
- cols := grid.columnLayout[cell.Column : cell.Column+cell.ColSpan]
- x := cols[0].Offset
- y := rows[0].Offset
- width := 0
- height := 0
- for _, col := range cols {
- width += col.Size
- }
- for _, row := range rows {
- height += row.Size
- }
- subctx := ctx.Subcontext(x, y, width, height)
- cell.Content.Draw(subctx)
- }
-}
-
-func (grid *Grid) reflow(ctx *Context) {
- grid.rowLayout = nil
- grid.columnLayout = nil
- flow := func(specs *[]GridSpec, layouts *[]gridLayout, extent int) {
- exact := 0
- weight := 0
- nweights := 0
- for _, spec := range *specs {
- if spec.Strategy == SIZE_EXACT {
- exact += spec.Size
- } else if spec.Strategy == SIZE_WEIGHT {
- nweights += 1
- weight += spec.Size
- }
- }
- offset := 0
- for _, spec := range *specs {
- layout := gridLayout{Offset: offset}
- if spec.Strategy == SIZE_EXACT {
- layout.Size = spec.Size
- } else if spec.Strategy == SIZE_WEIGHT {
- size := float64(spec.Size) / float64(weight)
- size *= float64(extent - exact)
- layout.Size = int(math.Floor(size))
- }
- offset += layout.Size
- *layouts = append(*layouts, layout)
- }
- }
- flow(&grid.rows, &grid.rowLayout, ctx.Height())
- flow(&grid.columns, &grid.columnLayout, ctx.Width())
- grid.invalid = false
-}
-
-func (grid *Grid) invalidateLayout() {
- grid.invalid = true
- if grid.onInvalidate != nil {
- grid.onInvalidate(grid)
- }
-}
-
-func (grid *Grid) Invalidate() {
- grid.invalidateLayout()
- for _, cell := range grid.Cells {
- cell.Content.Invalidate()
- }
-}
-
-func (grid *Grid) OnInvalidate(onInvalidate func(d Drawable)) {
- grid.onInvalidate = onInvalidate
-}
-
-func (grid *Grid) AddChild(content Drawable) *GridCell {
- cell := &GridCell{
- RowSpan: 1,
- ColSpan: 1,
- Content: content,
- invalid: true,
- }
- grid.Cells = append(grid.Cells, cell)
- cell.Content.OnInvalidate(grid.cellInvalidated)
- cell.invalid = true
- grid.invalidateLayout()
- return cell
-}
-
-func (grid *Grid) RemoveChild(cell *GridCell) {
- for i, _cell := range grid.Cells {
- if _cell == cell {
- grid.Cells = append(grid.Cells[:i], grid.Cells[i+1:]...)
- break
- }
- }
- grid.invalidateLayout()
-}
-
-func (grid *Grid) cellInvalidated(drawable Drawable) {
- var cell *GridCell
- for _, cell = range grid.Cells {
- if cell.Content == drawable {
- break
- }
- cell = nil
- }
- if cell == nil {
- panic(fmt.Errorf("Attempted to invalidate unknown cell"))
- }
- cell.invalid = true
- if grid.onInvalidate != nil {
- grid.onInvalidate(grid)
- }
-}
diff --git a/ui/interactive.go b/ui/interactive.go
deleted file mode 100644
index 5dd5fef..0000000
--- a/ui/interactive.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package ui
-
-import (
- tb "github.com/nsf/termbox-go"
-)
-
-type Interactive interface {
- // Returns true if the event was handled by this component
- Event(event tb.Event) bool
-}
diff --git a/ui/tab.go b/ui/tab.go
deleted file mode 100644
index e6a8aa5..0000000
--- a/ui/tab.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package ui
-
-import (
- tb "github.com/nsf/termbox-go"
-)
-
-type Tabs struct {
- Tabs []*Tab
- TabStrip *TabStrip
- TabContent *TabContent
- Selected int
-
- onInvalidateStrip func(d Drawable)
- onInvalidateContent func(d Drawable)
-}
-
-type Tab struct {
- Content Drawable
- Name string
- invalid bool
-}
-
-type TabStrip Tabs
-type TabContent Tabs
-
-func NewTabs() *Tabs {
- tabs := &Tabs{}
- tabs.TabStrip = (*TabStrip)(tabs)
- tabs.TabContent = (*TabContent)(tabs)
- return tabs
-}
-
-func (tabs *Tabs) Add(content Drawable, name string) {
- tabs.Tabs = append(tabs.Tabs, &Tab{
- Content: content,
- Name: name,
- })
- tabs.TabStrip.Invalidate()
- content.OnInvalidate(tabs.invalidateChild)
-}
-
-func (tabs *Tabs) invalidateChild(d Drawable) {
- for i, tab := range tabs.Tabs {
- if tab.Content == d {
- if i == tabs.Selected {
- tabs.TabContent.Invalidate()
- }
- return
- }
- }
-}
-
-func (tabs *Tabs) Remove(content Drawable) {
- for i, tab := range tabs.Tabs {
- if tab.Content == content {
- tabs.Tabs = append(tabs.Tabs[:i], tabs.Tabs[i+1:]...)
- break
- }
- }
- tabs.TabStrip.Invalidate()
-}
-
-func (tabs *Tabs) Select(index int) {
- if tabs.Selected != index {
- tabs.Selected = index
- tabs.TabStrip.Invalidate()
- tabs.TabContent.Invalidate()
- }
-}
-
-// TODO: Color repository
-func (strip *TabStrip) Draw(ctx *Context) {
- x := 0
- for i, tab := range strip.Tabs {
- cell := tb.Cell{
- Fg: tb.ColorBlack,
- Bg: tb.ColorWhite,
- }
- if strip.Selected == i {
- cell.Fg = tb.ColorDefault
- cell.Bg = tb.ColorDefault
- }
- x += ctx.Printf(x, 0, cell, " %s ", tab.Name)
- }
- cell := tb.Cell{
- Fg: tb.ColorBlack,
- Bg: tb.ColorWhite,
- }
- ctx.Fill(x, 0, ctx.Width()-x, 1, cell)
-}
-
-func (strip *TabStrip) Invalidate() {
- if strip.onInvalidateStrip != nil {
- strip.onInvalidateStrip(strip)
- }
-}
-
-func (strip *TabStrip) OnInvalidate(onInvalidate func(d Drawable)) {
- strip.onInvalidateStrip = onInvalidate
-}
-
-func (content *TabContent) Draw(ctx *Context) {
- tab := content.Tabs[content.Selected]
- tab.Content.Draw(ctx)
-}
-
-func (content *TabContent) Invalidate() {
- if content.onInvalidateContent != nil {
- content.onInvalidateContent(content)
- }
-}
-
-func (content *TabContent) OnInvalidate(onInvalidate func(d Drawable)) {
- content.onInvalidateContent = onInvalidate
-}
diff --git a/ui/text.go b/ui/text.go
deleted file mode 100644
index 6164837..0000000
--- a/ui/text.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package ui
-
-import (
- "github.com/mattn/go-runewidth"
- tb "github.com/nsf/termbox-go"
-)
-
-const (
- TEXT_LEFT = iota
- TEXT_CENTER = iota
- TEXT_RIGHT = iota
-)
-
-type Text struct {
- text string
- strategy uint
- fg tb.Attribute
- bg tb.Attribute
- onInvalidate func(d Drawable)
-}
-
-func NewText(text string) *Text {
- return &Text{text: text}
-}
-
-func (t *Text) Text(text string) *Text {
- t.text = text
- t.Invalidate()
- return t
-}
-
-func (t *Text) Strategy(strategy uint) *Text {
- t.strategy = strategy
- t.Invalidate()
- return t
-}
-
-func (t *Text) Color(fg tb.Attribute, bg tb.Attribute) *Text {
- t.fg = fg
- t.bg = bg
- t.Invalidate()
- return t
-}
-
-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
- }
- 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)
-}
-
-func (t *Text) OnInvalidate(onInvalidate func(d Drawable)) {
- t.onInvalidate = onInvalidate
-}
-
-func (t *Text) Invalidate() {
- if t.onInvalidate != nil {
- t.onInvalidate(t)
- }
-}
diff --git a/ui/ui.go b/ui/ui.go
deleted file mode 100644
index 9ea037c..0000000
--- a/ui/ui.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package ui
-
-import (
- tb "github.com/nsf/termbox-go"
-
- "git.sr.ht/~sircmpwn/aerc2/config"
-)
-
-type UI struct {
- Exit bool
- Content Drawable
- ctx *Context
-
- interactive []Interactive
-
- tbEvents chan tb.Event
- invalidations chan interface{}
-}
-
-func Initialize(conf *config.AercConfig, content Drawable) (*UI, error) {
- if err := tb.Init(); err != nil {
- return nil, err
- }
- width, height := tb.Size()
- state := UI{
- Content: content,
- ctx: NewContext(width, height),
-
- tbEvents: make(chan tb.Event, 10),
- invalidations: make(chan interface{}),
- }
- tb.SetInputMode(tb.InputEsc | tb.InputMouse)
- tb.SetOutputMode(tb.Output256)
- go (func() {
- for !state.Exit {
- state.tbEvents <- tb.PollEvent()
- }
- })()
- go (func() { state.invalidations <- nil })()
- content.OnInvalidate(func(_ Drawable) {
- go (func() { state.invalidations <- nil })()
- })
- return &state, nil
-}
-
-func (state *UI) Close() {
- tb.Close()
-}
-
-func (state *UI) Tick() bool {
- select {
- case event := <-state.tbEvents:
- switch event.Type {
- case tb.EventKey:
- if event.Key == tb.KeyEsc {
- state.Exit = true
- }
- case tb.EventResize:
- tb.Clear(tb.ColorDefault, tb.ColorDefault)
- state.ctx = NewContext(event.Width, event.Height)
- state.Content.Invalidate()
- }
- if state.interactive != nil {
- for _, i := range state.interactive {
- i.Event(event)
- }
- }
- case <-state.invalidations:
- state.Content.Draw(state.ctx)
- tb.Flush()
- default:
- return false
- }
- return true
-}
-
-func (state *UI) AddInteractive(i Interactive) {
- state.interactive = append(state.interactive, i)
-}