use masonry::kurbo::{Insets, Point, Rect, Size, Vec2};
use wi_core::Side;
use crate::graph::{Node, NodeStyle};
pub const PORT_HEIGHT_32: f32 = 18.0;
pub const PORT_HEIGHT: f64 = 18.0;
pub const PORT_GAP: f64 = 4.0;
pub trait NodeExt: Node {
fn inner_size(&self) -> Size {
let arity = match self.style() {
NodeStyle::Small => 1,
NodeStyle::Medium => self.in_arity().max(self.out_arity()).max(1),
NodeStyle::Large => (self.in_arity() + self.out_arity()).max(1),
};
Size::new(
self.width(),
PORT_HEIGHT * f64::from(arity) + PORT_GAP * f64::from(arity - 1),
)
}
#[inline]
fn padding(&self) -> Insets {
match self.style() {
NodeStyle::Small => Insets::uniform(2.0),
NodeStyle::Medium => Insets::uniform(4.0),
NodeStyle::Large => Insets::new(12.0, 8.0 + PORT_HEIGHT + 2.0 * 4.0, 12.0, 8.0),
}
}
fn name_rect(&self) -> Rect {
let vec = match self.style() {
NodeStyle::Small => Vec2::new(12.0, 2.0),
NodeStyle::Medium => {
Vec2::new(12.0, 4.0 + (self.inner_size().height - PORT_HEIGHT) * 0.5)
},
NodeStyle::Large => Vec2::new(4.0, 4.0),
};
Rect::from_points(
vec.to_point(),
Point::new(self.outer_size().width - vec.x, PORT_HEIGHT + vec.y),
)
}
fn port_label_y(&self, idx: u16, side: Side) -> f64 {
match self.style() {
NodeStyle::Small => {
assert!(idx == 0);
0.0
},
NodeStyle::Medium => {
let in_arity = self.in_arity();
let out_arity = self.out_arity();
let arity = in_arity.max(out_arity).saturating_sub(match side {
Side::In => in_arity,
Side::Out => out_arity,
});
(PORT_HEIGHT * f64::from(arity) + PORT_GAP * f64::from(arity.saturating_sub(1)))
* 0.5
+ (PORT_HEIGHT + PORT_GAP) * f64::from(idx)
},
NodeStyle::Large => {
(PORT_HEIGHT + PORT_GAP)
* (f64::from(idx)
+ f64::from(u16::from(matches!(side, Side::In)) * self.out_arity()))
},
}
}
#[inline]
fn port_inner_offs(&self, idx: u16, side: Side) -> Vec2 {
Vec2::new(
-self.padding().x0,
self.port_label_y(idx, side) + PORT_HEIGHT * 0.5,
) + f64::from(matches!(side, Side::Out)) * Vec2::new(self.outer_size().width, 0.0)
}
#[inline]
fn outer_size(&self) -> Size { self.inner_size() + self.padding().size() }
#[inline]
fn rect(&self) -> Rect { Rect::from_origin_size(self.position(), self.outer_size()) }
#[inline]
fn port_pos(&self, idx: u16, side: Side) -> Point {
let padding = self.padding();
self.position() + self.port_inner_offs(idx, side) + Vec2::new(padding.x0, padding.y0)
}
#[inline]
fn edge_midpoint(&self, port: u16, to_node: &Self, to_port: u16) -> Point {
((self.port_pos(port, Side::Out).to_vec2() + to_node.port_pos(to_port, Side::In).to_vec2())
* 0.5)
.to_point()
}
}
impl<N: Node> NodeExt for N {}