diff options
author | Minijackson <minijackson@riseup.net> | 2023-01-04 09:38:58 +0100 |
---|---|---|
committer | Minijackson <minijackson@riseup.net> | 2023-01-04 09:38:58 +0100 |
commit | b02862a937ebaea178b1c3d08f76ab6d60a7aeed (patch) | |
tree | f6cd18a5fa7bce6ad0fb1f969825a702b637514d /examples/lib-dfscq-log | |
parent | efc83b6fec3f38c45a6b2f51d5e791c30f59eb42 (diff) | |
download | diaphragm-b02862a937ebaea178b1c3d08f76ab6d60a7aeed.tar.gz diaphragm-b02862a937ebaea178b1c3d08f76ab6d60a7aeed.zip |
examples/dfscq-log.lua: update
Diffstat (limited to 'examples/lib-dfscq-log')
-rw-r--r-- | examples/lib-dfscq-log/dfscq-log.lua | 438 |
1 files changed, 435 insertions, 3 deletions
diff --git a/examples/lib-dfscq-log/dfscq-log.lua b/examples/lib-dfscq-log/dfscq-log.lua index c54e4f2..b4e2f8e 100644 --- a/examples/lib-dfscq-log/dfscq-log.lua +++ b/examples/lib-dfscq-log/dfscq-log.lua | |||
@@ -1,7 +1,439 @@ | |||
1 | local diaphragm = require("diaphragm") | 1 | package.cpath = package.cpath .. ";../../target/debug/?.so" |
2 | package.path = package.path .. ";../../lua-bindings/?.lua" | ||
3 | |||
4 | local dia = require("diaphragm") | ||
5 | |||
6 | -- TODO: add a way to have modified prototypes of these functions | ||
7 | -- e.g.: local my_blocks = Blocks:new({ default_color = my_color }) | ||
8 | -- my_blocks:new({ elements = ... }):draw() | ||
9 | |||
10 | dia.util.eprint("--------------------") | ||
11 | |||
12 | -- TODO: Fanwood has a high baseline, which renders weirdly in the GroupCommit layer, | ||
13 | -- and "Goudy Bookletter 1911" doesn't work | ||
14 | -- local serif_family = "Fanwood" | ||
15 | -- local serif_family = "Latin Modern Math" | ||
16 | -- local serif_family = "Goudy Bookletter 1911 Normal" | ||
17 | local serif_family = "OFL Sorts Mill Goudy" | ||
18 | local mono_family = "Fira Mono" | ||
19 | |||
20 | local active_color = "#5959ff" | ||
21 | local light_gray = "#cccccc" | ||
22 | local dark_gray = "#7f7f7f" | ||
23 | |||
24 | local block_unit_width = 24 | ||
25 | local block_height = 36 | ||
26 | local block_stroke_width = 2 | ||
27 | |||
28 | local normal_margin = 20 | ||
29 | local small_margin = 10 | ||
30 | |||
31 | local function blocks(params) | ||
32 | local result = dia.shape(params) | ||
33 | |||
34 | result.unit_width = result.unit_width or dia.float.new() | ||
35 | result.default_color = result.default_color or light_gray | ||
36 | result.default_stroke_width = result.default_stroke_width or block_stroke_width | ||
37 | |||
38 | result.blocks = dia.util.tbl_map(function(el) | ||
39 | return dia.rectangle.new({ | ||
40 | fill_color = el.color or result.default_color, | ||
41 | stroke_width = result.default_stroke_width, | ||
42 | height = result.height, | ||
43 | width = result.unit_width * (el.grow or 1), | ||
44 | }) | ||
45 | end, params.elements) | ||
46 | |||
47 | function result:draw() | ||
48 | local len = #self.elements | ||
49 | assert(len >= 1, "Blocks must have at least 1 element") | ||
50 | |||
51 | local total_grow = 0 | ||
52 | for _, el in pairs(self.elements) do | ||
53 | total_grow = total_grow + (el.grow or 1) | ||
54 | end | ||
55 | |||
56 | dia.constrain(self.width:eq(self.unit_width * total_grow)) | ||
57 | |||
58 | dia.layout | ||
59 | .hstack({ | ||
60 | elements = self.blocks, | ||
61 | top_left = self.top_left, | ||
62 | bottom_right = self.bottom_right, | ||
63 | width = self.width, | ||
64 | }) | ||
65 | :draw() | ||
66 | end | ||
2 | 67 | ||
3 | -- TODO: anyone can use metatable? | 68 | return result |
69 | end | ||
70 | |||
71 | local function active_txn(params) | ||
72 | return blocks(dia.util.tbl_extend({ | ||
73 | elements = { {}, {}, {}, {}, {} }, | ||
74 | height = block_height, | ||
75 | default_color = active_color, | ||
76 | }, params)) | ||
77 | end | ||
78 | |||
79 | local function fixed_blocks(params) | ||
80 | local elements = {} | ||
81 | for _ = 1, params.count do | ||
82 | table.insert(elements, {}) | ||
83 | end | ||
84 | return blocks({ | ||
85 | elements = elements, | ||
86 | height = block_height, | ||
87 | unit_width = block_unit_width, | ||
88 | default_color = params.color or dark_gray, | ||
89 | }) | ||
90 | end | ||
91 | |||
92 | local function block_list(params) | ||
93 | local result = dia.shape(params) | ||
94 | |||
95 | result.delimiter_height = result.delimiter_height or dia.float.new() | ||
96 | result.font = result.font or dia.text.font({ family = serif_family }) | ||
97 | |||
98 | function result:draw() | ||
99 | local opening_delimiter = dia.text.new({ | ||
100 | content = "[", | ||
101 | height = self.delimiter_height, | ||
102 | font = self.font, | ||
103 | }) | ||
104 | |||
105 | local closing_delimiter = dia.text.new({ | ||
106 | content = "]", | ||
107 | height = self.delimiter_height, | ||
108 | font = self.font, | ||
109 | }) | ||
110 | |||
111 | local function comma() | ||
112 | return dia.text.new({ | ||
113 | content = ", ", | ||
114 | font = self.font, | ||
115 | }) | ||
116 | end | ||
117 | |||
118 | local elements = dia.util.list_intersperse_with(comma, self.elements) | ||
119 | |||
120 | elements = { opening_delimiter, table.unpack(elements) } | ||
121 | table.insert(elements, closing_delimiter) | ||
122 | |||
123 | -- TODO: not really elegant | ||
124 | dia.constrain(self.delimiter_height:eq(self.elements[1].height * 2.5)) | ||
125 | |||
126 | dia.layout | ||
127 | .hstack({ | ||
128 | elements = elements, | ||
129 | align = "center", | ||
130 | top_left = self.top_left, | ||
131 | bottom_right = self.bottom_right, | ||
132 | }) | ||
133 | :draw() | ||
134 | end | ||
135 | |||
136 | return result | ||
137 | end | ||
138 | |||
139 | local function disk_log_legend(params) | ||
140 | local result = dia.shape(params) | ||
141 | |||
142 | local function lines(params) | ||
143 | local result = dia.shape(params) | ||
144 | |||
145 | result.ticks = {} | ||
146 | for _, tick in ipairs(params.ticks) do | ||
147 | table.insert(result.ticks, | ||
148 | dia.straight_path.new({ | ||
149 | points = { | ||
150 | { x = tick, y = result.top }, | ||
151 | { x = tick, y = result.bottom }, | ||
152 | } | ||
153 | })) | ||
154 | end | ||
155 | |||
156 | result.baseline = dia.straight_path.new({ | ||
157 | points = { result.middle_left, result.middle_right }, | ||
158 | width = result.width, | ||
159 | }) | ||
160 | |||
161 | function result:draw() | ||
162 | for _, tick in ipairs(self.ticks) do | ||
163 | tick:draw() | ||
164 | end | ||
165 | self.baseline:draw() | ||
166 | end | ||
167 | |||
168 | return result | ||
169 | end | ||
4 | 170 | ||
171 | result.lines = lines({ | ||
172 | ticks = params.ticks, | ||
173 | top_left = result.top_left, | ||
174 | height = result.height / 2, | ||
175 | width = result.width, | ||
176 | }) | ||
177 | |||
178 | result.font = dia.text.font({ family = serif_family }) | ||
179 | |||
180 | result.labels = {} | ||
181 | for i = 1, #params.ticks - 1 do | ||
182 | local label = dia.text.new({ | ||
183 | content = params.labels[i], | ||
184 | height = (result.height / 2) + result.height / 6, | ||
185 | top = result.lines.bottom - result.height / 6, | ||
186 | horiz_center = (params.ticks[i] + params.ticks[i + 1]) / 2, | ||
187 | font = result.font, | ||
188 | }) | ||
189 | table.insert(result.labels, label) | ||
190 | end | ||
191 | |||
192 | function result:draw() | ||
193 | self.lines:draw() | ||
194 | for _, label in ipairs(self.labels) do | ||
195 | label:draw() | ||
196 | end | ||
197 | end | ||
198 | |||
199 | return result | ||
200 | end | ||
201 | |||
202 | local function disk_log(params) | ||
203 | local result = dia.shape(params) | ||
204 | |||
205 | local anchor_ids = {} | ||
206 | local last_group_id = 0 | ||
207 | local labels = {} | ||
208 | local elements = {} | ||
209 | for _, global_spec in pairs(params.elements) do | ||
210 | for _, spec in pairs(global_spec.elements) do | ||
211 | local spec_params = spec.params or {} | ||
212 | for _ = 1, spec.count do | ||
213 | table.insert(elements, spec_params) | ||
214 | end | ||
215 | last_group_id = last_group_id + spec.count | ||
216 | end | ||
217 | table.insert(anchor_ids, last_group_id) | ||
218 | table.insert(labels, global_spec.label) | ||
219 | end | ||
220 | result.blocks = blocks({ | ||
221 | elements = elements, | ||
222 | height = block_height, | ||
223 | top_left = result.top_left, | ||
224 | width = result.width, | ||
225 | }) | ||
226 | result.anchors = { result.left } | ||
227 | for _, id in pairs(anchor_ids) do | ||
228 | table.insert(result.anchors, result.blocks.blocks[id].right) | ||
229 | end | ||
230 | |||
231 | result.legend = disk_log_legend({ | ||
232 | ticks = result.anchors, | ||
233 | labels = labels, | ||
234 | height = normal_margin * 2, | ||
235 | width = result.width, | ||
236 | bottom_right = result.bottom_right, | ||
237 | }) | ||
238 | dia.constraint.below(result.legend, result.blocks, normal_margin) | ||
239 | |||
240 | function result:draw() | ||
241 | result.blocks:draw() | ||
242 | result.legend:draw() | ||
243 | end | ||
244 | |||
245 | return result | ||
246 | end | ||
247 | |||
248 | local function layer_entry(params) | ||
249 | local result = dia.shape(params) | ||
250 | |||
251 | result.text = params.text or dia.text.new({ | ||
252 | content = params.name .. ": ", | ||
253 | font = params.font, | ||
254 | }) | ||
255 | result.text_vert_center = params.text_vert_center or params.content.vert_center | ||
256 | |||
257 | function result:draw() | ||
258 | dia.constraint.left_of(self.text, self.content) | ||
259 | dia.constrain(self.text.vert_center:eq(self.text_vert_center)) | ||
260 | |||
261 | dia.constrain(self.left:eq(self.text.left)) | ||
262 | dia.constrain(self.right:eq(self.content.right)) | ||
263 | dia.constrain(self.top:eq(dia.float.min({ self.text.top, self.content.top }))) | ||
264 | dia.constrain(self.bottom:eq(dia.float.max({ self.text.bottom, self.content.bottom }))) | ||
265 | |||
266 | self.text:draw() | ||
267 | self.content:draw() | ||
268 | end | ||
269 | |||
270 | return result | ||
271 | end | ||
272 | |||
273 | local function layer(params) | ||
274 | local result = dia.shape(params) | ||
275 | |||
276 | result.name = result.name or "Layer" | ||
277 | result.title = dia.text.new({ | ||
278 | content = result.name, | ||
279 | font = result.title_font, | ||
280 | top_left = result.top_left + { x = normal_margin, y = normal_margin }, | ||
281 | }) | ||
282 | result.content = result.content or dia.rectangle.new({ | ||
283 | height = 100, | ||
284 | width = 100, | ||
285 | }) | ||
286 | |||
287 | function result:draw() | ||
288 | dia.rectangle | ||
289 | .new({ | ||
290 | top_left = self.top_left, | ||
291 | bottom_right = self.bottom_right, | ||
292 | fill_color = "#fff", | ||
293 | }) | ||
294 | :draw() | ||
295 | |||
296 | dia.constrain(self.right:eq(self.content.right + normal_margin)) | ||
297 | dia.constraint.below(self.content, self.title) | ||
298 | dia.constrain(self.left:lt(self.content.left - 150)) | ||
299 | |||
300 | dia.constrain(self.bottom:eq(dia.float.max({ self.title.bottom, self.content.bottom }) + normal_margin)) | ||
301 | |||
302 | self.title:draw() | ||
303 | self.content:draw() | ||
304 | end | ||
305 | |||
306 | return result | ||
307 | end | ||
308 | |||
309 | dia.draw({ | ||
310 | content = { | ||
311 | draw = function() | ||
312 | local title_font = dia.text.font({ family = serif_family, size = 50000 }) | ||
313 | local entry_font = dia.text.font({ family = mono_family, size = 20000 }) | ||
314 | local action_font = dia.text.font({ family = mono_family, height = normal_margin }) | ||
315 | |||
316 | local function action(name) | ||
317 | return dia.layout.margin_top({ | ||
318 | margin_top = small_margin, | ||
319 | content = dia.text.new({ | ||
320 | content = '<span foreground="' .. active_color .. '">' .. name .. "</span>", | ||
321 | font = action_font, | ||
322 | height = normal_margin, | ||
323 | }), | ||
324 | }) | ||
325 | end | ||
326 | |||
327 | local layer_right = dia.float.new() | ||
328 | |||
329 | local log_layer_entry_left = dia.float.new() | ||
330 | local group_commit_entry_left = dia.float.new() | ||
331 | local disk_log_entry_left = dia.float.new() | ||
332 | |||
333 | local layers = { | ||
334 | layer({ | ||
335 | name = "LogAPI", | ||
336 | title_font = title_font, | ||
337 | -- top_left = { x = normal_margin, y = normal_margin }, | ||
338 | top_left = { x = normal_margin, y = normal_margin }, | ||
339 | content = dia.layout.margin_right({ | ||
340 | content = layer_entry({ | ||
341 | name = "activeTxn", | ||
342 | font = entry_font, | ||
343 | content = active_txn({ | ||
344 | unit_width = block_unit_width, | ||
345 | left = log_layer_entry_left, | ||
346 | }), | ||
347 | }), | ||
348 | }), | ||
349 | }), | ||
350 | action("commit"), | ||
351 | layer({ | ||
352 | name = "GroupCommit", | ||
353 | title_font = title_font, | ||
354 | -- top_left = { x = 20, y = 100 + 40 }, | ||
355 | -- right = layer_right, | ||
356 | content = dia.layout.margin_right({ | ||
357 | -- HACK: because I know that "GroupCommit" + "commitedTxns:" | ||
358 | -- takes the most space | ||
359 | margin_right = 0, | ||
360 | content = layer_entry({ | ||
361 | name = "commitedTxns", | ||
362 | font = entry_font, | ||
363 | content = block_list({ | ||
364 | elements = { | ||
365 | fixed_blocks({ count = 2 }), | ||
366 | fixed_blocks({ count = 7 }), | ||
367 | fixed_blocks({ count = 4 }), | ||
368 | active_txn({ unit_width = block_unit_width }), | ||
369 | }, | ||
370 | left = group_commit_entry_left, | ||
371 | }), | ||
372 | }), | ||
373 | }), | ||
374 | }), | ||
375 | action("flush"), | ||
376 | layer({ | ||
377 | name = "DiskLog", | ||
378 | title_font = title_font, | ||
379 | -- top_left = { x = 20, y = 100 + 40 }, | ||
380 | right = layer_right, | ||
381 | content = dia.layout.margin_right({ | ||
382 | margin_right = 0, | ||
383 | content = layer_entry({ | ||
384 | -- TODO: align to blocks | ||
385 | name = "disk log", | ||
386 | font = entry_font, | ||
387 | content = disk_log({ | ||
388 | elements = { | ||
389 | { | ||
390 | -- TODO: seems to fail solving if using other font size within text, or line returns | ||
391 | label = "header", | ||
392 | elements = { | ||
393 | { count = 1, params = { color = "#000", grow = 11 } }, | ||
394 | }, | ||
395 | }, | ||
396 | { | ||
397 | label = "data", | ||
398 | elements = { | ||
399 | { count = 2, params = { color = light_gray, grow = 13 + 5 } }, | ||
400 | { count = 13, params = { color = dark_gray } }, | ||
401 | { count = 5, params = { color = active_color } }, | ||
402 | }, | ||
403 | }, | ||
404 | { | ||
405 | label = "available", | ||
406 | elements = { | ||
407 | { count = 1, params = { color = "#fff", grow = 13 + 5 } }, | ||
408 | }, | ||
409 | }, | ||
410 | }, | ||
411 | left = disk_log_entry_left, | ||
412 | }), | ||
413 | }), | ||
414 | }), | ||
415 | }), | ||
416 | action("apply"), | ||
417 | layer({ | ||
418 | name = "Applier", | ||
419 | title_font = title_font, | ||
420 | right = layer_right, | ||
421 | }), | ||
422 | } | ||
423 | |||
424 | dia.layout.vstack({ elements = layers, align = "right" }):draw() | ||
425 | |||
426 | local layer_entries_text_right = dia.float.new() | ||
427 | for _, entry_left in pairs({ log_layer_entry_left, group_commit_entry_left, disk_log_entry_left }) do | ||
428 | dia.constrain(layer_entries_text_right:eq(entry_left)) | ||
429 | end | ||
430 | end, | ||
431 | }, | ||
432 | output = {}, | ||
433 | }) | ||
434 | |||
435 | -- TODO: anyone can use metatable? | ||
436 | --[[ | ||
5 | local Blocks = diaphragm.Drawable:new() | 437 | local Blocks = diaphragm.Drawable:new() |
6 | Blocks.elements = {} | 438 | Blocks.elements = {} |
7 | Blocks.unit_width = diaphragm.float() | 439 | Blocks.unit_width = diaphragm.float() |
@@ -121,4 +553,4 @@ diaphragm.draw(diaphragm.layout.vstack({ | |||
121 | -- group_commit, | 553 | -- group_commit, |
122 | -- disk_log, | 554 | -- disk_log, |
123 | -- applier, | 555 | -- applier, |
124 | })) | 556 | })) ]] |