aboutsummaryrefslogtreecommitdiff
path: root/vendor/gioui.org/layout/list.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gioui.org/layout/list.go')
-rw-r--r--vendor/gioui.org/layout/list.go139
1 files changed, 89 insertions, 50 deletions
diff --git a/vendor/gioui.org/layout/list.go b/vendor/gioui.org/layout/list.go
index 68b63f7..aa78f1b 100644
--- a/vendor/gioui.org/layout/list.go
+++ b/vendor/gioui.org/layout/list.go
@@ -6,7 +6,6 @@ import (
"image"
"gioui.org/gesture"
- "gioui.org/io/pointer"
"gioui.org/op"
"gioui.org/op/clip"
)
@@ -29,15 +28,13 @@ type List struct {
// Alignment is the cross axis alignment of list elements.
Alignment Alignment
- ctx Context
- macro op.MacroOp
- child op.MacroOp
+ cs Constraints
scroll gesture.Scroll
scrollDelta int
// Position is updated during Layout. To save the list scroll position,
// just save Position after Layout finishes. To scroll the list
- // programatically, update Position (e.g. restore it from a saved value)
+ // programmatically, update Position (e.g. restore it from a saved value)
// before calling Layout.
Position Position
@@ -71,6 +68,13 @@ type Position struct {
// Offset is the distance in pixels from the top edge to the child at index
// First.
Offset int
+ // OffsetLast is the signed distance in pixels from the bottom edge to the
+ // bottom edge of the child at index First+Count.
+ OffsetLast int
+ // Count is the number of visible children.
+ Count int
+ // Length is the estimated total size of all children, measured in pixels.
+ Length int
}
const (
@@ -86,29 +90,41 @@ func (l *List) init(gtx Context, len int) {
if l.more() {
panic("unfinished child")
}
- l.ctx = gtx
+ l.cs = gtx.Constraints
l.maxSize = 0
l.children = l.children[:0]
l.len = len
- l.update()
+ l.update(gtx)
if l.scrollToEnd() || l.Position.First > len {
l.Position.Offset = 0
l.Position.First = len
}
- l.macro = op.Record(gtx.Ops)
- l.next()
}
// Layout the List.
func (l *List) Layout(gtx Context, len int, w ListElement) Dimensions {
- for l.init(gtx, len); l.more(); l.next() {
- crossMin, crossMax := axisCrossConstraint(l.Axis, l.ctx.Constraints)
- cs := axisConstraints(l.Axis, 0, inf, crossMin, crossMax)
- i := l.index()
- gtx.Constraints = cs
- l.end(w(gtx, i))
+ l.init(gtx, len)
+ crossMin, crossMax := l.Axis.crossConstraint(gtx.Constraints)
+ gtx.Constraints = l.Axis.constraints(0, inf, crossMin, crossMax)
+ macro := op.Record(gtx.Ops)
+ laidOutTotalLength := 0
+ numLaidOut := 0
+
+ for l.next(); l.more(); l.next() {
+ child := op.Record(gtx.Ops)
+ dims := w(gtx, l.index())
+ call := child.Stop()
+ l.end(dims, call)
+ laidOutTotalLength += l.Axis.Convert(dims.Size).X
+ numLaidOut++
+ }
+
+ if numLaidOut > 0 {
+ l.Position.Length = laidOutTotalLength * len / numLaidOut
+ } else {
+ l.Position.Length = 0
}
- return l.layout()
+ return l.layout(gtx.Ops, macro)
}
func (l *List) scrollToEnd() bool {
@@ -120,8 +136,8 @@ func (l *List) Dragging() bool {
return l.scroll.State() == gesture.StateDragging
}
-func (l *List) update() {
- d := l.scroll.Scroll(l.ctx.Metric, l.ctx, l.ctx.Now, gesture.Axis(l.Axis))
+func (l *List) update(gtx Context) {
+ d := l.scroll.Scroll(gtx.Metric, gtx, gtx.Now, gesture.Axis(l.Axis))
l.scrollDelta = d
l.Position.Offset += d
}
@@ -136,9 +152,6 @@ func (l *List) next() {
l.Position.Offset += l.scrollDelta
l.dir = l.nextDir()
}
- if l.more() {
- l.child = op.Record(l.ctx.Ops)
- }
}
// index is current child's position in the underlying list.
@@ -159,7 +172,7 @@ func (l *List) more() bool {
}
func (l *List) nextDir() iterationDir {
- _, vsize := axisMainConstraint(l.Axis, l.ctx.Constraints)
+ _, vsize := l.Axis.mainConstraint(l.cs)
last := l.Position.First + len(l.children)
// Clamp offset.
if l.maxSize-l.Position.Offset < vsize && last == l.len {
@@ -180,16 +193,17 @@ func (l *List) nextDir() iterationDir {
}
// End the current child by specifying its dimensions.
-func (l *List) end(dims Dimensions) {
- call := l.child.Stop()
+func (l *List) end(dims Dimensions, call op.CallOp) {
child := scrollChild{dims.Size, call}
- mainSize := axisMain(l.Axis, child.size)
+ mainSize := l.Axis.Convert(child.size).X
l.maxSize += mainSize
switch l.dir {
case iterateForward:
l.children = append(l.children, child)
case iterateBackward:
- l.children = append([]scrollChild{child}, l.children...)
+ l.children = append(l.children, scrollChild{})
+ copy(l.children[1:], l.children)
+ l.children[0] = child
l.Position.First--
l.Position.Offset += mainSize
default:
@@ -199,17 +213,18 @@ func (l *List) end(dims Dimensions) {
}
// Layout the List and return its dimensions.
-func (l *List) layout() Dimensions {
+func (l *List) layout(ops *op.Ops, macro op.MacroOp) Dimensions {
if l.more() {
panic("unfinished child")
}
- mainMin, mainMax := axisMainConstraint(l.Axis, l.ctx.Constraints)
+ mainMin, mainMax := l.Axis.mainConstraint(l.cs)
children := l.children
// Skip invisible children
for len(children) > 0 {
sz := children[0].size
- mainSize := axisMain(l.Axis, sz)
- if l.Position.Offset <= mainSize {
+ mainSize := l.Axis.Convert(sz).X
+ if l.Position.Offset < mainSize {
+ // First child is partially visible.
break
}
l.Position.First++
@@ -219,32 +234,33 @@ func (l *List) layout() Dimensions {
size := -l.Position.Offset
var maxCross int
for i, child := range children {
- sz := child.size
- if c := axisCross(l.Axis, sz); c > maxCross {
+ sz := l.Axis.Convert(child.size)
+ if c := sz.Y; c > maxCross {
maxCross = c
}
- size += axisMain(l.Axis, sz)
+ size += sz.X
if size >= mainMax {
children = children[:i+1]
break
}
}
- ops := l.ctx.Ops
+ l.Position.Count = len(children)
+ l.Position.OffsetLast = mainMax - size
pos := -l.Position.Offset
// ScrollToEnd lists are end aligned.
- if space := mainMax - size; l.ScrollToEnd && space > 0 {
+ if space := l.Position.OffsetLast; l.ScrollToEnd && space > 0 {
pos += space
}
for _, child := range children {
- sz := child.size
+ sz := l.Axis.Convert(child.size)
var cross int
switch l.Alignment {
case End:
- cross = maxCross - axisCross(l.Axis, sz)
+ cross = maxCross - sz.Y
case Middle:
- cross = (maxCross - axisCross(l.Axis, sz)) / 2
+ cross = (maxCross - sz.Y) / 2
}
- childSize := axisMain(l.Axis, sz)
+ childSize := sz.X
max := childSize + pos
if max > mainMax {
max = mainMax
@@ -254,14 +270,15 @@ func (l *List) layout() Dimensions {
min = 0
}
r := image.Rectangle{
- Min: axisPoint(l.Axis, min, -inf),
- Max: axisPoint(l.Axis, max, inf),
+ Min: l.Axis.Convert(image.Pt(min, -inf)),
+ Max: l.Axis.Convert(image.Pt(max, inf)),
}
- stack := op.Push(ops)
- clip.Rect{Rect: FRect(r)}.Op(ops).Add(ops)
- op.Offset(FPt(axisPoint(l.Axis, pos, cross))).Add(ops)
+ cl := clip.Rect(r).Push(ops)
+ pt := l.Axis.Convert(image.Pt(pos, cross))
+ trans := op.Offset(FPt(pt)).Push(ops)
child.call.Add(ops)
- stack.Pop()
+ trans.Pop()
+ cl.Pop()
pos += childSize
}
atStart := l.Position.First == 0 && l.Position.Offset <= 0
@@ -276,11 +293,33 @@ func (l *List) layout() Dimensions {
if pos > mainMax {
pos = mainMax
}
- dims := axisPoint(l.Axis, pos, maxCross)
- call := l.macro.Stop()
- defer op.Push(l.ctx.Ops).Pop()
- pointer.Rect(image.Rectangle{Max: dims}).Add(ops)
- l.scroll.Add(ops)
+ if crossMin, crossMax := l.Axis.crossConstraint(l.cs); maxCross < crossMin {
+ maxCross = crossMin
+ } else if maxCross > crossMax {
+ maxCross = crossMax
+ }
+ dims := l.Axis.Convert(image.Pt(pos, maxCross))
+ call := macro.Stop()
+ defer clip.Rect(image.Rectangle{Max: dims}).Push(ops).Pop()
+
+ var min, max int
+ if o := l.Position.Offset; o > 0 {
+ // Use the size of the invisible part as scroll boundary.
+ min = -o
+ } else if l.Position.First > 0 {
+ min = -inf
+ }
+ if o := l.Position.OffsetLast; o < 0 {
+ max = -o
+ } else if l.Position.First+l.Position.Count < l.len {
+ max = inf
+ }
+ scrollRange := image.Rectangle{
+ Min: l.Axis.Convert(image.Pt(min, 0)),
+ Max: l.Axis.Convert(image.Pt(max, 0)),
+ }
+ l.scroll.Add(ops, scrollRange)
+
call.Add(ops)
return Dimensions{Size: dims}
}