pinned_headers/
pinned_headers.rs

1// Example: pinned/sticky rows via range_extractor + IndexEmitter.
2use std::sync::Arc;
3
4use virtualizer::{IndexEmitter, Range, Virtualizer, VirtualizerOptions};
5
6fn main() {
7    // Example: pinned/sticky "headers" at fixed indexes.
8    let mut opts = VirtualizerOptions::new(1_000, |_| 1);
9    opts.overscan = 2;
10
11    let pinned: Arc<[usize]> = Arc::from([0usize, 10, 20, 30, 40, 999]);
12    opts.range_extractor = Some(Arc::new({
13        let pinned = Arc::clone(&pinned);
14        move |r: Range, emit: &mut dyn FnMut(usize)| {
15            let mut e = IndexEmitter::new(r, emit);
16            // IMPORTANT: indexes must be emitted in ascending order.
17            //
18            // We want pinned rows both before and after the overscanned range. To keep the output
19            // sorted, emit:
20            // 1) pinned indexes before the overscanned range
21            // 2) the overscanned contiguous range
22            // 3) pinned indexes after the overscanned range
23            let overscanned_start = r.start_index.saturating_sub(r.overscan);
24            let overscanned_end = r.end_index.saturating_add(r.overscan).min(r.count);
25
26            for &idx in pinned.iter() {
27                if idx < overscanned_start {
28                    e.emit_pinned(idx);
29                }
30            }
31
32            e.emit_overscanned();
33
34            for &idx in pinned.iter() {
35                if idx >= overscanned_end {
36                    e.emit_pinned(idx);
37                }
38            }
39        }
40    }));
41
42    let mut v = Virtualizer::new(opts);
43    v.set_viewport_and_scroll_clamped(10, 500);
44
45    let mut collected = Vec::new();
46    v.for_each_virtual_index(|i| collected.push(i));
47
48    println!("visible_range={:?}", v.visible_range());
49    println!("virtual_range={:?}", v.virtual_range());
50    println!(
51        "indexes_len={} first_20={:?}",
52        collected.len(),
53        &collected[..20.min(collected.len())]
54    );
55
56    // A real UI would typically iterate items:
57    let mut headers = 0usize;
58    v.for_each_virtual_item(|it| {
59        if pinned.binary_search(&it.index).is_ok() {
60            headers += 1;
61        }
62    });
63    println!("pinned_headers_in_output={headers}");
64}