summaryrefslogtreecommitdiffstats
path: root/examples/lib-dfscq-log
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2022-12-22 12:19:59 +0100
committerMinijackson <minijackson@riseup.net>2022-12-22 12:19:59 +0100
commit92a02c34628343153b33602eae00cef46e28d191 (patch)
tree8622ec528d24e456be22d984d93aa9bcafc97399 /examples/lib-dfscq-log
downloaddiaphragm-92a02c34628343153b33602eae00cef46e28d191.tar.gz
diaphragm-92a02c34628343153b33602eae00cef46e28d191.zip
WIP
Diffstat (limited to 'examples/lib-dfscq-log')
-rw-r--r--examples/lib-dfscq-log/Cargo.toml15
-rw-r--r--examples/lib-dfscq-log/dfscq-log.lua124
-rw-r--r--examples/lib-dfscq-log/src/block_list.rs183
-rw-r--r--examples/lib-dfscq-log/src/blocks.rs72
-rw-r--r--examples/lib-dfscq-log/src/bracket.rs42
-rw-r--r--examples/lib-dfscq-log/src/explode.rs86
-rw-r--r--examples/lib-dfscq-log/src/labeled.rs64
-rw-r--r--examples/lib-dfscq-log/src/labeled_delimiter.rs121
-rw-r--r--examples/lib-dfscq-log/src/layer.rs169
-rw-r--r--examples/lib-dfscq-log/src/main.rs642
-rw-r--r--examples/lib-dfscq-log/src/main2.rs61
-rw-r--r--examples/lib-dfscq-log/src/spacer.rs133
12 files changed, 1712 insertions, 0 deletions
diff --git a/examples/lib-dfscq-log/Cargo.toml b/examples/lib-dfscq-log/Cargo.toml
new file mode 100644
index 0000000..8146aa4
--- /dev/null
+++ b/examples/lib-dfscq-log/Cargo.toml
@@ -0,0 +1,15 @@
1[package]
2name = "diaphragm-examples-lib-dfscq-log"
3version = "0.1.0"
4authors = ["Minijackson <minijackson@riseup.net>"]
5edition = "2021"
6
7# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
9[package.metadata.riff]
10runtime-inputs = ["z3", "cairo"]
11
12[dependencies]
13diaphragm-core = { path = "../../core" }
14diaphragm-z3-solver = { path = "../../z3-solver" }
15diaphragm-cairo-renderer = { path = "../../cairo-renderer" }
diff --git a/examples/lib-dfscq-log/dfscq-log.lua b/examples/lib-dfscq-log/dfscq-log.lua
new file mode 100644
index 0000000..c54e4f2
--- /dev/null
+++ b/examples/lib-dfscq-log/dfscq-log.lua
@@ -0,0 +1,124 @@
1local diaphragm = require("diaphragm")
2
3-- TODO: anyone can use metatable?
4
5local Blocks = diaphragm.Drawable:new()
6Blocks.elements = {}
7Blocks.unit_width = diaphragm.float()
8
9function Blocks:draw()
10 local len = #self.elements
11 assert(len >= 1, "Blocks must have at least 1 element")
12
13 local total_grow = 0
14 for el in self.elements do
15 total_grow = el.grow or 1
16 end
17
18 diaphragm.constrain(self.width == self.unit_width * total_grow)
19
20 local param = self.elements[0]
21
22 -- TODO: this would be written with layout.hstack
23
24 local block = diaphragm.shape.Rectangle:new()
25 block.fill(param.color)
26 diaphragm.constrain(block.left() == self.left())
27 diaphragm.constrain(block.top() == self.top())
28 diaphragm.constrain(block.bottom() == self.bottom())
29 diaphragm.constrain(block.width() == (param.grow or 1) * self.unit_width)
30
31 block.draw()
32
33 local previous_right = block.right()
34
35 for i = 2, len do
36 param = self.elements[i]
37
38 block = diaphragm.shape.Rectangle:new()
39 block.fill(param.color)
40
41 diaphragm.constrain(block.left() == previous_right)
42 diaphragm.constrain(block.top() == self.top())
43 diaphragm.constrain(block.bottom() == self.bottom())
44 diaphragm.constrain(block.width() == (param.grow or 1) * self.unit_width)
45
46 block.draw()
47
48 previous_right = block.right()
49 end
50end
51
52-- Library
53----------
54
55local function block(color)
56 local res = diaphragm.shape.Rectangle:new()
57 res.fill(color)
58 return res
59end
60
61local function blocks_by_len(count, color)
62 local res = {}
63 for i = 1, count do
64 res[i] = block(color)
65 end
66
67 -- TODO: rename cons? Misleading
68 diaphragm.cons.same_size(res)
69 return diaphragm.layout.hstack(res)
70end
71
72local function layer(config)
73 local name = config.name or ""
74 local entries = config.entries or {}
75
76 -- TODO: how to do it without box?
77 -- TODO: implement union or combine
78 -- probably combine because
79 -- union could remove some
80 -- strokes
81 return diaphragm.layout.box({})
82end
83
84-- Parameters
85-------------
86
87local blue = diaphragm.color.from_rgb(0.35, 0.35, 1.)
88
89local active_txn_count = 5
90
91-- Log API
92----------
93
94local log_api = layer({
95 name = "LogAPI",
96 entries = {
97 {
98 name = "activeTxn",
99 content = blocks_by_len(active_txn_count, blue),
100 },
101 },
102})
103
104-- Group Commit
105---------------
106
107-- local group_commit = nil
108
109-- Disk Log
110-----------
111
112-- local disk_log = nil
113
114-- Applier
115----------
116
117-- local applier = nil
118
119diaphragm.draw(diaphragm.layout.vstack({
120 log_api,
121 -- group_commit,
122 -- disk_log,
123 -- applier,
124}))
diff --git a/examples/lib-dfscq-log/src/block_list.rs b/examples/lib-dfscq-log/src/block_list.rs
new file mode 100644
index 0000000..be0eee0
--- /dev/null
+++ b/examples/lib-dfscq-log/src/block_list.rs
@@ -0,0 +1,183 @@
1use super::blocks::Blocks;
2use super::bracket::*;
3
4use diaphragm_core::{
5 core_shapes::Text,
6 text::FontDescription,
7 types::{Bounds, Float, ShapeContext},
8 ComplexShape, DrawResult, Drawable, SolverContext,
9};
10
11#[derive(Clone)]
12pub struct BlockList {
13 pub block_list: Vec<Drawable<Blocks>>,
14 pub block_unit_width: Float,
15 pub bracket_width: Float,
16 pub blocks_vert_padding: Float,
17}
18
19impl ComplexShape for BlockList {
20 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
21 let mut result = DrawResult::new();
22
23 let bounds = context.bounds();
24
25 // Left bracket
26 let opening_bracket_left = {
27 let bracket = Drawable::builder(Bracket {
28 r#type: BracketType::Opening,
29 })
30 .bounds(
31 Bounds::builder()
32 .top(bounds.top(solver))
33 .left(bounds.left(solver))
34 .width(self.bracket_width)
35 .height(bounds.height(solver))
36 .build(solver),
37 )
38 .stroke(context.stroke().clone())
39 .build(solver);
40
41 let bracket_left = bracket.bounds().left(solver);
42
43 result.push(bracket);
44
45 bracket_left
46 };
47
48 let bounds_left = bounds.left(solver);
49 let mut x_acc = solver.float_add(&[bounds_left, self.bracket_width]);
50
51 // Block list
52
53 let bounds_top = bounds.top(solver);
54 let bounds_height = bounds.height(solver);
55 let wanted_blocks_top = solver.float_add(&[bounds_top, self.blocks_vert_padding]);
56 let wanted_blocks_height = solver.float_sub(&[
57 bounds_height,
58 self.blocks_vert_padding,
59 self.blocks_vert_padding,
60 ]);
61
62 let mut block_list_iter = self.block_list.iter();
63
64 // First blocks
65 if let Some(first_blocks) = block_list_iter.next() {
66 // TODO: waaay too verbose
67
68 let blocks_top = first_blocks.bounds().top(solver);
69 let blocks_top_constraint = solver.float_eq(blocks_top, wanted_blocks_top);
70 solver.constrain(blocks_top_constraint);
71
72 let blocks_left = first_blocks.bounds().left(solver);
73 let blocks_left_constraint = solver.float_eq(blocks_left, x_acc);
74 solver.constrain(blocks_left_constraint);
75
76 let blocks_height = first_blocks.bounds().height(solver);
77 let blocks_height_constraint = solver.float_eq(blocks_height, wanted_blocks_height);
78 solver.constrain(blocks_height_constraint);
79
80 let block_unit_width_constraint =
81 solver.float_eq(first_blocks.shape().unit_width, self.block_unit_width);
82 solver.constrain(block_unit_width_constraint);
83
84 result.push(first_blocks.clone());
85
86 let blocks_width = first_blocks.bounds().width(solver);
87 x_acc = solver.float_add(&[x_acc, blocks_width]);
88 }
89
90 // Rest of the blocks
91 for blocks in block_list_iter {
92 // Comma
93 let comma = Drawable::builder(Text {
94 content: String::from(", "),
95 font: FontDescription {
96 family: String::from("mono"),
97 style: Default::default(),
98 weight: Default::default(),
99 size: wanted_blocks_height,
100 },
101 })
102 .bounds(
103 Bounds::builder()
104 .top(wanted_blocks_top)
105 .left(x_acc)
106 .build(solver),
107 )
108 .stroke(context.stroke().clone())
109 .build(solver);
110
111 let comma_width = comma.bounds().width(solver);
112
113 x_acc = solver.float_add(&[x_acc, comma_width]);
114
115 result.push(comma);
116
117 // Blocks
118 /*
119 let blocks_context = ShapeContext {
120 bounds: Bounds {
121 top: blocks_top,
122 left: x_acc,
123 height: blocks_height,
124 width: blocks_width,
125 },
126 fill: FillStyle::default(),
127 stroke: StrokeStyle::default(),
128 };
129 */
130
131 let blocks_top = blocks.bounds().top(solver);
132 let blocks_top_constraint = solver.float_eq(blocks_top, wanted_blocks_top);
133 solver.constrain(blocks_top_constraint);
134
135 let blocks_left = blocks.bounds().left(solver);
136 let blocks_left_constraint = solver.float_eq(blocks_left, x_acc);
137 solver.constrain(blocks_left_constraint);
138
139 let blocks_height = blocks.bounds().height(solver);
140 let blocks_height_constraint = solver.float_eq(blocks_height, wanted_blocks_height);
141 solver.constrain(blocks_height_constraint);
142
143 let block_unit_width_constraint =
144 solver.float_eq(blocks.shape().unit_width, self.block_unit_width);
145 solver.constrain(block_unit_width_constraint);
146
147 result.push(blocks.clone());
148
149 let blocks_width = blocks.bounds().width(solver);
150 x_acc = solver.float_add(&[x_acc, blocks_width]);
151 }
152
153 // Right bracket
154 let closing_bracket_right = {
155 let bracket = Drawable::builder(Bracket {
156 r#type: BracketType::Closing,
157 })
158 .bounds(
159 Bounds::builder()
160 .top(bounds.top(solver))
161 .left(x_acc)
162 .width(self.bracket_width)
163 .height(bounds.height(solver))
164 .build(solver),
165 )
166 .stroke(context.stroke().clone())
167 .build(solver);
168
169 let bracket_right = bracket.bounds().right(solver);
170
171 result.push(bracket);
172
173 bracket_right
174 };
175
176 let this_width = solver.float_sub(&[closing_bracket_right, opening_bracket_left]);
177 let bounds_width = bounds.width(solver);
178 let bounds_width_constraint = solver.float_eq(bounds_width, this_width);
179 solver.constrain(bounds_width_constraint);
180
181 result
182 }
183}
diff --git a/examples/lib-dfscq-log/src/blocks.rs b/examples/lib-dfscq-log/src/blocks.rs
new file mode 100644
index 0000000..0576b7d
--- /dev/null
+++ b/examples/lib-dfscq-log/src/blocks.rs
@@ -0,0 +1,72 @@
1use diaphragm_core::{
2 core_shapes::Rectangle,
3 types::{Float, ShapeContext},
4 ComplexShape, DrawResult, Drawable, SolverContext,
5};
6
7#[derive(Debug, Clone)]
8pub struct Block {
9 pub grow: u8,
10}
11
12impl ComplexShape for Block {
13 fn draw(&self, context: &ShapeContext, _solver: &mut dyn SolverContext) -> DrawResult {
14 let mut result = DrawResult::new();
15
16 // Grow is handled at the upper level
17 let block = Drawable::new(Rectangle {}, context.clone());
18
19 result.push(block);
20
21 result
22 }
23}
24
25#[derive(Debug, Clone)]
26pub struct Blocks {
27 pub blocks: Vec<Drawable<Block>>,
28 pub unit_width: Float,
29}
30
31impl ComplexShape for Blocks {
32 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
33 let mut result = DrawResult::new();
34
35 let sum: u8 = self.blocks.iter().map(|block| block.shape().grow).sum();
36
37 let mut rect_left = context.bounds().left(solver);
38 let rect_top = context.bounds().top(solver);
39 let rect_height = context.bounds().height(solver);
40
41 for block in &self.blocks {
42 let block_top = block.bounds().top(solver);
43 let rect_top_constraint = solver.float_eq(block_top, rect_top);
44 solver.constrain(rect_top_constraint);
45
46 let block_left = block.bounds().left(solver);
47 let rect_left_constraint = solver.float_eq(block_left, rect_left);
48 solver.constrain(rect_left_constraint);
49
50 let grow = Float::Fixed(block.shape().grow as f64);
51 let block_width = block.bounds().width(solver);
52 let rect_width = solver.float_mul(&[self.unit_width, grow]);
53 let rect_width_constraint = solver.float_eq(block_width, rect_width);
54 solver.constrain(rect_width_constraint);
55
56 let block_height = block.bounds().height(solver);
57 let rect_height_constraint = solver.float_eq(block_height, rect_height);
58 solver.constrain(rect_height_constraint);
59
60 result.push(block.clone());
61
62 rect_left = solver.float_add(&[rect_left, rect_width]);
63 }
64
65 let this_width = solver.float_mul(&[self.unit_width, Float::Fixed(sum as f64)]);
66 let bounds_width = context.bounds().width(solver);
67 let bounds_width_constraint = solver.float_eq(bounds_width, this_width);
68 solver.constrain(bounds_width_constraint);
69
70 result
71 }
72}
diff --git a/examples/lib-dfscq-log/src/bracket.rs b/examples/lib-dfscq-log/src/bracket.rs
new file mode 100644
index 0000000..02bca8d
--- /dev/null
+++ b/examples/lib-dfscq-log/src/bracket.rs
@@ -0,0 +1,42 @@
1use diaphragm_core::{
2 core_shapes::StraightPath, types::ShapeContext, ComplexShape, DrawResult, Drawable,
3 SolverContext,
4};
5
6#[derive(Copy, Clone)]
7pub enum BracketType {
8 Opening,
9 Closing,
10}
11
12#[derive(Clone)]
13pub struct Bracket {
14 pub r#type: BracketType,
15}
16
17impl ComplexShape for Bracket {
18 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
19 let mut result = DrawResult::new();
20
21 let bounds = context.bounds();
22
23 let path = match self.r#type {
24 BracketType::Opening => StraightPath::new(vec![
25 bounds.top_right(solver),
26 bounds.top_left(solver),
27 bounds.bottom_left(solver),
28 bounds.bottom_right(solver),
29 ]),
30 BracketType::Closing => StraightPath::new(vec![
31 bounds.top_left(solver),
32 bounds.top_right(solver),
33 bounds.bottom_right(solver),
34 bounds.bottom_left(solver),
35 ]),
36 };
37
38 result.push(Drawable::new(path, context.clone()));
39
40 result
41 }
42}
diff --git a/examples/lib-dfscq-log/src/explode.rs b/examples/lib-dfscq-log/src/explode.rs
new file mode 100644
index 0000000..aeb85bd
--- /dev/null
+++ b/examples/lib-dfscq-log/src/explode.rs
@@ -0,0 +1,86 @@
1use diaphragm_core::{
2 core_shapes::StraightPath,
3 types::{Float, Point2D, ShapeContext},
4 ComplexShape, DrawResult, Drawable, SolverContext,
5};
6
7#[derive(Clone)]
8pub struct Explode {
9 pub top_left: Point2D,
10 pub top_right: Point2D,
11 pub bottom_left: Point2D,
12 pub bottom_right: Point2D,
13
14 pub arm_length: Float,
15}
16
17impl ComplexShape for Explode {
18 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
19 let mut result = DrawResult::new();
20
21 let wanted_top = solver.float_min(&[self.top_left.y(), self.top_right.y()]);
22 let wanted_left = solver.float_min(&[self.top_left.x(), self.bottom_left.x()]);
23 let wanted_bottom = solver.float_max(&[self.bottom_left.x(), self.bottom_right.x()]);
24 let wanted_right = solver.float_max(&[self.top_right.y(), self.bottom_right.y()]);
25
26 let bounds_top = context.bounds().top(solver);
27 let bounds_left = context.bounds().left(solver);
28 let bounds_bottom = context.bounds().bottom(solver);
29 let bounds_right = context.bounds().right(solver);
30
31 // TODO: add a facility to help this?
32 let bounds_top_constraint = solver.float_eq(bounds_top, wanted_top);
33 solver.constrain(bounds_top_constraint);
34
35 let bounds_left_constraint = solver.float_eq(bounds_left, wanted_left);
36 solver.constrain(bounds_left_constraint);
37
38 let bounds_bottom_constraint = solver.float_eq(bounds_bottom, wanted_bottom);
39 solver.constrain(bounds_bottom_constraint);
40
41 let bounds_right_constraint = solver.float_eq(bounds_right, wanted_right);
42 solver.constrain(bounds_right_constraint);
43
44 let top_left_arm_bottom = Point2D::new(
45 self.top_left.x(),
46 solver.float_add(&[self.top_left.y(), self.arm_length]),
47 );
48
49 let bottom_left_arm_top = Point2D::new(
50 self.bottom_left.x(),
51 solver.float_sub(&[self.bottom_left.y(), self.arm_length]),
52 );
53
54 result.push(Drawable::new(
55 StraightPath::new(vec![
56 self.top_left.clone(),
57 top_left_arm_bottom,
58 bottom_left_arm_top,
59 self.bottom_left.clone(),
60 ]),
61 context.clone(),
62 ));
63
64 let top_right_arm_bottom = Point2D::new(
65 self.top_right.x(),
66 solver.float_add(&[self.top_right.y(), self.arm_length]),
67 );
68
69 let bottom_right_arm_top = Point2D::new(
70 self.bottom_right.x(),
71 solver.float_sub(&[self.bottom_right.y(), self.arm_length]),
72 );
73
74 result.push(Drawable::new(
75 StraightPath::new(vec![
76 self.top_right.clone(),
77 top_right_arm_bottom,
78 bottom_right_arm_top,
79 self.bottom_right.clone(),
80 ]),
81 context.clone(),
82 ));
83
84 result
85 }
86}
diff --git a/examples/lib-dfscq-log/src/labeled.rs b/examples/lib-dfscq-log/src/labeled.rs
new file mode 100644
index 0000000..20aebcd
--- /dev/null
+++ b/examples/lib-dfscq-log/src/labeled.rs
@@ -0,0 +1,64 @@
1use diaphragm_core::{
2 core_shapes::Text,
3 text::FontDescription,
4 types::{Bounds, Float, ShapeContext},
5 ComplexShape, DrawResult, DynClone, SolverContext,
6};
7
8pub struct Labeled {
9 pub label: String,
10 pub label_font: FontDescription,
11 pub content: Box<dyn ComplexShape>,
12 pub content_left: Float,
13}
14
15impl ComplexShape for Labeled {
16 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
17 let mut result = DrawResult::new();
18
19 // Label
20
21 let label = Text {
22 content: self.label.clone(),
23 font: self.label_font.clone(),
24 };
25
26 let mut label_context = context.clone();
27 // TODO: make the text constrain the width
28 label_context.bounds.width = solver.new_free_float();
29
30 let label_right = solver.float_add(&[context.bounds.left, label_context.bounds.width]);
31 let content_left_constrain = solver.float_eq(label_right, self.content_left);
32 solver.constrain(content_left_constrain);
33
34 result.push_shape(label, label_context);
35
36 // Content
37
38 let content_context = ShapeContext {
39 bounds: Bounds {
40 top: context.bounds.top,
41 left: solver.float_add(&[context.bounds.left, self.content_left]),
42 height: context.bounds.height,
43 width: context.bounds.width,
44 },
45 fill: context.fill.clone(),
46 stroke: context.stroke.clone(),
47 };
48
49 result.push_boxed_shape(self.content.dyn_clone(), content_context);
50
51 result
52 }
53}
54
55impl DynClone for Labeled {
56 fn dyn_clone(&self) -> Box<dyn ComplexShape> {
57 Box::new(Labeled {
58 label: self.label.clone(),
59 label_font: self.label_font.clone(),
60 content: self.content.dyn_clone(),
61 content_left: self.content_left.clone(),
62 })
63 }
64}
diff --git a/examples/lib-dfscq-log/src/labeled_delimiter.rs b/examples/lib-dfscq-log/src/labeled_delimiter.rs
new file mode 100644
index 0000000..5a1c610
--- /dev/null
+++ b/examples/lib-dfscq-log/src/labeled_delimiter.rs
@@ -0,0 +1,121 @@
1use diaphragm_core::{
2 core_shapes::{StraightPath, Text},
3 types::{Bounds, Float, Point2D, ShapeContext},
4 ComplexShape, DrawResult, Drawable, SolverContext,
5};
6
7#[derive(Debug, Clone)]
8pub struct Delimiter {
9 pub width: Float,
10 pub label: Drawable<Text>,
11}
12
13#[derive(Debug, Clone)]
14pub struct LabeledDelimiter {
15 pub delimiters: Vec<Delimiter>,
16 pub tick_height: Float,
17}
18
19impl ComplexShape for LabeledDelimiter {
20 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
21 let mut result = DrawResult::new();
22
23 let bounds_left = context.bounds().left(solver);
24 let bounds_right = context.bounds().right(solver);
25 let bounds_bottom = context.bounds().bottom(solver);
26 let bounds_width = context.bounds().width(solver);
27
28 let tick_top = context.bounds().top(solver);
29 let tick_bottom = solver.float_add(&[tick_top, self.tick_height]);
30
31 let first_tick = Drawable::builder(StraightPath::new(vec![
32 context.bounds().top_left(solver),
33 Point2D::new(bounds_left, tick_bottom),
34 ]))
35 .bounds(
36 Bounds::builder()
37 .top(tick_top)
38 .left(bounds_left)
39 .height(self.tick_height)
40 .width(Float::Fixed(0.))
41 .build(solver),
42 )
43 .stroke(context.stroke().clone())
44 .build(solver);
45
46 let baseline_y = first_tick.bounds().vert_center(solver);
47
48 result.push(first_tick);
49
50 // TODO: split everything into functions
51
52 let baseline = Drawable::builder(StraightPath::new(vec![
53 Point2D::new(bounds_left, baseline_y),
54 Point2D::new(bounds_right, baseline_y),
55 ]))
56 .bounds(
57 Bounds::builder()
58 .top(baseline_y)
59 .left(bounds_left)
60 .width(bounds_width)
61 .height(Float::Fixed(0.))
62 .build(solver),
63 )
64 .stroke(context.stroke().clone())
65 .build(solver);
66
67 result.push(baseline);
68
69 let mut section_end = bounds_left;
70 let mut all_label_bottoms = vec![];
71
72 for &Delimiter {
73 width: section_width,
74 ref label,
75 } in &self.delimiters
76 {
77 let section_begin = section_end;
78 section_end = solver.float_add(&[section_end, section_width]);
79
80 let section_half_width = solver.float_div(section_width, Float::Fixed(2.));
81 let section_middle = solver.float_add(&[section_begin, section_half_width]);
82
83 let tick = Drawable::builder(StraightPath::new(vec![
84 Point2D::new(section_end, tick_top),
85 Point2D::new(section_end, tick_bottom),
86 ]))
87 .bounds(
88 Bounds::builder()
89 .top(tick_top)
90 .left(section_end)
91 .height(self.tick_height)
92 .width(Float::Fixed(0.))
93 .build(solver),
94 )
95 .stroke(context.stroke().clone())
96 .build(solver);
97
98 result.push(tick);
99
100 let label_top = label.bounds().top(solver);
101 let label_bottom = label.bounds().bottom(solver);
102 let label_horiz_center = label.bounds().horiz_center(solver);
103
104 let label_top_constraint = solver.float_eq(label_top, tick_bottom);
105 solver.constrain(label_top_constraint);
106
107 let label_middle_constraint = solver.float_eq(label_horiz_center, section_middle);
108 solver.constrain(label_middle_constraint);
109
110 result.push(label.clone());
111
112 all_label_bottoms.push(label_bottom);
113 }
114
115 let wanted_bounds_bottom = solver.float_max(&all_label_bottoms);
116 let bounds_bottom_constraint = solver.float_eq(bounds_bottom, wanted_bounds_bottom);
117 solver.constrain(bounds_bottom_constraint);
118
119 result
120 }
121}
diff --git a/examples/lib-dfscq-log/src/layer.rs b/examples/lib-dfscq-log/src/layer.rs
new file mode 100644
index 0000000..45edb56
--- /dev/null
+++ b/examples/lib-dfscq-log/src/layer.rs
@@ -0,0 +1,169 @@
1use diaphragm_core::{
2 core_shapes::Rectangle,
3 core_shapes::Text,
4 text::FontDescription,
5 types::{Bounds, Float, ShapeContext},
6 ComplexShape, DrawResult, Drawable, DynDrawable, SolverContext,
7};
8
9#[derive(Clone)]
10pub struct Entry {
11 // TODO: transform this to just Text
12 pub label: Option<String>,
13 pub label_vert_center_offset: Option<Float>,
14 pub content: DynDrawable,
15}
16
17#[derive(Clone)]
18pub struct Layer {
19 // TODO: transform this to just Text
20 pub name: String,
21 pub name_font: FontDescription,
22 pub label_font: FontDescription,
23 pub padding: Float,
24 pub entries: Vec<Entry>,
25 pub entries_width: Float,
26}
27
28impl ComplexShape for Layer {
29 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
30 let mut result = DrawResult::new();
31
32 let bounds_top = context.bounds().top(solver);
33 let bounds_left = context.bounds().left(solver);
34 let bounds_right = context.bounds().right(solver);
35 let bounds_height = context.bounds().height(solver);
36
37 let inner_top = solver.float_add(&[bounds_top, self.padding]);
38 let inner_right = solver.float_sub(&[bounds_right, self.padding]);
39
40 // Outer box
41
42 result.push(Drawable::new(Rectangle {}, context.clone()));
43
44 // Layer name
45
46 let layer_name = Drawable::builder(Text {
47 content: self.name.clone(),
48 font: self.name_font.clone(),
49 })
50 .bounds(
51 Bounds::builder()
52 .top(inner_top)
53 .left(solver.float_add(&[bounds_left, self.padding]))
54 .build(solver),
55 )
56 .stroke(context.stroke().clone())
57 .fill(context.fill().clone())
58 .build(solver);
59
60 let layer_name_bottom = layer_name.bounds().bottom(solver);
61
62 /*
63 let mut rect_context = layer_name_context.clone();
64 rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
65 result.push_shape(Rectangle {}, rect_context);
66 */
67
68 result.push(layer_name);
69
70 // Entries
71
72 let mut entry_y_acc = inner_top;
73
74 for entry in &self.entries {
75 // Entry content
76
77 /*
78 let content_context = ShapeContext {
79 bounds: Bounds {
80 top: solver.new_free_float(),
81 left: content_left,
82 width: entry.width,
83 height: entry.height,
84 },
85 fill: Default::default(),
86 stroke: Default::default(),
87 };
88 */
89
90 let content_vert_center = entry.content.bounds().vert_center(solver);
91 let content_top = entry.content.bounds().top(solver);
92 let content_left = entry.content.bounds().left(solver);
93 let content_bottom = entry.content.bounds().bottom(solver);
94
95 // TODO: to replace with label offset
96 let content_half_height = solver.float_sub(&[content_vert_center, content_top]);
97
98 result.push_dyn(entry.content.clone());
99
100 // Entry label
101
102 if let Some(label_content) = entry.label.clone() {
103 let label_top = solver.new_free_float();
104 let label_width = solver.new_free_float();
105 let label_left = solver.float_sub(&[inner_right, self.entries_width, label_width]);
106
107 let label = Drawable::builder(Text {
108 content: label_content,
109 font: self.label_font.clone(),
110 })
111 .bounds(
112 Bounds::builder()
113 .top(label_top)
114 .left(label_left)
115 .width(label_width)
116 .build(solver),
117 )
118 .build(solver);
119
120 /*
121 let mut rect_context = label_context.clone();
122 rect_context.stroke = StrokeStyle::solid(Color::from_rgb(1., 0., 0.));
123 result.push_shape(Rectangle {}, rect_context);
124 */
125
126 // TODO
127 let label_vert_center = label.bounds().vert_center(solver);
128 let label_top = label.bounds().top(solver);
129 let label_right = label.bounds().right(solver);
130
131 let label_vert_center_constraint =
132 solver.float_eq(label_vert_center, content_vert_center);
133 solver.constrain(label_vert_center_constraint);
134
135 let label_half_height = solver.float_sub(&[label_vert_center, label_top]);
136
137 let dumb_label_mid_placement =
138 solver.float_add(&[entry_y_acc, content_half_height]);
139 let safe_label_mid_placement =
140 solver.float_add(&[layer_name_bottom, label_half_height]);
141 let label_mid_placement =
142 solver.float_max(&[safe_label_mid_placement, dumb_label_mid_placement]);
143 let label_mid_placement_constraint =
144 solver.float_eq(label_vert_center, label_mid_placement);
145 solver.constrain(label_mid_placement_constraint);
146
147 let label_right_constraint = solver.float_eq(label_right, content_left);
148 solver.constrain(label_right_constraint);
149
150 result.push(label);
151 } else {
152 let content_top_constraint = solver.float_eq(content_top, entry_y_acc);
153 solver.constrain(content_top_constraint);
154
155 let wanted_content_left = solver.float_sub(&[inner_right, self.entries_width]);
156 let content_left_constraint = solver.float_eq(content_left, wanted_content_left);
157 solver.constrain(content_left_constraint);
158 }
159
160 entry_y_acc = solver.float_add(&[content_bottom, self.padding]);
161 }
162
163 let wanted_bounds_height = solver.float_sub(&[entry_y_acc, bounds_top]);
164 let height_constraint = solver.float_eq(bounds_height, wanted_bounds_height);
165 solver.constrain(height_constraint);
166
167 result
168 }
169}
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 @@
1mod block_list;
2mod blocks;
3mod bracket;
4mod explode;
5mod labeled_delimiter;
6mod layer;
7mod spacer;
8
9//mod labeled;
10//use labeled::Labeled;
11
12use block_list::BlockList;
13use blocks::*;
14use explode::*;
15use labeled_delimiter::*;
16use layer::*;
17use spacer::*;
18
19use diaphragm_cairo_renderer::CairoRenderer;
20use diaphragm_core::{
21 colors::Color,
22 core_shapes::{Text},
23 styles::*,
24 text::FontDescription,
25 types::*,
26 *,
27};
28use diaphragm_z3_solver::{z3, Z3Context};
29
30fn 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}
diff --git a/examples/lib-dfscq-log/src/main2.rs b/examples/lib-dfscq-log/src/main2.rs
new file mode 100644
index 0000000..9db235d
--- /dev/null
+++ b/examples/lib-dfscq-log/src/main2.rs
@@ -0,0 +1,61 @@
1fn main() {
2 let solver = Solver::new();
3 let output = Output::new();
4
5 let blue_transaction_len = 5;
6
7 let blue_block = Block::builder().color(blue);
8 let dark_gray_block = Block::builder().color(dark_gray);
9
10 let log_layer = Layer::builder()
11 .name("LogAPI")
12 .push_entry(
13 Entry::builder()
14 .label("activeTxn: ")
15 .content(
16 Blocks::builder()
17 .push(blue_transaction_len, blue_block.build())
18 .build(),
19 )
20 .build(),
21 )
22 .build();
23
24 let other_transactions = [2, 7, 4];
25
26 let group_commit_layer = Layer::builder()
27 .name("GroupCommit")
28 .push_entry(
29 Entry::builder()
30 .label("commitedTxn: ")
31 .content(
32 BlockList::builder()
33 .append(
34 other_transactions
35 .iter()
36 // TODO: need collect?
37 .map(|len| Blocks::builder().push(len, dark_gray_block.build())),
38 )
39 .push(Blocks::builder().push(blue_transaction_len, blue_block.build()))
40 .build(),
41 )
42 .build(),
43 )
44 .build();
45
46 let disk_log_layer = todo!();
47
48 let applier_layer = todo!();
49
50 let layers = &[
51 &log_layer,
52 &group_commit_layer,
53 &disk_log_layer,
54 &applier_layer,
55 ];
56 constraints::distribute_vertically(solver, layers);
57 constraints::align_left(solver, layers);
58
59 solver.solve();
60 output.write_to_stdout(Output::Format::SVG);
61}
diff --git a/examples/lib-dfscq-log/src/spacer.rs b/examples/lib-dfscq-log/src/spacer.rs
new file mode 100644
index 0000000..6878183
--- /dev/null
+++ b/examples/lib-dfscq-log/src/spacer.rs
@@ -0,0 +1,133 @@
1use diaphragm_core::{
2 types::{Float, ShapeContext},
3 ComplexShape, DrawResult, DynDrawable, SolverContext,
4};
5
6#[derive(Clone)]
7pub struct Spacer {
8 pub margin_left: Float,
9 pub margin_right: Float,
10 pub margin_top: Float,
11 pub margin_bottom: Float,
12 pub content: DynDrawable,
13}
14
15impl Spacer {
16 pub fn builder<T: Into<DynDrawable>>(drawable: T) -> SpacerBuilder {
17 SpacerBuilder::new(drawable)
18 }
19}
20
21impl ComplexShape for Spacer {
22 fn draw(&self, context: &ShapeContext, solver: &mut dyn SolverContext) -> DrawResult {
23 let mut result = DrawResult::new();
24
25 let bounds_left = context.bounds().left(solver);
26 let bounds_right = context.bounds().right(solver);
27 let bounds_top = context.bounds().top(solver);
28 let bounds_bottom = context.bounds().bottom(solver);
29
30 let wanted_content_left = solver.float_add(&[bounds_left, self.margin_left]);
31 let content_left = self.content.bounds().left(solver);
32 let content_left_constraint = solver.float_eq(content_left, wanted_content_left);
33 solver.constrain(content_left_constraint);
34
35 let wanted_content_right = solver.float_sub(&[bounds_right, self.margin_right]);
36 let content_right = self.content.bounds().right(solver);
37 let content_right_constraint = solver.float_eq(content_right, wanted_content_right);
38 solver.constrain(content_right_constraint);
39
40 let wanted_content_top = solver.float_add(&[bounds_top, self.margin_top]);
41 let content_top = self.content.bounds().top(solver);
42 let content_top_constraint = solver.float_eq(content_top, wanted_content_top);
43 solver.constrain(content_top_constraint);
44
45 let wanted_content_bottom = solver.float_sub(&[bounds_bottom, self.margin_bottom]);
46 let content_bottom = self.content.bounds().bottom(solver);
47 let content_bottom_constraint = solver.float_eq(content_bottom, wanted_content_bottom);
48 solver.constrain(content_bottom_constraint);
49
50 result.push_dyn(self.content.clone());
51
52 result
53 }
54}
55
56#[derive(Clone)]
57pub struct SpacerBuilder {
58 pub margin_left: Option<Float>,
59 pub margin_right: Option<Float>,
60 pub margin_top: Option<Float>,
61 pub margin_bottom: Option<Float>,
62 pub content: DynDrawable,
63}
64
65impl SpacerBuilder {
66 pub fn new<T: Into<DynDrawable>>(drawable: T) -> Self {
67 SpacerBuilder {
68 margin_left: None,
69 margin_right: None,
70 margin_top: None,
71 margin_bottom: None,
72 content: drawable.into(),
73 }
74 }
75
76 pub fn margin_left(&mut self, margin_left: Float) -> &mut Self {
77 self.margin_left = Some(margin_left);
78 self
79 }
80
81 pub fn margin_right(&mut self, margin_right: Float) -> &mut Self {
82 self.margin_right = Some(margin_right);
83 self
84 }
85
86 pub fn margin_top(&mut self, margin_top: Float) -> &mut Self {
87 self.margin_top = Some(margin_top);
88 self
89 }
90
91 pub fn margin_bottom(&mut self, margin_bottom: Float) -> &mut Self {
92 self.margin_bottom = Some(margin_bottom);
93 self
94 }
95
96 pub fn vertical_align_center(&mut self, solver: &mut dyn SolverContext) -> &mut Self {
97 let vertical_margin = solver.new_free_float();
98 self.margin_top = Some(vertical_margin);
99 self.margin_bottom = Some(vertical_margin);
100 self
101 }
102
103 pub fn vertical_align_center_with(&mut self, margin: Float) -> &mut Self {
104 self.margin_top = Some(margin);
105 self.margin_bottom = Some(margin);
106 self
107 }
108
109 pub fn horizontal_align_center(&mut self, solver: &mut dyn SolverContext) -> &mut Self {
110 let horizontal_margin = solver.new_free_float();
111 self.margin_left = Some(horizontal_margin);
112 self.margin_right = Some(horizontal_margin);
113 self
114 }
115
116 pub fn horizontal_align_center_with(&mut self, margin: Float) -> &mut Self {
117 self.margin_left = Some(margin);
118 self.margin_right = Some(margin);
119 self
120 }
121
122 pub fn build(&self, solver: &mut dyn SolverContext) -> Spacer {
123 Spacer {
124 margin_left: self.margin_left.unwrap_or_else(|| solver.new_free_float()),
125 margin_right: self.margin_right.unwrap_or_else(|| solver.new_free_float()),
126 margin_top: self.margin_top.unwrap_or_else(|| solver.new_free_float()),
127 margin_bottom: self
128 .margin_bottom
129 .unwrap_or_else(|| solver.new_free_float()),
130 content: self.content.clone(),
131 }
132 }
133}