1#[derive(Debug, Clone)]
5pub struct MenuItem {
6 pub id: String,
7 pub label: String,
8 pub description: String,
9}
10
11impl MenuItem {
12 pub fn new(id: impl Into<String>, label: impl Into<String>, description: impl Into<String>) -> Self {
13 Self {
14 id: id.into(),
15 label: label.into(),
16 description: description.into(),
17 }
18 }
19
20 pub fn display_label(&self) -> String {
22 format!("{:12} - {}", self.label, self.description)
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq)]
28pub enum MenuAction {
29 Continue, Back, Exit, }
33
34pub struct MenuBuilder {
36 items: Vec<MenuItem>,
37 title: String,
38 include_back: bool,
39 include_exit: bool,
40}
41
42impl MenuBuilder {
43 pub fn new(title: impl Into<String>) -> Self {
44 Self {
45 items: Vec::new(),
46 title: title.into(),
47 include_back: false,
48 include_exit: true,
49 }
50 }
51
52 pub fn with_back(mut self) -> Self {
53 self.include_back = true;
54 self
55 }
56
57 pub fn with_exit(mut self, include: bool) -> Self {
58 self.include_exit = include;
59 self
60 }
61
62 pub fn add_item(mut self, id: impl Into<String>, label: impl Into<String>, description: impl Into<String>) -> Self {
63 self.items.push(MenuItem::new(id, label, description));
64 self
65 }
66
67 pub fn build(mut self) -> Menu {
68 let mut all_items = Vec::new();
69
70 if self.include_back {
72 all_items.push(MenuItem::new(
73 "back",
74 "Back",
75 "Back to previous menu"
76 ));
77 }
78
79 all_items.append(&mut self.items);
81
82 if self.include_exit {
84 all_items.push(MenuItem::new(
85 "exit",
86 "Exit",
87 "Exit the program"
88 ));
89 }
90
91 Menu {
92 title: self.title,
93 items: all_items,
94 }
95 }
96}
97
98pub struct Menu {
100 pub title: String,
101 pub items: Vec<MenuItem>,
102}
103
104impl Menu {
105 pub fn builder(title: impl Into<String>) -> MenuBuilder {
106 MenuBuilder::new(title)
107 }
108
109 pub fn get_item(&self, id: &str) -> Option<&MenuItem> {
111 self.items.iter().find(|item| item.id == id)
112 }
113
114 pub fn get_display_options(&self) -> Vec<String> {
116 self.items.iter().map(|item| item.display_label()).collect()
117 }
118
119 pub fn get_item_by_index(&self, index: usize) -> Option<&MenuItem> {
121 self.items.get(index)
122 }
123}