tui_lipan/widgets/scroll_view/
mod.rs1pub mod layout;
4pub mod node;
5pub mod reconcile;
6pub(crate) mod utils;
7
8pub(crate) use self::layout::measure_scroll_view;
9pub(crate) use self::reconcile::{ScrollViewReconcile, reconcile_scroll_view};
10
11use crate::callback::Callback;
12use crate::core::element::{Element, ElementKind, Key};
13use crate::style::{Align, BorderStyle, Length, Padding, ScrollbarConfig, Style};
14use crate::widgets::internal::StackProps;
15
16pub(crate) use self::node::RememberedScrollAnchor;
17pub use self::node::ScrollViewNode;
18
19pub use crate::widgets::scroll::{
20 ScrollAxis, ScrollBehavior, ScrollChildExitDirection, ScrollChildVisibility, ScrollClip,
21 ScrollDistanceConfig, ScrollEvent, ScrollExitedChild, ScrollKeymap, ScrollMetrics,
22 ScrollRequest, ScrollTarget, ScrollViewportEvent, ScrollVisibleChild, ScrollWheelBehavior,
23 ScrollWheelConfig,
24};
25
26#[derive(Clone)]
28pub struct ScrollView {
29 pub(crate) props: StackProps,
31 pub(crate) offset: Option<usize>,
33 pub(crate) horizontal_reveal_range: Option<(usize, usize)>,
35 pub(crate) scroll_request: Option<ScrollRequest>,
37 pub(crate) scroll_target: Option<ScrollTarget>,
39 pub(crate) scroll_behavior: ScrollBehavior,
41 pub(crate) scroll_keys: ScrollKeymap,
43 pub(crate) scroll_wheel: bool,
45 pub(crate) scroll_wheel_multiplier: Option<u16>,
47 pub(crate) h_scroll_wheel_multiplier: Option<u16>,
50 pub(crate) scroll_wheel_behavior: ScrollWheelBehavior,
52 pub(crate) ambient_page_scroll: bool,
54 pub(crate) focusable: bool,
56 pub(crate) on_scroll: Option<Callback<ScrollEvent>>,
58 pub(crate) on_scroll_to: Option<Callback<usize>>,
60 pub(crate) on_viewport_change: Option<Callback<ScrollViewportEvent>>,
62 pub(crate) scrollbar: bool,
64 pub(crate) scrollbar_config: ScrollbarConfig,
66 pub(crate) show_scroll_indicators: bool,
68 pub(crate) scroll_indicator_style: Style,
69 pub(crate) clip_mode: ScrollClip,
70 pub(crate) estimated_child_height: u16,
74 pub(crate) scroll_state_key: Option<Key>,
80 pub(crate) axis: ScrollAxis,
82 pub(crate) h_scrollbar: bool,
84 pub(crate) h_scrollbar_config: ScrollbarConfig,
86 pub(crate) children: Vec<Element>,
88}
89
90impl Default for ScrollView {
91 fn default() -> Self {
92 Self {
93 props: StackProps::default(),
94 offset: None,
95 horizontal_reveal_range: None,
96 scroll_request: None,
97 scroll_target: None,
98 scroll_behavior: ScrollBehavior::default(),
99 scroll_keys: ScrollKeymap::default(),
100 scroll_wheel: true,
101 scroll_wheel_multiplier: None,
102 h_scroll_wheel_multiplier: None,
103 scroll_wheel_behavior: ScrollWheelBehavior::default(),
104 ambient_page_scroll: false,
105 focusable: false,
106 on_scroll: None,
107 on_scroll_to: None,
108 on_viewport_change: None,
109 scrollbar: false,
110 scrollbar_config: ScrollbarConfig::default(),
111 show_scroll_indicators: false,
112 scroll_indicator_style: Style::default(),
113 clip_mode: ScrollClip::default(),
114 estimated_child_height: 3,
115 scroll_state_key: None,
116 axis: ScrollAxis::default(),
117 h_scrollbar: false,
118 h_scrollbar_config: ScrollbarConfig::default(),
119 children: Vec::new(),
120 }
121 }
122}
123
124impl ScrollView {
125 pub fn new() -> Self {
127 Self::default()
128 }
129
130 pub fn child(mut self, child: impl Into<Element>) -> Self {
132 self.children.push(child.into());
133 self
134 }
135
136 pub fn children(mut self, children: impl IntoIterator<Item = Element>) -> Self {
139 self.children = children.into_iter().collect();
140 self
141 }
142
143 pub fn border(mut self, border: bool) -> Self {
145 self.props.border = border;
146 self
147 }
148
149 pub fn border_style(mut self, border_style: BorderStyle) -> Self {
151 self.props.border_style = border_style;
152 self
153 }
154
155 pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
157 self.props.padding = padding.into();
158 self
159 }
160
161 pub fn style(mut self, style: Style) -> Self {
163 self.props.style = style;
164 self
165 }
166
167 pub fn gap(mut self, gap: u16) -> Self {
169 self.props.gap = gap;
170 self
171 }
172
173 pub fn width(mut self, width: Length) -> Self {
175 self.props.width = width;
176 self
177 }
178
179 pub fn height(mut self, height: Length) -> Self {
181 self.props.height = height;
182 self
183 }
184
185 pub fn align(mut self, align: Align) -> Self {
187 self.props.align = align;
188 self
189 }
190
191 pub fn offset(mut self, offset: usize) -> Self {
193 self.offset = Some(offset);
194 self
195 }
196
197 pub fn reveal_horizontal_range(mut self, start: usize, end: usize) -> Self {
202 self.horizontal_reveal_range = Some((start.min(end), start.max(end)));
203 self
204 }
205
206 pub fn scroll_request(mut self, request: ScrollRequest) -> Self {
213 self.scroll_request = Some(request);
214 self
215 }
216
217 pub fn scroll_to(mut self, target: ScrollTarget) -> Self {
224 self.scroll_target = Some(target);
225 self
226 }
227
228 pub fn scroll_to_top(self) -> Self {
230 self.scroll_to(ScrollTarget::Top)
231 }
232
233 pub fn scroll_to_bottom(self) -> Self {
235 self.scroll_to(ScrollTarget::Bottom)
236 }
237
238 pub fn scroll_to_key(mut self, key: impl Into<Key>) -> Self {
244 self.scroll_target = Some(ScrollTarget::Key(key.into()));
245 self
246 }
247
248 pub fn scroll_to_key_offset(mut self, key: impl Into<Key>, offset: usize) -> Self {
254 self.scroll_target = Some(ScrollTarget::key_offset(key, offset));
255 self
256 }
257
258 pub fn scroll_behavior(mut self, behavior: ScrollBehavior) -> Self {
264 self.scroll_behavior = behavior;
265 self
266 }
267
268 pub fn scroll_transition(mut self, config: crate::animation::TransitionConfig) -> Self {
270 self.scroll_behavior = ScrollBehavior::smooth(config);
271 self
272 }
273
274 pub fn scroll_state_key(mut self, key: impl Into<Key>) -> Self {
281 self.scroll_state_key = Some(key.into());
282 self
283 }
284
285 pub fn scroll_keys(mut self, keys: ScrollKeymap) -> Self {
287 self.scroll_keys = keys;
288 if keys != ScrollKeymap::NONE {
289 self.focusable = true;
290 }
291 self
292 }
293
294 pub fn scroll_wheel(mut self, enabled: bool) -> Self {
296 self.scroll_wheel = enabled;
297 self
298 }
299
300 pub fn scroll_wheel_multiplier(mut self, multiplier: u16) -> Self {
302 self.scroll_wheel_multiplier = Some(multiplier.max(1));
303 self
304 }
305
306 pub fn h_scroll_wheel_multiplier(mut self, multiplier: u16) -> Self {
313 self.h_scroll_wheel_multiplier = Some(multiplier.max(1));
314 self
315 }
316
317 pub fn scroll_wheel_behavior(mut self, behavior: ScrollWheelBehavior) -> Self {
319 self.scroll_wheel_behavior = behavior;
320 self
321 }
322
323 pub fn smooth_wheel_scroll(mut self, enabled: bool) -> Self {
325 self.scroll_wheel_behavior = if enabled {
326 ScrollWheelBehavior::smooth_default()
327 } else {
328 ScrollWheelBehavior::Immediate
329 };
330 self
331 }
332
333 pub fn scroll_acceleration(mut self, acceleration: f32) -> Self {
335 let mut config = match self.scroll_wheel_behavior {
336 ScrollWheelBehavior::Immediate => ScrollWheelConfig::default(),
337 ScrollWheelBehavior::Smooth(config) => config,
338 };
339 config.acceleration = acceleration;
340 self.scroll_wheel_behavior = ScrollWheelBehavior::Smooth(config);
341 self
342 }
343
344 pub fn ambient_page_scroll(mut self, enabled: bool) -> Self {
349 self.ambient_page_scroll = enabled;
350 self
351 }
352
353 pub fn focusable(mut self, focusable: bool) -> Self {
355 self.focusable = focusable;
356 self
357 }
358
359 pub fn on_scroll(mut self, cb: Callback<ScrollEvent>) -> Self {
361 self.on_scroll = Some(cb);
362 self
363 }
364
365 pub fn on_scroll_to(mut self, cb: Callback<usize>) -> Self {
367 self.on_scroll_to = Some(cb);
368 self
369 }
370
371 pub fn on_viewport_change(mut self, cb: Callback<ScrollViewportEvent>) -> Self {
373 self.on_viewport_change = Some(cb);
374 self
375 }
376
377 pub fn scrollbar(mut self, scrollbar: bool) -> Self {
379 self.scrollbar = scrollbar;
380 self
381 }
382
383 pub fn scrollbar_config(mut self, config: ScrollbarConfig) -> Self {
385 self.scrollbar_config = config;
386 self
387 }
388
389 pub fn show_scroll_indicators(mut self, show: bool) -> Self {
391 self.show_scroll_indicators = show;
392 self
393 }
394
395 pub fn scroll_indicator_style(mut self, style: Style) -> Self {
397 self.scroll_indicator_style = style;
398 self
399 }
400
401 pub fn clip_mode(mut self, clip_mode: ScrollClip) -> Self {
403 self.clip_mode = clip_mode;
404 self
405 }
406
407 pub fn estimated_child_height(mut self, height: u16) -> Self {
412 self.estimated_child_height = height;
413 self
414 }
415
416 pub fn axis(mut self, axis: ScrollAxis) -> Self {
422 self.axis = axis;
423 self
424 }
425
426 pub fn h_scrollbar(mut self, h_scrollbar: bool) -> Self {
430 self.h_scrollbar = h_scrollbar;
431 self
432 }
433
434 pub fn h_scrollbar_config(mut self, config: ScrollbarConfig) -> Self {
436 self.h_scrollbar_config = config;
437 self
438 }
439}
440
441impl From<ScrollView> for Element {
442 fn from(value: ScrollView) -> Self {
443 Element::new(ElementKind::ScrollView(Box::new(value)))
444 }
445}
446
447impl crate::layout::hash::LayoutHash for ScrollView {
448 fn layout_hash(
449 &self,
450 hasher: &mut impl std::hash::Hasher,
451 recurse: &dyn Fn(&Element) -> Option<u64>,
452 ) -> Option<()> {
453 use std::hash::Hash;
454
455 crate::layout::hash::hash_stack_props(&self.props, hasher);
456 self.scrollbar.hash(hasher);
457 self.scrollbar_config.variant.hash(hasher);
458 self.scrollbar_config.gap.hash(hasher);
459 self.show_scroll_indicators.hash(hasher);
460 self.axis.hash(hasher);
461 self.h_scrollbar.hash(hasher);
462 self.h_scrollbar_config.variant.hash(hasher);
463 self.h_scrollbar_config.gap.hash(hasher);
464 crate::layout::hash::hash_children(&self.children, hasher, recurse)
465 }
466}