use crate::event::EventContext;
use crate::geometry::Color;
use crate::layout::style::FlexStyle;
use crate::layout::types::FlexAlign;
use crate::layout_methods;
use crate::view::node::{Listener, ViewNode};
use crate::view::paint::PaintStyle;
use crate::widget::layout::LayoutAttr;
use crate::widget::{BuildContext, Widget};
use std::rc::Rc;
pub struct Container {
layout: LayoutAttr,
clip_content: bool,
children: Vec<Box<dyn Widget>>,
listeners: Vec<Listener>,
paint: Option<PaintStyle>,
}
impl Container {
pub fn new() -> Self {
Self {
layout: LayoutAttr::new(),
clip_content: false,
children: Vec::new(),
listeners: Vec::new(),
paint: None,
}
}
layout_methods!(for Container);
pub fn child(mut self, c: impl Widget + 'static) -> Self {
self.children.push(Box::new(c));
self
}
pub fn clip(mut self, v: bool) -> Self {
self.clip_content = v;
self
}
pub fn on_click<F: Fn() + 'static>(mut self, f: F) -> Self {
self.listeners.push(Listener::on_click(Rc::new(f)));
self
}
pub fn on_click_with_ctx<F: Fn(&mut EventContext) + 'static>(mut self, f: F) -> Self {
self.listeners.push(Listener::on_click_with_ctx(Rc::new(f)));
self
}
pub fn paint_style(mut self, p: PaintStyle) -> Self {
self.paint = Some(p);
self
}
pub fn background(mut self, c: Color) -> Self {
self.paint
.get_or_insert_with(PaintStyle::new)
.background_color = Some(c);
self
}
pub fn hover_background(mut self, c: Color) -> Self {
self.paint
.get_or_insert_with(PaintStyle::new)
.hover_background = Some(c);
self
}
pub fn pressed_background(mut self, c: Color) -> Self {
self.paint
.get_or_insert_with(PaintStyle::new)
.pressed_background = Some(c);
self
}
pub fn border_radius(mut self, r: f32) -> Self {
self.paint.get_or_insert_with(PaintStyle::new).border_radius = r;
self
}
pub fn border(mut self, width: f32, color: Color) -> Self {
let p = self.paint.get_or_insert_with(PaintStyle::new);
p.border_width = width;
p.border_color = Some(color);
self
}
pub fn opacity(mut self, o: f32) -> Self {
self.paint.get_or_insert_with(PaintStyle::new).opacity = o.clamp(0.0, 1.0);
self
}
pub fn shadow(mut self, s: crate::view::paint::ShadowSpec) -> Self {
self.paint.get_or_insert_with(PaintStyle::new).shadow = Some(s);
self
}
}
impl Default for Container {
fn default() -> Self {
Self::new()
}
}
impl Widget for Container {
fn build(&self, ctx: &mut BuildContext) -> ViewNode {
let mut layout = FlexStyle::block().padding_all(self.layout.padding);
if let Some(v) = self.layout.padding_l {
layout = layout.padding_left(v);
}
if let Some(v) = self.layout.padding_t {
layout = layout.padding_top(v);
}
if let Some(v) = self.layout.padding_r {
layout = layout.padding_right(v);
}
if let Some(v) = self.layout.padding_b {
layout = layout.padding_bottom(v);
}
layout = self.layout.apply(layout);
let mut paint = PaintStyle::default();
if let Some(p) = &self.paint {
if let Some(bg) = p.background_color {
paint = paint.background(bg);
}
if let Some(hbg) = p.hover_background {
paint = paint.hover_background(hbg);
}
if let Some(pbg) = p.pressed_background {
paint = paint.pressed_background(pbg);
}
if p.border_radius > 0.0 {
paint = paint.radius(p.border_radius);
}
if let Some(bc) = p.border_color
&& p.border_width > 0.0
{
paint = paint.border(p.border_width, bc);
}
if p.opacity != 1.0 {
paint = paint.opacity(p.opacity);
}
if let Some(sh) = p.shadow {
paint = paint.shadow(sh);
}
}
if self.clip_content {
paint = paint.clip(true);
}
ViewNode::Div {
layout,
paint,
key: None,
children: self
.children
.iter()
.enumerate()
.map(|(i, c)| ctx.child(i, c.as_ref()))
.collect(),
listeners: self.listeners.clone(),
}
}
}