use kurbo::{Affine, Rect, Size};
use peniko::Color;
use drafftink_core::canvas::Canvas;
use drafftink_core::shapes::Shape;
use drafftink_core::snap::SnapTarget;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum RendererError {
#[error("Initialization failed: {0}")]
InitFailed(String),
#[error("Render failed: {0}")]
RenderFailed(String),
#[error("Surface error: {0}")]
Surface(String),
}
#[allow(dead_code)]
pub type RenderResult<T> = Result<T, RendererError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum GridStyle {
None,
#[default]
Lines,
CrossPlus,
Dots,
}
impl GridStyle {
pub fn next(self) -> Self {
match self {
GridStyle::None => GridStyle::Lines,
GridStyle::Lines => GridStyle::CrossPlus,
GridStyle::CrossPlus => GridStyle::Dots,
GridStyle::Dots => GridStyle::None,
}
}
pub fn name(self) -> &'static str {
match self {
GridStyle::None => "None",
GridStyle::Lines => "Lines",
GridStyle::CrossPlus => "Crosses",
GridStyle::Dots => "Dots",
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct AngleSnapInfo {
pub start_point: kurbo::Point,
pub end_point: kurbo::Point,
pub angle_degrees: f64,
pub is_snapped: bool,
}
pub struct RenderContext<'a> {
pub canvas: &'a Canvas,
pub viewport_size: Size,
pub scale_factor: f64,
pub background_color: Color,
pub grid_style: GridStyle,
pub selection_color: Color,
pub selection_rect: Option<Rect>,
pub editing_shape_id: Option<drafftink_core::shapes::ShapeId>,
pub snap_point: Option<kurbo::Point>,
pub angle_snap_info: Option<AngleSnapInfo>,
pub nearby_snap_targets: Vec<SnapTarget>,
}
impl<'a> RenderContext<'a> {
pub fn new(canvas: &'a Canvas, viewport_size: Size) -> Self {
Self {
canvas,
viewport_size,
scale_factor: 1.0,
background_color: Color::from_rgba8(250, 250, 250, 255),
grid_style: GridStyle::Lines,
selection_color: Color::from_rgba8(59, 130, 246, 255), selection_rect: None,
editing_shape_id: None,
snap_point: None,
angle_snap_info: None,
nearby_snap_targets: Vec::new(),
}
}
pub fn with_scale_factor(mut self, scale_factor: f64) -> Self {
self.scale_factor = scale_factor;
self
}
pub fn with_background(mut self, color: Color) -> Self {
self.background_color = color;
self
}
pub fn with_grid(mut self, style: GridStyle) -> Self {
self.grid_style = style;
self
}
pub fn with_selection_rect(mut self, rect: Option<Rect>) -> Self {
self.selection_rect = rect;
self
}
pub fn with_editing_shape(mut self, shape_id: Option<drafftink_core::shapes::ShapeId>) -> Self {
self.editing_shape_id = shape_id;
self
}
pub fn with_snap_point(mut self, point: Option<kurbo::Point>) -> Self {
self.snap_point = point;
self
}
pub fn with_angle_snap(mut self, info: Option<AngleSnapInfo>) -> Self {
self.angle_snap_info = info;
self
}
pub fn with_snap_targets(mut self, targets: Vec<SnapTarget>) -> Self {
self.nearby_snap_targets = targets;
self
}
}
pub trait Renderer: Send + Sync {
fn build_scene(&mut self, ctx: &RenderContext);
fn background_color(&self, ctx: &RenderContext) -> Color {
ctx.background_color
}
}
#[allow(dead_code)]
pub trait ShapeRenderer {
fn render_shape(&mut self, shape: &Shape, transform: Affine, selected: bool);
fn render_grid(&mut self, viewport: Rect, transform: Affine, grid_size: f64);
fn render_selection_handles(&mut self, bounds: Rect, transform: Affine);
}