diff --git a/gallery/example1.pdf b/gallery/example1.pdf index b1f22ec..9b37aef 100644 Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ diff --git a/gallery/example2.pdf b/gallery/example2.pdf index d9f55c1..c158811 100644 Binary files a/gallery/example2.pdf and b/gallery/example2.pdf differ diff --git a/gallery/example2.typ b/gallery/example2.typ index 5eb59dd..2b50105 100644 --- a/gallery/example2.typ +++ b/gallery/example2.typ @@ -6,7 +6,7 @@ _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("C", "B", comment: "WorkDone", destroy-src: true, disable-src: true, dashed: true) _seq("B", "A", comment: "RequestCreated", disable-src: true, dashed: true) _seq("A", "User", comment: "Done", disable-src: true) }) @@ -37,4 +37,5 @@ _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) -}) \ No newline at end of file +}) + diff --git a/src/diagram.typ b/src/diagram.typ index 9ec2f50..916b5c7 100644 --- a/src/diagram.typ +++ b/src/diagram.typ @@ -39,11 +39,18 @@ participants.push(_par(elmt.p1).first()) } if not participant._exists(participants, elmt.p2) { - participants.push(_par(elmt.p2).first()) + let par = _par(elmt.p2, from-start: not elmt.create-dst).first() + participants.push(par) } } } + // Add index to participant + for (i, p) in participants.enumerate() { + p.insert("i", i) + participants.at(i) = p + } + // Compute groups spans (horizontal) for (i, elmt) in elmts.enumerate() { if elmt.type == "grp" { diff --git a/src/participant.typ b/src/participant.typ index 5a1c6f1..4ff6761 100644 --- a/src/participant.typ +++ b/src/participant.typ @@ -1,9 +1,12 @@ -#let _par(name, display-name: auto, start-at: 0) = { +#import "@preview/cetz:0.2.2": draw +#import "consts.typ": * + +#let _par(name, display-name: auto, from-start: true) = { return (( type: "par", name: name, display-name: if display-name == auto {name} else {display-name}, - start-at: start-at + from-start: from-start ),) } @@ -14,4 +17,15 @@ } } return false +} + +#let render(x-pos, p, y: 0) = { + draw.content( + (x-pos.at(p.i), y), + p.display-name, + name: p.name, + frame: "rect", + padding: PAR-PAD, + anchor: "south" + ) } \ No newline at end of file diff --git a/src/renderer.typ b/src/renderer.typ index 7c6b951..531fc37 100644 --- a/src/renderer.typ +++ b/src/renderer.typ @@ -1,6 +1,7 @@ #import "@preview/cetz:0.2.2": canvas, draw #import "utils.typ": get-participants-i, get-style #import "group.typ" +#import "participant.typ" #import "sequence.typ" #import "separator.typ" #import "consts.typ": * @@ -106,17 +107,17 @@ for width in widths { x-pos.push(x-pos.last() + width) } + + let draw-seq = sequence.render.with(pars-i, x-pos, participants) + let draw-group = group.render.with() + let draw-sep = separator.render.with(x-pos) + let draw-par = participant.render.with(x-pos) // Draw participants (start) - for (i, p) in participants.enumerate() { - shapes += draw.content( - (x-pos.at(i), 0), - p.display-name, - name: p.name, - frame: "rect", - padding: PAR-PAD, - anchor: "south" - ) + for p in participants { + if p.from-start { + shapes += draw-par(p) + } } let y = -Y-SPACE @@ -126,10 +127,6 @@ lines: () )) - 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 @@ -181,11 +178,7 @@ let x = x-pos.at(i) // Draw vertical line - draw.line( - (x, 0), - (x, y), - stroke: (dash: "dashed", paint: gray.darken(40%)) - ) + let last-y = 0 let rects = () let destructions = () @@ -194,19 +187,45 @@ // Compute lifeline rectangles + destruction positions for line in lifelines.at(i).lines { let event = line.first() - if event == "enable" { + if event == "create" { + last-y = line.at(1) + + } else if event == "enable" { + if lines.len() == 0 { + draw.line( + (x, last-y), + (x, line.at(1)), + stroke: (dash: "dashed", paint: gray.darken(40%)) + ) + } 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))) + let lvl = 0 + if lines.len() != 0 { + let l = lines.pop() + lvl = lines.len() + rects.push(( + x + lvl * LIFELINE-W / 2, + l.at(1), + line.at(1), + l.at(2) + )) + last-y = line.at(1) + } + if event == "destroy" { destructions.push((x + lvl * LIFELINE-W / 2, line.at(1))) } } } + draw.line( + (x, last-y), + (x, y), + stroke: (dash: "dashed", paint: gray.darken(40%)) + ) + // Draw lifeline rectangles (reverse for bottom to top) for rect in rects.rev() { let (cx, y0, y1, style) = rect diff --git a/src/sequence.typ b/src/sequence.typ index aae21ac..575450f 100644 --- a/src/sequence.typ +++ b/src/sequence.typ @@ -1,5 +1,6 @@ -#import "consts.typ": * #import "@preview/cetz:0.2.2": draw +#import "consts.typ": * +#import "participant.typ" #let _seq( p1, @@ -36,15 +37,34 @@ ),) } -#let render(pars-i, x-pos, elmt, y, lifelines) = { +#let render(pars-i, x-pos, participants, elmt, y, lifelines) = { let shapes = () + // Reserve space for comment + if elmt.comment != none { + y -= measure(box(elmt.comment)).height / 1pt + 6 + } + 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 - } + let start-info = ( + i: i1, + x: x-pos.at(i1), + y: y, + ll-lvl: lifelines.at(i1).level * LIFELINE-W / 2 + ) + let end-info = ( + i: i2, + x: x-pos.at(i2), + y: y, + ll-lvl: lifelines.at(i2).level * LIFELINE-W / 2 + ) + + let ll-lvl1 = lifelines.at(i1).level * LIFELINE-W / 2 + + let x1 = x-pos.at(i1) + let x2 = x-pos.at(i2) if elmt.disable-src { let src-line = lifelines.at(i1) @@ -54,23 +74,18 @@ } if elmt.destroy-src { let src-line = lifelines.at(i1) - src-line.level -= 1 - src-line.lines.push(("destroy", y, auto)) + src-line.lines.push(("destroy", y)) 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)) + dst-line.lines.push(("disable", y)) 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)) + dst-line.lines.push(("destroy", y)) lifelines.at(i2) = dst-line } if elmt.enable-dst { @@ -78,10 +93,14 @@ dst-line.level += 1 lifelines.at(i2) = dst-line } + if elmt.create-dst { + let par = participants.at(i2) + let m = measure(box(par.display-name)) + x2 -= (m.width + PAR-PAD.last() * 2) / 2pt + shapes += participant.render(x-pos, par, y: y) + } - let x1 = x-pos.at(i1) - let x2 = x-pos.at(i2) - + end-info.ll-lvl = lifelines.at(i2).level * LIFELINE-W / 2 let ll-lvl2 = lifelines.at(i2).level * LIFELINE-W / 2 let f = if elmt.flip {-1} else {1}