aetna_core/scroll.rs
1//! App-side scroll request types.
2//!
3//! Apps push [`ScrollRequest`]s via [`crate::App::drain_scroll_requests`];
4//! the layout pass resolves each one against the matching scroll
5//! container's live viewport rect and writes the resulting offset into
6//! the scroll state so the same frame's render reflects the new position.
7//!
8//! Mirrors [`crate::toast`]: the App produces fire-and-forget descriptors
9//! and the runtime resolves them with state that's only fully known
10//! mid-frame.
11
12/// Where in the viewport a row-targeted [`ScrollRequest`] should land
13/// its target row.
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum ScrollAlignment {
16 /// Top of the row aligns with the top of the viewport.
17 Start,
18 /// Centre of the row aligns with the centre of the viewport.
19 Center,
20 /// Bottom of the row aligns with the bottom of the viewport.
21 End,
22 /// No-op if the row already fits entirely inside the viewport;
23 /// otherwise scroll the minimum amount that brings it into view
24 /// (i.e., align to the nearer edge).
25 Visible,
26}
27
28/// What the app produces from [`crate::App::drain_scroll_requests`].
29/// Three shapes today:
30///
31/// - [`ScrollRequest::ToRow`] — "scroll the virtual list keyed
32/// `list_key` so row `row` lands per `align`." Resolved during
33/// layout of the matching `virtual_list` / `virtual_list_dyn` using
34/// the live viewport and the row-height cache.
35/// - [`ScrollRequest::ToRowKey`] — same operation, but targets the
36/// virtual-list row by stable row identity instead of current row
37/// index. Prefer this for `virtual_list_dyn` when the app already
38/// has message/thread/commit ids.
39/// - [`ScrollRequest::EnsureVisible`] — "scroll the nearest scroll
40/// container under the node keyed `container_key` so the content-
41/// space rect `y..y+h` is visible." Resolved during layout of the
42/// matching `scroll(...)` container; minimal-displacement (top edge
43/// if above viewport, bottom edge if below, no-op if already
44/// visible). Used by [`crate::widgets::text_area`] for
45/// caret-into-view on keyboard navigation, and available for any
46/// widget that needs to keep an inner anchor on screen.
47#[derive(Clone, Debug)]
48pub enum ScrollRequest {
49 /// Bring `row` of the virtual list keyed `list_key` into view per
50 /// `align`.
51 ToRow {
52 list_key: String,
53 row: usize,
54 align: ScrollAlignment,
55 },
56 /// Bring the row identified by `row_key` in the virtual list keyed
57 /// `list_key` into view per `align`.
58 ToRowKey {
59 list_key: String,
60 row_key: String,
61 align: ScrollAlignment,
62 },
63 /// Ensure the content-space rect at `y..y+h` is visible inside
64 /// the scroll container under the node keyed `container_key`.
65 /// `container_key` is the outer widget's key (e.g. the text_area's
66 /// key) — the resolver descends to find the nearest `Kind::Scroll`
67 /// inside that node.
68 EnsureVisible {
69 container_key: String,
70 y: f32,
71 h: f32,
72 },
73}
74
75impl ScrollRequest {
76 /// Construct a [`ScrollRequest::ToRow`]. Kept for source-compat
77 /// with callers that predate the enum — `ScrollRequest::new(...)`
78 /// has always meant "scroll a virtual list to a row."
79 pub fn new(list_key: impl Into<String>, row: usize, align: ScrollAlignment) -> Self {
80 ScrollRequest::ToRow {
81 list_key: list_key.into(),
82 row,
83 align,
84 }
85 }
86
87 /// Construct a [`ScrollRequest::ToRowKey`]. Dynamic virtual lists
88 /// resolve this against the same stable row identities passed to
89 /// [`crate::virtual_list_dyn`].
90 pub fn to_row_key(
91 list_key: impl Into<String>,
92 row_key: impl Into<String>,
93 align: ScrollAlignment,
94 ) -> Self {
95 ScrollRequest::ToRowKey {
96 list_key: list_key.into(),
97 row_key: row_key.into(),
98 align,
99 }
100 }
101
102 /// Construct a [`ScrollRequest::EnsureVisible`] for the widget
103 /// keyed `container_key`, asking the resolver to keep
104 /// `y..y+h` (in the scroll container's content coordinates)
105 /// inside the viewport.
106 pub fn ensure_visible(container_key: impl Into<String>, y: f32, h: f32) -> Self {
107 ScrollRequest::EnsureVisible {
108 container_key: container_key.into(),
109 y,
110 h,
111 }
112 }
113}