Skip to content

Commit

Permalink
properly validate offset in ScrollToOffset + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dweymouth committed Feb 22, 2024
1 parent be7222e commit a81c82d
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 33 deletions.
71 changes: 41 additions & 30 deletions widget/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,17 @@ func (l *List) ScrollToTop() {
//
// Since: 2.5
func (l *List) ScrollToOffset(offset float32) {
if l.scroller != nil {
l.scroller.Offset.Y = offset
l.offsetUpdated(l.scroller.Offset)
if l.scroller == nil {
return
}
if offset < 0 {
offset = 0
} else if h := l.contentMinSize().Height; offset > h {
offset = h
}
l.scroller.Offset.Y = offset
l.offsetUpdated(l.scroller.Offset)
l.Refresh()
}

// GetScrollOffset returns the current scroll offset position
Expand Down Expand Up @@ -338,6 +345,36 @@ func (l *List) UnselectAll() {
}
}

func (l *List) contentMinSize() fyne.Size {
l.propertyLock.Lock()
defer l.propertyLock.Unlock()
items := 0
if f := l.Length; f == nil {
return fyne.NewSize(0, 0)
} else {
items = f()
}

separatorThickness := theme.Padding()
if l.itemHeights == nil || len(l.itemHeights) == 0 {
return fyne.NewSize(l.itemMin.Width,
(l.itemMin.Height+separatorThickness)*float32(items)-separatorThickness)
}

height := float32(0)
templateHeight := l.itemMin.Height
for item := 0; item < items; item++ {
itemHeight, ok := l.itemHeights[item]
if ok {
height += itemHeight
} else {
height += templateHeight
}
}

return fyne.NewSize(l.itemMin.Width, height+separatorThickness*float32(items-1))
}

// fills l.visibleRowHeights and also returns offY and minRow
func (l *listLayout) calculateVisibleRowHeights(itemHeight float32, length int) (offY float32, minRow int) {
rowOffset := float32(0)
Expand Down Expand Up @@ -575,33 +612,7 @@ func (l *listLayout) Layout([]fyne.CanvasObject, fyne.Size) {
}

func (l *listLayout) MinSize([]fyne.CanvasObject) fyne.Size {
l.list.propertyLock.Lock()
defer l.list.propertyLock.Unlock()
items := 0
if f := l.list.Length; f == nil {
return fyne.NewSize(0, 0)
} else {
items = f()
}

separatorThickness := theme.Padding()
if l.list.itemHeights == nil || len(l.list.itemHeights) == 0 {
return fyne.NewSize(l.list.itemMin.Width,
(l.list.itemMin.Height+separatorThickness)*float32(items)-separatorThickness)
}

height := float32(0)
templateHeight := l.list.itemMin.Height
for item := 0; item < items; item++ {
itemHeight, ok := l.list.itemHeights[item]
if ok {
height += itemHeight
} else {
height += templateHeight
}
}

return fyne.NewSize(l.list.itemMin.Width, height+separatorThickness*float32(items-1))
return l.list.contentMinSize()
}

func (l *listLayout) getItem() *listItem {
Expand Down
10 changes: 7 additions & 3 deletions widget/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,17 @@ func TestList_ScrollToTop(t *testing.T) {
}

func TestList_ScrollOffset(t *testing.T) {
list := createList(1000)
list := createList(10)

offset := float32(25)
list.ScrollToOffset(25)
assert.Equal(t, offset, list.offsetY)
assert.Equal(t, offset, list.scroller.Offset.Y)
assert.Equal(t, offset, list.GetScrollOffset())

list.ScrollToOffset(-2)
assert.Equal(t, float32(0), list.GetScrollOffset())

list.ScrollToOffset(1000)
assert.LessOrEqual(t, list.GetScrollOffset(), float32(500) /*upper bound on content height*/)
}

func TestList_Selection(t *testing.T) {
Expand Down

0 comments on commit a81c82d

Please sign in to comment.