maycoon_core/app/
mod.rs

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