use crate::key::{Key, KeyWithModifiers};
use crate::style::{
Border, BorderEdges, BorderStyle, Color, Dimension, Direction, Overflow, Position, Spacing,
Style, WrapMode,
};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::rc::Rc;
pub type KeyHandler = (Key, Rc<dyn Fn()>, bool);
pub type KeyWithModifiersHandler = (KeyWithModifiers, Rc<dyn Fn()>, bool);
#[derive(Clone)]
pub struct Div<T> {
pub children: Vec<T>,
pub styles: DivStyles,
pub events: EventCallbacks,
pub focusable: bool,
pub focused: bool,
}
#[derive(Clone, Default)]
pub struct DivStyles {
pub base: Option<Style>,
pub focus: Option<Style>,
pub hover: Option<Style>,
}
#[derive(Clone, Default)]
pub struct EventCallbacks {
pub on_click: Option<Rc<dyn Fn()>>,
pub on_key: Vec<KeyHandler>,
pub on_key_with_modifiers: Vec<KeyWithModifiersHandler>,
pub on_any_char: Option<Rc<dyn Fn(char)>>,
pub on_any_key: Option<Rc<dyn Fn(Key)>>,
pub on_focus: Option<Rc<dyn Fn()>>,
pub on_blur: Option<Rc<dyn Fn()>>,
}
impl<T> Div<T> {
pub fn new() -> Self {
Self {
children: Vec::new(),
styles: DivStyles::default(),
events: EventCallbacks::default(),
focusable: false,
focused: false,
}
}
pub fn children(mut self, children: Vec<T>) -> Self {
self.children = children;
self
}
pub fn child(mut self, child: T) -> Self {
self.children.push(child);
self
}
pub fn focusable(mut self, focusable: bool) -> Self {
self.focusable = focusable;
self
}
pub fn direction(mut self, direction: Direction) -> Self {
self.styles.base.get_or_insert(Style::default()).direction = Some(direction);
self
}
pub fn position(mut self, position: Position) -> Self {
self.styles.base.get_or_insert(Style::default()).position = Some(position);
self
}
pub fn overflow(mut self, overflow: Overflow) -> Self {
self.styles.base.get_or_insert(Style::default()).overflow = Some(overflow);
self
}
pub fn padding(mut self, padding: Spacing) -> Self {
self.styles.base.get_or_insert(Style::default()).padding = Some(padding);
self
}
pub fn margin(mut self, margin: Spacing) -> Self {
self.styles.base.get_or_insert(Style::default()).margin = Some(margin);
self
}
pub fn gap(mut self, gap: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).gap = Some(gap);
self
}
pub fn wrap(mut self, wrap: WrapMode) -> Self {
self.styles.base.get_or_insert(Style::default()).wrap = Some(wrap);
self
}
pub fn width(mut self, width: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).width = Some(Dimension::Fixed(width));
self
}
pub fn width_dim(mut self, width: Dimension) -> Self {
self.styles.base.get_or_insert(Style::default()).width = Some(width);
self
}
pub fn height(mut self, height: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).height = Some(Dimension::Fixed(height));
self
}
pub fn height_dim(mut self, height: Dimension) -> Self {
self.styles.base.get_or_insert(Style::default()).height = Some(height);
self
}
pub fn width_percent(mut self, percent: f32) -> Self {
self.styles.base.get_or_insert(Style::default()).width =
Some(Dimension::Percentage(percent));
self
}
pub fn height_percent(mut self, percent: f32) -> Self {
self.styles.base.get_or_insert(Style::default()).height =
Some(Dimension::Percentage(percent));
self
}
pub fn width_auto(mut self) -> Self {
self.styles.base.get_or_insert(Style::default()).width = Some(Dimension::Auto);
self
}
pub fn height_auto(mut self) -> Self {
self.styles.base.get_or_insert(Style::default()).height = Some(Dimension::Auto);
self
}
pub fn height_content(mut self) -> Self {
self.styles.base.get_or_insert(Style::default()).height = Some(Dimension::Content);
self
}
pub fn width_content(mut self) -> Self {
self.styles.base.get_or_insert(Style::default()).width = Some(Dimension::Content);
self
}
pub fn min_width(mut self, width: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).min_width = Some(width);
self
}
pub fn min_height(mut self, height: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).min_height = Some(height);
self
}
pub fn max_width(mut self, width: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).max_width = Some(width);
self
}
pub fn max_height(mut self, height: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).max_height = Some(height);
self
}
pub fn background(mut self, color: Color) -> Self {
self.styles.base.get_or_insert(Style::default()).background = Some(color);
self
}
pub fn border(mut self, border: BorderStyle) -> Self {
self.styles.base.get_or_insert(Style::default()).border = Some(Border {
enabled: true,
style: border,
color: Color::White,
edges: BorderEdges::ALL,
});
self
}
pub fn border_color(mut self, color: Color) -> Self {
self.styles.base.get_or_insert(Style::default()).border = Some(Border {
enabled: true,
style: BorderStyle::Single,
color,
edges: BorderEdges::ALL,
});
self
}
pub fn border_style(self, style: BorderStyle) -> Self {
self.border(style)
}
pub fn border_style_with_color(mut self, style: BorderStyle, color: Color) -> Self {
self.styles.base.get_or_insert(Style::default()).border = Some(Border {
enabled: true,
style,
color,
edges: BorderEdges::ALL,
});
self
}
pub fn border_edges(mut self, edges: BorderEdges) -> Self {
let style = self.styles.base.get_or_insert(Style::default());
if let Some(border) = &mut style.border {
border.edges = edges;
} else {
style.border = Some(Border {
enabled: true,
style: BorderStyle::Single,
color: Color::White,
edges,
});
}
self
}
pub fn show_scrollbar(mut self, show: bool) -> Self {
self.styles
.base
.get_or_insert(Style::default())
.show_scrollbar = Some(show);
self
}
pub fn absolute_position(mut self) -> Self {
self.styles.base.get_or_insert(Style::default()).position = Some(Position::Absolute);
self
}
pub fn absolute(mut self, x: u16, y: u16) -> Self {
let style = self.styles.base.get_or_insert(Style::default());
style.position = Some(Position::Absolute);
style.x = Some(x);
style.y = Some(y);
self
}
pub fn x(mut self, x: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).x = Some(x);
self
}
pub fn y(mut self, y: u16) -> Self {
self.styles.base.get_or_insert(Style::default()).y = Some(y);
self
}
pub fn top(mut self, top: i16) -> Self {
self.styles.base.get_or_insert(Style::default()).top = Some(top);
self
}
pub fn right(mut self, right: i16) -> Self {
self.styles.base.get_or_insert(Style::default()).right = Some(right);
self
}
pub fn bottom(mut self, bottom: i16) -> Self {
self.styles.base.get_or_insert(Style::default()).bottom = Some(bottom);
self
}
pub fn left(mut self, left: i16) -> Self {
self.styles.base.get_or_insert(Style::default()).left = Some(left);
self
}
pub fn z_index(mut self, z: i32) -> Self {
self.styles.base.get_or_insert(Style::default()).z_index = Some(z);
self
}
pub fn focus_style(mut self, style: Style) -> Self {
self.styles.focus = Some(style);
self
}
pub fn style(mut self, style: Style) -> Self {
self.styles.base = Some(style);
self
}
pub fn on_key(mut self, key: Key, handler: impl Fn() + 'static) -> Self {
self.events.on_key.push((key, Rc::new(handler), false));
self
}
pub fn on_char(mut self, ch: char, handler: impl Fn() + 'static) -> Self {
self.events
.on_key
.push((Key::Char(ch), Rc::new(handler), false));
self
}
pub fn on_key_global(mut self, key: Key, handler: impl Fn() + 'static) -> Self {
self.events.on_key.push((key, Rc::new(handler), true));
self
}
pub fn on_char_global(mut self, ch: char, handler: impl Fn() + 'static) -> Self {
self.events
.on_key
.push((Key::Char(ch), Rc::new(handler), true));
self
}
pub fn on_key_with_modifiers(
mut self,
key_with_modifiers: KeyWithModifiers,
handler: impl Fn() + 'static,
) -> Self {
self.events
.on_key_with_modifiers
.push((key_with_modifiers, Rc::new(handler), false));
self
}
pub fn on_key_with_modifiers_global(
mut self,
key_with_modifiers: KeyWithModifiers,
handler: impl Fn() + 'static,
) -> Self {
self.events
.on_key_with_modifiers
.push((key_with_modifiers, Rc::new(handler), true));
self
}
pub fn on_any_char(mut self, handler: impl Fn(char) + 'static) -> Self {
self.events.on_any_char = Some(Rc::new(handler));
self
}
pub fn on_any_key(mut self, handler: impl Fn(Key) + 'static) -> Self {
self.events.on_any_key = Some(Rc::new(handler));
self
}
pub fn on_click(mut self, handler: impl Fn() + 'static) -> Self {
self.events.on_click = Some(Rc::new(handler));
self
}
pub fn on_focus(mut self, handler: impl Fn() + 'static) -> Self {
self.events.on_focus = Some(Rc::new(handler));
self
}
pub fn on_blur(mut self, handler: impl Fn() + 'static) -> Self {
self.events.on_blur = Some(Rc::new(handler));
self
}
pub fn map<U, F>(self, f: F) -> Div<U>
where
F: FnMut(T) -> U,
{
Div {
children: self.children.into_iter().map(f).collect(),
styles: self.styles,
events: self.events,
focusable: self.focusable,
focused: self.focused,
}
}
pub fn active_style(&self) -> Option<&Style> {
if self.focused && self.styles.focus.is_some() {
self.styles.focus.as_ref()
} else {
self.styles.base.as_ref()
}
}
}
impl<T> Default for Div<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: PartialEq> PartialEq for Div<T> {
fn eq(&self, other: &Self) -> bool {
self.children == other.children
&& self.styles == other.styles
&& self.focusable == other.focusable
&& self.focused == other.focused
}
}
impl PartialEq for DivStyles {
fn eq(&self, other: &Self) -> bool {
self.base == other.base && self.focus == other.focus && self.hover == other.hover
}
}
impl Debug for DivStyles {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DivStyles")
.field("base", &self.base)
.field("focus", &self.focus)
.field("hover", &self.hover)
.finish()
}
}
impl Debug for EventCallbacks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EventCallbacks")
.field("on_click", &self.on_click.is_some())
.field("on_key_count", &self.on_key.len())
.field(
"on_key_with_modifiers_count",
&self.on_key_with_modifiers.len(),
)
.field("on_any_char", &self.on_any_char.is_some())
.field("on_any_key", &self.on_any_key.is_some())
.field("on_focus", &self.on_focus.is_some())
.field("on_blur", &self.on_blur.is_some())
.finish()
}
}
impl<T: Debug> Debug for Div<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Div")
.field("children", &self.children)
.field("styles", &self.styles)
.field("events", &self.events)
.field("focusable", &self.focusable)
.field("focused", &self.focused)
.finish()
}
}
pub struct ElementBuilder<T> {
element: T,
_phantom: PhantomData<T>,
}
impl<T> ElementBuilder<T> {
pub fn new(element: T) -> Self {
Self {
element,
_phantom: PhantomData,
}
}
pub fn build(self) -> T {
self.element
}
}