xdot/xdot_parse/
shapes.rs

1//! Drawable shapes included in [Shape].
2
3/// A drawable shape including closed shapes, lines, and text.
4#[derive(Debug, Clone, PartialEq)]
5pub enum Shape {
6    Ellipse(Ellipse),
7    Points(Points),
8    Text(Text),
9}
10
11/// A horizontal ellipse shape.
12#[derive(Debug, Clone, PartialEq)]
13#[cfg_attr(
14    feature = "pyo3",
15    pyo3::pyclass(eq, get_all, set_all, module = "xdot_rs.shapes")
16)]
17pub struct Ellipse {
18    pub filled: bool,
19    pub x: f32,
20    pub y: f32,
21    pub w: f32,
22    pub h: f32,
23}
24#[cfg(feature = "pyo3")]
25#[pyo3::pymethods]
26impl Ellipse {
27    #[new]
28    #[pyo3(signature = (x, y, w, h, filled=true))]
29    fn new(x: f32, y: f32, w: f32, h: f32, filled: bool) -> Self {
30        Ellipse { x, y, w, h, filled }
31    }
32}
33impl From<Ellipse> for Shape {
34    fn from(val: Ellipse) -> Self {
35        Shape::Ellipse(val)
36    }
37}
38
39/// Type of shape defined by a sequence of points.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[cfg_attr(
42    feature = "pyo3",
43    pyo3::pyclass(eq, eq_int, get_all, set_all, module = "xdot_rs.shapes")
44)]
45pub enum PointsType {
46    Polygon,
47    Polyline,
48    BSpline,
49}
50/// Shape defined by a sequence of points (line or closed shape).
51#[derive(Debug, Clone, PartialEq)]
52#[cfg_attr(
53    feature = "pyo3",
54    pyo3::pyclass(eq, get_all, set_all, module = "xdot_rs.shapes")
55)]
56pub struct Points {
57    pub filled: bool,
58    pub r#type: PointsType,
59    pub points: Vec<(f32, f32)>,
60}
61#[cfg(feature = "pyo3")]
62#[pyo3::pymethods]
63impl Points {
64    #[new]
65    #[pyo3(signature = (r#type, points, filled=true))]
66    fn new(r#type: PointsType, points: Vec<(f32, f32)>, filled: bool) -> Self {
67        Points {
68            points,
69            r#type,
70            filled,
71        }
72    }
73}
74impl From<Points> for Shape {
75    fn from(val: Points) -> Self {
76        Shape::Points(val)
77    }
78}
79
80/// Horizontal text alignment: left, center, or right.
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82#[cfg_attr(
83    feature = "pyo3",
84    pyo3::pyclass(eq, eq_int, get_all, set_all, module = "xdot_rs.shapes")
85)]
86pub enum TextAlign {
87    Left,
88    Center,
89    Right,
90}
91/// Multiline text for node or edge labels.
92#[derive(Debug, Clone, PartialEq)]
93#[cfg_attr(
94    feature = "pyo3",
95    pyo3::pyclass(eq, get_all, set_all, module = "xdot_rs.shapes")
96)]
97pub struct Text {
98    pub x: f32,
99    pub y: f32,
100    pub align: TextAlign,
101    pub width: f32,
102    pub text: String,
103}
104#[cfg(feature = "pyo3")]
105#[pyo3::pymethods]
106impl Text {
107    #[new]
108    fn new(x: f32, y: f32, align: TextAlign, width: f32, text: String) -> Self {
109        Text {
110            x,
111            y,
112            align,
113            width,
114            text,
115        }
116    }
117}
118impl From<Text> for Shape {
119    fn from(val: Text) -> Self {
120        Shape::Text(val)
121    }
122}
123
124/// External image, currently unimplemented.
125#[doc(hidden)]
126#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
127#[cfg_attr(feature = "pyo3", pyo3::pyclass(module = "xdot_rs.shapes"))]
128pub struct ExternalImage;
129
130#[cfg(feature = "pyo3")]
131#[pyo3::pymodule]
132#[pyo3(name = "shapes")]
133pub fn pymodule(m: &pyo3::Bound<'_, pyo3::types::PyModule>) -> pyo3::PyResult<()> {
134    use pyo3::prelude::*;
135
136    m.add_class::<Ellipse>()?;
137    m.add_class::<PointsType>()?;
138    m.add_class::<Points>()?;
139    m.add_class::<TextAlign>()?;
140    m.add_class::<Text>()?;
141    m.add_class::<ExternalImage>()?;
142    Ok(())
143}