194 lines
4.7 KiB
Typst
194 lines
4.7 KiB
Typst
#import "/src/cetz.typ": draw, styles
|
|
|
|
#import "/src/consts.typ": *
|
|
#import "/src/core/utils.typ": get-ctx, get-style, is-elmt, set-ctx
|
|
|
|
#let shapes = {
|
|
let from-module(path) = {
|
|
import path as mod
|
|
return (mod.name: (
|
|
get-size: mod.get-size,
|
|
render: mod.render,
|
|
default-style: mod.default-style
|
|
))
|
|
}
|
|
from-module("participant/default.typ")
|
|
from-module("participant/actor.typ")
|
|
from-module("participant/boundary.typ")
|
|
from-module("participant/control.typ")
|
|
from-module("participant/entity.typ")
|
|
from-module("participant/database.typ")
|
|
from-module("participant/collections.typ")
|
|
from-module("participant/queue.typ")
|
|
from-module("participant/custom.typ")
|
|
}
|
|
|
|
#let participant-default-style = (
|
|
fill: rgb("#E2E2F0"),
|
|
stroke: black + .5pt,
|
|
from-start: true,
|
|
show-bottom: true,
|
|
show-top: true,
|
|
shape: "participant",
|
|
track: (
|
|
dash: "dashed",
|
|
paint: gray.darken(40%),
|
|
thickness: .5pt
|
|
)
|
|
)
|
|
|
|
#let resolve-style(ctx, par) = {
|
|
let style = styles.resolve(
|
|
ctx.style,
|
|
merge: par.style,
|
|
root: "participant",
|
|
base: participant-default-style
|
|
)
|
|
let shape-style = shapes.at(style.shape, default: (:))
|
|
.at("default-style", default: (:))
|
|
style = styles.resolve(
|
|
ctx.style,
|
|
merge: style,
|
|
base: shape-style
|
|
)
|
|
return style
|
|
}
|
|
|
|
#let pre-resolve-styles() = get-ctx(ctx => {
|
|
let idx = (:)
|
|
let elements = ctx.setup.elements
|
|
let participants = ctx.setup.participants
|
|
for (i, par) in participants.enumerate() {
|
|
par.insert("resolved-style", resolve-style(ctx, par))
|
|
participants.at(i) = par
|
|
idx.insert(par.name, i)
|
|
}
|
|
for (i, elmt) in elements.enumerate() {
|
|
if type(elmt) == function {
|
|
ctx = elmt(ctx).ctx
|
|
} else if is-elmt(elmt) {
|
|
if elmt.type == "par" {
|
|
let style = resolve-style(ctx, elmt)
|
|
elements.at(i).insert("resolved-style", style)
|
|
let i = idx.at(elmt.name)
|
|
participants.at(i).resolved-style = style
|
|
}
|
|
}
|
|
}
|
|
|
|
set-ctx(c => {
|
|
c.setup.elements = elements
|
|
c.setup.participants = participants
|
|
return c
|
|
})
|
|
})
|
|
|
|
#let get-size(par) = {
|
|
if par.invisible {
|
|
return (width: 0, height: 0)
|
|
}
|
|
let style = par.resolved-style
|
|
let func = shapes.at(style.shape).get-size
|
|
return func(par)
|
|
}
|
|
|
|
#let render(par, y: 0, bottom: false) = get-ctx(ctx => {
|
|
let style = resolve-style(ctx, par)
|
|
let func = shapes.at(style.shape).render
|
|
let par = par
|
|
par.resolved-style = style
|
|
func(ctx.x-pos.at(par.i), y, par, bottom)
|
|
},)
|
|
|
|
#let render-lifelines() = get-ctx(ctx => {
|
|
let participants = ctx.participants
|
|
for p in participants.filter(p => not p.invisible) {
|
|
let style = p.resolved-style
|
|
let x = ctx.x-pos.at(p.i)
|
|
|
|
// Draw vertical line
|
|
let last-y = 0
|
|
|
|
let rects = ()
|
|
let destructions = ()
|
|
let stack = ()
|
|
|
|
// Compute lifeline rectangles + destruction positions
|
|
for event in ctx.lifelines.at(p.i).events {
|
|
if event.type == "create" {
|
|
last-y = line.at(1)
|
|
|
|
} else if event.type == "enable" {
|
|
if stack.len() == 0 {
|
|
draw.line(
|
|
(x, last-y),
|
|
(x, event.y),
|
|
stroke: style.track
|
|
)
|
|
}
|
|
stack.push(event)
|
|
|
|
} else if event.type == "disable" or event.type == "destroy" {
|
|
let lvl = 0
|
|
if stack.len() != 0 {
|
|
let e = stack.pop()
|
|
lvl = stack.len()
|
|
rects.push((
|
|
x + lvl * LIFELINE-W / 2,
|
|
e.y,
|
|
event.y,
|
|
e.style
|
|
))
|
|
last-y = event.y
|
|
}
|
|
|
|
if event.type == "destroy" {
|
|
destructions.push((x + lvl * LIFELINE-W / 2, event.y))
|
|
}
|
|
} else if event.type == "delay-start" {
|
|
draw.line(
|
|
(x, last-y),
|
|
(x, event.y),
|
|
stroke: style.track
|
|
)
|
|
last-y = event.y
|
|
} else if event.type == "delay-end" {
|
|
draw.line(
|
|
(x, last-y),
|
|
(x, event.y),
|
|
stroke: event.stroke
|
|
)
|
|
last-y = event.y
|
|
}
|
|
}
|
|
|
|
draw.line(
|
|
(x, last-y),
|
|
(x, ctx.y),
|
|
stroke: style.track
|
|
)
|
|
|
|
// Draw lifeline rectangles (reverse for bottom to top)
|
|
for rect in rects.rev() {
|
|
let (cx, y0, y1, style) = rect
|
|
let style = get-style("lifeline", style)
|
|
draw.rect(
|
|
(cx - LIFELINE-W / 2, y0),
|
|
(cx + LIFELINE-W / 2, y1),
|
|
..style
|
|
)
|
|
}
|
|
|
|
// Draw lifeline destructions
|
|
for dest in destructions {
|
|
let (cx, cy) = dest
|
|
draw.line((cx - 8, cy - 8), (cx + 8, cy + 8), stroke: COL-DESTRUCTION + 2pt)
|
|
draw.line((cx - 8, cy + 8), (cx + 8, cy - 8), stroke: COL-DESTRUCTION + 2pt)
|
|
}
|
|
|
|
// Draw participants (end)
|
|
if style.show-bottom {
|
|
(p.draw)(p, y: ctx.y, bottom: true)
|
|
}
|
|
}
|
|
},) |