maycoon_core/
plugin.rs

1use crate::app::info::AppInfo;
2use crate::app::update::UpdateManager;
3use crate::config::MayConfig;
4use indexmap::IndexMap;
5use maycoon_theme::theme::Theme;
6use std::sync::Arc;
7use std::time::Instant;
8use taffy::{NodeId, TaffyTree};
9use vello::util::{RenderContext, RenderSurface};
10use vello::{Renderer, Scene};
11use winit::event::WindowEvent;
12use winit::event_loop::{ActiveEventLoop, EventLoop};
13use winit::window::{Window, WindowAttributes};
14
15/// A plugin interface for maycoon applications.
16///
17/// Plugins are used to extend functionality and manipulate the inner state of applications.
18/// Beware that tampering with the application state may cause crashes or other issues if not done correctly.
19///
20/// All functions defined in this trait get called before the app handler logic and therefore can control the application flow.
21pub trait Plugin<T: Theme> {
22    /// The plugin name.
23    ///
24    /// Should be unique among the ecosystem.
25    fn name(&self) -> &'static str;
26
27    /// Called when the plugin is registered using [PluginManager::register].
28    fn on_register(&mut self, _manager: &mut PluginManager<T>) {}
29
30    /// Called when the plugin is unregistered using [PluginManager::unregister].
31    fn on_unregister(&mut self, _manager: &mut PluginManager<T>) {}
32
33    /// Called right before initializing the [AppHandler](crate::app::handler::AppHandler) and running the event loop.
34    fn init(
35        &mut self,
36        _event_loop: &mut EventLoop<()>,
37        _update: &UpdateManager,
38        _window: &mut WindowAttributes,
39        _config: &mut MayConfig<T>,
40    ) {
41    }
42
43    /// Called when the application is resumed after being suspended or when it's first started.
44    ///
45    /// Desktop applications typically don't get suspended and this function is only called once,
46    /// while mobile apps can be suspended and resumed.
47    fn on_resume(
48        &mut self,
49        _config: &mut MayConfig<T>,
50        _scene: &mut Scene,
51        _taffy: &mut TaffyTree,
52        _window_node: NodeId,
53        _info: &mut AppInfo,
54        _update: &UpdateManager,
55        _last_update: &mut Instant,
56        _event_loop: &ActiveEventLoop,
57    ) {
58    }
59
60    /// Called right before the application handler tries to update the application
61    /// and figure out what updates to apply.
62    fn on_update(
63        &mut self,
64        _config: &mut MayConfig<T>,
65        _window: &Arc<Window>,
66        _renderer: &mut Renderer,
67        _scene: &mut Scene,
68        _surface: &mut RenderSurface<'_>,
69        _taffy: &mut TaffyTree,
70        _window_node: NodeId,
71        _info: &mut AppInfo,
72        _render_ctx: &mut RenderContext,
73        _update: &UpdateManager,
74        _last_update: &mut Instant,
75        _event_loop: &ActiveEventLoop,
76    ) {
77    }
78
79    /// Called when a window event is received.
80    fn on_window_event(
81        &mut self,
82        _event: &mut WindowEvent,
83        _config: &mut MayConfig<T>,
84        _window: &Arc<Window>,
85        _renderer: &mut Renderer,
86        _scene: &mut Scene,
87        _surface: &mut RenderSurface<'_>,
88        _taffy: &mut TaffyTree,
89        _window_node: NodeId,
90        _info: &mut AppInfo,
91        _render_ctx: &mut RenderContext,
92        _update: &UpdateManager,
93        _last_update: &mut Instant,
94        _event_loop: &ActiveEventLoop,
95    ) {
96    }
97
98    /// Called when the application is suspended.
99    fn on_suspended(
100        &mut self,
101        _config: &mut MayConfig<T>,
102        _scene: &mut Scene,
103        _taffy: &mut TaffyTree,
104        _window_node: NodeId,
105        _info: &mut AppInfo,
106        _update: &UpdateManager,
107        _last_update: &mut Instant,
108        _event_loop: &ActiveEventLoop,
109    ) {
110    }
111}
112
113/// A plugin manager for maycoon applications.
114pub struct PluginManager<T: Theme> {
115    plugins: IndexMap<&'static str, Box<dyn Plugin<T>>>,
116}
117
118impl<T: Theme> PluginManager<T> {
119    /// Creates a new empty plugin manager.
120    pub fn new() -> Self {
121        Self {
122            plugins: IndexMap::new(),
123        }
124    }
125
126    /// Registers a new plugin.
127    pub fn register(&mut self, mut plugin: impl Plugin<T> + 'static) {
128        plugin.on_register(self);
129
130        self.plugins.insert(plugin.name(), Box::new(plugin));
131    }
132
133    /// Unregisters a plugin.
134    pub fn unregister(&mut self, name: &'static str) {
135        let mut pl = self.plugins.swap_remove(name).expect("Plugin not found");
136
137        pl.on_unregister(self);
138    }
139
140    /// Unregisters all plugins.
141    pub fn clear(&mut self) {
142        let plugins = self.plugins.keys().cloned().collect::<Vec<_>>();
143
144        for name in plugins {
145            self.unregister(name);
146        }
147    }
148
149    /// Runs a closure on all plugins.
150    pub fn run<F>(&mut self, mut op: F)
151    where
152        F: FnMut(&mut Box<dyn Plugin<T>>),
153    {
154        for pl in self.plugins.values_mut() {
155            op(pl);
156        }
157    }
158}
159
160impl<T: Theme> Default for PluginManager<T> {
161    fn default() -> Self {
162        Self::new()
163    }
164}