jellyflow_runtime/runtime/
layout.rs1use jellyflow_core::core::Graph;
7use jellyflow_core::ops::GraphTransaction;
8pub use jellyflow_layout::{
9 DUGONG_LAYOUT_ENGINE_ID, DugongLayoutEngine, LAYERED_DAG_LAYOUT_FAMILY_ID, LayoutContext,
10 LayoutDirection, LayoutEdgeRoute, LayoutEngine, LayoutEngineCapability, LayoutEngineId,
11 LayoutEngineMetadata, LayoutEngineRegistry, LayoutEngineRequest, LayoutError, LayoutFamilyId,
12 LayoutFamilyMetadata, LayoutNodePosition, LayoutOptions, LayoutPresetBuilder, LayoutRequest,
13 LayoutResult, LayoutScope, LayoutSpacing, MIND_MAP_FREEFORM_LAYOUT_ENGINE_ID,
14 MIND_MAP_LAYOUT_FAMILY_ID, MIND_MAP_RADIAL_LAYOUT_ENGINE_ID, MindMapFreeformLayoutEngine,
15 MindMapRadialLayoutEngine, TIDY_TREE_LAYOUT_ENGINE_ID, TidyTreeLayoutEngine,
16 builtin_layout_engine_registry, layout_graph_to_transaction_with_dugong,
17 layout_graph_to_transaction_with_engine, layout_graph_to_transaction_with_mind_map_freeform,
18 layout_graph_to_transaction_with_mind_map_radial, layout_graph_to_transaction_with_tidy_tree,
19 layout_graph_with_dugong, layout_graph_with_engine, layout_graph_with_mind_map_freeform,
20 layout_graph_with_mind_map_radial, layout_graph_with_tidy_tree,
21};
22
23use crate::runtime::store::{DispatchError, DispatchOutcome, NodeGraphStore};
24
25#[derive(Debug, Clone)]
27pub struct LayoutApplyOutcome {
28 pub layout: LayoutResult,
29 pub dispatch: Option<DispatchOutcome>,
30}
31
32impl LayoutApplyOutcome {
33 pub fn committed(&self) -> Option<&GraphTransaction> {
34 self.dispatch.as_ref().map(DispatchOutcome::committed)
35 }
36}
37
38#[derive(Debug, thiserror::Error)]
40pub enum LayoutApplyError {
41 #[error(transparent)]
42 Layout(#[from] LayoutError),
43 #[error(transparent)]
44 Dispatch(#[from] DispatchError),
45}
46
47#[derive(Debug, Clone)]
49pub struct DugongLayoutApplyOutcome {
50 pub layout: LayoutResult,
51 pub dispatch: Option<DispatchOutcome>,
52}
53
54impl DugongLayoutApplyOutcome {
55 pub fn committed(&self) -> Option<&GraphTransaction> {
56 self.dispatch.as_ref().map(DispatchOutcome::committed)
57 }
58}
59
60#[derive(Debug, thiserror::Error)]
62pub enum DugongLayoutApplyError {
63 #[error(transparent)]
64 Layout(#[from] LayoutError),
65 #[error(transparent)]
66 Dispatch(#[from] DispatchError),
67}
68
69impl From<LayoutApplyOutcome> for DugongLayoutApplyOutcome {
70 fn from(outcome: LayoutApplyOutcome) -> Self {
71 Self {
72 layout: outcome.layout,
73 dispatch: outcome.dispatch,
74 }
75 }
76}
77
78impl From<LayoutApplyError> for DugongLayoutApplyError {
79 fn from(error: LayoutApplyError) -> Self {
80 match error {
81 LayoutApplyError::Layout(error) => Self::Layout(error),
82 LayoutApplyError::Dispatch(error) => Self::Dispatch(error),
83 }
84 }
85}
86
87pub fn layout_context_from_store(store: &NodeGraphStore) -> LayoutContext {
89 let measured_node_sizes = store.graph().nodes.keys().filter_map(|node| {
90 store
91 .node_measurement(*node)
92 .and_then(|measurement| measurement.size.map(|size| (*node, size)))
93 });
94 let node_origin = store.resolved_interaction_state().node_origin.normalized();
95
96 LayoutContext::new()
97 .with_measured_node_sizes(measured_node_sizes)
98 .with_node_origin((node_origin.x, node_origin.y))
99}
100
101pub fn plan_layout(
103 graph: &Graph,
104 request: &LayoutEngineRequest,
105 registry: &LayoutEngineRegistry,
106 context: &LayoutContext,
107) -> Result<LayoutResult, LayoutError> {
108 layout_graph_with_engine(graph, request, registry, context)
109}
110
111pub fn layout_transaction(
113 graph: &Graph,
114 request: &LayoutEngineRequest,
115 registry: &LayoutEngineRegistry,
116 context: &LayoutContext,
117) -> Result<GraphTransaction, LayoutError> {
118 layout_graph_to_transaction_with_engine(graph, request, registry, context)
119}
120
121pub fn apply_layout(
123 store: &mut NodeGraphStore,
124 request: &LayoutEngineRequest,
125 registry: &LayoutEngineRegistry,
126) -> Result<LayoutApplyOutcome, LayoutApplyError> {
127 let context = layout_context_from_store(store);
128 let layout = plan_layout(store.graph(), request, registry, &context)?;
129 let tx = layout.to_transaction(store.graph())?;
130 let dispatch = if tx.is_empty() {
131 None
132 } else {
133 Some(store.dispatch_transaction(&tx)?)
134 };
135
136 Ok(LayoutApplyOutcome { layout, dispatch })
137}
138
139pub fn plan_dugong_layout(
141 graph: &Graph,
142 request: &LayoutRequest,
143) -> Result<LayoutResult, LayoutError> {
144 layout_graph_with_dugong(graph, request)
145}
146
147pub fn dugong_layout_transaction(
149 graph: &Graph,
150 request: &LayoutRequest,
151) -> Result<GraphTransaction, LayoutError> {
152 plan_dugong_layout(graph, request)?.to_transaction(graph)
153}
154
155pub fn apply_dugong_layout(
157 store: &mut NodeGraphStore,
158 request: &LayoutRequest,
159) -> Result<DugongLayoutApplyOutcome, DugongLayoutApplyError> {
160 let registry = builtin_layout_engine_registry();
161 let request = LayoutEngineRequest::dugong(request.clone());
162 apply_layout(store, &request, ®istry)
163 .map(Into::into)
164 .map_err(Into::into)
165}
166
167impl NodeGraphStore {
168 pub fn layout_context(&self) -> LayoutContext {
170 layout_context_from_store(self)
171 }
172
173 pub fn plan_layout(
175 &self,
176 request: &LayoutEngineRequest,
177 registry: &LayoutEngineRegistry,
178 ) -> Result<LayoutResult, LayoutError> {
179 let context = self.layout_context();
180 plan_layout(self.graph(), request, registry, &context)
181 }
182
183 pub fn layout_transaction(
185 &self,
186 request: &LayoutEngineRequest,
187 registry: &LayoutEngineRegistry,
188 ) -> Result<GraphTransaction, LayoutError> {
189 let context = self.layout_context();
190 layout_transaction(self.graph(), request, registry, &context)
191 }
192
193 pub fn apply_layout(
195 &mut self,
196 request: &LayoutEngineRequest,
197 registry: &LayoutEngineRegistry,
198 ) -> Result<LayoutApplyOutcome, LayoutApplyError> {
199 apply_layout(self, request, registry)
200 }
201
202 pub fn plan_dugong_layout(&self, request: &LayoutRequest) -> Result<LayoutResult, LayoutError> {
204 let registry = builtin_layout_engine_registry();
205 let request = LayoutEngineRequest::dugong(request.clone());
206 self.plan_layout(&request, ®istry)
207 }
208
209 pub fn dugong_layout_transaction(
211 &self,
212 request: &LayoutRequest,
213 ) -> Result<GraphTransaction, LayoutError> {
214 let registry = builtin_layout_engine_registry();
215 let request = LayoutEngineRequest::dugong(request.clone());
216 self.layout_transaction(&request, ®istry)
217 }
218
219 pub fn apply_dugong_layout(
221 &mut self,
222 request: &LayoutRequest,
223 ) -> Result<DugongLayoutApplyOutcome, DugongLayoutApplyError> {
224 apply_dugong_layout(self, request)
225 }
226}