more views
This commit is contained in:
parent
dfa00f5fe3
commit
b797dc0b2c
@ -55,6 +55,46 @@ func TestFlowGroup(t *testing.T) {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestSeparatorGroup(t *testing.T) {
|
||||
textView := views.NewTextView("hello world!")
|
||||
textView.SetStyle(tui.StyleDefault.Background(tcell.ColorRed).Foreground(tcell.ColorBlack))
|
||||
|
||||
frameView := views.NewFrameView(textView)
|
||||
|
||||
textView2 := views.NewTextView("Hi!")
|
||||
textView2.SetStyle(tui.StyleDefault.Background(tcell.ColorBlue).Foreground(tcell.ColorYellow))
|
||||
|
||||
growView := views.NewGrowView()
|
||||
growView.SetStyle(tui.StyleDefault.Background(tcell.ColorGreen))
|
||||
|
||||
growView2 := views.NewGrowView()
|
||||
growView2.SetStyle(tui.StyleDefault.Background(tcell.ColorYellow))
|
||||
|
||||
separatorGroup := views.NewSeparatorGroup(tui.Vertical)
|
||||
separatorGroup.AppendView(frameView, 1)
|
||||
separatorGroup.AppendView(growView, 1)
|
||||
separatorGroup.AppendView(textView2, 1)
|
||||
|
||||
screen, err := tui.NewScreen(separatorGroup)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
screen.KeyPressed = func(event *tui.KeyEvent) (consumed bool) {
|
||||
textView.Text = event.When().String()
|
||||
|
||||
if event.Key() == tcell.KeyCtrlC {
|
||||
screen.StopWithError(errors.New(fmt.Sprintf("key: %#v | rune: %s", event.Key(), string(event.Rune()))))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
err = screen.Start()
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestBorderGroup(t *testing.T) {
|
||||
topView := views.NewConstrainView(nil)
|
||||
topView.SetStyle(tui.StyleDefault.Background(tcell.ColorBlue))
|
||||
|
22
types.go
22
types.go
@ -35,8 +35,22 @@ const (
|
||||
type Side uint8
|
||||
|
||||
const (
|
||||
Top Side = iota
|
||||
Bottom
|
||||
Left
|
||||
Right
|
||||
SideTop Side = iota
|
||||
SideBottom
|
||||
SideLeft
|
||||
SideRight
|
||||
)
|
||||
|
||||
type Anchor uint8
|
||||
|
||||
const (
|
||||
AnchorTopLeft Anchor = iota
|
||||
AnchorTop
|
||||
AnchorTopRight
|
||||
AnchorLeft
|
||||
AnchorCenter
|
||||
AnchorRight
|
||||
AnchorBottomLeft
|
||||
AnchorBottom
|
||||
AnchorBottomRight
|
||||
)
|
||||
|
25
utils.go
25
utils.go
@ -87,3 +87,28 @@ func iff[T any](condition bool, trueValue, falseValue T) T {
|
||||
}
|
||||
return falseValue
|
||||
}
|
||||
|
||||
func ConstrainBufferToAnchor(buf *ViewBuffer, anchor Anchor, width, height int) *ViewBuffer {
|
||||
switch anchor {
|
||||
default:
|
||||
fallthrough
|
||||
case AnchorTopLeft:
|
||||
return buf.Sub(0, 0, width, height)
|
||||
case AnchorTop:
|
||||
return buf.Sub(buf.Width()/2-width/2, 0, width, height)
|
||||
case AnchorTopRight:
|
||||
return buf.Sub(buf.Width()-width, 0, width, height)
|
||||
case AnchorLeft:
|
||||
return buf.Sub(0, buf.Height()/2-height/2, width, height)
|
||||
case AnchorCenter:
|
||||
return buf.Sub(buf.Width()/2-width/2, buf.Height()/2-height/2, width, height)
|
||||
case AnchorRight:
|
||||
return buf.Sub(buf.Width()-width, buf.Height()/2-height/2, width, height)
|
||||
case AnchorBottomLeft:
|
||||
return buf.Sub(0, buf.Height()-height, width, height)
|
||||
case AnchorBottom:
|
||||
return buf.Sub(buf.Width()/2-width/2, buf.Height()-height, width, height)
|
||||
case AnchorBottomRight:
|
||||
return buf.Sub(buf.Width()-width, buf.Height()-height, width, height)
|
||||
}
|
||||
}
|
||||
|
7
view.go
7
view.go
@ -10,7 +10,14 @@ type View interface {
|
||||
SetStyle(s Style)
|
||||
Style() Style
|
||||
|
||||
// Layout is usually called by the parent view to ask the view's preferred size.
|
||||
// If the parent view does not care about its preferred size, it might not be called at all.
|
||||
// Negative values indicate as much space as possible.
|
||||
Layout() (prefWidth, prefHeight int)
|
||||
|
||||
// Draw is called for each view when it should print itself onto the screen.
|
||||
// The parent view has full control of the ViewBuffer size
|
||||
// and may or may not use the values returned from Layout() to set the size.
|
||||
Draw(buf *ViewBuffer)
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"git.tordarus.net/Tordarus/tui"
|
||||
)
|
||||
|
||||
// BorderGroup ia a tui.Group which places its children in a linear layout
|
||||
// BorderGroup ia a tui.Group which places its children onto a given tui.Side
|
||||
type BorderGroup struct {
|
||||
tui.ViewTmpl
|
||||
views map[Slot]tui.View
|
||||
|
@ -39,6 +39,15 @@ func (g *FlowGroup) InsertView(v tui.View, index int) {
|
||||
g.views = append(g.views[:index], append([]tui.View{v}, g.views[index:]...)...)
|
||||
}
|
||||
|
||||
func (g *FlowGroup) RemoveView(v tui.View) {
|
||||
for index, view := range g.Views() {
|
||||
if view == v {
|
||||
g.views = append(g.views[:index], g.views[index:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *FlowGroup) Draw(buf *tui.ViewBuffer) {
|
||||
g.ViewTmpl.Draw(buf)
|
||||
|
||||
|
35
views/frameview.go
Normal file
35
views/frameview.go
Normal file
@ -0,0 +1,35 @@
|
||||
package views
|
||||
|
||||
import "git.tordarus.net/Tordarus/tui"
|
||||
|
||||
// FrameView is a tui.Wrapper which draws its view preferably with preferred size on its tui.Anchor point
|
||||
type FrameView struct {
|
||||
tui.WrapperTmpl
|
||||
Anchor tui.Anchor
|
||||
}
|
||||
|
||||
var _ tui.View = &FrameView{}
|
||||
|
||||
func NewFrameView(view tui.View) *FrameView {
|
||||
v := new(FrameView)
|
||||
v.SetView(view)
|
||||
v.Anchor = tui.AnchorCenter
|
||||
return v
|
||||
}
|
||||
|
||||
func (g *FrameView) Draw(buf *tui.ViewBuffer) {
|
||||
g.ViewTmpl.Draw(buf)
|
||||
|
||||
w, h := g.View().Layout()
|
||||
w = iff(w >= 0, w, buf.Width())
|
||||
h = iff(h >= 0, h, buf.Height())
|
||||
g.View().Draw(tui.ConstrainBufferToAnchor(buf, g.Anchor, w, h))
|
||||
}
|
||||
|
||||
func (v *FrameView) Layout() (prefWidth, prefHeight int) {
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
func (v *FrameView) Style() tui.Style {
|
||||
return v.ViewTmpl.Style()
|
||||
}
|
@ -18,10 +18,10 @@ func NewMarginView(view tui.View) *MarginView {
|
||||
}
|
||||
|
||||
func (g *MarginView) Draw(buf *tui.ViewBuffer) {
|
||||
x := g.Margin[tui.Left]
|
||||
y := g.Margin[tui.Top]
|
||||
w := buf.Width() - x - g.Margin[tui.Right]
|
||||
h := buf.Height() - y - g.Margin[tui.Bottom]
|
||||
x := g.Margin[tui.SideLeft]
|
||||
y := g.Margin[tui.SideTop]
|
||||
w := buf.Width() - x - g.Margin[tui.SideRight]
|
||||
h := buf.Height() - y - g.Margin[tui.SideBottom]
|
||||
|
||||
g.ViewTmpl.Draw(buf)
|
||||
g.View().Draw(buf.Sub(x, y, w, h))
|
||||
@ -29,8 +29,8 @@ func (g *MarginView) Draw(buf *tui.ViewBuffer) {
|
||||
|
||||
func (v *MarginView) Layout() (prefWidth, prefHeight int) {
|
||||
w, h := v.View().Layout()
|
||||
w = iff(w > 0, w+v.Margin[tui.Left]+v.Margin[tui.Right], w)
|
||||
h = iff(h > 0, h+v.Margin[tui.Top]+v.Margin[tui.Bottom], h)
|
||||
w = iff(w > 0, w+v.Margin[tui.SideLeft]+v.Margin[tui.SideRight], w)
|
||||
h = iff(h > 0, h+v.Margin[tui.SideTop]+v.Margin[tui.SideBottom], h)
|
||||
return w, h
|
||||
}
|
||||
|
||||
@ -40,9 +40,9 @@ func (v *MarginView) Style() tui.Style {
|
||||
|
||||
func (v *MarginView) SetMargin(top, right, bottom, left int) {
|
||||
v.Margin = map[tui.Side]int{
|
||||
tui.Top: top,
|
||||
tui.Right: right,
|
||||
tui.Bottom: bottom,
|
||||
tui.Left: left,
|
||||
tui.SideTop: top,
|
||||
tui.SideRight: right,
|
||||
tui.SideBottom: bottom,
|
||||
tui.SideLeft: left,
|
||||
}
|
||||
}
|
||||
|
111
views/separatorgroup.go
Normal file
111
views/separatorgroup.go
Normal file
@ -0,0 +1,111 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"git.tordarus.net/Tordarus/tui"
|
||||
)
|
||||
|
||||
// SeperatorGroup ia a tui.Group which separates
|
||||
type SeperatorGroup struct {
|
||||
tui.ViewTmpl
|
||||
views []tui.View
|
||||
|
||||
gravity map[tui.View]int
|
||||
gravitySum int
|
||||
|
||||
Orientation tui.Orientation
|
||||
}
|
||||
|
||||
var _ tui.Group = &SeperatorGroup{}
|
||||
|
||||
func NewSeparatorGroup(orientation tui.Orientation) *SeperatorGroup {
|
||||
return &SeperatorGroup{
|
||||
views: make([]tui.View, 0),
|
||||
gravity: map[tui.View]int{},
|
||||
Orientation: orientation,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) Views() []tui.View {
|
||||
return g.views[:]
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) AppendView(v tui.View, gravity int) {
|
||||
g.views = append(g.views, v)
|
||||
g.gravitySum += gravity
|
||||
g.gravity[v] = gravity
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) PrependView(v tui.View, gravity int) {
|
||||
g.views = append([]tui.View{v}, g.views...)
|
||||
g.gravitySum += gravity
|
||||
g.gravity[v] = gravity
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) InsertView(v tui.View, index int, gravity int) {
|
||||
g.views = append(g.views[:index], append([]tui.View{v}, g.views[index:]...)...)
|
||||
g.gravitySum += gravity
|
||||
g.gravity[v] = gravity
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) SetGravity(v tui.View, gravity int) {
|
||||
for _, view := range g.Views() {
|
||||
if view == v {
|
||||
g.gravitySum += gravity - g.gravity[v]
|
||||
g.gravity[v] = gravity
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) RemoveView(v tui.View) {
|
||||
for index, view := range g.Views() {
|
||||
if view == v {
|
||||
g.views = append(g.views[:index], g.views[index:]...)
|
||||
g.gravitySum -= g.gravity[v]
|
||||
delete(g.gravity, v)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) View(slot Slot) tui.View {
|
||||
return g.views[slot]
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) Draw(buf *tui.ViewBuffer) {
|
||||
g.ViewTmpl.Draw(buf)
|
||||
|
||||
if g.Orientation == tui.Horizontal {
|
||||
x := 0
|
||||
for _, v := range g.Views() {
|
||||
viewGravity := g.gravity[v]
|
||||
percentage := float64(viewGravity) / float64(g.gravitySum)
|
||||
width := int(percentage * float64(buf.Width()))
|
||||
v.Draw(buf.Sub(x, 0, width, buf.Height()))
|
||||
x += width
|
||||
}
|
||||
} else if g.Orientation == tui.Vertical {
|
||||
y := 0
|
||||
for _, v := range g.Views() {
|
||||
viewGravity := g.gravity[v]
|
||||
percentage := float64(viewGravity) / float64(g.gravitySum)
|
||||
height := int(percentage * float64(buf.Height()))
|
||||
v.Draw(buf.Sub(0, y, buf.Width(), height))
|
||||
y += height
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) Layout() (prefWidth, prefHeight int) {
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
func (g *SeperatorGroup) OnKeyPressed(event *tui.KeyEvent) (consumed bool) {
|
||||
for _, view := range g.Views() {
|
||||
if view.OnKeyPressed(event) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -13,6 +13,7 @@ type TextView struct {
|
||||
var _ tui.View = &TextView{}
|
||||
|
||||
func (v *TextView) Draw(buf *tui.ViewBuffer) {
|
||||
v.ViewTmpl.Draw(buf)
|
||||
tui.WriteMultiLineString(buf, v.Text, v.Style(), 0, 0)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user