drafftink_render/
renderer.rs1use kurbo::{Affine, Rect, Size};
4use peniko::Color;
5use drafftink_core::canvas::Canvas;
6use drafftink_core::shapes::Shape;
7use drafftink_core::snap::SnapTarget;
8use thiserror::Error;
9
10#[derive(Debug, Error)]
12pub enum RendererError {
13 #[error("Initialization failed: {0}")]
14 InitFailed(String),
15 #[error("Render failed: {0}")]
16 RenderFailed(String),
17 #[error("Surface error: {0}")]
18 Surface(String),
19}
20
21#[allow(dead_code)]
23pub type RenderResult<T> = Result<T, RendererError>;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
27pub enum GridStyle {
28 None,
30 #[default]
32 Lines,
33 CrossPlus,
35 Dots,
37}
38
39impl GridStyle {
40 pub fn next(self) -> Self {
42 match self {
43 GridStyle::None => GridStyle::Lines,
44 GridStyle::Lines => GridStyle::CrossPlus,
45 GridStyle::CrossPlus => GridStyle::Dots,
46 GridStyle::Dots => GridStyle::None,
47 }
48 }
49
50 pub fn name(self) -> &'static str {
52 match self {
53 GridStyle::None => "None",
54 GridStyle::Lines => "Lines",
55 GridStyle::CrossPlus => "Crosses",
56 GridStyle::Dots => "Dots",
57 }
58 }
59}
60
61#[derive(Debug, Clone, Copy)]
63pub struct AngleSnapInfo {
64 pub start_point: kurbo::Point,
66 pub end_point: kurbo::Point,
68 pub angle_degrees: f64,
70 pub is_snapped: bool,
72}
73
74pub struct RenderContext<'a> {
76 pub canvas: &'a Canvas,
78 pub viewport_size: Size,
80 pub scale_factor: f64,
82 pub background_color: Color,
84 pub grid_style: GridStyle,
86 pub selection_color: Color,
88 pub selection_rect: Option<Rect>,
90 pub editing_shape_id: Option<drafftink_core::shapes::ShapeId>,
92 pub snap_point: Option<kurbo::Point>,
94 pub angle_snap_info: Option<AngleSnapInfo>,
96 pub nearby_snap_targets: Vec<SnapTarget>,
98}
99
100impl<'a> RenderContext<'a> {
101 pub fn new(canvas: &'a Canvas, viewport_size: Size) -> Self {
103 Self {
104 canvas,
105 viewport_size,
106 scale_factor: 1.0,
107 background_color: Color::from_rgba8(250, 250, 250, 255),
108 grid_style: GridStyle::Lines,
109 selection_color: Color::from_rgba8(59, 130, 246, 255), selection_rect: None,
111 editing_shape_id: None,
112 snap_point: None,
113 angle_snap_info: None,
114 nearby_snap_targets: Vec::new(),
115 }
116 }
117
118 pub fn with_scale_factor(mut self, scale_factor: f64) -> Self {
120 self.scale_factor = scale_factor;
121 self
122 }
123
124 pub fn with_background(mut self, color: Color) -> Self {
126 self.background_color = color;
127 self
128 }
129
130 pub fn with_grid(mut self, style: GridStyle) -> Self {
132 self.grid_style = style;
133 self
134 }
135
136 pub fn with_selection_rect(mut self, rect: Option<Rect>) -> Self {
138 self.selection_rect = rect;
139 self
140 }
141
142 pub fn with_editing_shape(mut self, shape_id: Option<drafftink_core::shapes::ShapeId>) -> Self {
144 self.editing_shape_id = shape_id;
145 self
146 }
147
148 pub fn with_snap_point(mut self, point: Option<kurbo::Point>) -> Self {
150 self.snap_point = point;
151 self
152 }
153
154 pub fn with_angle_snap(mut self, info: Option<AngleSnapInfo>) -> Self {
156 self.angle_snap_info = info;
157 self
158 }
159
160 pub fn with_snap_targets(mut self, targets: Vec<SnapTarget>) -> Self {
162 self.nearby_snap_targets = targets;
163 self
164 }
165}
166
167pub trait Renderer: Send + Sync {
171 fn build_scene(&mut self, ctx: &RenderContext);
175
176 fn background_color(&self, ctx: &RenderContext) -> Color {
178 ctx.background_color
179 }
180}
181
182#[allow(dead_code)]
184pub trait ShapeRenderer {
185 fn render_shape(&mut self, shape: &Shape, transform: Affine, selected: bool);
187
188 fn render_grid(&mut self, viewport: Rect, transform: Affine, grid_size: f64);
190
191 fn render_selection_handles(&mut self, bounds: Rect, transform: Affine);
193}