migrated to git.milar.in
This commit is contained in:
parent
67b65231fa
commit
2dbd0cc15e
3
go.mod
3
go.mod
@ -4,7 +4,8 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
git.tordarus.net/Tordarus/adverr v0.2.0
|
git.tordarus.net/Tordarus/adverr v0.2.0
|
||||||
git.tordarus.net/Tordarus/buf2d v1.1.4
|
git.tordarus.net/Tordarus/buf2d v1.1.6
|
||||||
|
git.tordarus.net/Tordarus/dstruct v0.0.3
|
||||||
github.com/gdamore/tcell v1.4.0
|
github.com/gdamore/tcell v1.4.0
|
||||||
github.com/mattn/go-runewidth v0.0.7
|
github.com/mattn/go-runewidth v0.0.7
|
||||||
)
|
)
|
||||||
|
6
go.sum
6
go.sum
@ -1,7 +1,9 @@
|
|||||||
git.tordarus.net/Tordarus/adverr v0.2.0 h1:kLYjR2/Vb2GHiSAMvAv+WPNaHR9BRphKanf8H/pCZdA=
|
git.tordarus.net/Tordarus/adverr v0.2.0 h1:kLYjR2/Vb2GHiSAMvAv+WPNaHR9BRphKanf8H/pCZdA=
|
||||||
git.tordarus.net/Tordarus/adverr v0.2.0/go.mod h1:XRf0+7nhOkIEr0gi9DUG4RvV2KaOFB0fYPDaR1KLenw=
|
git.tordarus.net/Tordarus/adverr v0.2.0/go.mod h1:XRf0+7nhOkIEr0gi9DUG4RvV2KaOFB0fYPDaR1KLenw=
|
||||||
git.tordarus.net/Tordarus/buf2d v1.1.4 h1:5R33Bq/no3uQIk7Tql6z55LI635DHeXQ7STNz0R7FQQ=
|
git.tordarus.net/Tordarus/buf2d v1.1.6 h1:qBLHSRj0eDxaG/IOUncJpWr1xwEKD4SCZReLo5r5eJw=
|
||||||
git.tordarus.net/Tordarus/buf2d v1.1.4/go.mod h1:XXPpS8nQK0gUI0ki7ftV/qlprsGCRWFVSD4ybvDuUL8=
|
git.tordarus.net/Tordarus/buf2d v1.1.6/go.mod h1:XXPpS8nQK0gUI0ki7ftV/qlprsGCRWFVSD4ybvDuUL8=
|
||||||
|
git.tordarus.net/Tordarus/dstruct v0.0.3 h1:cnUOM2rf96skIXGwBhSyzGMcT65ks8lFrOjpg6k23K8=
|
||||||
|
git.tordarus.net/Tordarus/dstruct v0.0.3/go.mod h1:RvLL2G4lUCGzwr8KaBGQRi3qlMG0WTgGhcVN6iyZZuw=
|
||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
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/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 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package views
|
package layouts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.tordarus.net/Tordarus/tui"
|
"git.tordarus.net/Tordarus/tui"
|
@ -1,4 +1,4 @@
|
|||||||
package views
|
package layouts
|
||||||
|
|
||||||
import "git.tordarus.net/Tordarus/tui"
|
import "git.tordarus.net/Tordarus/tui"
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package views
|
package layouts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.tordarus.net/Tordarus/tui"
|
"git.tordarus.net/Tordarus/tui"
|
3
layouts/layout_grid.go
Normal file
3
layouts/layout_grid.go
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package layouts
|
||||||
|
|
||||||
|
// TODO
|
@ -1,4 +1,4 @@
|
|||||||
package views
|
package layouts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.tordarus.net/Tordarus/tui"
|
"git.tordarus.net/Tordarus/tui"
|
90
layouts/utils.go
Normal file
90
layouts/utils.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package layouts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"git.tordarus.net/Tordarus/tui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func min(x, y int) int {
|
||||||
|
if x < y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
func max(x, y int) int {
|
||||||
|
if x > y {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|
||||||
|
func limit(v, minv, maxv int) int {
|
||||||
|
return min(max(v, minv), maxv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func iff[T any](condition bool, trueValue, falseValue T) T {
|
||||||
|
if condition {
|
||||||
|
return trueValue
|
||||||
|
}
|
||||||
|
return falseValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type LayoutResult struct {
|
||||||
|
Sizes map[tui.View]tui.Size
|
||||||
|
|
||||||
|
Sum tui.Size
|
||||||
|
Min tui.Size
|
||||||
|
Max tui.Size
|
||||||
|
Pref tui.Size
|
||||||
|
|
||||||
|
Count int
|
||||||
|
|
||||||
|
VerticalNegativeCount int
|
||||||
|
HorizontalNegativeCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalculateLayoutResult(views []tui.View) *LayoutResult {
|
||||||
|
result := &LayoutResult{
|
||||||
|
Sizes: map[tui.View]tui.Size{},
|
||||||
|
|
||||||
|
Sum: tui.Size{Width: 0, Height: 0},
|
||||||
|
Min: tui.Size{Width: math.MaxInt, Height: math.MaxInt},
|
||||||
|
Max: tui.Size{Width: -1, Height: -1},
|
||||||
|
|
||||||
|
Count: 0,
|
||||||
|
|
||||||
|
VerticalNegativeCount: 0,
|
||||||
|
HorizontalNegativeCount: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, view := range views {
|
||||||
|
if view == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Count++
|
||||||
|
|
||||||
|
width, height := view.Layout()
|
||||||
|
result.Sizes[view] = tui.Size{Width: width, Height: height}
|
||||||
|
|
||||||
|
if width > 0 {
|
||||||
|
result.Sum.Width += width
|
||||||
|
result.Min.Width = min(result.Min.Width, width)
|
||||||
|
result.Max.Width = max(result.Max.Width, width)
|
||||||
|
} else if width < 0 {
|
||||||
|
result.HorizontalNegativeCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if height > 0 {
|
||||||
|
result.Sum.Height += height
|
||||||
|
result.Min.Height = min(result.Min.Height, height)
|
||||||
|
result.Max.Height = max(result.Max.Height, height)
|
||||||
|
} else if height < 0 {
|
||||||
|
result.VerticalNegativeCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
31
modals/modal_info.go
Normal file
31
modals/modal_info.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package modals
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.tordarus.net/Tordarus/tui"
|
||||||
|
"git.tordarus.net/Tordarus/tui/views"
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InfoModal struct {
|
||||||
|
*views.FrameView
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInfoModal(message string) *InfoModal {
|
||||||
|
tv := views.NewTextView(message)
|
||||||
|
bv := views.NewBorderView(views.NewMarginView(tv, 0, 1, 0, 1))
|
||||||
|
fv := views.NewFrameView(bv)
|
||||||
|
fv.DontClearBuffer = true
|
||||||
|
|
||||||
|
m := &InfoModal{
|
||||||
|
FrameView: fv,
|
||||||
|
}
|
||||||
|
|
||||||
|
m.KeyPressed = func(event *tui.KeyEvent) (consumed bool) {
|
||||||
|
if event.Key() == tcell.KeyEnter || event.Key() == tcell.KeyESC {
|
||||||
|
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
51
screen.go
51
screen.go
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"git.tordarus.net/Tordarus/adverr"
|
"git.tordarus.net/Tordarus/adverr"
|
||||||
"git.tordarus.net/Tordarus/buf2d"
|
"git.tordarus.net/Tordarus/buf2d"
|
||||||
|
"git.tordarus.net/Tordarus/dstruct"
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,6 +17,9 @@ type Screen struct {
|
|||||||
|
|
||||||
stopCh chan error
|
stopCh chan error
|
||||||
redrawCh chan struct{}
|
redrawCh chan struct{}
|
||||||
|
started bool
|
||||||
|
|
||||||
|
modals *dstruct.Stack[View]
|
||||||
|
|
||||||
// Root is the root view which is currently shown on screen
|
// Root is the root view which is currently shown on screen
|
||||||
Root View
|
Root View
|
||||||
@ -32,6 +36,7 @@ func NewScreen(root View) (*Screen, error) {
|
|||||||
scr: scr,
|
scr: scr,
|
||||||
stopCh: make(chan error, 1),
|
stopCh: make(chan error, 1),
|
||||||
redrawCh: make(chan struct{}, 1),
|
redrawCh: make(chan struct{}, 1),
|
||||||
|
modals: dstruct.NewStack[View](),
|
||||||
}
|
}
|
||||||
|
|
||||||
s.KeyPressed = CloseOnCtrlC(s)
|
s.KeyPressed = CloseOnCtrlC(s)
|
||||||
@ -49,9 +54,10 @@ func (s *Screen) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer s.scr.Fini()
|
defer s.scr.Fini()
|
||||||
//defer close(s.redrawCh)
|
defer close(s.redrawCh)
|
||||||
|
|
||||||
s.scr.EnableMouse()
|
s.scr.EnableMouse()
|
||||||
|
s.started = true
|
||||||
return <-s.stopCh
|
return <-s.stopCh
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +70,11 @@ func (s *Screen) StopWithError(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) onKeyPressed(event *KeyEvent) {
|
func (s *Screen) onKeyPressed(event *KeyEvent) {
|
||||||
|
if !s.modals.Empty() {
|
||||||
|
s.modals.Peek().OnKeyPressed(event)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if s.KeyPressed == nil || !s.KeyPressed(event) {
|
if s.KeyPressed == nil || !s.KeyPressed(event) {
|
||||||
s.Root.OnKeyPressed(event)
|
s.Root.OnKeyPressed(event)
|
||||||
}
|
}
|
||||||
@ -71,12 +82,20 @@ func (s *Screen) onKeyPressed(event *KeyEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) onMouseEvent(event *MouseEvent) {
|
func (s *Screen) onMouseEvent(event *MouseEvent) {
|
||||||
if s.MouseEvent == nil || !s.MouseEvent(event) {
|
|
||||||
s.Root.OnMouseEvent(event)
|
|
||||||
}
|
|
||||||
if event.Button != MouseButtonNone {
|
if event.Button != MouseButtonNone {
|
||||||
s.Redraw()
|
defer s.Redraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.modals.Empty() {
|
||||||
|
s.modals.Peek().OnMouseEvent(event)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.MouseEvent != nil && s.MouseEvent(event) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Root.OnMouseEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
|
func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
|
||||||
@ -89,7 +108,9 @@ func convertMouseEvent(original *tcell.EventMouse) *MouseEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) Redraw() {
|
func (s *Screen) Redraw() {
|
||||||
|
if s.started {
|
||||||
s.redrawCh <- struct{}{}
|
s.redrawCh <- struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Screen) eventloop() {
|
func (s *Screen) eventloop() {
|
||||||
@ -128,8 +149,18 @@ func (s *Screen) drawloop() {
|
|||||||
s.buf.Fill(DefaultRune)
|
s.buf.Fill(DefaultRune)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw root view
|
||||||
rw, rh := s.Root.Layout()
|
rw, rh := s.Root.Layout()
|
||||||
s.Root.Draw(truncateBuffer(s.buf, rw, rh))
|
s.Root.Draw(truncateBuffer(s.buf, rw, rh))
|
||||||
|
|
||||||
|
// draw modals
|
||||||
|
for i := 0; i < s.modals.Size(); i++ {
|
||||||
|
v := s.modals.PeekAt(i)
|
||||||
|
mw, mh := v.Layout()
|
||||||
|
v.Draw(s.buf.Sub(0, 0, iff(mw >= 0, mw, s.buf.Width()), iff(mh >= 0, mh, s.buf.Height())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw buffer onto screen
|
||||||
drawBuffer(s.scr, s.buf)
|
drawBuffer(s.scr, s.buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,3 +174,13 @@ func (s *Screen) handlePanic(msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Screen) OpenModal(v View) {
|
||||||
|
s.modals.Push(v)
|
||||||
|
s.Redraw()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Screen) CloseModal() {
|
||||||
|
s.modals.Pop()
|
||||||
|
s.Redraw()
|
||||||
|
}
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.tordarus.net/Tordarus/tui"
|
"git.tordarus.net/Tordarus/tui"
|
||||||
|
"git.tordarus.net/Tordarus/tui/layouts"
|
||||||
|
"git.tordarus.net/Tordarus/tui/modals"
|
||||||
"git.tordarus.net/Tordarus/tui/views"
|
"git.tordarus.net/Tordarus/tui/views"
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
@ -38,7 +40,7 @@ func TestScrollView(t *testing.T) {
|
|||||||
textViews[i].SetStyle(textViews[i].Style().Foreground(tcell.ColorBlack).Background(tcell.Color(rand.Intn(int(tcell.ColorYellowGreen)))))
|
textViews[i].SetStyle(textViews[i].Style().Foreground(tcell.ColorBlack).Background(tcell.Color(rand.Intn(int(tcell.ColorYellowGreen)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
flowLayout := views.NewFlowLayout(tui.Vertical)
|
flowLayout := layouts.NewFlowLayout(tui.Vertical)
|
||||||
flowLayout.AppendViews(textViews...)
|
flowLayout.AppendViews(textViews...)
|
||||||
|
|
||||||
scrollView := views.NewScrollView(flowLayout)
|
scrollView := views.NewScrollView(flowLayout)
|
||||||
@ -128,6 +130,9 @@ func TestMousePosition(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modal := modals.NewInfoModal("Programm wird geschlossen")
|
||||||
|
screen.OpenModal(modal)
|
||||||
|
|
||||||
if err := screen.Start(); err != nil {
|
if err := screen.Start(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
@ -153,7 +158,7 @@ func TestFlowLayout(t *testing.T) {
|
|||||||
growView2 := views.NewGrowView(nil)
|
growView2 := views.NewGrowView(nil)
|
||||||
growView2.SetStyle(tui.StyleDefault.Background(tcell.ColorYellow))
|
growView2.SetStyle(tui.StyleDefault.Background(tcell.ColorYellow))
|
||||||
|
|
||||||
flowLayout := views.NewFlowLayout(tui.Vertical)
|
flowLayout := layouts.NewFlowLayout(tui.Vertical)
|
||||||
flowLayout.AppendViews(textView, growView, textView2)
|
flowLayout.AppendViews(textView, growView, textView2)
|
||||||
|
|
||||||
screen, err := tui.NewScreen(flowLayout)
|
screen, err := tui.NewScreen(flowLayout)
|
||||||
@ -181,7 +186,7 @@ func TestSeparatorLayout(t *testing.T) {
|
|||||||
growView2 := views.NewGrowView(nil)
|
growView2 := views.NewGrowView(nil)
|
||||||
growView2.SetStyle(tui.StyleDefault.Background(tcell.ColorYellow))
|
growView2.SetStyle(tui.StyleDefault.Background(tcell.ColorYellow))
|
||||||
|
|
||||||
separatorLayout := views.NewSeparatorLayout(tui.Vertical)
|
separatorLayout := layouts.NewSeparatorLayout(tui.Vertical)
|
||||||
separatorLayout.AppendView(frameView, 1)
|
separatorLayout.AppendView(frameView, 1)
|
||||||
separatorLayout.AppendView(growView, 1)
|
separatorLayout.AppendView(growView, 1)
|
||||||
separatorLayout.AppendView(textView2, 1)
|
separatorLayout.AppendView(textView2, 1)
|
||||||
@ -260,13 +265,13 @@ func TestBorderLayout(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
borderLayout := views.NewBorderLayout()
|
borderLayout := layouts.NewBorderLayout()
|
||||||
borderLayout.SetStyle(tui.StyleDefault.Background(tcell.ColorPurple))
|
borderLayout.SetStyle(tui.StyleDefault.Background(tcell.ColorPurple))
|
||||||
borderLayout.SetView(topView, views.Top)
|
borderLayout.SetView(topView, layouts.Top)
|
||||||
borderLayout.SetView(bottomView, views.Bottom)
|
borderLayout.SetView(bottomView, layouts.Bottom)
|
||||||
borderLayout.SetView(leftView, views.Left)
|
borderLayout.SetView(leftView, layouts.Left)
|
||||||
borderLayout.SetView(rightView, views.Right)
|
borderLayout.SetView(rightView, layouts.Right)
|
||||||
borderLayout.SetView(centerView, views.Center)
|
borderLayout.SetView(centerView, layouts.Center)
|
||||||
|
|
||||||
screen, err := tui.NewScreen(borderLayout)
|
screen, err := tui.NewScreen(borderLayout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
21
tmpl_modal.go
Normal file
21
tmpl_modal.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package tui
|
||||||
|
|
||||||
|
type ModalTmpl[T any] struct {
|
||||||
|
WrapperTmpl
|
||||||
|
|
||||||
|
resultCh chan T
|
||||||
|
screen *Screen
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Modal[int] = &ModalTmpl[int]{}
|
||||||
|
|
||||||
|
func (m *ModalTmpl[T]) Open(s *Screen) <-chan T {
|
||||||
|
m.resultCh = make(chan T)
|
||||||
|
m.screen = s
|
||||||
|
return m.resultCh
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ModalTmpl[T]) Close(result T) {
|
||||||
|
m.resultCh <- result
|
||||||
|
m.screen.CloseModal() // TODO which modal
|
||||||
|
}
|
4
utils.go
4
utils.go
@ -127,8 +127,8 @@ func CloseOnKeyPressed(screen *Screen, key tcell.Key) func(event *KeyEvent) (con
|
|||||||
return func(event *KeyEvent) (consumed bool) {
|
return func(event *KeyEvent) (consumed bool) {
|
||||||
if event.Key() == key {
|
if event.Key() == key {
|
||||||
screen.Stop()
|
screen.Stop()
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
10
view.go
10
view.go
@ -38,3 +38,13 @@ type Wrapper interface {
|
|||||||
SetView(View)
|
SetView(View)
|
||||||
View() View
|
View() View
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modal defines the behavior of a Wrapper which captures
|
||||||
|
// all screen space and all events when opened and can return results.
|
||||||
|
// It can be used to make dialogs, alert boxes and context menus
|
||||||
|
type Modal[T any] interface {
|
||||||
|
Wrapper
|
||||||
|
|
||||||
|
Open(s *Screen) <-chan T
|
||||||
|
Close(result T)
|
||||||
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
package views
|
|
||||||
|
|
||||||
// TODO
|
|
@ -1,11 +1,5 @@
|
|||||||
package views
|
package views
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"git.tordarus.net/Tordarus/tui"
|
|
||||||
)
|
|
||||||
|
|
||||||
func min(x, y int) int {
|
func min(x, y int) int {
|
||||||
if x < y {
|
if x < y {
|
||||||
return x
|
return x
|
||||||
@ -30,61 +24,3 @@ func iff[T any](condition bool, trueValue, falseValue T) T {
|
|||||||
}
|
}
|
||||||
return falseValue
|
return falseValue
|
||||||
}
|
}
|
||||||
|
|
||||||
type LayoutResult struct {
|
|
||||||
Sizes map[tui.View]tui.Size
|
|
||||||
|
|
||||||
Sum tui.Size
|
|
||||||
Min tui.Size
|
|
||||||
Max tui.Size
|
|
||||||
Pref tui.Size
|
|
||||||
|
|
||||||
Count int
|
|
||||||
|
|
||||||
VerticalNegativeCount int
|
|
||||||
HorizontalNegativeCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func CalculateLayoutResult(views []tui.View) *LayoutResult {
|
|
||||||
result := &LayoutResult{
|
|
||||||
Sizes: map[tui.View]tui.Size{},
|
|
||||||
|
|
||||||
Sum: tui.Size{Width: 0, Height: 0},
|
|
||||||
Min: tui.Size{Width: math.MaxInt, Height: math.MaxInt},
|
|
||||||
Max: tui.Size{Width: -1, Height: -1},
|
|
||||||
|
|
||||||
Count: 0,
|
|
||||||
|
|
||||||
VerticalNegativeCount: 0,
|
|
||||||
HorizontalNegativeCount: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, view := range views {
|
|
||||||
if view == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Count++
|
|
||||||
|
|
||||||
width, height := view.Layout()
|
|
||||||
result.Sizes[view] = tui.Size{Width: width, Height: height}
|
|
||||||
|
|
||||||
if width > 0 {
|
|
||||||
result.Sum.Width += width
|
|
||||||
result.Min.Width = min(result.Min.Width, width)
|
|
||||||
result.Max.Width = max(result.Max.Width, width)
|
|
||||||
} else if width < 0 {
|
|
||||||
result.HorizontalNegativeCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
if height > 0 {
|
|
||||||
result.Sum.Height += height
|
|
||||||
result.Min.Height = min(result.Min.Height, height)
|
|
||||||
result.Max.Height = max(result.Max.Height, height)
|
|
||||||
} else if height < 0 {
|
|
||||||
result.VerticalNegativeCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,8 @@ import "git.tordarus.net/Tordarus/tui"
|
|||||||
type FrameView struct {
|
type FrameView struct {
|
||||||
tui.WrapperTmpl
|
tui.WrapperTmpl
|
||||||
Anchor tui.Anchor
|
Anchor tui.Anchor
|
||||||
|
|
||||||
|
DontClearBuffer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tui.Wrapper = &FrameView{}
|
var _ tui.Wrapper = &FrameView{}
|
||||||
@ -18,7 +20,9 @@ func NewFrameView(view tui.View) *FrameView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *FrameView) Draw(buf *tui.ViewBuffer) {
|
func (g *FrameView) Draw(buf *tui.ViewBuffer) {
|
||||||
|
if !g.DontClearBuffer {
|
||||||
g.ViewTmpl.Draw(buf)
|
g.ViewTmpl.Draw(buf)
|
||||||
|
}
|
||||||
|
|
||||||
w, h := g.View().Layout()
|
w, h := g.View().Layout()
|
||||||
w = iff(w >= 0, w, buf.Width())
|
w = iff(w >= 0, w, buf.Width())
|
||||||
|
Loading…
Reference in New Issue
Block a user