use embedded_graphics::{geometry::Size, prelude::PixelColor};
use crate::{
Context, Style,
common::{Gap, NodeIndex},
element::{BuildError, ElementBuilder, ParentElement},
layout::Layout,
style::{FlexDirection, StyledElement},
tree::{Node, NodeKind},
};
#[cfg(feature = "flexbox")]
use crate::style::{AlignItems, JustifyContent};
#[derive(Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DivStyle {
pub(crate) gap: Size,
pub(crate) direction: FlexDirection,
#[cfg(feature = "flexbox")]
pub(crate) justify_content: JustifyContent,
#[cfg(feature = "flexbox")]
pub(crate) align_items: AlignItems,
}
pub struct DivBuilder<'cx, 'frame, C, CE>
where
C: PixelColor,
{
style: Style<DivStyle, C>,
cx: &'cx Context<'frame, C, CE>,
first_child: Option<NodeIndex>,
last_child: Option<NodeIndex>,
error: Option<BuildError>,
}
impl<'cx, 'frame, C, CE> DivBuilder<'cx, 'frame, C, CE>
where
C: PixelColor,
{
pub fn new(cx: &'cx Context<'frame, C, CE>) -> Self {
Self { style: Style::default(), cx, first_child: None, last_child: None, error: None }
}
}
impl<'frame, C, CE> Context<'frame, C, CE>
where
C: PixelColor,
{
pub fn div(&self) -> DivBuilder<'_, 'frame, C, CE> {
DivBuilder::new(self)
}
pub fn row(&self) -> DivBuilder<'_, 'frame, C, CE> {
DivBuilder::new(self).flex_direction(FlexDirection::Row)
}
pub fn column(&self) -> DivBuilder<'_, 'frame, C, CE> {
DivBuilder::new(self).flex_direction(FlexDirection::Column)
}
}
impl<'frame, C, CE> StyledElement for DivBuilder<'_, 'frame, C, CE>
where
C: PixelColor,
{
type Color = C;
type Specific = DivStyle;
fn style(&self) -> &Style<Self::Specific, Self::Color> {
&self.style
}
fn style_mut(&mut self) -> &mut Style<Self::Specific, Self::Color> {
&mut self.style
}
}
impl<'frame, C, CE> ParentElement for DivBuilder<'_, 'frame, C, CE>
where
C: PixelColor,
{
fn extend<E: ElementBuilder>(&mut self, elements: impl IntoIterator<Item = E>) {
if self.error.is_some() {
return;
}
for element in elements {
match element.try_build() {
Ok(idx) => {
self.first_child.get_or_insert(idx);
if let Some(last) = self.last_child {
self.cx.link_sibling(last, idx);
}
self.last_child = Some(idx);
}
Err(err) => {
self.error = Some(err);
break;
}
}
}
}
}
impl<'frame, C, CE> ElementBuilder for DivBuilder<'_, 'frame, C, CE>
where
C: PixelColor,
{
fn try_build(self) -> Result<NodeIndex, BuildError> {
if let Some(err) = self.error {
return Err(err);
}
let node = Node {
kind: NodeKind::Div(self.style),
layout: Layout::empty(),
child: self.first_child,
sibling: None,
};
self.cx.insert(node)
}
}
pub trait StyledFlexContainer<C>: StyledElement<Color = C, Specific = DivStyle>
where
C: PixelColor,
{
fn gap(mut self, gap: impl Into<Gap>) -> Self {
self.style_mut().specific.gap = gap.into().0;
self
}
fn flex_direction(mut self, direction: FlexDirection) -> Self {
self.style_mut().specific.direction = direction;
self
}
#[cfg(feature = "flexbox")]
fn justify_content(mut self, justify_content: JustifyContent) -> Self {
self.style_mut().specific.justify_content = justify_content;
self
}
#[cfg(feature = "flexbox")]
fn align_items(mut self, align_items: AlignItems) -> Self {
self.style_mut().specific.align_items = align_items;
self
}
}
impl<T, C> StyledFlexContainer<C> for T
where
T: StyledElement<Color = C, Specific = DivStyle>,
C: PixelColor,
{
}