1use std::collections::HashMap;
2
3use gpui::{
4 AnyElement, Bounds, Context, Div, KeyDownEvent, KeyUpEvent, MouseDownEvent, MouseMoveEvent,
5 MouseUpEvent, Pixels, Point, ScrollWheelEvent, Size, Styled, Window, div, px, rgb,
6};
7
8use crate::{
9 Edge, EdgeBuilder, EdgeId, FlowCanvas, FlowTheme, Graph, Node, NodeBuilder, NodeId,
10 NodeRenderer, Port, PortId, RendererRegistry, Viewport,
11 alignment_guides::AlignmentGuides,
12 canvas::{
13 Command, CommandContext, HistoryProvider, Interaction, InteractionState, PortLayoutCache,
14 },
15 copied_subgraph::CopiedSubgraph,
16};
17
18mod sync;
19mod utils;
20
21pub use sync::SyncPlugin;
22
23pub use utils::{
24 cache_all_node_port_offset, cache_node_port_offset, cache_port_offset_with_edge,
25 cache_port_offset_with_port, is_edge_visible, is_node_visible, port_offset_cached,
26 primary_platform_modifier,
27};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum NodeCardVariant {
34 Default,
37 UndefinedType,
40
41 Custom,
43}
44
45pub trait Plugin {
46 fn name(&self) -> &'static str;
47
48 fn setup(&mut self, _ctx: &mut InitPluginContext) {}
49
50 fn on_event(&mut self, _event: &FlowEvent, _ctx: &mut PluginContext) -> EventResult {
51 EventResult::Continue
52 }
53
54 fn render(&mut self, _ctx: &mut RenderContext) -> Option<AnyElement> {
55 None
56 }
57
58 fn priority(&self) -> i32 {
59 0
60 }
61
62 fn render_layer(&self) -> RenderLayer {
63 RenderLayer::Overlay
64 }
65}
66
67pub struct InitPluginContext<'a, 'b> {
68 pub graph: &'a mut Graph,
69 pub port_offset_cache: &'a mut PortLayoutCache,
70 pub viewport: &'a mut Viewport,
71 pub renderers: &'a mut RendererRegistry,
72 pub gpui_ctx: &'a Context<'b, FlowCanvas>,
73 pub drawable_size: Size<Pixels>,
75 pub theme: &'a mut FlowTheme,
77 }
79
80impl<'a, 'b> InitPluginContext<'a, 'b> {
81 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
82 self.graph.create_node(node_type)
83 }
84
85 pub fn create_edge(&self) -> EdgeBuilder {
86 self.graph.create_dege()
87 }
88
89 pub fn next_node_id(&self) -> NodeId {
90 self.graph.next_node_id()
91 }
92
93 pub fn next_port_id(&self) -> PortId {
94 self.graph.next_port_id()
95 }
96
97 pub fn next_edge_id(&self) -> EdgeId {
98 self.graph.next_edge_id()
99 }
100
101 pub fn add_node(&mut self, node: Node) {
102 self.graph.add_node(node);
103 }
104
105 pub fn add_port(&mut self, port: Port) {
106 self.graph.add_port(port);
107 }
108
109 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
110 self.graph.get_node(id)
111 }
112
113 pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
114 self.graph.get_node_mut(id)
115 }
116 pub fn remove_node(&mut self, id: &NodeId) {
117 self.graph.remove_node(id);
118 }
119 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
120 self.graph.nodes()
121 }
122 pub fn node_order(&self) -> &Vec<NodeId> {
123 self.graph.node_order()
124 }
125
126 pub fn new_edge(&self) -> Edge {
127 self.graph.new_edge()
128 }
129
130 pub fn add_edge(&mut self, edge: Edge) {
131 self.graph.add_edge(edge);
132 }
133
134 pub fn remove_edge(&mut self, edge_id: EdgeId) {
135 self.graph.remove_edge(edge_id);
136 }
137
138 pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
139 self.graph.add_selected_node(id, shift);
140 }
141 pub fn clear_selected_node(&mut self) {
142 self.graph.clear_selected_node();
143 }
144 pub fn remove_selected_node(&mut self) -> bool {
145 self.graph.remove_selected_node()
146 }
147
148 pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
149 self.graph.add_selected_edge(id, shift);
150 }
151 pub fn clear_selected_edge(&mut self) {
152 self.graph.clear_selected_edge();
153 }
154 pub fn remove_selected_edge(&mut self) -> bool {
155 self.graph.remove_selected_edge()
156 }
157
158 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
159 self.graph.selection_bounds()
160 }
161
162 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
163 self.graph.selected_nodes_with_positions()
164 }
165
166 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
167 self.graph.hit_node(mouse)
168 }
169
170 pub fn bring_node_to_front(&mut self, node_id: NodeId) {
171 self.graph.bring_node_to_front(node_id);
172 }
173
174 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
175 self.viewport.world_to_screen(p)
176 }
177
178 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
179 self.viewport.screen_to_world(p)
180 }
181
182 pub fn is_node_visible(&self, node_id: &NodeId) -> bool {
183 is_node_visible(self.graph, self.viewport, node_id)
184 }
185
186 pub fn is_edge_visible(&self, edge: &Edge) -> bool {
187 is_edge_visible(self.graph, self.viewport, edge)
188 }
189
190 pub fn port_offset_cached(&self, node_id: &NodeId, port_id: &PortId) -> Option<Point<Pixels>> {
191 port_offset_cached(self.port_offset_cache, node_id, port_id)
192 }
193
194 pub fn cache_port_offset_with_node(&mut self, node_ids: &Vec<NodeId>) {
195 for node_id in node_ids {
196 self.cache_node_port_offset(&node_id);
197 }
198 }
199
200 pub fn cache_port_offset_with_edge(&mut self, edge_id: &EdgeId) {
201 cache_port_offset_with_edge(self.graph, self.renderers, self.port_offset_cache, edge_id)
202 }
203
204 pub fn cache_port_offset_with_port(&mut self, port_id: &PortId) {
205 cache_port_offset_with_port(self.graph, self.renderers, self.port_offset_cache, port_id)
206 }
207
208 fn cache_node_port_offset(&mut self, node_id: &NodeId) {
209 cache_node_port_offset(self.graph, self.renderers, self.port_offset_cache, node_id);
210 }
211}
212
213pub struct PluginContext<'a> {
214 pub graph: &'a mut Graph,
215 pub port_offset_cache: &'a mut PortLayoutCache,
216 pub viewport: &'a mut Viewport,
217 pub(crate) interaction: &'a mut InteractionState,
218 pub renderers: &'a mut RendererRegistry,
219
220 sync_plugin: &'a mut Option<Box<dyn SyncPlugin + 'static>>,
221
222 pub history: &'a mut dyn HistoryProvider,
223 pub(crate) clipboard_subgraph: &'a mut Option<CopiedSubgraph>,
225 pub theme: &'a mut FlowTheme,
227 emit: &'a mut dyn FnMut(FlowEvent),
228 notify: &'a mut dyn FnMut(),
229}
230
231pub enum EventResult {
232 Continue,
233 Stop,
234}
235
236impl<'a> PluginContext<'a> {
237 pub fn new(
238 graph: &'a mut Graph,
239 port_offset_cache: &'a mut PortLayoutCache,
240 viewport: &'a mut Viewport,
241 interaction: &'a mut InteractionState,
242 renderers: &'a mut RendererRegistry,
243 sync_plugin: &'a mut Option<Box<dyn SyncPlugin + 'static>>,
244 history: &'a mut dyn HistoryProvider,
245 clipboard_subgraph: &'a mut Option<CopiedSubgraph>,
246 theme: &'a mut FlowTheme,
247 emit: &'a mut dyn FnMut(FlowEvent),
248 notify: &'a mut dyn FnMut(),
249 ) -> Self {
250 Self {
251 graph,
252 port_offset_cache,
253 viewport,
254 interaction,
255 renderers,
256 sync_plugin,
257 history,
258 clipboard_subgraph,
259 theme,
260 emit,
261 notify,
262 }
263 }
264
265 pub fn start_interaction(&mut self, handler: impl Interaction + 'static) {
266 self.interaction.alignment_guides = None;
267 self.interaction.handler = Some(Box::new(handler));
268 }
269
270 pub fn cancel_interaction(&mut self) {
271 self.interaction.alignment_guides = None;
272 self.interaction.handler = None;
273 }
274
275 pub fn has_interaction(&self) -> bool {
276 self.interaction.handler.is_some()
277 }
278
279 pub fn notify(&mut self) {
281 (self.notify)();
282 }
283
284 pub fn emit(&mut self, event: FlowEvent) {
285 (self.emit)(event);
286 self.notify();
287 }
288
289 pub fn has_sync_plugin(&self) -> bool {
290 self.sync_plugin.is_some()
291 }
292
293 pub fn execute_command(&mut self, command: impl Command + 'static) {
294 let mut ctx = CommandContext {
295 graph: self.graph,
296 port_offset_cache: self.port_offset_cache,
297 viewport: self.viewport,
298 renderers: self.renderers,
299 notify: self.notify,
300 };
301 if let Some(sync) = &mut self.sync_plugin {
302 let ops = command.to_ops(&mut ctx);
303 for op in ops.into_iter() {
304 sync.process_intent(op);
305 }
306 self.notify();
307 } else {
308 self.history.push(Box::new(command), &mut ctx);
309
310 self.notify();
311 }
312 }
313
314 pub fn undo(&mut self) {
315 if let Some(sync) = &mut self.sync_plugin {
316 sync.undo();
317 } else {
318 let mut ctx = CommandContext {
319 graph: self.graph,
320 port_offset_cache: self.port_offset_cache,
321 viewport: self.viewport,
322 renderers: self.renderers,
323 notify: self.notify,
324 };
325
326 self.history.undo(&mut ctx);
327
328 self.notify();
329 }
330 }
331
332 pub fn redo(&mut self) {
333 if let Some(sync) = &mut self.sync_plugin {
334 sync.redo();
335 } else {
336 let mut ctx = CommandContext {
337 graph: self.graph,
338 port_offset_cache: self.port_offset_cache,
339 viewport: self.viewport,
340 renderers: self.renderers,
341 notify: self.notify,
342 };
343
344 self.history.redo(&mut ctx);
345
346 self.notify();
347 }
348 }
349
350 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
351 self.graph.create_node(node_type)
352 }
353
354 pub fn create_edge(&self) -> EdgeBuilder {
355 self.graph.create_dege()
356 }
357
358 pub fn next_node_id(&self) -> NodeId {
359 self.graph.next_node_id()
360 }
361
362 pub fn next_port_id(&self) -> PortId {
363 self.graph.next_port_id()
364 }
365
366 pub fn next_edge_id(&self) -> EdgeId {
367 self.graph.next_edge_id()
368 }
369
370 pub fn add_node(&mut self, node: Node) {
371 self.graph.add_node(node);
372 }
373
374 pub fn add_port(&mut self, port: Port) {
375 self.graph.add_port(port);
376 }
377
378 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
379 self.graph.get_node(id)
380 }
381
382 pub fn get_node_render(&self, id: &NodeId) -> Option<&dyn NodeRenderer> {
383 let node = self.get_node(id)?;
384
385 Some(self.renderers.get(&node.node_type))
386 }
387
388 pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
389 self.graph.get_node_mut(id)
390 }
391 pub fn remove_node(&mut self, id: &NodeId) {
392 self.graph.remove_node(id);
393 self.port_offset_cache.clear_node(id);
394 }
395 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
396 self.graph.nodes()
397 }
398 pub fn node_order(&self) -> &Vec<NodeId> {
399 self.graph.node_order()
400 }
401
402 pub fn new_edge(&self) -> Edge {
403 self.graph.new_edge()
404 }
405
406 pub fn add_edge(&mut self, edge: Edge) {
407 self.graph.add_edge(edge);
408 }
409
410 pub fn remove_edge(&mut self, edge_id: EdgeId) {
411 self.graph.remove_edge(edge_id);
412 }
413
414 pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
415 self.graph.add_selected_node(id, shift);
416 }
417 pub fn clear_selected_node(&mut self) {
418 self.graph.clear_selected_node();
419 }
420 pub fn remove_selected_node(&mut self) -> bool {
421 self.graph.remove_selected_node()
422 }
423
424 pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
425 self.graph.add_selected_edge(id, shift);
426 }
427 pub fn clear_selected_edge(&mut self) {
428 self.graph.clear_selected_edge();
429 }
430 pub fn remove_selected_edge(&mut self) -> bool {
431 self.graph.remove_selected_edge()
432 }
433
434 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
435 self.graph.selection_bounds()
436 }
437
438 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
439 self.graph.selected_nodes_with_positions()
440 }
441
442 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
443 self.graph.hit_node(mouse)
444 }
445
446 pub fn bring_node_to_front(&mut self, node_id: NodeId) {
447 self.graph.bring_node_to_front(node_id);
448 }
449
450 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
451 self.viewport.world_to_screen(p)
452 }
453
454 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
455 self.viewport.screen_to_world(p)
456 }
457
458 pub fn is_node_visible(&self, node_id: &NodeId) -> bool {
459 is_node_visible(self.graph, self.viewport, node_id)
460 }
461
462 pub fn is_edge_visible(&self, edge: &Edge) -> bool {
463 is_edge_visible(self.graph, self.viewport, edge)
464 }
465
466 pub fn port_offset_cached(&self, node_id: &NodeId, port_id: &PortId) -> Option<Point<Pixels>> {
467 port_offset_cached(self.port_offset_cache, node_id, port_id)
468 }
469
470 pub fn cache_all_node_port_offset(&mut self) {
471 cache_all_node_port_offset(self.graph, self.renderers, self.port_offset_cache);
472 }
473
474 pub fn cache_port_offset_with_node(&mut self, node_ids: &Vec<NodeId>) {
475 for node_id in node_ids {
476 self.cache_node_port_offset(&node_id);
477 }
478 }
479
480 pub fn cache_port_offset_with_edge(&mut self, edge_id: &EdgeId) {
481 cache_port_offset_with_edge(self.graph, self.renderers, self.port_offset_cache, edge_id)
482 }
483
484 pub fn cache_port_offset_with_port(&mut self, port_id: &PortId) {
485 cache_port_offset_with_port(self.graph, self.renderers, self.port_offset_cache, port_id)
486 }
487
488 fn cache_node_port_offset(&mut self, node_id: &NodeId) {
489 cache_node_port_offset(self.graph, self.renderers, self.port_offset_cache, node_id);
490 }
491}
492
493pub enum FlowEvent {
494 Input(InputEvent),
495 Custom(Box<dyn std::any::Any + Send>),
496}
497
498impl FlowEvent {
499 pub fn custom<T: 'static + Send>(event: T) -> Self {
500 FlowEvent::Custom(Box::new(event))
501 }
502 pub fn as_custom<T: 'static>(&self) -> Option<&T> {
503 match self {
504 FlowEvent::Custom(e) => e.downcast_ref::<T>(),
505 _ => None,
506 }
507 }
508}
509
510pub enum InputEvent {
511 KeyDown(KeyDownEvent),
512 KeyUp(KeyUpEvent),
513
514 MouseDown(MouseDownEvent),
515 MouseMove(MouseMoveEvent),
516 MouseUp(MouseUpEvent),
517
518 Wheel(ScrollWheelEvent),
519}
520
521pub struct RenderContext<'a> {
522 pub graph: &'a Graph,
523 pub port_offset_cache: &'a mut PortLayoutCache,
524 pub viewport: &'a Viewport,
525 pub renderers: &'a RendererRegistry,
526
527 pub window: &'a Window,
528
529 pub layer: RenderLayer,
530 pub alignment_guides: Option<&'a AlignmentGuides>,
532 pub theme: &'a FlowTheme,
534}
535
536impl<'a> RenderContext<'a> {
537 pub fn new(
538 graph: &'a mut Graph,
539 port_offset_cache: &'a mut PortLayoutCache,
540 viewport: &'a Viewport,
541 renderers: &'a RendererRegistry,
542 window: &'a Window,
543 layer: RenderLayer,
544 alignment_guides: Option<&'a AlignmentGuides>,
545 theme: &'a FlowTheme,
546 ) -> Self {
547 Self {
548 graph,
549 port_offset_cache,
550 viewport,
551 renderers,
552 window,
553 layer,
554 alignment_guides,
555 theme,
556 }
557 }
558
559 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
560 self.graph.create_node(node_type)
561 }
562
563 pub fn create_edge(&self) -> EdgeBuilder {
564 self.graph.create_dege()
565 }
566
567 pub fn next_node_id(&self) -> NodeId {
568 self.graph.next_node_id()
569 }
570
571 pub fn next_port_id(&self) -> PortId {
572 self.graph.next_port_id()
573 }
574
575 pub fn next_edge_id(&self) -> EdgeId {
576 self.graph.next_edge_id()
577 }
578
579 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
580 self.graph.get_node(id)
581 }
582
583 pub fn get_node_render(&self, id: &NodeId) -> Option<&dyn NodeRenderer> {
584 let node = self.get_node(id)?;
585
586 Some(self.renderers.get(&node.node_type))
587 }
588
589 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
590 self.graph.nodes()
591 }
592 pub fn node_order(&self) -> &Vec<NodeId> {
593 self.graph.node_order()
594 }
595
596 pub fn new_edge(&self) -> Edge {
597 self.graph.new_edge()
598 }
599
600 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
601 self.graph.selection_bounds()
602 }
603
604 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
605 self.graph.selected_nodes_with_positions()
606 }
607
608 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
609 self.graph.hit_node(mouse)
610 }
611
612 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
613 self.viewport.world_to_screen(p)
614 }
615
616 pub fn node_card_shell(&self, node: &Node, selected: bool, variant: NodeCardVariant) -> Div {
620 let screen = self.world_to_screen(node.point());
621 let z = self.viewport.zoom;
622 let base = div()
623 .absolute()
624 .left(screen.x)
625 .top(screen.y)
626 .w(node.size.width * z)
627 .h(node.size.height * z)
628 .rounded(px(6.0))
629 .border(px(1.5));
630 let t = self.theme;
631 match variant {
632 NodeCardVariant::Default => {
633 base.bg(rgb(t.node_card_background))
634 .border_color(rgb(if selected {
635 t.node_card_border_selected
636 } else {
637 t.node_card_border
638 }))
639 }
640 NodeCardVariant::UndefinedType => base
641 .bg(rgb(t.undefined_node_background))
642 .border_color(rgb(t.undefined_node_border)),
643 NodeCardVariant::Custom => base,
644 }
645 }
646
647 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
648 self.viewport.screen_to_world(p)
649 }
650
651 pub fn is_node_visible(&self, node_id: &NodeId) -> bool {
652 is_node_visible(self.graph, self.viewport, node_id)
653 }
654
655 pub fn is_edge_visible(&self, edge: &Edge) -> bool {
656 is_edge_visible(self.graph, self.viewport, edge)
657 }
658
659 pub fn port_offset_cached(&self, node_id: &NodeId, port_id: &PortId) -> Option<Point<Pixels>> {
660 port_offset_cached(self.port_offset_cache, node_id, port_id)
661 }
662
663 pub fn cache_all_node_port_offset(&mut self) {
664 for (node_id, _) in self.graph.nodes() {
665 self.cache_node_port_offset(node_id);
666 }
667 }
668
669 pub fn cache_port_offset_with_nodes(&mut self, node_ids: &Vec<NodeId>) {
670 for node_id in node_ids {
671 self.cache_node_port_offset(node_id);
672 }
673 }
674
675 pub fn cache_port_offset_with_edge(&mut self, edge_id: &EdgeId) {
676 cache_port_offset_with_edge(self.graph, self.renderers, self.port_offset_cache, edge_id)
677 }
678
679 pub fn cache_port_offset_with_port(&mut self, port_id: &PortId) {
680 cache_port_offset_with_port(self.graph, self.renderers, self.port_offset_cache, port_id)
681 }
682
683 fn cache_node_port_offset(&mut self, node_id: &NodeId) {
684 cache_node_port_offset(self.graph, self.renderers, self.port_offset_cache, node_id);
685 }
686}
687
688#[derive(Debug, PartialEq, Eq, Clone, Copy)]
689pub enum RenderLayer {
690 Background,
691 Edges,
692 Nodes,
693 Selection,
694 Interaction,
695 Overlay,
696}
697
698impl RenderLayer {
699 pub const ALL: [RenderLayer; 6] = [
700 RenderLayer::Background,
701 RenderLayer::Edges,
702 RenderLayer::Nodes,
703 RenderLayer::Selection,
704 RenderLayer::Interaction,
705 RenderLayer::Overlay,
706 ];
707 pub fn index(self) -> usize {
708 match self {
709 RenderLayer::Background => 0,
710 RenderLayer::Edges => 1,
711 RenderLayer::Nodes => 2,
712 RenderLayer::Selection => 3,
713 RenderLayer::Interaction => 4,
714 RenderLayer::Overlay => 5,
715 }
716 }
717}
718
719pub struct PluginRegistry {
720 pub plugins: Vec<Box<dyn Plugin>>,
721}
722
723impl PluginRegistry {
724 pub fn new() -> Self {
725 Self { plugins: vec![] }
726 }
727
728 pub fn add(mut self, plugin: impl Plugin + 'static) -> Self {
729 self.plugins.push(Box::new(plugin));
730 self
731 }
732}