use super::writer::Statement;
pub trait Attributes: Sized {
fn set_font(&mut self, label: &str) -> &mut Self {
self.set("fontname", label, true)
}
fn set_html(&mut self, label: &str) -> &mut Self {
self.set("label", label, false)
}
fn set_label(&mut self, label: &str) -> &mut Self {
self.set("label", label, true)
}
fn set_head_label(&mut self, label: &str) -> &mut Self {
self.set("headlabel", label, true)
}
fn set_tail_label(&mut self, label: &str) -> &mut Self {
self.set("taillabel", label, true)
}
fn set_color(&mut self, color: Color) -> &mut Self {
self.set("color", color.as_str(), false)
}
fn set_fill_color(&mut self, color: Color) -> &mut Self {
self.set("fillcolor", color.as_str(), false)
}
fn set_font_color(&mut self, color: Color) -> &mut Self {
self.set("fontcolor", color.as_str(), false)
}
fn set_background_color(&mut self, color: Color) -> &mut Self {
self.set("bgcolor", color.as_str(), false)
}
fn set_shape(&mut self, shape: Shape) -> &mut Self {
self.set("shape", shape.as_str(), false)
}
fn set_style(&mut self, style: Style) -> &mut Self {
self.set("style", style.as_str(), true)
}
fn set_arrow_head(&mut self, arrow_type: ArrowType) -> &mut Self {
self.set("arrowhead", arrow_type.as_str(), false)
}
fn set_arrow_tail(&mut self, arrow_type: ArrowType) -> &mut Self {
self.set("arrowtail", arrow_type.as_str(), false)
}
fn set_rank(&mut self, rank: Rank) -> &mut Self {
self.set("rank", rank.as_str(), false)
}
fn set_pen_width(&mut self, width: f32) -> &mut Self {
self.set("penwidth", &width.to_string(), false)
}
fn set_arrow_size(&mut self, size: f32) -> &mut Self {
self.set("arrowsize", &size.to_string(), false)
}
fn set_font_size(&mut self, size: f32) -> &mut Self {
self.set("fontsize", &size.to_string(), false)
}
fn set_rank_direction(&mut self, rank_direction: RankDirection) -> &mut Self {
self.set("rankdir", rank_direction.as_str(), false)
}
fn set(&mut self, name: &str, value: &str, quote: bool) -> &mut Self;
}
pub struct AttributesList<'d, 'w> {
statement: Statement<'d, 'w>,
at_least_one_set: bool,
}
impl<'d, 'w> AttributesList<'d, 'w> {
pub(crate) fn new(statement: Statement<'d, 'w>) -> Self {
Self {
statement,
at_least_one_set: false,
}
}
}
impl<'d, 'w> Attributes for AttributesList<'d, 'w> {
fn set(&mut self, name: &str, value: &str, quote: bool) -> &mut Self {
if !self.at_least_one_set {
self.at_least_one_set = true;
self.statement.write(b" [");
} else {
self.statement.write(b", ");
}
self.statement.write(name.as_bytes());
self.statement.write(b"=");
if quote {
self.statement.write_quoted(value.as_bytes());
} else {
self.statement.write(value.as_bytes());
}
self
}
}
impl<'d, 'w> Drop for AttributesList<'d, 'w> {
fn drop(&mut self) {
if self.at_least_one_set {
self.statement.write(b"]");
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Shape {
Circle,
Record,
Rectangle,
None,
Mdiamond,
Mrecord,
Msquare,
}
impl Shape {
fn as_str(&self) -> &str {
match self {
Self::Circle => "circle",
Self::Record => "record",
Self::Mrecord => "Mrecord",
Self::Mdiamond => "Mdiamond",
Self::Rectangle => "rectangle",
Self::Msquare => "Msquare",
Self::None => "none",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Color {
Black,
Grey,
LightGrey,
PaleGreen,
PaleTurquoise,
Red,
White,
Blue,
Gray20,
}
impl Color {
pub fn as_str(&self) -> &str {
match self {
Self::Black => "black",
Self::Grey => "gray",
Self::LightGrey => "lightgray",
Self::PaleGreen => "palegreen",
Self::PaleTurquoise => "paleturquoise",
Self::Red => "red",
Self::White => "white",
Self::Blue => "blue",
Self::Gray20 => "gray20",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Style {
Dashed,
Dotted,
Solid,
Invisible,
Bold,
Tapered,
Wedged,
Diagonals,
Filled,
Striped,
Rounded,
Radial,
Unfilled,
}
impl Style {
fn as_str(&self) -> &str {
match self {
Self::Dashed => "dashed",
Self::Dotted => "dotted",
Self::Solid => "solid",
Self::Invisible => "invis",
Self::Bold => "bold",
Self::Tapered => "tapered",
Self::Wedged => "wedged",
Self::Diagonals => "diagonals",
Self::Filled => "filled",
Self::Striped => "striped",
Self::Rounded => "rounded",
Self::Radial => "radial",
Self::Unfilled => "",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Rank {
Min,
Same,
Max,
Source,
Sink,
}
impl Rank {
fn as_str(&self) -> &str {
match self {
Self::Source => "source",
Self::Min => "min",
Self::Same => "same",
Self::Max => "max",
Self::Sink => "sink",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ArrowType {
Normal,
Dot,
Inv,
InvDot,
ODit,
InvODot,
None,
Tee,
Empty,
InvEmpty,
Diamond,
ODiamond,
EDiamond,
Crow,
Box,
OBox,
Open,
HalfOpen,
Vee,
}
impl ArrowType {
fn as_str(&self) -> &str {
match self {
Self::Normal => "normal",
Self::Dot => "dot",
Self::Inv => "inv",
Self::InvDot => "invdot",
Self::ODit => "odot",
Self::InvODot => "invdot",
Self::None => "none",
Self::Tee => "tee",
Self::Empty => "empty",
Self::InvEmpty => "invempty",
Self::Diamond => "diamond",
Self::ODiamond => "odiamond",
Self::EDiamond => "ediamond",
Self::Crow => "crow",
Self::Box => "box",
Self::OBox => "obox",
Self::Open => "open",
Self::HalfOpen => "halfopen",
Self::Vee => "vee",
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum RankDirection {
TopBottom,
BottomTop,
LeftRight,
RightLeft,
}
impl RankDirection {
fn as_str(&self) -> &str {
match self {
Self::TopBottom => "TB",
Self::BottomTop => "BT",
Self::LeftRight => "LR",
Self::RightLeft => "RL",
}
}
}