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
28pub struct WindowConfig {
30 pub size: (f64, f64),
32 pub min_size: Option<(f64, f64)>,
34 pub max_size: Option<(f64, f64)>,
36 pub decorations: bool,
38 pub title: &'static str,
40 pub transparent: bool,
42 pub background: Color,
44 pub visible: bool,
46 pub icon: Option<Icon>,
48 pub on_setup: Option<WindowCallback>,
50 pub on_exit: Option<WindowCallback>,
52 pub window_attributes_hook: Option<WindowBuilderHook>,
54 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
78pub 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 pub fn with_size(mut self, width: f64, height: f64) -> Self {
123 self.window_config.size = (width, height);
124 self
125 }
126
127 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 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 pub fn with_decorations(mut self, decorations: bool) -> Self {
141 self.window_config.decorations = decorations;
142 self
143 }
144
145 pub fn with_title(mut self, title: &'static str) -> Self {
147 self.window_config.title = title;
148 self
149 }
150
151 pub fn with_transparency(mut self, transparency: bool) -> Self {
153 self.window_config.transparent = transparency;
154 self
155 }
156
157 pub fn with_state(mut self, state: T) -> Self {
159 self.state = Some(state);
160 self
161 }
162
163 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 pub fn with_visible(mut self, visible: bool) -> Self {
171 self.window_config.visible = visible;
172 self
173 }
174
175 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 pub fn without_default_fonts(mut self) -> Self {
183 self.default_fonts.clear();
184 self
185 }
186
187 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 pub fn with_icon(mut self, icon: Icon) -> Self {
195 self.window_config.icon = Some(icon);
196 self
197 }
198
199 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 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 pub fn with_plugin(mut self, plugin: impl FreyaPlugin + 'static) -> Self {
213 self.plugins.add_plugin(plugin);
214 self
215 }
216
217 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 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}