mod layout;
mod node;
mod reconcile;
pub use layout::measure_button;
pub use node::ButtonNode;
pub use reconcile::reconcile_button;
use std::sync::Arc;
use crate::callback::{Callback, KeyHandler};
use crate::core::element::{Element, ElementKind};
use crate::core::event::MouseEvent;
use crate::input::KeyBindings;
use crate::style::{Align, BorderStyle, LayoutConstraints, Length, Padding, Style, StyleSlot};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum ButtonVariant {
#[default]
Bracket,
Filled,
Outlined,
}
#[derive(Clone)]
pub struct Button {
pub label: Arc<str>,
pub icon: Option<Arc<str>>,
pub icon_style: Style,
pub icon_gap: u16,
pub shortcut: Option<Arc<str>>,
pub shortcut_style: Style,
pub shortcut_gap: u16,
pub style: Style,
pub hover_style: StyleSlot,
pub focus_style: StyleSlot,
pub align: Align,
pub width: Length,
pub height: Length,
pub variant: ButtonVariant,
pub border_style: BorderStyle,
pub hover_border_style: Option<BorderStyle>,
pub focus_border_style: Option<BorderStyle>,
pub padding: Padding,
pub disabled: bool,
pub disabled_style: Style,
pub on_click: Option<Callback<MouseEvent>>,
pub on_key: Option<KeyHandler>,
pub focusable: bool,
}
impl Button {
pub fn new(label: impl Into<Arc<str>>) -> Self {
Self {
label: label.into(),
icon: None,
icon_style: Style::default(),
icon_gap: 1,
shortcut: None,
shortcut_style: Style::default(),
shortcut_gap: 1,
style: Style::default(),
hover_style: StyleSlot::Inherit,
focus_style: StyleSlot::Inherit,
align: Align::Center,
width: Length::Auto,
height: Length::Auto,
variant: ButtonVariant::Bracket,
border_style: BorderStyle::Plain,
hover_border_style: None,
focus_border_style: None,
padding: Padding {
left: 1,
right: 1,
top: 0,
bottom: 0,
},
disabled: false,
disabled_style: Style::default(),
on_click: None,
on_key: None,
focusable: true,
}
}
pub fn filled(label: impl Into<Arc<str>>) -> Self {
let mut button = Self::new(label);
button.variant = ButtonVariant::Filled;
button
}
pub fn outlined(label: impl Into<Arc<str>>) -> Self {
let mut button = Self::new(label);
button.variant = ButtonVariant::Outlined;
button.border_style = BorderStyle::Plain;
button.hover_border_style = None;
button.focus_border_style = None;
button
}
pub fn style(mut self, style: Style) -> Self {
self.style = style;
self
}
pub fn icon(mut self, icon: impl Into<Arc<str>>) -> Self {
self.icon = Some(icon.into());
self
}
pub fn icon_style(mut self, style: Style) -> Self {
self.icon_style = style;
self
}
pub fn icon_gap(mut self, gap: u16) -> Self {
self.icon_gap = gap;
self
}
pub fn shortcut(mut self, shortcut: impl Into<Arc<str>>) -> Self {
self.shortcut = Some(shortcut.into());
self
}
pub fn shortcut_bindings(mut self, bindings: KeyBindings) -> Self {
self.shortcut = Some(bindings.to_string().into());
self
}
pub fn shortcut_style(mut self, style: Style) -> Self {
self.shortcut_style = style;
self
}
pub fn shortcut_gap(mut self, gap: u16) -> Self {
self.shortcut_gap = gap;
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 focus_style(mut self, style: Style) -> Self {
self.focus_style = StyleSlot::Replace(style);
self
}
pub fn extend_focus_style(mut self, style: Style) -> Self {
self.focus_style = StyleSlot::Extend(style);
self
}
pub fn inherit_focus_style(mut self) -> Self {
self.focus_style = StyleSlot::Inherit;
self
}
pub fn focus_style_slot(mut self, slot: StyleSlot) -> Self {
self.focus_style = slot;
self
}
pub fn align(mut self, align: Align) -> Self {
self.align = align;
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 variant(mut self, variant: ButtonVariant) -> Self {
self.variant = variant;
self
}
pub fn border_style(mut self, border_style: BorderStyle) -> Self {
self.border_style = border_style;
self
}
pub fn hover_border_style(mut self, border_style: Option<BorderStyle>) -> Self {
self.hover_border_style = border_style;
self
}
pub fn focus_border_style(mut self, border_style: Option<BorderStyle>) -> Self {
self.focus_border_style = border_style;
self
}
pub fn padding(mut self, padding: impl Into<Padding>) -> Self {
self.padding = padding.into();
self
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn disabled_style(mut self, style: Style) -> Self {
self.disabled_style = style;
self
}
pub fn full_width(mut self, full_width: bool) -> Self {
self.width = if full_width {
Length::Flex(1)
} else {
Length::Auto
};
self
}
pub fn on_click(mut self, cb: Callback<MouseEvent>) -> Self {
self.on_click = Some(cb);
self
}
pub fn on_key(mut self, handler: KeyHandler) -> Self {
self.on_key = Some(handler);
self
}
pub fn focusable(mut self, focusable: bool) -> Self {
self.focusable = focusable;
self
}
}
impl From<Button> for Element {
fn from(value: Button) -> Self {
let (min_w, min_h) = measure_button(&value);
Element::new(ElementKind::Button(Box::new(value))).with_layout(
LayoutConstraints::default()
.min_width(Length::Px(min_w))
.min_height(Length::Px(min_h)),
)
}
}
impl crate::layout::hash::LayoutHash for Button {
fn layout_hash(
&self,
hasher: &mut impl std::hash::Hasher,
_recurse: &dyn Fn(&Element) -> Option<u64>,
) -> Option<()> {
use std::hash::Hash;
self.width.hash(hasher);
self.height.hash(hasher);
self.variant.hash(hasher);
self.padding.hash(hasher);
self.label.hash(hasher);
self.icon.hash(hasher);
self.icon_gap.hash(hasher);
self.shortcut.hash(hasher);
self.shortcut_gap.hash(hasher);
Some(())
}
}