use crate::ImageHandle;
use super::{
Align, Color, ContainerDirection, ContainerWrap, CursorIcon, InteractionEvents, IntoSpacing,
Justify, NoAction, SizeMode, Spacing, Style, Ui, UiNode,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ImageFit {
Contain,
Cover,
Fill,
ScaleDown,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Container<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub direction: ContainerDirection,
pub wrap: ContainerWrap,
pub padding: Option<Spacing>,
pub margin: Option<Spacing>,
pub gap: Option<u32>,
pub customMinimumSize: Option<(u32, u32)>,
pub width: SizeMode,
pub height: SizeMode,
pub align: Align,
pub justify: Justify,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
pub children: Vec<UiNode<A>>,
}
impl<A: Clone> Container<A> {
pub fn new() -> Self {
Self {
id: None,
key: None,
class: None,
direction: ContainerDirection::Vertical,
wrap: ContainerWrap::NoWrap,
padding: None,
margin: None,
gap: None,
customMinimumSize: None,
width: SizeMode::Fill,
height: SizeMode::Fill,
align: Align::Stretch,
justify: Justify::Start,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
children: Vec::new(),
}
}
pub fn withId(id: impl Into<String>) -> Self {
Self::new().id(id)
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
pub fn class(mut self, class: impl Into<String>) -> Self {
self.class = Some(class.into());
self
}
pub fn direction(mut self, direction: ContainerDirection) -> Self {
self.direction = direction;
self
}
pub fn wrap(mut self, wrap: ContainerWrap) -> Self {
self.wrap = wrap;
self
}
pub fn padding(mut self, padding: impl IntoSpacing) -> Self {
self.padding = Some(padding.intoSpacing());
self
}
pub fn margin(mut self, margin: impl IntoSpacing) -> Self {
self.margin = Some(margin.intoSpacing());
self
}
pub fn gap(mut self, gap: u32) -> Self {
self.gap = Some(gap);
self
}
pub fn customMinimumSize(mut self, width: u32, height: u32) -> Self {
self.customMinimumSize = Some((width, height));
self
}
pub fn backgroundColor(mut self, color: Color) -> Self {
self.style.background = Some(color);
self
}
pub fn size(mut self, width: SizeMode, height: SizeMode) -> Self {
self.width = width;
self.height = height;
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, configure: impl FnOnce(&mut Style)) -> Self {
configure(&mut self.style);
self
}
pub fn onClick(mut self, action: A) -> Self {
self.interactions.click = Some(action);
self
}
pub fn onHover(mut self, action: A) -> Self {
self.interactions.hover = Some(action);
self
}
pub fn onUnhover(mut self, action: A) -> Self {
self.interactions.unhover = Some(action);
self
}
pub fn onFocus(mut self, action: A) -> Self {
self.interactions.focus = Some(action);
self
}
pub fn onBlur(mut self, action: A) -> Self {
self.interactions.blur = Some(action);
self
}
pub fn onPointerDown(mut self, action: A) -> Self {
self.interactions.pointerDown = Some(action);
self
}
pub fn onPointerUp(mut self, action: A) -> Self {
self.interactions.pointerUp = Some(action);
self
}
pub fn cursor(mut self, cursor: CursorIcon) -> Self {
self.cursor = Some(cursor);
self
}
pub fn children(mut self, build: impl FnOnce(&mut Ui<A>)) -> Self {
let mut ui = Ui::new();
build(&mut ui);
self.children = ui.nodes;
self
}
pub fn empty(self) -> Self {
self
}
}
impl<A: Clone> Default for Container<A> {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Text<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub value: String,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
}
impl<A> Text<A> {
pub fn new(value: impl Into<String>) -> Self {
Self {
id: None,
key: None,
class: None,
value: value.into(),
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
}
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
pub fn class(mut self, class: impl Into<String>) -> Self {
self.class = Some(class.into());
self
}
pub fn color(mut self, color: Color) -> Self {
self.style.color = Some(color);
self
}
pub fn size(mut self, size: u32) -> Self {
self.style.fontSize = Some(size);
self
}
pub fn style(mut self, configure: impl FnOnce(&mut Style)) -> Self {
configure(&mut self.style);
self
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Image<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub image: ImageHandle,
pub fit: ImageFit,
pub customMinimumSize: Option<(u32, u32)>,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
}
impl<A> Image<A> {
pub fn new(image: ImageHandle) -> Self {
Self {
id: None,
key: None,
class: None,
image,
fit: ImageFit::Contain,
customMinimumSize: None,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Button<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub text: String,
pub customMinimumSize: Option<(u32, u32)>,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
}
impl<A> Button<A> {
pub fn new(text: impl Into<String>) -> Self {
Self {
id: None,
key: None,
class: None,
text: text.into(),
customMinimumSize: None,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
}
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
pub fn class(mut self, class: impl Into<String>) -> Self {
self.class = Some(class.into());
self
}
}
#[derive(Clone)]
pub struct TextInput<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub value: String,
pub placeholder: Option<String>,
pub customMinimumSize: Option<(u32, u32)>,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
pub onChange: Option<std::sync::Arc<dyn Fn(String) -> A>>,
pub onSubmit: Option<std::sync::Arc<dyn Fn(String) -> A>>,
}
impl<A> TextInput<A> {
pub fn new(value: impl Into<String>) -> Self {
Self {
id: None,
key: None,
class: None,
value: value.into(),
placeholder: None,
customMinimumSize: None,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
onChange: None,
onSubmit: None,
}
}
}
impl<A> std::fmt::Debug for TextInput<A> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("TextInput")
.field("id", &self.id)
.field("key", &self.key)
.field("class", &self.class)
.field("value", &self.value)
.field("placeholder", &self.placeholder)
.field("customMinimumSize", &self.customMinimumSize)
.field("style", &self.style)
.field("interactions", &self.interactions.hasLocalInput())
.field("cursor", &self.cursor)
.finish()
}
}
impl<A> PartialEq for TextInput<A> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.key == other.key
&& self.class == other.class
&& self.value == other.value
&& self.placeholder == other.placeholder
&& self.customMinimumSize == other.customMinimumSize
&& self.style == other.style
&& self.cursor == other.cursor
}
}
#[derive(Clone)]
pub struct Checkbox<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub checked: bool,
pub text: Option<String>,
pub customMinimumSize: Option<(u32, u32)>,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
pub onToggle: Option<std::sync::Arc<dyn Fn(bool) -> A>>,
}
impl<A> Checkbox<A> {
pub fn new(checked: bool) -> Self {
Self {
id: None,
key: None,
class: None,
checked,
text: None,
customMinimumSize: None,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
onToggle: None,
}
}
}
impl<A> std::fmt::Debug for Checkbox<A> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Checkbox")
.field("id", &self.id)
.field("key", &self.key)
.field("class", &self.class)
.field("checked", &self.checked)
.field("text", &self.text)
.field("customMinimumSize", &self.customMinimumSize)
.field("style", &self.style)
.field("interactions", &self.interactions.hasLocalInput())
.field("cursor", &self.cursor)
.finish()
}
}
impl<A> PartialEq for Checkbox<A> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.key == other.key
&& self.class == other.class
&& self.checked == other.checked
&& self.text == other.text
&& self.customMinimumSize == other.customMinimumSize
&& self.style == other.style
&& self.cursor == other.cursor
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Scroll<A = NoAction> {
pub id: Option<String>,
pub key: Option<String>,
pub class: Option<String>,
pub customMinimumSize: Option<(u32, u32)>,
pub style: Style,
pub interactions: InteractionEvents<A>,
pub cursor: Option<CursorIcon>,
pub children: Vec<UiNode<A>>,
}
impl<A> Scroll<A> {
pub fn new() -> Self {
Self {
id: None,
key: None,
class: None,
customMinimumSize: None,
style: Style::default(),
interactions: InteractionEvents::default(),
cursor: None,
children: Vec::new(),
}
}
}