ui/layout: introduce Context

Context keeps the current Constraints and Dimensions so the layout
function scopes don't have to.

With

	ctx := new(layout.Context)

a label with margins and alignment goes from

	return al.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
		in := layout.Inset{...}
		return in.Layout(c, ops, cs, func(cs layout.Constraints) layout.Dimensions {
			return text.Label{...}.Layout(ops, cs)
		})
	})

to

	al.Layout(ops, ctx, func() {
		in := layout.Inset{...}
		in.Layout(c, ops, ctx, func() {
		       text.Label{...}.Layout(ops, ctx)
		})
	})

It was a difficult trade-off between the verbose functional approach
and the shorter but more complex Context.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-09-24 19:06:07 +02:00
parent 64add13d28
commit ce9bcee62b
9 changed files with 126 additions and 89 deletions
+8 -4
View File
@@ -58,7 +58,7 @@ type List struct {
// ListElement is a function that computes the dimensions of
// a list element.
type ListElement func(cs Constraints, index int) Dimensions
type ListElement func(index int)
type iterationDir uint8
@@ -96,12 +96,16 @@ func (l *List) init(cfg ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, l
}
// Layout the List and return its dimensions.
func (l *List) Layout(c ui.Config, q input.Queue, ops *ui.Ops, cs Constraints, len int, w ListElement) Dimensions {
func (l *List) Layout(c ui.Config, q input.Queue, ops *ui.Ops, ctx *Context, len int, w ListElement) {
cs := ctx.Constraints
for l.init(c, q, ops, cs, len); l.more(); l.next() {
cs := axisConstraints(l.Axis, Constraint{Max: inf}, axisCrossConstraint(l.Axis, l.cs))
l.end(w(cs, l.index()))
i := l.index()
l.end(ctx.Layout(cs, func() {
w(i)
}))
}
return l.layout()
ctx.Dimensions = l.layout()
}
func (l *List) scrollToEnd() bool {