layout: added number of visible children to List

Also fixed an edge case where the first visible child was off by 1 when it was just fully hidden.

Signed-off-by: pierre <pierre.curto@gmail.com>
This commit is contained in:
pierre
2021-01-20 18:25:16 +01:00
committed by Elias Naur
parent cd47a158a2
commit 9bede80a3d
2 changed files with 107 additions and 1 deletions
+5 -1
View File
@@ -69,6 +69,8 @@ type Position struct {
// Offset is the distance in pixels from the top edge to the child at index
// First.
Offset int
// Count is the number of visible children.
Count int
}
const (
@@ -206,7 +208,8 @@ func (l *List) layout(ops *op.Ops, macro op.MacroOp) Dimensions {
for len(children) > 0 {
sz := children[0].size
mainSize := l.Axis.Convert(sz).X
if l.Position.Offset <= mainSize {
if l.Position.Offset < mainSize {
// First child is partially visible.
break
}
l.Position.First++
@@ -226,6 +229,7 @@ func (l *List) layout(ops *op.Ops, macro op.MacroOp) Dimensions {
break
}
}
l.Position.Count = len(children)
pos := -l.Position.Offset
// ScrollToEnd lists are end aligned.
if space := mainMax - size; l.ScrollToEnd && space > 0 {
+102
View File
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Unlicense OR MIT
package layout
import (
"image"
"testing"
"gioui.org/f32"
"gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/io/router"
"gioui.org/op"
)
func TestListPosition(t *testing.T) {
_s := func(e ...event.Event) []event.Event { return e }
r := new(router.Router)
gtx := Context{
Ops: new(op.Ops),
Constraints: Constraints{
Max: image.Pt(20, 10),
},
Queue: r,
}
el := func(gtx Context, idx int) Dimensions {
return Dimensions{Size: image.Pt(10, 10)}
}
for _, tc := range []struct {
label string
num int
scroll []event.Event
first int
count int
}{
{label: "no item"},
{label: "1 visible 0 hidden", num: 1, count: 1},
{label: "2 visible 0 hidden", num: 2, count: 2},
{label: "2 visible 1 hidden", num: 3, count: 2},
{label: "3 visible 0 hidden small scroll", num: 3, count: 3,
scroll: _s(
pointer.Event{
Source: pointer.Mouse,
Buttons: pointer.ButtonLeft,
Type: pointer.Press,
Position: f32.Pt(0, 0),
},
pointer.Event{
Source: pointer.Mouse,
Type: pointer.Scroll,
Scroll: f32.Pt(5, 0),
},
pointer.Event{
Source: pointer.Mouse,
Buttons: pointer.ButtonLeft,
Type: pointer.Release,
Position: f32.Pt(5, 0),
},
)},
{label: "2 visible 1 hidden large scroll", num: 3, count: 2, first: 1,
scroll: _s(
pointer.Event{
Source: pointer.Mouse,
Buttons: pointer.ButtonLeft,
Type: pointer.Press,
Position: f32.Pt(0, 0),
},
pointer.Event{
Source: pointer.Mouse,
Type: pointer.Scroll,
Scroll: f32.Pt(10, 0),
},
pointer.Event{
Source: pointer.Mouse,
Buttons: pointer.ButtonLeft,
Type: pointer.Release,
Position: f32.Pt(15, 0),
},
)},
} {
t.Run(tc.label, func(t *testing.T) {
gtx.Ops.Reset()
var list List
// Initialize the list.
list.Layout(gtx, tc.num, el)
// Generate the scroll events.
r.Frame(gtx.Ops)
r.Add(tc.scroll...)
// Let the list process the events.
list.Layout(gtx, tc.num, el)
pos := list.Position
if got, want := pos.First, tc.first; got != want {
t.Errorf("List: invalid first position: got %v; want %v", got, want)
}
if got, want := pos.Count, tc.count; got != want {
t.Errorf("List: invalid number of visible children: got %v; want %v", got, want)
}
})
}
}