Skip to main content

ferrum_flow/
plugin.rs

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 take_interaction(&mut self) -> Option<Box<dyn InteractionHandler + 'static>> {
186    //     self.interaction.handler.take()
187    // }
188
189    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
387// TODO
388// pub trait Command {
389//     fn execute(&mut self, graph: &mut Graph);
390//     fn undo(&mut self, graph: &mut Graph);
391// }
392
393// pub struct CommandQueue {
394//     undo_stack: Vec<Box<dyn Command>>,
395//     redo_stack: Vec<Box<dyn Command>>,
396// }
397
398pub 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}