use tuirealm::command::{Cmd, CmdResult};
use tuirealm::component::Component;
use tuirealm::props::{
AttrValue, Attribute, Borders, Color, Layout, Props, QueryResult, Style, TextModifiers, Title,
};
use tuirealm::ratatui::Frame;
use tuirealm::ratatui::layout::Rect;
use tuirealm::state::State;
use crate::prop_ext::CommonProps;
#[must_use]
pub struct Container {
common: CommonProps,
props: Props,
pub children: Vec<Box<dyn Component>>,
}
impl Default for Container {
fn default() -> Self {
Self {
common: CommonProps {
border: Some(Borders::default()),
..CommonProps::default()
},
props: Props::default(),
children: Vec::new(),
}
}
}
impl Container {
pub fn foreground(mut self, fg: Color) -> Self {
self.attr(Attribute::Foreground, AttrValue::Color(fg));
self
}
pub fn background(mut self, bg: Color) -> Self {
self.attr(Attribute::Background, AttrValue::Color(bg));
self
}
pub fn modifiers(mut self, m: TextModifiers) -> Self {
self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
self
}
pub fn style(mut self, style: Style) -> Self {
self.attr(Attribute::Style, AttrValue::Style(style));
self
}
pub fn inactive(mut self, s: Style) -> Self {
self.attr(Attribute::UnfocusedBorderStyle, AttrValue::Style(s));
self
}
pub fn borders(mut self, b: Borders) -> Self {
self.attr(Attribute::Borders, AttrValue::Borders(b));
self
}
pub fn title<T: Into<Title>>(mut self, title: T) -> Self {
self.attr(Attribute::Title, AttrValue::Title(title.into()));
self
}
pub fn layout(mut self, layout: Layout) -> Self {
self.attr(Attribute::Layout, AttrValue::Layout(layout));
self
}
pub fn children(mut self, children: Vec<Box<dyn Component>>) -> Self {
self.children = children;
self
}
}
impl Component for Container {
fn view(&mut self, render: &mut Frame, mut area: Rect) {
if !self.common.display {
return;
}
if let Some(block) = self.common.get_block() {
let inner = block.inner(area);
render.render_widget(block, area);
area = inner;
}
if let Some(layout) = self
.props
.get(Attribute::Layout)
.and_then(AttrValue::as_layout)
{
let chunks = layout.chunks(area);
for (i, chunk) in chunks.into_iter().enumerate() {
if let Some(child) = self.children.get_mut(i) {
child.view(render, chunk);
}
}
}
}
fn query<'a>(&'a self, attr: Attribute) -> Option<QueryResult<'a>> {
if let Some(value) = self.common.get_for_query(attr) {
return Some(value);
}
self.props.get_for_query(attr)
}
fn attr(&mut self, attr: Attribute, value: AttrValue) {
if let Some(value) = self.common.set(attr, value.clone()) {
self.props.set(attr, value);
}
if matches!(attr, Attribute::Borders | Attribute::Title) {
return;
}
self.children
.iter_mut()
.for_each(|x| x.attr(attr, value.clone()));
}
fn state(&self) -> State {
State::None
}
fn perform(&mut self, cmd: Cmd) -> CmdResult {
CmdResult::Batch(self.children.iter_mut().map(|x| x.perform(cmd)).collect())
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use tuirealm::props::HorizontalAlignment;
use super::*;
#[test]
fn test_components_paragraph() {
let component = Container::default()
.background(Color::Blue)
.foreground(Color::Red)
.title(Title::from("title").alignment(HorizontalAlignment::Center));
assert_eq!(component.state(), State::None);
}
}