cli_animate/
interactive_menu.rs1use std::io::stdin;
2use std::io::{self, Write};
3
4use crate::utils::Color;
5
6pub struct InteractiveMenu {
7 options: Vec<String>,
9
10 selected_index: usize,
12
13 style: Style,
15}
16
17pub struct Style {
19 color: Color,
20
21 selected_prefix: char,
23}
24
25impl Default for Style {
26 fn default() -> Self {
27 Self {
28 color: Color::White,
29 selected_prefix: '>',
30 }
31 }
32}
33
34pub struct StyleBuilder {
35 color: Option<Color>,
36 selected_prefix: Option<char>,
37}
38
39impl StyleBuilder {
40 pub fn new() -> StyleBuilder {
41 StyleBuilder {
42 color: None,
43 selected_prefix: None,
44 }
45 }
46
47 pub fn color(mut self, color: Color) -> StyleBuilder {
48 self.color = Some(color);
49 self
50 }
51
52 pub fn selected_prefix(mut self, prefix: char) -> StyleBuilder {
53 self.selected_prefix = Some(prefix);
54 self
55 }
56
57 pub fn build(self) -> Style {
58 Style {
59 color: self.color.unwrap_or(Color::White),
60 selected_prefix: self.selected_prefix.unwrap_or('>'),
61 }
62 }
63}
64
65impl InteractiveMenu {
66 pub fn new(options: Vec<String>, style: Style) -> Self {
68 Self {
69 options,
70 selected_index: 0,
71 style,
72 }
73 }
74
75 pub fn run(&mut self) -> io::Result<usize> {
78 self.display()?;
79
80 loop {
81 let mut input = String::new();
82 stdin().read_line(&mut input)?;
83
84 match input.trim() {
85 "w" | "W" => self.previous(), "s" | "S" => self.next(), "" => break, _ => continue,
89 }
90
91 self.display()?;
92 }
93
94 Ok(self.selected_index)
95 }
96
97 fn display(&mut self) -> io::Result<()> {
99 println!("\x1B[2J\x1B[1;1H{}", self.style.color.to_ansi_code());
101 io::stdout().flush()?;
102
103 println!("'w' for up, 's' for down, then press Enter to select. Double Enter to submit.\n");
104
105 for (i, option) in self.options.iter().enumerate() {
106 if i == self.selected_index {
107 print!("{} ", self.style.selected_prefix);
108 } else {
109 print!(" ");
110 }
111
112 println!("{}", option);
113 }
114
115 io::stdout().flush()?;
116 Ok(())
117 }
118
119 fn previous(&mut self) {
120 if self.selected_index > 0 {
121 self.selected_index -= 1;
122 } else {
123 self.selected_index = self.options.len() - 1;
124 }
125 }
126
127 fn next(&mut self) {
128 self.selected_index = (self.selected_index + 1) % self.options.len();
129 }
130}