summaryrefslogtreecommitdiffstats
path: root/src/components/choice.rs
blob: 73f7e77163d2dec4c78f870195e57cccc477803c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#[cfg(test)]
mod tests;

use std::collections::HashMap;

use lazy_static::lazy_static;

use crate::{
	display::DisplayColor,
	input::{Event, InputOptions, KeyCode},
	util::handle_view_data_scroll,
	view::{LineSegment, ViewData, ViewLine},
};

lazy_static! {
	pub(crate) static ref INPUT_OPTIONS: InputOptions = InputOptions::RESIZE | InputOptions::MOVEMENT;
}

pub(crate) struct Choice<T> {
	map: HashMap<char, T>,
	view_data: ViewData,
	options: Vec<(T, char, String)>,
	invalid_selection: bool,
}

impl<T> Choice<T>
where T: Clone
{
	#[allow(clippy::pattern_type_mismatch)]
	pub(crate) fn new(options: Vec<(T, char, String)>) -> Self {
		let map = options
			.iter()
			.map(|(v, k, _)| {
				let c = *k;
				let t = v.clone();
				(c, t)
			})
			.collect::<HashMap<char, T>>();
		Self {
			map,
			options,
			view_data: ViewData::new(|updater| {
				updater.set_show_title(true);
				updater.set_retain_scroll_position(false);
			}),
			invalid_selection: false,
		}
	}

	pub(crate) fn set_prompt(&mut self, prompt_lines: Vec<ViewLine>) {
		self.view_data.update_view_data(|updater| {
			updater.clear();
			for line in prompt_lines {
				updater.push_leading_line(line);
			}
			updater.push_leading_line(ViewLine::new_empty_line());
		});
	}

	#[allow(clippy::pattern_type_mismatch)]
	pub(crate) fn get_view_data(&mut self) -> &ViewData {
		let options = &self.options;
		let invalid_selection = self.invalid_selection;
		self.view_data.update_view_data(|updater| {
			updater.clear_body();
			for (_, key, description) in options {
				updater.push_line(ViewLine::from(format!("{key}) {description}")));
			}
			updater.push_line(ViewLine::new_empty_line());
			if invalid_selection {
				updater.push_line(ViewLine::from(LineSegment::new_with_color(
					"Invalid option selected. Please choose an option.",
					DisplayColor::IndicatorColor,
				)));
			}
			else {
				updater.push_line(ViewLine::from(LineSegment::new_with_color(
					"Please choose an option.",
					DisplayColor::IndicatorColor,
				)));
			}
		});
		&self.view_data
	}

	pub(crate) fn handle_event(&mut self, event: Event, view_state: &crate::view::State) -> Option<&T> {
		if handle_view_data_scroll(event, view_state).is_none() {
			if let Event::Key(key_event) = event {
				if let KeyCode::Char(c) = key_event.code {
					if let Some(v) = self.map.get(&c) {
						self.invalid_selection = false;
						return Some(v);
					}
				}
				self.invalid_selection = true;
			}
		}
		None
	}
}