1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
use diaphragm_core::{
core_shapes::{StraightPath, Text},
types::{Bounds, Float, Point2D, ShapeContext},
ComplexShape, DrawResult, Drawable, SolverContext,
};
#[derive(Debug, Clone)]
pub struct Delimiter {
pub width: Float,
pub label: Drawable<Text>,
}
#[derive(Debug, Clone)]
pub struct LabeledDelimiter {
pub delimiters: Vec<Delimiter>,
pub tick_height: Float,
}
impl ComplexShape for LabeledDelimiter {
fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
let mut result = DrawResult::new();
let bounds_left = context.bounds().left(solver);
let bounds_right = context.bounds().right(solver);
let bounds_bottom = context.bounds().bottom(solver);
let bounds_width = context.bounds().width(solver);
let tick_top = context.bounds().top(solver);
let tick_bottom = solver.float_add(&[tick_top, self.tick_height]);
let first_tick = Drawable::builder(StraightPath::new(vec![
context.bounds().top_left(solver),
Point2D::new(bounds_left, tick_bottom),
]))
.bounds(
Bounds::builder()
.top(tick_top)
.left(bounds_left)
.height(self.tick_height)
.width(Float::Fixed(0.))
.build(solver),
)
.stroke(context.stroke().clone())
.build(solver);
let baseline_y = first_tick.bounds().vert_center(solver);
result.push(first_tick);
// TODO: split everything into functions
let baseline = Drawable::builder(StraightPath::new(vec![
Point2D::new(bounds_left, baseline_y),
Point2D::new(bounds_right, baseline_y),
]))
.bounds(
Bounds::builder()
.top(baseline_y)
.left(bounds_left)
.width(bounds_width)
.height(Float::Fixed(0.))
.build(solver),
)
.stroke(context.stroke().clone())
.build(solver);
result.push(baseline);
let mut section_end = bounds_left;
let mut all_label_bottoms = vec![];
for &Delimiter {
width: section_width,
ref label,
} in &self.delimiters
{
let section_begin = section_end;
section_end = solver.float_add(&[section_end, section_width]);
let section_half_width = solver.float_div(section_width, Float::Fixed(2.));
let section_middle = solver.float_add(&[section_begin, section_half_width]);
let tick = Drawable::builder(StraightPath::new(vec![
Point2D::new(section_end, tick_top),
Point2D::new(section_end, tick_bottom),
]))
.bounds(
Bounds::builder()
.top(tick_top)
.left(section_end)
.height(self.tick_height)
.width(Float::Fixed(0.))
.build(solver),
)
.stroke(context.stroke().clone())
.build(solver);
result.push(tick);
let label_top = label.bounds().top(solver);
let label_bottom = label.bounds().bottom(solver);
let label_horiz_center = label.bounds().horiz_center(solver);
let label_top_constraint = solver.float_eq(label_top, tick_bottom);
solver.constrain(label_top_constraint);
let label_middle_constraint = solver.float_eq(label_horiz_center, section_middle);
solver.constrain(label_middle_constraint);
result.push(label.clone());
all_label_bottoms.push(label_bottom);
}
let wanted_bounds_bottom = solver.float_max(&all_label_bottoms);
let bounds_bottom_constraint = solver.float_eq(bounds_bottom, wanted_bounds_bottom);
solver.constrain(bounds_bottom_constraint);
result
}
}
|