Skip to content

Commit

Permalink
Allow options on intermediate containers in the grid.
Browse files Browse the repository at this point in the history
Fixes #181.
  • Loading branch information
mum4k committed Apr 7, 2019
1 parent ea2e0b7 commit d31b767
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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

Expand Down
35 changes: 31 additions & 4 deletions container/grid/grid.go
Expand Up @@ -109,32 +109,33 @@ 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 {
perc := innerPerc(e.widthPerc, parentWidthPerc)
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
Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
78 changes: 78 additions & 0 deletions container/grid/grid_test.go
Expand Up @@ -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},
Expand All @@ -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},
Expand Down
20 changes: 11 additions & 9 deletions termdashdemo/termdashdemo.go
Expand Up @@ -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"),
),
),
),
),
Expand Down

0 comments on commit d31b767

Please sign in to comment.