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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
use diaphragm_core::{
core_shapes::Rectangle,
core_shapes::Text,
text::FontDescription,
types::{Bounds, Float, ShapeContext},
ComplexShape, DrawResult, Drawable, DynDrawable, SolverContext,
};
#[derive(Clone)]
pub struct Entry {
// TODO: transform this to just Text
pub label: Option<String>,
pub label_vert_center_offset: Option<Float>,
pub content: DynDrawable,
}
#[derive(Clone)]
pub struct Layer {
// TODO: transform this to just Text
pub name: String,
pub name_font: FontDescription,
pub label_font: FontDescription,
pub padding: Float,
pub entries: Vec<Entry>,
pub entries_width: Float,
}
impl ComplexShape for Layer {
fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
let mut result = DrawResult::new();
let bounds_top = context.bounds().top(solver);
let bounds_left = context.bounds().left(solver);
let bounds_right = context.bounds().right(solver);
let bounds_height = context.bounds().height(solver);
let inner_top = solver.float_add(&[bounds_top, self.padding]);
let inner_right = solver.float_sub(&[bounds_right, self.padding]);
// Outer box
result.push(Drawable::new(Rectangle {}, context.clone()));
// Layer name
let layer_name = Drawable::builder(Text {
content: self.name.clone(),
font: self.name_font.clone(),
})
.bounds(
Bounds::builder()
.top(inner_top)
.left(solver.float_add(&[bounds_left, self.padding]))
.build(solver),
)
.stroke(context.stroke().clone())
.fill(context.fill().clone())
.build(solver);
let layer_name_bottom = layer_name.bounds().bottom(solver);
/*
let mut rect_context = layer_name_context.clone();
rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
result.push_shape(Rectangle {}, rect_context);
*/
result.push(layer_name);
// Entries
let mut entry_y_acc = inner_top;
for entry in &self.entries {
// Entry content
/*
let content_context = ShapeContext {
bounds: Bounds {
top: solver.new_free_float(),
left: content_left,
width: entry.width,
height: entry.height,
},
fill: Default::default(),
stroke: Default::default(),
};
*/
let content_vert_center = entry.content.bounds().vert_center(solver);
let content_top = entry.content.bounds().top(solver);
let content_left = entry.content.bounds().left(solver);
let content_bottom = entry.content.bounds().bottom(solver);
// TODO: to replace with label offset
let content_half_height = solver.float_sub(&[content_vert_center, content_top]);
result.push_dyn(entry.content.clone());
// Entry label
if let Some(label_content) = entry.label.clone() {
let label_top = solver.new_free_float();
let label_width = solver.new_free_float();
let label_left = solver.float_sub(&[inner_right, self.entries_width, label_width]);
let label = Drawable::builder(Text {
content: label_content,
font: self.label_font.clone(),
})
.bounds(
Bounds::builder()
.top(label_top)
.left(label_left)
.width(label_width)
.build(solver),
)
.build(solver);
/*
let mut rect_context = label_context.clone();
rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
result.push_shape(Rectangle {}, rect_context);
*/
// TODO
let label_vert_center = label.bounds().vert_center(solver);
let label_top = label.bounds().top(solver);
let label_right = label.bounds().right(solver);
let label_vert_center_constraint =
solver.float_eq(label_vert_center, content_vert_center);
solver.constrain(label_vert_center_constraint);
let label_half_height = solver.float_sub(&[label_vert_center, label_top]);
let dumb_label_mid_placement =
solver.float_add(&[entry_y_acc, content_half_height]);
let safe_label_mid_placement =
solver.float_add(&[layer_name_bottom, label_half_height]);
let label_mid_placement =
solver.float_max(&[safe_label_mid_placement, dumb_label_mid_placement]);
let label_mid_placement_constraint =
solver.float_eq(label_vert_center, label_mid_placement);
solver.constrain(label_mid_placement_constraint);
let label_right_constraint = solver.float_eq(label_right, content_left);
solver.constrain(label_right_constraint);
result.push(label);
} else {
let content_top_constraint = solver.float_eq(content_top, entry_y_acc);
solver.constrain(content_top_constraint);
let wanted_content_left = solver.float_sub(&[inner_right, self.entries_width]);
let content_left_constraint = solver.float_eq(content_left, wanted_content_left);
solver.constrain(content_left_constraint);
}
entry_y_acc = solver.float_add(&[content_bottom, self.padding]);
}
let wanted_bounds_height = solver.float_sub(&[entry_y_acc, bounds_top]);
let height_constraint = solver.float_eq(bounds_height, wanted_bounds_height);
solver.constrain(height_constraint);
result
}
}
|