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