forked from joejulian/gio
29639565cd
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>
158 lines
3.0 KiB
Go
158 lines
3.0 KiB
Go
package layout_test
|
|
|
|
import (
|
|
"fmt"
|
|
"image"
|
|
"time"
|
|
|
|
"gioui.org/ui"
|
|
"gioui.org/ui/input"
|
|
"gioui.org/ui/layout"
|
|
)
|
|
|
|
type queue struct{}
|
|
|
|
type config struct{}
|
|
|
|
var q queue
|
|
var cfg = new(config)
|
|
|
|
func ExampleInset() {
|
|
ops := new(ui.Ops)
|
|
|
|
// Loose constraints with no minimal size.
|
|
var cs layout.Constraints
|
|
cs.Width.Max = 100
|
|
cs.Height.Max = 100
|
|
|
|
// Inset all edges by 10.
|
|
inset := layout.UniformInset(ui.Dp(10))
|
|
dims := inset.Layout(cfg, ops, cs, func(cs layout.Constraints) layout.Dimensions {
|
|
// Lay out a 50x50 sized widget.
|
|
dims := layoutWidget(50, 50, cs)
|
|
fmt.Println(dims.Size)
|
|
return dims
|
|
})
|
|
|
|
fmt.Println(dims.Size)
|
|
|
|
// Output:
|
|
// (50,50)
|
|
// (70,70)
|
|
}
|
|
|
|
func ExampleAlign() {
|
|
ops := new(ui.Ops)
|
|
|
|
// Rigid constraints with both minimum and maximum set.
|
|
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
|
|
|
align := layout.Align{Alignment: layout.Center}
|
|
dims := align.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
|
|
// Lay out a 50x50 sized widget.
|
|
dims := layoutWidget(50, 50, cs)
|
|
fmt.Println(dims.Size)
|
|
return dims
|
|
})
|
|
|
|
fmt.Println(dims.Size)
|
|
|
|
// Output:
|
|
// (50,50)
|
|
// (100,100)
|
|
}
|
|
|
|
func ExampleFlex() {
|
|
ops := new(ui.Ops)
|
|
|
|
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
|
|
|
flex := layout.Flex{}
|
|
flex.Init(ops, cs)
|
|
|
|
// Rigid 10x10 widget.
|
|
child1 := flex.Rigid(func(cs layout.Constraints) layout.Dimensions {
|
|
fmt.Printf("Rigid: %v\n", cs.Width)
|
|
return layoutWidget(10, 10, cs)
|
|
})
|
|
|
|
// Child with 50% space allowance.
|
|
child2 := flex.Flexible(0.5, func(cs layout.Constraints) layout.Dimensions {
|
|
fmt.Printf("50%%: %v\n", cs.Width)
|
|
return layoutWidget(10, 10, cs)
|
|
})
|
|
|
|
flex.Layout(child1, child2)
|
|
|
|
// Output:
|
|
// Rigid: {0 100}
|
|
// 50%: {0 45}
|
|
}
|
|
|
|
func ExampleStack() {
|
|
ops := new(ui.Ops)
|
|
|
|
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
|
|
|
stack := layout.Stack{}
|
|
stack.Init(ops, cs)
|
|
|
|
// Rigid 50x50 widget.
|
|
child1 := stack.Rigid(func(cs layout.Constraints) layout.Dimensions {
|
|
return layoutWidget(50, 50, cs)
|
|
})
|
|
|
|
// Force widget to the same size as the first.
|
|
child2 := stack.Expand(func(cs layout.Constraints) layout.Dimensions {
|
|
fmt.Printf("Expand: %v\n", cs)
|
|
return layoutWidget(10, 10, cs)
|
|
})
|
|
|
|
stack.Layout(child1, child2)
|
|
|
|
// Output:
|
|
// Expand: {{50 50} {50 50}}
|
|
}
|
|
|
|
func ExampleList() {
|
|
ops := new(ui.Ops)
|
|
|
|
cs := layout.RigidConstraints(image.Point{X: 100, Y: 100})
|
|
|
|
// The list is 1e6 elements, but only 5 fit the constraints.
|
|
const listLen = 1e6
|
|
|
|
var list layout.List
|
|
count := 0
|
|
list.Layout(cfg, q, ops, cs, listLen, func(cs layout.Constraints, i int) layout.Dimensions {
|
|
count++
|
|
return layoutWidget(20, 20, cs)
|
|
})
|
|
|
|
fmt.Println(count)
|
|
|
|
// Output:
|
|
// 5
|
|
}
|
|
|
|
func layoutWidget(width, height int, cs layout.Constraints) layout.Dimensions {
|
|
return layout.Dimensions{
|
|
Size: image.Point{
|
|
X: width,
|
|
Y: height,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (config) Now() time.Time {
|
|
return time.Now()
|
|
}
|
|
|
|
func (config) Px(v ui.Value) int {
|
|
return int(v.V + .5)
|
|
}
|
|
|
|
func (queue) Next(k input.Key) (input.Event, bool) {
|
|
return nil, false
|
|
}
|