Allow options on intermediate containers in the grid.

Fixes #181.
This commit is contained in:
Jakub Sobon 2019-04-07 16:58:18 -04:00
parent ea2e0b7855
commit d31b767d5d
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
4 changed files with 123 additions and 13 deletions

View File

@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
executed.
- The SegmentDisplay widget now has a method that returns the observed character
capacity the last time Draw was called.
- The grid.Builder API now allows users to specify options for intermediate
containers, i.e. containers that don't have widgets, but represent rows and
columns.
#### Breaking API changes

View File

@ -109,18 +109,19 @@ func build(elems []Element, parentHeightPerc, parentWidthPerc int) []container.O
switch e := elem.(type) {
case *row:
if len(elems) > 0 {
perc := innerPerc(e.heightPerc, parentHeightPerc)
childHeightPerc := parentHeightPerc - e.heightPerc
return []container.Option{
container.SplitHorizontal(
container.Top(build(e.subElem, 100, parentWidthPerc)...),
container.Top(append(e.cOpts, build(e.subElem, 100, parentWidthPerc)...)...),
container.Bottom(build(elems, childHeightPerc, parentWidthPerc)...),
container.SplitPercent(perc),
),
}
}
return build(e.subElem, 100, parentWidthPerc)
return append(e.cOpts, build(e.subElem, 100, parentWidthPerc)...)
case *col:
if len(elems) > 0 {
@ -128,13 +129,13 @@ func build(elems []Element, parentHeightPerc, parentWidthPerc int) []container.O
childWidthPerc := parentWidthPerc - e.widthPerc
return []container.Option{
container.SplitVertical(
container.Left(build(e.subElem, parentHeightPerc, 100)...),
container.Left(append(e.cOpts, build(e.subElem, parentHeightPerc, 100)...)...),
container.Right(build(elems, parentHeightPerc, childWidthPerc)...),
container.SplitPercent(perc),
),
}
}
return build(e.subElem, parentHeightPerc, 100)
return append(e.cOpts, build(e.subElem, parentHeightPerc, 100)...)
case *widget:
opts := e.cOpts
@ -186,6 +187,9 @@ type row struct {
// subElem are the sub Rows or Columns or a single widget.
subElem []Element
// cOpts are the options for the row's container.
cOpts []container.Option
}
// isElement implements Element.isElement.
@ -204,6 +208,9 @@ type col struct {
// subElem are the sub Rows or Columns or a single widget.
subElem []Element
// cOpts are the options for the column's container.
cOpts []container.Option
}
// isElement implements Element.isElement.
@ -244,6 +251,16 @@ func RowHeightPerc(heightPerc int, subElements ...Element) Element {
}
}
// RowHeightPercWithOpts is like RowHeightPerc, but also allows to apply
// additional options to the container that represents the row.
func RowHeightPercWithOpts(heightPerc int, cOpts []container.Option, subElements ...Element) Element {
return &row{
heightPerc: heightPerc,
subElem: subElements,
cOpts: cOpts,
}
}
// ColWidthPerc creates a column of the specified width.
// The width is supplied as width percentage of the parent element.
// The sum of all widths at the same level cannot be larger than 100%. If it
@ -257,6 +274,16 @@ func ColWidthPerc(widthPerc int, subElements ...Element) Element {
}
}
// ColWidthPercWithOpts is like ColWidthPerc, but also allows to apply
// additional options to the container that represents the column.
func ColWidthPercWithOpts(widthPerc int, cOpts []container.Option, subElements ...Element) Element {
return &col{
widthPerc: widthPerc,
subElem: subElements,
cOpts: cOpts,
}
}
// Widget adds a widget into the Row or Column.
// The options will be applied to the container that directly holds this
// widget.

View File

@ -389,6 +389,45 @@ func TestBuilder(t *testing.T) {
return ft
},
},
{
desc: "two equal rows with options",
termSize: image.Point{10, 10},
builder: func() *Builder {
b := New()
b.Add(RowHeightPercWithOpts(
50,
[]container.Option{
container.Border(linestyle.Double),
},
Widget(mirror()),
))
b.Add(RowHeightPercWithOpts(
50,
[]container.Option{
container.Border(linestyle.Double),
},
Widget(mirror()),
))
return b
}(),
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
top, bot := mustHSplit(ft.Area(), 50)
topCvs := testcanvas.MustNew(top)
botCvs := testcanvas.MustNew(bot)
testdraw.MustBorder(topCvs, topCvs.Area(), draw.BorderLineStyle(linestyle.Double))
testdraw.MustBorder(botCvs, botCvs.Area(), draw.BorderLineStyle(linestyle.Double))
testcanvas.MustApply(topCvs, ft)
testcanvas.MustApply(botCvs, ft)
topWidget := testcanvas.MustNew(area.ExcludeBorder(top))
botWidget := testcanvas.MustNew(area.ExcludeBorder(bot))
fakewidget.MustDraw(ft, topWidget, &widgetapi.Meta{}, widgetapi.Options{})
fakewidget.MustDraw(ft, botWidget, &widgetapi.Meta{}, widgetapi.Options{})
return ft
},
},
{
desc: "two unequal rows",
termSize: image.Point{10, 10},
@ -406,6 +445,45 @@ func TestBuilder(t *testing.T) {
return ft
},
},
{
desc: "two equal columns with options",
termSize: image.Point{20, 10},
builder: func() *Builder {
b := New()
b.Add(ColWidthPercWithOpts(
50,
[]container.Option{
container.Border(linestyle.Double),
},
Widget(mirror()),
))
b.Add(ColWidthPercWithOpts(
50,
[]container.Option{
container.Border(linestyle.Double),
},
Widget(mirror()),
))
return b
}(),
want: func(size image.Point) *faketerm.Terminal {
ft := faketerm.MustNew(size)
left, right := mustVSplit(ft.Area(), 50)
leftCvs := testcanvas.MustNew(left)
rightCvs := testcanvas.MustNew(right)
testdraw.MustBorder(leftCvs, leftCvs.Area(), draw.BorderLineStyle(linestyle.Double))
testdraw.MustBorder(rightCvs, rightCvs.Area(), draw.BorderLineStyle(linestyle.Double))
testcanvas.MustApply(leftCvs, ft)
testcanvas.MustApply(rightCvs, ft)
leftWidget := testcanvas.MustNew(area.ExcludeBorder(left))
rightWidget := testcanvas.MustNew(area.ExcludeBorder(right))
fakewidget.MustDraw(ft, leftWidget, &widgetapi.Meta{}, widgetapi.Options{})
fakewidget.MustDraw(ft, rightWidget, &widgetapi.Meta{}, widgetapi.Options{})
return ft
},
},
{
desc: "two equal columns",
termSize: image.Point{20, 10},

View File

@ -166,16 +166,18 @@ func gridLayout(w *widgets, lt layoutType) ([]container.Option, error) {
container.BorderTitle("A rolling text"),
),
),
grid.RowHeightPerc(50,
grid.Widget(w.spGreen,
container.Border(linestyle.Light),
container.BorderTitle("Green SparkLine"),
grid.ColWidthPerc(50,
grid.RowHeightPerc(50,
grid.Widget(w.spGreen,
container.Border(linestyle.Light),
container.BorderTitle("Green SparkLine"),
),
),
),
grid.RowHeightPerc(50,
grid.Widget(w.spRed,
container.Border(linestyle.Light),
container.BorderTitle("Red SparkLine"),
grid.RowHeightPerc(50,
grid.Widget(w.spRed,
container.Border(linestyle.Light),
container.BorderTitle("Red SparkLine"),
),
),
),
),