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    /// A Window just got closed.
106    WindowClosed {
107        window: &'a Window,
108        tree: &'a Tree,
109    },
110
111    /// After having rendered, presented and everything else.
112    AfterRedraw {
113        window: &'a Window,
114        font_collection: &'a FontCollection,
115        tree: &'a Tree,
116    },
117
118    /// Before presenting the canvas to the window.
119    BeforePresenting {
120        window: &'a Window,
121        font_collection: &'a FontCollection,
122        tree: &'a Tree,
123    },
124
125    /// After presenting the canvas to the window.
126    AfterPresenting {
127        window: &'a Window,
128        font_collection: &'a FontCollection,
129        tree: &'a Tree,
130    },
131
132    /// Before starting to render the app to the Canvas.
133    BeforeRender {
134        window: &'a Window,
135        canvas: &'a Canvas,
136        font_collection: &'a FontCollection,
137        tree: &'a Tree,
138    },
139
140    /// After rendering the app to the Canvas.
141    AfterRender {
142        window: &'a Window,
143        canvas: &'a Canvas,
144        font_collection: &'a FontCollection,
145        tree: &'a Tree,
146        animation_clock: &'a AnimationClock,
147    },
148
149    /// Before starting to measure the layout.
150    StartedMeasuringLayout {
151        window: &'a Window,
152        tree: &'a Tree,
153    },
154
155    /// After measuringg the layout.
156    FinishedMeasuringLayout {
157        window: &'a Window,
158        tree: &'a Tree,
159    },
160
161    /// Before starting to process the queued events.
162    StartedMeasuringEvents {
163        window: &'a Window,
164        tree: &'a Tree,
165    },
166
167    /// After processing the queued events.
168    FinishedMeasuringEvents {
169        window: &'a Window,
170        tree: &'a Tree,
171    },
172
173    StartedUpdatingTree {
174        window: &'a Window,
175        tree: &'a Tree,
176    },
177
178    FinishedUpdatingTree {
179        window: &'a Window,
180        tree: &'a Tree,
181    },
182
183    BeforeAccessibility {
184        window: &'a Window,
185        font_collection: &'a FontCollection,
186        tree: &'a Tree,
187    },
188
189    AfterAccessibility {
190        window: &'a Window,
191        font_collection: &'a FontCollection,
192        tree: &'a Tree,
193    },
194
195    /// A keyboard input was received.
196    KeyboardInput {
197        window: &'a Window,
198        key: Key,
199        code: Code,
200        modifiers: Modifiers,
201        is_pressed: bool,
202    },
203}
204
205/// Skeleton for Freya plugins.
206pub trait FreyaPlugin {
207    /// Unique identifier for this plugin. Used for deduplication.
208    fn plugin_id(&self) -> &'static str;
209
210    /// React on events emitted by Freya.
211    fn on_event(&mut self, event: &mut PluginEvent, handle: PluginHandle);
212
213    /// Wrap the root element with a custom component.
214    /// Called during window creation. The default implementation returns the element unchanged.
215    fn root_component(&self, root: Element) -> Element {
216        root
217    }
218}