use crate::Event;
use crate::{buffer::Buffer, Cmd};
pub use button::Button;
pub use checkbox::Checkbox;
use expanse::result::Layout;
use expanse::{
node::{Node, Stretch},
style::Style,
};
pub use flex_box::FlexBox;
pub use group_box::GroupBox;
pub use image_control::Image;
pub use link::Link;
pub use list_box::ListBox;
pub use radio::Radio;
pub use slider::Slider;
use std::{any::Any, fmt};
pub use tab_box::TabBox;
pub use text_area::TextArea;
pub use text_input::TextInput;
pub use text_label::TextLabel;
mod button;
mod checkbox;
mod flex_box;
mod group_box;
mod image_control;
mod link;
mod list_box;
mod radio;
mod slider;
mod tab_box;
mod text_area;
mod text_input;
mod text_label;
pub trait Widget<MSG>
where
Self: fmt::Debug,
{
fn style(&self) -> Style;
fn layout(&self) -> Option<&Layout>;
fn get_offset(&self) -> (f32, f32) {
(0.0, 0.0)
}
fn set_layout(&mut self, layout: Layout);
fn add_child(&mut self, _child: Box<dyn Widget<MSG>>) -> bool {
false
}
fn children(&self) -> Option<&[Box<dyn Widget<MSG>>]> {
None
}
fn children_mut(&mut self) -> Option<&mut [Box<dyn Widget<MSG>>]> {
None
}
fn child_mut(
&mut self,
_index: usize,
) -> Option<&mut Box<dyn Widget<MSG>>> {
None
}
fn draw(&self, but: &mut Buffer) -> Vec<Cmd>;
fn style_node(&self, stretch: &mut Stretch) -> Option<Node> {
let children_styles = if let Some(children) = self.children() {
children
.iter()
.filter_map(|c| c.style_node(stretch))
.collect()
} else {
vec![]
};
stretch.new_node(self.style(), &children_styles).ok()
}
fn set_focused(&mut self, _focused: bool) {}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn set_size(&mut self, width: Option<f32>, height: Option<f32>);
fn as_mut(&mut self) -> Option<&mut Self>
where
Self: Sized + 'static,
{
self.as_any_mut().downcast_mut::<Self>()
}
fn process_event(&mut self, _event: Event) -> Vec<MSG> {
vec![]
}
fn take_child(&mut self, _index: usize) -> Option<Box<dyn Widget<MSG>>> {
None
}
fn set_id(&mut self, id: &str);
fn get_id(&self) -> &Option<String>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
use expanse::{geometry::*, number::Number};
use std::boxed;
#[test]
fn layout() {
let mut control = FlexBox::<()>::new();
control.horizontal();
let mut btn = Button::<()>::new("Hello");
btn.set_size(Some(30.0), Some(34.0));
control.add_child(boxed::Box::new(btn));
let mut btn = Button::<()>::new("world");
btn.set_size(Some(20.0), Some(10.0));
control.add_child(boxed::Box::new(btn));
crate::layout::compute_node_layout(
&mut control,
Size {
width: Number::Defined(100.0),
height: Number::Defined(100.0),
},
);
let layout1 = control.children().expect("must have children")[1]
.layout()
.expect("must have layout");
assert_eq!(
layout1.size,
Size {
width: 20.0,
height: 10.0
}
);
assert_eq!(layout1.location, Point { x: 30.0, y: 0.0 });
}
#[test]
fn layout2() {
let mut control = FlexBox::<()>::new();
control.vertical();
let mut btn1 = Button::<()>::new("Hello");
btn1.set_size(Some(100.0), Some(20.0));
control.add_child(boxed::Box::new(btn1));
let mut btn2 = Button::<()>::new("world");
btn2.set_size(Some(20.0), Some(10.0));
let mut btn3 = Button::<()>::new("world");
btn3.set_size(Some(20.0), Some(10.0));
let mut hrow = FlexBox::<()>::new();
hrow.horizontal();
hrow.add_child(boxed::Box::new(btn2));
hrow.add_child(boxed::Box::new(btn3));
control.add_child(boxed::Box::new(hrow));
crate::layout::compute_node_layout(
&mut control,
Size {
width: Number::Defined(100.0),
height: Number::Defined(100.0),
},
);
let layout_btn2 = control.children().expect("must have children")[1]
.children()
.expect("must have grand children")[1]
.layout()
.expect("must have a layout");
assert_eq!(layout_btn2.location, Point { x: 20.0, y: 17.0 });
}
}