use crate::component::{propagate_event, Component as ComponentTrait, Container as ContainerTrait};
use crate::context::RenderContext;
use crate::event::{Event, EventHandler};
use crate::layout::{FlexDirection, FlexLayout, Rect, Size};
use crate::render::Renderer;
use anyhow::Result;
pub struct Container {
children: Vec<Box<dyn ComponentTrait>>,
layout: FlexLayout,
sizes: Vec<Size>,
dirty: bool,
}
impl Container {
pub fn new(direction: FlexDirection) -> Self {
Container {
children: Vec::new(),
layout: FlexLayout::new(direction),
sizes: Vec::new(),
dirty: true,
}
}
pub fn row() -> Self {
Self::new(FlexDirection::Row)
}
pub fn column() -> Self {
Self::new(FlexDirection::Column)
}
pub fn with_gap(mut self, gap: u16) -> Self {
self.layout = self.layout.gap(gap);
self.dirty = true;
self
}
pub fn with_padding(mut self, padding: u16) -> Self {
self.layout = self.layout.padding(padding);
self.dirty = true;
self
}
pub fn add_child_with_size(&mut self, child: Box<dyn ComponentTrait>, size: Size) {
self.children.push(child);
self.sizes.push(size);
self.dirty = true;
}
pub fn add_fixed(&mut self, child: Box<dyn ComponentTrait>, size: u16) {
self.add_child_with_size(child, Size::Fixed(size));
}
pub fn add_flex(&mut self, child: Box<dyn ComponentTrait>, flex: u16) {
self.add_child_with_size(child, Size::Flex(flex));
}
}
impl EventHandler for Container {
fn handle_event(&mut self, event: &Event) -> bool {
propagate_event(&mut self.children, event)
}
}
impl ComponentTrait for Container {
fn render(&mut self, renderer: &mut Renderer, bounds: Rect, ctx: &RenderContext) -> Result<()> {
let child_bounds = self.layout.layout(bounds, &self.sizes);
for (child, rect) in self.children.iter_mut().zip(child_bounds.iter()) {
child.render(renderer, *rect, ctx)?;
}
self.dirty = false;
Ok(())
}
fn mark_dirty(&mut self) {
self.dirty = true;
for child in &mut self.children {
child.mark_dirty();
}
}
fn is_dirty(&self) -> bool {
self.dirty || self.children.iter().any(|c| c.is_dirty())
}
fn name(&self) -> &str {
"Container"
}
}
impl ContainerTrait for Container {
fn children_mut(&mut self) -> &mut [Box<dyn ComponentTrait>] {
&mut self.children
}
fn children(&self) -> &[Box<dyn ComponentTrait>] {
&self.children
}
fn add_child(&mut self, child: Box<dyn ComponentTrait>) {
self.add_flex(child, 1);
}
fn remove_child(&mut self, index: usize) -> Option<Box<dyn ComponentTrait>> {
if index < self.children.len() {
self.sizes.remove(index);
self.dirty = true;
Some(self.children.remove(index))
} else {
None
}
}
}