mod context;
mod flex;
mod id;
mod idle;
mod mapped;
#[cfg(test)]
mod mapped_rules;
mod memory;
mod view;
use std::any::{Any, type_name};
pub use context::{EventCx, MeasureCx, PaintCx};
pub use id::WidgetId;
pub use view::{NodeMut, View};
pub(crate) use context::{Effects, FocusRequest, Frame, Grounds, Interaction, LayerRecord};
pub(crate) use flex::{Axis, Flex};
pub(crate) use id::{IdMap, Key};
pub(crate) use idle::{IdleScope, IdleWatch};
pub(crate) use mapped::Reached;
pub(crate) use memory::Memory;
use mapped::Mapped;
use crate::event::Event;
use crate::geometry::{Padding, Rect, Size};
pub trait Widget<Msg>: 'static {
fn measure(&self, cx: &mut MeasureCx<'_>, available: Size) -> Size;
fn paint(&self, cx: &mut PaintCx<'_>, area: Rect);
fn paint_overlay(&self, _cx: &mut PaintCx<'_>, _anchor: Rect) {}
fn event(&self, _cx: &mut EventCx<'_, Msg>, _event: &Event) -> bool {
false
}
fn focusable(&self) -> bool {
false
}
fn children(&self) -> &[Node<Msg>] {
&[]
}
fn children_mut(&mut self) -> &mut [Node<Msg>] {
&mut []
}
}
pub(crate) trait StoredWidget<Msg>: Widget<Msg> + Any {}
impl<Msg, W: Widget<Msg>> StoredWidget<Msg> for W {}
pub trait Container<Msg>: Widget<Msg> {
fn set_children(&mut self, children: Vec<Node<Msg>>);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Length {
#[default]
Auto,
Cells(u16),
Fill(u16),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Align {
#[default]
Start,
Center,
End,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct LayoutProps {
pub width: Length,
pub height: Length,
pub padding: Padding,
pub gap: u16,
pub justify: Align,
pub align: Align,
}
pub struct Node<Msg> {
pub(crate) key: Key,
pub(crate) id: WidgetId,
pub(crate) type_name: &'static str,
pub(crate) layout: LayoutProps,
pub(crate) persistent: bool,
pub(crate) selectable: Option<bool>,
pub(crate) widget: Box<dyn StoredWidget<Msg>>,
}
impl<Msg: 'static> Node<Msg> {
pub(crate) fn new<W: Widget<Msg>>(widget: W, index: usize) -> Self {
Self {
key: Key::Index(index),
id: WidgetId::ROOT,
type_name: type_name::<W>(),
layout: LayoutProps::default(),
persistent: false,
selectable: None,
widget: Box::new(widget),
}
}
#[must_use]
pub fn id(&self) -> WidgetId {
self.id
}
#[must_use]
pub fn layout(&self) -> LayoutProps {
self.layout
}
pub(crate) fn assign_ids(&mut self, parent: WidgetId) {
self.id = parent.child(&self.key, self.type_name);
let id = self.id;
if let Some(mapped) = (&mut *self.widget as &mut dyn Any).downcast_mut::<Mapped<Msg>>() {
mapped.assign_ids(id);
return;
}
for child in self.widget.children_mut() {
child.assign_ids(id);
}
}
pub(crate) fn find(&self, id: WidgetId) -> Option<Box<dyn Reached<Msg> + '_>> {
if self.id == id {
return Some(Box::new(self));
}
if let Some(mapped) = self.mapped() {
return mapped.find(id);
}
self.widget.children().iter().find_map(|child| child.find(id))
}
pub(crate) fn count_focusable(&self) -> usize {
let own = usize::from(self.widget.focusable());
match self.mapped() {
Some(mapped) => own + mapped.count_focusable(),
None => own + self.widget.children().iter().map(Self::count_focusable).sum::<usize>(),
}
}
fn mapped(&self) -> Option<&Mapped<Msg>> {
(&*self.widget as &dyn Any).downcast_ref::<Mapped<Msg>>()
}
}