use crate::{
errors::InvalidSettingsError,
layout::{DefaultPositionMapFn, LayoutOrPositionMap},
Layout,
};
pub const DEFAULT_WIDTH: f32 = 1000.0;
pub const DEFAULT_HEIGHT: f32 = 1000.0;
pub const DEFAULT_RADIUS: f32 = 25.0;
pub const DEFAULT_FONT_SIZE: f32 = 16.0;
pub const DEFAULT_STROKE_WIDTH: f32 = 5.0;
pub const DEFAULT_MARGIN: f32 = 0.05;
pub const DEFAULT_LAYOUT_OR_POS_MAP: LayoutOrPositionMap<DefaultPositionMapFn> =
LayoutOrPositionMap::Layout(Layout::Circular);
pub const DEFAULT_NODE_LABEL_FN: DefaultNodeLabelFn = |node_id| format!("{}", node_id.index());
pub const DEFAULT_EDGE_LABEL_FN: DefaultEdgeLabelFn = |_| "".to_string();
pub const DEFAULT_NODE_COLORING_FN: DefaultNodeColoringFn = |_| "white".to_string();
pub const DEFAULT_EDGE_COLORING_FN: DefaultEdgeColoringFn = |_| "black".to_string();
pub(crate) type DefaultNodeLabelFn = fn(petgraph::prelude::NodeIndex) -> String;
pub(crate) type DefaultEdgeLabelFn = fn(petgraph::prelude::EdgeIndex) -> String;
pub(crate) type DefaultNodeColoringFn = fn(petgraph::prelude::NodeIndex) -> String;
pub(crate) type DefaultEdgeColoringFn = fn(petgraph::prelude::EdgeIndex) -> String;
#[derive(Debug)]
pub struct Settings<
PositionMapFn = DefaultPositionMapFn,
NodeLabelFn = DefaultNodeLabelFn,
EdgeLabelFn = DefaultEdgeLabelFn,
NodeColoringFn = DefaultNodeColoringFn,
EdgeColoringFn = DefaultEdgeColoringFn,
> {
pub(crate) width: f32,
pub(crate) height: f32,
pub(crate) radius: f32,
pub(crate) font_size: f32,
pub(crate) stroke_width: f32,
pub(crate) margin_x: f32,
pub(crate) margin_y: f32,
pub(crate) layout_or_pos_map: LayoutOrPositionMap<PositionMapFn>,
pub(crate) node_label_fn: NodeLabelFn,
pub(crate) edge_label_fn: EdgeLabelFn,
pub(crate) node_coloring_fn: NodeColoringFn,
pub(crate) edge_coloring_fn: EdgeColoringFn,
}
impl Default for Settings<DefaultPositionMapFn, DefaultNodeLabelFn, DefaultEdgeLabelFn> {
fn default() -> Self {
Settings {
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
radius: DEFAULT_RADIUS,
font_size: DEFAULT_FONT_SIZE,
stroke_width: DEFAULT_STROKE_WIDTH,
margin_x: DEFAULT_MARGIN,
margin_y: DEFAULT_MARGIN,
layout_or_pos_map: DEFAULT_LAYOUT_OR_POS_MAP,
node_label_fn: DEFAULT_NODE_LABEL_FN,
edge_label_fn: DEFAULT_EDGE_LABEL_FN,
node_coloring_fn: DEFAULT_NODE_COLORING_FN,
edge_coloring_fn: DEFAULT_EDGE_COLORING_FN,
}
}
}
impl Settings<DefaultPositionMapFn, DefaultNodeLabelFn, DefaultEdgeLabelFn> {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug)]
pub struct SettingsBuilder<PositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>
{
pub width: f32,
pub height: f32,
pub node_radius: f32,
pub font_size: f32,
pub stroke_width: f32,
pub margin_x: f32,
pub margin_y: f32,
pub layout_or_pos_map: LayoutOrPositionMap<PositionMapFn>,
pub node_label_fn: NodeLabelFn,
pub edge_label_fn: EdgeLabelFn,
pub node_coloring_fn: NodeColoringFn,
pub edge_coloring_fn: EdgeColoringFn,
}
impl Default
for SettingsBuilder<
DefaultPositionMapFn,
DefaultNodeLabelFn,
DefaultEdgeLabelFn,
DefaultNodeColoringFn,
DefaultEdgeColoringFn,
>
{
fn default() -> Self {
SettingsBuilder {
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
node_radius: DEFAULT_RADIUS,
font_size: DEFAULT_FONT_SIZE,
stroke_width: DEFAULT_STROKE_WIDTH,
margin_x: DEFAULT_MARGIN,
margin_y: DEFAULT_MARGIN,
layout_or_pos_map: DEFAULT_LAYOUT_OR_POS_MAP,
node_label_fn: DEFAULT_NODE_LABEL_FN,
edge_label_fn: DEFAULT_EDGE_LABEL_FN,
node_coloring_fn: DEFAULT_NODE_COLORING_FN,
edge_coloring_fn: DEFAULT_EDGE_COLORING_FN,
}
}
}
impl
SettingsBuilder<
DefaultPositionMapFn,
DefaultNodeLabelFn,
DefaultEdgeLabelFn,
DefaultNodeColoringFn,
DefaultEdgeColoringFn,
>
{
pub fn new() -> Self {
SettingsBuilder::default()
}
}
impl<PositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>
SettingsBuilder<PositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>
{
pub fn width(mut self, width: f32) -> Self {
self.width = width;
self
}
pub fn height(mut self, height: f32) -> Self {
self.height = height;
self
}
pub fn node_radius(mut self, radius: f32) -> Self {
self.node_radius = radius;
self
}
pub fn font_size(mut self, font_size: f32) -> Self {
self.font_size = font_size;
self
}
pub fn stroke_width(mut self, stroke_width: f32) -> Self {
self.stroke_width = stroke_width;
self
}
pub fn margin_x(mut self, margin_x: f32) -> Self {
self.margin_x = margin_x;
self
}
pub fn margin_y(mut self, margin_y: f32) -> Self {
self.margin_y = margin_y;
self
}
pub fn layout(
self,
layout: Layout,
) -> SettingsBuilder<
DefaultPositionMapFn,
NodeLabelFn,
EdgeLabelFn,
NodeColoringFn,
EdgeColoringFn,
> {
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: LayoutOrPositionMap::Layout(layout),
node_label_fn: self.node_label_fn,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: self.edge_coloring_fn,
}
}
pub fn position_map<NewPositionMapFn>(
self,
position_map: NewPositionMapFn,
) -> SettingsBuilder<NewPositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>
where
NewPositionMapFn: Fn(petgraph::prelude::NodeIndex) -> (f32, f32),
{
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: LayoutOrPositionMap::PositionMap(position_map),
node_label_fn: self.node_label_fn,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: self.edge_coloring_fn,
}
}
pub fn node_label_fn<NewNodeLabelFn>(
self,
node_label: NewNodeLabelFn,
) -> SettingsBuilder<PositionMapFn, NewNodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>
where
NewNodeLabelFn: Fn(petgraph::prelude::NodeIndex) -> String,
{
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: self.layout_or_pos_map,
node_label_fn: node_label,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: self.edge_coloring_fn,
}
}
pub fn edge_label_fn<NewEdgeLabelFn>(
self,
edge_label: NewEdgeLabelFn,
) -> SettingsBuilder<PositionMapFn, NodeLabelFn, NewEdgeLabelFn, NodeColoringFn, EdgeColoringFn>
where
NewEdgeLabelFn: Fn(petgraph::prelude::EdgeIndex) -> String,
{
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: self.layout_or_pos_map,
node_label_fn: self.node_label_fn,
edge_label_fn: edge_label,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: self.edge_coloring_fn,
}
}
pub fn node_coloring_fn<NewNodeColoringFn>(
self,
node_coloring: NewNodeColoringFn,
) -> SettingsBuilder<PositionMapFn, NodeLabelFn, EdgeLabelFn, NewNodeColoringFn, EdgeColoringFn>
where
NewNodeColoringFn: Fn(petgraph::prelude::NodeIndex) -> String,
{
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: self.layout_or_pos_map,
node_label_fn: self.node_label_fn,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: node_coloring,
edge_coloring_fn: self.edge_coloring_fn,
}
}
pub fn edge_coloring_fn<NewEdgeColoringFn>(
self,
edge_coloring: NewEdgeColoringFn,
) -> SettingsBuilder<PositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, NewEdgeColoringFn>
where
NewEdgeColoringFn: Fn(petgraph::prelude::EdgeIndex) -> String,
{
SettingsBuilder {
width: self.width,
height: self.height,
node_radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: self.layout_or_pos_map,
node_label_fn: self.node_label_fn,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: edge_coloring,
}
}
fn validate(&self) -> Result<(), InvalidSettingsError> {
if self.width <= 0.0 || self.height <= 0.0 {
return Err(InvalidSettingsError::Dimensions(self.width, self.height));
} else if self.node_radius <= 0.0 {
return Err(InvalidSettingsError::Radius(self.node_radius));
} else if self.font_size <= 0.0 {
return Err(InvalidSettingsError::FontSize(self.font_size));
} else if self.stroke_width <= 0.0 {
return Err(InvalidSettingsError::StrokeWidth(self.stroke_width));
} else if self.margin_x < 0.0
|| self.margin_x > 0.5
|| self.margin_y < 0.0
|| self.margin_y > 0.5
{
return Err(InvalidSettingsError::Margin(self.margin_x, self.margin_y));
}
Ok(())
}
pub fn build(
self,
) -> Result<
Settings<PositionMapFn, NodeLabelFn, EdgeLabelFn, NodeColoringFn, EdgeColoringFn>,
InvalidSettingsError,
>
where
PositionMapFn: Fn(petgraph::prelude::NodeIndex) -> (f32, f32),
NodeLabelFn: Fn(petgraph::prelude::NodeIndex) -> String,
EdgeLabelFn: Fn(petgraph::prelude::EdgeIndex) -> String,
NodeColoringFn: Fn(petgraph::prelude::NodeIndex) -> String,
EdgeColoringFn: Fn(petgraph::prelude::EdgeIndex) -> String,
{
self.validate()?;
let settings = Settings {
width: self.width,
height: self.height,
radius: self.node_radius,
font_size: self.font_size,
stroke_width: self.stroke_width,
margin_x: self.margin_x,
margin_y: self.margin_y,
layout_or_pos_map: self.layout_or_pos_map,
node_label_fn: self.node_label_fn,
edge_label_fn: self.edge_label_fn,
node_coloring_fn: self.node_coloring_fn,
edge_coloring_fn: self.edge_coloring_fn,
};
Ok(settings)
}
}