layout: change Widget to take explicit Context and return explicit Dimensions

Change the definition of Widget from the implicit

        type Widget func()

to the explicit functional

        type Widget func(gtx layout.Context) layout.Dimensions

The advantages are numerous:

- Clearer connection between the incoming context and the output dimensions.
- Returning the Dimensions are impossible to omit.
- Contexts passed by value, so its fields can be exported
and freely mutated by the program.

The only disadvantage is the longer function literals and the many "returns".
What tipped the scales in favour of the explicit Widget variant is that type
aliases can dramatically shorten the literals:

	type (
		C = layout.Context
		D = layout.Dimensions
	)

	widget := func(gtx C) D {
		...
	}

Note that the aliases are not part of the Gio API and it is up to each user
whether they want to use them.

Finally the Go proposal for lightweight function literals,
https://github.com/golang/go/issues/21498, may remove the disadvantage
completely in future.

Context becomes a plain struct with only public fields, and its Reset is
replaced by a NewContext convenience constructor.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-05-23 19:55:02 +02:00
parent af10307f4a
commit 3af01a3f43
25 changed files with 226 additions and 208 deletions
+7 -8
View File
@@ -29,7 +29,7 @@ type List struct {
// Alignment is the cross axis alignment of list elements.
Alignment Alignment
ctx *Context
ctx Context
macro op.MacroOp
child op.MacroOp
scroll gesture.Scroll
@@ -51,7 +51,7 @@ type List struct {
// ListElement is a function that computes the dimensions of
// a list element.
type ListElement func(index int)
type ListElement func(gtx Context, index int) Dimensions
type iterationDir uint8
@@ -82,7 +82,7 @@ const (
const inf = 1e6
// init prepares the list for iterating through its children with next.
func (l *List) init(gtx *Context, len int) {
func (l *List) init(gtx Context, len int) {
if l.more() {
panic("unfinished child")
}
@@ -100,16 +100,15 @@ func (l *List) init(gtx *Context, len int) {
}
// Layout the List.
func (l *List) Layout(gtx *Context, len int, w ListElement) {
func (l *List) Layout(gtx Context, len int, w ListElement) Dimensions {
for l.init(gtx, len); l.more(); l.next() {
crossMin, crossMax := axisCrossConstraint(l.Axis, l.ctx.Constraints)
cs := axisConstraints(l.Axis, 0, inf, crossMin, crossMax)
i := l.index()
l.end(ctxLayout(gtx, cs, func() {
w(i)
}))
gtx.Constraints = cs
l.end(w(gtx, i))
}
gtx.Dimensions = l.layout()
return l.layout()
}
func (l *List) scrollToEnd() bool {