use super::super::ir::{Bbox, PlacedNode};
use super::geometry::P;
use super::{angle, dims, leaders, round};
use crate::ast::Side;
use crate::error::Error;
use crate::ledger::consts::{
DIM_OFFSET, DIM_PITCH, DRAWING_LINK_FONT_SIZE, DRAWING_LINK_STROKE_WIDTH, EXT_OVERSHOOT,
};
use crate::resolve::{AttrMap, LinkKind, MeasureOp, NodeKind, ResolvedLink, ResolvedValue};
mod rows;
#[cfg(test)]
mod tests;
pub(super) use rows::Rows;
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Axis {
Horizontal,
Vertical,
}
pub(super) struct Ctx<'a> {
pub kids: &'a [PlacedNode],
pub scope: &'a str,
pub extent: Bbox,
pub scale: f64,
}
pub(super) struct Paint {
pub stroke: ResolvedValue,
pub light: ResolvedValue,
pub sw: f64,
pub fs: f64,
pub font: crate::font::Font,
}
impl Paint {
pub fn of(attrs: &AttrMap) -> Paint {
let set = attrs.get("stroke").cloned();
let live = |name: &str| ResolvedValue::LiveVar {
name: name.into(),
raw: false,
};
Paint {
stroke: set.clone().unwrap_or_else(|| live("stroke-dark")),
light: set.unwrap_or_else(|| live("stroke-light")),
sw: attrs
.number("stroke-width")
.unwrap_or(DRAWING_LINK_STROKE_WIDTH),
fs: attrs.number("font-size").unwrap_or(DRAWING_LINK_FONT_SIZE),
font: crate::font::Font::of(attrs),
}
}
pub fn dim(&self, points: Vec<P>) -> PlacedNode {
let mut n = super::super::prim::line(points, self.stroke.clone(), self.sw);
n.type_chain = vec!["dim-line".into()];
n
}
pub fn ext(&self, points: Vec<P>) -> PlacedNode {
let mut n = super::super::prim::line(points, self.light.clone(), self.sw);
n.type_chain = vec!["ext-line".into()];
n
}
pub fn stroked_path(&self, d: String, bbox: Bbox) -> PlacedNode {
let mut n = super::super::prim::path(d, ResolvedValue::Ident("none".into()), bbox);
n.type_chain = vec!["dim-line".into()];
n.attrs.insert("stroke", self.stroke.clone());
n.attrs
.insert("stroke-width", ResolvedValue::Number(self.sw));
n
}
}
pub(in crate::layout) fn lower(
kids: &[PlacedNode],
links: &[&ResolvedLink],
scope: &str,
scale: f64,
extent: Option<Bbox>,
) -> Result<Vec<PlacedNode>, Error> {
let ctx = Ctx {
kids,
scope,
extent: extent.unwrap_or_else(|| geometry_extent(kids)),
scale,
};
let mut rows = Rows::new(ctx.extent);
let mut outs: Vec<Vec<PlacedNode>> = vec![Vec::new(); links.len()];
for (i, w) in links.iter().enumerate() {
let nodes = match w.kind {
LinkKind::Measure(MeasureOp::Angle) => angle::lower(&ctx, w)?,
LinkKind::Wire if w.endpoints.len() == 1 => leaders::callout(&ctx, w)?,
LinkKind::Wire => leaders::arrows(&ctx, w)?,
_ => continue,
};
rows.obstruct_texts(&nodes);
outs[i] = nodes;
}
for (i, w) in links.iter().enumerate() {
let nodes = match w.kind {
LinkKind::Measure(MeasureOp::Linear) => dims::linear(&ctx, w, &mut rows)?,
LinkKind::Measure(MeasureOp::Round) => round::lower(&ctx, w, &mut rows)?,
_ => continue,
};
rows.obstruct_texts(&nodes);
outs[i] = nodes;
}
Ok(outs.into_iter().flatten().collect())
}
fn geometry_extent(kids: &[PlacedNode]) -> Bbox {
Bbox::extent_of(kids, |k| {
!super::is_sheet(k.kind, &k.type_chain) && !super::super::anchors::is_pinned(&k.attrs)
})
}
pub(super) fn side_unit(name: &str) -> Option<P> {
let d = std::f64::consts::FRAC_1_SQRT_2;
Some(match name {
"top" => (0.0, -1.0),
"bottom" => (0.0, 1.0),
"left" => (-1.0, 0.0),
"right" => (1.0, 0.0),
"top-left" => (-d, -d),
"top-right" => (d, -d),
"bottom-left" => (-d, d),
"bottom-right" => (d, d),
_ => return None,
})
}
pub(super) fn side_attr(attrs: &AttrMap) -> Option<&str> {
match attrs.get("side") {
Some(ResolvedValue::Ident(s)) => Some(s),
_ => None,
}
}