mod coords;
mod force;
mod geom;
mod grid;
mod layered;
mod ordering;
mod resolve;
pub use force::{force, ForceOpts, IterationBudget};
pub use grid::grid;
pub use layered::{layered, LayeredOpts};
use abstracttui::base::{Point, Rect};
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NodeLayout {
pub id: String,
pub rect: Rect,
pub rank: usize,
}
impl NodeLayout {
pub fn new(id: impl Into<String>, rect: Rect, rank: usize) -> Self {
NodeLayout {
id: id.into(),
rect,
rank,
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EdgeLayout {
pub from: String,
pub to: String,
pub desc_index: usize,
pub waypoints: Vec<Point>,
pub broken: bool,
}
impl EdgeLayout {
pub fn new(
from: impl Into<String>,
to: impl Into<String>,
desc_index: usize,
waypoints: Vec<Point>,
) -> Self {
EdgeLayout {
from: from.into(),
to: to.into(),
desc_index,
waypoints,
broken: false,
}
}
pub fn broken(mut self) -> Self {
self.broken = true;
self
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Layout {
pub nodes: Vec<NodeLayout>,
pub edges: Vec<EdgeLayout>,
pub bounds: Rect,
pub fallback: Option<String>,
}
impl Layout {
pub fn new(nodes: Vec<NodeLayout>, edges: Vec<EdgeLayout>) -> Self {
let bounds = bounds_of(&nodes, &edges);
Layout {
nodes,
edges,
bounds,
fallback: None,
}
}
pub fn broken_edges(&self) -> Vec<usize> {
self.edges
.iter()
.filter(|e| e.broken)
.map(|e| e.desc_index)
.collect()
}
pub fn node(&self, id: &str) -> Option<&NodeLayout> {
self.nodes.iter().find(|n| n.id == id)
}
}
pub(crate) fn bounds_of(nodes: &[NodeLayout], edges: &[EdgeLayout]) -> Rect {
let mut acc = Rect::ZERO;
for n in nodes {
acc = acc.union(n.rect);
}
for e in edges {
for p in &e.waypoints {
acc = acc.union(Rect::new(p.x, p.y, 1, 1));
}
}
acc
}
pub(crate) fn assemble(
mut nodes: Vec<NodeLayout>,
mut edges: Vec<EdgeLayout>,
notes: Vec<String>,
) -> Layout {
let bounds = normalize(&mut nodes, &mut edges);
Layout {
nodes,
edges,
bounds,
fallback: resolve::fold_notes(notes),
}
}
pub(crate) fn normalize(nodes: &mut [NodeLayout], edges: &mut [EdgeLayout]) -> Rect {
let raw = bounds_of(nodes, edges);
let (dx, dy) = (-raw.x, -raw.y);
if dx != 0 || dy != 0 {
for n in nodes.iter_mut() {
n.rect = n.rect.translate(dx, dy);
}
for e in edges.iter_mut() {
for p in e.waypoints.iter_mut() {
*p = p.translate(dx, dy);
}
}
}
Rect::new(0, 0, raw.w, raw.h)
}