use std::fmt::Debug;
use figures::units::UPx;
use figures::Size;
use crate::context::{GraphicsContext, LayoutContext};
use crate::value::Dynamic;
use crate::widget::Widget;
use crate::{ConstraintLimit, Tick};
#[must_use]
pub struct Canvas {
render: Box<dyn RenderFunction>,
tick: Option<Tick>,
redraw: Dynamic<()>,
}
impl Canvas {
pub fn new<F>(render: F) -> Self
where
F: for<'clip, 'gfx, 'pass, 'context> FnMut(
&mut GraphicsContext<'context, 'clip, 'gfx, 'pass>,
) + Send
+ 'static,
{
Self {
render: Box::new(render),
tick: None,
redraw: Dynamic::new(()),
}
}
pub fn tick(mut self, tick: Tick) -> Self {
self.tick = Some(tick);
self
}
}
impl Widget for Canvas {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_>) {
context.redraw_when_changed(&self.redraw);
self.render.render(context);
if let Some(tick) = &self.tick {
tick.rendered(context);
}
}
fn layout(
&mut self,
available_space: Size<crate::ConstraintLimit>,
_context: &mut LayoutContext<'_, '_, '_, '_>,
) -> Size<UPx> {
available_space.map(ConstraintLimit::max)
}
}
impl Debug for Canvas {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Canvas").finish_non_exhaustive()
}
}
trait RenderFunction: Send + 'static {
fn render(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_>);
}
impl<F> RenderFunction for F
where
F: for<'clip, 'gfx, 'pass, 'context> FnMut(&mut GraphicsContext<'context, 'clip, 'gfx, 'pass>)
+ Send
+ 'static,
{
fn render(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_>) {
self(context);
}
}