#import "@preview/cetz:0.2.2": draw, coordinate #import "../ports.typ": add-ports, add-port #import "../element.typ" #let default-draw-shape(id, tl, tr, br, bl, fill, stroke) = { let f = {draw.rect(tl, br, fill: fill, stroke: stroke)} return (f, tl, tr, br, bl) } #let gate( draw-shape: default-draw-shape, x: none, y: none, w: none, h: none, inputs: 2, fill: none, stroke: black + 1pt, id: "", inverted: (), debug: ( ports: false ) ) = draw.get-ctx(ctx => { let width = w let height = h let x = x let y = y if x == none { panic("Parameter x must be set") } if y == none { panic("Parameter y must be set") } if w == none { panic("Parameter w must be set") } if h == none { panic("Parameter h must be set") } if (type(x) == dictionary) { let offset = x.rel let to = x.to let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0), to: to)) x = to-pos.at(0) } if (type(y) == dictionary) { let from = y.from let to = y.to let (to-side, i) = find-port(ports, to) let margins = (0%, 0%) if to-side in ports-margins { margins = ports-margins.at(to-side) } let used-pct = 100% - margins.at(0) - margins.at(1) let used-height = height * used-pct / 100% let top-margin = height * margins.at(0) / 100% let dy = used-height * (i + 1) / (ports.at(to-side).len() + 1) let (ctx, from-pos) = coordinate.resolve(ctx, from) y = from-pos.at(1) + dy - height + top-margin } let tl = (x, y + height) let tr = (x + width, y + height) let br = (x + width, y) let bl = (x, y) // Workaround because CeTZ needs to have all draw functions in the body let func = {} (func, tl, tr, br, bl) = draw-shape(id, tl, tr, br, bl, fill, stroke) { //draw.rect(tl, br) func } let space = 100% / (inputs + 1) for i in range(inputs) { let pct = (i + 1) * space let a = (tl, pct, bl) let b = (tr, pct, br) let int-name = id + "i" + str(i) draw.intersections( int-name, func, draw.hide(draw.line(a, b)) ) let port-name = "in" + str(i) let port-pos = int-name + ".0" if inverted == "all" or port-name in inverted { draw.circle(port-pos, radius: .2, anchor: "east", stroke: stroke) port-pos = (rel: (-.4, 0), to: port-pos) } add-port( id, "west", (id: port-name), port-pos, debug: debug.ports ) } let out-pos = id + ".east" if inverted == "all" or "out" in inverted { draw.circle(out-pos, radius: .2, anchor: "west", stroke: stroke) out-pos = (rel: (.4, 0), to: out-pos) } add-port( id, "east", (id: "out"), out-pos, debug: debug.ports ) }) /* { let ports = (west: (), east: ((id: "out"),)) for i in range(inputs) { ports.west.push((id: "in"+str(i))) } element.elmt( draw-shape: draw-shape, x: x, y: y, w: w, h: h, ports: ports, fill: fill, stroke: stroke, id: id, auto-ports: true, debug: debug ) }