forked from HEL/chronos
		
	restructured code in separated files
This commit is contained in:
		
							
								
								
									
										5
									
								
								src/consts.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/consts.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #let Y-SPACE = 10 | ||||
| #let PAR-PAD = (5pt, 3pt) | ||||
| #let PAR-SPACE = 10 | ||||
| #let COMMENT-PAD = 8 | ||||
| #let LIFELINE-W = 10 | ||||
| @@ -1,71 +1,6 @@ | ||||
| #import "utils.typ": get-group-span | ||||
| #import "renderer.typ": render | ||||
|  | ||||
| #let _seq( | ||||
|   p1, | ||||
|   p2, | ||||
|   comment: none, | ||||
|   dashed: false, | ||||
|   tip: "default", | ||||
|   color: black, | ||||
|   flip: false, | ||||
|   enable-dst: false, | ||||
|   disable-dst: false, | ||||
|   destroy-dst: false, | ||||
|   disable-src: false, | ||||
|   destroy-src: false, | ||||
| ) = { | ||||
|   return (( | ||||
|     type: "seq", | ||||
|     p1: p1, | ||||
|     p2: p2, | ||||
|     comment: comment, | ||||
|     dashed: dashed, | ||||
|     tip: tip, | ||||
|     color: color, | ||||
|     flip: flip, | ||||
|     enable-dst: enable-dst, | ||||
|     disable-dst: disable-dst, | ||||
|     destroy-dst: destroy-dst, | ||||
|     disable-src: disable-src, | ||||
|     destroy-src: destroy-src, | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let _par(name, display-name: auto, start-at: 0) = { | ||||
|   return (( | ||||
|     type: "par", | ||||
|     name: name, | ||||
|     display-name: if display-name == auto {name} else {display-name}, | ||||
|     start-at: start-at | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let _par-exists(participants, name) = { | ||||
|   for p in participants { | ||||
|     if name == p.name { | ||||
|       return true | ||||
|     } | ||||
|   } | ||||
|   return false | ||||
| } | ||||
|  | ||||
| #let _grp(name, desc: none, type: "default", elmts) = { | ||||
|   return (( | ||||
|     type: "grp", | ||||
|     name: name, | ||||
|     desc: desc, | ||||
|     grp-type: type, | ||||
|     elmts: elmts | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let _sep(name) = { | ||||
|   return (( | ||||
|     type: "sep", | ||||
|     name: name | ||||
|   ),) | ||||
| } | ||||
| #import "participant.typ" as participant: _par | ||||
|  | ||||
| #let _gap(size: 20) = { | ||||
|   return (( | ||||
| @@ -78,6 +13,8 @@ | ||||
|   let participants = () | ||||
|   let elmts = elements | ||||
|   let i = 0 | ||||
|  | ||||
|   // Flatten groups | ||||
|   while i < elmts.len() { | ||||
|     let elmt = elmts.at(i) | ||||
|     if elmt.type == "grp" { | ||||
| @@ -93,19 +30,21 @@ | ||||
|     i += 1 | ||||
|   } | ||||
|  | ||||
|   // List participants | ||||
|   for elmt in elmts { | ||||
|     if elmt.type == "par" { | ||||
|       participants.push(elmt) | ||||
|     } else if elmt.type == "seq" { | ||||
|       if not _par-exists(participants, elmt.p1) { | ||||
|       if not participant._exists(participants, elmt.p1) { | ||||
|         participants.push(_par(elmt.p1).first()) | ||||
|       } | ||||
|       if not _par-exists(participants, elmt.p2) { | ||||
|       if not participant._exists(participants, elmt.p2) { | ||||
|         participants.push(_par(elmt.p2).first()) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Compute groups spans (horizontal) | ||||
|   for (i, elmt) in elmts.enumerate() { | ||||
|     if elmt.type == "grp" { | ||||
|       let (min-i, max-i) = get-group-span(participants, elmt) | ||||
|   | ||||
							
								
								
									
										52
									
								
								src/group.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/group.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
|  | ||||
| #let _grp(name, desc: none, type: "default", elmts) = { | ||||
|   return (( | ||||
|     type: "grp", | ||||
|     name: name, | ||||
|     desc: desc, | ||||
|     grp-type: type, | ||||
|     elmts: elmts | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let render(x0, x1, y0, y1, group) = { | ||||
|   let shapes = () | ||||
|   let m = measure(box(group.name)) | ||||
|   let w = m.width / 1pt + 15 | ||||
|   let h = m.height / 1pt + 6 | ||||
|   shapes += draw.rect( | ||||
|     (x0, y0), | ||||
|     (x1, y1) | ||||
|   ) | ||||
|   shapes += draw.merge-path( | ||||
|     fill: gray.lighten(20%), | ||||
|     close: true, | ||||
|     { | ||||
|       draw.line( | ||||
|         (x0, y0), | ||||
|         (x0 + w, y0), | ||||
|         (x0 + w, y0 - h / 2), | ||||
|         (x0 + w - 5, y0 - h), | ||||
|         (x0, y0 - h) | ||||
|       ) | ||||
|     } | ||||
|   ) | ||||
|   shapes += draw.content( | ||||
|     (x0, y0), | ||||
|     group.name, | ||||
|     anchor: "north-west", | ||||
|     padding: (left: 5pt, right: 10pt, top: 3pt, bottom: 3pt) | ||||
|   ) | ||||
|  | ||||
|   if group.desc != none { | ||||
|     shapes += draw.content( | ||||
|       (x0 + w, y0), | ||||
|       text([\[#group.desc\]], weight: "bold"), | ||||
|       anchor: "north-west", | ||||
|       padding: 3pt | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   return shapes | ||||
| } | ||||
| @@ -1 +1,6 @@ | ||||
| #import "diagram.typ": diagram, from-plantuml | ||||
| #import "diagram.typ": diagram, from-plantuml, _gap | ||||
|  | ||||
| #import "sequence.typ": _seq | ||||
| #import "group.typ": _grp | ||||
| #import "participant.typ": _par | ||||
| #import "separator.typ": _sep | ||||
							
								
								
									
										17
									
								
								src/participant.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/participant.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #let _par(name, display-name: auto, start-at: 0) = { | ||||
|   return (( | ||||
|     type: "par", | ||||
|     name: name, | ||||
|     display-name: if display-name == auto {name} else {display-name}, | ||||
|     start-at: start-at | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let _exists(participants, name) = { | ||||
|   for p in participants { | ||||
|     if name == p.name { | ||||
|       return true | ||||
|     } | ||||
|   } | ||||
|   return false | ||||
| } | ||||
							
								
								
									
										240
									
								
								src/renderer.typ
									
									
									
									
									
								
							
							
						
						
									
										240
									
								
								src/renderer.typ
									
									
									
									
									
								
							| @@ -1,11 +1,9 @@ | ||||
| #import "@preview/cetz:0.2.2": canvas, draw | ||||
| #import "utils.typ": get-participants-i | ||||
|  | ||||
| #let Y-SPACE = 10 | ||||
| #let PAR-PAD = (5pt, 3pt) | ||||
| #let PAR-SPACE = 10 | ||||
| #let COMMENT-PAD = 8 | ||||
| #let LIFELINE-W = 10 | ||||
| #import "group.typ" | ||||
| #import "sequence.typ" | ||||
| #import "separator.typ" | ||||
| #import "consts.typ": * | ||||
|  | ||||
|  | ||||
| #let get-columns-width(participants, elements) = { | ||||
| @@ -16,6 +14,8 @@ | ||||
|   }) | ||||
|   let pars-i = get-participants-i(participants) | ||||
|   let cells = () | ||||
|  | ||||
|   // Compute max lifeline levels | ||||
|   for elmt in elements { | ||||
|     if elmt.type == "seq" { | ||||
|       let com = if elmt.comment == none {""} else {elmt.comment} | ||||
| @@ -49,6 +49,8 @@ | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Compute column widths | ||||
|   // Compute minimum widths for participant names | ||||
|   let widths = () | ||||
|   for i in range(participants.len() - 1) { | ||||
|     let p1 = participants.at(i) | ||||
| @@ -58,6 +60,7 @@ | ||||
|     widths.push(w1 / 2pt + w2 / 2pt + PAR-SPACE) | ||||
|   } | ||||
|  | ||||
|   // Compute minimum width for simple sequences (spanning 1 column) | ||||
|   for cell in cells.filter(c => c.i2 - c.i1 == 1) { | ||||
|     let m = measure(cell.cell) | ||||
|     widths.at(cell.i1) = calc.max( | ||||
| @@ -66,6 +69,7 @@ | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   // Compute remaining widths for longer sequences (spanning multiple columns) | ||||
|   let multicol-cells = cells.filter(c => c.i2 - c.i1 > 1) | ||||
|   multicol-cells = multicol-cells.sorted(key: c => { | ||||
|     c.i1 * 1000 + c.i2 | ||||
| @@ -77,6 +81,8 @@ | ||||
|       m.width / 1pt - widths.slice(0, cell.i2 - 1).sum() | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   // Add lifeline widths | ||||
|   for (i, w) in widths.enumerate() { | ||||
|     let p1 = participants.at(i) | ||||
|     let p2 = participants.at(i + 1) | ||||
| @@ -89,57 +95,21 @@ | ||||
|   return widths | ||||
| } | ||||
|  | ||||
| #let draw-group(x0, x1, y0, y1, group) = { | ||||
|   let m = measure(box(group.name)) | ||||
|   let w = m.width / 1pt + 15 | ||||
|   let h = m.height / 1pt + 6 | ||||
|   draw.rect( | ||||
|     (x0, y0), | ||||
|     (x1, y1) | ||||
|   ) | ||||
|   draw.merge-path( | ||||
|     fill: gray.lighten(20%), | ||||
|     close: true, | ||||
|     { | ||||
|       draw.line( | ||||
|         (x0, y0), | ||||
|         (x0 + w, y0), | ||||
|         (x0 + w, y0 - h / 2), | ||||
|         (x0 + w - 5, y0 - h), | ||||
|         (x0, y0 - h) | ||||
|       ) | ||||
|     } | ||||
|   ) | ||||
|   draw.content( | ||||
|     (x0, y0), | ||||
|     group.name, | ||||
|     anchor: "north-west", | ||||
|     padding: (left: 5pt, right: 10pt, top: 3pt, bottom: 3pt) | ||||
|   ) | ||||
|  | ||||
|   if group.desc != none { | ||||
|     draw.content( | ||||
|       (x0 + w, y0), | ||||
|       text([\[#group.desc\]], weight: "bold"), | ||||
|       anchor: "north-west", | ||||
|       padding: 3pt | ||||
|     ) | ||||
|   } | ||||
| } | ||||
|  | ||||
| #let render(participants, elements) = context canvas(length: 1pt, { | ||||
|   let shapes = () | ||||
|   let pars-i = get-participants-i(participants) | ||||
|  | ||||
|   let widths = get-columns-width(participants, elements) | ||||
|  | ||||
|   // Compute each column's X position | ||||
|   let x-pos = (0,) | ||||
|   for width in widths { | ||||
|     x-pos.push(x-pos.last() + width) | ||||
|   } | ||||
|    | ||||
|   // Draw participants | ||||
|   // Draw participants (start) | ||||
|   for (i, p) in participants.enumerate() { | ||||
|     draw.content( | ||||
|     shapes += draw.content( | ||||
|       (x-pos.at(i), 0), | ||||
|       p.display-name, | ||||
|       name: p.name, | ||||
| @@ -156,124 +126,23 @@ | ||||
|     lines: () | ||||
|   )) | ||||
|  | ||||
|   // Draw sequences | ||||
|   let draw-seq = sequence.render.with(pars-i, x-pos) | ||||
|   let draw-group = group.render.with() | ||||
|   let draw-sep = separator.render.with(x-pos) | ||||
|  | ||||
|   // Draw elemnts | ||||
|   for elmt in elements { | ||||
|     // Sequences | ||||
|     if elmt.type == "seq" { | ||||
|       let i1 = pars-i.at(elmt.p1) | ||||
|       let i2 = pars-i.at(elmt.p2) | ||||
|  | ||||
|       if elmt.comment != none { | ||||
|         y -= measure(box(elmt.comment)).height / 1pt + 6 | ||||
|       } | ||||
|  | ||||
|       if elmt.disable-src { | ||||
|         let src-line = lifelines.at(i1) | ||||
|         src-line.level -= 1 | ||||
|         src-line.lines.push(("disable", y, auto)) | ||||
|         lifelines.at(i1) = src-line | ||||
|       } | ||||
|       if elmt.destroy-src { | ||||
|         let src-line = lifelines.at(i1) | ||||
|         src-line.level -= 1 | ||||
|         src-line.lines.push(("destroy", y, auto)) | ||||
|         lifelines.at(i1) = src-line | ||||
|       } | ||||
|  | ||||
|       let ll-lvl1 = lifelines.at(i1).level * LIFELINE-W / 2 | ||||
|  | ||||
|       if elmt.disable-dst { | ||||
|         let dst-line = lifelines.at(i2) | ||||
|         dst-line.level -= 1 | ||||
|         dst-line.lines.push(("disable", y, auto)) | ||||
|         lifelines.at(i2) = dst-line | ||||
|       } | ||||
|       if elmt.destroy-dst { | ||||
|         let dst-line = lifelines.at(i2) | ||||
|         dst-line.level -= 1 | ||||
|         dst-line.lines.push(("destroy", y, auto)) | ||||
|         lifelines.at(i2) = dst-line | ||||
|       } | ||||
|       if elmt.enable-dst { | ||||
|         let dst-line = lifelines.at(i2) | ||||
|         dst-line.level += 1 | ||||
|         lifelines.at(i2) = dst-line | ||||
|       } | ||||
|  | ||||
|       let x1 = x-pos.at(i1) | ||||
|       let x2 = x-pos.at(i2) | ||||
|  | ||||
|       let ll-lvl2 = lifelines.at(i2).level * LIFELINE-W / 2 | ||||
|  | ||||
|       let f = if elmt.flip {-1} else {1} | ||||
|       if i1 <= i2 { | ||||
|         x1 += ll-lvl1 * f | ||||
|         x2 -= ll-lvl2 * f | ||||
|       } else { | ||||
|         x1 -= ll-lvl1 * f | ||||
|         x2 += ll-lvl2 * f | ||||
|       } | ||||
|  | ||||
|       let style = ( | ||||
|         mark: (end: "straight"), | ||||
|         stroke: ( | ||||
|           dash: if elmt.dashed {"dashed"} else {"solid"}, | ||||
|           paint: elmt.color | ||||
|         ) | ||||
|       ) | ||||
|  | ||||
|       if elmt.p1 == elmt.p2 { | ||||
|         let x3 = x1 - ll-lvl1 + ll-lvl2 | ||||
|  | ||||
|         x2 = if elmt.flip {x1 - 20} else {x1 + 20} | ||||
|  | ||||
|         if elmt.comment != none { | ||||
|           draw.content( | ||||
|             (x1, y), | ||||
|             elmt.comment, | ||||
|             anchor: if elmt.flip {"south-east"} else {"south-west"}, | ||||
|             padding: 3pt | ||||
|           ) | ||||
|         } | ||||
|  | ||||
|         draw.line( | ||||
|           (x1, y), | ||||
|           (x2, y), | ||||
|           (x2, y - 10), | ||||
|           (x3, y - 10), | ||||
|           ..style | ||||
|         ) | ||||
|         y -= 10 | ||||
|  | ||||
|       } else { | ||||
|         if elmt.comment != none { | ||||
|           let x = calc.min(x1, x2) | ||||
|           if x2 < x1 { | ||||
|             x += COMMENT-PAD | ||||
|           } | ||||
|           draw.content( | ||||
|             (x, y), | ||||
|             elmt.comment, | ||||
|             anchor: "south-west", | ||||
|             padding: 3pt | ||||
|           ) | ||||
|         } | ||||
|  | ||||
|         draw.line( | ||||
|           (x1, y), | ||||
|           (x2, y), | ||||
|           ..style | ||||
|         ) | ||||
|       } | ||||
|       if elmt.enable-dst { | ||||
|         let dst-line = lifelines.at(i2) | ||||
|         dst-line.lines.push(("enable", y, auto)) | ||||
|         lifelines.at(i2) = dst-line | ||||
|       } | ||||
|       y -= Y-SPACE | ||||
|       let shps | ||||
|       (y, lifelines, shps) = draw-seq(elmt, y, lifelines) | ||||
|       shapes += shps | ||||
|  | ||||
|     // Groups (start) -> reserve space for labels + store position | ||||
|     } else if elmt.type == "grp" { | ||||
|       let m = measure( | ||||
|         box( | ||||
|           elmt.name, | ||||
|           inset: (left: 5pt, right: 5pt, top: 3pt, bottom: 3pt), | ||||
|         ) | ||||
|       ) | ||||
| @@ -285,53 +154,33 @@ | ||||
|       groups.push((y, elmt, 0, 0)) | ||||
|       y -= m.height / 1pt + Y-SPACE | ||||
|      | ||||
|     // Groups (end) -> actual drawing | ||||
|     } else if elmt.type == "grp-end" { | ||||
|       let (start-y, group, start-lvl, end-lvl) = groups.pop() | ||||
|       let x0 = x-pos.at(group.min-i) - start-lvl * 10 - 20 | ||||
|       let x1 = x-pos.at(group.max-i) + end-lvl * 10 + 20 | ||||
|       draw-group(x0, x1, start-y, y, group) | ||||
|       shapes += draw-group(x0, x1, start-y, y, group) | ||||
|  | ||||
|       y -= Y-SPACE | ||||
|  | ||||
|     // Separator | ||||
|     } else if elmt.type == "sep" { | ||||
|       let x0 = x-pos.first() - 20 | ||||
|       let x1 = x-pos.last() + 20 | ||||
|       let m = measure( | ||||
|         box( | ||||
|           elmt.name, | ||||
|           inset: (left: 3pt, right: 3pt, top: 5pt, bottom: 5pt) | ||||
|         ) | ||||
|       ) | ||||
|       let w = m.width / 1pt | ||||
|       let h = m.height / 1pt | ||||
|       let cx = (x0 + x1) / 2 | ||||
|       let xl = cx - w / 2 | ||||
|       let xr = cx + w / 2 | ||||
|  | ||||
|       y -= h / 2 | ||||
|       draw.line((x0, y), (xl, y)) | ||||
|       draw.line((xr, y), (x1, y)) | ||||
|       y -= 3 | ||||
|       draw.line((x0, y), (xl, y)) | ||||
|       draw.line((xr, y), (x1, y)) | ||||
|       draw.content( | ||||
|         ((x0 + x1) / 2, y + 1.5), | ||||
|         elmt.name, | ||||
|         anchor: "center", | ||||
|         padding: (5pt, 3pt), | ||||
|         frame: "rect" | ||||
|       ) | ||||
|       y -= h / 2 | ||||
|       y -= Y-SPACE | ||||
|       let shps | ||||
|       (y, shps) = draw-sep(elmt, y) | ||||
|       shapes += shps | ||||
|      | ||||
|     // Gap | ||||
|     } else if elmt.type == "gap" { | ||||
|       y -= elmt.size | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Draw vertical lines + end participants | ||||
|   draw.on-layer(-1, { | ||||
|   // Draw vertical lines + lifelines + end participants | ||||
|   shapes += draw.on-layer(-1, { | ||||
|     for (i, p) in participants.enumerate() { | ||||
|       let x = x-pos.at(i) | ||||
|  | ||||
|       // Draw vertical line | ||||
|       draw.line( | ||||
|         (x, 0), | ||||
|         (x, y), | ||||
| @@ -341,10 +190,13 @@ | ||||
|       let rects = () | ||||
|       let destructions = () | ||||
|       let lines = () | ||||
|  | ||||
|       // Compute lifeline rectangles + destruction positions | ||||
|       for line in lifelines.at(i).lines { | ||||
|         let event = line.first() | ||||
|         if event == "enable" { | ||||
|           lines.push(line) | ||||
|          | ||||
|         } else if event == "disable" or event == "destroy" { | ||||
|           let l = lines.pop() | ||||
|           let lvl = lines.len() | ||||
| @@ -355,19 +207,23 @@ | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Draw lifeline rectangles (reverse for bottom to top) | ||||
|       for rect in rects.rev() { | ||||
|         let (cx, y0, y1) = rect | ||||
|         draw.rect( | ||||
|           (cx - LIFELINE-W / 2, y0), | ||||
|           (cx + LIFELINE-W / 2, y1), | ||||
|           (cx + LIFELINE-W / 2, y1) | ||||
|         ) | ||||
|       } | ||||
|  | ||||
|       // Draw lifeline destructions | ||||
|       for dest in destructions { | ||||
|         let (cx, cy) = dest | ||||
|         draw.line((cx - 8, cy - 8), (cx + 8, cy + 8), stroke: red + 2pt) | ||||
|         draw.line((cx - 8, cy + 8), (cx + 8, cy - 8), stroke: red + 2pt) | ||||
|       } | ||||
|  | ||||
|       // Draw participants (end) | ||||
|       draw.content( | ||||
|         (x, y), | ||||
|         p.display-name, | ||||
| @@ -378,4 +234,6 @@ | ||||
|       ) | ||||
|     } | ||||
|   }) | ||||
|  | ||||
|   shapes | ||||
| }) | ||||
							
								
								
									
										46
									
								
								src/separator.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/separator.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "consts.typ": * | ||||
|  | ||||
| #let _sep(name) = { | ||||
|   return (( | ||||
|     type: "sep", | ||||
|     name: name | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let render(x-pos, elmt, y) = { | ||||
|   let shapes = () | ||||
|  | ||||
|   let x0 = x-pos.first() - 20 | ||||
|   let x1 = x-pos.last() + 20 | ||||
|   let m = measure( | ||||
|     box( | ||||
|       elmt.name, | ||||
|       inset: (left: 3pt, right: 3pt, top: 5pt, bottom: 5pt) | ||||
|     ) | ||||
|   ) | ||||
|   let w = m.width / 1pt | ||||
|   let h = m.height / 1pt | ||||
|   let cx = (x0 + x1) / 2 | ||||
|   let xl = cx - w / 2 | ||||
|   let xr = cx + w / 2 | ||||
|  | ||||
|   y -= h / 2 | ||||
|   shapes += draw.line((x0, y), (xl, y)) | ||||
|   shapes += draw.line((xr, y), (x1, y)) | ||||
|   y -= 3 | ||||
|   shapes += draw.line((x0, y), (xl, y)) | ||||
|   shapes += draw.line((xr, y), (x1, y)) | ||||
|   shapes += draw.content( | ||||
|     ((x0 + x1) / 2, y + 1.5), | ||||
|     elmt.name, | ||||
|     anchor: "center", | ||||
|     padding: (5pt, 3pt), | ||||
|     frame: "rect" | ||||
|   ) | ||||
|   y -= h / 2 | ||||
|   y -= Y-SPACE | ||||
|  | ||||
|   let r = (y, shapes) | ||||
|   return r | ||||
| } | ||||
							
								
								
									
										152
									
								
								src/sequence.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/sequence.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| #import "consts.typ": * | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
|  | ||||
| #let _seq( | ||||
|   p1, | ||||
|   p2, | ||||
|   comment: none, | ||||
|   dashed: false, | ||||
|   tip: "default", | ||||
|   color: black, | ||||
|   flip: false, | ||||
|   enable-dst: false, | ||||
|   disable-dst: false, | ||||
|   destroy-dst: false, | ||||
|   disable-src: false, | ||||
|   destroy-src: false, | ||||
| ) = { | ||||
|   return (( | ||||
|     type: "seq", | ||||
|     p1: p1, | ||||
|     p2: p2, | ||||
|     comment: comment, | ||||
|     dashed: dashed, | ||||
|     tip: tip, | ||||
|     color: color, | ||||
|     flip: flip, | ||||
|     enable-dst: enable-dst, | ||||
|     disable-dst: disable-dst, | ||||
|     destroy-dst: destroy-dst, | ||||
|     disable-src: disable-src, | ||||
|     destroy-src: destroy-src, | ||||
|   ),) | ||||
| } | ||||
|  | ||||
| #let render(pars-i, x-pos, elmt, y, lifelines) = { | ||||
|   let shapes = () | ||||
|  | ||||
|   let i1 = pars-i.at(elmt.p1) | ||||
|   let i2 = pars-i.at(elmt.p2) | ||||
|  | ||||
|   if elmt.comment != none { | ||||
|     y -= measure(box(elmt.comment)).height / 1pt + 6 | ||||
|   } | ||||
|  | ||||
|   if elmt.disable-src { | ||||
|     let src-line = lifelines.at(i1) | ||||
|     src-line.level -= 1 | ||||
|     src-line.lines.push(("disable", y, auto)) | ||||
|     lifelines.at(i1) = src-line | ||||
|   } | ||||
|   if elmt.destroy-src { | ||||
|     let src-line = lifelines.at(i1) | ||||
|     src-line.level -= 1 | ||||
|     src-line.lines.push(("destroy", y, auto)) | ||||
|     lifelines.at(i1) = src-line | ||||
|   } | ||||
|  | ||||
|   let ll-lvl1 = lifelines.at(i1).level * LIFELINE-W / 2 | ||||
|  | ||||
|   if elmt.disable-dst { | ||||
|     let dst-line = lifelines.at(i2) | ||||
|     dst-line.level -= 1 | ||||
|     dst-line.lines.push(("disable", y, auto)) | ||||
|     lifelines.at(i2) = dst-line | ||||
|   } | ||||
|   if elmt.destroy-dst { | ||||
|     let dst-line = lifelines.at(i2) | ||||
|     dst-line.level -= 1 | ||||
|     dst-line.lines.push(("destroy", y, auto)) | ||||
|     lifelines.at(i2) = dst-line | ||||
|   } | ||||
|   if elmt.enable-dst { | ||||
|     let dst-line = lifelines.at(i2) | ||||
|     dst-line.level += 1 | ||||
|     lifelines.at(i2) = dst-line | ||||
|   } | ||||
|  | ||||
|   let x1 = x-pos.at(i1) | ||||
|   let x2 = x-pos.at(i2) | ||||
|  | ||||
|   let ll-lvl2 = lifelines.at(i2).level * LIFELINE-W / 2 | ||||
|  | ||||
|   let f = if elmt.flip {-1} else {1} | ||||
|   if i1 <= i2 { | ||||
|     x1 += ll-lvl1 * f | ||||
|     x2 -= ll-lvl2 * f | ||||
|   } else { | ||||
|     x1 -= ll-lvl1 * f | ||||
|     x2 += ll-lvl2 * f | ||||
|   } | ||||
|  | ||||
|   let style = ( | ||||
|     mark: (end: "straight"), | ||||
|     stroke: ( | ||||
|       dash: if elmt.dashed {"dashed"} else {"solid"}, | ||||
|       paint: elmt.color | ||||
|     ) | ||||
|   ) | ||||
|  | ||||
|   if elmt.p1 == elmt.p2 { | ||||
|     let x3 = x1 - ll-lvl1 + ll-lvl2 | ||||
|  | ||||
|     x2 = if elmt.flip {x1 - 20} else {x1 + 20} | ||||
|  | ||||
|     if elmt.comment != none { | ||||
|       shapes += draw.content( | ||||
|         (x1, y), | ||||
|         elmt.comment, | ||||
|         anchor: if elmt.flip {"south-east"} else {"south-west"}, | ||||
|         padding: 3pt | ||||
|       ) | ||||
|     } | ||||
|  | ||||
|     shapes += draw.line( | ||||
|       (x1, y), | ||||
|       (x2, y), | ||||
|       (x2, y - 10), | ||||
|       (x3, y - 10), | ||||
|       ..style | ||||
|     ) | ||||
|     y -= 10 | ||||
|  | ||||
|   } else { | ||||
|     if elmt.comment != none { | ||||
|       let x = calc.min(x1, x2) | ||||
|       if x2 < x1 { | ||||
|         x += COMMENT-PAD | ||||
|       } | ||||
|       shapes += draw.content( | ||||
|         (x, y), | ||||
|         elmt.comment, | ||||
|         anchor: "south-west", | ||||
|         padding: 3pt | ||||
|       ) | ||||
|     } | ||||
|  | ||||
|     shapes += draw.line( | ||||
|       (x1, y), | ||||
|       (x2, y), | ||||
|       ..style | ||||
|     ) | ||||
|   } | ||||
|   if elmt.enable-dst { | ||||
|     let dst-line = lifelines.at(i2) | ||||
|     dst-line.lines.push(("enable", y, auto)) | ||||
|     lifelines.at(i2) = dst-line | ||||
|   } | ||||
|   y -= Y-SPACE | ||||
|  | ||||
|   let r = (y, lifelines, shapes) | ||||
|   return r | ||||
| } | ||||
		Reference in New Issue
	
	Block a user