pub mod button;
pub mod card;
pub mod checkbox;
pub mod container;
pub mod divider;
pub mod draggable;
pub mod flex;
pub mod icon;
pub mod image;
pub mod input;
pub mod layout;
pub mod list_view;
pub mod progress;
pub mod radio;
pub mod scroll_bar;
pub mod scroll_view;
pub mod slider;
pub mod switch;
pub mod tab;
pub mod text;
pub mod tooltip;
pub mod virtual_list;
pub use button::{Button, ButtonSize, ButtonVariant};
pub use card::{Card, CardVariant};
pub use checkbox::Checkbox;
pub use container::Container;
pub use divider::Divider;
pub use draggable::Draggable;
pub use flex::{Column, Row};
pub use icon::{Icon, IconButton, IconButtonVariant, IconName};
pub use image::Image;
pub use input::{Input, InputSize, InputStatus};
pub use layout::LayoutAttr;
pub use list_view::ListView;
pub use progress::Progress;
pub use radio::Radio;
pub use scroll_bar::{ScrollBar, ScrollOrientation};
pub use scroll_view::ScrollView;
pub use slider::Slider;
pub use switch::Switch;
pub use tab::Tab;
pub use text::Text;
pub use tooltip::Tooltip;
pub use virtual_list::VirtualList;
use crate::view::node::ViewNode;
use std::any::Any;
use std::cell::{Ref, RefCell, RefMut};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::rc::Rc;
pub type StateMap = HashMap<String, Box<dyn Any>>;
pub trait Widget {
fn key(&self) -> Option<&str> {
None
}
fn build(&self, ctx: &mut BuildContext) -> ViewNode;
fn build_node(&self) -> ViewNode {
self.build(&mut BuildContext::empty())
}
}
pub struct BuildContext {
path: Vec<String>,
hook_index: usize,
state: Rc<RefCell<StateMap>>,
}
impl BuildContext {
pub fn new(state: Rc<RefCell<StateMap>>) -> Self {
Self {
path: Vec::new(),
hook_index: 0,
state,
}
}
pub fn empty() -> Self {
Self {
path: Vec::new(),
hook_index: 0,
state: Rc::new(RefCell::new(StateMap::new())),
}
}
pub fn child(&mut self, index: usize, widget: &dyn Widget) -> ViewNode {
let saved_hook = self.hook_index;
self.hook_index = 0;
let segment = widget
.key()
.map(|k| k.to_string())
.unwrap_or_else(|| index.to_string());
self.path.push(segment);
let node = widget.build(self);
self.path.pop();
self.hook_index = saved_hook;
node
}
pub fn use_state<T: 'static>(&mut self, init: impl FnOnce() -> T) -> Stateful<T> {
let key = format!("{}#{}", self.path.join("/"), self.hook_index);
self.hook_index += 1;
if !self.state.borrow().contains_key(&key) {
self.state
.borrow_mut()
.insert(key.clone(), Box::new(init()));
}
Stateful {
key,
state: Rc::clone(&self.state),
_marker: PhantomData,
}
}
}
pub struct Stateful<T> {
key: String,
state: Rc<RefCell<StateMap>>,
_marker: PhantomData<T>,
}
impl<T: 'static> Stateful<T> {
pub fn get(&self) -> Ref<'_, T> {
Ref::map(self.state.borrow(), |m| {
m.get(&self.key)
.expect("Stateful state missing")
.downcast_ref::<T>()
.expect("Stateful type mismatch")
})
}
pub fn get_mut(&self) -> RefMut<'_, T> {
RefMut::map(self.state.borrow_mut(), |m| {
m.get_mut(&self.key)
.expect("Stateful state missing")
.downcast_mut::<T>()
.expect("Stateful type mismatch")
})
}
pub fn set(&self, value: T) {
*self.get_mut() = value;
crate::state::request_rebuild();
}
pub fn update<F: FnOnce(&mut T)>(&self, f: F) {
f(&mut *self.get_mut());
crate::state::request_rebuild();
}
}
impl<T: 'static> Clone for Stateful<T> {
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
state: Rc::clone(&self.state),
_marker: PhantomData,
}
}
}