diff options
Diffstat (limited to 'examples/lib-dfscq-log/src/main.rs')
-rw-r--r-- | examples/lib-dfscq-log/src/main.rs | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/examples/lib-dfscq-log/src/main.rs b/examples/lib-dfscq-log/src/main.rs new file mode 100644 index 0000000..fe5db9a --- /dev/null +++ b/examples/lib-dfscq-log/src/main.rs | |||
@@ -0,0 +1,642 @@ | |||
1 | mod block_list; | ||
2 | mod blocks; | ||
3 | mod bracket; | ||
4 | mod explode; | ||
5 | mod labeled_delimiter; | ||
6 | mod layer; | ||
7 | mod spacer; | ||
8 | |||
9 | //mod labeled; | ||
10 | //use labeled::Labeled; | ||
11 | |||
12 | use block_list::BlockList; | ||
13 | use blocks::*; | ||
14 | use explode::*; | ||
15 | use labeled_delimiter::*; | ||
16 | use layer::*; | ||
17 | use spacer::*; | ||
18 | |||
19 | use diaphragm_cairo_renderer::CairoRenderer; | ||
20 | use diaphragm_core::{ | ||
21 | colors::Color, | ||
22 | core_shapes::{Text}, | ||
23 | styles::*, | ||
24 | text::FontDescription, | ||
25 | types::*, | ||
26 | *, | ||
27 | }; | ||
28 | use diaphragm_z3_solver::{z3, Z3Context}; | ||
29 | |||
30 | fn main() { | ||
31 | let z3_cfg = z3::Config::new(); | ||
32 | let z3_ctx = z3::Context::new(&z3_cfg); | ||
33 | let ctx = Z3Context::new(&z3_ctx); | ||
34 | |||
35 | let cairo_renderer = CairoRenderer::new(); | ||
36 | |||
37 | let mut runtime = Runtime::new(Box::new(ctx), Box::new(cairo_renderer)); | ||
38 | |||
39 | let solver = runtime.solver_ctx(); | ||
40 | |||
41 | let blue = Color::from_rgb(0.35, 0.35, 1.); | ||
42 | let light_grey = Color::from_rgb(0.8, 0.8, 0.8); | ||
43 | let dark_grey = Color::from_rgb(0.5, 0.5, 0.5); | ||
44 | |||
45 | // ----------------8<---------------- | ||
46 | |||
47 | /* | ||
48 | let mut make_blocks = |grows: &[u8]| { | ||
49 | grows | ||
50 | .iter() | ||
51 | .map(|&grow| { | ||
52 | Drawable::builder(Block { grow }) | ||
53 | .fill(FillStyle::solid(blue)) | ||
54 | .build(solver) | ||
55 | }) | ||
56 | .collect() | ||
57 | }; | ||
58 | |||
59 | let blocks = Drawable::builder(Blocks { | ||
60 | blocks: make_blocks(&[1, 2, 1, 1, 4, 1, 1]), | ||
61 | unit_width: solver.new_free_float(), | ||
62 | }) | ||
63 | .bounds( | ||
64 | Bounds::builder() | ||
65 | .top(Float::Fixed(20.)) | ||
66 | .left(Float::Fixed(20.)) | ||
67 | .width(Float::Fixed(150.)) | ||
68 | .height(Float::Fixed(50.)) | ||
69 | .build(solver), | ||
70 | ) | ||
71 | .build(solver); | ||
72 | |||
73 | runtime.add_drawable(blocks); | ||
74 | */ | ||
75 | |||
76 | // ----------------8<---------------- | ||
77 | |||
78 | /* | ||
79 | let block_unit_width = solver.new_fixed_float(10.); | ||
80 | |||
81 | fn color_block(grow: u8, color: Color, solver: &mut dyn SolverContext) -> Drawable<Block> { | ||
82 | Drawable::builder(Block { grow }) | ||
83 | .fill(FillStyle::solid(color)) | ||
84 | .build(solver) | ||
85 | }; | ||
86 | |||
87 | fn blocks(block_descs: &[(u8, Color)], solver: &mut dyn SolverContext) -> Drawable<Blocks> { | ||
88 | let mut blocks = Vec::new(); | ||
89 | |||
90 | for &(grow, color) in block_descs { | ||
91 | blocks.push(color_block(grow, color, solver)); | ||
92 | } | ||
93 | |||
94 | Drawable::builder(Blocks { | ||
95 | blocks, | ||
96 | unit_width: solver.new_free_float(), | ||
97 | }) | ||
98 | .build(solver) | ||
99 | } | ||
100 | |||
101 | let block_list = Drawable::builder(BlockList { | ||
102 | block_list: vec![ | ||
103 | blocks(&[(1, light_grey), (1, light_grey), (1, light_grey)], solver), | ||
104 | blocks( | ||
105 | &[ | ||
106 | (1, light_grey), | ||
107 | (2, blue), | ||
108 | (1, light_grey), | ||
109 | (1, light_grey), | ||
110 | (1, light_grey), | ||
111 | ], | ||
112 | solver, | ||
113 | ), | ||
114 | blocks(&[(3, light_grey), (2, blue)], solver), | ||
115 | ], | ||
116 | block_unit_width, | ||
117 | bracket_width: block_unit_width, | ||
118 | blocks_vert_padding: block_unit_width, | ||
119 | }) | ||
120 | .bounds( | ||
121 | Bounds::builder() | ||
122 | .top(Float::Fixed(10.)) | ||
123 | .left(Float::Fixed(10.)) | ||
124 | .height(Float::Fixed(40.)) | ||
125 | .build(solver), | ||
126 | ) | ||
127 | .build(solver); | ||
128 | |||
129 | runtime.add_drawable(block_list); | ||
130 | */ | ||
131 | |||
132 | // ----------------8<---------------- | ||
133 | |||
134 | /* | ||
135 | let label_font = FontDescription { | ||
136 | family: String::from("mono"), | ||
137 | style: Default::default(), | ||
138 | weight: Default::default(), | ||
139 | size: Float::Fixed(15.), | ||
140 | }; | ||
141 | |||
142 | let layer = Drawable::builder(Layer { | ||
143 | name: String::from("Hello"), | ||
144 | name_font: FontDescription { | ||
145 | family: Default::default(), | ||
146 | style: Default::default(), | ||
147 | weight: Default::default(), | ||
148 | size: Float::Fixed(10.), | ||
149 | }, | ||
150 | entries: vec![], | ||
151 | padding: Float::Fixed(5.), | ||
152 | entries_width: Float::Fixed(50.), | ||
153 | label_font, | ||
154 | }) | ||
155 | .bounds(Bounds::builder() | ||
156 | .top(Float::Fixed(10.)) | ||
157 | .left(Float::Fixed(10.)) | ||
158 | .width(Float::Fixed(100.)) | ||
159 | .height(Float::Fixed(40.)) | ||
160 | .build(solver)) | ||
161 | .build(solver); | ||
162 | |||
163 | runtime.add_drawable(layer); | ||
164 | */ | ||
165 | |||
166 | // ----------------8<---------------- | ||
167 | |||
168 | let title_font = FontDescription { | ||
169 | family: String::from("Fanwood"), | ||
170 | style: Default::default(), | ||
171 | weight: Default::default(), | ||
172 | size: Float::Fixed(30.), | ||
173 | }; | ||
174 | |||
175 | let label_font = FontDescription { | ||
176 | family: String::from("mono"), | ||
177 | style: Default::default(), | ||
178 | weight: Default::default(), | ||
179 | size: Float::Fixed(15.), | ||
180 | }; | ||
181 | |||
182 | let layer_padding = Float::Fixed(15.); | ||
183 | let layer_margin = Float::Fixed(15.); | ||
184 | //let layer_height = Float::Fixed(40.); | ||
185 | let layer_left_content_padding = Float::Fixed(240.); | ||
186 | //let layer_width = solver.new_free_float(); | ||
187 | //let layer_width_constraint = solver.float_eq(layer_width, Float::Fixed(100.)); | ||
188 | //solver.constrain(layer_width_constraint); | ||
189 | |||
190 | let mut layer_top = Float::Fixed(15.); | ||
191 | |||
192 | let entries_width = solver.new_free_float(); | ||
193 | let mut all_entry_content_widths = vec![]; | ||
194 | |||
195 | let layer_width = solver.float_add(&[ | ||
196 | layer_left_content_padding, | ||
197 | entries_width, | ||
198 | layer_padding, | ||
199 | layer_padding, | ||
200 | ]); | ||
201 | |||
202 | let blocks_vert_padding = Float::Fixed(10.); | ||
203 | |||
204 | let block_unit_width = Float::Fixed(20.); | ||
205 | |||
206 | let blocks_height = Float::Fixed(26.); | ||
207 | let block_list_height = | ||
208 | solver.float_add(&[blocks_height, blocks_vert_padding, blocks_vert_padding]); | ||
209 | |||
210 | let blue_transaction_len = 5; | ||
211 | |||
212 | let blocks = |grows: &[u8], color, solver: &mut dyn SolverContext| { | ||
213 | let mut blocks = Vec::new(); | ||
214 | |||
215 | for &grow in grows { | ||
216 | blocks.push( | ||
217 | Drawable::builder(Block { grow }) | ||
218 | .fill(FillStyle::solid(color)) | ||
219 | .build(solver), | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | Drawable::builder(Blocks { | ||
224 | blocks, | ||
225 | unit_width: block_unit_width, | ||
226 | }) | ||
227 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
228 | .build(solver) | ||
229 | }; | ||
230 | |||
231 | let blocks_by_len = | ||
232 | |len, color, solver: &mut dyn SolverContext| blocks(&vec![1; len], color, solver); | ||
233 | |||
234 | // Log API | ||
235 | { | ||
236 | let blocks = blocks_by_len(blue_transaction_len, blue, solver); | ||
237 | let blocks_width = blocks.bounds().width(solver); | ||
238 | |||
239 | let layer = Drawable::builder(Layer { | ||
240 | name: String::from("LogAPI"), | ||
241 | name_font: title_font.clone(), | ||
242 | label_font: label_font.clone(), | ||
243 | padding: layer_padding, | ||
244 | entries: vec![Entry { | ||
245 | label: Some(String::from("activeTxn: ")), | ||
246 | label_vert_center_offset: None, | ||
247 | content: blocks.into(), | ||
248 | }], | ||
249 | entries_width, | ||
250 | }) | ||
251 | .bounds( | ||
252 | Bounds::builder() | ||
253 | // TODO: Replace that with a "distributeHorizontally" that applies to all layer | ||
254 | .top(layer_top) | ||
255 | .left(Float::Fixed(10.)) | ||
256 | .width(layer_width) | ||
257 | .build(solver), | ||
258 | ) | ||
259 | .build(solver); | ||
260 | |||
261 | all_entry_content_widths.push(blocks_width); | ||
262 | |||
263 | let layer_height = layer.bounds().height(solver); | ||
264 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
265 | |||
266 | runtime.add_drawable(layer); | ||
267 | } | ||
268 | |||
269 | let solver = runtime.solver_ctx(); | ||
270 | |||
271 | let other_transactions = [2, 7, 4]; | ||
272 | |||
273 | let group_commit_left; | ||
274 | let group_commit_right; | ||
275 | let group_commit_bottom; | ||
276 | |||
277 | // Group Commit | ||
278 | { | ||
279 | let mut block_list = Vec::new(); | ||
280 | for &blocks_count in other_transactions.iter() { | ||
281 | block_list.push(blocks_by_len(blocks_count, dark_grey, solver)); | ||
282 | } | ||
283 | |||
284 | block_list.push(blocks_by_len(blue_transaction_len, blue, solver)); | ||
285 | |||
286 | let block_list = Drawable::builder(BlockList { | ||
287 | block_list, | ||
288 | block_unit_width, | ||
289 | blocks_vert_padding: Float::Fixed(10.), | ||
290 | bracket_width: Float::Fixed(10.), | ||
291 | }) | ||
292 | .bounds(Bounds::builder().height(block_list_height).build(solver)) | ||
293 | .build(solver); | ||
294 | |||
295 | let content_width = block_list.bounds().width(solver); | ||
296 | |||
297 | group_commit_left = block_list.bounds().left(solver); | ||
298 | group_commit_right = block_list.bounds().right(solver); | ||
299 | group_commit_bottom = block_list.bounds().bottom(solver); | ||
300 | |||
301 | let layer = Drawable::builder(Layer { | ||
302 | name: String::from("GroupCommit"), | ||
303 | name_font: title_font.clone(), | ||
304 | label_font: label_font.clone(), | ||
305 | padding: layer_padding, | ||
306 | entries: vec![Entry { | ||
307 | label: Some(String::from("commitedTxns: ")), | ||
308 | label_vert_center_offset: None, | ||
309 | content: block_list.into(), | ||
310 | }], | ||
311 | entries_width, | ||
312 | }) | ||
313 | .bounds( | ||
314 | Bounds::builder() | ||
315 | .top(layer_top) | ||
316 | .left(Float::Fixed(10.)) | ||
317 | .width(layer_width) | ||
318 | .build(solver), | ||
319 | ) | ||
320 | .build(solver); | ||
321 | |||
322 | all_entry_content_widths.push(content_width); | ||
323 | |||
324 | let layer_height = layer.bounds().height(solver); | ||
325 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
326 | |||
327 | runtime.add_drawable(layer); | ||
328 | } | ||
329 | |||
330 | let solver = runtime.solver_ctx(); | ||
331 | |||
332 | let commit_in_log_left; | ||
333 | let commit_in_log_right; | ||
334 | let commit_in_log_top; | ||
335 | let big_block_grow; | ||
336 | let small_block_unit_width; | ||
337 | let data_in_log_left; | ||
338 | let data_in_log_right; | ||
339 | let data_in_log_bottom; | ||
340 | |||
341 | // Disk log | ||
342 | { | ||
343 | big_block_grow = (blue_transaction_len + other_transactions.iter().sum::<usize>()) as u8; | ||
344 | |||
345 | let make_block = |grow, color, solver: &mut dyn SolverContext| { | ||
346 | Drawable::builder(Block { grow }) | ||
347 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
348 | .fill(FillStyle::solid(color)) | ||
349 | .build(solver) | ||
350 | }; | ||
351 | |||
352 | let make_blocks = |block_descs: &[_], solver: &mut dyn SolverContext| { | ||
353 | let mut blocks = Vec::new(); | ||
354 | |||
355 | for &(grow, color) in block_descs { | ||
356 | blocks.push(make_block(grow, color, solver)); | ||
357 | } | ||
358 | |||
359 | blocks | ||
360 | }; | ||
361 | |||
362 | let header_block = make_block(big_block_grow, Color::black(), solver); | ||
363 | let header_block_width = header_block.bounds().width(solver); | ||
364 | |||
365 | let mut blocks = vec![header_block]; | ||
366 | |||
367 | blocks.append(&mut make_blocks( | ||
368 | &[(big_block_grow, light_grey), (big_block_grow, light_grey)], | ||
369 | solver, | ||
370 | )); | ||
371 | |||
372 | let sample_commit_start_id = blocks.len(); | ||
373 | |||
374 | for &txn_block_count in other_transactions.iter() { | ||
375 | for _i in 0..txn_block_count { | ||
376 | blocks.push(make_block(1, dark_grey, solver)); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | for _ in 0..blue_transaction_len { | ||
381 | blocks.push(make_block(1, blue, solver)); | ||
382 | } | ||
383 | |||
384 | let sample_commit_end_id = blocks.len() - 1; | ||
385 | |||
386 | commit_in_log_left = blocks[sample_commit_start_id].bounds().left(solver); | ||
387 | commit_in_log_right = blocks[sample_commit_end_id].bounds().right(solver); | ||
388 | commit_in_log_top = blocks[sample_commit_end_id].bounds().top(solver); | ||
389 | |||
390 | let log_data_blocks_widths: Vec<_> = blocks[1..] | ||
391 | .iter() | ||
392 | .map(|block| block.bounds().width(solver)) | ||
393 | .collect(); | ||
394 | let log_data_blocks_width = solver.float_add(&log_data_blocks_widths); | ||
395 | |||
396 | let log_space_block = make_block(big_block_grow, Color::white(), solver); | ||
397 | let log_space_width = log_space_block.bounds().width(solver); | ||
398 | blocks.push(log_space_block); | ||
399 | |||
400 | // Make it so that it takes as much space as the bigger one | ||
401 | small_block_unit_width = solver.new_free_float(); | ||
402 | |||
403 | let disk_log_layout = Drawable::builder(Blocks { | ||
404 | blocks, | ||
405 | unit_width: small_block_unit_width, | ||
406 | }) | ||
407 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
408 | .build(solver); | ||
409 | |||
410 | let mut make_delimiter_label = |content| { | ||
411 | Drawable::builder(Text { | ||
412 | content: String::from(content), | ||
413 | font: FontDescription { | ||
414 | family: String::from("Fanwood"), | ||
415 | size: Float::Fixed(15.), | ||
416 | style: Default::default(), | ||
417 | weight: Default::default(), | ||
418 | }, | ||
419 | }) | ||
420 | .build(solver) | ||
421 | }; | ||
422 | |||
423 | let delimiters = vec![ | ||
424 | Delimiter { | ||
425 | label: make_delimiter_label("header"), | ||
426 | width: header_block_width, | ||
427 | }, | ||
428 | Delimiter { | ||
429 | label: make_delimiter_label("data"), | ||
430 | width: log_data_blocks_width, | ||
431 | }, | ||
432 | Delimiter { | ||
433 | label: make_delimiter_label("available"), | ||
434 | width: log_space_width, | ||
435 | }, | ||
436 | ]; | ||
437 | |||
438 | let disk_log_label = Drawable::builder(LabeledDelimiter { | ||
439 | delimiters, | ||
440 | tick_height: Float::Fixed(10.), | ||
441 | }) | ||
442 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
443 | .build(solver); | ||
444 | |||
445 | let label_left = disk_log_label.bounds().left(solver); | ||
446 | data_in_log_left = solver.float_add(&[label_left, header_block_width]); | ||
447 | data_in_log_right = solver.float_add(&[data_in_log_left, log_data_blocks_width]); | ||
448 | data_in_log_bottom = disk_log_label.bounds().bottom(solver); | ||
449 | |||
450 | let layer = Drawable::builder(Layer { | ||
451 | name: String::from("DiskLog"), | ||
452 | name_font: title_font.clone(), | ||
453 | label_font: label_font.clone(), | ||
454 | padding: layer_padding, | ||
455 | entries: vec![ | ||
456 | Entry { | ||
457 | label: Some(String::from("disk log: ")), | ||
458 | label_vert_center_offset: None, | ||
459 | content: disk_log_layout.into(), | ||
460 | }, | ||
461 | Entry { | ||
462 | label: None, | ||
463 | label_vert_center_offset: None, | ||
464 | content: disk_log_label.into(), | ||
465 | }, | ||
466 | ], | ||
467 | entries_width, | ||
468 | }) | ||
469 | .bounds( | ||
470 | Bounds::builder() | ||
471 | .top(layer_top) | ||
472 | .left(Float::Fixed(10.)) | ||
473 | .width(layer_width) | ||
474 | .build(solver), | ||
475 | ) | ||
476 | .build(solver); | ||
477 | |||
478 | let layer_height = layer.bounds().height(solver); | ||
479 | layer_top = solver.float_add(&[layer_top, layer_height, layer_margin]); | ||
480 | |||
481 | runtime.add_drawable(layer); | ||
482 | } | ||
483 | |||
484 | let solver = runtime.solver_ctx(); | ||
485 | |||
486 | // Explode GroupLog -> DiskLog | ||
487 | { | ||
488 | let margin = Float::Fixed(6.); | ||
489 | let explode_top = solver.float_add(&[group_commit_bottom, margin]); | ||
490 | let explode_bottom = solver.float_sub(&[commit_in_log_top, margin]); | ||
491 | |||
492 | let explode = Drawable::builder(Explode { | ||
493 | top_left: Point2D::new(group_commit_left, explode_top), | ||
494 | top_right: Point2D::new(group_commit_right, explode_top), | ||
495 | bottom_left: Point2D::new(commit_in_log_left, explode_bottom), | ||
496 | bottom_right: Point2D::new(commit_in_log_right, explode_bottom), | ||
497 | |||
498 | arm_length: Float::Fixed(12.), | ||
499 | }) | ||
500 | .stroke( | ||
501 | StrokeStyle::builder() | ||
502 | .dash(DashStyle::new(vec![Float::Fixed(2.)], Float::Fixed(0.))) | ||
503 | .build(), | ||
504 | ) | ||
505 | .build(solver); | ||
506 | |||
507 | runtime.add_drawable(explode); | ||
508 | } | ||
509 | |||
510 | let solver = runtime.solver_ctx(); | ||
511 | |||
512 | let data_in_applier_top; | ||
513 | let data_in_applier_left; | ||
514 | let data_in_applier_right; | ||
515 | |||
516 | // Applier | ||
517 | { | ||
518 | // TODO: this is exactly the same as before... | ||
519 | let make_block = |grow, color, solver: &mut dyn SolverContext| { | ||
520 | Drawable::builder(Block { grow }) | ||
521 | .bounds(Bounds::builder().height(blocks_height).build(solver)) | ||
522 | .fill(FillStyle::solid(color)) | ||
523 | .build(solver) | ||
524 | }; | ||
525 | |||
526 | let _make_blocks = |block_descs: &[_], solver: &mut dyn SolverContext| { | ||
527 | let mut blocks = Vec::new(); | ||
528 | |||
529 | for &(grow, color) in block_descs { | ||
530 | blocks.push(make_block(grow, color, solver)); | ||
531 | } | ||
532 | |||
533 | blocks | ||
534 | }; | ||
535 | |||
536 | let mut blocks = vec![]; | ||
537 | |||
538 | blocks.push(make_block(big_block_grow, light_grey, solver)); | ||
539 | for &txn_block_count in other_transactions.iter() { | ||
540 | for _i in 0..txn_block_count { | ||
541 | blocks.push(make_block(1, dark_grey, solver)); | ||
542 | } | ||
543 | } | ||
544 | |||
545 | for _ in 0..blue_transaction_len { | ||
546 | blocks.push(make_block(1, blue, solver)); | ||
547 | } | ||
548 | |||
549 | let blocks = Drawable::builder(Blocks { | ||
550 | blocks, | ||
551 | unit_width: small_block_unit_width, | ||
552 | }) | ||
553 | .build(solver); | ||
554 | |||
555 | data_in_applier_top = blocks.bounds().top(solver); | ||
556 | data_in_applier_left = blocks.bounds().left(solver); | ||
557 | data_in_applier_right = blocks.bounds().right(solver); | ||
558 | |||
559 | let spaced_data = Spacer::builder(blocks) | ||
560 | .horizontal_align_center(solver) | ||
561 | .vertical_align_center_with(Float::Fixed(10.)) | ||
562 | .build(solver); | ||
563 | |||
564 | let spaced_data = Drawable::builder(spaced_data) | ||
565 | .bounds(Bounds::builder().width(entries_width).build(solver)) | ||
566 | .build(solver); | ||
567 | |||
568 | let disk_data = Drawable::builder(Block { grow: 1 }) | ||
569 | .bounds( | ||
570 | Bounds::builder() | ||
571 | .height(blocks_height) | ||
572 | .width(entries_width) | ||
573 | .build(solver), | ||
574 | ) | ||
575 | .fill(FillStyle::solid(Color::white())) | ||
576 | .build(solver); | ||
577 | |||
578 | let layer = Drawable::builder(Layer { | ||
579 | name: String::from("Applier"), | ||
580 | name_font: title_font.clone(), | ||
581 | label_font: label_font.clone(), | ||
582 | padding: layer_padding, | ||
583 | entries: vec![ | ||
584 | Entry { | ||
585 | label: None, | ||
586 | label_vert_center_offset: None, | ||
587 | content: spaced_data.into(), | ||
588 | }, | ||
589 | Entry { | ||
590 | label: Some(String::from("disk data:")), | ||
591 | label_vert_center_offset: None, | ||
592 | content: disk_data.into(), | ||
593 | }, | ||
594 | ], | ||
595 | entries_width, | ||
596 | }) | ||
597 | .bounds( | ||
598 | Bounds::builder() | ||
599 | .top(layer_top) | ||
600 | .left(Float::Fixed(10.)) | ||
601 | .width(layer_width) | ||
602 | .build(solver), | ||
603 | ) | ||
604 | .build(solver); | ||
605 | |||
606 | runtime.add_drawable(layer); | ||
607 | } | ||
608 | |||
609 | let solver = runtime.solver_ctx(); | ||
610 | |||
611 | // Explode DiskLog -> Applier | ||
612 | { | ||
613 | let margin = Float::Fixed(6.); | ||
614 | let explode_top = solver.float_add(&[data_in_log_bottom, margin]); | ||
615 | let explode_bottom = solver.float_sub(&[data_in_applier_top, margin]); | ||
616 | |||
617 | let explode = Drawable::builder(Explode { | ||
618 | top_left: Point2D::new(data_in_log_left, explode_top), | ||
619 | top_right: Point2D::new(data_in_log_right, explode_top), | ||
620 | bottom_left: Point2D::new(data_in_applier_left, explode_bottom), | ||
621 | bottom_right: Point2D::new(data_in_applier_right, explode_bottom), | ||
622 | |||
623 | arm_length: Float::Fixed(12.), | ||
624 | }) | ||
625 | .stroke( | ||
626 | StrokeStyle::builder() | ||
627 | .dash(DashStyle::new(vec![Float::Fixed(2.)], Float::Fixed(0.))) | ||
628 | .build(), | ||
629 | ) | ||
630 | .build(solver); | ||
631 | |||
632 | runtime.add_drawable(explode); | ||
633 | } | ||
634 | |||
635 | let solver = runtime.solver_ctx(); | ||
636 | |||
637 | let max_entry_content_width = solver.float_max(&all_entry_content_widths); | ||
638 | let entries_width_constraint = solver.float_eq(entries_width, max_entry_content_width); | ||
639 | solver.constrain(entries_width_constraint); | ||
640 | |||
641 | runtime.render(); | ||
642 | } | ||