1use uuid::Uuid;
2
3use super::{ViewDataUpdater, ViewLine};
4
5#[derive(Debug)]
7pub struct ViewData {
8 lines: Vec<ViewLine>,
9 lines_leading: Vec<ViewLine>,
10 lines_trailing: Vec<ViewLine>,
11 name: String,
12 retain_scroll_position: bool,
13 scroll_version: u32,
14 show_help: bool,
15 show_title: bool,
16 version: u32,
17 visible_column: Option<usize>,
18 visible_row: Option<usize>,
19}
20
21impl ViewData {
22 #[inline]
24 pub fn new<C>(callback: C) -> Self
25 where C: FnOnce(&mut ViewDataUpdater<'_>) {
26 let mut view_data = Self {
27 lines: vec![],
28 lines_leading: vec![],
29 lines_trailing: vec![],
30 name: Uuid::new_v4().hyphenated().to_string(),
31 retain_scroll_position: true,
32 scroll_version: 0,
33 show_help: false,
34 show_title: false,
35 version: 0,
36 visible_column: None,
37 visible_row: None,
38 };
39 let mut view_data_updater = ViewDataUpdater::new(&mut view_data);
40 callback(&mut view_data_updater);
41 view_data
42 }
43
44 #[must_use]
46 #[inline]
47 pub fn is_empty(&self) -> bool {
48 self.lines.is_empty() && self.lines_leading.is_empty() && self.lines_trailing.is_empty()
49 }
50
51 #[inline]
53 pub fn update_view_data<C>(&mut self, callback: C)
54 where C: FnOnce(&mut ViewDataUpdater<'_>) {
55 let modified = {
56 let mut view_data_updater = ViewDataUpdater::new(self);
57 callback(&mut view_data_updater);
58 view_data_updater.is_modified()
59 };
60 if modified {
61 self.version = self.version.wrapping_add(1);
62 }
63 }
64
65 pub(crate) fn clear(&mut self) {
66 self.lines_leading.clear();
67 self.lines.clear();
68 self.lines_trailing.clear();
69 }
70
71 pub(crate) fn clear_body(&mut self) {
72 self.lines.clear();
73 }
74
75 pub(crate) fn ensure_line_visible(&mut self, row_index: usize) {
76 self.visible_row = Some(row_index);
77 }
78
79 pub(crate) fn ensure_column_visible(&mut self, column_index: usize) {
80 self.visible_column = Some(column_index);
81 }
82
83 pub(crate) fn set_show_title(&mut self, show: bool) {
84 self.show_title = show;
85 }
86
87 pub(crate) fn set_show_help(&mut self, show: bool) {
88 self.show_help = show;
89 }
90
91 pub(crate) fn push_leading_line(&mut self, view_line: ViewLine) {
92 self.lines_leading.push(view_line);
93 }
94
95 pub(crate) fn push_line(&mut self, view_line: ViewLine) {
96 self.lines.push(view_line);
97 }
98
99 pub(crate) fn push_trailing_line(&mut self, view_line: ViewLine) {
100 self.lines_trailing.push(view_line);
101 }
102
103 pub(crate) fn set_retain_scroll_position(&mut self, value: bool) {
104 self.retain_scroll_position = value;
105 }
106
107 pub(crate) fn reset_scroll_position(&mut self) {
108 self.scroll_version = self.scroll_version.wrapping_add(1);
109 }
110
111 pub(crate) const fn show_title(&self) -> bool {
112 self.show_title
113 }
114
115 pub(crate) const fn show_help(&self) -> bool {
116 self.show_help
117 }
118
119 pub(crate) const fn get_leading_lines(&self) -> &Vec<ViewLine> {
120 &self.lines_leading
121 }
122
123 pub(crate) const fn get_lines(&self) -> &Vec<ViewLine> {
124 &self.lines
125 }
126
127 pub(crate) const fn get_trailing_lines(&self) -> &Vec<ViewLine> {
128 &self.lines_trailing
129 }
130
131 pub(crate) const fn get_visible_column(&self) -> &Option<usize> {
132 &self.visible_column
133 }
134
135 pub(crate) const fn get_visible_row(&self) -> &Option<usize> {
136 &self.visible_row
137 }
138
139 pub(crate) fn get_name(&self) -> &str {
140 self.name.as_str()
141 }
142
143 pub(crate) const fn get_version(&self) -> u32 {
144 self.version
145 }
146
147 pub(crate) const fn retain_scroll_position(&self) -> bool {
148 self.retain_scroll_position
149 }
150
151 pub(crate) const fn get_scroll_version(&self) -> u32 {
152 self.scroll_version
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn new_updater_function() {
162 let view_data = ViewData::new(|updater| updater.set_show_title(true));
163 assert!(view_data.show_title());
164 }
165
166 #[test]
167 fn is_empty() {
168 let view_data = ViewData::new(|_| {});
169 assert!(view_data.is_empty());
170 }
171
172 #[test]
173 fn update_view_data_without_modifications() {
174 let mut view_data = ViewData::new(|_| {});
175 let current_version = view_data.get_version();
176 view_data.update_view_data(|_| {});
177 assert_eq!(view_data.get_version(), current_version);
178 }
179
180 #[test]
181 fn update_view_data_with_modifications() {
182 let mut view_data = ViewData::new(|_| {});
183 let current_version = view_data.get_version();
184 view_data.update_view_data(|updater| updater.set_show_title(true));
185 assert_ne!(view_data.get_version(), current_version);
186 }
187
188 #[test]
189 fn clear() {
190 let mut view_data = ViewData::new(|_| {});
191 view_data.push_line(ViewLine::new_empty_line());
192 view_data.push_leading_line(ViewLine::new_empty_line());
193 view_data.push_trailing_line(ViewLine::new_empty_line());
194 view_data.clear();
195 assert!(view_data.get_leading_lines().is_empty());
196 assert!(view_data.get_lines().is_empty());
197 assert!(view_data.get_trailing_lines().is_empty());
198 }
199
200 #[test]
201 fn clear_body() {
202 let mut view_data = ViewData::new(|_| {});
203 view_data.push_line(ViewLine::new_empty_line());
204 view_data.push_leading_line(ViewLine::new_empty_line());
205 view_data.push_trailing_line(ViewLine::new_empty_line());
206 view_data.clear_body();
207 assert!(!view_data.get_leading_lines().is_empty());
208 assert!(view_data.get_lines().is_empty());
209 assert!(!view_data.get_trailing_lines().is_empty());
210 }
211
212 #[test]
213 fn ensure_line_visible() {
214 let mut view_data = ViewData::new(|_| {});
215 view_data.ensure_line_visible(10);
216 assert_eq!(view_data.get_visible_row().unwrap(), 10);
217 }
218
219 #[test]
220 fn ensure_column_visible() {
221 let mut view_data = ViewData::new(|_| {});
222 view_data.ensure_column_visible(10);
223 assert_eq!(view_data.get_visible_column().unwrap(), 10);
224 }
225
226 #[test]
227 fn set_show_title() {
228 let mut view_data = ViewData::new(|_| {});
229 view_data.set_show_title(false);
230 assert!(!view_data.show_title());
231 }
232
233 #[test]
234 fn set_show_help() {
235 let mut view_data = ViewData::new(|_| {});
236 view_data.set_show_help(false);
237 assert!(!view_data.show_help());
238 }
239
240 #[test]
241 fn push_leading_line() {
242 let mut view_data = ViewData::new(|_| {});
243 view_data.push_leading_line(ViewLine::new_empty_line());
244 assert_eq!(view_data.get_leading_lines().len(), 1);
245 }
246
247 #[test]
248 fn push_line() {
249 let mut view_data = ViewData::new(|_| {});
250 view_data.push_line(ViewLine::new_empty_line());
251 assert_eq!(view_data.get_lines().len(), 1);
252 }
253
254 #[test]
255 fn push_trailing_line() {
256 let mut view_data = ViewData::new(|_| {});
257 view_data.push_trailing_line(ViewLine::new_empty_line());
258 assert_eq!(view_data.get_trailing_lines().len(), 1);
259 }
260
261 #[test]
262 fn set_retain_scroll_position() {
263 let mut view_data = ViewData::new(|_| {});
264 view_data.set_retain_scroll_position(false);
265 assert!(!view_data.retain_scroll_position());
266 }
267
268 #[test]
269 fn reset_scroll_position() {
270 let mut view_data = ViewData::new(|_| {});
271 let current_version = view_data.get_scroll_version();
272 view_data.reset_scroll_position();
273 assert_ne!(view_data.get_scroll_version(), current_version);
274 }
275
276 #[test]
277 fn get_name() {
278 let view_data_1 = ViewData::new(|_| {});
279 let view_data_2 = ViewData::new(|_| {});
280 assert!(!view_data_1.get_name().is_empty());
281 assert_ne!(view_data_1.get_name(), view_data_2.get_name());
282 }
283}