1use std::convert::TryFrom;
20use std::sync::LazyLock;
21
22use crate::prelude::*;
23
24pub use self::builder::MenuBuilder as Builder;
25
26pub type Menu <'element> = Widget <'element,
27 Selection, model::Component, view::Component>;
28
29pub static CONTROLS : LazyLock <Controls> = LazyLock::new (||
34 controls::Builder::new()
35 .buttons (vec![
36 controls::button::Builtin::MenuNextItem,
37 controls::button::Builtin::MenuPreviousItem,
38 controls::button::Builtin::MenuFirstItem,
39 controls::button::Builtin::MenuLastItem
40 ].into_iter().map (Into::into).collect::<Vec <_>>().into())
41 .build()
42);
43
44pub fn next_item (
49 _ : &controls::button::Release,
50 elements : &Tree <Element>,
51 frame_id : &NodeId,
52 action_buffer : &mut Vec <(NodeId, Action)>
53) {
54 use controller::component::{Kind, Selection};
55 log::trace!("next_item...");
56 let frame = elements.get (frame_id).unwrap();
57 let mut children_ids = frame.children().iter();
58 let menu_id = children_ids.next().unwrap();
59 let Widget (selection, _, _) = Menu::try_get (elements, menu_id).unwrap();
60 if let Some (selected_id) = selection.current.as_ref() {
61 for child_id in children_ids.by_ref() {
63 if child_id == selected_id {
64 debug_assert_eq!(
66 elements.get_element (child_id).controller.state,
67 State::Focused);
68 break
69 }
70 }
71 }
72 let mut select_id = None;
74 for next_id in children_ids {
75 let next = elements.get_element (next_id);
76 if next.controller.state == State::Enabled &&
77 Frame::try_from (next).is_ok()
78 {
79 select_id = Some (next_id);
80 break
81 }
82 }
83 if select_id.is_none() && selection.loop_ {
84 for next_id in frame.children().iter().skip (1) {
85 let next = elements.get_element (next_id);
86 if next.controller.state == State::Enabled &&
87 Frame::try_from (next).is_ok()
88 {
89 select_id = Some (next_id);
90 break
91 }
92 }
93 }
94 if let Some (next_id) = select_id {
95 let select_id = next_id.clone();
96 let select_next = Box::new (move |controller : &mut Controller|{
97 let selection = Selection::try_ref_mut (&mut controller.component)
98 .unwrap();
99 selection.current = Some (select_id);
100 });
101 action_buffer.push ((menu_id.clone(),
102 Action::ModifyController (select_next)));
103 action_buffer.push ((next_id.clone(), Action::Focus));
104 }
105 log::trace!("...next_item");
106}
107
108pub fn previous_item (
113 _ : &controls::button::Release,
114 elements : &Tree <Element>,
115 frame_id : &NodeId,
116 action_buffer : &mut Vec <(NodeId, Action)>
117) {
118 use controller::component::{Kind, Selection};
119 log::trace!("previous_item...");
120 let frame = elements.get (frame_id).unwrap();
121 let mut children_ids = frame.children().iter();
122 let menu_id = children_ids.next().unwrap();
123 let Widget (selection, _, _) = Menu::try_get (elements, menu_id).unwrap();
124 let mut children_ids = children_ids.rev();
125 if let Some (selected_id) = selection.current.as_ref() {
126 for child_id in children_ids.by_ref() {
128 if child_id == selected_id {
129 debug_assert_eq!(
131 elements.get_element (child_id).controller.state,
132 State::Focused);
133 break
134 }
135 }
136 }
137 let mut select_id = None;
139 for prev_id in children_ids {
140 let prev = elements.get_element (prev_id);
141 if prev.controller.state == State::Enabled &&
142 Frame::try_from (prev).is_ok()
143 {
144 select_id = Some (prev_id);
145 break
146 }
147 }
148 if select_id.is_none() && selection.loop_ {
149 for prev_id in frame.children().iter().rev() {
150 let prev = elements.get_element (prev_id);
151 if prev.controller.state == State::Enabled &&
152 Frame::try_from (prev).is_ok()
153 {
154 select_id = Some (prev_id);
155 break
156 }
157 }
158 }
159 if let Some (prev_id) = select_id {
160 let select_id = prev_id.clone();
161 let select_prev = Box::new (move |controller : &mut Controller|{
162 let selection = Selection::try_ref_mut (&mut controller.component)
163 .unwrap();
164 selection.current = Some (select_id);
165 });
166 action_buffer.push ((menu_id.clone(),
167 Action::ModifyController (select_prev)));
168 action_buffer.push ((prev_id.clone(), Action::Focus));
169 }
170 log::trace!("...previous_item");
171}
172
173pub fn first_item (
178 _ : &controls::button::Release,
179 elements : &Tree <Element>,
180 frame_id : &NodeId,
181 action_buffer : &mut Vec <(NodeId, Action)>
182) {
183 use controller::component::{Kind, Selection};
184 log::trace!("first_item...");
185 let frame = elements.get (frame_id).unwrap();
186 let mut children_ids = frame.children().iter();
187 let menu_id = children_ids.next().unwrap();
188 let mut select_id = None;
189 for child_id in children_ids {
190 let next = elements.get_element (child_id);
191 if next.controller.state == State::Enabled &&
192 Frame::try_from (next).is_ok()
193 {
194 select_id = Some (child_id);
195 break
196 }
197 }
198 if let Some (first_id) = select_id {
199 let select_id = first_id.clone();
200 let select_first = Box::new (move |controller : &mut Controller|{
201 let selection = Selection::try_ref_mut (&mut controller.component)
202 .unwrap();
203 selection.current = Some (select_id);
204 });
205 action_buffer.push ((menu_id.clone(),
206 Action::ModifyController (select_first)));
207 action_buffer.push ((first_id.clone(), Action::Focus));
208 }
209 log::trace!("...first_item");
210}
211
212pub fn last_item (
217 _ : &controls::button::Release,
218 elements : &Tree <Element>,
219 frame_id : &NodeId,
220 action_buffer : &mut Vec <(NodeId, Action)>
221) {
222 use controller::component::{Kind, Selection};
223 log::trace!("last_item...");
224 let frame = elements.get (frame_id).unwrap();
225 let mut children_ids = frame.children().iter();
226 let menu_id = children_ids.next().unwrap();
227 let mut select_id = None;
228 for child_id in children_ids.rev() {
229 let next = elements.get_element (child_id);
230 if next.controller.state == State::Enabled &&
231 Frame::try_from (next).is_ok()
232 {
233 select_id = Some (child_id);
234 break
235 }
236 }
237 if let Some (last_id) = select_id {
238 let select_id = last_id.clone();
239 let select_last = Box::new (move |controller : &mut Controller|{
240 let selection = Selection::try_ref_mut (&mut controller.component)
241 .unwrap();
242 selection.current = Some (select_id);
243 });
244 action_buffer.push ((menu_id.clone(),
245 Action::ModifyController (select_last)));
246 action_buffer.push ((last_id.clone(), Action::Focus));
247 }
248 log::trace!("...last_item");
249}
250
251pub fn get_selected_id <'a> (elements : &'a Tree <Element>, menu_id : &NodeId)
256 -> Option <&'a NodeId>
257{
258 let Widget (selection, _, _) = Menu::try_get (elements, menu_id).unwrap();
259 selection.current.as_ref()
260}
261
262pub (crate) fn find_first_item (
264 elements : &Tree <Element>, node_ids : std::slice::Iter <NodeId>
265) -> Option <NodeId> {
266 let mut first_item = None;
267 for node_id in node_ids {
268 let node = elements.get_element (node_id);
269 if node.controller.state == State::Enabled &&
270 Frame::try_from (node).is_ok()
271 {
272 first_item = Some (node_id.clone());
273 break
274 }
275 }
276 first_item
277}
278mod builder {
283 use derive_builder::Builder;
284 use crate::prelude::*;
285
286 #[derive(Builder)]
287 #[builder(public, pattern="owned", build_fn(private), setter(strip_option))]
288 struct Menu <'a, A : Application> {
289 elements : &'a Tree <Element>,
290 frame_id : &'a NodeId,
291 #[builder(default)]
292 bindings : Option <&'a Bindings <A>>,
293 #[builder(default)]
294 selection : Selection
295 }
296
297 impl <'a, A : Application> MenuBuilder <'a, A> {
298 pub const fn new (elements : &'a Tree <Element>, frame_id : &'a NodeId) -> Self {
299 MenuBuilder {
300 elements: Some (elements),
301 frame_id: Some (frame_id),
302 bindings: None,
303 selection: None,
304 }
305 }
306 }
307
308 impl <A : Application + 'static> BuildActions for MenuBuilder <'_, A> {
310 fn build_actions (self) -> Vec<(NodeId, Action)> {
316 log::trace!("build actions...");
317 let Menu { elements, frame_id, bindings, selection } = self.build()
318 .map_err(|err| log::error!("frame builder error: {err:?}"))
319 .unwrap();
320 let bindings_empty = Bindings::empty();
321 let bindings = bindings.unwrap_or (&bindings_empty)
322 .get_bindings (&super::CONTROLS);
323 let mut out = Vec::new();
324 { let set_controls = Box::new (move |controller : &mut Controller|
326 controller.add_bindings (&bindings));
327 out.push ((frame_id.clone(), Action::ModifyController (set_controls)));
328 }
329 { let set_focus_top_false = Box::new (|controller : &mut Controller|
331 controller.focus_top = false);
332 for child_id in elements.children_ids (frame_id).unwrap() {
333 out.push ((child_id.clone(),
334 Action::ModifyController (set_focus_top_false.clone())));
335 }
336 }
337 { let selection = {
339 let controller = ControllerComponent::from (selection).into();
340 Element::new (
341 "Menu".to_string(), controller, Model::default(), View::default())
342 };
343 out.push ((
344 frame_id.clone(),
345 Action::create_singleton (selection, CreateOrder::Prepend)));
346 }
347 if elements.get_element (frame_id).controller.state == State::Focused
349 && let Some (focus_id) = super::find_first_item (
350 elements, elements.get (frame_id).unwrap().children().iter())
351 {
352 out.push ((focus_id, Action::Focus))
353 }
354 log::trace!("...build actions");
355 out
356 }
357 }
358}