layout: make Flexed weight a weight, not a ratio

It's more intuitive to specify the weight as a ratio of the total
weight of all Flexed children than to specify the ratio of the
flexable space.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-06-10 11:25:25 +02:00
parent b1df2a61a9
commit 5272dc9fa5
2 changed files with 29 additions and 26 deletions
+4 -1
View File
@@ -69,10 +69,13 @@ func ExampleFlex() {
return layoutWidget(gtx, 10, 10) return layoutWidget(gtx, 10, 10)
}), }),
// Child with 50% space allowance. // Child with 50% space allowance.
layout.Flexed(0.5, func(gtx layout.Context) layout.Dimensions { layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
fmt.Printf("50%%: %v\n", gtx.Constraints) fmt.Printf("50%%: %v\n", gtx.Constraints)
return layoutWidget(gtx, 10, 10) return layoutWidget(gtx, 10, 10)
}), }),
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return layout.Dimensions{}
}),
) )
// Output: // Output:
+25 -25
View File
@@ -61,8 +61,9 @@ func Rigid(widget Widget) FlexChild {
} }
} }
// Flexed returns a Flex child forced to take up a fraction of // Flexed returns a Flex child forced to take up w fraction of the
// the remaining space. // of the space left over from Rigid children. The fraction is weight
// divided by the weight sum of all Flexed children.
func Flexed(weight float32, widget Widget) FlexChild { func Flexed(weight float32, widget Widget) FlexChild {
return FlexChild{ return FlexChild{
flex: true, flex: true,
@@ -76,60 +77,61 @@ func Flexed(weight float32, widget Widget) FlexChild {
// before Flexed children. // before Flexed children.
func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions { func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
size := 0 size := 0
cs := gtx.Constraints
mainMin, mainMax := axisMainConstraint(f.Axis, cs)
crossMin, crossMax := axisCrossConstraint(f.Axis, cs)
remaining := mainMax
var totalWeight float32
// Lay out Rigid children. // Lay out Rigid children.
for i, child := range children { for i, child := range children {
if child.flex { if child.flex {
totalWeight += child.weight
continue continue
} }
cs := gtx.Constraints
_, mainMax := axisMainConstraint(f.Axis, cs)
mainMax -= size
if mainMax < 0 {
mainMax = 0
}
crossMin, crossMax := axisCrossConstraint(f.Axis, cs)
cs = axisConstraints(f.Axis, 0, mainMax, crossMin, crossMax)
macro := op.Record(gtx.Ops) macro := op.Record(gtx.Ops)
gtx := gtx gtx := gtx
gtx.Constraints = cs gtx.Constraints = axisConstraints(f.Axis, 0, remaining, crossMin, crossMax)
dims := child.widget(gtx) dims := child.widget(gtx)
c := macro.Stop() c := macro.Stop()
sz := axisMain(f.Axis, dims.Size) sz := axisMain(f.Axis, dims.Size)
size += sz size += sz
remaining -= sz
if remaining < 0 {
remaining = 0
}
children[i].call = c children[i].call = c
children[i].dims = dims children[i].dims = dims
} }
rigidSize := size
// fraction is the rounding error from a Flex weighting. // fraction is the rounding error from a Flex weighting.
var fraction float32 var fraction float32
flexTotal := remaining
// Lay out Flexed children. // Lay out Flexed children.
for i, child := range children { for i, child := range children {
if !child.flex { if !child.flex {
continue continue
} }
cs := gtx.Constraints
_, mainMax := axisMainConstraint(f.Axis, cs)
var flexSize int var flexSize int
if mainMax > size { if remaining > 0 && totalWeight > 0 {
flexSize = mainMax - rigidSize
// Apply weight and add any leftover fraction from a // Apply weight and add any leftover fraction from a
// previous Flexed. // previous Flexed.
childSize := float32(flexSize)*child.weight + fraction childSize := float32(flexTotal) * child.weight / totalWeight
flexSize = int(childSize + .5) flexSize = int(childSize + fraction + .5)
fraction = childSize - float32(flexSize) fraction = childSize - float32(flexSize)
if max := mainMax - size; flexSize > max { if flexSize > remaining {
flexSize = max flexSize = remaining
} }
} }
crossMin, crossMax := axisCrossConstraint(f.Axis, cs)
cs = axisConstraints(f.Axis, flexSize, flexSize, crossMin, crossMax)
macro := op.Record(gtx.Ops) macro := op.Record(gtx.Ops)
gtx := gtx gtx := gtx
gtx.Constraints = cs gtx.Constraints = axisConstraints(f.Axis, flexSize, flexSize, crossMin, crossMax)
dims := child.widget(gtx) dims := child.widget(gtx)
c := macro.Stop() c := macro.Stop()
sz := axisMain(f.Axis, dims.Size) sz := axisMain(f.Axis, dims.Size)
size += sz size += sz
remaining -= sz
if remaining < 0 {
remaining = 0
}
children[i].call = c children[i].call = c
children[i].dims = dims children[i].dims = dims
} }
@@ -143,8 +145,6 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
maxBaseline = b maxBaseline = b
} }
} }
cs := gtx.Constraints
mainMin, _ := axisMainConstraint(f.Axis, cs)
var space int var space int
if mainMin > size { if mainMin > size {
space = mainMin - size space = mainMin - size