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
|
// size of Flexed children. If WeightSum is zero, the sum
|
||||||
// of all Flexed weights is used.
|
// of all Flexed weights is used.
|
||||||
WeightSum float32
|
WeightSum float32
|
||||||
|
// Gap is the space in pixels between children.
|
||||||
|
Gap int
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlexChild is the descriptor for a Flex child.
|
// 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)
|
mainMin, mainMax := f.Axis.mainConstraint(cs)
|
||||||
crossMin, crossMax := f.Axis.crossConstraint(cs)
|
crossMin, crossMax := f.Axis.crossConstraint(cs)
|
||||||
remaining := mainMax
|
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
|
var totalWeight float32
|
||||||
cgtx := gtx
|
cgtx := gtx
|
||||||
// Note: previously the scratch space was inside FlexChild.
|
// Note: previously the scratch space was inside FlexChild.
|
||||||
@@ -162,6 +172,9 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
|||||||
maxBaseline = b
|
maxBaseline = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(children) > 1 && f.Gap > 0 {
|
||||||
|
size += f.Gap * (len(children) - 1)
|
||||||
|
}
|
||||||
var space int
|
var space int
|
||||||
if mainMin > size {
|
if mainMin > size {
|
||||||
space = mainMin - size
|
space = mainMin - size
|
||||||
@@ -199,6 +212,7 @@ func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
|||||||
trans.Pop()
|
trans.Pop()
|
||||||
mainSize += f.Axis.Convert(dims.Size).X
|
mainSize += f.Axis.Convert(dims.Size).X
|
||||||
if i < len(children)-1 {
|
if i < len(children)-1 {
|
||||||
|
mainSize += f.Gap
|
||||||
switch f.Spacing {
|
switch f.Spacing {
|
||||||
case SpaceEvenly:
|
case SpaceEvenly:
|
||||||
mainSize += space / (1 + len(children))
|
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) {
|
func TestDirection(t *testing.T) {
|
||||||
max := image.Pt(100, 100)
|
max := image.Pt(100, 100)
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user