Compare commits
	
		
			2 Commits
		
	
	
		
			0e0be4e76a
			...
			ed84e06560
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						ed84e06560
	
				 | 
					
					
						|||
| 
						
						
							
						
						94d0eb286e
	
				 | 
					
					
						
										
											Binary file not shown.
										
									
								
							@@ -10,7 +10,7 @@ Alice <-- Bob: Another authentication Response
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
					  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
				
			||||||
  _seq("Bob", "Alice", comment: "Authentication Response", dashed: true)
 | 
					  _seq("Bob", "Alice", comment: "Authentication Response", dashed: true)
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@@ -19,19 +19,19 @@ Alice <-- Bob: Another authentication Response
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Bob", "Alice", comment: "bonjour", color: red)
 | 
					  _seq("Bob", "Alice", comment: "bonjour", color: red)
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "ok", color: blue)
 | 
					  _seq("Alice", "Bob", comment: "ok", color: blue)
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "This is a test")
 | 
					  _seq("Alice", "Bob", comment: "This is a test")
 | 
				
			||||||
  _seq("Alice", "Callum", comment: "This is another test with a long text")
 | 
					  _seq("Alice", "Callum", comment: "This is another test with a long text")
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
					  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
				
			||||||
  _seq("Bob", "Alice", comment: "Authentication Failure")
 | 
					  _seq("Bob", "Alice", comment: "Authentication Failure")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +45,7 @@ Alice <-- Bob: Another authentication Response
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _sep("Initialization")
 | 
					  _sep("Initialization")
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
					  _seq("Alice", "Bob", comment: "Authentication Request")
 | 
				
			||||||
  _seq("Bob", "Alice", comment: "Authentication Response", dashed: true)
 | 
					  _seq("Bob", "Alice", comment: "Authentication Response", dashed: true)
 | 
				
			||||||
@@ -56,7 +56,7 @@ Alice <-- Bob: Another authentication Response
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Alice", "Bob", comment: "message 1")
 | 
					  _seq("Alice", "Bob", comment: "message 1")
 | 
				
			||||||
  _seq("Bob", "Alice", comment: "ok", dashed: true)
 | 
					  _seq("Bob", "Alice", comment: "ok", dashed: true)
 | 
				
			||||||
  _gap()
 | 
					  _gap()
 | 
				
			||||||
@@ -68,7 +68,7 @@ Alice <-- Bob: Another authentication Response
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#chronos.diagram({
 | 
					#chronos.diagram({
 | 
				
			||||||
  import "/src/diagram.typ": *
 | 
					  import chronos: *
 | 
				
			||||||
  _seq("Alice", "Alice", comment: "On the\nright")
 | 
					  _seq("Alice", "Alice", comment: "On the\nright")
 | 
				
			||||||
  _seq("Alice", "Alice", flip: true, comment: "On the\nleft")
 | 
					  _seq("Alice", "Alice", flip: true, comment: "On the\nleft")
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								gallery/example2.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gallery/example2.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										40
									
								
								gallery/example2.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								gallery/example2.typ
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					#import "/src/lib.typ" as chronos
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#chronos.diagram({
 | 
				
			||||||
 | 
					  import chronos: *
 | 
				
			||||||
 | 
					  _seq("User", "A", comment: "DoWork", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("A", "B", comment: [#sym.quote.angle.l createRequest #sym.quote.angle.r], enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("B", "C", comment: "DoWork", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("C", "B", comment: "WorkDone", destroy-src: true, dashed: true)
 | 
				
			||||||
 | 
					  _seq("B", "A", comment: "RequestCreated", disable-src: true, dashed: true)
 | 
				
			||||||
 | 
					  _seq("A", "User", comment: "Done", disable-src: true)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#chronos.diagram({
 | 
				
			||||||
 | 
					  import chronos: *
 | 
				
			||||||
 | 
					  _seq("User", "A", comment: "DoWork", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("A", "A", comment: "Internal call", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("A", "B", comment: [#sym.quote.angle.l createRequest #sym.quote.angle.r], enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("B", "A", comment: "RequestCreated", disable-src: true, disable-dst: true, dashed: true)
 | 
				
			||||||
 | 
					  _seq("A", "User", comment: "Done", disable-src: true)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#chronos.diagram({
 | 
				
			||||||
 | 
					  import chronos: *
 | 
				
			||||||
 | 
					  _seq("alice", "bob", comment: "hello", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("bob", "bob", comment: "self call", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("bill", "bob", comment: "hello from thread 2", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("bob", "george", comment: "create", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("bob", "bill", comment: "done in thread 2", disable-src: true, dashed: true)
 | 
				
			||||||
 | 
					  _seq("bob", "bob", comment: "rc", disable-src: true, dashed: true)
 | 
				
			||||||
 | 
					  _seq("bob", "george", comment: "delete", destroy-dst: true)
 | 
				
			||||||
 | 
					  _seq("bob", "alice", comment: "success", disable-src: true, dashed: true)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#chronos.diagram({
 | 
				
			||||||
 | 
					  import chronos: *
 | 
				
			||||||
 | 
					  _seq("alice", "bob", comment: "hello1", enable-dst: true)
 | 
				
			||||||
 | 
					  _seq("bob", "charlie", comment: "hello2", enable-dst: true, disable-src: true)
 | 
				
			||||||
 | 
					  _seq("charlie", "alice", comment: "ok", dashed: true, disable-src: true)
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										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,61 +1,6 @@
 | 
				
			|||||||
#import "utils.typ": get-group-span
 | 
					#import "utils.typ": get-group-span
 | 
				
			||||||
#import "renderer.typ": render
 | 
					#import "renderer.typ": render
 | 
				
			||||||
 | 
					#import "participant.typ" as participant: _par
 | 
				
			||||||
#let _seq(
 | 
					 | 
				
			||||||
  p1,
 | 
					 | 
				
			||||||
  p2,
 | 
					 | 
				
			||||||
  comment: none,
 | 
					 | 
				
			||||||
  dashed: false,
 | 
					 | 
				
			||||||
  tip: "default",
 | 
					 | 
				
			||||||
  color: black,
 | 
					 | 
				
			||||||
  flip: false
 | 
					 | 
				
			||||||
) = {
 | 
					 | 
				
			||||||
  return ((
 | 
					 | 
				
			||||||
    type: "seq",
 | 
					 | 
				
			||||||
    p1: p1,
 | 
					 | 
				
			||||||
    p2: p2,
 | 
					 | 
				
			||||||
    comment: comment,
 | 
					 | 
				
			||||||
    dashed: dashed,
 | 
					 | 
				
			||||||
    tip: tip,
 | 
					 | 
				
			||||||
    color: color,
 | 
					 | 
				
			||||||
    flip: flip
 | 
					 | 
				
			||||||
  ),)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
  ),)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#let _gap(size: 20) = {
 | 
					#let _gap(size: 20) = {
 | 
				
			||||||
  return ((
 | 
					  return ((
 | 
				
			||||||
@@ -68,6 +13,8 @@
 | 
				
			|||||||
  let participants = ()
 | 
					  let participants = ()
 | 
				
			||||||
  let elmts = elements
 | 
					  let elmts = elements
 | 
				
			||||||
  let i = 0
 | 
					  let i = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Flatten groups
 | 
				
			||||||
  while i < elmts.len() {
 | 
					  while i < elmts.len() {
 | 
				
			||||||
    let elmt = elmts.at(i)
 | 
					    let elmt = elmts.at(i)
 | 
				
			||||||
    if elmt.type == "grp" {
 | 
					    if elmt.type == "grp" {
 | 
				
			||||||
@@ -83,19 +30,21 @@
 | 
				
			|||||||
    i += 1
 | 
					    i += 1
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // List participants
 | 
				
			||||||
  for elmt in elmts {
 | 
					  for elmt in elmts {
 | 
				
			||||||
    if elmt.type == "par" {
 | 
					    if elmt.type == "par" {
 | 
				
			||||||
      participants.push(elmt)
 | 
					      participants.push(elmt)
 | 
				
			||||||
    } else if elmt.type == "seq" {
 | 
					    } 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())
 | 
					        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())
 | 
					        participants.push(_par(elmt.p2).first())
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Compute groups spans (horizontal)
 | 
				
			||||||
  for (i, elmt) in elmts.enumerate() {
 | 
					  for (i, elmt) in elmts.enumerate() {
 | 
				
			||||||
    if elmt.type == "grp" {
 | 
					    if elmt.type == "grp" {
 | 
				
			||||||
      let (min-i, max-i) = get-group-span(participants, elmt)
 | 
					      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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										246
									
								
								src/renderer.typ
									
									
									
									
									
								
							
							
						
						
									
										246
									
								
								src/renderer.typ
									
									
									
									
									
								
							@@ -1,15 +1,21 @@
 | 
				
			|||||||
#import "@preview/cetz:0.2.2": canvas, draw
 | 
					#import "@preview/cetz:0.2.2": canvas, draw
 | 
				
			||||||
#import "utils.typ": get-participants-i
 | 
					#import "utils.typ": get-participants-i
 | 
				
			||||||
 | 
					#import "group.typ"
 | 
				
			||||||
#let Y-SPACE = 10
 | 
					#import "sequence.typ"
 | 
				
			||||||
#let PAR-PAD = (5pt, 3pt)
 | 
					#import "separator.typ"
 | 
				
			||||||
#let PAR-SPACE = 10
 | 
					#import "consts.typ": *
 | 
				
			||||||
#let COMMENT-PAD = 8
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#let get-columns-width(participants, elements) = {
 | 
					#let get-columns-width(participants, elements) = {
 | 
				
			||||||
 | 
					  participants = participants.map(p => {
 | 
				
			||||||
 | 
					    p.insert("lifeline-lvl", 0)
 | 
				
			||||||
 | 
					    p.insert("max-lifelines", 0)
 | 
				
			||||||
 | 
					    p
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
  let pars-i = get-participants-i(participants)
 | 
					  let pars-i = get-participants-i(participants)
 | 
				
			||||||
  let cells = ()
 | 
					  let cells = ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Compute max lifeline levels
 | 
				
			||||||
  for elmt in elements {
 | 
					  for elmt in elements {
 | 
				
			||||||
    if elmt.type == "seq" {
 | 
					    if elmt.type == "seq" {
 | 
				
			||||||
      let com = if elmt.comment == none {""} else {elmt.comment}
 | 
					      let com = if elmt.comment == none {""} else {elmt.comment}
 | 
				
			||||||
@@ -23,9 +29,28 @@
 | 
				
			|||||||
          cell: box(com, inset: 3pt)
 | 
					          cell: box(com, inset: 3pt)
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if elmt.disable-src or elmt.destroy-src {
 | 
				
			||||||
 | 
					        let p = participants.at(i1)
 | 
				
			||||||
 | 
					        p.lifeline-lvl -= 1
 | 
				
			||||||
 | 
					        participants.at(i1) = p
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if elmt.disable-dst {
 | 
				
			||||||
 | 
					        let p = participants.at(i2)
 | 
				
			||||||
 | 
					        p.lifeline-lvl -= 1
 | 
				
			||||||
 | 
					        participants.at(i2) = p
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if elmt.enable-dst {
 | 
				
			||||||
 | 
					        let p = participants.at(i2)
 | 
				
			||||||
 | 
					        p.lifeline-lvl += 1
 | 
				
			||||||
 | 
					        p.max-lifelines = calc.max(p.max-lifelines, p.lifeline-lvl)
 | 
				
			||||||
 | 
					        participants.at(i2) = p
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Compute column widths
 | 
				
			||||||
 | 
					  // Compute minimum widths for participant names
 | 
				
			||||||
  let widths = ()
 | 
					  let widths = ()
 | 
				
			||||||
  for i in range(participants.len() - 1) {
 | 
					  for i in range(participants.len() - 1) {
 | 
				
			||||||
    let p1 = participants.at(i)
 | 
					    let p1 = participants.at(i)
 | 
				
			||||||
@@ -35,6 +60,7 @@
 | 
				
			|||||||
    widths.push(w1 / 2pt + w2 / 2pt + PAR-SPACE)
 | 
					    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) {
 | 
					  for cell in cells.filter(c => c.i2 - c.i1 == 1) {
 | 
				
			||||||
    let m = measure(cell.cell)
 | 
					    let m = measure(cell.cell)
 | 
				
			||||||
    widths.at(cell.i1) = calc.max(
 | 
					    widths.at(cell.i1) = calc.max(
 | 
				
			||||||
@@ -43,6 +69,7 @@
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Compute remaining widths for longer sequences (spanning multiple columns)
 | 
				
			||||||
  let multicol-cells = cells.filter(c => c.i2 - c.i1 > 1)
 | 
					  let multicol-cells = cells.filter(c => c.i2 - c.i1 > 1)
 | 
				
			||||||
  multicol-cells = multicol-cells.sorted(key: c => {
 | 
					  multicol-cells = multicol-cells.sorted(key: c => {
 | 
				
			||||||
    c.i1 * 1000 + c.i2
 | 
					    c.i1 * 1000 + c.i2
 | 
				
			||||||
@@ -54,60 +81,35 @@
 | 
				
			|||||||
      m.width / 1pt - widths.slice(0, cell.i2 - 1).sum()
 | 
					      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)
 | 
				
			||||||
 | 
					    let w = w + p1.max-lifelines * LIFELINE-W / 2
 | 
				
			||||||
 | 
					    if p2.max-lifelines != 0 {
 | 
				
			||||||
 | 
					      w += LIFELINE-W / 2
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    widths.at(i) = w
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return widths
 | 
					  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 render(participants, elements) = context canvas(length: 1pt, {
 | 
				
			||||||
 | 
					  let shapes = ()
 | 
				
			||||||
  let pars-i = get-participants-i(participants)
 | 
					  let pars-i = get-participants-i(participants)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let widths = get-columns-width(participants, elements)
 | 
					  let widths = get-columns-width(participants, elements)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Compute each column's X position
 | 
				
			||||||
  let x-pos = (0,)
 | 
					  let x-pos = (0,)
 | 
				
			||||||
  for width in widths {
 | 
					  for width in widths {
 | 
				
			||||||
    x-pos.push(x-pos.last() + width)
 | 
					    x-pos.push(x-pos.last() + width)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  // Draw participants
 | 
					  // Draw participants (start)
 | 
				
			||||||
  for (i, p) in participants.enumerate() {
 | 
					  for (i, p) in participants.enumerate() {
 | 
				
			||||||
    draw.content(
 | 
					    shapes += draw.content(
 | 
				
			||||||
      (x-pos.at(i), 0),
 | 
					      (x-pos.at(i), 0),
 | 
				
			||||||
      p.display-name,
 | 
					      p.display-name,
 | 
				
			||||||
      name: p.name,
 | 
					      name: p.name,
 | 
				
			||||||
@@ -119,68 +121,28 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  let y = -Y-SPACE
 | 
					  let y = -Y-SPACE
 | 
				
			||||||
  let groups = ()
 | 
					  let groups = ()
 | 
				
			||||||
 | 
					  let lifelines = participants.map(_ => (
 | 
				
			||||||
 | 
					    level: 0,
 | 
				
			||||||
 | 
					    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 {
 | 
					  for elmt in elements {
 | 
				
			||||||
 | 
					    // Sequences
 | 
				
			||||||
    if elmt.type == "seq" {
 | 
					    if elmt.type == "seq" {
 | 
				
			||||||
      let x1 = x-pos.at(pars-i.at(elmt.p1))
 | 
					      let shps
 | 
				
			||||||
      let x2 = x-pos.at(pars-i.at(elmt.p2))
 | 
					      (y, lifelines, shps) = draw-seq(elmt, y, lifelines)
 | 
				
			||||||
      let style = (
 | 
					      shapes += shps
 | 
				
			||||||
        mark: (end: "straight"),
 | 
					 | 
				
			||||||
        stroke: (
 | 
					 | 
				
			||||||
          dash: if elmt.dashed {"dashed"} else {"solid"},
 | 
					 | 
				
			||||||
          paint: elmt.color
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if elmt.p1 == elmt.p2 {
 | 
					 | 
				
			||||||
        x2 = if elmt.flip {x1 - 20} else {x1 + 20}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if elmt.comment != none {
 | 
					 | 
				
			||||||
          y -= measure(box(elmt.comment)).height / 1pt + 6
 | 
					 | 
				
			||||||
          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),
 | 
					 | 
				
			||||||
          (x1, y - 10),
 | 
					 | 
				
			||||||
          ..style
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        y -= 10
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        if elmt.comment != none {
 | 
					 | 
				
			||||||
          let x = calc.min(x1, x2)
 | 
					 | 
				
			||||||
          if x2 < x1 {
 | 
					 | 
				
			||||||
            x += COMMENT-PAD
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          y -= measure(box(elmt.comment)).height / 1pt + 6
 | 
					 | 
				
			||||||
          draw.content(
 | 
					 | 
				
			||||||
            (x, y),
 | 
					 | 
				
			||||||
            elmt.comment,
 | 
					 | 
				
			||||||
            anchor: "south-west",
 | 
					 | 
				
			||||||
            padding: 3pt
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        draw.line(
 | 
					 | 
				
			||||||
          (x1, y),
 | 
					 | 
				
			||||||
          (x2, y),
 | 
					 | 
				
			||||||
          ..style
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      y -= Y-SPACE
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Groups (start) -> reserve space for labels + store position
 | 
				
			||||||
    } else if elmt.type == "grp" {
 | 
					    } else if elmt.type == "grp" {
 | 
				
			||||||
      let m = measure(
 | 
					      let m = measure(
 | 
				
			||||||
        box(
 | 
					        box(
 | 
				
			||||||
 | 
					          elmt.name,
 | 
				
			||||||
          inset: (left: 5pt, right: 5pt, top: 3pt, bottom: 3pt),
 | 
					          inset: (left: 5pt, right: 5pt, top: 3pt, bottom: 3pt),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
@@ -192,58 +154,76 @@
 | 
				
			|||||||
      groups.push((y, elmt, 0, 0))
 | 
					      groups.push((y, elmt, 0, 0))
 | 
				
			||||||
      y -= m.height / 1pt + Y-SPACE
 | 
					      y -= m.height / 1pt + Y-SPACE
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    // Groups (end) -> actual drawing
 | 
				
			||||||
    } else if elmt.type == "grp-end" {
 | 
					    } else if elmt.type == "grp-end" {
 | 
				
			||||||
      let (start-y, group, start-lvl, end-lvl) = groups.pop()
 | 
					      let (start-y, group, start-lvl, end-lvl) = groups.pop()
 | 
				
			||||||
      let x0 = x-pos.at(group.min-i) - start-lvl * 10 - 20
 | 
					      let x0 = x-pos.at(group.min-i) - start-lvl * 10 - 20
 | 
				
			||||||
      let x1 = x-pos.at(group.max-i) + end-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
 | 
					      y -= Y-SPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Separator
 | 
				
			||||||
    } else if elmt.type == "sep" {
 | 
					    } else if elmt.type == "sep" {
 | 
				
			||||||
      let x0 = x-pos.first() - 20
 | 
					      let shps
 | 
				
			||||||
      let x1 = x-pos.last() + 20
 | 
					      (y, shps) = draw-sep(elmt, y)
 | 
				
			||||||
      let m = measure(
 | 
					      shapes += shps
 | 
				
			||||||
        box(
 | 
					    
 | 
				
			||||||
          elmt.name,
 | 
					    // Gap
 | 
				
			||||||
          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
 | 
					 | 
				
			||||||
    } else if elmt.type == "gap" {
 | 
					    } else if elmt.type == "gap" {
 | 
				
			||||||
      y -= elmt.size
 | 
					      y -= elmt.size
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Draw vertical lines + end participants
 | 
					  // Draw vertical lines + lifelines + end participants
 | 
				
			||||||
  draw.on-layer(-1, {
 | 
					  shapes += draw.on-layer(-1, {
 | 
				
			||||||
    for (i, p) in participants.enumerate() {
 | 
					    for (i, p) in participants.enumerate() {
 | 
				
			||||||
      let x = x-pos.at(i)
 | 
					      let x = x-pos.at(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Draw vertical line
 | 
				
			||||||
      draw.line(
 | 
					      draw.line(
 | 
				
			||||||
        (x, 0),
 | 
					        (x, 0),
 | 
				
			||||||
        (x, y),
 | 
					        (x, y),
 | 
				
			||||||
        stroke: (dash: "dashed", paint: gray.darken(40%))
 | 
					        stroke: (dash: "dashed", paint: gray.darken(40%))
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      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()
 | 
				
			||||||
 | 
					          rects.push((x + lvl * LIFELINE-W / 2, l.at(1), line.at(1)))
 | 
				
			||||||
 | 
					          if event == "destroy" {
 | 
				
			||||||
 | 
					            destructions.push((x + lvl * LIFELINE-W / 2, line.at(1)))
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // 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)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // 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(
 | 
					      draw.content(
 | 
				
			||||||
        (x, y),
 | 
					        (x, y),
 | 
				
			||||||
        p.display-name,
 | 
					        p.display-name,
 | 
				
			||||||
@@ -254,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