tui_vision/menus/
state.rs1use super::{Menu, MenuBar, MenuItem};
2
3impl MenuBar {
5 pub fn has_open_menu(&self) -> bool {
7 self.opened_menu.is_some()
8 }
9
10 pub fn opened_menu(&self) -> Option<&Menu> {
12 self.opened_menu.and_then(|index| self.menus.get(index))
13 }
14
15 pub fn opened_menu_mut(&mut self) -> Option<&mut Menu> {
17 self.opened_menu.and_then(|index| self.menus.get_mut(index))
18 }
19
20 pub fn open_menu(&mut self, index: usize) {
22 if index < self.menus.len() {
23 if let Some(current_index) = self.opened_menu {
25 if let Some(menu) = self.menus.get_mut(current_index) {
26 menu.focused_item = None;
27 menu.close_all_submenus();
28 }
29 }
30
31 self.opened_menu = Some(index);
33 if let Some(menu) = self.menus.get_mut(index) {
34 menu.focused_item = None; }
37 }
38 }
39
40 pub fn close_menu(&mut self) {
42 if let Some(index) = self.opened_menu {
43 if let Some(menu) = self.menus.get_mut(index) {
44 menu.focused_item = None;
45 menu.close_all_submenus();
46 }
47 }
48 self.opened_menu = None;
49 }
50
51 pub fn open_next_menu(&mut self) {
53 if self.menus.is_empty() {
54 return;
55 }
56
57 let next_index = if let Some(current) = self.opened_menu {
58 (current + 1) % self.menus.len()
59 } else {
60 0
61 };
62 self.open_menu(next_index);
63 }
64
65 pub fn open_previous_menu(&mut self) {
67 if self.menus.is_empty() {
68 return;
69 }
70
71 let prev_index = if let Some(current) = self.opened_menu {
72 if current == 0 {
73 self.menus.len() - 1
74 } else {
75 current - 1
76 }
77 } else {
78 self.menus.len() - 1
79 };
80 self.open_menu(prev_index);
81 }
82}
83
84impl Menu {
86 pub fn set_enabled(&mut self, enabled: bool) {
88 self.enabled = enabled;
89 }
90
91 pub fn focus_next_item(&mut self) {
93 let next = if let Some(current) = self.focused_item {
94 self.find_next_selectable_item(current)
95 } else {
96 self.find_first_selectable_item()
97 };
98 self.focused_item = next;
99 }
100
101 pub fn focus_previous_item(&mut self) {
103 let previous = if let Some(current) = self.focused_item {
104 self.find_previous_selectable_item(current)
105 } else {
106 self.find_last_selectable_item()
107 };
108 self.focused_item = previous;
109 }
110
111 pub fn get_focused_item(&self) -> Option<&MenuItem> {
113 self.focused_item.and_then(|index| self.items.get(index))
114 }
115
116 pub fn close_all_submenus(&mut self) {
118 for item in &mut self.items {
119 if let MenuItem::SubMenu(submenu) = item {
120 submenu.is_open = false;
121 submenu.focused_item = None;
122 Self::close_submenus_recursive(&mut submenu.items);
124 }
125 }
126 }
127
128 fn close_submenus_recursive(items: &mut [MenuItem]) {
130 for item in items {
131 if let MenuItem::SubMenu(submenu) = item {
132 submenu.is_open = false;
133 submenu.focused_item = None;
134 Self::close_submenus_recursive(&mut submenu.items);
135 }
136 }
137 }
138
139 pub fn find_first_selectable_item(&self) -> Option<usize> {
141 self.items
142 .iter()
143 .position(|item| matches!(item, MenuItem::Action(_) | MenuItem::SubMenu(_)))
144 }
145
146 pub fn find_last_selectable_item(&self) -> Option<usize> {
148 self.items
149 .iter()
150 .rposition(|item| matches!(item, MenuItem::Action(_) | MenuItem::SubMenu(_)))
151 }
152
153 pub fn find_next_selectable_item(&self, current: usize) -> Option<usize> {
155 self.items
156 .iter()
157 .skip(current + 1)
158 .position(|item| matches!(item, MenuItem::Action(_) | MenuItem::SubMenu(_)))
159 .map(|pos| pos + current + 1)
160 .or_else(|| self.find_first_selectable_item())
161 }
162
163 pub fn find_previous_selectable_item(&self, current: usize) -> Option<usize> {
165 self.items
166 .iter()
167 .take(current)
168 .rposition(|item| matches!(item, MenuItem::Action(_) | MenuItem::SubMenu(_)))
169 .or_else(|| self.find_last_selectable_item())
170 }
171}