use std::path::PathBuf; use crate::{ text::{DefinedText, Text}, types::{CoreShapeContext, DefinedCoreShapeContext, DefinedPoint2D, Float, Point2D}, Renderer, SolverContext, }; #[derive(Debug, Clone)] pub struct CoreDrawable { pub(crate) shape: CoreShape, pub(crate) context: CoreShapeContext, } impl CoreDrawable { pub fn new(shape: CoreShape, context: CoreShapeContext) -> Self { Self { shape, context } } // TODO: I don't like this design // TODO: plus, having an enum for CoreShape could be bad since types have // various sizes pub(crate) fn inherent_constraints( &self, solver: &mut dyn SolverContext, renderer: &mut dyn Renderer, ) { match &self.shape { CoreShape::Text(text) => { let (text_width, text_height) = renderer.text_extents(&text.content, &text.font); let calculated_width = solver.float_mul(&[Float::Fixed(text_width), text.font.size]); let bounds_width = self.context.bounds().width(solver); let width_constraint = solver.float_eq(bounds_width, calculated_width); solver.constrain(width_constraint); let calculated_height = solver.float_mul(&[Float::Fixed(text_height), text.font.size]); let bounds_height = self.context.bounds().height(solver); let height_constraint = solver.float_eq(bounds_height, calculated_height); solver.constrain(height_constraint); } CoreShape::StraightPath(path) => { let (all_x, all_y): (Vec<_>, Vec<_>) = path.points.iter().map(|p| (p.x, p.y)).unzip(); let min_x = solver.float_min(&all_x); let max_x = solver.float_max(&all_x); let min_y = solver.float_min(&all_y); let max_y = solver.float_max(&all_y); let bounds_top = self.context.bounds().top(solver); let bounds_bottom = self.context.bounds().bottom(solver); let bounds_left = self.context.bounds().left(solver); let bounds_right = self.context.bounds().right(solver); let top_constraint = solver.float_eq(bounds_top, min_x); solver.constrain(top_constraint); let bottom_constraint = solver.float_eq(bounds_bottom, max_x); solver.constrain(bottom_constraint); let left_constraint = solver.float_eq(bounds_left, min_y); solver.constrain(left_constraint); let right_constraint = solver.float_eq(bounds_right, max_y); solver.constrain(right_constraint); } CoreShape::Image(image) => { if !image.keep_aspect_ratio { return; } let scale_x = solver.new_free_float(); let scale_y = solver.new_free_float(); let constraint = solver.float_eq(scale_x, scale_y); solver.constrain(constraint); let (orig_width, orig_height) = renderer.geometry_for_image(&image.path); let orig_width_scaled = solver.float_mul(&[scale_x, Float::Fixed(orig_width)]); let width_constraint = solver.float_eq(self.context.bounds().width, orig_width_scaled); solver.constrain(width_constraint); let orig_height_scaled = solver.float_mul(&[scale_y, Float::Fixed(orig_height)]); let height_constraint = solver.float_eq(self.context.bounds().height, orig_height_scaled); solver.constrain(height_constraint); } _ => (), } } } #[derive(Debug, Clone)] pub enum CoreShape { Rectangle(Rectangle), Text(Text), StraightPath(StraightPath), Image(Image), } impl From for CoreShape { fn from(rectangle: Rectangle) -> Self { CoreShape::Rectangle(rectangle) } } impl From for CoreShape { fn from(text: Text) -> Self { CoreShape::Text(text) } } impl From for CoreShape { fn from(path: StraightPath) -> Self { CoreShape::StraightPath(path) } } impl From for CoreShape { fn from(image: Image) -> Self { CoreShape::Image(image) } } pub struct DefinedCoreDrawable { pub(crate) shape: DefinedCoreShape, pub(crate) context: DefinedCoreShapeContext, } pub enum DefinedCoreShape { Rectangle(Rectangle), Text(DefinedText), StraightPath(DefinedStraightPath), Image(Image), } #[derive(Copy, Clone, Debug, Default)] pub struct Rectangle {} #[derive(Clone, Debug, Default)] pub struct StraightPath { pub(crate) points: Vec, } impl StraightPath { pub fn new(points: Vec) -> Self { Self { points } } } pub struct DefinedStraightPath { pub(crate) points: Vec, } #[derive(Clone, Debug, Default)] pub struct Image { pub(crate) path: PathBuf, pub(crate) keep_aspect_ratio: bool, } impl Image { pub fn new(path: PathBuf, keep_aspect_ratio: bool) -> Self { Self { path, keep_aspect_ratio, } } }