|
1 | 1 | #import "/src/path-util.typ"
|
2 | 2 |
|
3 | 3 | /// A path modifier is a function that accepts a contex, style and
|
4 |
| -/// a single drawable and returns a single (modified) drawable. |
| 4 | +/// a single drawable and returns either a single replacement drawable, |
| 5 | +/// or an dictionary with the keys `replacement` (single drawable) and `decoration` (list of drawables) |
| 6 | +/// that contain a replacement and/or additional drawable to render. |
| 7 | +/// |
| 8 | +/// Arguments: |
| 9 | +/// - ctx (context): |
| 10 | +/// - style (styles): |
| 11 | +/// - drawable (drawable): Single drawable to modify/decorate |
| 12 | +/// - close (bool): Boolean if the drawable is closed |
5 | 13 | ///
|
6 | 14 | /// Example:
|
7 | 15 | /// ```typ
|
8 |
| -/// (ctx, style, drawable) => { |
| 16 | +/// (ctx, style, drawable, close) => { |
9 | 17 | /// // ... modify the drawable ...
|
10 |
| -/// return drawable |
| 18 | +/// return (replacement: ..., decoration: ...) |
11 | 19 | /// }
|
12 | 20 | /// ```
|
13 | 21 |
|
|
44 | 52 | /// - ctx (context):
|
45 | 53 | /// - style (style):
|
46 | 54 | /// - elem (element): Single element
|
| 55 | +/// -> List of elements |
47 | 56 | #let apply-modifier-fn(ctx, style, elem, fn, close) = {
|
48 | 57 | assert(type(fn) == function,
|
49 | 58 | message: "Path modifier must be of type function.")
|
50 | 59 |
|
| 60 | + let new-elements = () |
51 | 61 | if "segments" in elem {
|
52 | 62 | let begin = style.at("begin", default: 0%)
|
53 | 63 | let end = style.at("end", default: 0%)
|
54 | 64 |
|
55 | 65 | let (head, mid, tail) = slice-segments(elem.segments, begin, end)
|
56 | 66 | let close = close and head == () and tail == ()
|
57 |
| - elem.segments = head + (fn)(ctx, style, mid, close) + tail |
| 67 | + let result = (fn)(ctx, style, mid, close) |
| 68 | + if type(result) != dictionary { |
| 69 | + result = (replacement: result) |
| 70 | + } else { |
| 71 | + new-elements += result.at("decoration", default: ()) |
| 72 | + } |
| 73 | + |
| 74 | + let replace = result.at("replacement", default: none) |
| 75 | + if replace != none { |
| 76 | + let replacement-elem = elem |
| 77 | + replacement-elem.segments = head + replace + tail |
| 78 | + |
| 79 | + if replacement-elem.segments != () { |
| 80 | + new-elements.insert(0, replacement-elem) |
| 81 | + } |
| 82 | + } else { |
| 83 | + if head != () { |
| 84 | + let head-elem = elem |
| 85 | + head-elem.segments = head |
| 86 | + |
| 87 | + new-elements.insert(0, head-elem) |
| 88 | + } |
| 89 | + |
| 90 | + if tail != () { |
| 91 | + let tail-elem = elem |
| 92 | + tail-elem.segments = tail |
| 93 | + |
| 94 | + new-elements.push(tail-elem) |
| 95 | + } |
| 96 | + } |
58 | 97 | }
|
59 | 98 |
|
60 |
| - return elem |
| 99 | + return new-elements |
61 | 100 | }
|
62 | 101 |
|
63 | 102 | /// Apply a path modifier to a list of drawables
|
|
72 | 111 | (style.modifier,)
|
73 | 112 | }.map(n => {
|
74 | 113 | let name = if type(n) == dictionary {
|
75 |
| - n.name |
| 114 | + n.at("name", default: none) |
76 | 115 | } else {
|
77 | 116 | n
|
78 | 117 | }
|
|
98 | 137 | style.modifier = ()
|
99 | 138 |
|
100 | 139 | // Apply function on all drawables
|
101 |
| - return drawables.map(d => { |
102 |
| - for fn in fns.filter(v => v.fn != none) { |
103 |
| - d = apply-modifier-fn(ctx, fn.style, d, fn.fn, close) |
| 140 | + for fn in fns.filter(v => v.fn != none) { |
| 141 | + let new = () |
| 142 | + for i in range(0, drawables.len()) { |
| 143 | + new += apply-modifier-fn(ctx, fn.style, drawables.at(i), fn.fn, close) |
104 | 144 | }
|
105 |
| - return d |
106 |
| - }) |
| 145 | + drawables = new |
| 146 | + } |
| 147 | + |
| 148 | + return drawables |
107 | 149 | }
|
0 commit comments