Skip to main content

ferrum_flow/
canvas.rs

1use gpui::*;
2
3use crate::{
4    graph::Graph,
5    plugin::{
6        EventResult, FlowEvent, InitPluginContext, InputEvent, Plugin, PluginContext,
7        PluginRegistry, RenderContext, RenderLayer,
8    },
9    viewport::Viewport,
10};
11
12mod types;
13mod undo;
14
15pub use undo::{CanvasState, Command, CompositeCommand, History};
16
17pub use types::{Interaction, InteractionResult, InteractionState};
18
19pub struct FlowCanvas {
20    pub graph: Graph,
21
22    pub(crate) viewport: Viewport,
23
24    pub(crate) plugins_registry: PluginRegistry,
25
26    pub(crate) focus_handle: FocusHandle,
27
28    pub(crate) interaction: InteractionState,
29
30    pub history: History,
31
32    pub event_queue: Vec<FlowEvent>,
33}
34
35// // TODO
36// impl Clone for FlowCanvas {
37//     fn clone(&self) -> Self {
38//         Self {
39//             graph: self.graph.clone(),
40//             viewport: self.viewport.clone(),
41//             plugins_registry: PluginRegistry::new(),
42//             focus_handle: self.focus_handle.clone(),
43//             interaction: InteractionState::new(),
44//             event_queue: vec![],
45//         }
46//     }
47// }
48
49impl FlowCanvas {
50    pub fn new(graph: Graph, cx: &mut Context<Self>) -> Self {
51        let focus_handle = cx.focus_handle();
52        Self {
53            graph,
54            viewport: Viewport::new(),
55            plugins_registry: PluginRegistry::new(),
56            focus_handle,
57            interaction: InteractionState::new(),
58            history: History::new(),
59            event_queue: vec![],
60        }
61    }
62
63    pub fn plugin(mut self, plugin: impl Plugin + 'static) -> Self {
64        self.plugins_registry = self.plugins_registry.add(plugin);
65        self
66    }
67
68    pub fn init_plugins(&mut self) {
69        let mut ctx = InitPluginContext {
70            graph: &mut self.graph,
71            viewport: &mut self.viewport,
72        };
73
74        self.plugins_registry.plugins.sort_by_key(|p| -p.priority());
75
76        for plugin in &mut self.plugins_registry.plugins.iter_mut() {
77            plugin.setup(&mut ctx);
78        }
79    }
80
81    pub fn handle_event(&mut self, event: FlowEvent, cx: &mut Context<Self>) {
82        let event_queue = &mut self.event_queue;
83
84        let mut emit = |event: FlowEvent| {
85            event_queue.push(event);
86        };
87
88        let mut notify = || {
89            cx.notify();
90        };
91
92        // if has interaction
93        if let Some(mut handler) = self.interaction.handler.take() {
94            let mut ctx = PluginContext::new(
95                &mut self.graph,
96                &mut self.viewport,
97                &mut self.interaction,
98                &mut self.history,
99                &mut emit,
100                &mut notify,
101            );
102            let mut fast_return = false;
103            let result = match &event {
104                FlowEvent::Input(InputEvent::MouseMove(ev)) => {
105                    fast_return = true;
106                    handler.on_mouse_move(ev, &mut ctx)
107                }
108
109                FlowEvent::Input(InputEvent::MouseUp(ev)) => {
110                    fast_return = true;
111                    handler.on_mouse_up(ev, &mut ctx)
112                }
113
114                _ => InteractionResult::Continue,
115            };
116
117            if fast_return {
118                match result {
119                    InteractionResult::Continue => self.interaction.handler = Some(handler),
120
121                    InteractionResult::End => {
122                        self.interaction.handler = None;
123                    }
124
125                    InteractionResult::Replace(h) => {
126                        self.interaction.handler = Some(h);
127                    }
128                }
129                return;
130            }
131        }
132
133        let mut ctx = PluginContext::new(
134            &mut self.graph,
135            &mut self.viewport,
136            &mut self.interaction,
137            &mut self.history,
138            &mut emit,
139            &mut notify,
140        );
141
142        // 否则广播给 plugins
143        for plugin in &mut self.plugins_registry.plugins {
144            let result = plugin.on_event(&event, &mut ctx);
145            match result {
146                EventResult::Continue => {}
147                EventResult::Stop => break,
148            }
149        }
150    }
151
152    fn process_event_queue(&mut self, cx: &mut Context<Self>) {
153        while let Some(event) = self.event_queue.pop() {
154            let mut emit = |e| self.event_queue.push(e);
155
156            let mut notify = || {
157                cx.notify();
158            };
159
160            let mut ctx = PluginContext::new(
161                &mut self.graph,
162                &mut self.viewport,
163                &mut self.interaction,
164                &mut self.history,
165                &mut emit,
166                &mut notify,
167            );
168
169            for plugin in &mut self.plugins_registry.plugins {
170                let result = plugin.on_event(&event, &mut ctx);
171                match result {
172                    EventResult::Continue => {}
173                    EventResult::Stop => break,
174                }
175            }
176        }
177    }
178
179    fn on_key_down(&mut self, ev: &KeyDownEvent, _: &mut Window, cx: &mut Context<Self>) {
180        self.handle_event(FlowEvent::Input(InputEvent::KeyDown(ev.clone())), cx);
181        self.process_event_queue(cx);
182    }
183
184    fn on_key_up(&mut self, ev: &KeyUpEvent, _: &mut Window, cx: &mut Context<Self>) {
185        self.handle_event(FlowEvent::Input(InputEvent::KeyUp(ev.clone())), cx);
186        self.process_event_queue(cx);
187    }
188
189    fn on_mouse_down(&mut self, ev: &MouseDownEvent, _: &mut Window, cx: &mut Context<Self>) {
190        self.handle_event(FlowEvent::Input(InputEvent::MouseDown(ev.clone())), cx);
191        self.process_event_queue(cx);
192    }
193
194    fn on_mouse_move(&mut self, ev: &MouseMoveEvent, _: &mut Window, cx: &mut Context<Self>) {
195        self.handle_event(FlowEvent::Input(InputEvent::MouseMove(ev.clone())), cx);
196        self.process_event_queue(cx);
197    }
198
199    fn on_mouse_up(&mut self, ev: &MouseUpEvent, _: &mut Window, cx: &mut Context<Self>) {
200        self.handle_event(FlowEvent::Input(InputEvent::MouseUp(ev.clone())), cx);
201        self.process_event_queue(cx);
202    }
203
204    fn on_scroll_wheel(&mut self, ev: &ScrollWheelEvent, _: &mut Window, cx: &mut Context<Self>) {
205        self.handle_event(FlowEvent::Input(InputEvent::Wheel(ev.clone())), cx);
206        self.process_event_queue(cx);
207    }
208}
209
210impl Render for FlowCanvas {
211    fn render(&mut self, window: &mut Window, this_cx: &mut Context<Self>) -> impl IntoElement {
212        // only run once
213        if self.viewport.window_bounds.is_none() {
214            self.viewport.window_bounds = Some(window.bounds());
215        }
216
217        let entity = this_cx.entity();
218
219        let graph = &self.graph;
220        let viewport = &self.viewport;
221
222        let mut layers: Vec<Vec<AnyElement>> =
223            (0..RenderLayer::ALL.len()).map(|_| Vec::new()).collect();
224
225        for plugin in self.plugins_registry.plugins.iter_mut() {
226            let layer = plugin.render_layer();
227
228            let mut ctx = RenderContext::new(graph, viewport, window, layer);
229
230            if let Some(el) = plugin.render(&mut ctx) {
231                layers[layer.index()].push(el);
232            }
233        }
234
235        if let Some(i) = self.interaction.handler.as_ref() {
236            let mut ctx = RenderContext::new(graph, viewport, window, RenderLayer::Interaction);
237
238            if let Some(el) = i.render(&mut ctx) {
239                layers[RenderLayer::Interaction.index()].push(el);
240            }
241        }
242
243        div()
244            .size_full()
245            .track_focus(&self.focus_handle)
246            .on_key_down(window.listener_for(&entity, Self::on_key_down))
247            .on_key_up(window.listener_for(&entity, Self::on_key_up))
248            .on_mouse_down(
249                MouseButton::Left,
250                window.listener_for(&entity, Self::on_mouse_down),
251            )
252            .on_mouse_move(window.listener_for(&entity, Self::on_mouse_move))
253            .on_mouse_up(
254                MouseButton::Left,
255                window.listener_for(&entity, Self::on_mouse_up),
256            )
257            .on_scroll_wheel(window.listener_for(&entity, Self::on_scroll_wheel))
258            .children(
259                RenderLayer::ALL
260                    .iter()
261                    .map(|layer| div().absolute().children(layers[layer.index()].drain(..))),
262            )
263    }
264}