2018-03-27 19:01:35 +01:00
|
|
|
package container
|
|
|
|
|
2018-04-01 00:57:33 +02:00
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
"testing"
|
|
|
|
|
2018-04-07 14:24:55 +02:00
|
|
|
"github.com/mum4k/termdash/canvas/testcanvas"
|
2018-04-01 00:57:33 +02:00
|
|
|
"github.com/mum4k/termdash/cell"
|
|
|
|
"github.com/mum4k/termdash/draw"
|
2018-04-07 14:24:55 +02:00
|
|
|
"github.com/mum4k/termdash/draw/testdraw"
|
2018-04-01 00:57:33 +02:00
|
|
|
"github.com/mum4k/termdash/terminal/faketerm"
|
2018-04-09 03:33:24 +01:00
|
|
|
"github.com/mum4k/termdash/widgetapi"
|
2018-04-09 03:17:40 +01:00
|
|
|
"github.com/mum4k/termdash/widgets/fakewidget"
|
2018-04-01 00:57:33 +02:00
|
|
|
)
|
|
|
|
|
2018-03-27 19:01:35 +01:00
|
|
|
// Example demonstrates how to use the Container API.
|
|
|
|
func Example() {
|
2018-04-01 16:00:20 +02:00
|
|
|
New(
|
2018-03-27 19:01:35 +01:00
|
|
|
/* terminal = */ nil,
|
2018-04-01 16:00:20 +02:00
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
2018-04-01 00:57:33 +02:00
|
|
|
|
2018-04-01 16:00:20 +02:00
|
|
|
// TODO(mum4k): Allow splits on different ratios.
|
|
|
|
// TODO(mum4k): Include an example with a widget.
|
2018-04-01 00:57:33 +02:00
|
|
|
}
|
|
|
|
|
2018-04-09 03:17:40 +01:00
|
|
|
func TestNew(t *testing.T) {
|
2018-04-01 00:57:33 +02:00
|
|
|
tests := []struct {
|
|
|
|
desc string
|
|
|
|
termSize image.Point
|
|
|
|
container func(ft *faketerm.Terminal) *Container
|
|
|
|
want func(size image.Point) *faketerm.Terminal
|
|
|
|
}{
|
|
|
|
{
|
2018-04-01 16:00:20 +02:00
|
|
|
desc: "empty container",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(ft)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
return faketerm.MustNew(size)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "container with a border",
|
|
|
|
termSize: image.Point{10, 10},
|
2018-04-01 00:57:33 +02:00
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
Border(draw.LineStyleLight),
|
2018-04-01 16:00:20 +02:00
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-06 04:56:36 +02:00
|
|
|
cvs,
|
|
|
|
image.Rect(0, 0, 10, 10),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorYellow),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 16:00:20 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "horizontal split, children have borders",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 0, 10, 5), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 5, 10, 10), draw.LineStyleLight)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 16:00:20 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "horizontal split, parent and children have borders",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
2018-04-01 00:57:33 +02:00
|
|
|
Border(draw.LineStyleLight),
|
2018-04-01 16:00:20 +02:00
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-06 04:56:36 +02:00
|
|
|
cvs,
|
|
|
|
image.Rect(0, 0, 10, 10),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorYellow),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(cvs, image.Rect(1, 1, 9, 5), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(1, 5, 9, 9), draw.LineStyleLight)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 16:00:20 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "vertical split, children have borders",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 0, 5, 10), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(5, 0, 10, 10), draw.LineStyleLight)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 16:00:20 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "vertical split, parent and children have borders",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
2018-04-01 00:57:33 +02:00
|
|
|
Border(draw.LineStyleLight),
|
2018-04-01 16:00:20 +02:00
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-06 04:56:36 +02:00
|
|
|
cvs,
|
|
|
|
image.Rect(0, 0, 10, 10),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorYellow),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(cvs, image.Rect(1, 1, 5, 9), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(5, 1, 9, 9), draw.LineStyleLight)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 16:00:20 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "multi level split",
|
2018-04-09 03:17:40 +01:00
|
|
|
termSize: image.Point{10, 16},
|
2018-04-01 16:00:20 +02:00
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
SplitHorizontal(
|
|
|
|
Top(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Bottom(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
2018-04-01 00:57:33 +02:00
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 0, 5, 8), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 8, 5, 12), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 12, 5, 16), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(5, 0, 10, 16), draw.LineStyleLight)
|
2018-04-07 14:24:55 +02:00
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-01 00:57:33 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
2018-04-05 19:57:46 +02:00
|
|
|
{
|
2018-04-06 04:56:36 +02:00
|
|
|
desc: "inherits border and focused color",
|
|
|
|
termSize: image.Point{10, 10},
|
2018-04-05 19:57:46 +02:00
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
BorderColor(cell.ColorRed),
|
2018-04-06 04:56:36 +02:00
|
|
|
FocusedColor(cell.ColorBlue),
|
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
2018-04-05 19:57:46 +02:00
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
2018-04-09 03:17:40 +01:00
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-06 04:56:36 +02:00
|
|
|
cvs,
|
|
|
|
image.Rect(0, 0, 10, 10),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorBlue),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-06 04:56:36 +02:00
|
|
|
cvs,
|
|
|
|
image.Rect(1, 1, 5, 9),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorRed),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testdraw.MustBox(
|
2018-04-05 19:57:46 +02:00
|
|
|
cvs,
|
2018-04-06 04:56:36 +02:00
|
|
|
image.Rect(5, 1, 9, 9),
|
2018-04-05 19:57:46 +02:00
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorRed),
|
|
|
|
)
|
2018-04-07 14:24:55 +02:00
|
|
|
testcanvas.MustApply(cvs, ft)
|
2018-04-05 19:57:46 +02:00
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
2018-04-09 03:17:40 +01:00
|
|
|
{
|
|
|
|
desc: "splitting a container removes the widget",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
Border(draw.LineStyleLight),
|
2018-04-09 03:33:24 +01:00
|
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
2018-04-09 03:17:40 +01:00
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
|
|
testdraw.MustBox(
|
|
|
|
cvs,
|
|
|
|
ft.Area(),
|
|
|
|
draw.LineStyleLight,
|
|
|
|
cell.FgColor(cell.ColorYellow),
|
|
|
|
)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(1, 1, 5, 9), draw.LineStyleLight)
|
|
|
|
testdraw.MustBox(cvs, image.Rect(5, 1, 9, 9), draw.LineStyleLight)
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "placing a widget removes container split",
|
|
|
|
termSize: image.Point{10, 10},
|
|
|
|
container: func(ft *faketerm.Terminal) *Container {
|
|
|
|
return New(
|
|
|
|
ft,
|
|
|
|
SplitVertical(
|
|
|
|
Left(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
Right(
|
|
|
|
Border(draw.LineStyleLight),
|
|
|
|
),
|
|
|
|
),
|
2018-04-09 03:33:24 +01:00
|
|
|
PlaceWidget(fakewidget.New(widgetapi.Options{})),
|
2018-04-09 03:17:40 +01:00
|
|
|
)
|
|
|
|
},
|
|
|
|
want: func(size image.Point) *faketerm.Terminal {
|
|
|
|
ft := faketerm.MustNew(size)
|
|
|
|
cvs := testcanvas.MustNew(ft.Area())
|
|
|
|
testdraw.MustBox(cvs, image.Rect(0, 0, 10, 10), draw.LineStyleLight)
|
|
|
|
testdraw.MustText(cvs, "(10,10)", draw.TextBounds{Start: image.Point{1, 1}})
|
|
|
|
testcanvas.MustApply(cvs, ft)
|
|
|
|
return ft
|
|
|
|
},
|
|
|
|
},
|
2018-04-01 00:57:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range tests {
|
|
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
|
|
got, err := faketerm.New(tc.termSize)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("faketerm.New => unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-04-09 03:17:40 +01:00
|
|
|
if err := tc.container(got).Draw(); err != nil {
|
|
|
|
t.Fatalf("Draw => unexpected error: %v", err)
|
2018-04-01 00:57:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if diff := faketerm.Diff(tc.want(tc.termSize), got); diff != "" {
|
|
|
|
t.Errorf("Draw => %v", diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-03-27 19:01:35 +01:00
|
|
|
}
|
2018-04-09 03:17:40 +01:00
|
|
|
|
|
|
|
// TODO(mum4k) Add missing tests (Keyboard):
|
|
|
|
// Keyboard event isn't forwarded if container has no widget.
|
|
|
|
// Keyboard event gets forwarded to focused widget.
|
|
|
|
// Keyboard event isn't forwarded if widget didn't request it.
|
|
|
|
// Widget returns an error when receiving the keyboard event.
|
|
|
|
|
|
|
|
// TODO(mum4k) Add missing tests (Mouse):
|
|
|
|
// Mouse event isn't forwarded if container has no widget.
|
|
|
|
// Mouse event is forwarded to container at that point.
|
|
|
|
// Mouse event isn't forwarded if widget didn't request it.
|
|
|
|
// Mouse event isn't forwarded if it falls outside of widget's usable area.
|
|
|
|
// Mouse coordinates are relative to widget's canvas.
|
|
|
|
// Widget returns an error when receiving the mouse event.
|