use std::any::Any;
use std::fmt::{self, Debug};
use std::ops::ControlFlow;
use anathema_geometry::{Pos, Region, Size};
use anathema_state::StateId;
use anathema_store::slab::SecondaryMap;
use anathema_store::tree::{Tree, TreeView};
use anathema_templates::ComponentBlueprintId;
use anathema_value_resolver::AttributeStorage;
pub use self::factory::Factory;
pub use self::style::{Attributes, Style};
use crate::WidgetContainer;
use crate::error::Result;
use crate::layout::{Constraints, LayoutCtx, PositionCtx, PositionFilter};
use crate::paint::{PaintCtx, PaintFilter, SizePos};
pub use crate::tree::{Filter, ForEach, LayoutForEach};
mod factory;
mod style;
pub type WidgetTreeView<'a, 'bp> = TreeView<'a, WidgetContainer<'bp>>;
pub type WidgetTree<'a> = Tree<WidgetContainer<'a>>;
pub type LayoutChildren<'a, 'bp> = LayoutForEach<'a, 'bp>;
pub type PositionChildren<'a, 'bp> = ForEach<'a, 'bp, PositionFilter>;
pub type PaintChildren<'a, 'bp> = ForEach<'a, 'bp, PaintFilter>;
pub type WidgetId = anathema_store::slab::Key;
#[derive(Debug)]
pub struct CompEntry {
pub state_id: StateId,
pub widget_id: WidgetId,
pub accept_ticks: bool,
component_id: ComponentBlueprintId,
}
pub struct Components {
inner: Vec<CompEntry>,
}
impl Components {
pub fn new() -> Self {
Self { inner: vec![] }
}
pub fn push(
&mut self,
component_id: ComponentBlueprintId,
widget_id: WidgetId,
state_id: StateId,
accept_ticks: bool,
) {
let entry = CompEntry {
component_id,
widget_id,
state_id,
accept_ticks,
};
self.inner.push(entry)
}
pub fn try_remove(&mut self, widget_id: WidgetId) {
self.inner.retain(|entry| entry.widget_id != widget_id);
}
pub fn get(&mut self, index: usize) -> Option<(WidgetId, StateId)> {
self.inner.get(index).map(|e| (e.widget_id, e.state_id))
}
pub fn get_by_component_id(&mut self, id: ComponentBlueprintId) -> Option<&CompEntry> {
self.inner.iter().find(|e| e.component_id == id)
}
pub fn get_by_widget_id(&mut self, id: WidgetId) -> Option<(WidgetId, StateId)> {
self.inner
.iter()
.find(|entry| entry.widget_id == id)
.map(|e| (e.widget_id, e.state_id))
}
pub fn get_ticking(&self, index: usize) -> Option<(WidgetId, StateId)> {
self.inner
.get(index)
.and_then(|e| e.accept_ticks.then_some((e.widget_id, e.state_id)))
}
pub fn iter(&self) -> impl Iterator<Item = &CompEntry> {
self.inner.iter()
}
pub fn len(&self) -> usize {
self.inner.len()
}
}
#[derive(Debug)]
pub struct FloatingWidgets(SecondaryMap<WidgetId, WidgetId>);
impl FloatingWidgets {
pub fn empty() -> Self {
Self(SecondaryMap::empty())
}
pub fn try_remove(&mut self, key: WidgetId) {
self.0.try_remove(key);
}
pub(crate) fn insert(&mut self, widget_id: WidgetId) {
self.0.insert(widget_id, widget_id);
}
pub fn iter(&self) -> impl Iterator<Item = &WidgetId> {
self.0.iter()
}
}
#[derive(Debug, Copy, Clone)]
pub struct Parent(pub WidgetId);
impl From<Parent> for WidgetId {
fn from(value: Parent) -> Self {
value.0
}
}
impl From<WidgetId> for Parent {
fn from(value: WidgetId) -> Self {
Self(value)
}
}
pub struct ComponentParents(SecondaryMap<ComponentBlueprintId, Parent>);
impl ComponentParents {
pub fn empty() -> Self {
Self(SecondaryMap::empty())
}
pub fn try_remove(&mut self, key: ComponentBlueprintId) {
self.0.try_remove(key);
}
pub fn get_parent(&self, child: ComponentBlueprintId) -> Option<Parent> {
self.0.get(child).copied()
}
}
pub trait AnyWidget {
fn to_any_ref(&self) -> &dyn Any;
fn to_any_mut(&mut self) -> &mut dyn Any;
fn any_layout<'bp>(
&mut self,
children: LayoutForEach<'_, 'bp>,
constraints: Constraints,
id: WidgetId,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size>;
fn any_position<'bp>(
&mut self,
children: ForEach<'_, 'bp, PositionFilter>,
id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
ctx: PositionCtx,
);
fn any_paint<'bp>(
&mut self,
children: ForEach<'_, 'bp, PaintFilter>,
id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
ctx: PaintCtx<'_, SizePos>,
);
fn any_floats(&self) -> bool;
fn any_inner_bounds(&self, pos: Pos, size: Size) -> Region;
fn any_needs_reflow(&mut self) -> bool;
}
impl<T: 'static + Widget> AnyWidget for T {
fn to_any_ref(&self) -> &dyn Any {
self
}
fn to_any_mut(&mut self) -> &mut dyn Any {
self
}
fn any_layout<'bp>(
&mut self,
children: LayoutForEach<'_, 'bp>,
constraints: Constraints,
id: WidgetId,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size> {
self.layout(children, constraints, id, ctx)
}
fn any_position<'bp>(
&mut self,
children: ForEach<'_, 'bp, PositionFilter>,
id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
ctx: PositionCtx,
) {
self.position(children, id, attribute_storage, ctx)
}
fn any_paint<'bp>(
&mut self,
children: ForEach<'_, 'bp, PaintFilter>,
id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
ctx: PaintCtx<'_, SizePos>,
) {
self.paint(children, id, attribute_storage, ctx)
}
fn any_inner_bounds(&self, pos: Pos, size: Size) -> Region {
self.inner_bounds(pos, size)
}
fn any_floats(&self) -> bool {
self.floats()
}
fn any_needs_reflow(&mut self) -> bool {
self.needs_reflow()
}
}
impl Debug for dyn AnyWidget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<dyn AnyWidget>")
}
}
pub trait Widget {
fn layout<'bp>(
&mut self,
children: LayoutForEach<'_, 'bp>,
constraints: Constraints,
id: WidgetId,
ctx: &mut LayoutCtx<'_, 'bp>,
) -> Result<Size>;
fn paint<'bp>(
&mut self,
mut children: ForEach<'_, 'bp, PaintFilter>,
_id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
mut ctx: PaintCtx<'_, SizePos>,
) {
_ = children.each(|child, children| {
let ctx = ctx.to_unsized();
child.paint(children, ctx, attribute_storage);
ControlFlow::Continue(())
});
}
fn position<'bp>(
&mut self,
children: ForEach<'_, 'bp, PositionFilter>,
id: WidgetId,
attribute_storage: &AttributeStorage<'bp>,
ctx: PositionCtx,
);
fn floats(&self) -> bool {
false
}
fn inner_bounds(&self, pos: Pos, size: Size) -> Region {
Region::from((pos, size))
}
fn needs_reflow(&mut self) -> bool {
false
}
}
impl Debug for dyn Widget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<dyn Widget>")
}
}