use crate::{
element::ElementType,
hooks::Hooks,
layout_style::LayoutStyle,
props::{AnyProps, Props},
render::{ComponentDrawer, ComponentUpdater},
};
use std::{any::Any, task::Context};
mod component_helper;
pub(crate) use component_helper::{ComponentHelper, ComponentHelperExt};
mod instantiated_component;
pub use instantiated_component::{Components, InstantiatedComponent};
use ratatui::layout::{Direction, Layout};
pub trait Component: Any + Unpin {
type Props<'a>: Props
where
Self: 'a;
fn new(props: &Self::Props<'_>) -> Self;
fn update(
&mut self,
_props: &mut Self::Props<'_>,
_hooks: Hooks,
_updater: &mut ComponentUpdater,
) {
}
fn draw(&mut self, _drawer: &mut ComponentDrawer<'_, '_>) {}
fn calc_children_areas(
&self,
children: &Components,
layout_style: &LayoutStyle,
drawer: &mut ComponentDrawer<'_, '_>,
) -> Vec<ratatui::prelude::Rect> {
let layout = layout_style
.get_layout()
.constraints(children.get_constraints(layout_style.flex_direction));
let areas = layout.split(drawer.area);
let mut children_areas: Vec<ratatui::prelude::Rect> = vec![];
let rev_direction = match layout_style.flex_direction {
Direction::Horizontal => Direction::Vertical,
Direction::Vertical => Direction::Horizontal,
};
for (area, constraint) in areas.iter().zip(children.get_constraints(rev_direction)) {
let area = Layout::new(rev_direction, [constraint]).split(*area)[0];
children_areas.push(area);
}
children_areas
}
fn poll_change(&mut self, _cx: &mut Context<'_>) -> std::task::Poll<()> {
std::task::Poll::Pending
}
}
pub trait AnyComponent: Any + Unpin {
fn update(&mut self, props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater);
fn draw(&mut self, drawer: &mut ComponentDrawer);
fn calc_children_areas(
&self,
children: &Components,
layout_style: &LayoutStyle,
drawer: &mut ComponentDrawer,
) -> Vec<ratatui::prelude::Rect>;
fn poll_change(&mut self, cx: &mut Context) -> std::task::Poll<()>;
}
impl<C> ElementType for C
where
C: Component,
{
type Props<'a> = C::Props<'a>;
}
impl<C> AnyComponent for C
where
C: Any + Component,
{
fn update(&mut self, mut props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater) {
Component::update(
self,
unsafe { props.downcast_mut_unchecked(ComponentHelper::<C>::props_type_id()) },
hooks,
updater,
);
}
fn draw(&mut self, drawer: &mut ComponentDrawer) {
Component::draw(self, drawer);
}
fn calc_children_areas(
&self,
children: &Components,
layout_style: &LayoutStyle,
drawer: &mut ComponentDrawer,
) -> Vec<ratatui::prelude::Rect> {
Component::calc_children_areas(self, children, layout_style, drawer)
}
fn poll_change(&mut self, cx: &mut Context) -> std::task::Poll<()> {
Component::poll_change(self, cx)
}
}