From fe4a61ec890fbc0989c07f39803966765342e372 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 11 Jul 2019 18:07:16 +0200 Subject: [PATCH] ui/layout: make List more friendly to for loops With this change, a List l can be iterated with for l.Init(...); l.More(); l.Next() { l.Elem(..., l.Constraints(), l.Index()) } instead of l.Init(...) for { i, cs, ok := l.Next() if !ok { break } l.End(..., cs, i)) } Signed-off-by: Elias Naur --- ui/layout/list.go | 53 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/ui/layout/list.go b/ui/layout/list.go index a383a564..c09dadb6 100644 --- a/ui/layout/list.go +++ b/ui/layout/list.go @@ -40,6 +40,10 @@ type List struct { maxSize int children []scrollChild dir iterationDir + + // Iterator state. + index int + more bool } type iterationDir uint8 @@ -50,7 +54,11 @@ const ( iterateBackward ) +// Init prepares the list for iterating through its elements with Next. func (l *List) Init(ops *ui.Ops, cs Constraints, len int) { + if l.more { + panic("unfinished element") + } l.update() l.ops = ops l.dir = iterateNone @@ -58,10 +66,12 @@ func (l *List) Init(ops *ui.Ops, cs Constraints, len int) { l.children = l.children[:0] l.cs = cs l.len = len + l.more = true if l.first > len { l.first = len } ops.Begin() + l.Next() } func (l *List) Dragging() bool { @@ -79,20 +89,35 @@ func (l *List) update() { l.offset += d } -func (l *List) Next() (int, Constraints, bool) { - if l.dir != iterateNone { - panic("a previous Next was not finished with Elem") +// Next advances the list to the next element. +func (l *List) Next() { + if !l.more { + panic("end of list reached") + } + i, more := l.next() + l.more = more + if !more { + return } - i, ok := l.next() if l.Invert { i = l.len - 1 - i } - var cs Constraints - if ok { - cs = axisConstraints(l.Axis, Constraint{Max: ui.Inf}, l.crossConstraintChild(l.cs)) - l.ops.Begin() - } - return i, cs, ok + l.index = i + l.ops.Begin() +} + +// Index is the current element index. +func (l *List) Index() int { + return l.index +} + +// Constraints is the constraints for the current element. +func (l *List) Constraints() Constraints { + return axisConstraints(l.Axis, Constraint{Max: ui.Inf}, l.crossConstraintChild(l.cs)) +} + +func (l *List) More() bool { + return l.more } func (l *List) next() (int, bool) { @@ -119,7 +144,8 @@ func (l *List) next() (int, bool) { return 0, false } -func (l *List) End(dims Dimens) { +// Elem completes an element. +func (l *List) Elem(dims Dimens) { block := l.ops.End() child := scrollChild{dims.Size, block} switch l.dir { @@ -134,12 +160,15 @@ func (l *List) End(dims Dimens) { l.maxSize += mainSize l.children = append([]scrollChild{child}, l.children...) default: - panic("call Next before End") + panic("call Next before Elem") } l.dir = iterateNone } func (l *List) Layout() Dimens { + if l.more { + panic("unfinished element") + } mainc := axisMainConstraint(l.Axis, l.cs) for len(l.children) > 0 { sz := l.children[0].size