gioser

tawasuyu/llimphi

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

Rust 229TOML 101Markdown 82Shell 24052 Definiciones

⎇ main widgets/lazy-list/LEEME.md Markdown · 52 líneas · 2.1 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
3*Read this in English: [README.md](README.md).*
4
5Lista **perezosa** llave-en-mano.
6
7Bloque 22 de `PLAN-NUCLEO-RETENIDO.md`. Ataca la Brecha #2 (scroll sin
8lazy): hoy `list`/`grid`/`table` **construyen todas las filas que se les
9pasan**, y `scroll_y` recibe el contenido **ya construido** — así, montar
101M de filas mide ~4 s/frame porque el árbol entero se rearma cada cuadro
11(ver el baseline del Bloque 21).
12
13Este widget invierte el contrato: en vez de un `content: View` ya armado,
14recibe un **builder** `item: Fn(usize) -> View<Msg>` + `total`, y **sólo
15llama `item(i)` para la ventana visible + overscan**. Las filas fuera de
16pantalla no existen: no se construyen, no se montan, no se layoutean. El
17costo por frame pasa a ser ∝ *lo visible*, no ∝ *el total*.
18
19Fiel al bucle Elm, es **sin estado**: el `offset` (px) vive en el `Model`
20del caller, igual que en `llimphi_widget_scroll`, cuya barra/física
21(thumb, page-jump, fling, rubber-band) se reusa tal cual — este crate sólo
22agrega la **virtualización real** que faltaba.
23
24Dos modelos de extent:
25- `lazy_list_fixed` — filas de alto **uniforme** (`item_h`). Ventana O(1).
26  Cubre el 90% (logs, filas de tabla, file-lists).
27- `lazy_list_varied` — alto **por fila**, vía un arreglo de offsets
28  acumulados **precomputado por el caller** (`offsets[i]` = tope de la fila
29  `i` en coords de contenido; `offsets[total]` = alto total). Ventana
30  O(log n) por búsqueda binaria; el caller reconstruye `offsets` cuando
31  cambian los datos/alturas, **no** por frame.
32```ignore
33// view (item_h fijo):
34lazy_list_fixed(
35    model.rows.len(),          // total
36    28.0,                      // item_h
37    model.offset,              // offset px (en el Model)
38    panel_h,                   // viewport_h
39    DEFAULT_OVERSCAN,
40    |i| fila_view(&model.rows[i]),   // sólo se llama para lo visible
41    Msg::ScrollBy,                   // Fn(f32)->Msg, delta px
42    &ScrollPalette::default(),
43)
44// update:
45Msg::ScrollBy(d) => {
46    m.offset = clamp_offset(m.offset + d, m.rows.len() as f32 * 28.0, panel_h);
47}
48```
49
50---
51
52Parte de **llimphi** — ver [llimphi](../../LEEME.md).

LEEME.md

llimphi-widget-lazy-list

Read this in English: README.md.

Lista perezosa llave-en-mano.

Bloque 22 de PLAN-NUCLEO-RETENIDO.md. Ataca la Brecha #2 (scroll sin lazy): hoy list/grid/table construyen todas las filas que se les pasan, y scroll_y recibe el contenido ya construido — así, montar 1M de filas mide ~4 s/frame porque el árbol entero se rearma cada cuadro (ver el baseline del Bloque 21).

Este widget invierte el contrato: en vez de un content: View ya armado, recibe un builder item: Fn(usize) -> View<Msg> + total, y sólo llama item(i) para la ventana visible + overscan. Las filas fuera de pantalla no existen: no se construyen, no se montan, no se layoutean. El costo por frame pasa a ser ∝ lo visible, no ∝ el total.

Fiel al bucle Elm, es sin estado: el offset (px) vive en el Model del caller, igual que en llimphi_widget_scroll, cuya barra/física (thumb, page-jump, fling, rubber-band) se reusa tal cual — este crate sólo agrega la virtualización real que faltaba.

Dos modelos de extent:

// view (item_h fijo):
lazy_list_fixed(
    model.rows.len(),          // total
    28.0,                      // item_h
    model.offset,              // offset px (en el Model)
    panel_h,                   // viewport_h
    DEFAULT_OVERSCAN,
    |i| fila_view(&model.rows[i]),   // sólo se llama para lo 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);
}

Parte de llimphi — ver llimphi.