summaryrefslogtreecommitdiffstats
path: root/core/src
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2023-02-03 19:59:43 +0100
committerMinijackson <minijackson@riseup.net>2023-02-03 19:59:43 +0100
commit82ffe3187a32bad4ecca0736882a23793a800822 (patch)
tree2d3ab9231b76dadcf2ab69b27053df6cc66bead1 /core/src
parentc8bb3e4a24ca1ca6ec1a57c9e8cd8655483b3eb0 (diff)
downloaddiaphragm-82ffe3187a32bad4ecca0736882a23793a800822.tar.gz
diaphragm-82ffe3187a32bad4ecca0736882a23793a800822.zip
add support for images, and some chores
- SVG files not yet supported - Remove dead commented code - Add inherent constraints for text, path, and images - Formatting
Diffstat (limited to 'core/src')
-rw-r--r--core/src/core_shapes.rs174
-rw-r--r--core/src/rendering.rs29
-rw-r--r--core/src/runtime.rs107
-rw-r--r--core/src/solving.rs2
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 @@
1use crate::types::{CoreShapeContext, DefinedCoreShapeContext, DefinedPoint2D, Point2D}; 1use std::path::PathBuf;
2 2
3pub use super::text::{DefinedText, Text}; 3use crate::{
4 text::{DefinedText, Text},
5 types::{CoreShapeContext, DefinedCoreShapeContext, DefinedPoint2D, Float, Point2D},
6 Renderer, SolverContext,
7};
4 8
9#[derive(Debug, Clone)]
5pub struct CoreDrawable { 10pub 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)]
16pub enum CoreShape { 99pub 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
22impl From<Rectangle> for CoreShape { 106impl From<Rectangle> for CoreShape {
@@ -37,6 +121,12 @@ impl From<StraightPath> for CoreShape {
37 } 121 }
38} 122}
39 123
124impl From<Image> for CoreShape {
125 fn from(image: Image) -> Self {
126 CoreShape::Image(image)
127 }
128}
129
40pub struct DefinedCoreDrawable { 130pub 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/*
52pub 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
63impl<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)]
75pub struct Rectangle {} 143pub struct Rectangle {}
76 144
77/*
78impl 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/*
87impl 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)]
116pub struct StraightPath { 146pub 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)]
131impl CoreShape for StraightPath { 161pub 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
166impl 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 @@
1use super::core_shapes::*; 1use std::path::Path;
2use super::styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern}; 2
3use super::text::{DefinedFontDescription, FontDescription}; 3use crate::{
4use super::types::DefinedCoreShapeContext; 4 core_shapes::*,
5 styles::{DefinedDashStyle, DefinedStrokeStyle, FillStyle, Pattern},
6 text::{DefinedFontDescription, DefinedText, FontDescription},
7 types::DefinedCoreShapeContext,
8};
5 9
6pub trait Renderer { 10pub 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
24pub trait Render { 31pub 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
108impl 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 @@
1use crate::core_shapes::CoreDrawable; 1use crate::{
2use crate::rendering::Render; 2 core_shapes::CoreDrawable,
3use crate::types::Bounds; 3 rendering::{Render, Renderer},
4 4 solving::{Constrainable, SolverContext},
5// use super::complex_shapes::{ComplexShape, Drawable}; 5 types::Bounds,
6use super::rendering::Renderer; 6};
7use super::solving::{Constrainable, SolverContext};
8 7
8// TODO:
9// const RECURSION_LIMIT: u64 = 10_000; 9// const RECURSION_LIMIT: u64 = 10_000;
10 10
11pub struct Runtime<'a> { 11pub 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 {
176impl Constrainable for CoreShape { 176impl 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}