ui/layout: replace implicit begin/end scopes with explicit function scopes

Before this change, layout objects followed a pattern where a
begin method would set up the layout and return a tweaked set
of constraints, and a end method would take the widget dimensions
and return the tweaked dimensions.

As has been pointed out, this process is error prone, because the
scope of the layout objects are not clear and because it is easy
to swap two begins or two ends.

It turns out that it is possible to implement layout with function
scopes in garbage free way. A typical layout changes from

        al := layout.Align{Alignment: layout.NE}
	cs = al.Begin(ops, cs)
	in := layout.Inset{Top: ui.Dp(16)}
	cs = in.Begin(c, ops, cs)
	txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
	dims := text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
	dims = in.End(dims)
	return al.End(dims)

to

        al := layout.Align{Alignment: layout.NE}
	return al.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
	       in := layout.Inset{Top: ui.Dp(16)}
	       return in.Layout(c, ops, cs, func(cs layout.Constraints) layout.Dimensions {
		       txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
		       return text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
	       })
	})

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-09-16 17:56:27 +02:00
parent 816f0e901f
commit 29639565cd
5 changed files with 117 additions and 141 deletions
+8 -7
View File
@@ -51,25 +51,26 @@ func (s *Stack) begin() {
s.macro.Record(s.ops)
}
// Rigid begins a child with the same constraints that were
// Rigid lays out a widget with the same constraints that were
// passed to Init.
func (s *Stack) Rigid() Constraints {
func (s *Stack) Rigid(w Widget) StackChild {
s.begin()
return s.cs
return s.end(w(s.cs))
}
// Expand begins a child with constraints that exactly match
// Expand lays out a widget with constraints that exactly match
// the biggest child previously added.
func (s *Stack) Expand() Constraints {
func (s *Stack) Expand(w Widget) StackChild {
s.begin()
return Constraints{
cs := Constraints{
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
}
return s.end(w(cs))
}
// End a child by specifying its dimensions.
func (s *Stack) End(dims Dimensions) StackChild {
func (s *Stack) end(dims Dimensions) StackChild {
s.macro.Stop()
s.begun = false
if w := dims.Size.X; w > s.maxSZ.X {