use crate::event::EventContext;
use crate::geometry::Color;
use crate::layout::style::FlexStyle;
use crate::layout::types::{FlexAlign, FlexWrap};
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 Column {
layout: LayoutAttr,
children: Vec<Box<dyn Widget>>,
listeners: Vec<Listener>,
paint: Option<PaintStyle>,
}
impl Column {
pub fn new() -> Self {
Self {
layout: LayoutAttr::new().gap(4.0).align_items(FlexAlign::Stretch),
children: Vec::new(),
listeners: Vec::new(),
paint: None,
}
}
pub fn child(mut self, c: impl Widget + 'static) -> Self {
self.children.push(Box::new(c));
self
}
pub fn spacing(mut self, s: f32) -> Self {
self.layout = self.layout.gap(s);
self
}
pub fn layout(mut self, l: LayoutAttr) -> Self {
self.layout = l;
self
}
pub fn width(mut self, v: f32) -> Self {
self.layout = self.layout.width(v);
self
}
pub fn height(mut self, v: f32) -> Self {
self.layout = self.layout.height(v);
self
}
pub fn justify_content(mut self, j: FlexAlign) -> Self {
self.layout = self.layout.justify_content(j);
self
}
pub fn align_items(mut self, a: FlexAlign) -> Self {
self.layout = self.layout.align_items(a);
self
}
pub fn expand(mut self, v: bool) -> Self {
self.layout = self.layout.expand(v);
self
}
pub fn flex_shrink(mut self, v: f32) -> Self {
self.layout = self.layout.flex_shrink(v);
self
}
pub fn margin(mut self, v: f32) -> Self {
self.layout = self.layout.margin(v);
self
}
pub fn center(mut self) -> Self {
self.layout = self
.layout
.justify_content(FlexAlign::Center)
.align_items(FlexAlign::Center)
.expand(true);
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 maybe_child<W: Widget + 'static>(mut self, c: Option<W>) -> Self {
if let Some(c) = c {
self.children.push(Box::new(c));
}
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
}
}
impl Default for Column {
fn default() -> Self {
Self::new()
}
}
impl Widget for Column {
fn build(&self, ctx: &mut BuildContext) -> ViewNode {
let mut layout = FlexStyle::column()
.justify_content(self.layout.justify_content.unwrap_or(FlexAlign::Start))
.align_items(self.layout.align_items.unwrap_or(FlexAlign::Stretch))
.gap(self.layout.gap)
.wrap(FlexWrap::NoWrap);
layout = self.layout.apply(layout);
ViewNode::Div {
layout,
paint: self.paint.clone().unwrap_or_default(),
key: None,
children: self
.children
.iter()
.enumerate()
.map(|(i, c)| ctx.child(i, c.as_ref()))
.collect(),
listeners: self.listeners.clone(),
}
}
}
pub struct Row {
layout: LayoutAttr,
children: Vec<Box<dyn Widget>>,
listeners: Vec<Listener>,
paint: Option<PaintStyle>,
}
impl Row {
pub fn new() -> Self {
Self {
layout: LayoutAttr::new().gap(4.0).align_items(FlexAlign::Center),
children: Vec::new(),
listeners: Vec::new(),
paint: None,
}
}
pub fn child(mut self, c: impl Widget + 'static) -> Self {
self.children.push(Box::new(c));
self
}
pub fn spacing(mut self, s: f32) -> Self {
self.layout = self.layout.gap(s);
self
}
pub fn layout(mut self, l: LayoutAttr) -> Self {
self.layout = l;
self
}
pub fn width(mut self, v: f32) -> Self {
self.layout = self.layout.width(v);
self
}
pub fn height(mut self, v: f32) -> Self {
self.layout = self.layout.height(v);
self
}
pub fn justify_content(mut self, j: FlexAlign) -> Self {
self.layout = self.layout.justify_content(j);
self
}
pub fn align_items(mut self, a: FlexAlign) -> Self {
self.layout = self.layout.align_items(a);
self
}
pub fn expand(mut self, v: bool) -> Self {
self.layout = self.layout.expand(v);
self
}
pub fn flex_shrink(mut self, v: f32) -> Self {
self.layout = self.layout.flex_shrink(v);
self
}
pub fn margin(mut self, v: f32) -> Self {
self.layout = self.layout.margin(v);
self
}
pub fn center(mut self) -> Self {
self.layout = self
.layout
.justify_content(FlexAlign::Center)
.align_items(FlexAlign::Center)
.expand(true);
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 maybe_child<W: Widget + 'static>(mut self, c: Option<W>) -> Self {
if let Some(c) = c {
self.children.push(Box::new(c));
}
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
}
}
impl Default for Row {
fn default() -> Self {
Self::new()
}
}
impl Widget for Row {
fn build(&self, ctx: &mut BuildContext) -> ViewNode {
let mut layout = FlexStyle::row()
.justify_content(self.layout.justify_content.unwrap_or(FlexAlign::Start))
.align_items(self.layout.align_items.unwrap_or(FlexAlign::Center))
.gap(self.layout.gap)
.wrap(FlexWrap::NoWrap);
layout = self.layout.apply(layout);
ViewNode::Div {
layout,
paint: self.paint.clone().unwrap_or_default(),
key: None,
children: self
.children
.iter()
.enumerate()
.map(|(i, c)| ctx.child(i, c.as_ref()))
.collect(),
listeners: self.listeners.clone(),
}
}
}