view/
view_data.rs

1use uuid::Uuid;
2
3use super::{ViewDataUpdater, ViewLine};
4
5/// Represents the content to be rendered to the `View`.
6#[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	/// Create a new instance using a `ViewDataUpdater`.
23	#[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	/// Does the instance contain any content.
45	#[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	/// Update the view data using a `ViewDataUpdater`. This allows for batch updating of the `ViewData`.
52	#[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}