maycoon_core/app/
runner.rs

1use crate::app::context::AppContext;
2use crate::app::font_ctx::FontContext;
3use crate::app::handler::AppHandler;
4use crate::app::update::UpdateManager;
5use crate::config::MayConfig;
6use crate::plugin::PluginManager;
7use crate::vgi::VectorGraphicsInterface;
8use crate::widget::Widget;
9use maycoon_theme::theme::Theme;
10use peniko::FontData;
11use winit::dpi::{LogicalPosition, LogicalSize, Position, Size};
12use winit::event_loop::EventLoopBuilder;
13use winit::window::WindowAttributes;
14
15/// The core Application structure.
16pub struct MayRunner<T: Theme, V: VectorGraphicsInterface> {
17    config: MayConfig<T, V>,
18    font_ctx: FontContext,
19}
20
21impl<T: Theme, V: VectorGraphicsInterface> MayRunner<T, V> {
22    /// Create a new App with the given [MayConfig].
23    #[inline(always)]
24    #[tracing::instrument(level = "trace", skip_all)]
25    pub fn new(config: MayConfig<T, V>) -> Self {
26        Self {
27            config,
28            font_ctx: FontContext::default(),
29        }
30    }
31
32    /// Loads a new font into the font context.
33    ///
34    /// See [FontContext::load] for more.
35    #[inline(always)]
36    pub fn with_font(self, name: impl ToString, font: FontData) -> Self {
37        Self {
38            config: self.config,
39            font_ctx: self.font_ctx.load(name, font).expect("Font already loaded"),
40        }
41    }
42
43    /// Set the font context. Can be used to configure fonts.
44    #[inline(always)]
45    pub fn with_font_context(mut self, font_ctx: FontContext) -> Self {
46        self.font_ctx = font_ctx;
47        self
48    }
49
50    /// Run the application with given widget and state.
51    #[inline(always)]
52    #[tracing::instrument(level = "info", skip_all)]
53    pub fn run<S, W, F>(mut self, state: S, builder: F, mut plugins: PluginManager<T, V>)
54    where
55        W: Widget,
56        F: Fn(AppContext, S) -> W,
57    {
58        tracing::trace!("building event loop");
59        let mut event_loop = EventLoopBuilder::default()
60            .build()
61            .expect("Failed to create event loop");
62
63        let mut attrs = WindowAttributes::default()
64            .with_inner_size(LogicalSize::new(
65                self.config.window.size.x,
66                self.config.window.size.y,
67            ))
68            .with_resizable(self.config.window.resizable)
69            .with_enabled_buttons(self.config.window.buttons)
70            .with_title(self.config.window.title.clone())
71            .with_maximized(self.config.window.maximized)
72            .with_visible(self.config.window.visible)
73            .with_transparent(self.config.window.transparent)
74            .with_blur(self.config.window.blur)
75            .with_decorations(self.config.window.decorations)
76            .with_window_icon(self.config.window.icon.clone())
77            .with_content_protected(self.config.window.content_protected)
78            .with_window_level(self.config.window.level)
79            .with_active(self.config.window.active)
80            .with_cursor(self.config.window.cursor.clone());
81
82        // since `with_max_inner_size()` doesn't support `Option` values, we need to manually set it
83        attrs.max_inner_size = self
84            .config
85            .window
86            .max_size
87            .map(|v| Size::Logical(LogicalSize::new(v.x, v.y)));
88
89        // since `with_min_inner_size()` doesn't support `Option` values, we need to manually set it
90        attrs.min_inner_size = self
91            .config
92            .window
93            .min_size
94            .map(|v| Size::Logical(LogicalSize::new(v.x, v.y)));
95
96        // since `with_position()` doesn't support `Option` values, we need to manually set it
97        attrs.position = self
98            .config
99            .window
100            .position
101            .map(|v| Position::Logical(LogicalPosition::new(v.x, v.y)));
102
103        // since `with_resize_increments()` doesn't support `Option` values, we need to manually set it
104        attrs.resize_increments = self
105            .config
106            .window
107            .resize_increments
108            .map(|v| Size::Logical(LogicalSize::new(v.x, v.y)));
109
110        tracing::trace!("creating update manager");
111        let update = UpdateManager::new();
112
113        tracing::trace!("initializing plugins");
114        plugins.run(|pl| pl.init(&mut event_loop, &update, &mut attrs, &mut self.config));
115
116        tracing::info!("running application handler");
117        event_loop
118            .run_app(&mut AppHandler::new(
119                attrs,
120                self.config,
121                builder,
122                state,
123                self.font_ctx,
124                update,
125                plugins,
126            ))
127            .expect("Failed to run event loop");
128    }
129}