1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Virtualized list — a thin binding over gpui's `uniform_list`, and a bridge
//! that lets [`crate::scroll::scrollbar`] report on one.
//!
//! Thin on purpose: gpui already does the hard part, and a wrapper that only
//! re-exported it with extra steps would be worse than none. This module exists
//! for two things it can guarantee that a caller otherwise has to know.
//!
//! **The row height.** `uniform_list` measures the *first* row it renders and
//! lays every other one out at that height. Hand it rows of different heights
//! and nothing errors — the content simply overlaps, at a size nobody chose.
//! [`virtual_list`] takes the height and applies it to every row it hands back,
//! so that cannot happen by accident.
//!
//! **The scroll handle.** A `UniformListScrollHandle` wraps a real
//! [`ScrollHandle`] and gpui registers it as the list's tracked handle, so the
//! bar's geometry is all there — behind `handle.0.borrow().base_handle`, which
//! is not something a consumer should have to find by reading gpui's source.
//! [`scroll_handle`] is that reach, named.
//!
//! ## Why not gpui's `list()`
//!
//! gpui has a second virtualizer for rows of *varying* height, and it cannot
//! carry a proportional scrollbar: `ListState` speaks in `ListOffset { item_ix,
//! offset_in_item }` — logical position, not pixels — with no maximum offset
//! and no viewport. A thumb's length is the visible share of a total height, and
//! a variable-height list cannot know its total without measuring every row,
//! which is the work virtualization exists to skip. A list of thousands of rows
//! wants a bar; a list that needs varying heights is a different component, and
//! nothing has asked for one yet.
//!
//! ```ignore
//! div().relative().h(px(240.0))
//! .child(virtual_list("rows", rows.len(), px(28.0), &self.rows_scroll, {
//! let rows = rows.clone();
//! move |range, _, _| range.map(|ix| row(&rows[ix])).collect()
//! }))
//! .child(scroll::scrollbar("rows-bar", &list::scroll_handle(&self.rows_scroll), &self.rows_bar))
//! ```
use Range;
use ;
/// The pixel-space scroll handle inside a `UniformListScrollHandle`.
///
/// `uniform_list` tracks its scrolling through this one, so it carries the
/// offset, the maximum offset and the viewport that [`crate::scroll::thumb`]
/// needs — a virtualized list takes the same bar as any other scroller, with no
/// second implementation behind a trait.
///
/// The clone shares state rather than copying it: the returned handle *is* the
/// list's, and moving one moves the other.
/// A list that builds only the rows on screen.
///
/// `render` is handed the visible range and returns one element per index in
/// it; each comes back sized to `row_height`, which is what keeps the list
/// uniform and therefore virtualizable at all.
///
/// Fills its parent, which is the other thing that has to be true for any of
/// this to work: a list with no height of its own collapses, and a collapsed
/// list builds a single row to measure and then nothing — an empty box, no
/// error, no clue. A virtualized list is bounded by definition, so filling is
/// the only sane default; a caller wanting otherwise sets its own size after,
/// and the later call wins.