Skip to content
This repository has been archived by the owner on Oct 13, 2021. It is now read-only.

Reset Label's cached size hint on Resize #84

Merged
merged 3 commits into from
Dec 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions label.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ func NewLabel(text string) *Label {
}
}

// Resize changes the size of the Widget.
func (l *Label) Resize(size image.Point) {
if l.Size() != size {
l.cacheSizeHint = nil
}
l.WidgetBase.Resize(size)
}

// Draw draws the label.
func (l *Label) Draw(p *Painter) {
lines := strings.Split(l.text, "\n")
Expand Down
151 changes: 151 additions & 0 deletions label_sizehint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package tui

import (
"image"
"testing"
)

var TailBoxTests = []struct {
Test string
Setup func() Widget
Want string
} {
{
Test: "draw small labels",
Setup: func() Widget {
return NewTailBox(
NewLabel("hello mom"),
NewLabel("hello dad"),
)
},
Want: `



hello mom
hello dad
`,
},
{
Test: "draw unwrapped labels",
Setup: func() Widget {
l1, l2 := NewLabel("hello muddah"), NewLabel("hello faddah")
return NewTailBox(l1, l2)
},
Want: `



hello mudd
hello fadd
`,
},
{
Test: "draw wrapped labels",
Setup: func() Widget {
l1, l2 := NewLabel("hello muddah"), NewLabel("hello faddah")
l1.SetWordWrap(true)
l2.SetWordWrap(true)
return NewTailBox(l1, l2)
},
Want: `

hello
muddah
hello
faddah
`,
},


}

func TestTailBox(t *testing.T) {
for _, tt := range TailBoxTests {
tt := tt
t.Run(tt.Test, func(t *testing.T) {
surface := NewTestSurface(10, 5)
p := NewPainter(surface, NewTheme())
p.Repaint(tt.Setup())

if surface.String() != tt.Want {
t.Errorf("unexpected contents: got = \n%s\nwant = \n%s", surface.String(), tt.Want)
}
})
}
}


// TailBox is a container Widget that may not show all its
// While Box attempts to show every contained Widget - sometimes shrinking
// those Widgets to do so- TailBox prioritizes completely displaying its last
// Widget, then the next-to-last widget, etc.
// It is vertically-aligned, i.e. all the contained Widgets have the same width.
type TailBox struct {
WidgetBase
sz image.Point
contents []Widget
}

var _ Widget = &TailBox{}

func NewTailBox(w ...Widget) *TailBox {
return &TailBox{
contents: w,
}
}

func (t *TailBox) Append(w Widget) {
t.contents = append(t.contents, w)
t.doLayout(t.Size())
}

func (t *TailBox) SetContents(w ...Widget) {
t.contents = w
t.doLayout(t.Size())
}

func (t *TailBox) Draw(p *Painter) {
p.WithMask(image.Rect(0, 0, t.sz.X, t.sz.Y), func(p *Painter) {
// Draw background
p.FillRect(0, 0, t.sz.X, t.sz.Y)

// Draw from the bottom up.
space := t.sz.Y
p.Translate(0, space)
defer p.Restore()
for i := len(t.contents) - 1; i >= 0 && space > 0; i-- {
w := t.contents[i]
space -= w.Size().Y
p.Translate(0, -w.Size().Y)
defer p.Restore()
w.Draw(p)
}
})
}

// Resize recalculates the layout of the box's contents.
func (t *TailBox) Resize(size image.Point) {
t.WidgetBase.Resize(size)
defer func() {
t.sz = size
}()

// If it's just a height change, Draw should do the right thing already.
if size.X != t.sz.X {
t.doLayout(size)
}
}

func (t *TailBox) doLayout(size image.Point) {
for _, w := range t.contents {
hint := w.SizeHint()
// Set the width to the container width, and height to the requested height
w.Resize(image.Pt(size.X, hint.Y))
// ...and then resize again, now that the Y-hint has been refreshed by the X-value.
hint = w.SizeHint()
w.Resize(image.Pt(size.X, hint.Y))
}
}