1#[derive(Debug, Clone, Default)]
5pub struct ScrollState {
6 pub position: usize,
8 pub follow_bottom: bool,
10 pub content_size: usize,
12 pub viewport_size: usize,
14}
15
16impl ScrollState {
17 pub fn new() -> Self {
19 Self {
20 position: 0,
21 follow_bottom: true,
22 content_size: 0,
23 viewport_size: 0,
24 }
25 }
26
27 pub fn update_dimensions(&mut self, content_size: usize, viewport_size: usize) {
29 self.content_size = content_size;
30 self.viewport_size = viewport_size;
31
32 if self.follow_bottom {
34 self.scroll_to_bottom();
35 } else {
36 self.clamp_position();
38 }
39 }
40
41 pub fn max_scroll(&self) -> usize {
43 self.content_size.saturating_sub(self.viewport_size)
44 }
45
46 pub fn clamp_position(&mut self) {
48 let max = self.max_scroll();
49 if self.position > max {
50 self.position = max;
51 }
52 }
53
54 pub fn scroll_down(&mut self, amount: usize) {
56 let max = self.max_scroll();
57
58 if self.position >= max {
60 self.follow_bottom = true;
61 return;
62 }
63
64 self.position = (self.position + amount).min(max);
66
67 self.follow_bottom = self.position >= max;
69 }
70
71 pub fn scroll_up(&mut self, amount: usize) {
73 self.follow_bottom = false;
75
76 self.position = self.position.saturating_sub(amount);
78 }
79
80 pub fn scroll_to_top(&mut self) {
82 self.follow_bottom = false;
83 self.position = 0;
84 }
85
86 pub fn scroll_to_bottom(&mut self) {
88 self.follow_bottom = true;
89 self.position = self.max_scroll();
91 }
92
93 pub fn page_up(&mut self) {
95 self.scroll_up(self.viewport_size.saturating_sub(1).max(1));
96 }
97
98 pub fn page_down(&mut self) {
100 self.scroll_down(self.viewport_size.saturating_sub(1).max(1));
101 }
102
103 pub fn has_more_above(&self) -> bool {
105 self.position > 0
106 }
107
108 pub fn has_more_below(&self) -> bool {
110 self.position < self.max_scroll()
111 }
112}
113
114pub trait Scrollable {
116 fn message_scroll_state(&mut self) -> &mut ScrollState;
118
119 fn task_scroll_state(&mut self) -> &mut ScrollState;
121
122 fn scroll_up(&mut self, amount: usize) {
124 self.message_scroll_state().scroll_up(amount);
125 }
126
127 fn scroll_down(&mut self, amount: usize) {
129 self.message_scroll_state().scroll_down(amount);
130 }
131
132 fn auto_scroll_to_bottom(&mut self) {
134 self.message_scroll_state().scroll_to_bottom();
135 }
136
137 fn scroll_tasks_up(&mut self, amount: usize) {
139 self.task_scroll_state().scroll_up(amount);
140 }
141
142 fn scroll_tasks_down(&mut self, amount: usize) {
144 self.task_scroll_state().scroll_down(amount);
145 }
146}
147
148pub trait ErrorHandler {
150 fn handle_error(&mut self, message: String);
151}