use wgpu_canvas::Area as CanvasArea;
use wgpu_canvas::Item as CanvasItem;
use std::fmt::Debug;
use std::any::Any;
use super::{Context, resources};
use super::events::*;
use super::layout::{SizeRequest, Area};
use crate::events::OnEvent;
pub use wgpu_canvas::{Text, Font, Span, Align, Cursor, Color};
pub use wgpu_canvas::Shape as ShapeType;
#[derive(Default, Debug, Clone)]
pub struct RequestBranch(pub SizeRequest, Vec<RequestBranch>);
#[derive(Default, Debug, Clone)]
pub struct SizedBranch(pub Size, Vec<(Offset, SizedBranch)>);
type Offset = (f32, f32);
type Rect = (f32, f32, f32, f32);
type Size = (f32, f32);
#[allow(private_bounds)]
pub trait Drawable: _Drawable + Debug + Any {
fn request_size(&self, ctx: &mut Context) -> SizeRequest;
fn name(&self) -> String;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl _Drawable for Box<dyn Drawable> {
fn request_size(&self, ctx: &mut Context) -> RequestBranch {_Drawable::request_size(&**self, ctx)}
fn build(&mut self, ctx: &mut Context, size: Size, request: RequestBranch) -> SizedBranch {
_Drawable::build(&mut **self, ctx, size, request)
}
fn draw(&mut self, sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
_Drawable::draw(&mut **self, sized, offset, bound)
}
fn name(&self) -> String {_Drawable::name(&**self)}
fn event(&mut self, ctx: &mut Context, sized: SizedBranch, event: Box<dyn Event>) {
_Drawable::event(&mut **self, ctx, sized, event)
}
}
impl<D: _Drawable + Debug + Any> Drawable for D {
fn request_size(&self, ctx: &mut Context) -> SizeRequest {_Drawable::request_size(self, ctx).0}
fn name(&self) -> String {_Drawable::name(self)}
fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
fn as_any(&self) -> &dyn Any { self }
fn as_any_mut(&mut self) -> &mut dyn Any { self }
}
pub(crate) trait _Drawable: Debug {
fn request_size(&self, ctx: &mut Context) -> RequestBranch;
fn build(&mut self, _ctx: &mut Context, size: Size, request: RequestBranch) -> SizedBranch {
SizedBranch(request.0.get(size), vec![])
}
fn draw(&mut self, sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)>;
fn name(&self) -> String {std::any::type_name_of_val(self).to_string()}
fn event(&mut self, _ctx: &mut Context, _sized: SizedBranch, _event: Box<dyn Event>) {}
}
impl _Drawable for Text {
fn request_size(&self, ctx: &mut Context) -> RequestBranch {
RequestBranch(SizeRequest::fixed(self.size(ctx)), vec![])
}
fn draw(&mut self, _sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
vec![(CanvasArea(offset, Some(bound)), CanvasItem::Text(self.clone()))]
}
}
impl<D: _Drawable + Debug + Any> _Drawable for Option<D> {
fn request_size(&self, ctx: &mut Context) -> RequestBranch {
match self {
Some(d) => d.request_size(ctx),
None => RequestBranch(SizeRequest::fixed((0.0, 0.0)), vec![]),
}
}
fn build(&mut self, ctx: &mut Context, size: Size, request: RequestBranch) -> SizedBranch {
match self {
Some(d) => d.build(ctx, size, request),
None => SizedBranch(size, vec![]),
}
}
fn draw(&mut self, sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
match self {
Some(d) => d.draw(sized, offset, bound),
None => vec![],
}
}
fn name(&self) -> String {
match self {
Some(d) => d.name(),
None => "None".to_string(),
}
}
fn event(&mut self, ctx: &mut Context, sized: SizedBranch, event: Box<dyn Event>) {
if let Some(d) = self {
d.event(ctx, sized, event);
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Shape {
pub shape: ShapeType,
pub color: Color,
}
impl _Drawable for Shape {
fn request_size(&self, _ctx: &mut Context) -> RequestBranch {
RequestBranch(SizeRequest::fixed(self.shape.size()), vec![])
}
fn draw(&mut self, _sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
vec![(CanvasArea(offset, Some(bound)), CanvasItem::Shape(self.shape, self.color))]
}
}
#[derive(Clone, Debug)]
pub struct Image {
pub shape: ShapeType,
pub image: resources::Image,
pub color: Option<Color>,
}
impl _Drawable for Image {
fn request_size(&self, _ctx: &mut Context) -> RequestBranch {
RequestBranch(SizeRequest::fixed(self.shape.size()), vec![])
}
fn draw(&mut self, _sized: SizedBranch, offset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
vec![(CanvasArea(offset, Some(bound)), CanvasItem::Image(self.shape, self.image.clone(), self.color))]
}
}
pub trait Component: Debug {
fn children_mut(&mut self) -> Vec<&mut dyn Drawable>;
fn children(&self) -> Vec<&dyn Drawable>;
fn request_size(&self, ctx: &mut Context, children: Vec<SizeRequest>) -> SizeRequest;
fn build(&mut self, ctx: &mut Context, size: Size, children: Vec<SizeRequest>) -> Vec<Area>;
}
impl<C: Component + ?Sized + 'static + OnEvent> _Drawable for C {
fn request_size(&self, ctx: &mut Context) -> RequestBranch {
let requests = self.children().into_iter().map(|i| _Drawable::request_size(i, ctx)).collect::<Vec<_>>();
let info = requests.iter().map(|i| i.0).collect::<Vec<_>>();
let r = Component::request_size(self, ctx, info);
RequestBranch(r, requests)
}
fn build(&mut self, ctx: &mut Context, size: Size, request: RequestBranch) -> SizedBranch {
let size = request.0.get(size);
let children = request.1.iter().map(|b| b.0).collect::<Vec<_>>();
SizedBranch(
size,
Component::build(self, ctx, size, children).into_iter()
.zip(self.children_mut()).zip(request.1)
.map(|((Area{offset, size}, child), branch)| {
(offset, child.build(ctx, size, branch))
}).collect()
)
}
fn draw(&mut self, sized: SizedBranch, poffset: Offset, bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
sized.1.into_iter().zip(self.children_mut()).flat_map(|((offset, branch), child)| {
let size = branch.0;
let poffset = (poffset.0+offset.0, poffset.1+offset.1);
let bound = (
bound.0.max(poffset.0), bound.1.max(poffset.1), bound.2.min((offset.0 + size.0).max(0.0)), bound.3.min((offset.1 + size.1).max(0.0)) );
if bound.2 != 0.0 && bound.3 != 0.0 {
child.draw(branch, poffset, bound)
} else {vec![]}
}).collect()
}
fn event(&mut self, ctx: &mut Context, sized: SizedBranch, event: Box<dyn Event>) {
let children = sized.1.iter().map(|(o, branch)| (*o, branch.0)).collect::<Vec<_>>();
for event in OnEvent::on_event(self, ctx, event) {
event.pass(ctx, &children).into_iter().zip(self.children_mut()).zip(sized.1.iter()).for_each(
|((e, child), branch)| if let Some(e) = e {child.event(ctx, branch.1.clone(), e);}
);
}
}
}
#[macro_export]
macro_rules! drawables {
( $( $x:expr ),* $(,)? ) => {
{
vec![
$(Box::new($x) as Box<dyn roost::drawable::Drawable>),*
]
}
};
}