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,6 +166,7 @@ func gridLayout(w *widgets, lt layoutType) ([]container.Option, error) {
container.BorderTitle("A rolling text"),
),
),
grid.ColWidthPerc(50,
grid.RowHeightPerc(50,
grid.Widget(w.spGreen,
container.Border(linestyle.Light),
@ -179,6 +180,7 @@ func gridLayout(w *widgets, lt layoutType) ([]container.Option, error) {
),
),
),
),
grid.RowHeightPerc(7,
grid.Widget(w.gauge,
container.Border(linestyle.Light),