1use std::cell::{Cell, RefCell};
61use std::marker::PhantomData;
62use std::rc::Rc;
63use std::time::Duration;
64
65use rich::{Segment, Style};
66
67use crate::component::{Component, Context, Flow, View};
68use crate::event::{Event, Key, Mouse, MouseKind};
69use crate::keymap::{Binding, Keymap, keys};
70use crate::kit::{self, Divider, Theme};
71use crate::policy::{LineIo, NotInteractive};
72
73pub const FOCUS_NEXT: &str = "focus-next";
75pub const FOCUS_PREVIOUS: &str = "focus-previous";
77
78pub type Child<'a, M> = Box<dyn Component<Output = M> + 'a>;
81
82#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
84pub struct Rect {
85 pub x: usize,
86 pub y: usize,
87 pub width: usize,
88 pub height: usize,
89}
90
91impl Rect {
92 pub const fn new(x: usize, y: usize, width: usize, height: usize) -> Rect {
93 Rect {
94 x,
95 y,
96 width,
97 height,
98 }
99 }
100
101 pub fn contains(&self, column: usize, row: usize) -> bool {
103 column >= self.x
104 && column < self.x + self.width
105 && row >= self.y
106 && row < self.y + self.height
107 }
108
109 pub fn local(&self, mouse: Mouse) -> Mouse {
111 let clamp = |value: usize| u16::try_from(value).unwrap_or(u16::MAX);
112 Mouse {
113 column: clamp((mouse.column as usize).saturating_sub(self.x)),
114 row: clamp((mouse.row as usize).saturating_sub(self.y)),
115 ..mouse
116 }
117 }
118
119 pub fn context<'c>(&self, context: &Context<'c>) -> Context<'c> {
122 Context {
123 console: context.console,
124 width: self.width.max(1),
125 height: self.height.max(1),
126 }
127 }
128}
129
130#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
132pub enum Axis {
133 Horizontal,
135 #[default]
137 Vertical,
138}
139
140#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
142pub enum Size {
143 Fixed(usize),
146 Flex(u16),
149 #[default]
152 Auto,
153}
154
155fn share(total: usize, weights: &[u16]) -> Vec<usize> {
157 let sum: usize = weights.iter().map(|w| usize::from(*w)).sum();
158 if sum == 0 {
159 return vec![0; weights.len()];
160 }
161 let mut out: Vec<usize> = weights
162 .iter()
163 .map(|w| total * usize::from(*w) / sum)
164 .collect();
165 let mut left = total - out.iter().sum::<usize>();
166 for (index, weight) in weights.iter().enumerate() {
167 if left == 0 {
168 break;
169 }
170 if *weight > 0 {
171 out[index] += 1;
172 left -= 1;
173 }
174 }
175 out
176}
177
178pub struct Map<'a, C: Component, M> {
185 inner: C,
186 done: Box<dyn FnMut(C::Output) -> Flow<M> + 'a>,
187 cancel: Box<dyn FnMut() -> Flow<M> + 'a>,
188 finished: bool,
189}
190
191impl<'a, C: Component, M> Map<'a, C, M> {
192 #[must_use]
195 pub fn on_cancel(mut self, cancel: impl FnMut() -> Flow<M> + 'a) -> Self {
196 self.cancel = Box::new(cancel);
197 self
198 }
199
200 pub fn inner(&self) -> &C {
202 &self.inner
203 }
204
205 pub fn inner_mut(&mut self) -> &mut C {
206 &mut self.inner
207 }
208
209 pub fn finished(&self) -> bool {
211 self.finished
212 }
213
214 fn convert(&mut self, flow: Flow<C::Output>) -> Flow<M> {
215 match flow {
216 Flow::Continue => Flow::Continue,
217 Flow::Ignored => Flow::Ignored,
218 Flow::Handoff(command) => Flow::Handoff(command),
219 Flow::Done(value) => {
220 self.finished = true;
221 (self.done)(value)
222 }
223 Flow::Cancel => {
224 self.finished = true;
225 (self.cancel)()
226 }
227 }
228 }
229}
230
231impl<C: Component, M> Component for Map<'_, C, M> {
232 type Output = M;
233
234 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
235 let flow = self.inner.start(context);
236 self.convert(flow)
237 }
238
239 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
240 if self.finished {
241 return Flow::Ignored;
242 }
243 let flow = self.inner.handle(event, context);
244 self.convert(flow)
245 }
246
247 fn render(&self, context: &Context<'_>) -> View {
248 self.inner.render(context)
249 }
250
251 fn tick(&self) -> Option<Duration> {
252 if self.finished {
253 None
254 } else {
255 self.inner.tick()
256 }
257 }
258
259 fn mouse(&self) -> bool {
260 !self.finished && self.inner.mouse()
261 }
262
263 fn keymap(&self) -> Keymap {
264 if self.finished {
265 Keymap::default()
266 } else {
267 self.inner.keymap()
268 }
269 }
270
271 fn focusable(&self) -> bool {
272 !self.finished && self.inner.focusable()
273 }
274
275 fn focus_step(&mut self, forward: bool) -> bool {
276 !self.finished && self.inner.focus_step(forward)
277 }
278
279 fn focus_enter(&mut self, forward: bool) -> bool {
280 !self.finished && self.inner.focus_enter(forward)
281 }
282}
283
284pub trait ComponentExt: Component + Sized {
286 fn map<'a, M>(self, done: impl FnMut(Self::Output) -> Flow<M> + 'a) -> Map<'a, Self, M>
292 where
293 Self: 'a,
294 {
295 Map {
296 inner: self,
297 done: Box::new(done),
298 cancel: Box::new(|| Flow::Cancel),
299 finished: false,
300 }
301 }
302
303 fn with_overlays<'a>(self) -> crate::overlay::Overlays<'a, Self::Output>
307 where
308 Self: 'a,
309 Self::Output: 'a,
310 {
311 crate::overlay::Overlays::new(self)
312 }
313
314 fn boxed<'a>(self) -> Child<'a, Self::Output>
316 where
317 Self: 'a,
318 {
319 Box::new(self)
320 }
321}
322
323impl<C: Component> ComponentExt for C {}
324
325pub struct Label<M> {
327 markup: String,
328 _output: PhantomData<fn() -> M>,
329}
330
331impl<M> Label<M> {
332 pub fn new(markup: impl Into<String>) -> Label<M> {
333 Label {
334 markup: markup.into(),
335 _output: PhantomData,
336 }
337 }
338
339 pub fn set(&mut self, markup: impl Into<String>) {
341 self.markup = markup.into();
342 }
343}
344
345impl<M> Component for Label<M> {
346 type Output = M;
347
348 fn handle(&mut self, _: &Event, _: &Context<'_>) -> Flow<M> {
349 Flow::Ignored
350 }
351
352 fn render(&self, context: &Context<'_>) -> View {
353 View::new(context.markup(&self.markup))
354 }
355
356 fn focusable(&self) -> bool {
357 false
358 }
359}
360
361pub struct Painted<F, M> {
364 paint: F,
365 _output: PhantomData<fn() -> M>,
366}
367
368impl<F: Fn(&Context<'_>) -> View, M> Painted<F, M> {
369 pub fn new(paint: F) -> Painted<F, M> {
370 Painted {
371 paint,
372 _output: PhantomData,
373 }
374 }
375}
376
377impl<F: Fn(&Context<'_>) -> View, M> Component for Painted<F, M> {
378 type Output = M;
379
380 fn handle(&mut self, _: &Event, _: &Context<'_>) -> Flow<M> {
381 Flow::Ignored
382 }
383
384 fn render(&self, context: &Context<'_>) -> View {
385 (self.paint)(context)
386 }
387
388 fn focusable(&self) -> bool {
389 false
390 }
391}
392
393fn decisive<M>(flow: &Flow<M>) -> bool {
398 !matches!(flow, Flow::Continue | Flow::Ignored)
399}
400
401struct Group<'a, M> {
404 children: Vec<Child<'a, M>>,
405 focus: Option<usize>,
406 grab: Option<usize>,
407 handoff: Option<usize>,
408}
409
410impl<'a, M> Group<'a, M> {
411 fn new() -> Group<'a, M> {
412 Group {
413 children: Vec::new(),
414 focus: None,
415 grab: None,
416 handoff: None,
417 }
418 }
419
420 fn focused(&self) -> Option<usize> {
423 let takes = |index: usize| self.children[index].focusable();
424 self.focus
425 .filter(|&index| index < self.children.len() && takes(index))
426 .or_else(|| (0..self.children.len()).find(|&index| takes(index)))
427 }
428
429 fn settle(&mut self) {
430 self.focus = self.focused();
431 }
432
433 fn focus_step(&mut self, forward: bool) -> bool {
434 let current = self.focused();
435 if let Some(index) = current
436 && self.children[index].focus_step(forward)
437 {
438 return true;
439 }
440 let count = self.children.len();
441 let order: Vec<usize> = if forward {
442 (current.map_or(0, |index| index + 1)..count).collect()
443 } else {
444 (0..current.unwrap_or(count)).rev().collect()
445 };
446 for index in order {
447 if self.children[index].focus_enter(forward) {
448 self.focus = Some(index);
449 return true;
450 }
451 }
452 false
453 }
454
455 fn focus_enter(&mut self, forward: bool) -> bool {
456 let count = self.children.len();
457 let order: Vec<usize> = if forward {
458 (0..count).collect()
459 } else {
460 (0..count).rev().collect()
461 };
462 for index in order {
463 if self.children[index].focus_enter(forward) {
464 self.focus = Some(index);
465 return true;
466 }
467 }
468 false
469 }
470
471 fn deliver(&mut self, index: usize, event: &Event, context: &Context<'_>) -> Flow<M> {
472 let flow = self.children[index].handle(event, context);
473 if let Flow::Handoff(_) = flow {
474 self.handoff = Some(index);
475 }
476 flow
477 }
478
479 fn start(&mut self, context: &Context<'_>, rect: impl Fn(usize) -> Rect) -> Flow<M> {
480 for index in 0..self.children.len() {
481 let flow = self.children[index].start(&rect(index).context(context));
482 if decisive(&flow) {
483 return flow;
484 }
485 }
486 self.settle();
487 Flow::Continue
488 }
489
490 fn route(
494 &mut self,
495 event: &Event,
496 context: &Context<'_>,
497 rects: &[(usize, Rect)],
498 hidden: Rect,
499 ) -> Flow<M> {
500 let rect_of = |index: usize| {
501 rects
502 .iter()
503 .find(|(i, _)| *i == index)
504 .map_or(hidden, |(_, rect)| *rect)
505 };
506 match event {
507 Event::Mouse(mouse) => self.route_mouse(*mouse, context, rects),
508 Event::Tick | Event::Resize { .. } => {
509 for index in 0..self.children.len() {
510 if matches!(event, Event::Tick) && self.children[index].tick().is_none() {
511 continue;
512 }
513 let flow = self.deliver(index, event, &rect_of(index).context(context));
514 if decisive(&flow) {
515 return flow;
516 }
517 }
518 Flow::Continue
519 }
520 Event::Returned(_) => match self.handoff.take().or_else(|| self.focused()) {
521 Some(index) => self.deliver(index, event, &rect_of(index).context(context)),
522 None => Flow::Ignored,
523 },
524 _ => match self.focused() {
525 Some(index) => {
526 self.focus = Some(index);
527 self.deliver(index, event, &rect_of(index).context(context))
528 }
529 None => Flow::Ignored,
530 },
531 }
532 }
533
534 fn route_mouse(
535 &mut self,
536 mouse: Mouse,
537 context: &Context<'_>,
538 rects: &[(usize, Rect)],
539 ) -> Flow<M> {
540 let (column, row) = (mouse.column as usize, mouse.row as usize);
541 let under = rects
544 .iter()
545 .find(|(index, rect)| *index < self.children.len() && rect.contains(column, row))
546 .map(|(index, _)| *index);
547 let mut focused = false;
548 let target = match mouse.kind {
549 MouseKind::Down(_) => {
550 self.grab = under;
551 if let Some(index) = under.filter(|&i| self.children[i].focusable()) {
552 focused = self.focused() != Some(index);
553 self.focus = Some(index);
554 }
555 under
556 }
557 MouseKind::Drag(_) => self.grab.or(under),
558 MouseKind::Up(_) => self.grab.take().or(under),
559 _ => under,
560 };
561 let Some(index) = target else {
562 return Flow::Ignored;
563 };
564 let Some((_, rect)) = rects.iter().find(|(i, _)| *i == index).copied() else {
565 return Flow::Ignored;
566 };
567 if !self.children[index].mouse() {
568 return if focused {
569 Flow::Continue
570 } else {
571 Flow::Ignored
572 };
573 }
574 let flow = self.deliver(
575 index,
576 &Event::Mouse(rect.local(mouse)),
577 &rect.context(context),
578 );
579 match flow {
580 Flow::Ignored if focused => Flow::Continue,
581 flow => flow,
582 }
583 }
584
585 fn tick(&self) -> Option<Duration> {
586 self.children.iter().filter_map(|child| child.tick()).min()
587 }
588
589 fn mouse(&self) -> bool {
590 self.children.iter().any(|child| child.mouse())
591 }
592
593 fn focusable(&self) -> bool {
594 self.children.iter().any(|child| child.focusable())
595 }
596}
597
598type Handler<'a, M> = Box<dyn FnMut() -> Flow<M> + 'a>;
599
600struct Bindings<'a, M> {
603 keymap: Keymap,
604 priority: Vec<String>,
605 handlers: Vec<(String, Handler<'a, M>)>,
606}
607
608impl<'a, M> Bindings<'a, M> {
609 fn new(context: &str) -> Bindings<'a, M> {
610 Bindings {
611 keymap: Keymap::new(context),
612 priority: Vec::new(),
613 handlers: Vec::new(),
614 }
615 }
616
617 fn declare(&mut self, action: &str, keys: Vec<Key>, description: &str, priority: bool) {
618 let binding = Binding::new(self.keymap.context(), action, keys, description);
619 self.keymap.add(binding);
620 self.priority.retain(|p| p != action);
621 if priority {
622 self.priority.push(action.to_string());
623 }
624 }
625
626 fn focus_keys(mut self) -> Self {
627 self.declare(FOCUS_NEXT, keys("tab"), "next field", false);
628 self.declare(FOCUS_PREVIOUS, keys("shift+tab"), "previous field", false);
629 self
630 }
631
632 fn on(
633 &mut self,
634 action: &str,
635 keys: Vec<Key>,
636 description: &str,
637 priority: bool,
638 handler: impl FnMut() -> Flow<M> + 'a,
639 ) {
640 self.declare(action, keys, description, priority);
641 self.handlers.retain(|(name, _)| name != action);
642 self.handlers.push((action.to_string(), Box::new(handler)));
643 }
644
645 fn action(&self, key: Key, priority: bool) -> Option<String> {
648 let action = self.keymap.action(key)?;
649 (self.priority.iter().any(|p| p == action) == priority).then(|| action.to_string())
650 }
651
652 fn run(&mut self, action: &str) -> Option<Flow<M>> {
654 self.handlers
655 .iter_mut()
656 .find(|(name, _)| name == action)
657 .map(|(_, handler)| handler())
658 }
659}
660
661macro_rules! binding_builders {
663 () => {
664 #[must_use]
668 pub fn on(
669 mut self,
670 action: &str,
671 keys: impl IntoIterator<Item = Key>,
672 description: &str,
673 handler: impl FnMut() -> Flow<M> + 'a,
674 ) -> Self {
675 let keys = keys.into_iter().collect();
676 self.bindings.on(action, keys, description, false, handler);
677 self
678 }
679
680 #[must_use]
683 pub fn shortcut(
684 mut self,
685 action: &str,
686 keys: impl IntoIterator<Item = Key>,
687 description: &str,
688 handler: impl FnMut() -> Flow<M> + 'a,
689 ) -> Self {
690 let keys = keys.into_iter().collect();
691 self.bindings.on(action, keys, description, true, handler);
692 self
693 }
694
695 #[must_use]
698 pub fn rebind(mut self, action: &str, keys: impl IntoIterator<Item = Key>) -> Self {
699 self.bindings.keymap.rebind(action, keys);
700 self
701 }
702
703 pub fn own_keymap(&self) -> &Keymap {
705 &self.bindings.keymap
706 }
707
708 #[must_use]
711 pub fn with_mouse(mut self, on: bool) -> Self {
712 self.mouse = on;
713 self
714 }
715 };
716}
717
718pub struct Stack<'a, M> {
724 axis: Axis,
725 group: Group<'a, M>,
726 sizes: Vec<Size>,
727 gap: usize,
728 bindings: Bindings<'a, M>,
729 mouse: bool,
730}
731
732impl<'a, M> Stack<'a, M> {
733 pub fn new(axis: Axis) -> Stack<'a, M> {
734 Stack {
735 axis,
736 group: Group::new(),
737 sizes: Vec::new(),
738 gap: 0,
739 bindings: Bindings::new("stack").focus_keys(),
740 mouse: false,
741 }
742 }
743
744 #[must_use]
746 pub fn child(self, child: impl Component<Output = M> + 'a) -> Self {
747 self.sized(Size::Auto, child)
748 }
749
750 #[must_use]
752 pub fn sized(mut self, size: Size, child: impl Component<Output = M> + 'a) -> Self {
753 self.push(size, Box::new(child));
754 self
755 }
756
757 pub fn push(&mut self, size: Size, child: Child<'a, M>) {
759 self.group.children.push(child);
760 self.sizes.push(size);
761 }
762
763 #[must_use]
765 pub fn gap(mut self, cells: usize) -> Self {
766 self.gap = cells;
767 self
768 }
769
770 binding_builders!();
771
772 pub fn axis(&self) -> Axis {
773 self.axis
774 }
775
776 pub fn len(&self) -> usize {
777 self.group.children.len()
778 }
779
780 pub fn is_empty(&self) -> bool {
781 self.group.children.is_empty()
782 }
783
784 pub fn get(&self, index: usize) -> Option<&(dyn Component<Output = M> + 'a)> {
786 self.group.children.get(index).map(|child| &**child)
787 }
788
789 pub fn get_mut(&mut self, index: usize) -> Option<&mut (dyn Component<Output = M> + 'a)> {
790 self.group.children.get_mut(index).map(|child| &mut **child)
791 }
792
793 pub fn focused(&self) -> Option<usize> {
795 self.group.focused()
796 }
797
798 pub fn focus(&mut self, index: usize) -> bool {
800 let takes = self
801 .group
802 .children
803 .get_mut(index)
804 .is_some_and(|child| child.focus_enter(true));
805 if takes {
806 self.group.focus = Some(index);
807 }
808 takes
809 }
810
811 pub fn layout(&self, context: &Context<'_>) -> Vec<Rect> {
814 let count = self.len();
815 let gaps = self.gap * count.saturating_sub(1);
816 let vertical = self.axis == Axis::Vertical;
817 let total = if vertical {
818 context.height
819 } else {
820 context.width
821 };
822 let mut left = total.saturating_sub(gaps);
823 let mut extent = vec![0; count];
824 for (index, size) in self.sizes.iter().enumerate() {
825 if let Size::Fixed(cells) = size {
826 extent[index] = (*cells).min(left);
827 left -= extent[index];
828 }
829 }
830 if vertical {
831 for (index, size) in self.sizes.iter().enumerate() {
832 if *size == Size::Auto {
833 let probe = Rect::new(0, 0, context.width, left).context(context);
834 extent[index] = self.group.children[index]
835 .render(&probe)
836 .lines
837 .len()
838 .min(left);
839 left -= extent[index];
840 }
841 }
842 }
843 let weights: Vec<u16> = self
844 .sizes
845 .iter()
846 .map(|size| match size {
847 Size::Flex(weight) => *weight,
848 Size::Auto if !vertical => 1,
849 _ => 0,
850 })
851 .collect();
852 for (index, cells) in share(left, &weights).into_iter().enumerate() {
853 if weights[index] > 0 {
854 extent[index] = cells;
855 }
856 }
857 let mut at = 0;
858 extent
859 .into_iter()
860 .map(|cells| {
861 let rect = if vertical {
862 Rect::new(0, at, context.width, cells)
863 } else {
864 Rect::new(at, 0, cells, context.height)
865 };
866 at += cells + self.gap;
867 rect
868 })
869 .collect()
870 }
871
872 fn indexed(&self, context: &Context<'_>) -> Vec<(usize, Rect)> {
873 self.layout(context).into_iter().enumerate().collect()
874 }
875}
876
877fn rows_of(view: &View, rect: Rect, fill: bool) -> Vec<Vec<Segment>> {
880 let mut lines: Vec<Vec<Segment>> = view
881 .lines
882 .iter()
883 .take(rect.height)
884 .map(|line| kit::fit(line.clone(), rect.width))
885 .collect();
886 if fill {
887 lines.resize_with(rect.height, Vec::new);
888 }
889 lines
890}
891
892fn side_by_side(
895 views: &[(View, Rect)],
896 rows: usize,
897 focus: Option<usize>,
898 between: &[Vec<Segment>],
899) -> View {
900 let mut lines = Vec::with_capacity(rows);
901 for row in 0..rows {
902 let mut line = Vec::new();
903 for (index, (view, rect)) in views.iter().enumerate() {
904 let cells = view.lines.get(row).cloned().unwrap_or_default();
905 if index + 1 == views.len() {
906 line.extend(kit::fit(cells, rect.width));
907 } else {
908 line.extend(kit::pad(cells, rect.width));
909 line.extend(between.get(index).cloned().unwrap_or_default());
910 }
911 }
912 lines.push(line);
913 }
914 let mut out = View::new(lines);
915 if let Some((view, rect)) = focus.and_then(|index| views.get(index))
916 && let Some((row, column)) = view.cursor
917 && row < rows
918 && column < rect.width.max(1)
919 {
920 out.cursor = Some((rect.y + row, rect.x + column));
921 }
922 out
923}
924
925fn keymap_with<M>(focused: Option<&Child<'_, M>>, own: &Keymap) -> Keymap {
927 let mut keymap = focused.map(|child| child.keymap()).unwrap_or_default();
928 keymap.extend(own.clone());
929 keymap
930}
931
932impl<M> Component for Stack<'_, M> {
933 type Output = M;
934
935 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
936 let rects = self.layout(context);
937 self.group.start(context, |index| rects[index])
938 }
939
940 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
941 if let Some(key) = event.key()
942 && let Some(action) = self.bindings.action(key, true)
943 && let Some(flow) = self.bindings.run(&action)
944 {
945 return flow;
946 }
947 let rects = self.indexed(context);
948 let flow = self.group.route(event, context, &rects, Rect::default());
949 self.group.settle();
950 if !matches!(flow, Flow::Ignored) {
951 return flow;
952 }
953 let Some(action) = event.key().and_then(|key| self.bindings.action(key, false)) else {
954 return Flow::Ignored;
955 };
956 match action.as_str() {
957 FOCUS_NEXT | FOCUS_PREVIOUS => {
958 if self.group.focus_step(action == FOCUS_NEXT) {
959 Flow::Continue
960 } else {
961 Flow::Ignored
962 }
963 }
964 _ => self.bindings.run(&action).unwrap_or(Flow::Ignored),
965 }
966 }
967
968 fn render(&self, context: &Context<'_>) -> View {
969 let rects = self.layout(context);
970 let focus = self.group.focused();
971 let views: Vec<(View, Rect)> = rects
972 .iter()
973 .enumerate()
974 .map(|(index, rect)| {
975 (
976 self.group.children[index].render(&rect.context(context)),
977 *rect,
978 )
979 })
980 .collect();
981 match self.axis {
982 Axis::Vertical => {
983 let mut out = View::default();
984 for (index, (view, rect)) in views.iter().enumerate() {
985 if index > 0 {
986 out.lines.extend(std::iter::repeat_n(Vec::new(), self.gap));
987 }
988 let fill = self.sizes[index] != Size::Auto;
989 let top = out.lines.len();
990 out.lines.extend(rows_of(view, *rect, fill));
991 if Some(index) == focus
992 && let Some((row, column)) = view.cursor
993 && row < rect.height
994 {
995 out.cursor = Some((top + row, column));
996 }
997 }
998 out
999 }
1000 Axis::Horizontal => {
1001 let rows = views
1002 .iter()
1003 .map(|(view, _)| view.lines.len())
1004 .max()
1005 .unwrap_or(0)
1006 .min(context.height);
1007 let gap = vec![kit::plain(" ".repeat(self.gap))];
1008 let between = vec![gap; views.len()];
1009 side_by_side(&views, rows, focus, &between)
1010 }
1011 }
1012 }
1013
1014 fn tick(&self) -> Option<Duration> {
1015 self.group.tick()
1016 }
1017
1018 fn mouse(&self) -> bool {
1019 self.mouse || self.group.mouse()
1020 }
1021
1022 fn keymap(&self) -> Keymap {
1023 let focused = self
1024 .group
1025 .focused()
1026 .map(|index| &self.group.children[index]);
1027 keymap_with(focused, &self.bindings.keymap)
1028 }
1029
1030 fn focusable(&self) -> bool {
1031 self.group.focusable()
1032 }
1033
1034 fn focus_step(&mut self, forward: bool) -> bool {
1035 self.group.focus_step(forward)
1036 }
1037
1038 fn focus_enter(&mut self, forward: bool) -> bool {
1039 self.group.focus_enter(forward)
1040 }
1041}
1042
1043macro_rules! axis_stack {
1045 ($(#[$doc:meta])* $name:ident, $axis:expr) => {
1046 $(#[$doc])*
1047 pub struct $name<'a, M>(Stack<'a, M>);
1048
1049 impl<'a, M> Default for $name<'a, M> {
1050 fn default() -> Self {
1051 Self::new()
1052 }
1053 }
1054
1055 impl<'a, M> $name<'a, M> {
1056 pub fn new() -> Self {
1057 $name(Stack::new($axis))
1058 }
1059
1060 #[must_use]
1062 pub fn child(self, child: impl Component<Output = M> + 'a) -> Self {
1063 $name(self.0.child(child))
1064 }
1065
1066 #[must_use]
1068 pub fn sized(self, size: Size, child: impl Component<Output = M> + 'a) -> Self {
1069 $name(self.0.sized(size, child))
1070 }
1071
1072 #[must_use]
1074 pub fn gap(self, cells: usize) -> Self {
1075 $name(self.0.gap(cells))
1076 }
1077
1078 #[must_use]
1080 pub fn on(
1081 self,
1082 action: &str,
1083 keys: impl IntoIterator<Item = Key>,
1084 description: &str,
1085 handler: impl FnMut() -> Flow<M> + 'a,
1086 ) -> Self {
1087 $name(self.0.on(action, keys, description, handler))
1088 }
1089
1090 #[must_use]
1092 pub fn shortcut(
1093 self,
1094 action: &str,
1095 keys: impl IntoIterator<Item = Key>,
1096 description: &str,
1097 handler: impl FnMut() -> Flow<M> + 'a,
1098 ) -> Self {
1099 $name(self.0.shortcut(action, keys, description, handler))
1100 }
1101
1102 #[must_use]
1104 pub fn rebind(self, action: &str, keys: impl IntoIterator<Item = Key>) -> Self {
1105 $name(self.0.rebind(action, keys))
1106 }
1107
1108 #[must_use]
1110 pub fn with_mouse(self, on: bool) -> Self {
1111 $name(self.0.with_mouse(on))
1112 }
1113
1114 pub fn stack(&self) -> &Stack<'a, M> {
1116 &self.0
1117 }
1118
1119 pub fn stack_mut(&mut self) -> &mut Stack<'a, M> {
1120 &mut self.0
1121 }
1122 }
1123
1124 impl<'a, M> Component for $name<'a, M> {
1125 type Output = M;
1126
1127 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
1128 self.0.start(context)
1129 }
1130
1131 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
1132 self.0.handle(event, context)
1133 }
1134
1135 fn render(&self, context: &Context<'_>) -> View {
1136 self.0.render(context)
1137 }
1138
1139 fn tick(&self) -> Option<Duration> {
1140 self.0.tick()
1141 }
1142
1143 fn mouse(&self) -> bool {
1144 Component::mouse(&self.0)
1145 }
1146
1147 fn keymap(&self) -> Keymap {
1148 self.0.keymap()
1149 }
1150
1151 fn focusable(&self) -> bool {
1152 self.0.focusable()
1153 }
1154
1155 fn focus_step(&mut self, forward: bool) -> bool {
1156 self.0.focus_step(forward)
1157 }
1158
1159 fn focus_enter(&mut self, forward: bool) -> bool {
1160 self.0.focus_enter(forward)
1161 }
1162 }
1163 };
1164}
1165
1166axis_stack!(
1167 Column,
1171 Axis::Vertical
1172);
1173
1174axis_stack!(
1175 Row,
1178 Axis::Horizontal
1179);
1180
1181pub struct Split<'a, M> {
1190 axis: Axis,
1191 group: Group<'a, M>,
1192 divider: Divider,
1193 ratio: u8,
1194 style: Style,
1195 bindings: Bindings<'a, M>,
1196 mouse: bool,
1197}
1198
1199impl<'a, M> Split<'a, M> {
1200 fn new(
1201 axis: Axis,
1202 first: impl Component<Output = M> + 'a,
1203 second: impl Component<Output = M> + 'a,
1204 ) -> Split<'a, M> {
1205 let mut group = Group::new();
1206 group.children.push(Box::new(first) as Child<'a, M>);
1207 group.children.push(Box::new(second) as Child<'a, M>);
1208 let mut bindings = Bindings::new("split").focus_keys();
1209 let (shrink, grow) = match axis {
1210 Axis::Horizontal => ("alt+h", "alt+l"),
1211 Axis::Vertical => ("alt+k", "alt+j"),
1212 };
1213 bindings.declare("shrink", keys(shrink), "move the border back", true);
1214 bindings.declare("grow", keys(grow), "move the border on", true);
1215 Split {
1216 axis,
1217 group,
1218 divider: Divider::new(1).min(1),
1219 ratio: 50,
1220 style: Theme::default().border,
1221 bindings,
1222 mouse: false,
1223 }
1224 }
1225
1226 pub fn horizontal(
1228 left: impl Component<Output = M> + 'a,
1229 right: impl Component<Output = M> + 'a,
1230 ) -> Split<'a, M> {
1231 Split::new(Axis::Horizontal, left, right)
1232 }
1233
1234 pub fn vertical(
1236 top: impl Component<Output = M> + 'a,
1237 bottom: impl Component<Output = M> + 'a,
1238 ) -> Split<'a, M> {
1239 Split::new(Axis::Vertical, top, bottom)
1240 }
1241
1242 #[must_use]
1245 pub fn ratio(mut self, percent: u8) -> Self {
1246 self.ratio = percent.min(100);
1247 self
1248 }
1249
1250 #[must_use]
1252 pub fn at(mut self, cells: usize) -> Self {
1253 self.divider.set_position(Some(cells));
1254 self
1255 }
1256
1257 #[must_use]
1259 pub fn min(mut self, cells: usize) -> Self {
1260 self.divider.min_before = cells;
1261 self.divider.min_after = cells;
1262 self
1263 }
1264
1265 #[must_use]
1268 pub fn mins(mut self, first: usize, second: usize) -> Self {
1269 self.divider.min_before = first;
1270 self.divider.min_after = second;
1271 self
1272 }
1273
1274 #[must_use]
1276 pub fn style(mut self, style: Style) -> Self {
1277 self.style = style;
1278 self
1279 }
1280
1281 binding_builders!();
1282
1283 pub fn axis(&self) -> Axis {
1284 self.axis
1285 }
1286
1287 pub fn divider(&self) -> &Divider {
1289 &self.divider
1290 }
1291
1292 pub fn first(&self) -> &(dyn Component<Output = M> + 'a) {
1293 &*self.group.children[0]
1294 }
1295
1296 pub fn second(&self) -> &(dyn Component<Output = M> + 'a) {
1297 &*self.group.children[1]
1298 }
1299
1300 pub fn first_mut(&mut self) -> &mut (dyn Component<Output = M> + 'a) {
1301 &mut *self.group.children[0]
1302 }
1303
1304 pub fn second_mut(&mut self) -> &mut (dyn Component<Output = M> + 'a) {
1305 &mut *self.group.children[1]
1306 }
1307
1308 pub fn focused(&self) -> Option<usize> {
1310 self.group.focused()
1311 }
1312
1313 pub fn focus(&mut self, index: usize) -> bool {
1315 let takes = self
1316 .group
1317 .children
1318 .get_mut(index)
1319 .is_some_and(|child| child.focus_enter(true));
1320 if takes {
1321 self.group.focus = Some(index);
1322 }
1323 takes
1324 }
1325
1326 fn extent(&self, context: &Context<'_>) -> (usize, usize) {
1328 let total = match self.axis {
1329 Axis::Horizontal => context.width,
1330 Axis::Vertical => context.height,
1331 };
1332 let default = self
1333 .divider
1334 .clamp(total * usize::from(self.ratio) / 100, total);
1335 (total, self.divider.resolve(total, default))
1336 }
1337
1338 pub fn layout(&self, context: &Context<'_>) -> [Rect; 2] {
1340 let (total, first) = self.extent(context);
1341 let second = total.saturating_sub(first + self.divider.thickness);
1342 match self.axis {
1343 Axis::Horizontal => [
1344 Rect::new(0, 0, first, context.height),
1345 Rect::new(first + self.divider.thickness, 0, second, context.height),
1346 ],
1347 Axis::Vertical => [
1348 Rect::new(0, 0, context.width, first),
1349 Rect::new(0, first + self.divider.thickness, context.width, second),
1350 ],
1351 }
1352 }
1353}
1354
1355impl<M> Component for Split<'_, M> {
1356 type Output = M;
1357
1358 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
1359 let rects = self.layout(context);
1360 self.group.start(context, |index| rects[index])
1361 }
1362
1363 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
1364 let (total, first) = self.extent(context);
1365 if let Some(key) = event.key()
1366 && let Some(action) = self.bindings.action(key, true)
1367 {
1368 let step = match self.axis {
1369 Axis::Horizontal => 2,
1370 Axis::Vertical => 1,
1371 };
1372 match action.as_str() {
1373 "shrink" => self.divider.nudge(-step, first, total),
1374 "grow" => self.divider.nudge(step, first, total),
1375 _ => {
1376 if let Some(flow) = self.bindings.run(&action) {
1377 return flow;
1378 }
1379 }
1380 }
1381 return Flow::Continue;
1382 }
1383 if let Event::Mouse(mouse) = event {
1384 let along = match self.axis {
1385 Axis::Horizontal => mouse.column as usize,
1386 Axis::Vertical => mouse.row as usize,
1387 };
1388 if self.divider.handle_mouse(mouse, along, first, total) {
1389 self.group.grab = None;
1390 return Flow::Continue;
1391 }
1392 }
1393 let [a, b] = self.layout(context);
1394 let flow = self
1395 .group
1396 .route(event, context, &[(0, a), (1, b)], Rect::default());
1397 self.group.settle();
1398 if !matches!(flow, Flow::Ignored) {
1399 return flow;
1400 }
1401 let Some(action) = event.key().and_then(|key| self.bindings.action(key, false)) else {
1402 return Flow::Ignored;
1403 };
1404 match action.as_str() {
1405 FOCUS_NEXT | FOCUS_PREVIOUS => {
1406 if self.group.focus_step(action == FOCUS_NEXT) {
1407 Flow::Continue
1408 } else {
1409 Flow::Ignored
1410 }
1411 }
1412 _ => self.bindings.run(&action).unwrap_or(Flow::Ignored),
1413 }
1414 }
1415
1416 fn render(&self, context: &Context<'_>) -> View {
1417 let [a, b] = self.layout(context);
1418 let focus = self.group.focused();
1419 let first = self.group.children[0].render(&a.context(context));
1420 let second = self.group.children[1].render(&b.context(context));
1421 match self.axis {
1422 Axis::Horizontal => {
1423 let rows = first
1424 .lines
1425 .len()
1426 .max(second.lines.len())
1427 .min(context.height)
1428 .max(1);
1429 let border = vec![vec![kit::text("│", &self.style)]];
1430 side_by_side(&[(first, a), (second, b)], rows, focus, &border)
1431 }
1432 Axis::Vertical => {
1433 let mut out = View::new(rows_of(&first, a, true));
1434 out.lines
1435 .push(vec![kit::text("─".repeat(context.width), &self.style)]);
1436 out.lines.extend(rows_of(&second, b, true));
1437 let (view, rect) = match focus {
1438 Some(0) => (&first, a),
1439 _ => (&second, b),
1440 };
1441 if let Some((row, column)) = view.cursor.filter(|(row, _)| *row < rect.height) {
1442 out.cursor = Some((rect.y + row, column));
1443 }
1444 out
1445 }
1446 }
1447 }
1448
1449 fn tick(&self) -> Option<Duration> {
1450 self.group.tick()
1451 }
1452
1453 fn mouse(&self) -> bool {
1454 self.mouse || self.group.mouse()
1455 }
1456
1457 fn keymap(&self) -> Keymap {
1458 let focused = self
1459 .group
1460 .focused()
1461 .map(|index| &self.group.children[index]);
1462 keymap_with(focused, &self.bindings.keymap)
1463 }
1464
1465 fn focusable(&self) -> bool {
1466 self.group.focusable()
1467 }
1468
1469 fn focus_step(&mut self, forward: bool) -> bool {
1470 self.group.focus_step(forward)
1471 }
1472
1473 fn focus_enter(&mut self, forward: bool) -> bool {
1474 self.group.focus_enter(forward)
1475 }
1476}
1477
1478pub struct Tabs<'a, M> {
1488 titles: Vec<String>,
1489 group: Group<'a, M>,
1490 active: usize,
1491 selected: Style,
1492 unselected: Style,
1493 bindings: Bindings<'a, M>,
1494 mouse: bool,
1495}
1496
1497impl<'a, M> Default for Tabs<'a, M> {
1498 fn default() -> Self {
1499 Self::new()
1500 }
1501}
1502
1503impl<'a, M> Tabs<'a, M> {
1504 pub fn new() -> Tabs<'a, M> {
1505 let mut bindings = Bindings::new("tabs").focus_keys();
1506 bindings.declare("next", keys("alt+right ctrl+pagedown"), "next tab", true);
1507 bindings.declare(
1508 "previous",
1509 keys("alt+left ctrl+pageup"),
1510 "previous tab",
1511 true,
1512 );
1513 Tabs {
1514 titles: Vec::new(),
1515 group: Group::new(),
1516 active: 0,
1517 selected: Style::parse("bold reverse").expect("a built-in style"),
1518 unselected: Theme::default().hint,
1519 bindings,
1520 mouse: false,
1521 }
1522 }
1523
1524 #[must_use]
1526 pub fn tab(mut self, title: impl Into<String>, child: impl Component<Output = M> + 'a) -> Self {
1527 self.push(title, Box::new(child));
1528 self
1529 }
1530
1531 pub fn push(&mut self, title: impl Into<String>, child: Child<'a, M>) {
1533 self.titles.push(title.into());
1534 self.group.children.push(child);
1535 let number = self.titles.len();
1536 if number <= 9 {
1537 self.bindings.declare(
1538 &format!("tab-{number}"),
1539 keys(&format!("alt+{number}")),
1540 &format!("show tab {number}"),
1541 true,
1542 );
1543 }
1544 }
1545
1546 #[must_use]
1548 pub fn styles(mut self, selected: Style, unselected: Style) -> Self {
1549 self.selected = selected;
1550 self.unselected = unselected;
1551 self
1552 }
1553
1554 #[must_use]
1556 pub fn active(mut self, index: usize) -> Self {
1557 self.select(index);
1558 self
1559 }
1560
1561 binding_builders!();
1562
1563 pub fn select(&mut self, index: usize) {
1565 if index < self.titles.len() {
1566 self.active = index;
1567 self.group.focus = Some(index);
1568 }
1569 }
1570
1571 pub fn selected(&self) -> usize {
1573 self.active
1574 }
1575
1576 pub fn titles(&self) -> &[String] {
1577 &self.titles
1578 }
1579
1580 pub fn len(&self) -> usize {
1581 self.titles.len()
1582 }
1583
1584 pub fn is_empty(&self) -> bool {
1585 self.titles.is_empty()
1586 }
1587
1588 pub fn get(&self, index: usize) -> Option<&(dyn Component<Output = M> + 'a)> {
1590 self.group.children.get(index).map(|child| &**child)
1591 }
1592
1593 pub fn get_mut(&mut self, index: usize) -> Option<&mut (dyn Component<Output = M> + 'a)> {
1594 self.group.children.get_mut(index).map(|child| &mut **child)
1595 }
1596
1597 fn bar(&self, width: usize) -> (Vec<Segment>, Vec<(usize, usize)>) {
1599 let mut line = Vec::new();
1600 let mut spans = Vec::new();
1601 let mut at = 0;
1602 for (index, title) in self.titles.iter().enumerate() {
1603 if index > 0 {
1604 line.push(kit::plain(" "));
1605 at += 1;
1606 }
1607 let label = format!(" {} ", kit::shown(title));
1610 let cells = rich::cells::cell_len(&label);
1611 let style = if index == self.active {
1612 &self.selected
1613 } else {
1614 &self.unselected
1615 };
1616 line.push(kit::text(label, style));
1617 spans.push((at, at + cells));
1618 at += cells;
1619 }
1620 (kit::fit(line, width), spans)
1621 }
1622
1623 pub fn content(&self, context: &Context<'_>) -> Rect {
1625 Rect::new(0, 1, context.width, context.height.saturating_sub(1))
1626 }
1627}
1628
1629impl<M> Component for Tabs<'_, M> {
1630 type Output = M;
1631
1632 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
1633 let rect = self.content(context);
1634 let flow = self.group.start(context, |_| rect);
1635 self.group.focus = Some(self.active);
1636 flow
1637 }
1638
1639 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
1640 let count = self.titles.len();
1641 if let Some(key) = event.key()
1642 && let Some(action) = self.bindings.action(key, true)
1643 {
1644 match action.as_str() {
1645 "next" if count > 0 => self.select((self.active + 1) % count),
1646 "previous" if count > 0 => self.select((self.active + count - 1) % count),
1647 number if number.starts_with("tab-") => {
1648 if let Ok(n) = number[4..].parse::<usize>() {
1649 self.select(n.saturating_sub(1));
1650 }
1651 }
1652 _ => {
1653 if let Some(flow) = self.bindings.run(&action) {
1654 return flow;
1655 }
1656 }
1657 }
1658 return Flow::Continue;
1659 }
1660 if let Event::Mouse(mouse) = event
1661 && mouse.row == 0
1662 && self.group.grab.is_none()
1663 {
1664 if mouse.is_click() {
1665 let (_, spans) = self.bar(context.width);
1666 let column = mouse.column as usize;
1667 if let Some(index) = spans.iter().position(|(a, b)| (*a..*b).contains(&column)) {
1668 self.select(index);
1669 return Flow::Continue;
1670 }
1671 }
1672 return Flow::Ignored;
1673 }
1674 let rect = self.content(context);
1675 self.group.focus = Some(self.active);
1676 let flow = self
1677 .group
1678 .route(event, context, &[(self.active, rect)], rect);
1679 if !matches!(flow, Flow::Ignored) {
1680 return flow;
1681 }
1682 let Some(action) = event.key().and_then(|key| self.bindings.action(key, false)) else {
1683 return Flow::Ignored;
1684 };
1685 match action.as_str() {
1686 FOCUS_NEXT | FOCUS_PREVIOUS => {
1687 let forward = action == FOCUS_NEXT;
1688 if self
1690 .group
1691 .children
1692 .get_mut(self.active)
1693 .is_some_and(|child| child.focus_step(forward))
1694 {
1695 Flow::Continue
1696 } else {
1697 Flow::Ignored
1698 }
1699 }
1700 _ => self.bindings.run(&action).unwrap_or(Flow::Ignored),
1701 }
1702 }
1703
1704 fn render(&self, context: &Context<'_>) -> View {
1705 let (bar, _) = self.bar(context.width);
1706 let mut out = View::new(vec![bar]);
1707 if let Some(child) = self.group.children.get(self.active) {
1708 let rect = self.content(context);
1709 let view = child.render(&rect.context(context));
1710 out.lines.extend(rows_of(&view, rect, false));
1711 if let Some((row, column)) = view.cursor.filter(|(row, _)| *row < rect.height) {
1712 out.cursor = Some((rect.y + row, column));
1713 }
1714 }
1715 out
1716 }
1717
1718 fn tick(&self) -> Option<Duration> {
1719 self.group.tick()
1720 }
1721
1722 fn mouse(&self) -> bool {
1723 self.mouse || self.group.mouse()
1724 }
1725
1726 fn keymap(&self) -> Keymap {
1727 keymap_with(self.group.children.get(self.active), &self.bindings.keymap)
1728 }
1729
1730 fn focusable(&self) -> bool {
1731 self.group
1732 .children
1733 .get(self.active)
1734 .is_some_and(|child| child.focusable())
1735 }
1736
1737 fn focus_step(&mut self, forward: bool) -> bool {
1738 let active = self.active;
1739 self.group
1740 .children
1741 .get_mut(active)
1742 .is_some_and(|child| child.focus_step(forward))
1743 }
1744
1745 fn focus_enter(&mut self, forward: bool) -> bool {
1746 let active = self.active;
1747 self.group
1748 .children
1749 .get_mut(active)
1750 .is_some_and(|child| child.focus_enter(forward))
1751 }
1752}
1753
1754#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
1759pub enum LayerKind {
1760 #[default]
1763 Modal,
1764 Popover,
1767}
1768
1769#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1771pub enum Placement {
1772 Center { width: usize, height: usize },
1775 At(Rect),
1777}
1778
1779impl Default for Placement {
1780 fn default() -> Self {
1781 Placement::Center {
1782 width: 40,
1783 height: 10,
1784 }
1785 }
1786}
1787
1788pub struct Layer<'a, M> {
1794 child: Child<'a, M>,
1795 kind: LayerKind,
1796 placement: Placement,
1797 title: Option<String>,
1798 border: bool,
1799 backdrop: bool,
1800 dismissable: bool,
1801 took_focus: bool,
1805}
1806
1807impl<'a, M> Layer<'a, M> {
1808 fn new(kind: LayerKind, child: impl Component<Output = M> + 'a) -> Layer<'a, M> {
1809 Layer {
1810 child: Box::new(child),
1811 kind,
1812 placement: Placement::default(),
1813 title: None,
1814 border: true,
1815 backdrop: kind == LayerKind::Modal,
1816 dismissable: true,
1817 took_focus: false,
1818 }
1819 }
1820
1821 pub fn modal(child: impl Component<Output = M> + 'a) -> Layer<'a, M> {
1823 Layer::new(LayerKind::Modal, child)
1824 }
1825
1826 pub fn popover(child: impl Component<Output = M> + 'a) -> Layer<'a, M> {
1828 Layer::new(LayerKind::Popover, child)
1829 }
1830
1831 #[must_use]
1833 pub fn size(mut self, width: usize, height: usize) -> Self {
1834 self.placement = Placement::Center { width, height };
1835 self
1836 }
1837
1838 #[must_use]
1839 pub fn placement(mut self, placement: Placement) -> Self {
1840 self.placement = placement;
1841 self
1842 }
1843
1844 #[must_use]
1846 pub fn title(mut self, title: impl Into<String>) -> Self {
1847 self.title = Some(title.into());
1848 self
1849 }
1850
1851 #[must_use]
1853 pub fn border(mut self, on: bool) -> Self {
1854 self.border = on;
1855 self
1856 }
1857
1858 #[must_use]
1860 pub fn backdrop(mut self, on: bool) -> Self {
1861 self.backdrop = on;
1862 self
1863 }
1864
1865 #[must_use]
1867 pub fn dismissable(mut self, on: bool) -> Self {
1868 self.dismissable = on;
1869 self
1870 }
1871
1872 pub fn kind(&self) -> LayerKind {
1873 self.kind
1874 }
1875}
1876
1877enum Request<'a, M> {
1878 Open(Layer<'a, M>),
1879 Close,
1880}
1881
1882pub struct LayerHandle<'a, M> {
1886 requests: Rc<RefCell<Vec<Request<'a, M>>>>,
1887 open: Rc<Cell<usize>>,
1888}
1889
1890impl<M> Clone for LayerHandle<'_, M> {
1891 fn clone(&self) -> Self {
1892 LayerHandle {
1893 requests: Rc::clone(&self.requests),
1894 open: Rc::clone(&self.open),
1895 }
1896 }
1897}
1898
1899impl<'a, M> LayerHandle<'a, M> {
1900 pub fn open(&self, layer: Layer<'a, M>) {
1902 self.requests.borrow_mut().push(Request::Open(layer));
1903 }
1904
1905 pub fn close(&self) {
1907 self.requests.borrow_mut().push(Request::Close);
1908 }
1909
1910 pub fn open_count(&self) -> usize {
1912 self.open.get()
1913 }
1914}
1915
1916pub struct Layers<'a, M> {
1922 base: Child<'a, M>,
1923 layers: Vec<Layer<'a, M>>,
1924 requests: Rc<RefCell<Vec<Request<'a, M>>>>,
1925 open: Rc<Cell<usize>>,
1926 backdrop: Style,
1927 border: Style,
1928 bindings: Bindings<'a, M>,
1929 mouse: bool,
1930 grab: Option<Option<usize>>,
1931 handoff: Option<Option<usize>>,
1932}
1933
1934impl<'a, M> Layers<'a, M> {
1935 pub fn new(base: impl Component<Output = M> + 'a) -> Layers<'a, M> {
1936 let mut bindings = Bindings::new("layers").focus_keys();
1937 bindings.declare("dismiss", keys("escape"), "close the dialog", false);
1938 Layers {
1939 base: Box::new(base),
1940 layers: Vec::new(),
1941 requests: Rc::new(RefCell::new(Vec::new())),
1942 open: Rc::new(Cell::new(0)),
1943 backdrop: Style::parse("dim").expect("a built-in style"),
1944 border: Style::default(),
1945 bindings,
1946 mouse: false,
1947 grab: None,
1948 handoff: None,
1949 }
1950 }
1951
1952 pub fn handle(&self) -> LayerHandle<'a, M> {
1954 LayerHandle {
1955 requests: Rc::clone(&self.requests),
1956 open: Rc::clone(&self.open),
1957 }
1958 }
1959
1960 pub fn open(&mut self, mut layer: Layer<'a, M>) {
1962 layer.took_focus = layer.child.focusable();
1963 self.layers.push(layer);
1964 self.open.set(self.layers.len());
1965 }
1966
1967 pub fn close(&mut self) -> bool {
1969 let closed = self.layers.pop().is_some();
1970 self.open.set(self.layers.len());
1971 closed
1972 }
1973
1974 #[must_use]
1978 pub fn open_on(
1979 mut self,
1980 action: &str,
1981 keys: impl IntoIterator<Item = Key>,
1982 description: &str,
1983 mut layer: impl FnMut() -> Layer<'a, M> + 'a,
1984 ) -> Self
1985 where
1986 M: 'a,
1987 {
1988 let handle = self.handle();
1989 let keys = keys.into_iter().collect();
1990 self.bindings.on(action, keys, description, false, move || {
1991 handle.open(layer());
1992 Flow::Continue
1993 });
1994 self
1995 }
1996
1997 #[must_use]
1999 pub fn backdrop_style(mut self, style: Style) -> Self {
2000 self.backdrop = style;
2001 self
2002 }
2003
2004 #[must_use]
2006 pub fn border_style(mut self, style: Style) -> Self {
2007 self.border = style;
2008 self
2009 }
2010
2011 binding_builders!();
2012
2013 pub fn depth(&self) -> usize {
2015 self.layers.len()
2016 }
2017
2018 pub fn base(&self) -> &(dyn Component<Output = M> + 'a) {
2019 &*self.base
2020 }
2021
2022 pub fn base_mut(&mut self) -> &mut (dyn Component<Output = M> + 'a) {
2023 &mut *self.base
2024 }
2025
2026 fn apply(&mut self, context: &Context<'_>) -> Flow<M> {
2028 let requests: Vec<Request<'a, M>> = self.requests.borrow_mut().drain(..).collect();
2029 let mut result = Flow::Continue;
2030 for request in requests {
2031 match request {
2032 Request::Open(mut layer) => {
2033 layer.took_focus = layer.child.focusable();
2034 self.layers.push(layer);
2035 let index = self.layers.len() - 1;
2036 let inner = self.placements(context)[index].1;
2037 let flow = self.layers[index].child.start(&inner.context(context));
2038 if let Some(flow) = self.after_layer(index, flow) {
2039 result = flow;
2040 }
2041 }
2042 Request::Close => {
2043 self.layers.pop();
2044 }
2045 }
2046 }
2047 self.open.set(self.layers.len());
2048 result
2049 }
2050
2051 pub fn placements(&self, context: &Context<'_>) -> Vec<(Rect, Rect)> {
2053 if self.layers.is_empty() {
2054 return Vec::new();
2055 }
2056 let rows = self.base.render(context).lines.len();
2057 self.layers
2058 .iter()
2059 .map(|layer| {
2060 let outer = match layer.placement {
2061 Placement::Center { width, height } => {
2062 let width = width.min(context.width);
2063 let height = height.min(context.height.max(1));
2064 let area = rows.max(height).min(context.height.max(height));
2065 Rect::new(
2066 (context.width - width) / 2,
2067 (area - height) / 2,
2068 width,
2069 height,
2070 )
2071 }
2072 Placement::At(rect) => {
2073 let x = rect.x.min(context.width);
2074 Rect::new(x, rect.y, rect.width.min(context.width - x), rect.height)
2075 }
2076 };
2077 let inner = if layer.border && outer.width >= 2 && outer.height >= 2 {
2078 Rect::new(outer.x + 1, outer.y + 1, outer.width - 2, outer.height - 2)
2079 } else {
2080 outer
2081 };
2082 (outer, inner)
2083 })
2084 .collect()
2085 }
2086
2087 fn after_layer(&mut self, index: usize, flow: Flow<M>) -> Option<Flow<M>> {
2089 let layer = &self.layers[index];
2090 let finished = layer.took_focus && !layer.child.focusable();
2091 match flow {
2092 Flow::Cancel => {
2093 self.layers.remove(index);
2094 Some(Flow::Continue)
2095 }
2096 Flow::Done(value) => {
2097 self.layers.remove(index);
2098 Some(Flow::Done(value))
2099 }
2100 Flow::Handoff(command) => {
2101 self.handoff = Some(Some(index));
2102 Some(Flow::Handoff(command))
2103 }
2104 flow if finished => {
2105 self.layers.remove(index);
2106 Some(match flow {
2107 Flow::Ignored => Flow::Continue,
2108 flow => flow,
2109 })
2110 }
2111 _ => None,
2112 }
2113 }
2114
2115 fn handle_top(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
2116 let top = self.layers.len() - 1;
2117 let places = self.placements(context);
2118 let (outer, inner) = places[top];
2119 match event {
2120 Event::Tick | Event::Resize { .. } => {
2121 let flow = self.broadcast(event, context, &places);
2122 return flow;
2123 }
2124 Event::Returned(_) => {
2125 return match self.handoff.take() {
2126 Some(None) => self.base.handle(event, context),
2127 Some(Some(index)) if index < self.layers.len() => {
2128 let inner = places[index].1;
2129 let flow = self.layers[index]
2130 .child
2131 .handle(event, &inner.context(context));
2132 self.after_layer(index, flow).unwrap_or(Flow::Continue)
2133 }
2134 _ => Flow::Continue,
2135 };
2136 }
2137 Event::Mouse(mouse) => {
2138 let (column, row) = (mouse.column as usize, mouse.row as usize);
2139 let inside = outer.contains(column, row);
2140 let held = matches!(mouse.kind, MouseKind::Drag(_) | MouseKind::Up(_))
2141 && self.grab == Some(Some(top));
2142 if let MouseKind::Down(_) = mouse.kind {
2143 self.grab = Some(Some(if inside { top } else { usize::MAX }));
2145 }
2146 if !inside && !held {
2147 if mouse.is_click() && self.layers[top].kind == LayerKind::Popover {
2148 self.layers.pop();
2149 }
2150 if let MouseKind::Up(_) = mouse.kind {
2151 self.grab = None;
2152 }
2153 return Flow::Continue;
2154 }
2155 if matches!(mouse.kind, MouseKind::Up(_)) {
2156 self.grab = None;
2157 }
2158 if !self.layers[top].child.mouse() || !(inner.contains(column, row) || held) {
2159 return Flow::Continue;
2160 }
2161 let event = Event::Mouse(inner.local(*mouse));
2162 let flow = self.layers[top]
2163 .child
2164 .handle(&event, &inner.context(context));
2165 return self.after_layer(top, flow).unwrap_or(Flow::Continue);
2166 }
2167 _ => {}
2168 }
2169 let flow = self.layers[top]
2170 .child
2171 .handle(event, &inner.context(context));
2172 let ignored = matches!(flow, Flow::Ignored);
2173 if let Some(flow) = self.after_layer(top, flow) {
2174 return flow;
2175 }
2176 if !ignored {
2177 return Flow::Continue;
2178 }
2179 let Some(action) = event.key().and_then(|key| self.bindings.action(key, false)) else {
2181 return Flow::Continue;
2182 };
2183 match action.as_str() {
2184 "dismiss" if self.layers[top].dismissable => {
2185 self.layers.pop();
2186 }
2187 FOCUS_NEXT | FOCUS_PREVIOUS => {
2188 let forward = action == FOCUS_NEXT;
2189 let child = &mut self.layers[top].child;
2190 if !child.focus_step(forward) {
2191 child.focus_enter(forward);
2192 }
2193 }
2194 _ => {}
2195 }
2196 Flow::Continue
2197 }
2198
2199 fn broadcast(
2200 &mut self,
2201 event: &Event,
2202 context: &Context<'_>,
2203 places: &[(Rect, Rect)],
2204 ) -> Flow<M> {
2205 if !matches!(event, Event::Tick) || self.base.tick().is_some() {
2206 let flow = self.base.handle(event, context);
2207 if decisive(&flow) {
2208 return flow;
2209 }
2210 }
2211 let mut index = 0;
2212 while index < self.layers.len() {
2213 if matches!(event, Event::Tick) && self.layers[index].child.tick().is_none() {
2214 index += 1;
2215 continue;
2216 }
2217 let inner = places
2218 .get(index)
2219 .map_or(Rect::default(), |(_, inner)| *inner);
2220 let flow = self.layers[index]
2221 .child
2222 .handle(event, &inner.context(context));
2223 let count = self.layers.len();
2224 if let Some(flow) = self.after_layer(index, flow)
2225 && decisive(&flow)
2226 {
2227 return flow;
2228 }
2229 if self.layers.len() == count {
2230 index += 1;
2231 }
2232 }
2233 Flow::Continue
2234 }
2235
2236 fn boxed(
2238 &self,
2239 layer: &Layer<'a, M>,
2240 view: &View,
2241 outer: Rect,
2242 inner: Rect,
2243 ) -> Vec<Vec<Segment>> {
2244 let lines = rows_of(view, inner, true)
2245 .into_iter()
2246 .map(|line| kit::pad(line, inner.width))
2247 .collect::<Vec<_>>();
2248 if !(layer.border && inner != outer) {
2249 return lines;
2250 }
2251 kit::frame(lines, inner.width, layer.title.as_deref(), &self.border)
2252 }
2253}
2254
2255impl<M> Component for Layers<'_, M> {
2256 type Output = M;
2257
2258 fn start(&mut self, context: &Context<'_>) -> Flow<M> {
2259 let flow = self.base.start(context);
2260 if decisive(&flow) {
2261 return flow;
2262 }
2263 let places = self.placements(context);
2265 let mut index = 0;
2266 while index < self.layers.len() {
2267 let inner = places
2268 .get(index)
2269 .map_or(Rect::default(), |(_, inner)| *inner);
2270 let flow = self.layers[index].child.start(&inner.context(context));
2271 let count = self.layers.len();
2272 if let Some(flow) = self.after_layer(index, flow)
2273 && decisive(&flow)
2274 {
2275 return flow;
2276 }
2277 if self.layers.len() == count {
2278 index += 1;
2279 }
2280 }
2281 self.apply(context)
2282 }
2283
2284 fn handle(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
2285 let before = self.apply(context);
2286 if decisive(&before) {
2287 return before;
2288 }
2289 let flow = if self.layers.is_empty() {
2290 self.handle_base(event, context)
2291 } else {
2292 self.handle_top(event, context)
2293 };
2294 self.open.set(self.layers.len());
2295 if decisive(&flow) {
2296 return flow;
2297 }
2298 let after = self.apply(context);
2299 if decisive(&after) {
2300 return after;
2301 }
2302 flow
2303 }
2304
2305 fn render(&self, context: &Context<'_>) -> View {
2306 let base = self.base.render(context);
2307 if self.layers.is_empty() {
2308 return base;
2309 }
2310 let places = self.placements(context);
2311 let mut lines = base.lines;
2312 let mut cursor = None;
2313 for (index, layer) in self.layers.iter().enumerate() {
2314 let (outer, inner) = places[index];
2315 let view = layer.child.render(&inner.context(context));
2316 let boxed = self.boxed(layer, &view, outer, inner);
2317 let backdrop = layer.backdrop.then_some(&self.backdrop);
2318 kit::place(&mut lines, outer.x, outer.y, &boxed, backdrop);
2319 cursor = view
2320 .cursor
2321 .filter(|(row, column)| *row < inner.height && *column < inner.width.max(1))
2322 .map(|(row, column)| (inner.y + row, inner.x + column));
2323 }
2324 View { lines, cursor }
2325 }
2326
2327 fn tick(&self) -> Option<Duration> {
2328 self.layers
2329 .iter()
2330 .filter_map(|layer| layer.child.tick())
2331 .chain(self.base.tick())
2332 .min()
2333 }
2334
2335 fn mouse(&self) -> bool {
2336 self.mouse || self.base.mouse() || self.layers.iter().any(|layer| layer.child.mouse())
2337 }
2338
2339 fn keymap(&self) -> Keymap {
2340 match self.layers.last() {
2341 Some(layer) => keymap_with(Some(&layer.child), &self.bindings.keymap),
2342 None => keymap_with(Some(&self.base), &self.bindings.keymap),
2343 }
2344 }
2345
2346 fn focusable(&self) -> bool {
2347 match self.layers.last() {
2348 Some(_) => true,
2349 None => self.base.focusable(),
2350 }
2351 }
2352
2353 fn focus_step(&mut self, forward: bool) -> bool {
2354 match self.layers.last_mut() {
2355 Some(layer) => {
2357 if !layer.child.focus_step(forward) {
2358 layer.child.focus_enter(forward);
2359 }
2360 true
2361 }
2362 None => self.base.focus_step(forward),
2363 }
2364 }
2365
2366 fn focus_enter(&mut self, forward: bool) -> bool {
2367 match self.layers.last_mut() {
2368 Some(layer) => {
2369 layer.child.focus_enter(forward);
2370 true
2371 }
2372 None => self.base.focus_enter(forward),
2373 }
2374 }
2375
2376 fn default_value(&self) -> Option<M> {
2377 self.base.default_value()
2378 }
2379
2380 fn prompt(&mut self, io: &mut dyn LineIo) -> Result<Option<M>, NotInteractive> {
2381 self.base.prompt(io)
2382 }
2383}
2384
2385impl<M> Layers<'_, M> {
2386 fn handle_base(&mut self, event: &Event, context: &Context<'_>) -> Flow<M> {
2387 if let Some(key) = event.key()
2388 && let Some(action) = self.bindings.action(key, true)
2389 && let Some(flow) = self.bindings.run(&action)
2390 {
2391 return flow;
2392 }
2393 if let Event::Mouse(mouse) = event {
2394 if !self.base.mouse() {
2395 return Flow::Ignored;
2396 }
2397 match mouse.kind {
2398 MouseKind::Down(_) => self.grab = Some(None),
2399 MouseKind::Drag(_) | MouseKind::Up(_) if matches!(self.grab, Some(Some(_))) => {
2402 if matches!(mouse.kind, MouseKind::Up(_)) {
2403 self.grab = None;
2404 }
2405 return Flow::Continue;
2406 }
2407 MouseKind::Up(_) => self.grab = None,
2408 _ => {}
2409 }
2410 }
2411 if let Event::Returned(_) = event {
2412 self.handoff = None;
2413 }
2414 let flow = self.base.handle(event, context);
2415 if let Flow::Handoff(_) = flow {
2416 self.handoff = Some(None);
2417 }
2418 if !matches!(flow, Flow::Ignored) {
2419 return flow;
2420 }
2421 let Some(action) = event.key().and_then(|key| self.bindings.action(key, false)) else {
2422 return Flow::Ignored;
2423 };
2424 match action.as_str() {
2425 FOCUS_NEXT | FOCUS_PREVIOUS | "dismiss" => Flow::Ignored,
2426 _ => self.bindings.run(&action).unwrap_or(Flow::Ignored),
2427 }
2428 }
2429}