mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
layout: add API for efficiently scrolling to and by items
The majority of scrolling happens by manipulating the index of the first displayed item instead of by just manipulating the offset. This lets us avoid having to render all items that were scrolled past. Instead of numbers of items we could've accepted a ratio in [0, 1] to scroll by or to, to match the data we get from scrollbars. However, there are more use cases for scrolling by items, such as keyboard shortcuts, go-to dialogs, etc. And converting from [0, 1] to items is trivial for the user as long as they know the number of items, and will usually be handled for them by a theme. Signed-off-by: Dominik Honnef <dominik@honnef.co>
This commit is contained in:
committed by
Elias Naur
parent
bb12508a8a
commit
8af4472672
@@ -4,6 +4,7 @@ package layout
|
||||
|
||||
import (
|
||||
"image"
|
||||
"math"
|
||||
|
||||
"gioui.org/gesture"
|
||||
"gioui.org/op"
|
||||
@@ -354,3 +355,33 @@ func (l *List) layout(ops *op.Ops, macro op.MacroOp) Dimensions {
|
||||
call.Add(ops)
|
||||
return Dimensions{Size: dims}
|
||||
}
|
||||
|
||||
// ScrollBy scrolls the list by a relative amount of items. The result will only be accurate if all items have the same
|
||||
// height. Otherwise, it will be approximate.
|
||||
func (l *List) ScrollBy(num float32) {
|
||||
// Split number of items into integer and fractional parts
|
||||
i, f := math.Modf(float64(num))
|
||||
|
||||
// Scroll by integer amount of items
|
||||
l.Position.First += int(i)
|
||||
|
||||
// Adjust Offset to account for fractional items. If Offset gets so large that it amounts to an entire item, then
|
||||
// the layout code will handle that for us and adjust First and Offset accordingly.
|
||||
itemHeight := float64(l.Position.Length) / float64(l.len)
|
||||
l.Position.Offset += int(math.Round(itemHeight * f))
|
||||
|
||||
// First and Offset can go out of bounds, but the layout code knows how to handle that.
|
||||
|
||||
// Ensure that the list pays attention to the Offset field when the scrollbar drag
|
||||
// is started while the bar is at the end of the list. Without this, the scrollbar
|
||||
// cannot be dragged away from the end.
|
||||
l.Position.BeforeEnd = true
|
||||
}
|
||||
|
||||
// ScrollTo scrolls to the specified item. THe result will only be accurate if all items have the same height.
|
||||
// Otherwise, it will be approximate.
|
||||
func (l *List) ScrollTo(n int) {
|
||||
l.Position.First = 0
|
||||
l.Position.Offset = 0
|
||||
l.ScrollBy(float32(n))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user