forked from joejulian/gio
layout: add Flex.Gap for spacing out items
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit is contained in:
@@ -22,6 +22,8 @@ type Flex struct {
|
||||
// size of Flexed children. If WeightSum is zero, the sum
|
||||
// of all Flexed weights is used.
|
||||
WeightSum float32
|
||||
// Gap is the space in pixels between children.
|
||||
Gap int
|
||||
}
|
||||
|
||||
// FlexChild is the descriptor for a Flex child.
|
||||
@@ -82,6 +84,14 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
||||
mainMin, mainMax := f.Axis.mainConstraint(cs)
|
||||
crossMin, crossMax := f.Axis.crossConstraint(cs)
|
||||
remaining := mainMax
|
||||
// Reserve space for gaps between children.
|
||||
if len(children) > 1 && f.Gap > 0 {
|
||||
totalGap := f.Gap * (len(children) - 1)
|
||||
remaining -= totalGap
|
||||
if remaining < 0 {
|
||||
remaining = 0
|
||||
}
|
||||
}
|
||||
var totalWeight float32
|
||||
cgtx := gtx
|
||||
// Note: previously the scratch space was inside FlexChild.
|
||||
@@ -162,6 +172,9 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
||||
maxBaseline = b
|
||||
}
|
||||
}
|
||||
if len(children) > 1 && f.Gap > 0 {
|
||||
size += f.Gap * (len(children) - 1)
|
||||
}
|
||||
var space int
|
||||
if mainMin > size {
|
||||
space = mainMin - size
|
||||
@@ -199,6 +212,7 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
||||
trans.Pop()
|
||||
mainSize += f.Axis.Convert(dims.Size).X
|
||||
if i < len(children)-1 {
|
||||
mainSize += f.Gap
|
||||
switch f.Spacing {
|
||||
case SpaceEvenly:
|
||||
mainSize += space / (1 + len(children))
|
||||
|
||||
@@ -44,6 +44,106 @@ func TestFlex(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlexGap(t *testing.T) {
|
||||
gtx := Context{
|
||||
Ops: new(op.Ops),
|
||||
Constraints: Constraints{
|
||||
Max: image.Pt(100, 100),
|
||||
},
|
||||
}
|
||||
|
||||
// Two 20px children with 10px gap = 50px total.
|
||||
dims := Flex{Gap: 10}.Layout(gtx,
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(20, 10)}
|
||||
}),
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(20, 10)}
|
||||
}),
|
||||
)
|
||||
if got, exp := dims.Size.X, 50; got != exp {
|
||||
t.Errorf("two rigid children with gap: got width %d, expected %d", got, exp)
|
||||
}
|
||||
|
||||
// Three children: gap added between each pair.
|
||||
dims = Flex{Gap: 5}.Layout(gtx,
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(10, 10)}
|
||||
}),
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(10, 10)}
|
||||
}),
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(10, 10)}
|
||||
}),
|
||||
)
|
||||
if got, exp := dims.Size.X, 40; got != exp {
|
||||
t.Errorf("three rigid children with gap: got width %d, expected %d", got, exp)
|
||||
}
|
||||
|
||||
// Single child: no gap added.
|
||||
dims = Flex{Gap: 10}.Layout(gtx,
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(20, 10)}
|
||||
}),
|
||||
)
|
||||
if got, exp := dims.Size.X, 20; got != exp {
|
||||
t.Errorf("single child with gap: got width %d, expected %d", got, exp)
|
||||
}
|
||||
|
||||
// Gap with flexed children: gap is reserved from available space.
|
||||
dims = Flex{Gap: 10}.Layout(gtx,
|
||||
Flexed(1, func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(gtx.Constraints.Max.X, 10)}
|
||||
}),
|
||||
Flexed(1, func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(gtx.Constraints.Max.X, 10)}
|
||||
}),
|
||||
)
|
||||
// 100px max - 10px gap = 90px for flex; 45px each.
|
||||
if got, exp := dims.Size.X, 100; got != exp {
|
||||
t.Errorf("flexed children with gap: got width %d, expected %d", got, exp)
|
||||
}
|
||||
|
||||
// Vertical axis with gap.
|
||||
dims = Flex{Axis: Vertical, Gap: 15}.Layout(gtx,
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(10, 20)}
|
||||
}),
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(10, 20)}
|
||||
}),
|
||||
)
|
||||
if got, exp := dims.Size.Y, 55; got != exp {
|
||||
t.Errorf("vertical with gap: got height %d, expected %d", got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlexGapConstraints(t *testing.T) {
|
||||
gtx := Context{
|
||||
Ops: new(op.Ops),
|
||||
Constraints: Constraints{
|
||||
Max: image.Pt(100, 100),
|
||||
},
|
||||
}
|
||||
|
||||
// Verify that flexed children receive constraints with gap accounted for.
|
||||
var flexMax int
|
||||
Flex{Gap: 10}.Layout(gtx,
|
||||
Rigid(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Pt(30, 10)}
|
||||
}),
|
||||
Flexed(1, func(gtx Context) Dimensions {
|
||||
flexMax = gtx.Constraints.Max.X
|
||||
return Dimensions{Size: image.Pt(gtx.Constraints.Max.X, 10)}
|
||||
}),
|
||||
)
|
||||
// 100 - 10 (gap) - 30 (rigid) = 60 remaining for flex.
|
||||
if got, exp := flexMax, 60; got != exp {
|
||||
t.Errorf("flex constraint with gap: got %d, expected %d", got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDirection(t *testing.T) {
|
||||
max := image.Pt(100, 100)
|
||||
for _, tc := range []struct {
|
||||
|
||||
Reference in New Issue
Block a user