Files
circuiteria/src/elements/group.typ
T

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
}