Skip to content

Commit 9ca1dec

Browse files
authored
Merge pull request #38 from azriel91/feature/margins
2 parents f4f3369 + 4fde92e commit 9ca1dec

File tree

8 files changed

+401
-64
lines changed

8 files changed

+401
-64
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## unreleased
44

5+
* Support `margins` in `GraphvizAttrs`.
6+
* Support `margin_cluster_default` in `GraphvizAttrs`.
7+
* Support `margin_node_default` in `GraphvizAttrs`.
58
* Support `node_width_default` in `GraphvizAttrs`.
69
* Support `node_widths` in `GraphvizAttrs`.
710
* Support `node_height_default` in `GraphvizAttrs`.

crate/model/src/common/graphviz_attrs.rs

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
use serde::{Deserialize, Serialize};
22

33
pub use self::{
4-
edge_constraints::EdgeConstraints, edge_dir::EdgeDir, edge_dirs::EdgeDirs,
5-
edge_minlens::EdgeMinlens, fixed_size::FixedSize, node_heights::NodeHeights,
6-
node_widths::NodeWidths, pack_mode::PackMode, pack_mode_flag::PackModeFlag, splines::Splines,
4+
cluster_margin::ClusterMargin, edge_constraints::EdgeConstraints, edge_dir::EdgeDir,
5+
edge_dirs::EdgeDirs, edge_minlens::EdgeMinlens, fixed_size::FixedSize, margin::Margin,
6+
margins::Margins, node_heights::NodeHeights, node_margin::NodeMargin, node_widths::NodeWidths,
7+
pack_mode::PackMode, pack_mode_flag::PackModeFlag, splines::Splines,
78
};
89

10+
mod cluster_margin;
911
mod edge_constraints;
1012
mod edge_dir;
1113
mod edge_dirs;
1214
mod edge_minlens;
1315
mod fixed_size;
16+
mod margin;
17+
mod margins;
1418
mod node_heights;
19+
mod node_margin;
1520
mod node_widths;
1621
mod pack_mode;
1722
mod pack_mode_flag;
@@ -69,6 +74,24 @@ pub struct GraphvizAttrs {
6974
///
7075
/// [`minlen`]: https://graphviz.org/docs/attrs/minlen/
7176
pub edge_minlens: EdgeMinlens,
77+
/// The default value for each node's [`margin`], defaults to `0.11,0.055`.
78+
///
79+
/// May be a single float, or two floats separated by a comma.
80+
///
81+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
82+
pub margin_cluster_default: ClusterMargin,
83+
/// The default value for each cluster's [`margin`], defaults to `8.0`.
84+
///
85+
/// May be a single float, or two floats separated by a comma.
86+
///
87+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
88+
pub margin_node_default: NodeMargin,
89+
/// Each node or cluster's [`margin`].
90+
///
91+
/// May be a single float, or two floats separated by a comma.
92+
///
93+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
94+
pub margins: Margins,
7295
/// Minimum / initial [`width`] for nodes, defaults to `0.3`.
7396
///
7497
/// If `fixedsize` is true, this will be the exact / maximum width for
@@ -197,6 +220,37 @@ impl GraphvizAttrs {
197220
self
198221
}
199222

223+
/// Sets the default value for each node's [`margin`], defaults to
224+
/// `0.11,0.055`.
225+
///
226+
/// May be a single float, or two floats separated by a comma.
227+
///
228+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
229+
pub fn with_margin_cluster_default(mut self, margin_cluster_default: ClusterMargin) -> Self {
230+
self.margin_cluster_default = margin_cluster_default;
231+
self
232+
}
233+
234+
/// Sets the default value for each cluster's [`margin`], defaults to `8.0`.
235+
///
236+
/// May be a single float, or two floats separated by a comma.
237+
///
238+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
239+
pub fn with_margin_node_default(mut self, margin_node_default: NodeMargin) -> Self {
240+
self.margin_node_default = margin_node_default;
241+
self
242+
}
243+
244+
/// Sets each node or cluster's [`margin`].
245+
///
246+
/// May be a single float, or two floats separated by a comma.
247+
///
248+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
249+
pub fn with_margins(mut self, margins: Margins) -> Self {
250+
self.margins = margins;
251+
self
252+
}
253+
200254
/// Sets the minimum / initial [`width`] for nodes, defaults to `0.3`.
201255
///
202256
/// If `fixedsize` is true, this will be the exact / maximum width for
@@ -323,6 +377,33 @@ impl GraphvizAttrs {
323377
&self.edge_minlens
324378
}
325379

380+
/// Returns the default value for each node's [`margin`].
381+
///
382+
/// May be a single float, or two floats separated by a comma.
383+
///
384+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
385+
pub fn margin_cluster_default(&self) -> ClusterMargin {
386+
self.margin_cluster_default
387+
}
388+
389+
/// Returns the default value for each cluster's [`margin`].
390+
///
391+
/// May be a single float, or two floats separated by a comma.
392+
///
393+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
394+
pub fn margin_node_default(&self) -> NodeMargin {
395+
self.margin_node_default
396+
}
397+
398+
/// Returns each node or cluster's [`margin`].
399+
///
400+
/// May be a single float, or two floats separated by a comma.
401+
///
402+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
403+
pub fn margins(&self) -> &Margins {
404+
&self.margins
405+
}
406+
326407
/// Returns the minimum / initial [`width`] for nodes.
327408
///
328409
/// If `fixedsize` is true, this will be the exact / maximum width for
@@ -385,6 +466,9 @@ impl Default for GraphvizAttrs {
385466
edge_dirs: EdgeDirs::default(),
386467
edge_minlen_default: 2,
387468
edge_minlens: EdgeMinlens::default(),
469+
margin_cluster_default: ClusterMargin::default(),
470+
margin_node_default: NodeMargin::default(),
471+
margins: Margins::default(),
388472
node_width_default: 0.3,
389473
node_widths: NodeWidths::default(),
390474
node_height_default: 0.1,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::fmt;
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
use crate::common::graphviz_attrs::Margin;
6+
7+
/// A node [`margin`], which specifies the space between the nodes in the
8+
/// cluster and the cluster bounding box.
9+
///
10+
/// Defaults to `Margin::Same(8.0)`; Graphviz default: `8.0`.
11+
///
12+
/// May be a single float, or two floats separated by a comma.
13+
///
14+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
15+
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
16+
#[serde(rename_all = "snake_case")]
17+
pub struct ClusterMargin(pub Margin);
18+
19+
impl ClusterMargin {
20+
/// Returns a new `ClusterMargin`.
21+
pub fn new() -> Self {
22+
Self::default()
23+
}
24+
25+
/// Returns the inner `Margin`.
26+
pub fn into_inner(self) -> Margin {
27+
self.0
28+
}
29+
}
30+
31+
impl Default for ClusterMargin {
32+
fn default() -> Self {
33+
Self(Margin::Same(8.0))
34+
}
35+
}
36+
37+
impl From<Margin> for ClusterMargin {
38+
fn from(margin: Margin) -> Self {
39+
Self(margin)
40+
}
41+
}
42+
43+
impl std::ops::DerefMut for ClusterMargin {
44+
fn deref_mut(&mut self) -> &mut Self::Target {
45+
&mut self.0
46+
}
47+
}
48+
49+
impl std::ops::Deref for ClusterMargin {
50+
type Target = Margin;
51+
52+
fn deref(&self) -> &Self::Target {
53+
&self.0
54+
}
55+
}
56+
57+
impl fmt::Display for ClusterMargin {
58+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59+
self.0.fmt(f)
60+
}
61+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::{fmt, fmt::Display, str::FromStr};
2+
3+
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
4+
5+
/// Node or cluster [`margin`]s.
6+
///
7+
/// May be a single float, or two floats separated by a comma.
8+
///
9+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
10+
#[derive(Clone, Copy, Debug, PartialEq)]
11+
pub enum Margin {
12+
/// Margins on both left/right and top/bottom are the same.
13+
Same(f64),
14+
/// Margins for left/right are different to top/bottom.
15+
Different(f64, f64),
16+
}
17+
18+
impl FromStr for Margin {
19+
type Err = String;
20+
21+
fn from_str(s: &str) -> Result<Self, Self::Err> {
22+
match s.split_once(',') {
23+
Some((margin_x, margin_y)) => {
24+
let margin_x = margin_x.parse::<f64>().map_err(|_e| {
25+
format!(
26+
"Failed to parse `{margin_x}` as a margin. \
27+
Please use a floating point number such as 0.5."
28+
)
29+
})?;
30+
let margin_y = margin_y.parse::<f64>().map_err(|_e| {
31+
format!(
32+
"Failed to parse `{margin_y}` as a margin. \
33+
Please use a floating point number such as 0.5."
34+
)
35+
})?;
36+
37+
Ok(Self::Different(margin_x, margin_y))
38+
}
39+
None => {
40+
let margin = s.parse::<f64>().map_err(|_e| {
41+
format!(
42+
"Failed to parse `{s}` as a margin. \
43+
Please use a floating point number such as 0.5."
44+
)
45+
})?;
46+
Ok(Self::Same(margin))
47+
}
48+
}
49+
}
50+
}
51+
52+
impl Display for Margin {
53+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54+
match self {
55+
Margin::Same(margin) => margin.fmt(f),
56+
Margin::Different(margin_x, margin_y) => write!(f, "{margin_x},{margin_y}"),
57+
}
58+
}
59+
}
60+
61+
impl<'de> Deserialize<'de> for Margin {
62+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63+
where
64+
D: Deserializer<'de>,
65+
{
66+
let s = String::deserialize(deserializer)?;
67+
FromStr::from_str(&s).map_err(de::Error::custom)
68+
}
69+
}
70+
71+
impl Serialize for Margin {
72+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73+
where
74+
S: Serializer,
75+
{
76+
serializer.serialize_str(&self.to_string())
77+
}
78+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use std::ops::{Deref, DerefMut};
2+
3+
use indexmap::IndexMap;
4+
use serde::{Deserialize, Serialize};
5+
6+
use crate::common::{graphviz_attrs::Margin, NodeId};
7+
8+
/// GraphViz node or cluster margins. `IndexMap<NodeId, Margin>` newtype.
9+
///
10+
/// This is only used for GraphViz dot graphs, which sets the [`margin`]
11+
/// attribute for the node / cluster.
12+
///
13+
/// If this is unset, nodes will use the default [`NodeMargin`], and clusters
14+
/// will use the default [`ClusterMargin`].
15+
///
16+
/// [`margin`]: https://graphviz.org/docs/attrs/margin/
17+
/// [`NodeMargin`]: crate::common::graphviz_attrs::NodeMargin
18+
/// [`ClusterMargin`]: crate::common::graphviz_attrs::ClusterMargin
19+
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
20+
pub struct Margins(IndexMap<NodeId, Margin>);
21+
22+
impl Margins {
23+
/// Returns a new `Margins` map.
24+
pub fn new() -> Self {
25+
Self::default()
26+
}
27+
28+
/// Returns a new `Margins` map with the given preallocated
29+
/// capacity.
30+
pub fn with_capacity(capacity: usize) -> Self {
31+
Self(IndexMap::with_capacity(capacity))
32+
}
33+
34+
/// Returns the underlying map.
35+
pub fn into_inner(self) -> IndexMap<NodeId, Margin> {
36+
self.0
37+
}
38+
}
39+
40+
impl Deref for Margins {
41+
type Target = IndexMap<NodeId, Margin>;
42+
43+
fn deref(&self) -> &Self::Target {
44+
&self.0
45+
}
46+
}
47+
48+
impl DerefMut for Margins {
49+
fn deref_mut(&mut self) -> &mut Self::Target {
50+
&mut self.0
51+
}
52+
}
53+
54+
impl From<IndexMap<NodeId, Margin>> for Margins {
55+
fn from(inner: IndexMap<NodeId, Margin>) -> Self {
56+
Self(inner)
57+
}
58+
}
59+
60+
impl FromIterator<(NodeId, Margin)> for Margins {
61+
fn from_iter<I: IntoIterator<Item = (NodeId, Margin)>>(iter: I) -> Self {
62+
Self(IndexMap::from_iter(iter))
63+
}
64+
}

0 commit comments

Comments
 (0)