use super::core_shapes::*; use super::styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern}; use super::text::{DefinedFontDescription, FontDescription}; use super::types::DefinedCoreShapeContext; pub trait Renderer { // Must be called once before any drawing happens fn set_size(&mut self, width: f64, height: f64); fn move_to(&mut self, x: f64, y: f64); fn stroke(&mut self); fn fill(&mut self); fn fill_preserve(&mut self); fn set_pattern(&mut self, pattern: &Pattern); fn set_dash(&mut self, dash: &DefinedDashStyle); fn clear_dash(&mut self); fn set_line_width(&mut self, width: f64); fn line_to(&mut self, x: f64, y: f64); fn rectangle(&mut self, x: f64, y: f64, width: f64, height: f64); // For a font of size 1. fn text_extents(&self, text: &str, font: &FontDescription) -> (f64, f64); fn show_text(&mut self, text: &str, font: &DefinedFontDescription); } pub trait Render { fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer); } impl Render for DefinedCoreShape { fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer) { match self { Self::Rectangle(r) => r.render(context, renderer), Self::Text(t) => t.render(context, renderer), Self::StraightPath(p) => p.render(context, renderer), } } } fn draw(fill: &FillStyle, stroke: &DefinedStrokeStyle, renderer: &mut dyn Renderer) { let stroking = !stroke.pattern.is_none(); if !fill.pattern.is_none() { renderer.set_pattern(&fill.pattern); if stroking { renderer.fill_preserve(); } else { renderer.fill(); } } if !stroke.pattern.is_none() { renderer.set_pattern(&stroke.pattern); renderer.set_line_width(stroke.line_width); if let Some(dash) = &stroke.dash { renderer.set_dash(dash); } renderer.stroke(); renderer.clear_dash(); } } impl Render for Rectangle { fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer) { let bounds = &context.bounds; renderer.rectangle(bounds.left, bounds.top, bounds.width, bounds.height); draw(&context.fill, &context.stroke, renderer); } } impl Render for DefinedText { fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer) { // TODO: select font, style, text shaping (renderer specific), etc. let bounds = &context.bounds; //renderer.move_to(bounds.left, bounds.top + self.font.size); renderer.move_to(bounds.left, bounds.top); // TODO: ??? //draw(&context.fill, &context.stroke, renderer); renderer.show_text(&self.content, &self.font); } } impl Render for DefinedStraightPath { fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer) { let mut iter = self.points.iter(); let first_point = match iter.next() { Some(point) => point, None => return, }; renderer.move_to(first_point.x, first_point.y); for point in iter { renderer.line_to(point.x, point.y); } draw(&context.fill, &context.stroke, renderer); } }