1use frus_core::{Rect, Scene};
5use frus_layout::{Align, FlexDirection, Style};
6
7use crate::button::{Button, Variant};
8use crate::flex::Flex;
9use crate::interaction::Status;
10use crate::theme::Theme;
11use crate::widget::Widget;
12
13fn arrow<Msg: Clone + 'static>(label: &str, message: Option<Msg>) -> Box<dyn Widget<Msg>> {
15 let mut button = Button::new(label).variant(Variant::Outlined).size(16.0);
16 if let Some(message) = message {
17 button = button.on_press(message);
18 }
19 Box::new(button)
20}
21
22pub struct CarouselView<Msg = crate::callback::Callback> {
24 children: Vec<Box<dyn Widget<Msg>>>,
25}
26
27impl<Msg: Clone + 'static> CarouselView<Msg> {
28 pub fn new(
31 index: usize,
32 count: usize,
33 on_change: impl Fn(usize) -> Msg + 'static,
34 slide: impl Widget<Msg> + 'static,
35 ) -> Self {
36 let prev = arrow("‹", (index > 0).then(|| on_change(index - 1)));
37 let next = arrow("›", (index + 1 < count).then(|| on_change(index + 1)));
38 Self {
39 children: vec![prev, Box::new(Flex::column().flex(1.0).child(slide)), next],
40 }
41 }
42}
43
44impl<Msg: Clone> Widget<Msg> for CarouselView<Msg> {
45 fn style(&self) -> Style {
46 Style {
47 flex_direction: FlexDirection::Row,
48 align: Align::Center,
49 gap: 12.0,
50 ..Default::default()
51 }
52 }
53
54 fn children(&self) -> &[Box<dyn Widget<Msg>>] {
55 &self.children
56 }
57
58 fn paint(&self, _bounds: Rect, _status: Status, _theme: &Theme, _scene: &mut Scene) {}
59
60 fn on_click(&self) -> Option<Msg> {
61 None
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use crate::Text;
69
70 #[derive(Clone, Debug, PartialEq)]
71 enum Msg {
72 Go(usize),
73 }
74
75 #[test]
76 fn arrows_bounded_and_emit_change() {
77 let first = CarouselView::new(0, 3, Msg::Go, Text::new("A"));
79 let c = Widget::<Msg>::children(&first);
80 assert_eq!(c.len(), 3);
81 assert_eq!(c[0].on_click(), None); assert_eq!(c[2].on_click(), Some(Msg::Go(1))); let last = CarouselView::new(2, 3, Msg::Go, Text::new("C"));
86 let c = Widget::<Msg>::children(&last);
87 assert_eq!(c[0].on_click(), Some(Msg::Go(1)));
88 assert_eq!(c[2].on_click(), None);
89 }
90}