use frus_core::{Rect, Scene};
use frus_layout::{Align, FlexDirection, Style};
use crate::button::{Button, Variant};
use crate::flex::Flex;
use crate::interaction::Status;
use crate::theme::Theme;
use crate::widget::Widget;
fn arrow<Msg: Clone + 'static>(label: &str, message: Option<Msg>) -> Box<dyn Widget<Msg>> {
let mut button = Button::new(label).variant(Variant::Outlined).size(16.0);
if let Some(message) = message {
button = button.on_press(message);
}
Box::new(button)
}
pub struct CarouselView<Msg = crate::callback::Callback> {
children: Vec<Box<dyn Widget<Msg>>>,
}
impl<Msg: Clone + 'static> CarouselView<Msg> {
pub fn new(
index: usize,
count: usize,
on_change: impl Fn(usize) -> Msg + 'static,
slide: impl Widget<Msg> + 'static,
) -> Self {
let prev = arrow("‹", (index > 0).then(|| on_change(index - 1)));
let next = arrow("›", (index + 1 < count).then(|| on_change(index + 1)));
Self {
children: vec![prev, Box::new(Flex::column().flex(1.0).child(slide)), next],
}
}
}
impl<Msg: Clone> Widget<Msg> for CarouselView<Msg> {
fn style(&self) -> Style {
Style {
flex_direction: FlexDirection::Row,
align: Align::Center,
gap: 12.0,
..Default::default()
}
}
fn children(&self) -> &[Box<dyn Widget<Msg>>] {
&self.children
}
fn paint(&self, _bounds: Rect, _status: Status, _theme: &Theme, _scene: &mut Scene) {}
fn on_click(&self) -> Option<Msg> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Text;
#[derive(Clone, Debug, PartialEq)]
enum Msg {
Go(usize),
}
#[test]
fn arrows_bounded_and_emit_change() {
let first = CarouselView::new(0, 3, Msg::Go, Text::new("A"));
let c = Widget::<Msg>::children(&first);
assert_eq!(c.len(), 3);
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"));
let c = Widget::<Msg>::children(&last);
assert_eq!(c[0].on_click(), Some(Msg::Go(1)));
assert_eq!(c[2].on_click(), None);
}
}