huge refactor
This commit is contained in:
parent
322b954149
commit
d335211770
@ -1,13 +1,12 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"git.tordarus.net/tordarus/buf2d"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
func drawBuffer(scr tcell.Screen, buf *buf2d.Buffer) {
|
||||
buf.Draw(func(x, y int, cn rune) {
|
||||
scr.SetContent(x, y, cn, nil, tcell.StyleDefault)
|
||||
func drawBuffer(scr tcell.Screen, buf *ViewBuffer) {
|
||||
buf.ForEach(func(x, y int, rn Rune) {
|
||||
scr.SetContent(x, y, rn.Rn, nil, rn.Style)
|
||||
})
|
||||
scr.Show()
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package tui
|
||||
|
||||
import "github.com/gdamore/tcell"
|
||||
|
||||
type Events interface {
|
||||
OnKeyPressed(key tcell.Key)
|
||||
OnKeyPressed(event *KeyEvent) (consumed bool)
|
||||
}
|
||||
|
16
go.mod
Normal file
16
go.mod
Normal file
@ -0,0 +1,16 @@
|
||||
module git.tordarus.net/Tordarus/tui
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
git.tordarus.net/Tordarus/buf2d v1.1.0
|
||||
github.com/gdamore/tcell v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 // indirect
|
||||
golang.org/x/text v0.3.0 // indirect
|
||||
)
|
14
go.sum
Normal file
14
go.sum
Normal file
@ -0,0 +1,14 @@
|
||||
git.tordarus.net/Tordarus/buf2d v1.1.0 h1:rIZjD7yeX5XK2D1h75ET5Og0u/NQF3eVonnC5aaqVkQ=
|
||||
git.tordarus.net/Tordarus/buf2d v1.1.0/go.mod h1:XXPpS8nQK0gUI0ki7ftV/qlprsGCRWFVSD4ybvDuUL8=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
||||
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
60
rune.go
Normal file
60
rune.go
Normal file
@ -0,0 +1,60 @@
|
||||
package tui
|
||||
|
||||
import "regexp"
|
||||
|
||||
type Rune struct {
|
||||
Rn rune
|
||||
Style Style
|
||||
}
|
||||
|
||||
var DefaultRune = Rune{' ', StyleDefault}
|
||||
|
||||
// Text represents a string with rune-based styling
|
||||
type Text struct {
|
||||
str string
|
||||
style []Style
|
||||
}
|
||||
|
||||
// Txt returns a Text containing the given str
|
||||
// using the default style
|
||||
func Txt(str string) *Text {
|
||||
styles := make([]Style, 0, len(str))
|
||||
for range str {
|
||||
styles = append(styles, StyleDefault)
|
||||
}
|
||||
return &Text{str: str, style: styles}
|
||||
}
|
||||
|
||||
// Len returns the amount of runes in t
|
||||
func (t *Text) Len() int {
|
||||
return len(t.style)
|
||||
}
|
||||
|
||||
// AppendString appends str with default styling to t
|
||||
func (t *Text) AppendString(str string) {
|
||||
t.AppendText(Txt(str))
|
||||
}
|
||||
|
||||
// PrependString prepends str with default styling to t
|
||||
func (t *Text) PrependString(str string) {
|
||||
newTxt := Txt(str)
|
||||
newTxt.AppendText(t)
|
||||
*t = *newTxt
|
||||
}
|
||||
|
||||
// AppendText appends txt to t
|
||||
func (t *Text) AppendText(txt *Text) {
|
||||
t.str += txt.str
|
||||
t.style = append(t.style, txt.style...)
|
||||
}
|
||||
|
||||
// Style applies the given style to the part of t between startIndex (inclusive) and endIndex (exclusive)
|
||||
func (t *Text) Style(style Style, startIndex, endIndex int) {
|
||||
for i := startIndex; i < endIndex; i++ {
|
||||
t.style[i] = style
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Text) StyleRegex(style Style, pattern *regexp.Regexp) {
|
||||
// TODO
|
||||
}
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.tordarus.net/tordarus/buf2d"
|
||||
"git.tordarus.net/Tordarus/buf2d"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
@ -38,7 +38,7 @@ func (s *Screen) eventloop() {
|
||||
go s.Redraw()
|
||||
case *tcell.EventKey:
|
||||
go func() {
|
||||
s.Root.OnKeyPressed(event.Key())
|
||||
s.Root.OnKeyPressed(event)
|
||||
s.Redraw()
|
||||
}()
|
||||
default:
|
||||
@ -53,6 +53,8 @@ func (s *Screen) Start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.scr.Fini()
|
||||
|
||||
s.Redraw()
|
||||
return <-s.stopCh
|
||||
}
|
||||
@ -67,7 +69,7 @@ func (s *Screen) StopWithError(err error) {
|
||||
|
||||
func (s *Screen) Redraw() {
|
||||
w, h := s.scr.Size()
|
||||
buf := buf2d.NewBuffer(w, h)
|
||||
buf := buf2d.NewBuffer(w, h, DefaultRune)
|
||||
s.Root.Draw(buf)
|
||||
drawBuffer(s.scr, buf)
|
||||
}
|
||||
|
@ -4,22 +4,28 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"tui"
|
||||
"tui/views"
|
||||
|
||||
"git.tordarus.net/Tordarus/tui"
|
||||
"git.tordarus.net/Tordarus/tui/views"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
func TestScreen(t *testing.T) {
|
||||
eventView := views.NewEventView()
|
||||
textView := views.NewTextView("hello world")
|
||||
eventView := views.NewEventView(textView)
|
||||
screen, err := tui.NewScreen(eventView)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
eventView.KeyPressed = func(key tcell.Key) {
|
||||
screen.StopWithError(errors.New(fmt.Sprintf("%#v", key)))
|
||||
eventView.KeyPressed = func(event *tui.KeyEvent) (consumed bool) {
|
||||
if event.Key() == tcell.KeyCtrlC {
|
||||
screen.StopWithError(errors.New(fmt.Sprintf("key: %#v | rune: %s", event.Key(), string(event.Rune()))))
|
||||
}
|
||||
|
||||
//textView.Text = event.When().String()
|
||||
return true
|
||||
}
|
||||
|
||||
err = screen.Start()
|
||||
|
13
types.go
Normal file
13
types.go
Normal file
@ -0,0 +1,13 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"git.tordarus.net/Tordarus/buf2d"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
type ViewBuffer = buf2d.Buffer[Rune]
|
||||
type KeyEvent = tcell.EventKey
|
||||
type Style = tcell.Style
|
||||
type Color = tcell.Color
|
||||
|
||||
var StyleDefault Style = tcell.StyleDefault
|
31
utils.go
Normal file
31
utils.go
Normal file
@ -0,0 +1,31 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// WriteString writes a whole string to the buffer at position (x,y)
|
||||
// no word wrap is applied at all. If the string does not fit, it will be truncated
|
||||
func WriteString(b *ViewBuffer, str string, style Style, x, y int) {
|
||||
dx := x
|
||||
for _, r := range str {
|
||||
if dx >= b.Width() {
|
||||
return
|
||||
}
|
||||
b.Set(dx, y, Rune{r, style})
|
||||
dx++
|
||||
}
|
||||
}
|
||||
|
||||
// WriteMultiLineString writes a multi-line string to the buffer at position (x,y)
|
||||
// no word wrap is applied at all. If a line does not fit horizontally, it will be truncated
|
||||
// All lines which do not fit vertically will be truncated as well
|
||||
func WriteMultiLineString(b *ViewBuffer, str string, style Style, x, y int) {
|
||||
lines := strings.Split(str, "\n")
|
||||
for dy, line := range lines {
|
||||
if dy >= b.Height() {
|
||||
return
|
||||
}
|
||||
WriteString(b, line, style, x, y+dy)
|
||||
}
|
||||
}
|
42
view.go
42
view.go
@ -1,18 +1,40 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"git.tordarus.net/tordarus/buf2d"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
|
||||
// View defines the behavior of any element displayable on screen
|
||||
// To define custom Views, it is recommended to add ViewTmpl
|
||||
// as the promoted anonymous field for your custom View struct.
|
||||
// It implements the View interface with useful default behavior
|
||||
type View interface {
|
||||
Events
|
||||
|
||||
SetForeground(color tcell.Color)
|
||||
Foreground() tcell.Color
|
||||
SetForeground(color Color)
|
||||
Foreground() Color
|
||||
|
||||
SetBackground(color tcell.Color)
|
||||
Background() tcell.Color
|
||||
SetBackground(color Color)
|
||||
Background() Color
|
||||
|
||||
Draw(*buf2d.Buffer)
|
||||
Style() Style
|
||||
|
||||
Draw(*ViewBuffer)
|
||||
}
|
||||
|
||||
// Group defines the behavior of a View which can hold multiple sub views
|
||||
// To define custom Groups, it is recommended to add GroupTmpl
|
||||
// as the promoted anonymous field for your custom Wrapper struct.
|
||||
// It implements the Group interface with useful default behavior
|
||||
type Group interface {
|
||||
View
|
||||
|
||||
Children() []View
|
||||
}
|
||||
|
||||
// Wrapper defines the behavior of a GroupView which can hold exactly one sub view
|
||||
// To define custom Wrappers, it is recommended to add WrapperTmpl
|
||||
// as the promoted anonymous field for your custom Wrapper struct.
|
||||
// It implements the Wrapper interface with useful default behavior
|
||||
type Wrapper interface {
|
||||
Group
|
||||
|
||||
SetView(View)
|
||||
View() View
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
package tui
|
||||
|
||||
type ViewGroup interface {
|
||||
View
|
||||
Children() []*View
|
||||
}
|
||||
// TODO GroupTmpl
|
||||
|
@ -1,22 +1,27 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"tui"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"git.tordarus.net/Tordarus/tui"
|
||||
)
|
||||
|
||||
type EventView struct {
|
||||
tui.ViewTmpl
|
||||
KeyPressed func(key tcell.Key)
|
||||
tui.WrapperTmpl
|
||||
|
||||
View tui.View
|
||||
KeyPressed func(event *tui.KeyEvent) (consumed bool)
|
||||
}
|
||||
|
||||
func (v *EventView) OnKeyPressed(key tcell.Key) {
|
||||
func NewEventView(view tui.View) *EventView {
|
||||
return &EventView{View: view}
|
||||
}
|
||||
|
||||
func (v *EventView) OnKeyPressed(event *tui.KeyEvent) (consumed bool) {
|
||||
if v.KeyPressed != nil {
|
||||
v.KeyPressed(key)
|
||||
return v.KeyPressed(event)
|
||||
}
|
||||
return v.ViewTmpl.OnKeyPressed(event)
|
||||
}
|
||||
|
||||
func NewEventView() *EventView {
|
||||
return &EventView{}
|
||||
func (v *EventView) Draw(buf *tui.ViewBuffer) {
|
||||
v.View.Draw(buf)
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"tui"
|
||||
|
||||
"git.tordarus.net/tordarus/buf2d"
|
||||
"git.tordarus.net/Tordarus/tui"
|
||||
)
|
||||
|
||||
type TextView struct {
|
||||
@ -13,8 +11,8 @@ type TextView struct {
|
||||
|
||||
var _ tui.View = &TextView{}
|
||||
|
||||
func (v *TextView) Draw(buf *buf2d.Buffer) {
|
||||
buf.WriteMultiLineString(v.Text, 0, 0)
|
||||
func (v *TextView) Draw(buf *tui.ViewBuffer) {
|
||||
tui.WriteMultiLineString(buf, v.Text, v.Style(), 0, 0)
|
||||
}
|
||||
|
||||
func NewTextView(text string) *TextView {
|
||||
|
57
viewtmpl.go
57
viewtmpl.go
@ -1,45 +1,44 @@
|
||||
package tui
|
||||
|
||||
import (
|
||||
"git.tordarus.net/tordarus/buf2d"
|
||||
"github.com/gdamore/tcell"
|
||||
)
|
||||
import "github.com/gdamore/tcell"
|
||||
|
||||
type ViewTmpl struct {
|
||||
view View
|
||||
|
||||
foreground tcell.Color
|
||||
background tcell.Color
|
||||
foreground *Color
|
||||
background *Color
|
||||
}
|
||||
|
||||
var _ View = &ViewTmpl{}
|
||||
|
||||
func NewViewTmpl(v View) *ViewTmpl {
|
||||
return &ViewTmpl{
|
||||
view: v,
|
||||
func (v *ViewTmpl) Draw(buf *ViewBuffer) {
|
||||
buf.Fill(DefaultRune)
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) OnKeyPressed(event *KeyEvent) (consumed bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) Style() Style {
|
||||
return StyleDefault.Background(v.Background()).Foreground(v.Foreground())
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) Foreground() Color {
|
||||
if v.foreground == nil {
|
||||
return tcell.ColorDefault
|
||||
}
|
||||
return *v.foreground
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) Draw(buf *buf2d.Buffer) {
|
||||
buf.Fill(' ')
|
||||
func (v *ViewTmpl) SetForeground(color Color) {
|
||||
v.foreground = &color
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) OnKeyPressed(key tcell.Key) {
|
||||
|
||||
func (v *ViewTmpl) Background() Color {
|
||||
if v.background == nil {
|
||||
return tcell.ColorDefault
|
||||
}
|
||||
return *v.background
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) Foreground() tcell.Color {
|
||||
return v.foreground
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) SetForeground(color tcell.Color) {
|
||||
v.foreground = color
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) Background() tcell.Color {
|
||||
return v.background
|
||||
}
|
||||
|
||||
func (v *ViewTmpl) SetBackground(color tcell.Color) {
|
||||
v.background = color
|
||||
func (v *ViewTmpl) SetBackground(color Color) {
|
||||
v.background = &color
|
||||
}
|
||||
|
74
wrappertmpl.go
Normal file
74
wrappertmpl.go
Normal file
@ -0,0 +1,74 @@
|
||||
package tui
|
||||
|
||||
import "github.com/gdamore/tcell"
|
||||
|
||||
type WrapperTmpl struct {
|
||||
ViewTmpl
|
||||
view View
|
||||
}
|
||||
|
||||
var _ Wrapper = &WrapperTmpl{}
|
||||
|
||||
func (v *WrapperTmpl) Draw(buf *ViewBuffer) {
|
||||
if v.view != nil {
|
||||
v.view.Draw(buf)
|
||||
} else {
|
||||
v.ViewTmpl.Draw(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) OnKeyPressed(event *KeyEvent) (consumed bool) {
|
||||
if v.view != nil {
|
||||
return v.view.OnKeyPressed(event)
|
||||
}
|
||||
return v.ViewTmpl.OnKeyPressed(event)
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) Style() Style {
|
||||
if v.view != nil {
|
||||
return v.view.Style()
|
||||
}
|
||||
return v.ViewTmpl.Style()
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) Foreground() Color {
|
||||
if v.view != nil {
|
||||
return v.view.Foreground()
|
||||
}
|
||||
return v.ViewTmpl.Foreground()
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) SetForeground(color Color) {
|
||||
if v.view != nil {
|
||||
v.view.SetForeground(color)
|
||||
} else {
|
||||
v.ViewTmpl.SetForeground(color)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) Background() Color {
|
||||
if v.background == nil {
|
||||
return tcell.ColorDefault
|
||||
}
|
||||
return *v.background
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) SetBackground(color Color) {
|
||||
if v.view != nil {
|
||||
v.view.SetBackground(color)
|
||||
} else {
|
||||
v.ViewTmpl.SetBackground(color)
|
||||
}
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) Children() []View {
|
||||
return []View{v.view}
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) View() View {
|
||||
return v.view
|
||||
}
|
||||
|
||||
func (v *WrapperTmpl) SetView(view View) {
|
||||
v.view = view
|
||||
}
|
Loading…
Reference in New Issue
Block a user