freya_winit/
config.rs

1use std::io::Cursor;
2
3use freya_core::{
4    event_loop_messages::EventLoopMessage,
5    parsing::Parse,
6    plugins::{
7        FreyaPlugin,
8        PluginsManager,
9    },
10    style::default_fonts,
11};
12use freya_engine::prelude::Color;
13use image::ImageReader;
14use winit::{
15    event_loop::EventLoopBuilder,
16    window::{
17        Icon,
18        Window,
19        WindowAttributes,
20    },
21};
22
23pub type WindowCallback = Box<dyn FnOnce(&mut Window)>;
24pub type EventLoopBuilderHook = Box<dyn FnOnce(&mut EventLoopBuilder<EventLoopMessage>)>;
25pub type WindowBuilderHook = Box<dyn FnOnce(WindowAttributes) -> WindowAttributes>;
26pub type EmbeddedFonts<'a> = Vec<(&'a str, &'a [u8])>;
27
28/// Configuration for a Window.
29pub struct WindowConfig {
30    /// Size of the Window.
31    pub size: (f64, f64),
32    /// Minimum size of the Window.
33    pub min_size: Option<(f64, f64)>,
34    /// Maximum size of the Window.
35    pub max_size: Option<(f64, f64)>,
36    /// Enable Window decorations.
37    pub decorations: bool,
38    /// Title for the Window.
39    pub title: &'static str,
40    /// Make the Window transparent or not.
41    pub transparent: bool,
42    /// Background color of the Window.
43    pub background: Color,
44    /// Window visibility. Default to `true`.
45    pub visible: bool,
46    /// The Icon of the Window.
47    pub icon: Option<Icon>,
48    /// Setup callback.
49    pub on_setup: Option<WindowCallback>,
50    /// Exit callback.
51    pub on_exit: Option<WindowCallback>,
52    /// Hook function called with the Window Attributes.
53    pub window_attributes_hook: Option<WindowBuilderHook>,
54    /// Hook function called with the Event Loop Builder.
55    pub event_loop_builder_hook: Option<EventLoopBuilderHook>,
56}
57
58impl Default for WindowConfig {
59    fn default() -> Self {
60        Self {
61            size: (700.0, 500.0),
62            min_size: None,
63            max_size: None,
64            decorations: true,
65            title: "Freya App",
66            transparent: false,
67            background: Color::WHITE,
68            visible: true,
69            icon: None,
70            on_setup: None,
71            on_exit: None,
72            window_attributes_hook: None,
73            event_loop_builder_hook: None,
74        }
75    }
76}
77
78/// Launch configuration.
79pub struct LaunchConfig<'a, T: Clone = ()> {
80    pub state: Option<T>,
81    pub window_config: WindowConfig,
82    pub embedded_fonts: EmbeddedFonts<'a>,
83    pub plugins: PluginsManager,
84    pub default_fonts: Vec<String>,
85}
86
87impl<T: Clone> Default for LaunchConfig<'_, T> {
88    fn default() -> Self {
89        Self {
90            state: None,
91            window_config: Default::default(),
92            embedded_fonts: Default::default(),
93            plugins: Default::default(),
94            default_fonts: default_fonts(),
95        }
96    }
97}
98
99impl<'a, T: Clone> LaunchConfig<'a, T> {
100    pub fn new() -> LaunchConfig<'a, T> {
101        LaunchConfig::default()
102    }
103}
104
105impl LaunchConfig<'_, ()> {
106    pub fn load_icon(icon: &[u8]) -> Icon {
107        let reader = ImageReader::new(Cursor::new(icon))
108            .with_guessed_format()
109            .expect("Cursor io never fails");
110        let image = reader
111            .decode()
112            .expect("Failed to open icon path")
113            .into_rgba8();
114        let (width, height) = image.dimensions();
115        let rgba = image.into_raw();
116        Icon::from_rgba(rgba, width, height).expect("Failed to open icon")
117    }
118}
119
120impl<'a, T: Clone> LaunchConfig<'a, T> {
121    /// Specify a Window size.
122    pub fn with_size(mut self, width: f64, height: f64) -> Self {
123        self.window_config.size = (width, height);
124        self
125    }
126
127    /// Specify a minimum Window size.
128    pub fn with_min_size(mut self, min_width: f64, min_height: f64) -> Self {
129        self.window_config.min_size = Some((min_width, min_height));
130        self
131    }
132
133    /// Specify a maximum Window size.
134    pub fn with_max_size(mut self, max_width: f64, max_height: f64) -> Self {
135        self.window_config.max_size = Some((max_width, max_height));
136        self
137    }
138
139    /// Whether the Window will have decorations or not.
140    pub fn with_decorations(mut self, decorations: bool) -> Self {
141        self.window_config.decorations = decorations;
142        self
143    }
144
145    /// Specify the Window title.
146    pub fn with_title(mut self, title: &'static str) -> Self {
147        self.window_config.title = title;
148        self
149    }
150
151    /// Make the Window transparent or not.
152    pub fn with_transparency(mut self, transparency: bool) -> Self {
153        self.window_config.transparent = transparency;
154        self
155    }
156
157    /// Pass a custom value that your app will consume.
158    pub fn with_state(mut self, state: T) -> Self {
159        self.state = Some(state);
160        self
161    }
162
163    /// Specify the Window background color.
164    pub fn with_background(mut self, background: &str) -> Self {
165        self.window_config.background = Color::parse(background).unwrap_or(Color::WHITE);
166        self
167    }
168
169    /// Specify the Window visibility at launch.
170    pub fn with_visible(mut self, visible: bool) -> Self {
171        self.window_config.visible = visible;
172        self
173    }
174
175    /// Embed a font.
176    pub fn with_font(mut self, font_name: &'a str, font: &'a [u8]) -> Self {
177        self.embedded_fonts.push((font_name, font));
178        self
179    }
180
181    /// Clear default fonts.
182    pub fn without_default_fonts(mut self) -> Self {
183        self.default_fonts.clear();
184        self
185    }
186
187    /// Regiter a default font.
188    pub fn with_default_font(mut self, font_name: &str) -> Self {
189        self.default_fonts.push(font_name.to_string());
190        self
191    }
192
193    /// Specify the Window icon.
194    pub fn with_icon(mut self, icon: Icon) -> Self {
195        self.window_config.icon = Some(icon);
196        self
197    }
198
199    /// Register a callback that will be executed when the window is created.
200    pub fn on_setup(mut self, callback: impl FnOnce(&mut Window) + 'static) -> Self {
201        self.window_config.on_setup = Some(Box::new(callback));
202        self
203    }
204
205    /// Register a callback that will be executed when the window is closed.
206    pub fn on_exit(mut self, callback: impl FnOnce(&mut Window) + 'static) -> Self {
207        self.window_config.on_exit = Some(Box::new(callback));
208        self
209    }
210
211    /// Add a new plugin.
212    pub fn with_plugin(mut self, plugin: impl FreyaPlugin + 'static) -> Self {
213        self.plugins.add_plugin(plugin);
214        self
215    }
216
217    /// Register a Window Attributes hook.
218    pub fn with_window_attributes(
219        mut self,
220        window_attributes_hook: impl FnOnce(WindowAttributes) -> WindowAttributes + 'static,
221    ) -> Self {
222        self.window_config.window_attributes_hook = Some(Box::new(window_attributes_hook));
223        self
224    }
225
226    /// Register an Event Loop Builder hook.
227    pub fn with_event_loop_builder(
228        mut self,
229        event_loop_builder_hook: impl FnOnce(&mut EventLoopBuilder<EventLoopMessage>) + 'static,
230    ) -> Self {
231        self.window_config.event_loop_builder_hook = Some(Box::new(event_loop_builder_hook));
232        self
233    }
234}