1use std::collections::HashMap;
2
3use gpui::{
4 AnyElement, Bounds, KeyDownEvent, KeyUpEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
5 Pixels, Point, ScrollWheelEvent, Window,
6};
7
8use crate::{
9 Edge, EdgeId, Graph, Node, NodeBuilder, NodeId, Port, PortId, Viewport,
10 canvas::{CanvasState, Command, History, Interaction, InteractionState},
11};
12
13pub trait Plugin {
14 fn name(&self) -> &'static str;
15
16 fn setup(&mut self, ctx: &mut InitPluginContext);
17
18 fn on_event(&mut self, _event: &FlowEvent, _context: &mut PluginContext) -> EventResult {
19 EventResult::Continue
20 }
21
22 fn render(&mut self, _context: &mut RenderContext) -> Option<AnyElement> {
23 None
24 }
25
26 fn priority(&self) -> i32 {
27 0
28 }
29
30 fn render_layer(&self) -> RenderLayer {
31 RenderLayer::Overlay
32 }
33}
34
35pub struct InitPluginContext<'a> {
36 pub graph: &'a mut Graph,
37 pub viewport: &'a mut Viewport,
38}
39
40impl<'a> InitPluginContext<'a> {
41 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
42 self.graph.create_node(node_type)
43 }
44
45 pub fn next_node_id(&self) -> NodeId {
46 self.graph.next_node_id()
47 }
48
49 pub fn next_port_id(&self) -> PortId {
50 self.graph.next_port_id()
51 }
52
53 pub fn next_edge_id(&self) -> EdgeId {
54 self.graph.next_edge_id()
55 }
56
57 pub fn add_node(&mut self, node: Node) {
58 self.graph.add_node(node);
59 }
60
61 pub fn add_point(&mut self, port: Port) {
62 self.graph.add_point(port);
63 }
64
65 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
66 self.graph.get_node(id)
67 }
68
69 pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
70 self.graph.get_node_mut(id)
71 }
72 pub fn remove_node(&mut self, id: &NodeId) {
73 self.graph.remove_node(id);
74 }
75 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
76 self.graph.nodes()
77 }
78 pub fn node_order(&self) -> &Vec<NodeId> {
79 self.graph.node_order()
80 }
81
82 pub fn new_edge(&self) -> Edge {
83 self.graph.new_edge()
84 }
85
86 pub fn add_edge(&mut self, edge: Edge) {
87 self.graph.add_edge(edge);
88 }
89
90 pub fn remove_edge(&mut self, edge_id: EdgeId) {
91 self.graph.remove_edge(edge_id);
92 }
93
94 pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
95 self.graph.add_selected_node(id, shift);
96 }
97 pub fn clear_selected_node(&mut self) {
98 self.graph.clear_selected_node();
99 }
100 pub fn remove_selected_node(&mut self) -> bool {
101 self.graph.remove_selected_node()
102 }
103
104 pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
105 self.graph.add_selected_edge(id, shift);
106 }
107 pub fn clear_selected_edge(&mut self) {
108 self.graph.clear_selected_edge();
109 }
110 pub fn remove_selected_edge(&mut self) -> bool {
111 self.graph.remove_selected_edge()
112 }
113
114 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
115 self.graph.selection_bounds()
116 }
117
118 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
119 self.graph.selected_nodes_with_positions()
120 }
121
122 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
123 self.graph.hit_node(mouse)
124 }
125
126 pub fn bring_node_to_front(&mut self, node_id: NodeId) {
127 self.graph.bring_node_to_front(node_id);
128 }
129
130 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
131 self.viewport.world_to_screen(p)
132 }
133
134 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
135 self.viewport.screen_to_world(p)
136 }
137}
138
139pub struct PluginContext<'a> {
140 pub graph: &'a mut Graph,
141 pub viewport: &'a mut Viewport,
142 pub(crate) interaction: &'a mut InteractionState,
143
144 pub history: &'a mut History,
145 emit: &'a mut dyn FnMut(FlowEvent),
146 notify: &'a mut dyn FnMut(),
147}
148
149pub enum EventResult {
150 Continue,
151 Stop,
152}
153
154impl<'a> PluginContext<'a> {
155 pub fn new(
156 graph: &'a mut Graph,
157 viewport: &'a mut Viewport,
158 interaction: &'a mut InteractionState,
159 history: &'a mut History,
160 emit: &'a mut dyn FnMut(FlowEvent),
161 notify: &'a mut dyn FnMut(),
162 ) -> Self {
163 Self {
164 graph,
165 viewport,
166 interaction,
167 history,
168 emit,
169 notify,
170 }
171 }
172
173 pub fn start_interaction(&mut self, handler: impl Interaction + 'static) {
174 self.interaction.handler = Some(Box::new(handler));
175 }
176
177 pub fn cancel_interaction(&mut self) {
178 self.interaction.handler = None;
179 }
180
181 pub fn has_interaction(&self) -> bool {
182 self.interaction.handler.is_some()
183 }
184
185 pub fn notify(&mut self) {
190 (self.notify)();
191 }
192
193 pub fn emit(&mut self, event: FlowEvent) {
194 (self.emit)(event);
195 self.notify();
196 }
197
198 pub fn execute_command(&mut self, command: impl Command + 'static) {
199 let mut canvas = CanvasState {
200 graph: self.graph,
201 viewport: self.viewport,
202 };
203
204 self.history.execute(Box::new(command), &mut canvas);
205
206 self.notify();
207 }
208
209 pub fn undo(&mut self) {
210 let mut canvas = CanvasState {
211 graph: self.graph,
212 viewport: self.viewport,
213 };
214
215 self.history.undo(&mut canvas);
216
217 self.notify();
218 }
219
220 pub fn redo(&mut self) {
221 let mut canvas = CanvasState {
222 graph: self.graph,
223 viewport: self.viewport,
224 };
225
226 self.history.redo(&mut canvas);
227
228 self.notify();
229 }
230
231 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
232 self.graph.create_node(node_type)
233 }
234
235 pub fn next_node_id(&self) -> NodeId {
236 self.graph.next_node_id()
237 }
238
239 pub fn next_port_id(&self) -> PortId {
240 self.graph.next_port_id()
241 }
242
243 pub fn next_edge_id(&self) -> EdgeId {
244 self.graph.next_edge_id()
245 }
246
247 pub fn add_node(&mut self, node: Node) {
248 self.graph.add_node(node);
249 }
250
251 pub fn add_point(&mut self, port: Port) {
252 self.graph.add_point(port);
253 }
254
255 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
256 self.graph.get_node(id)
257 }
258
259 pub fn get_node_mut(&mut self, id: &NodeId) -> Option<&mut Node> {
260 self.graph.get_node_mut(id)
261 }
262 pub fn remove_node(&mut self, id: &NodeId) {
263 self.graph.remove_node(id);
264 }
265 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
266 self.graph.nodes()
267 }
268 pub fn node_order(&self) -> &Vec<NodeId> {
269 self.graph.node_order()
270 }
271
272 pub fn new_edge(&self) -> Edge {
273 self.graph.new_edge()
274 }
275
276 pub fn add_edge(&mut self, edge: Edge) {
277 self.graph.add_edge(edge);
278 }
279
280 pub fn remove_edge(&mut self, edge_id: EdgeId) {
281 self.graph.remove_edge(edge_id);
282 }
283
284 pub fn add_selected_node(&mut self, id: NodeId, shift: bool) {
285 self.graph.add_selected_node(id, shift);
286 }
287 pub fn clear_selected_node(&mut self) {
288 self.graph.clear_selected_node();
289 }
290 pub fn remove_selected_node(&mut self) -> bool {
291 self.graph.remove_selected_node()
292 }
293
294 pub fn add_selected_edge(&mut self, id: EdgeId, shift: bool) {
295 self.graph.add_selected_edge(id, shift);
296 }
297 pub fn clear_selected_edge(&mut self) {
298 self.graph.clear_selected_edge();
299 }
300 pub fn remove_selected_edge(&mut self) -> bool {
301 self.graph.remove_selected_edge()
302 }
303
304 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
305 self.graph.selection_bounds()
306 }
307
308 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
309 self.graph.selected_nodes_with_positions()
310 }
311
312 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
313 self.graph.hit_node(mouse)
314 }
315
316 pub fn bring_node_to_front(&mut self, node_id: NodeId) {
317 self.graph.bring_node_to_front(node_id);
318 }
319
320 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
321 self.viewport.world_to_screen(p)
322 }
323
324 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
325 self.viewport.screen_to_world(p)
326 }
327}
328
329pub enum FlowEvent {
330 Input(InputEvent),
331 Graph(GraphEvent),
332 Ui(UiEvent),
333 Custom(Box<dyn std::any::Any + Send>),
334}
335
336impl FlowEvent {
337 pub fn custom<T: 'static + Send>(event: T) -> Self {
338 FlowEvent::Custom(Box::new(event))
339 }
340 pub fn as_custom<T: 'static>(&self) -> Option<&T> {
341 match self {
342 FlowEvent::Custom(e) => e.downcast_ref::<T>(),
343 _ => None,
344 }
345 }
346}
347
348pub enum InputEvent {
349 KeyDown(KeyDownEvent),
350 KeyUp(KeyUpEvent),
351
352 MouseDown(MouseDownEvent),
353 MouseMove(MouseMoveEvent),
354 MouseUp(MouseUpEvent),
355
356 Wheel(ScrollWheelEvent),
357}
358
359pub enum GraphEvent {
360 NodeClicked(NodeId),
361
362 NodeDragStart(NodeId),
363 NodeDragging(NodeId, Point<Pixels>),
364 NodeDragEnd(NodeId),
365
366 EdgeClicked(EdgeId),
367
368 EdgeCreated { from: PortId, to: PortId },
369
370 EdgeRemoved(EdgeId),
371}
372
373pub enum UiEvent {
374 SelectionChanged(Vec<NodeId>),
375
376 ConnectStart(PortId),
377
378 ConnectPreview(Point<Pixels>),
379
380 ConnectEnd(PortId),
381
382 ConnectCancel,
383
384 ViewportChanged { zoom: f32, pan: Point<Pixels> },
385}
386
387pub struct RenderContext<'a> {
399 pub graph: &'a Graph,
400 pub viewport: &'a Viewport,
401
402 pub window: &'a Window,
403
404 pub layer: RenderLayer,
405}
406
407impl<'a> RenderContext<'a> {
408 pub fn new(
409 graph: &'a Graph,
410 viewport: &'a Viewport,
411 window: &'a Window,
412 layer: RenderLayer,
413 ) -> Self {
414 Self {
415 graph,
416 viewport,
417 window,
418 layer,
419 }
420 }
421
422 pub fn create_node(&self, node_type: &str) -> NodeBuilder {
423 self.graph.create_node(node_type)
424 }
425
426 pub fn next_node_id(&self) -> NodeId {
427 self.graph.next_node_id()
428 }
429
430 pub fn next_port_id(&self) -> PortId {
431 self.graph.next_port_id()
432 }
433
434 pub fn next_edge_id(&self) -> EdgeId {
435 self.graph.next_edge_id()
436 }
437
438 pub fn get_node(&self, id: &NodeId) -> Option<&Node> {
439 self.graph.get_node(id)
440 }
441
442 pub fn nodes(&self) -> &HashMap<NodeId, Node> {
443 self.graph.nodes()
444 }
445 pub fn node_order(&self) -> &Vec<NodeId> {
446 self.graph.node_order()
447 }
448
449 pub fn new_edge(&self) -> Edge {
450 self.graph.new_edge()
451 }
452
453 pub fn selection_bounds(&self) -> Option<Bounds<Pixels>> {
454 self.graph.selection_bounds()
455 }
456
457 pub fn selected_nodes_with_positions(&self) -> HashMap<NodeId, Point<Pixels>> {
458 self.graph.selected_nodes_with_positions()
459 }
460
461 pub fn hit_node(&self, mouse: Point<Pixels>) -> Option<NodeId> {
462 self.graph.hit_node(mouse)
463 }
464
465 pub fn world_to_screen(&self, p: Point<Pixels>) -> Point<Pixels> {
466 self.viewport.world_to_screen(p)
467 }
468
469 pub fn screen_to_world(&self, p: Point<Pixels>) -> Point<Pixels> {
470 self.viewport.screen_to_world(p)
471 }
472}
473
474#[derive(Debug, PartialEq, Eq, Clone, Copy)]
475pub enum RenderLayer {
476 Background,
477 Edges,
478 Nodes,
479 Selection,
480 Interaction,
481 Overlay,
482}
483
484impl RenderLayer {
485 pub const ALL: [RenderLayer; 6] = [
486 RenderLayer::Background,
487 RenderLayer::Edges,
488 RenderLayer::Nodes,
489 RenderLayer::Selection,
490 RenderLayer::Interaction,
491 RenderLayer::Overlay,
492 ];
493 pub fn index(self) -> usize {
494 match self {
495 RenderLayer::Background => 0,
496 RenderLayer::Edges => 1,
497 RenderLayer::Nodes => 2,
498 RenderLayer::Selection => 3,
499 RenderLayer::Interaction => 4,
500 RenderLayer::Overlay => 5,
501 }
502 }
503}
504
505pub struct PluginRegistry {
506 pub plugins: Vec<Box<dyn Plugin>>,
507}
508
509impl PluginRegistry {
510 pub fn new() -> Self {
511 Self { plugins: vec![] }
512 }
513
514 pub fn add(mut self, plugin: impl Plugin + 'static) -> Self {
515 self.plugins.push(Box::new(plugin));
516 self
517 }
518}