1use crate::_private::NonExhaustive;
4use crate::button::{Button, ButtonState, ButtonStyle};
5use crate::checkbox::{Checkbox, CheckboxState, CheckboxStyle};
6use crate::choice::{Choice, ChoicePopup, ChoiceSelect, ChoiceState, ChoiceStyle, ChoiceWidget};
7use crate::event::{ButtonOutcome, CheckOutcome, ChoiceOutcome};
8use crate::paired::{PairSplit, Paired, PairedState, PairedWidget};
9use rat_event::{ConsumedEvent, HandleEvent, Outcome, Popup, Regular, event_flow};
10use rat_focus::{Focus, FocusBuilder, FocusFlag, HasFocus, Navigation};
11use rat_reloc::RelocatableState;
12use ratatui_core::buffer::Buffer;
13use ratatui_core::layout::Rect;
14use ratatui_core::style::Style;
15use ratatui_core::text::{Line, Span};
16use ratatui_core::widgets::{StatefulWidget, Widget};
17use ratatui_crossterm::crossterm::event::{Event, KeyEvent, KeyEventKind};
18use ratatui_widgets::block::{Block, BlockExt};
19use std::borrow::Cow;
20
21#[derive(Debug)]
22enum Tool<'a> {
23 CollapsedButtons(Cow<'a, str>),
24 BasicButton(Cow<'a, str>, Cow<'a, str>, bool),
25 BasicCheckbox(Cow<'a, str>, Cow<'a, str>, bool),
26 BasicChoice(Cow<'a, str>, Vec<Line<'a>>, usize),
27 Text(Line<'a>),
28}
29
30#[derive(Debug)]
32pub enum ToolState {
33 BasicButton(ButtonState, bool),
34 BasicCheckbox(CheckboxState),
35 BasicChoice(ChoiceState<usize>),
36}
37
38#[derive(Debug)]
43pub struct Toolbar<'a> {
44 tools: Vec<Tool<'a>>,
45 style: Style,
46 block: Option<Block<'a>>,
47 spacing: u16,
48 key_style: Option<Style>,
49 button_style: ButtonStyle,
50 checkbox_style: CheckboxStyle,
51 choice_style: ChoiceStyle,
52 collapsed_style: ChoiceStyle,
53}
54
55#[derive(Debug)]
57pub struct ToolbarWidget<'a> {
58 tools: Vec<ToolWidget1<'a>>,
59 style: Style,
60 block: Option<Block<'a>>,
61}
62
63#[derive(Debug)]
65pub struct ToolbarPopup<'a> {
66 tools: Vec<ToolWidget2<'a>>,
67}
68
69#[derive(Debug, Clone)]
71pub struct ToolbarStyle {
72 pub style: Style,
73 pub block: Option<Block<'static>>,
74 pub border_style: Option<Style>,
75 pub title_style: Option<Style>,
76
77 pub key_style: Option<Style>,
78
79 pub button: Option<ButtonStyle>,
80 pub checkbox: Option<CheckboxStyle>,
81 pub choice: Option<ChoiceStyle>,
82 pub collapsed: Option<ChoiceStyle>,
83
84 pub non_exhaustive: NonExhaustive,
85}
86
87#[derive(Debug)]
89pub struct ToolbarState {
90 pub area: Rect,
93 pub inner: Rect,
96
97 pub collapsed: ChoiceState<Option<usize>>,
99 pub collapsed_active: bool,
101 pub tools: Vec<Option<ToolState>>,
103 pub focus_before: Option<FocusFlag>,
106
107 pub container: FocusFlag,
109
110 pub non_exhaustive: NonExhaustive,
111}
112
113impl Default for ToolbarStyle {
114 fn default() -> Self {
115 Self {
116 style: Default::default(),
117 block: Default::default(),
118 border_style: Default::default(),
119 title_style: Default::default(),
120 key_style: Default::default(),
121 button: Default::default(),
122 checkbox: Default::default(),
123 choice: Default::default(),
124 collapsed: Default::default(),
125 non_exhaustive: NonExhaustive,
126 }
127 }
128}
129
130impl<'a> Default for Toolbar<'a> {
131 fn default() -> Self {
132 Self {
133 tools: Default::default(),
134 style: Default::default(),
135 block: Default::default(),
136 spacing: 1,
137 key_style: Default::default(),
138 button_style: Default::default(),
139 checkbox_style: Default::default(),
140 choice_style: Default::default(),
141 collapsed_style: Default::default(),
142 }
143 }
144}
145
146impl<'a> Toolbar<'a> {
147 pub fn new() -> Self {
148 Self::default()
149 }
150
151 pub fn spacing(mut self, sp: u16) -> Self {
153 self.spacing = sp;
154 self
155 }
156
157 pub fn collapsed_buttons(mut self, text: impl Into<Cow<'a, str>>) -> Self {
159 self.tools.push(Tool::CollapsedButtons(text.into()));
160 self
161 }
162
163 pub fn button(
168 mut self,
169 key: impl Into<Cow<'a, str>>,
170 text: impl Into<Cow<'a, str>>,
171 collapsible: bool,
172 ) -> Self {
173 self.tools
174 .push(Tool::BasicButton(key.into(), text.into(), collapsible));
175 self
176 }
177
178 pub fn checkbox(
183 mut self,
184 key: impl Into<Cow<'a, str>>,
185 text: impl Into<Cow<'a, str>>,
186 checked: bool,
187 ) -> Self {
188 self.tools
189 .push(Tool::BasicCheckbox(key.into(), text.into(), checked));
190 self
191 }
192
193 pub fn choice<V: Into<Line<'a>>>(
195 mut self,
196 key: impl Into<Cow<'a, str>>,
197 items: impl IntoIterator<Item = V>,
198 selected: usize,
199 ) -> Self {
200 self.tools.push(Tool::BasicChoice(
201 key.into(),
202 items.into_iter().map(|v| v.into()).collect(),
203 selected,
204 ));
205 self
206 }
207
208 pub fn text(mut self, text: impl Into<Line<'a>>) -> Self {
210 self.tools.push(Tool::Text(text.into()));
211 self
212 }
213
214 pub fn styles(mut self, styles: ToolbarStyle) -> Self {
216 self.style = styles.style;
217 if styles.block.is_some() {
218 self.block = styles.block;
219 }
220 if let Some(border_style) = styles.border_style {
221 self.block = self.block.map(|v| v.border_style(border_style));
222 }
223 if let Some(title_style) = styles.title_style {
224 self.block = self.block.map(|v| v.title_style(title_style));
225 }
226 self.block = self.block.map(|v| v.style(self.style));
227
228 if styles.key_style.is_some() {
229 self.key_style = styles.key_style;
230 }
231 if let Some(button) = styles.button {
232 self.button_style = button;
233 }
234 if let Some(checkbox) = styles.checkbox {
235 self.checkbox_style = checkbox;
236 }
237 if let Some(choice) = styles.choice {
238 self.choice_style = choice;
239 }
240 if let Some(collapsed) = styles.collapsed {
241 self.collapsed_style = collapsed;
242 }
243 self
244 }
245
246 pub fn style(mut self, style: Style) -> Self {
248 self.style = style;
249 self.block = self.block.map(|v| v.style(self.style));
250 self
251 }
252
253 pub fn block(mut self, block: Block<'a>) -> Self {
255 self.block = Some(block);
256 self.block = self.block.map(|v| v.style(self.style));
257 self
258 }
259
260 pub fn key_style(mut self, style: Style) -> Self {
262 self.key_style = Some(style);
263 self
264 }
265
266 pub fn button_style(mut self, style: ButtonStyle) -> Self {
268 self.button_style = style;
269 self
270 }
271
272 pub fn checkbox_style(mut self, style: CheckboxStyle) -> Self {
274 self.checkbox_style = style;
275 self
276 }
277
278 pub fn choice_style(mut self, style: ChoiceStyle) -> Self {
280 self.choice_style = style;
281 self
282 }
283
284 pub fn collapsed_style(mut self, style: ChoiceStyle) -> Self {
286 self.collapsed_style = style;
287 self
288 }
289
290 pub fn into_widgets(
294 self,
295 area: Rect,
296 state: &mut ToolbarState,
297 ) -> (ToolbarWidget<'a>, ToolbarPopup<'a>) {
298 let block = self.block.clone();
299 let style = self.style.clone();
300
301 let (t1, t2) = layout(self, area, state);
302 (
303 ToolbarWidget {
304 tools: t1,
305 style,
306 block,
307 },
308 ToolbarPopup { tools: t2 },
309 )
310 }
311}
312
313enum ToolLayout<'a> {
314 CollapsedButton(Line<'a>),
315 BasicButton(u16, Button<'a>, Line<'a>, bool),
316 BasicCheckbox(Checkbox<'a>),
317 BasicChoice(Line<'a>, Choice<'a, usize>, usize),
318 Text(Line<'a>),
319}
320
321enum ToolLayout2<'a> {
322 CollapsedPlaceHolder(),
323 CollapsedButton(Choice<'a, Option<usize>>),
324 BasicButton(usize, Button<'a>),
325 BasicCheckbox(usize, Checkbox<'a>),
326 BasicChoice(usize, Line<'a>, Choice<'a, usize>, usize),
327 Text(Line<'a>),
328}
329
330#[derive(Debug)]
331enum ToolWidget1<'a> {
332 CollapsedButton(Rect, ChoiceWidget<'a, Option<usize>>),
333 BasicButton(usize, Rect, Button<'a>),
334 BasicCheckbox(usize, Rect, Checkbox<'a>),
335 BasicChoice(
336 usize,
337 Rect,
338 Paired<'a, PairedWidget<'a, Line<'a>>, ChoiceWidget<'a, usize>>,
339 ),
340 Text(Rect, Line<'a>),
341}
342
343#[derive(Debug)]
344enum ToolWidget2<'a> {
345 CollapsedButton(ChoicePopup<'a, Option<usize>>),
346 BasicChoice(usize, ChoicePopup<'a, usize>),
347}
348
349fn layout<'a>(
350 widget: Toolbar<'a>,
351 area: Rect,
352 state: &mut ToolbarState,
353) -> (Vec<ToolWidget1<'a>>, Vec<ToolWidget2<'a>>) {
354 let inner = widget.block.inner_if_some(area);
355
356 let key_style = widget.key_style.unwrap_or_default();
357
358 let mut layout1 = Vec::with_capacity(widget.tools.len());
360 let mut total_width = 0;
361 let mut have_collapsed = false;
362 for tool in widget.tools {
363 match tool {
364 Tool::CollapsedButtons(text) => {
365 let text = Line::from(text);
366 have_collapsed = true;
367 layout1.push(ToolLayout::CollapsedButton(text));
368 }
369 Tool::BasicButton(key, text, collapse) => {
370 let text =
371 Line::from_iter([Span::from(key).style(key_style.clone()), Span::from(text)]);
372 let w = Button::new(text.clone()).styles(widget.button_style.clone());
373 let w_width = w.width() + widget.spacing;
374 total_width += w_width;
375 layout1.push(ToolLayout::BasicButton(w_width, w, text, collapse));
376 }
377 Tool::BasicCheckbox(key, text, checked) => {
378 let text =
379 Line::from_iter([Span::from(key).style(key_style.clone()), Span::from(text)]);
380 let c = Checkbox::new()
381 .text(text)
382 .checked(checked)
383 .styles(widget.checkbox_style.clone());
384 let w_width = c.width() + widget.spacing;
385 total_width += w_width;
386 layout1.push(ToolLayout::BasicCheckbox(c));
387 }
388 Tool::BasicChoice(key, items, selected) => {
389 let key = Line::from(key).style(key_style.clone());
390 let c = Choice::new()
391 .items(items.into_iter().enumerate())
392 .styles(widget.choice_style.clone());
393 let w_width = key.width() as u16 + c.width() + widget.spacing;
394 total_width += w_width;
395 layout1.push(ToolLayout::BasicChoice(key, c, selected));
396 }
397 Tool::Text(txt) => {
398 let w_width = txt.width() as u16 + widget.spacing;
399 total_width += w_width;
400 layout1.push(ToolLayout::Text(txt.clone()));
401 }
402 }
403 }
404
405 state.collapsed_active = false;
407 for w in state.tools.iter_mut().flatten() {
408 if let ToolState::BasicButton(_, active) = w {
409 *active = false;
410 }
411 }
412
413 let mut layout2 = Vec::with_capacity(layout1.len());
415 if total_width > inner.width && have_collapsed {
416 let mut collapsed_width = 0;
417 let mut collapsed = Choice::<Option<usize>>::new()
418 .styles(widget.collapsed_style.clone())
419 .behave_select(ChoiceSelect::MouseMove);
420
421 let mut n = 0;
422 for w in layout1.into_iter() {
423 match w {
424 ToolLayout::CollapsedButton(text) => {
425 collapsed = collapsed.unknown_item(text);
426 layout2.push(ToolLayout2::CollapsedPlaceHolder());
427 }
428 ToolLayout::BasicButton(w, button, text, collapse) => {
429 if total_width > inner.width && collapse {
430 total_width -= w;
431 total_width -= collapsed_width;
432
433 collapsed = collapsed.item(Some(n), text);
434
435 collapsed_width = collapsed.width() + widget.spacing;
436 total_width += collapsed_width;
437 } else {
438 layout2.push(ToolLayout2::BasicButton(n, button));
439 }
440 n += 1;
441 }
442 ToolLayout::BasicCheckbox(c) => {
443 layout2.push(ToolLayout2::BasicCheckbox(n, c));
444 n += 1;
445 }
446 ToolLayout::BasicChoice(t, c, selected) => {
447 layout2.push(ToolLayout2::BasicChoice(n, t, c, selected));
448 n += 1;
449 }
450 ToolLayout::Text(t) => {
451 layout2.push(ToolLayout2::Text(t));
452 }
453 }
454 }
455
456 for i in 0..layout2.len() {
457 if matches!(layout2[i], ToolLayout2::CollapsedPlaceHolder()) {
458 layout2[i] = ToolLayout2::CollapsedButton(collapsed);
459 break;
460 }
461 }
462 } else {
463 let mut n = 0;
464 for w in layout1.into_iter() {
465 match w {
466 ToolLayout::CollapsedButton(_) => {
467 layout2.push(ToolLayout2::CollapsedPlaceHolder());
468 }
469 ToolLayout::BasicButton(_, b, _, _) => {
470 layout2.push(ToolLayout2::BasicButton(n, b));
471 n += 1;
472 }
473 ToolLayout::BasicCheckbox(c) => {
474 layout2.push(ToolLayout2::BasicCheckbox(n, c));
475 n += 1;
476 }
477 ToolLayout::BasicChoice(t, c, selected) => {
478 layout2.push(ToolLayout2::BasicChoice(n, t, c, selected));
479 n += 1;
480 }
481 ToolLayout::Text(t) => {
482 layout2.push(ToolLayout2::Text(t));
483 }
484 }
485 }
486 }
487
488 let mut widgets1 = Vec::with_capacity(layout2.len());
490 let mut widgets2 = Vec::with_capacity(layout2.len());
491 let mut widget_area = inner;
492 for w in layout2 {
493 match w {
494 ToolLayout2::CollapsedPlaceHolder() => {
495 widget_area.width = 0;
496 }
497 ToolLayout2::CollapsedButton(w) => {
498 state.collapsed_active = true;
499
500 widget_area.width = w.width();
501 let (w, p) = w.into_widgets();
502 widgets1.push(ToolWidget1::CollapsedButton(widget_area, w));
503 widgets2.push(ToolWidget2::CollapsedButton(p));
504 }
505 ToolLayout2::BasicButton(n, w) => {
506 while state.tools.len() <= n {
507 state.tools.push(None);
508 }
509 if state.tools[n].is_none() {
510 state.tools[n] = Some(ToolState::BasicButton(ButtonState::default(), true));
511 } else {
512 if let Some(ToolState::BasicButton(_, active)) = &mut state.tools[n] {
513 *active = true;
514 }
515 }
516
517 widget_area.width = w.width();
518 widgets1.push(ToolWidget1::BasicButton(n, widget_area, w));
519 }
520 ToolLayout2::BasicCheckbox(n, w) => {
521 while state.tools.len() <= n {
522 state.tools.push(None);
523 }
524 if state.tools[n].is_none() {
525 state.tools[n] = Some(ToolState::BasicCheckbox(CheckboxState::default()));
526 }
527 widget_area.width = w.width();
528 widgets1.push(ToolWidget1::BasicCheckbox(n, widget_area, w));
529 }
530 ToolLayout2::BasicChoice(n, key, w, selected) => {
531 while state.tools.len() <= n {
532 state.tools.push(None);
533 }
534 if state.tools[n].is_none() {
535 state.tools[n] = Some(ToolState::BasicChoice(ChoiceState::default()));
536 }
537 let Some(ToolState::BasicChoice(s)) = &mut state.tools[n] else {
538 unreachable!("invalid_state");
539 };
540 if !s.is_popup_active() {
541 s.set_value(selected);
542 }
543
544 let key_len = key.width() as u16;
545 widget_area.width = key_len + w.width();
546 let (w, p) = w.into_widgets();
547 widgets1.push(ToolWidget1::BasicChoice(
548 n,
549 widget_area,
550 Paired::new(PairedWidget::new(key), w)
551 .spacing(0)
552 .split(PairSplit::Fix1(key_len)),
553 ));
554 widgets2.push(ToolWidget2::BasicChoice(n, p));
555 }
556 ToolLayout2::Text(w) => {
557 widget_area.width = w.width() as u16;
558 widgets1.push(ToolWidget1::Text(widget_area, w));
559 }
560 }
561
562 if widget_area.width > 0 {
563 widget_area.x += widget_area.width;
564 widget_area.x += widget.spacing;
565 }
566 }
567
568 state.collapsed.relocate_hidden();
570 state.collapsed.relocate_popup_hidden();
571 for w in state.tools.iter_mut().flatten() {
572 match w {
573 ToolState::BasicButton(w, _) => {
574 w.relocate_hidden();
575 }
576 ToolState::BasicCheckbox(w) => {
577 w.relocate_hidden();
578 }
579 ToolState::BasicChoice(w) => {
580 w.relocate_hidden();
581 w.relocate_popup_hidden();
582 }
583 }
584 }
585
586 (widgets1, widgets2)
587}
588
589impl<'a> StatefulWidget for ToolbarWidget<'a> {
590 type State = ToolbarState;
591
592 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
593 render_ref(self, area, buf, state);
594 }
595}
596
597fn render_ref(widget: ToolbarWidget, area: Rect, buf: &mut Buffer, state: &mut ToolbarState) {
598 state.area = area;
599 state.inner = widget.block.inner_if_some(area);
600
601 if widget.block.is_some() {
602 widget.block.render(area, buf);
603 } else {
604 buf.set_style(area, widget.style);
605 }
606
607 for w in widget.tools {
608 match w {
609 ToolWidget1::CollapsedButton(widget_area, w) => {
610 w.render(widget_area, buf, &mut state.collapsed);
611 }
612 ToolWidget1::BasicButton(n, widget_area, w) => {
613 let ToolState::BasicButton(state, _) = state.tools[n].as_mut().expect("state")
614 else {
615 unreachable!("invalid_state");
616 };
617 w.render(widget_area, buf, state);
618 }
619 ToolWidget1::BasicCheckbox(n, widget_area, w) => {
620 let ToolState::BasicCheckbox(state) = state.tools[n].as_mut().expect("state")
621 else {
622 unreachable!("invalid_state");
623 };
624 w.render(widget_area, buf, state);
625 }
626 ToolWidget1::BasicChoice(n, widget_area, w) => {
627 let ToolState::BasicChoice(state) = state.tools[n].as_mut().expect("state") else {
628 unreachable!("invalid_state");
629 };
630 w.render(widget_area, buf, &mut PairedState::new(&mut (), state));
631 }
632 ToolWidget1::Text(widget_area, w) => {
633 w.render(widget_area, buf);
634 }
635 }
636 }
637}
638
639impl<'a> StatefulWidget for ToolbarPopup<'a> {
640 type State = ToolbarState;
641
642 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
643 render_popup(self, area, buf, state);
644 }
645}
646
647fn render_popup(widget: ToolbarPopup, _area: Rect, buf: &mut Buffer, state: &mut ToolbarState) {
648 for w in widget.tools {
649 match w {
650 ToolWidget2::CollapsedButton(w) => {
651 w.render(Rect::default(), buf, &mut state.collapsed);
652 }
653 ToolWidget2::BasicChoice(n, w) => {
654 let ToolState::BasicChoice(state) = state.tools[n].as_mut().expect("state") else {
655 unreachable!("invalid_state");
656 };
657 w.render(Rect::default(), buf, state);
658 }
659 }
660 }
661}
662
663impl Default for ToolbarState {
664 fn default() -> Self {
665 Self {
666 area: Default::default(),
667 inner: Default::default(),
668 collapsed: Default::default(),
669 collapsed_active: Default::default(),
670 tools: Default::default(),
671 focus_before: Default::default(),
672 container: Default::default(),
673 non_exhaustive: NonExhaustive,
674 }
675 }
676}
677
678impl HasFocus for ToolbarState {
679 fn build(&self, builder: &mut FocusBuilder) {
680 for w in self.tools.iter().flatten() {
681 match w {
682 ToolState::BasicButton(_, _) => {}
683 ToolState::BasicCheckbox(_) => {}
684 ToolState::BasicChoice(w) => {
685 builder.widget_navigate(w, Navigation::Leave);
686 }
687 }
688 }
689 }
690
691 fn focus(&self) -> FocusFlag {
692 self.container.clone()
693 }
694
695 fn area(&self) -> Rect {
696 self.area
697 }
698}
699
700impl RelocatableState for ToolbarState {
701 fn relocate(&mut self, _shift: (i16, i16), _clip: Rect) {}
702
703 fn relocate_popup(&mut self, shift: (i16, i16), clip: Rect) {
704 self.area.relocate(shift, clip);
705 self.inner.relocate(shift, clip);
706 self.collapsed.relocate(shift, clip);
707 self.collapsed.relocate_popup(shift, clip);
708 for w in self.tools.iter_mut().flatten() {
709 match w {
710 ToolState::BasicButton(w, active) => {
711 if *active {
712 w.relocate(shift, clip);
713 }
714 }
715 ToolState::BasicCheckbox(w) => {
716 w.relocate(shift, clip);
717 }
718 ToolState::BasicChoice(w) => {
719 w.relocate_popup(shift, clip);
720 }
721 }
722 }
723 }
724}
725
726impl ToolbarState {
727 pub fn new() -> Self {
728 Self::default()
729 }
730}
731
732pub enum ToolbarOutcome {
734 Continue,
736 Unchanged,
738 Changed,
740 Pressed(usize),
742 Checked(usize, bool),
744 Selected(usize, usize),
747}
748
749impl ConsumedEvent for ToolbarOutcome {
750 fn is_consumed(&self) -> bool {
751 !matches!(self, ToolbarOutcome::Continue)
752 }
753}
754
755impl From<Outcome> for ToolbarOutcome {
756 fn from(value: Outcome) -> Self {
757 match value {
758 Outcome::Continue => ToolbarOutcome::Continue,
759 Outcome::Unchanged => ToolbarOutcome::Unchanged,
760 Outcome::Changed => ToolbarOutcome::Changed,
761 }
762 }
763}
764
765impl From<ToolbarOutcome> for Outcome {
766 fn from(value: ToolbarOutcome) -> Self {
767 match value {
768 ToolbarOutcome::Continue => Outcome::Continue,
769 ToolbarOutcome::Unchanged => Outcome::Unchanged,
770 ToolbarOutcome::Changed => Outcome::Changed,
771 ToolbarOutcome::Pressed(_) => Outcome::Changed,
772 ToolbarOutcome::Selected(_, _) => Outcome::Changed,
773 ToolbarOutcome::Checked(_, _) => Outcome::Changed,
774 }
775 }
776}
777
778pub struct ToolbarKeys<'a, const N: usize> {
786 pub focus: &'a Focus,
788 pub keys: [Option<KeyEvent>; N],
790}
791
792impl<const N: usize> HandleEvent<Event, ToolbarKeys<'_, N>, ToolbarOutcome> for ToolbarState {
793 fn handle(&mut self, event: &Event, qualifier: ToolbarKeys<N>) -> ToolbarOutcome {
794 if let Event::Key(event) = event {
795 for (n, key) in qualifier.keys.iter().enumerate() {
796 if let Some(key) = key.as_ref()
797 && event.code == key.code
798 && event.modifiers == key.modifiers
799 {
800 match &mut self.tools[n] {
801 Some(ToolState::BasicButton(w, _)) => event_flow!(
802 return {
803 match w.pressed(event.kind == KeyEventKind::Press) {
804 ButtonOutcome::Pressed => ToolbarOutcome::Pressed(n),
805 r => ToolbarOutcome::from(Outcome::from(r)),
806 }
807 }
808 ),
809 Some(ToolState::BasicCheckbox(w)) => event_flow!(
810 return {
811 if event.kind == KeyEventKind::Press {
812 w.flip_checked();
813 ToolbarOutcome::Checked(n, w.value())
814 } else {
815 ToolbarOutcome::Unchanged
816 }
817 }
818 ),
819 Some(ToolState::BasicChoice(w)) => event_flow!(
820 return {
821 if event.kind == KeyEventKind::Press {
822 if w.is_focused() {
823 if let Some(focus_before) = self.focus_before.as_ref() {
824 qualifier.focus.focus(focus_before);
825 } else {
826 qualifier.focus.next();
827 }
828 } else {
829 qualifier.focus.focus(w);
830 self.focus_before = qualifier.focus.lost_focus();
831 }
832 ToolbarOutcome::Changed
833 } else {
834 ToolbarOutcome::Unchanged
835 }
836 }
837 ),
838 None => {}
839 }
840 }
841 }
842 }
843
844 if self.collapsed_active {
845 match self.collapsed.handle(event, Popup) {
846 ChoiceOutcome::Value | ChoiceOutcome::Changed => event_flow!(
847 return {
848 if !self.collapsed.is_popup_active() {
849 if let Some(value) = self.collapsed.value() {
850 self.collapsed.set_value(None);
851 ToolbarOutcome::Pressed(value)
852 } else {
853 ToolbarOutcome::Changed
854 }
855 } else {
856 ToolbarOutcome::Changed
857 }
858 }
859 ),
860 ChoiceOutcome::Continue => {
861 if self.collapsed.lost_focus() {
862 self.collapsed.set_value(None);
863 }
864 }
865 r => event_flow!(return ToolbarOutcome::from(Outcome::from(r))),
866 }
867 }
868
869 for (n, w) in self.tools.iter_mut().enumerate() {
870 match w {
871 Some(ToolState::BasicButton(w, active)) => event_flow!(
872 return {
873 if !*active {
874 continue;
875 }
876 match w.handle(event, Regular) {
877 ButtonOutcome::Pressed => ToolbarOutcome::Pressed(n),
878 r => ToolbarOutcome::from(Outcome::from(r)),
879 }
880 }
881 ),
882 Some(ToolState::BasicCheckbox(w)) => event_flow!(
883 return match w.handle(event, Regular) {
884 CheckOutcome::Value => ToolbarOutcome::Checked(n, w.value()),
885 r => ToolbarOutcome::from(Outcome::from(r)),
886 }
887 ),
888 Some(ToolState::BasicChoice(w)) => event_flow!(
889 return match w.handle(event, Popup) {
890 ChoiceOutcome::Value | ChoiceOutcome::Changed => {
891 if !w.is_popup_active() {
892 if let Some(focus_before) = self.focus_before.as_ref() {
893 qualifier.focus.focus(focus_before);
894 } else {
895 qualifier.focus.next();
896 }
897 ToolbarOutcome::Selected(n, w.value())
898 } else {
899 ToolbarOutcome::Changed
900 }
901 }
902 r => ToolbarOutcome::from(Outcome::from(r)),
903 }
904 ),
905 None => {}
906 }
907 }
908
909 ToolbarOutcome::Continue
910 }
911}