diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/src/core_shapes.rs | 174 | ||||
-rw-r--r-- | core/src/rendering.rs | 29 | ||||
-rw-r--r-- | core/src/runtime.rs | 107 | ||||
-rw-r--r-- | core/src/solving.rs | 2 |
4 files changed, 156 insertions, 156 deletions
diff --git a/core/src/core_shapes.rs b/core/src/core_shapes.rs index e6d79c9..c380870 100644 --- a/core/src/core_shapes.rs +++ b/core/src/core_shapes.rs | |||
@@ -1,7 +1,12 @@ | |||
1 | use crate::types::{CoreShapeContext, DefinedCoreShapeContext, DefinedPoint2D, Point2D}; | 1 | use std::path::PathBuf; |
2 | 2 | ||
3 | pub use super::text::{DefinedText, Text}; | 3 | use crate::{ |
4 | text::{DefinedText, Text}, | ||
5 | types::{CoreShapeContext, DefinedCoreShapeContext, DefinedPoint2D, Float, Point2D}, | ||
6 | Renderer, SolverContext, | ||
7 | }; | ||
4 | 8 | ||
9 | #[derive(Debug, Clone)] | ||
5 | pub struct CoreDrawable { | 10 | pub struct CoreDrawable { |
6 | pub(crate) shape: CoreShape, | 11 | pub(crate) shape: CoreShape, |
7 | pub(crate) context: CoreShapeContext, | 12 | pub(crate) context: CoreShapeContext, |
@@ -11,12 +16,91 @@ impl CoreDrawable { | |||
11 | pub fn new(shape: CoreShape, context: CoreShapeContext) -> Self { | 16 | pub fn new(shape: CoreShape, context: CoreShapeContext) -> Self { |
12 | Self { shape, context } | 17 | Self { shape, context } |
13 | } | 18 | } |
19 | |||
20 | // TODO: I don't like this design | ||
21 | // TODO: plus, having an enum for CoreShape could be bad since types have | ||
22 | // various sizes | ||
23 | pub(crate) fn inherent_constraints( | ||
24 | &self, | ||
25 | solver: &mut dyn SolverContext, | ||
26 | renderer: &mut dyn Renderer, | ||
27 | ) { | ||
28 | match &self.shape { | ||
29 | CoreShape::Text(text) => { | ||
30 | let (text_width, text_height) = renderer.text_extents(&text.content, &text.font); | ||
31 | |||
32 | let calculated_width = | ||
33 | solver.float_mul(&[Float::Fixed(text_width), text.font.size]); | ||
34 | let bounds_width = self.context.bounds().width(solver); | ||
35 | let width_constraint = solver.float_eq(bounds_width, calculated_width); | ||
36 | solver.constrain(width_constraint); | ||
37 | |||
38 | let calculated_height = | ||
39 | solver.float_mul(&[Float::Fixed(text_height), text.font.size]); | ||
40 | let bounds_height = self.context.bounds().height(solver); | ||
41 | let height_constraint = solver.float_eq(bounds_height, calculated_height); | ||
42 | solver.constrain(height_constraint); | ||
43 | } | ||
44 | CoreShape::StraightPath(path) => { | ||
45 | let (all_x, all_y): (Vec<_>, Vec<_>) = | ||
46 | path.points.iter().map(|p| (p.x, p.y)).unzip(); | ||
47 | |||
48 | let min_x = solver.float_min(&all_x); | ||
49 | let max_x = solver.float_max(&all_x); | ||
50 | let min_y = solver.float_min(&all_y); | ||
51 | let max_y = solver.float_max(&all_y); | ||
52 | |||
53 | let bounds_top = self.context.bounds().top(solver); | ||
54 | let bounds_bottom = self.context.bounds().bottom(solver); | ||
55 | let bounds_left = self.context.bounds().left(solver); | ||
56 | let bounds_right = self.context.bounds().right(solver); | ||
57 | |||
58 | let top_constraint = solver.float_eq(bounds_top, min_x); | ||
59 | solver.constrain(top_constraint); | ||
60 | |||
61 | let bottom_constraint = solver.float_eq(bounds_bottom, max_x); | ||
62 | solver.constrain(bottom_constraint); | ||
63 | |||
64 | let left_constraint = solver.float_eq(bounds_left, min_y); | ||
65 | solver.constrain(left_constraint); | ||
66 | |||
67 | let right_constraint = solver.float_eq(bounds_right, max_y); | ||
68 | solver.constrain(right_constraint); | ||
69 | } | ||
70 | CoreShape::Image(image) => { | ||
71 | if !image.keep_aspect_ratio { | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | let scale_x = solver.new_free_float(); | ||
76 | let scale_y = solver.new_free_float(); | ||
77 | |||
78 | let constraint = solver.float_eq(scale_x, scale_y); | ||
79 | solver.constrain(constraint); | ||
80 | |||
81 | let (orig_width, orig_height) = renderer.geometry_for_image(&image.path); | ||
82 | |||
83 | let orig_width_scaled = solver.float_mul(&[scale_x, Float::Fixed(orig_width)]); | ||
84 | let width_constraint = | ||
85 | solver.float_eq(self.context.bounds().width, orig_width_scaled); | ||
86 | solver.constrain(width_constraint); | ||
87 | |||
88 | let orig_height_scaled = solver.float_mul(&[scale_y, Float::Fixed(orig_height)]); | ||
89 | let height_constraint = | ||
90 | solver.float_eq(self.context.bounds().height, orig_height_scaled); | ||
91 | solver.constrain(height_constraint); | ||
92 | } | ||
93 | _ => (), | ||
94 | } | ||
95 | } | ||
14 | } | 96 | } |
15 | 97 | ||
98 | #[derive(Debug, Clone)] | ||
16 | pub enum CoreShape { | 99 | pub enum CoreShape { |
17 | Rectangle(Rectangle), | 100 | Rectangle(Rectangle), |
18 | Text(Text), | 101 | Text(Text), |
19 | StraightPath(StraightPath), | 102 | StraightPath(StraightPath), |
103 | Image(Image), | ||
20 | } | 104 | } |
21 | 105 | ||
22 | impl From<Rectangle> for CoreShape { | 106 | impl From<Rectangle> for CoreShape { |
@@ -37,6 +121,12 @@ impl From<StraightPath> for CoreShape { | |||
37 | } | 121 | } |
38 | } | 122 | } |
39 | 123 | ||
124 | impl From<Image> for CoreShape { | ||
125 | fn from(image: Image) -> Self { | ||
126 | CoreShape::Image(image) | ||
127 | } | ||
128 | } | ||
129 | |||
40 | pub struct DefinedCoreDrawable { | 130 | pub struct DefinedCoreDrawable { |
41 | pub(crate) shape: DefinedCoreShape, | 131 | pub(crate) shape: DefinedCoreShape, |
42 | pub(crate) context: DefinedCoreShapeContext, | 132 | pub(crate) context: DefinedCoreShapeContext, |
@@ -46,72 +136,12 @@ pub enum DefinedCoreShape { | |||
46 | Rectangle(Rectangle), | 136 | Rectangle(Rectangle), |
47 | Text(DefinedText), | 137 | Text(DefinedText), |
48 | StraightPath(DefinedStraightPath), | 138 | StraightPath(DefinedStraightPath), |
139 | Image(Image), | ||
49 | } | 140 | } |
50 | 141 | ||
51 | /* | ||
52 | pub trait CoreShape { | ||
53 | fn constrain( | ||
54 | &self, | ||
55 | _context: &ShapeContext, | ||
56 | _solver: &mut dyn SolverContext, | ||
57 | _renderer: &dyn Renderer, | ||
58 | ) { | ||
59 | } | ||
60 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>>; | ||
61 | } | ||
62 | |||
63 | impl<T: CoreShape + Clone + 'static> ComplexShape for T { | ||
64 | fn as_core_shape(&self) -> Option<&dyn CoreShape> { | ||
65 | Some(self) | ||
66 | } | ||
67 | |||
68 | fn draw(&self, _context: &ShapeContext, _solver: &mut dyn SolverContext) -> DrawResult { | ||
69 | panic!("Tried to decompose core shape") | ||
70 | } | ||
71 | } | ||
72 | */ | ||
73 | |||
74 | #[derive(Copy, Clone, Debug, Default)] | 142 | #[derive(Copy, Clone, Debug, Default)] |
75 | pub struct Rectangle {} | 143 | pub struct Rectangle {} |
76 | 144 | ||
77 | /* | ||
78 | impl CoreShape for Rectangle { | ||
79 | fn to_render(&self, _model: &dyn SolverModel) -> Option<Box<dyn Render>> { | ||
80 | Some(Box::new(*self)) | ||
81 | } | ||
82 | } | ||
83 | */ | ||
84 | |||
85 | // TODO: re-enable this in some way | ||
86 | /* | ||
87 | impl CoreShape for Text { | ||
88 | fn constrain( | ||
89 | &self, | ||
90 | context: &ShapeContext, | ||
91 | solver: &mut dyn SolverContext, | ||
92 | renderer: &dyn Renderer, | ||
93 | ) { | ||
94 | let height_constraint = solver.float_eq(context.bounds.height, self.font.size); | ||
95 | solver.constrain(height_constraint); | ||
96 | |||
97 | // TODO: handle multiline | ||
98 | let (width, height) = renderer.text_extents(&self.content, &self.font); | ||
99 | dbg!(height); | ||
100 | |||
101 | let scale = solver.float_div(self.font.size, Float::Fixed(height)); | ||
102 | |||
103 | let calculated_width = solver.float_mul(&[Float::Fixed(width), scale]); | ||
104 | let width_constraint = solver.float_eq(context.bounds.width, calculated_width); | ||
105 | solver.constrain(width_constraint); | ||
106 | } | ||
107 | |||
108 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>> { | ||
109 | self.fixate(model) | ||
110 | .map(|path| -> Box<dyn Render> { Box::new(path) }) | ||
111 | } | ||
112 | } | ||
113 | */ | ||
114 | |||
115 | #[derive(Clone, Debug, Default)] | 145 | #[derive(Clone, Debug, Default)] |
116 | pub struct StraightPath { | 146 | pub struct StraightPath { |
117 | pub(crate) points: Vec<Point2D>, | 147 | pub(crate) points: Vec<Point2D>, |
@@ -127,11 +157,17 @@ pub struct DefinedStraightPath { | |||
127 | pub(crate) points: Vec<DefinedPoint2D>, | 157 | pub(crate) points: Vec<DefinedPoint2D>, |
128 | } | 158 | } |
129 | 159 | ||
130 | /* | 160 | #[derive(Clone, Debug, Default)] |
131 | impl CoreShape for StraightPath { | 161 | pub struct Image { |
132 | fn to_render(&self, model: &dyn SolverModel) -> Option<Box<dyn Render>> { | 162 | pub(crate) path: PathBuf, |
133 | self.fixate(model) | 163 | pub(crate) keep_aspect_ratio: bool, |
134 | .map(|path| -> Box<dyn Render> { Box::new(path) }) | 164 | } |
165 | |||
166 | impl Image { | ||
167 | pub fn new(path: PathBuf, keep_aspect_ratio: bool) -> Self { | ||
168 | Self { | ||
169 | path, | ||
170 | keep_aspect_ratio, | ||
171 | } | ||
135 | } | 172 | } |
136 | } | 173 | } |
137 | */ | ||
diff --git a/core/src/rendering.rs b/core/src/rendering.rs index 73daa2a..9c719c4 100644 --- a/core/src/rendering.rs +++ b/core/src/rendering.rs | |||
@@ -1,7 +1,11 @@ | |||
1 | use super::core_shapes::*; | 1 | use std::path::Path; |
2 | use super::styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern}; | 2 | |
3 | use super::text::{DefinedFontDescription, FontDescription}; | 3 | use crate::{ |
4 | use super::types::DefinedCoreShapeContext; | 4 | core_shapes::*, |
5 | styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern}, | ||
6 | text::{DefinedFontDescription, DefinedText, FontDescription}, | ||
7 | types::DefinedCoreShapeContext, | ||
8 | }; | ||
5 | 9 | ||
6 | pub trait Renderer { | 10 | pub trait Renderer { |
7 | // Must be called once before any drawing happens | 11 | // Must be called once before any drawing happens |
@@ -19,6 +23,9 @@ pub trait Renderer { | |||
19 | // For a font of size 1. | 23 | // For a font of size 1. |
20 | fn text_extents(&self, text: &str, font: &FontDescription) -> (f64, f64); | 24 | fn text_extents(&self, text: &str, font: &FontDescription) -> (f64, f64); |
21 | fn show_text(&mut self, text: &str, font: &DefinedFontDescription); | 25 | fn show_text(&mut self, text: &str, font: &DefinedFontDescription); |
26 | |||
27 | fn show_image(&mut self, path: &Path, x: f64, y: f64, width: f64, height: f64); | ||
28 | fn geometry_for_image(&mut self, path: &Path) -> (f64, f64); | ||
22 | } | 29 | } |
23 | 30 | ||
24 | pub trait Render { | 31 | pub trait Render { |
@@ -31,6 +38,7 @@ impl Render for DefinedCoreShape { | |||
31 | Self::Rectangle(r) => r.render(context, renderer), | 38 | Self::Rectangle(r) => r.render(context, renderer), |
32 | Self::Text(t) => t.render(context, renderer), | 39 | Self::Text(t) => t.render(context, renderer), |
33 | Self::StraightPath(p) => p.render(context, renderer), | 40 | Self::StraightPath(p) => p.render(context, renderer), |
41 | Self::Image(i) => i.render(context, renderer), | ||
34 | } | 42 | } |
35 | } | 43 | } |
36 | } | 44 | } |
@@ -96,3 +104,16 @@ impl Render for DefinedStraightPath { | |||
96 | draw(&context.fill, &context.stroke, renderer); | 104 | draw(&context.fill, &context.stroke, renderer); |
97 | } | 105 | } |
98 | } | 106 | } |
107 | |||
108 | impl Render for Image { | ||
109 | fn render(&self, context: DefinedCoreShapeContext, renderer: &mut dyn Renderer) { | ||
110 | // TODO: what about pattern, and fill color? Do we do something with that? | ||
111 | renderer.show_image( | ||
112 | &self.path, | ||
113 | context.bounds.left, | ||
114 | context.bounds.top, | ||
115 | context.bounds.width, | ||
116 | context.bounds.height, | ||
117 | ); | ||
118 | } | ||
119 | } | ||
diff --git a/core/src/runtime.rs b/core/src/runtime.rs index 6b1b5d1..5fd17e9 100644 --- a/core/src/runtime.rs +++ b/core/src/runtime.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | use crate::core_shapes::CoreDrawable; | 1 | use crate::{ |
2 | use crate::rendering::Render; | 2 | core_shapes::CoreDrawable, |
3 | use crate::types::Bounds; | 3 | rendering::{Render, Renderer}, |
4 | 4 | solving::{Constrainable, SolverContext}, | |
5 | // use super::complex_shapes::{ComplexShape, Drawable}; | 5 | types::Bounds, |
6 | use super::rendering::Renderer; | 6 | }; |
7 | use super::solving::{Constrainable, SolverContext}; | ||
8 | 7 | ||
8 | // TODO: | ||
9 | // const RECURSION_LIMIT: u64 = 10_000; | 9 | // const RECURSION_LIMIT: u64 = 10_000; |
10 | 10 | ||
11 | pub struct Runtime<'a> { | 11 | pub struct Runtime<'a> { |
@@ -20,15 +20,10 @@ impl<'a> Runtime<'a> { | |||
20 | Self { | 20 | Self { |
21 | solver_ctx, | 21 | solver_ctx, |
22 | renderer, | 22 | renderer, |
23 | // drawables: Vec::new(), | ||
24 | drawables: Vec::new(), | 23 | drawables: Vec::new(), |
25 | } | 24 | } |
26 | } | 25 | } |
27 | 26 | ||
28 | // pub fn add_drawable<T: ComplexShape + 'static>(&mut self, drawable: Drawable<T>) { | ||
29 | // self.drawables.push(drawable.into()) | ||
30 | // } | ||
31 | |||
32 | pub fn add_drawable(&mut self, drawable: CoreDrawable) { | 27 | pub fn add_drawable(&mut self, drawable: CoreDrawable) { |
33 | self.drawables.push(drawable) | 28 | self.drawables.push(drawable) |
34 | } | 29 | } |
@@ -41,88 +36,34 @@ impl<'a> Runtime<'a> { | |||
41 | &mut *self.renderer | 36 | &mut *self.renderer |
42 | } | 37 | } |
43 | 38 | ||
44 | pub fn render(mut self, bounds: Bounds) { | 39 | pub fn render(self, bounds: Bounds) { |
45 | let model = self.solver_ctx.solve(); | 40 | // Separate self into several variables, so we can get mutable references to each at the |
41 | // same time | ||
42 | let Runtime { | ||
43 | mut solver_ctx, | ||
44 | mut renderer, | ||
45 | drawables, | ||
46 | } = self; | ||
47 | |||
48 | for drawable in &drawables { | ||
49 | drawable.inherent_constraints(&mut *solver_ctx, &mut *renderer); | ||
50 | } | ||
51 | |||
52 | let model = solver_ctx.solve(); | ||
46 | 53 | ||
47 | let bounds = bounds | 54 | let bounds = bounds |
48 | .fixate(&*model) | 55 | .fixate(&*model) |
49 | .expect("Could not fixate figure bounds"); | 56 | .expect("Could not fixate figure bounds"); |
50 | 57 | ||
51 | self.renderer.set_size(bounds.width, bounds.height); | 58 | renderer.set_size(bounds.width, bounds.height); |
52 | 59 | ||
53 | for drawable in &self.drawables { | 60 | for drawable in &drawables { |
54 | let defined_drawable = drawable | 61 | let defined_drawable = drawable |
55 | .fixate(&*model) | 62 | .fixate(&*model) |
56 | .expect("Could not fixate core shape"); | 63 | .expect("Could not fixate core shape"); |
57 | defined_drawable | 64 | defined_drawable |
58 | .shape | 65 | .shape |
59 | .render(defined_drawable.context, &mut *self.renderer); | 66 | .render(defined_drawable.context, &mut *renderer); |
60 | } | 67 | } |
61 | } | 68 | } |
62 | |||
63 | // TODO: preserve ordering of shapes | ||
64 | // pub fn render(mut self) { | ||
65 | // let mut drawables = self.drawables; | ||
66 | // let mut waited_on_variables = Vec::new(); | ||
67 | // let mut core_shapes = Vec::new(); | ||
68 | // | ||
69 | // /* | ||
70 | // for drawable in &self.shapes { | ||
71 | // let bounds = &drawable.bounds; | ||
72 | // let shape = &drawable.shape; | ||
73 | // | ||
74 | // if let Some(core_shape) = shape.to_render() { | ||
75 | // drawables.push((*drawable).clone()); | ||
76 | // continue; | ||
77 | // } | ||
78 | // | ||
79 | // let mut result = shape.draw(bounds); | ||
80 | // drawables.append(&mut result.subshapes); | ||
81 | // waited_on_variables.append(&mut result.waiting_on); | ||
82 | // } | ||
83 | // */ | ||
84 | // | ||
85 | // let mut recursion_count = 0; | ||
86 | // | ||
87 | // while !drawables.is_empty() { | ||
88 | // recursion_count += 1; | ||
89 | // | ||
90 | // if recursion_count > RECURSION_LIMIT { | ||
91 | // panic!("Recursion limit reached"); | ||
92 | // } | ||
93 | // | ||
94 | // let mut tmp_drawables = Vec::new(); | ||
95 | // | ||
96 | // for drawable in drawables.drain(..) { | ||
97 | // let shape_ctx = &drawable.context; | ||
98 | // let shape = &drawable.shape; | ||
99 | // | ||
100 | // if let Some(core_shape) = shape.as_core_shape() { | ||
101 | // core_shape.constrain(shape_ctx, &mut *self.solver_ctx, &*self.renderer); | ||
102 | // core_shapes.push((shape.dyn_clone(), shape_ctx.clone())); // Better to Arc? Cow? | ||
103 | // continue; | ||
104 | // } | ||
105 | // | ||
106 | // let mut result = shape.draw(shape_ctx, &mut *self.solver_ctx); | ||
107 | // tmp_drawables.append(&mut result.subshapes); | ||
108 | // waited_on_variables.append(&mut result.waiting_on); | ||
109 | // } | ||
110 | // | ||
111 | // drawables = tmp_drawables; | ||
112 | // } | ||
113 | // | ||
114 | // let model = self.solver_ctx.solve(); | ||
115 | // | ||
116 | // // Delay rendering core shapes until later to have all the constraints | ||
117 | // for (core_shape, shape_ctx) in core_shapes { | ||
118 | // let core_shape = core_shape.as_core_shape().unwrap(); | ||
119 | // | ||
120 | // match (core_shape.to_render(&*model), shape_ctx.fixate(&*model)) { | ||
121 | // (Some(defined_shape), Some(shape_ctx)) => { | ||
122 | // defined_shape.render(shape_ctx, &mut *self.renderer) | ||
123 | // } | ||
124 | // _ => panic!("Failed to fixate core shape"), | ||
125 | // } | ||
126 | // } | ||
127 | // } | ||
128 | } | 69 | } |
diff --git a/core/src/solving.rs b/core/src/solving.rs index bfe3ff3..63e4562 100644 --- a/core/src/solving.rs +++ b/core/src/solving.rs | |||
@@ -176,11 +176,13 @@ pub trait Constrainable { | |||
176 | impl Constrainable for CoreShape { | 176 | impl Constrainable for CoreShape { |
177 | type Fixated = DefinedCoreShape; | 177 | type Fixated = DefinedCoreShape; |
178 | 178 | ||
179 | // TODO: why &self, why not self? | ||
179 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | 180 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { |
180 | match self { | 181 | match self { |
181 | CoreShape::Rectangle(r) => Some(DefinedCoreShape::Rectangle(*r)), | 182 | CoreShape::Rectangle(r) => Some(DefinedCoreShape::Rectangle(*r)), |
182 | CoreShape::Text(t) => t.fixate(model).map(DefinedCoreShape::Text), | 183 | CoreShape::Text(t) => t.fixate(model).map(DefinedCoreShape::Text), |
183 | CoreShape::StraightPath(p) => p.fixate(model).map(DefinedCoreShape::StraightPath), | 184 | CoreShape::StraightPath(p) => p.fixate(model).map(DefinedCoreShape::StraightPath), |
185 | CoreShape::Image(i) => Some(DefinedCoreShape::Image(i.clone())), | ||
184 | } | 186 | } |
185 | } | 187 | } |
186 | } | 188 | } |