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