use std::sync::Arc;
use crate::callback::Callback;
use crate::core::element::Element;
use crate::core::event::MouseEvent;
use crate::style::{Align, Justify, Length, Padding, Style, StyleSlot};
use crate::widgets::{Button, HStack, Text};
#[derive(Clone)]
pub struct Breadcrumb {
segments: Vec<Arc<str>>,
separator: Arc<str>,
gap: u16,
width: Length,
height: Length,
padding: Padding,
align: Align,
justify: Justify,
style: Style,
active: Option<usize>,
on_select: Option<Callback<usize>>,
active_style: Style,
inactive_style: Style,
hover_style: StyleSlot,
separator_style: Style,
}
impl Default for Breadcrumb {
fn default() -> Self {
Self {
segments: Vec::new(),
separator: "/".into(),
gap: 1,
width: Length::Flex(1),
height: Length::Auto,
padding: Padding::default(),
align: Align::Center,
justify: Justify::Start,
style: Style::default(),
active: None,
on_select: None,
active_style: Style::default(),
inactive_style: Style::default(),
hover_style: StyleSlot::Inherit,
separator_style: Style::default(),
}
}
}
impl Breadcrumb {
pub fn new() -> Self {
Self::default()
}
pub fn segments(mut self, segments: impl IntoIterator<Item = impl Into<Arc<str>>>) -> Self {
self.segments = segments.into_iter().map(Into::into).collect();
self
}
pub fn separator(mut self, separator: impl Into<Arc<str>>) -> Self {
self.separator = separator.into();
self
}
pub fn gap(mut self, gap: u16) -> Self {
self.gap = gap;
self
}
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
self.padding = padding.into();
self
}
pub fn align(mut self, align: Align) -> Self {
self.align = align;
self
}
pub fn justify(mut self, justify: Justify) -> Self {
self.justify = justify;
self
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn active(mut self, active: Option<usize>) -> Self {
self.active = active;
self
}
pub fn on_select(mut self, cb: Callback<usize>) -> Self {
self.on_select = Some(cb);
self
}
pub fn active_style(mut self, style: Style) -> Self {
self.active_style = style;
self
}
pub fn inactive_style(mut self, style: Style) -> Self {
self.inactive_style = style;
self
}
pub fn hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Replace(style);
self
}
pub fn extend_hover_style(mut self, style: Style) -> Self {
self.hover_style = StyleSlot::Extend(style);
self
}
pub fn inherit_hover_style(mut self) -> Self {
self.hover_style = StyleSlot::Inherit;
self
}
pub fn hover_style_slot(mut self, slot: StyleSlot) -> Self {
self.hover_style = slot;
self
}
pub fn separator_style(mut self, style: Style) -> Self {
self.separator_style = style;
self
}
}
impl From<Breadcrumb> for Element {
fn from(breadcrumb: Breadcrumb) -> Self {
let mut stack = HStack::new()
.gap(breadcrumb.gap)
.width(breadcrumb.width)
.height(breadcrumb.height)
.padding(breadcrumb.padding)
.align(breadcrumb.align)
.justify(breadcrumb.justify)
.style(breadcrumb.style);
let active_index = breadcrumb
.active
.unwrap_or_else(|| breadcrumb.segments.len().saturating_sub(1));
for (i, segment) in breadcrumb.segments.into_iter().enumerate() {
if i > 0 {
stack = stack.child(
Text::new(breadcrumb.separator.clone()).style(breadcrumb.separator_style),
);
}
let is_active = i == active_index;
let style = if is_active {
breadcrumb.active_style
} else {
breadcrumb.inactive_style
};
if let Some(cb) = breadcrumb.on_select.clone() {
let mut button = Button::filled(segment)
.padding(0)
.style(style)
.hover_style_slot(breadcrumb.hover_style)
.width(Length::Auto);
button = button.on_click(Callback::new(move |_: MouseEvent| cb.emit(i)));
stack = stack.child(button);
} else {
stack = stack.child(Text::new(segment).style(style));
}
}
stack.into()
}
}