jellyflow_layout/
preset.rs1use jellyflow_core::{CanvasSize, NodeId};
2use serde::{Deserialize, Serialize};
3
4use crate::engine::{
5 LayoutDirection, LayoutEngineId, LayoutEngineRequest, LayoutOptions, LayoutRequest,
6 LayoutScope, LayoutSpacing,
7};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11pub struct LayoutPresetBuilder {
12 request: LayoutEngineRequest,
13}
14
15impl Default for LayoutPresetBuilder {
16 fn default() -> Self {
17 Self::workflow()
18 }
19}
20
21impl LayoutPresetBuilder {
22 pub fn workflow() -> Self {
24 Self::new(LayoutEngineId::dugong(), LayoutRequest::all())
25 }
26
27 pub fn tree() -> Self {
29 Self::new(LayoutEngineId::tidy_tree(), LayoutRequest::all()).with_options(LayoutOptions {
30 direction: LayoutDirection::TopToBottom,
31 spacing: LayoutSpacing {
32 nodesep: 32.0,
33 ranksep: 72.0,
34 edgesep: 16.0,
35 },
36 ..LayoutOptions::default()
37 })
38 }
39
40 pub fn mind_map() -> Self {
42 Self::new(LayoutEngineId::mind_map_radial(), LayoutRequest::all())
43 }
44
45 pub fn freeform() -> Self {
47 Self::new(LayoutEngineId::mind_map_freeform(), LayoutRequest::all()).with_options(
48 LayoutOptions {
49 spacing: LayoutSpacing {
50 nodesep: 24.0,
51 ranksep: 24.0,
52 edgesep: 24.0,
53 },
54 ..LayoutOptions::default()
55 },
56 )
57 }
58
59 pub fn new(engine: impl Into<LayoutEngineId>, layout: LayoutRequest) -> Self {
61 Self {
62 request: LayoutEngineRequest::new(engine, layout),
63 }
64 }
65
66 pub fn with_engine(mut self, engine: impl Into<LayoutEngineId>) -> Self {
68 self.request.engine = engine.into();
69 self
70 }
71
72 pub fn with_layout(mut self, layout: LayoutRequest) -> Self {
74 self.request.layout = layout;
75 self
76 }
77
78 pub fn with_options(mut self, options: LayoutOptions) -> Self {
80 self.request.layout.options = options;
81 self
82 }
83
84 pub fn with_direction(mut self, direction: LayoutDirection) -> Self {
86 self.request.layout.options.direction = direction;
87 self
88 }
89
90 pub fn with_spacing(mut self, spacing: LayoutSpacing) -> Self {
92 self.request.layout.options.spacing = spacing;
93 self
94 }
95
96 pub fn with_margin(mut self, margin: CanvasSize) -> Self {
98 self.request.layout.options.margin = margin;
99 self
100 }
101
102 pub fn with_default_node_size(mut self, size: CanvasSize) -> Self {
104 self.request.layout.options.default_node_size = size;
105 self
106 }
107
108 pub fn with_node_origin(mut self, node_origin: (f32, f32)) -> Self {
110 self.request.layout.options.node_origin = node_origin;
111 self
112 }
113
114 pub fn all(mut self) -> Self {
116 self.request.layout.scope = LayoutScope::All;
117 self
118 }
119
120 pub fn nodes(mut self, nodes: impl IntoIterator<Item = NodeId>) -> Self {
122 self.request.layout.scope = LayoutScope::Nodes {
123 nodes: nodes.into_iter().collect(),
124 };
125 self
126 }
127
128 pub fn with_scope(mut self, scope: LayoutScope) -> Self {
130 self.request.layout.scope = scope;
131 self
132 }
133
134 pub fn with_measured_node_sizes(
136 mut self,
137 sizes: impl IntoIterator<Item = (NodeId, CanvasSize)>,
138 ) -> Self {
139 self.request.layout.measured_node_sizes.extend(sizes);
140 self
141 }
142
143 pub fn build(self) -> LayoutEngineRequest {
145 self.request
146 }
147
148 pub fn layout_request(&self) -> LayoutRequest {
150 self.request.layout.clone()
151 }
152
153 pub fn engine_request(&self) -> LayoutEngineRequest {
155 self.request.clone()
156 }
157}
158
159impl From<LayoutPresetBuilder> for LayoutEngineRequest {
160 fn from(value: LayoutPresetBuilder) -> Self {
161 value.build()
162 }
163}