use super::GraphNode;
use crate::graphics::*;
pub struct Node<T: GraphNode> {
pub(super) obj: T,
pub(super) rect: Rect,
pub(super) border: Option<LineType>,
pub(super) text_align: TextAlignment,
pub(super) text_attr: Option<CharAttribute>,
pub(super) edges_in: Vec<u32>,
pub(super) edges_out: Vec<u32>,
pub(super) filtered: bool,
}
impl<T> Node<T>
where
T: GraphNode,
{
pub fn value(&self) -> &T {
&self.obj
}
fn resize(&mut self, mut size: Size) {
let p = self.rect.top_left();
if self.border.is_some() {
size.width += 2;
size.height += 2;
} else {
size.width += 2;
}
self.rect = Rect::with_point_and_size(p, size);
}
#[inline]
pub(super) fn contains(&self, x: i32, y: i32) -> bool {
self.rect.contains(Point::new(x, y))
}
pub(super) fn paint(&self, surface: &mut Surface, attr: CharAttribute, out: &mut String) {
surface.fill_rect(self.rect, Character::with_attributes(' ', attr));
if let Some(line_type) = self.border {
surface.draw_rect(self.rect, line_type, attr);
surface.set_relative_clip(self.rect.left() + 1, self.rect.top() + 1, self.rect.right() - 1, self.rect.bottom() - 1);
} else {
surface.set_relative_clip(self.rect.left(), self.rect.top(), self.rect.right(), self.rect.bottom());
}
let mut cx = self.rect.center_x();
let cy = if self.border.is_some() { 1 } else { 0 } + self.rect.top();
let w = self.rect.width().saturating_sub(2) as u16;
if (w > 0) && ((w & 1) == 0) {
cx += 1;
}
let format = TextFormatBuilder::new()
.align(self.text_align)
.attribute(attr)
.wrap_type(WrapType::WordWrap(w))
.position(cx, cy)
.build();
let mut sz = self.rect.size();
if self.border.is_some() {
sz = sz.reduce_by(2);
}
if self.obj.write_label(out, sz).is_err() {
out.clear();
out.push_str("???");
}
surface.write_text(out, &format);
surface.reset_clip();
}
}
pub struct NodeBuilder<T>
where
T: GraphNode,
{
node: Node<T>,
size: Option<Size>,
}
impl<T> NodeBuilder<T>
where
T: GraphNode,
{
pub fn new(obj: T) -> Self {
Self {
node: Node {
obj,
rect: Rect::new(0, 0, 0, 0),
border: None,
text_align: TextAlignment::Center,
text_attr: None,
edges_in: Vec::new(),
edges_out: Vec::new(),
filtered: false,
},
size: None,
}
}
pub fn border(mut self, line_type: LineType) -> Self {
self.node.border = Some(line_type);
self
}
pub fn text_attribute(mut self, attr: CharAttribute) -> Self {
self.node.text_attr = Some(attr);
self
}
pub fn text_alignment(mut self, align: TextAlignment) -> Self {
self.node.text_align = align;
self
}
pub fn size(mut self, size: Size) -> Self {
self.size = Some(size);
self
}
pub fn position(mut self, p: Point) -> Self {
self.node.rect.set_left(p.x, true);
self.node.rect.set_top(p.y, true);
self
}
#[inline(always)]
pub fn build(mut self) -> Node<T> {
if let Some(size) = self.size {
self.node.resize(size);
} else {
let sz = self.node.obj.prefered_size();
self.node.resize(sz);
}
self.node
}
}