uzor_core/widgets/
scrollable.rs1use crate::types::{Rect, ScrollState};
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Default, Serialize, Deserialize)]
11pub struct ScrollableResponse {
12 pub content_size: f64,
14 pub viewport_size: f64,
16 pub has_scrollbar: bool,
18 pub viewport: Rect,
20 pub content_area: Rect,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct ScrollableConfig {
27 pub scrollbar_size: f64,
29 pub always_show_scrollbar: bool,
31}
32
33impl Default for ScrollableConfig {
34 fn default() -> Self {
35 Self {
36 scrollbar_size: 8.0,
37 always_show_scrollbar: false,
38 }
39 }
40}
41
42pub struct ScrollableContainer {
44 viewport: Rect,
45 scroll_offset: f64,
46 #[allow(dead_code)]
47 is_dragging: bool,
48 config: ScrollableConfig,
49}
50
51impl ScrollableContainer {
52 pub fn new(viewport: Rect, scroll_state: &ScrollState, config: Option<ScrollableConfig>) -> Self {
53 Self {
54 viewport,
55 scroll_offset: scroll_state.offset,
56 is_dragging: scroll_state.is_dragging,
57 config: config.unwrap_or_default(),
58 }
59 }
60
61 pub fn content_area(&self) -> Rect {
63 Rect::new(
64 self.viewport.x,
65 self.viewport.y,
66 self.viewport.width - self.config.scrollbar_size,
67 self.viewport.height,
68 )
69 }
70
71 pub fn calculate(self, content_height: f64) -> ScrollableResponse {
73 let needs_scrollbar = content_height > self.viewport.height || self.config.always_show_scrollbar;
74
75 let content_area = Rect::new(
76 self.viewport.x,
77 self.viewport.y,
78 self.viewport.width - self.config.scrollbar_size,
79 self.viewport.height,
80 );
81
82 ScrollableResponse {
83 content_size: content_height,
84 viewport_size: self.viewport.height,
85 has_scrollbar: needs_scrollbar,
86 viewport: self.viewport,
87 content_area,
88 }
89 }
90
91 pub fn content_y(&self) -> f64 {
92 self.viewport.y - self.scroll_offset
93 }
94
95 pub fn content_width(&self) -> f64 {
96 self.viewport.width - self.config.scrollbar_size
97 }
98}