forked from HEL/circuiteria
123 lines
3.8 KiB
Typst
123 lines
3.8 KiB
Typst
#import "/src/cetz.typ": draw, coordinate
|
|
#import "../util.typ"
|
|
#import "ports.typ": add-ports
|
|
|
|
/// Draws a group of elements
|
|
///
|
|
/// #examples.group
|
|
///
|
|
/// Ports can also be defined on a group, just like on a block. By default
|
|
/// port labels are drawn *outside* the group border so they do not overlap
|
|
/// child elements. Set `outside-port-names: false` to draw them inside.
|
|
/// #examples.group-ports
|
|
/// - body (elements, function): Elements to group
|
|
/// - id (str): see #doc-ref("element.elmt")
|
|
/// - name (str): The group's name
|
|
/// - name-anchor (str): The anchor for the name. \
|
|
/// Note: the name will be placed on the *outside* of the group
|
|
/// - fill (color): see #doc-ref("element.elmt")
|
|
/// - stroke (stroke): see #doc-ref("element.elmt")
|
|
/// - padding (float,length,array,dictionary): The inside padding:
|
|
/// - float / length: same for all sides
|
|
/// - array: either (`<all>`,), (`<vertical>`, `<horizontal>`) or (`<top>`, `<right>`, `<bottom>`, `<left>`)
|
|
/// - dictionary: valid keys are "top", "right", "bottom" and "left"
|
|
/// - radius (number): The corner radius
|
|
/// - ports (dictionary): see #doc-ref("element.elmt")
|
|
/// - ports-margins (dictionary): see #doc-ref("element.elmt")
|
|
/// - outside-port-names (bool): If `true` (default), port name labels are drawn outside the group border so they do not overlap child elements. Set to `false` to draw labels inside, matching the block behaviour
|
|
/// - port-name-padding (number, length): Padding between the port name label and the group border (default `2pt`). Accepts anything CeTZ accepts as `padding` (number or length)
|
|
/// - port-shape (none, str): see #doc-ref("element.elmt")
|
|
/// - port-kind (str): see #doc-ref("element.elmt")
|
|
/// - port-size (length): see #doc-ref("element.elmt")
|
|
/// - debug (dictionary): see #doc-ref("element.elmt")
|
|
#let group(
|
|
body,
|
|
id: "",
|
|
name: none,
|
|
name-anchor: "south",
|
|
fill: none,
|
|
stroke: black + 1pt,
|
|
padding: 0.5em,
|
|
radius: 0.5em,
|
|
ports: (:),
|
|
ports-margins: (:),
|
|
outside-port-names: true,
|
|
port-name-padding: 2pt,
|
|
port-shape: none,
|
|
port-kind: "in",
|
|
port-size: 1em,
|
|
debug: (
|
|
ports: false
|
|
)
|
|
) = {
|
|
let min-x = none
|
|
let max-x = none
|
|
let min-y = none
|
|
let max-y = none
|
|
|
|
let pad-top = padding
|
|
let pad-bottom = padding
|
|
let pad-left = padding
|
|
let pad-right = padding
|
|
|
|
if type(padding) == array {
|
|
if padding.len() == 0 {
|
|
panic("Padding array must contain at least one value")
|
|
} else if padding.len() == 1 {
|
|
pad-top = padding.first()
|
|
pad-bottom = padding.first()
|
|
pad-left = padding.first()
|
|
pad-right = padding.first()
|
|
} else if padding.len() == 2 {
|
|
pad-top = padding.first()
|
|
pad-bottom = padding.first()
|
|
pad-left = padding.last()
|
|
pad-right = padding.last()
|
|
} else if padding.len() == 4 {
|
|
(pad-top, pad-right, pad-bottom, pad-left) = padding
|
|
}
|
|
} else if type(padding) == dictionary {
|
|
pad-top = padding.at("top", default: 0.5em)
|
|
pad-right = padding.at("right", default: 0.5em)
|
|
pad-bottom = padding.at("bottom", default: 0.5em)
|
|
pad-left = padding.at("left", default: 0.5em)
|
|
}
|
|
|
|
draw.hide(draw.group(name: id+"-inner", body))
|
|
draw.rect(
|
|
(rel: (-pad-left, -pad-bottom), to: id+"-inner.south-west"),
|
|
(rel: (pad-right, pad-top), to: id+"-inner.north-east"),
|
|
name: id,
|
|
radius: radius,
|
|
stroke: stroke,
|
|
fill: fill
|
|
)
|
|
|
|
add-ports(
|
|
id,
|
|
id + ".north-west",
|
|
id + ".north-east",
|
|
id + ".south-east",
|
|
id + ".south-west",
|
|
ports,
|
|
ports-margins,
|
|
debug: debug.ports,
|
|
outside-name: outside-port-names,
|
|
name-padding: port-name-padding,
|
|
port-shape: port-shape,
|
|
port-kind: port-kind,
|
|
port-size: port-size,
|
|
elmt-stroke: stroke,
|
|
elmt-fill: fill,
|
|
)
|
|
|
|
if name != none {
|
|
draw.content(
|
|
id + "." + name-anchor,
|
|
anchor: util.opposite-anchor(name-anchor),
|
|
padding: 5pt,
|
|
[*#name*]
|
|
)
|
|
}
|
|
body
|
|
} |