tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 229TOML 101Markdown 82Shell 24052 Definiciones

⎇ c5a232cf24788ab75a850ffe81eca5a7af50e2f8 widgets/lazy-list/README.md Markdown · 51 líneas · 2.0 KB Historia crudo

chore: refresco desde el monorepo — 27 crates nuevos (anim, lottie, svg, mesh, image, layer, test, wire-view, widgets rag-sidebar/router/lazy-list/rive-button) y sync de los 95 existentes 93253cc22 · Sergio ·

1# llimphi-widget-lazy-list
2
3A turnkey **lazy** list.
4
5It attacks the "scroll without laziness" gap: `list`/`grid`/`table` **build every
6row handed to them**, and `scroll_y` receives content **already built** — so
7mounting 1M rows measured ~4 s/frame, because the whole tree is rebuilt each
8frame.
9
10This widget inverts the contract: instead of a ready-made `content: View`, it
11takes a **builder** `item: Fn(usize) -> View<Msg>` plus `total`, and **only calls
12`item(i)` for the visible window + overscan**. Off-screen rows do not exist: not
13built, not mounted, not laid out. The per-frame cost becomes ∝ *what is visible*,
14not ∝ *the total*.
15
16True to the Elm loop it is **stateless**: the `offset` (px) lives in the caller's
17`Model`, just as in `llimphi_widget_scroll`, whose scrollbar and physics (thumb,
18page jump, fling, rubber band) are reused as-is — this crate only adds the **real
19virtualization** that was missing.
20
21Two extent models:
22
23- `lazy_list_fixed` — rows of **uniform** height (`item_h`). O(1) window. Covers
24  90% of cases (logs, table rows, file lists).
25- `lazy_list_varied` — **per-row** height, through an array of accumulated
26  offsets **precomputed by the caller** (`offsets[i]` = top of row `i` in content
27  coordinates; `offsets[total]` = total height). O(log n) window by binary
28  search; the caller rebuilds `offsets` when the data or the heights change,
29  **not** every frame.
30
31```ignore
32// view (fixed item_h):
33lazy_list_fixed(
34    model.rows.len(),          // total
35    28.0,                      // item_h
36    model.offset,              // offset px (in the Model)
37    panel_h,                   // viewport_h
38    DEFAULT_OVERSCAN,
39    |i| row_view(&model.rows[i]),    // only called for what is visible
40    Msg::ScrollBy,                   // Fn(f32)->Msg, delta px
41    &ScrollPalette::default(),
42)
43// update:
44Msg::ScrollBy(d) => {
45    m.offset = clamp_offset(m.offset + d, m.rows.len() as f32 * 28.0, panel_h);
46}
47```
48
49---
50
51Part of **llimphi** — see [llimphi](../../README.md).

README.md

llimphi-widget-lazy-list

A turnkey lazy list.

It attacks the "scroll without laziness" gap: list/grid/table build every row handed to them, and scroll_y receives content already built — so mounting 1M rows measured ~4 s/frame, because the whole tree is rebuilt each frame.

This widget inverts the contract: instead of a ready-made content: View, it takes a builder item: Fn(usize) -> View<Msg> plus total, and only calls item(i) for the visible window + overscan. Off-screen rows do not exist: not built, not mounted, not laid out. The per-frame cost becomes ∝ what is visible, not ∝ the total.

True to the Elm loop it is stateless: the offset (px) lives in the caller's Model, just as in llimphi_widget_scroll, whose scrollbar and physics (thumb, page jump, fling, rubber band) are reused as-is — this crate only adds the real virtualization that was missing.

Two extent models:

// view (fixed item_h):
lazy_list_fixed(
    model.rows.len(),          // total
    28.0,                      // item_h
    model.offset,              // offset px (in the Model)
    panel_h,                   // viewport_h
    DEFAULT_OVERSCAN,
    |i| row_view(&model.rows[i]),    // only called for what is visible
    Msg::ScrollBy,                   // Fn(f32)->Msg, delta px
    &ScrollPalette::default(),
)
// update:
Msg::ScrollBy(d) => {
    m.offset = clamp_offset(m.offset + d, m.rows.len() as f32 * 28.0, panel_h);
}

Part of llimphi — see llimphi.