Documentation
¶
Overview ¶
Package virtual adds live-data list virtualization on top of the go-widgets/toolkit widget set. Where the core ListBox / Table / TreeView window a static []string, the widgets here bind to a live mvvm.ObservableList and realise ONLY the rows (or cells) that intersect the viewport, so a model with a million items costs the same per frame as one with a handful.
Two widgets are provided, both toolkit.Widget (Draw / OnEvent / Bounds / SetBounds via the embedded toolkit.Base):
- VirtualList — a scrollable vertical list with a per-row draw callback and optional VARIABLE row heights. The scroll-offset → first-visible-row lookup is O(1) when every row is the same height and O(log n) via a Fenwick (binary-indexed) prefix-sum tree when heights vary.
- VirtualGrid — the gengrid analogue: it reflows N uniform cells into as many columns as the width allows and realises only the visible cells.
Both subscribe to their model's ListEvent stream and keep the scroll anchor stable across mutations: an insert (or remove) ABOVE the viewport shifts the offset so the rows on screen do not jump, while a change below the top item leaves the offset untouched. Rendering reuses painter.Clipper (when the back-end supports it) to clip the partially-visible trailing item to the exact viewport edge.
Index ¶
- Constants
- type VirtualGrid
- func (g *VirtualGrid[T]) Close()
- func (g *VirtualGrid[T]) Draw(p painter.Painter, th *toolkit.Theme)
- func (g *VirtualGrid[T]) OnEvent(ev toolkit.Event)
- func (g *VirtualGrid[T]) ScrollBy(delta int)
- func (g *VirtualGrid[T]) ScrollByRows(delta int)
- func (g *VirtualGrid[T]) ScrollTo(offset int)
- func (g *VirtualGrid[T]) SetBounds(r toolkit.Rect)
- func (g *VirtualGrid[T]) VisibleRange() (first, count int)
- type VirtualList
- func (v *VirtualList[T]) Close()
- func (v *VirtualList[T]) Draw(p painter.Painter, th *toolkit.Theme)
- func (v *VirtualList[T]) OnEvent(ev toolkit.Event)
- func (v *VirtualList[T]) ScrollBy(delta int)
- func (v *VirtualList[T]) ScrollByRows(delta int)
- func (v *VirtualList[T]) ScrollTo(offset int)
- func (v *VirtualList[T]) VisibleRange() (first, count int)
Constants ¶
const DefaultRowHeight = 20
DefaultRowHeight is the row height a VirtualList uses when its RowHeight callback is nil — a comfortable uniform default that mirrors the core ListBox's proportions.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type VirtualGrid ¶
type VirtualGrid[T any] struct { toolkit.Base // Model is the live backing collection. Model *mvvm.ObservableList[T] // CellSize is every cell's fixed footprint in painter units. CellSize toolkit.Size // Render draws one cell into rectangle r (its exact on-screen span), // invoked only for the cells currently in the viewport. Render func(p painter.Painter, th *toolkit.Theme, r toolkit.Rect, i int, item T) // ScrollOffset is the pixel offset of the viewport top from the top of the // content. Reads clamp it; prefer ScrollTo / ScrollBy. ScrollOffset int // contains filtered or unexported fields }
VirtualGrid reflows N uniform-sized cells (CellSize) into as many columns as the widget width allows and realises only the cells that intersect the viewport — the recycled 2-D card / thumbnail grid. It binds to a live mvvm.ObservableList and keeps its scroll anchor stable across mutations above the viewport, exactly like VirtualList.
func NewVirtualGrid ¶
func NewVirtualGrid[T any]( model *mvvm.ObservableList[T], cell toolkit.Size, render func(p painter.Painter, th *toolkit.Theme, r toolkit.Rect, i int, item T), ) *VirtualGrid[T]
NewVirtualGrid builds a VirtualGrid over model with the given cell size and draw callback, wiring the model subscription immediately.
func (*VirtualGrid[T]) Close ¶
func (g *VirtualGrid[T]) Close()
Close unsubscribes from the model. Safe to call more than once.
func (*VirtualGrid[T]) Draw ¶
func (g *VirtualGrid[T]) Draw(p painter.Painter, th *toolkit.Theme)
Draw paints only the cells intersecting the viewport, each at its reflowed column/row position minus the scroll offset. When the content overflows it clips (if the painter supports Clipper) so partially-visible edge rows are trimmed to the viewport.
func (*VirtualGrid[T]) OnEvent ¶
func (g *VirtualGrid[T]) OnEvent(ev toolkit.Event)
OnEvent handles a wheel EventScroll by scrolling whole cell-rows; every other event kind is ignored.
func (*VirtualGrid[T]) ScrollBy ¶
func (g *VirtualGrid[T]) ScrollBy(delta int)
ScrollBy shifts the pixel scroll offset by delta, clamped.
func (*VirtualGrid[T]) ScrollByRows ¶
func (g *VirtualGrid[T]) ScrollByRows(delta int)
ScrollByRows shifts the viewport by whole cell-rows (negative scrolls up).
func (*VirtualGrid[T]) ScrollTo ¶
func (g *VirtualGrid[T]) ScrollTo(offset int)
ScrollTo sets the pixel scroll offset, clamped to the valid range, and resyncs the anchor.
func (*VirtualGrid[T]) SetBounds ¶
func (g *VirtualGrid[T]) SetBounds(r toolkit.Rect)
SetBounds positions the grid and resyncs the anchor, since a width change reflows the columns (and so changes which item sits at the top-left).
func (*VirtualGrid[T]) VisibleRange ¶
func (g *VirtualGrid[T]) VisibleRange() (first, count int)
VisibleRange returns the index of the first visible cell and the number of cells intersecting the viewport (a whole number of rows' worth, clamped to the model length). Allocation-free.
type VirtualList ¶
type VirtualList[T any] struct { toolkit.Base // Model is the live backing collection. Setting it (via the field or // NewVirtualList) rewires the subscription on the next operation. Model *mvvm.ObservableList[T] // RowHeight returns row i's pixel height. A constant function yields the // uniform O(1) fast path; a varying one drives the Fenwick index. nil means // a uniform DefaultRowHeight. RowHeight func(i int) int // Render draws one row into rectangle r (its exact on-screen span). It is // invoked only for rows currently in the viewport. Render func(p painter.Painter, th *toolkit.Theme, r toolkit.Rect, i int, item T) // ScrollOffset is the pixel offset of the viewport top from the top of the // content. Reads clamp it to [0, maxOffset]; prefer ScrollTo / ScrollBy. ScrollOffset int // contains filtered or unexported fields }
VirtualList binds a scrollable vertical list to a live mvvm.ObservableList and a per-row draw callback, realising only the rows that intersect the viewport. Row heights may be uniform (a constant RowHeight, or nil for DefaultRowHeight) or variable (an arbitrary RowHeight function); the scroll-offset → first-visible-row lookup is O(1) in the uniform case and O(log n) via a Fenwick prefix-sum tree in the variable case. It subscribes to the model and holds the scroll anchor stable across inserts / removes above the viewport.
func NewVirtualList ¶
func NewVirtualList[T any]( model *mvvm.ObservableList[T], rowHeight func(i int) int, render func(p painter.Painter, th *toolkit.Theme, r toolkit.Rect, i int, item T), ) *VirtualList[T]
NewVirtualList builds a VirtualList over model with the given per-row height and draw callbacks, wiring the model subscription immediately.
func (*VirtualList[T]) Close ¶
func (v *VirtualList[T]) Close()
Close unsubscribes from the model. Safe to call more than once.
func (*VirtualList[T]) Draw ¶
func (v *VirtualList[T]) Draw(p painter.Painter, th *toolkit.Theme)
Draw paints only the rows intersecting the viewport, positioning row i at its exact content Y minus the scroll offset. When the content overflows the bounds it pushes a clip rect (if the painter supports Clipper) so the partially-visible trailing (and leading) row is clipped to the viewport edge.
func (*VirtualList[T]) OnEvent ¶
func (v *VirtualList[T]) OnEvent(ev toolkit.Event)
OnEvent handles a wheel EventScroll by scrolling whole rows; every other event kind is ignored (the row-content widgets the Render callback draws handle their own input).
func (*VirtualList[T]) ScrollBy ¶
func (v *VirtualList[T]) ScrollBy(delta int)
ScrollBy shifts the pixel scroll offset by delta, clamped.
func (*VirtualList[T]) ScrollByRows ¶
func (v *VirtualList[T]) ScrollByRows(delta int)
ScrollByRows shifts the viewport by whole rows (negative scrolls up), snapping the offset to the resulting row's top so wheel scrolling advances a row at a time regardless of variable heights.
func (*VirtualList[T]) ScrollTo ¶
func (v *VirtualList[T]) ScrollTo(offset int)
ScrollTo sets the pixel scroll offset, clamped to the valid range.
func (*VirtualList[T]) VisibleRange ¶
func (v *VirtualList[T]) VisibleRange() (first, count int)
VisibleRange returns the index of the first visible row and the number of rows that intersect the viewport (including the partially-visible top and bottom rows). It is O(1) for uniform heights and O(log n) otherwise, and allocation-free, so it is safe to call every scroll tick.