Skip to main content

freya_winit/
plugins.rs

1use std::{
2    cell::RefCell,
3    collections::HashMap,
4    rc::Rc,
5};
6
7use freya_core::integration::*;
8use freya_engine::prelude::{
9    Canvas,
10    FontCollection,
11};
12pub use keyboard_types::{
13    Code,
14    Key,
15    Modifiers,
16};
17use winit::{
18    event_loop::EventLoopProxy,
19    window::{
20        Window,
21        WindowId,
22    },
23};
24
25use crate::renderer::{
26    NativeEvent,
27    NativeWindowEvent,
28    NativeWindowEventAction,
29};
30
31#[derive(Clone)]
32pub struct PluginHandle {
33    pub proxy: EventLoopProxy<NativeEvent>,
34}
35
36impl PluginHandle {
37    pub fn new(proxy: &EventLoopProxy<NativeEvent>) -> Self {
38        Self {
39            proxy: proxy.clone(),
40        }
41    }
42
43    /// Emit a [PlatformEvent]. Useful to simulate certain events.
44    pub fn send_platform_event(&self, event: PlatformEvent, window_id: WindowId) {
45        self.proxy
46            .send_event(NativeEvent::Window(NativeWindowEvent {
47                window_id,
48                action: NativeWindowEventAction::PlatformEvent(event),
49            }))
50            .ok();
51    }
52
53    /// Emit a [NativeEvent].
54    pub fn send_event_loop_event(&self, event: NativeEvent) {
55        self.proxy.send_event(event).ok();
56    }
57}
58
59/// Manages all loaded plugins.
60#[derive(Default, Clone)]
61pub struct PluginsManager {
62    plugins: Rc<RefCell<HashMap<&'static str, Box<dyn FreyaPlugin>>>>,
63}
64
65impl PluginsManager {
66    /// Add a plugin by its ID. First insert wins.
67    pub fn add_plugin(&mut self, plugin: impl FreyaPlugin + 'static) {
68        self.plugins
69            .borrow_mut()
70            .entry(plugin.plugin_id())
71            .or_insert(Box::new(plugin));
72    }
73
74    pub fn send(&mut self, mut event: PluginEvent, handle: PluginHandle) {
75        for plugin in self.plugins.borrow_mut().values_mut() {
76            plugin.on_event(&mut event, handle.clone())
77        }
78    }
79
80    /// Compose the root element through all plugins' root components.
81    pub fn wrap_root(&self, mut root: Element) -> Element {
82        for plugin in self.plugins.borrow().values() {
83            root = plugin.root_component(root);
84        }
85        root
86    }
87}
88
89/// Event emitted to Plugins.
90pub enum PluginEvent<'a> {
91    /// A runner just got created.
92    RunnerCreated {
93        runner: &'a mut Runner,
94    },
95    /// A Window just got created.
96    WindowCreated {
97        window: &'a Window,
98        font_collection: &'a FontCollection,
99        tree: &'a Tree,
100        animation_clock: &'a AnimationClock,
101        runner: &'a mut Runner,
102        graphics_driver: &'static str,
103    },
104
105    /// The graphics driver was rebuilt at runtime.
106    GraphicsDriverChanged {
107        window: &'a Window,
108        graphics_driver: &'static str,
109    },
110
111    /// A Window just got closed.
112    WindowClosed {
113        window: &'a Window,
114        tree: &'a Tree,
115    },
116
117    /// After having rendered, presented and everything else.
118    AfterRedraw {
119        window: &'a Window,
120        font_collection: &'a FontCollection,
121        tree: &'a Tree,
122    },
123
124    /// Before presenting the canvas to the window.
125    BeforePresenting {
126        window: &'a Window,
127        font_collection: &'a FontCollection,
128        tree: &'a Tree,
129    },
130
131    /// After presenting the canvas to the window.
132    AfterPresenting {
133        window: &'a Window,
134        font_collection: &'a FontCollection,
135        tree: &'a Tree,
136    },
137
138    /// Before starting to render the app to the Canvas.
139    BeforeRender {
140        window: &'a Window,
141        canvas: &'a Canvas,
142        font_collection: &'a FontCollection,
143        tree: &'a Tree,
144    },
145
146    /// After rendering the app to the Canvas.
147    AfterRender {
148        window: &'a Window,
149        canvas: &'a Canvas,
150        font_collection: &'a FontCollection,
151        tree: &'a Tree,
152        animation_clock: &'a AnimationClock,
153    },
154
155    /// Before starting to measure the layout.
156    StartedMeasuringLayout {
157        window: &'a Window,
158        tree: &'a Tree,
159    },
160
161    /// After measuringg the layout.
162    FinishedMeasuringLayout {
163        window: &'a Window,
164        tree: &'a Tree,
165    },
166
167    /// Before starting to process the queued events.
168    StartedMeasuringEvents {
169        window: &'a Window,
170        tree: &'a Tree,
171    },
172
173    /// After processing the queued events.
174    FinishedMeasuringEvents {
175        window: &'a Window,
176        tree: &'a Tree,
177    },
178
179    StartedUpdatingTree {
180        window: &'a Window,
181        tree: &'a Tree,
182    },
183
184    FinishedUpdatingTree {
185        window: &'a Window,
186        tree: &'a Tree,
187    },
188
189    BeforeAccessibility {
190        window: &'a Window,
191        font_collection: &'a FontCollection,
192        tree: &'a Tree,
193    },
194
195    AfterAccessibility {
196        window: &'a Window,
197        font_collection: &'a FontCollection,
198        tree: &'a Tree,
199    },
200
201    /// A keyboard input was received.
202    KeyboardInput {
203        window: &'a Window,
204        key: Key,
205        code: Code,
206        modifiers: Modifiers,
207        is_pressed: bool,
208    },
209}
210
211/// Skeleton for Freya plugins.
212pub trait FreyaPlugin {
213    /// Unique identifier for this plugin. Used for deduplication.
214    fn plugin_id(&self) -> &'static str;
215
216    /// React on events emitted by Freya.
217    fn on_event(&mut self, event: &mut PluginEvent, handle: PluginHandle);
218
219    /// Wrap the root element with a custom component.
220    /// Called during window creation. The default implementation returns the element unchanged.
221    fn root_component(&self, root: Element) -> Element {
222        root
223    }
224}