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