1use std::sync::Arc;
2use std::time::{Duration, Instant};
3
4use nalgebra::Vector2;
5use taffy::{
6 AvailableSpace, Dimension, NodeId, PrintTree, Size, Style, TaffyResult, TaffyTree,
7 TraversePartialTree,
8};
9use vello::util::{RenderContext, RenderSurface};
10use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
11use winit::application::ApplicationHandler;
12use winit::event::WindowEvent;
13use winit::event_loop::ActiveEventLoop;
14use winit::window::{Window, WindowAttributes, WindowId};
15
16use crate::app::context::AppContext;
17use crate::app::font_ctx::FontContext;
18use crate::app::info::AppInfo;
19use crate::app::update::{Update, UpdateManager};
20use crate::config::MayConfig;
21use crate::layout::{LayoutNode, StyleNode};
22use crate::plugin::PluginManager;
23use crate::widget::Widget;
24use maycoon_theme::theme::Theme;
25
26pub struct AppHandler<'a, T, W>
28where
29 T: Theme,
30 W: Widget,
31{
32 config: MayConfig<T>,
33 attrs: WindowAttributes,
34 window: Option<Arc<Window>>,
35 renderer: Option<Renderer>,
36 scene: Scene,
37 surface: Option<RenderSurface<'a>>,
38 taffy: TaffyTree,
39 window_node: NodeId,
40 widget: W,
41 info: AppInfo,
42 render_ctx: Option<RenderContext>,
43 update: UpdateManager,
44 last_update: Instant,
45 plugins: PluginManager<T>,
46}
47
48impl<T, W> AppHandler<'_, T, W>
49where
50 T: Theme,
51 W: Widget,
52{
53 pub fn new(
55 attrs: WindowAttributes,
56 config: MayConfig<T>,
57 widget: W,
58 font_context: FontContext,
59 update: UpdateManager,
60 plugins: PluginManager<T>,
61 ) -> Self {
62 let mut taffy = TaffyTree::with_capacity(16);
63
64 let window_node = taffy
66 .new_leaf(Style::default())
67 .expect("Failed to create window node");
68
69 let size = config.window.size;
70
71 Self {
72 attrs,
73 window: None,
74 renderer: None,
75 config,
76 scene: Scene::new(),
77 surface: None,
78 taffy,
79 widget,
80 info: AppInfo {
81 font_context,
82 size,
83 ..Default::default()
84 },
85 window_node,
86 render_ctx: None,
87 update,
88 last_update: Instant::now(),
89 plugins,
90 }
91 }
92
93 pub fn context(&self) -> AppContext {
95 AppContext::new(self.update.clone())
96 }
97
98 fn layout_widget(&mut self, parent: NodeId, style: &StyleNode) -> TaffyResult<()> {
100 log::debug!("Laying out widget: {:?}", parent);
101
102 let node = self.taffy.new_leaf(style.style.clone().into())?;
103
104 self.taffy.add_child(parent, node)?;
105
106 for child in &style.children {
107 self.layout_widget(node, child)?;
108 }
109
110 Ok(())
111 }
112
113 fn compute_layout(&mut self) -> TaffyResult<()> {
115 log::debug!("Computing root layout.");
116
117 self.taffy.compute_layout(
118 self.window_node,
119 Size::<AvailableSpace> {
120 width: AvailableSpace::Definite(
121 self.window.as_ref().unwrap().inner_size().width as f32,
122 ),
123 height: AvailableSpace::Definite(
124 self.window.as_ref().unwrap().inner_size().height as f32,
125 ),
126 },
127 )?;
128 Ok(())
129 }
130
131 fn collect_layout(&mut self, node: NodeId, style: &StyleNode) -> TaffyResult<LayoutNode> {
133 log::debug!("Collecting layout for node: {:?}", node);
134
135 let mut children = Vec::with_capacity(style.children.capacity());
136
137 for (i, child) in style.children.iter().enumerate() {
138 children.push(self.collect_layout(self.taffy.child_at_index(node, i)?, child)?);
139 }
140
141 Ok(LayoutNode {
142 layout: *self.taffy.get_final_layout(node),
143 children,
144 })
145 }
146
147 fn request_redraw(&self) {
149 log::debug!("Requesting redraw...");
150
151 if let Some(window) = self.window.as_ref() {
152 window.request_redraw();
153 }
154 }
155
156 fn update(&mut self, event_loop: &ActiveEventLoop) {
158 self.plugins.run(|pl| {
160 pl.on_update(
161 &mut self.config,
162 self.window.as_ref().expect("Window not initialized"),
163 self.renderer.as_mut().expect("Renderer not initialized"),
164 &mut self.scene,
165 self.surface.as_mut().expect("Surface not initialized"),
166 &mut self.taffy,
167 self.window_node,
168 &mut self.info,
169 self.render_ctx
170 .as_mut()
171 .expect("Render context not initialized"),
172 &self.update,
173 &mut self.last_update,
174 event_loop,
175 )
176 });
177
178 if self.taffy.child_count(self.window_node) == 0 {
180 log::debug!("Setting up layout...");
181
182 let style = self.widget.layout_style();
183
184 self.layout_widget(self.window_node, &style)
185 .expect("Failed to layout window");
186
187 self.compute_layout().expect("Failed to compute layout");
188
189 self.update.insert(Update::FORCE);
190 }
191
192 let style = self.widget.layout_style();
193
194 let mut layout_node = self
195 .collect_layout(
196 self.taffy.child_at_index(self.window_node, 0).unwrap(),
197 &style,
198 )
199 .expect("Failed to collect layout");
200
201 log::debug!("Updating root widget...");
203 self.update
204 .insert(self.widget.update(&layout_node, self.context(), &self.info));
205
206 if self.update.get().intersects(Update::LAYOUT | Update::FORCE) {
208 log::debug!("Layout update detected!");
209
210 self.taffy
212 .set_children(self.window_node, &[])
213 .expect("Failed to set children");
214
215 let style = self.widget.layout_style();
216
217 self.layout_widget(self.window_node, &style)
218 .expect("Failed to layout window");
219
220 self.compute_layout().expect("Failed to compute layout");
221
222 layout_node = self
223 .collect_layout(
224 self.taffy.child_at_index(self.window_node, 0).unwrap(),
225 &style,
226 )
227 .expect("Failed to collect layout");
228 }
229
230 if self.update.get().intersects(Update::FORCE | Update::DRAW) {
232 log::debug!("Draw update detected!");
233
234 self.scene.reset();
236
237 let context = self.context();
238
239 log::debug!("Rendering root widget...");
240 self.widget.render(
241 &mut self.scene,
242 &mut self.config.theme,
243 &layout_node,
244 &self.info,
245 context,
246 );
247
248 let renderer = self.renderer.as_mut().expect("Renderer not initialized");
249 let render_ctx = self
250 .render_ctx
251 .as_ref()
252 .expect("Render context not initialized");
253 let surface = self.surface.as_ref().expect("Surface not initialized");
254 let window = self.window.as_ref().expect("Window not initialized");
255
256 let device_handle = render_ctx.devices.first().expect("No devices available");
257
258 if window.inner_size().width != 0 && window.inner_size().height != 0 {
260 let surface_texture = surface
261 .surface
262 .get_current_texture()
263 .expect("Failed to get surface texture");
264
265 window.pre_present_notify();
267
268 renderer
270 .render_to_surface(
271 &device_handle.device,
272 &device_handle.queue,
273 &self.scene,
274 &surface_texture,
275 &RenderParams {
276 base_color: self.config.theme.window_background(),
277 width: window.inner_size().width,
278 height: window.inner_size().height,
279 antialiasing_method: self.config.render.antialiasing,
280 },
281 )
282 .expect("Failed to render to surface");
283
284 surface_texture.present();
285 } else {
286 log::debug!("Surface invalid. Skipping render.");
287 }
288 }
289
290 if self.update.get().intersects(Update::EVAL | Update::FORCE) {
292 log::debug!("Evaluation update detected!");
293
294 if let Some(window) = self.window.as_ref() {
295 window.request_redraw();
296 }
297 }
298
299 self.info.reset();
301 self.update.clear();
302
303 if self.last_update.elapsed() >= Duration::from_secs(1) {
305 self.last_update = Instant::now();
306
307 self.info.diagnostics.updates_per_sec =
309 (self.info.diagnostics.updates_per_sec + self.info.diagnostics.updates) / 2;
310
311 self.info.diagnostics.updates = 0;
313 } else {
314 self.info.diagnostics.updates += 1;
316 }
317
318 log::debug!("Updates per sec: {}", self.info.diagnostics.updates_per_sec);
319 }
320}
321
322impl<T, W> ApplicationHandler for AppHandler<'_, T, W>
323where
324 T: Theme,
325 W: Widget,
326{
327 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
328 log::info!("Resuming/Starting app execution...");
329
330 self.plugins.run(|pl| {
331 pl.on_resume(
332 &mut self.config,
333 &mut self.scene,
334 &mut self.taffy,
335 self.window_node,
336 &mut self.info,
337 &self.update,
338 &mut self.last_update,
339 event_loop,
340 )
341 });
342
343 let mut render_ctx = RenderContext::new();
344
345 log::debug!("Creating window...");
346 self.window = Some(Arc::new(
347 event_loop
348 .create_window(self.attrs.clone())
349 .expect("Failed to create window"),
350 ));
351
352 self.taffy
353 .set_style(
354 self.window_node,
355 Style {
356 size: Size::<Dimension> {
357 width: Dimension::length(
358 self.window.as_ref().unwrap().inner_size().width as f32,
359 ),
360 height: Dimension::length(
361 self.window.as_ref().unwrap().inner_size().height as f32,
362 ),
363 },
364 ..Default::default()
365 },
366 )
367 .expect("Failed to set window node style");
368
369 self.surface = Some(
370 crate::tasks::block_on(async {
371 log::debug!("Creating surface...");
372
373 render_ctx
374 .create_surface(
375 self.window.clone().unwrap(),
376 self.window.as_ref().unwrap().inner_size().width,
377 self.window.as_ref().unwrap().inner_size().height,
378 self.config.render.present_mode,
379 )
380 .await
381 })
382 .expect("Failed to create surface"),
383 );
384
385 log::debug!("Requesting device handle via selector...");
386 let device_handle = (self.config.render.device_selector)(&render_ctx.devices);
387
388 log::debug!("Creating renderer...");
389 self.renderer = Some(
390 Renderer::new(
391 &device_handle.device,
392 RendererOptions {
393 surface_format: Some(self.surface.as_ref().unwrap().format),
394 use_cpu: self.config.render.cpu,
395 antialiasing_support: match self.config.render.antialiasing {
396 AaConfig::Area => AaSupport::area_only(),
397
398 AaConfig::Msaa8 => AaSupport {
399 area: false,
400 msaa8: true,
401 msaa16: false,
402 },
403
404 AaConfig::Msaa16 => AaSupport {
405 area: false,
406 msaa8: false,
407 msaa16: true,
408 },
409 },
410 num_init_threads: self.config.render.init_threads,
411 },
412 )
413 .expect("Failed to create renderer"),
414 );
415
416 self.render_ctx = Some(render_ctx);
417 self.update.set(Update::FORCE);
418 }
419
420 fn window_event(
421 &mut self,
422 event_loop: &ActiveEventLoop,
423 window_id: WindowId,
424 mut event: WindowEvent,
425 ) {
426 self.plugins.run(|pl| {
427 pl.on_window_event(
428 &mut event,
429 &mut self.config,
430 self.window.as_ref().unwrap(),
431 self.renderer.as_mut().unwrap(),
432 &mut self.scene,
433 self.surface.as_mut().unwrap(),
434 &mut self.taffy,
435 self.window_node,
436 &mut self.info,
437 self.render_ctx.as_mut().unwrap(),
438 &self.update,
439 &mut self.last_update,
440 event_loop,
441 )
442 });
443
444 if let Some(window) = &self.window {
445 if window.id() == window_id {
446 match event {
447 WindowEvent::Resized(new_size) => {
448 if new_size.width != 0 && new_size.height != 0 {
449 log::info!("Window resized to {}x{}", new_size.width, new_size.height);
450
451 if let Some(ctx) = &self.render_ctx {
452 if let Some(surface) = &mut self.surface {
453 ctx.resize_surface(surface, new_size.width, new_size.height);
454 }
455 }
456
457 self.taffy
458 .set_style(
459 self.window_node,
460 Style {
461 size: Size::<Dimension> {
462 width: Dimension::length(new_size.width as f32),
463 height: Dimension::length(new_size.height as f32),
464 },
465 ..Default::default()
466 },
467 )
468 .expect("Failed to set window node style");
469
470 self.info.size =
471 Vector2::new(new_size.width as f64, new_size.height as f64);
472
473 self.request_redraw();
474
475 self.update.insert(Update::DRAW | Update::LAYOUT);
476 } else {
477 log::debug!("Window size is 0x0, ignoring resize event.");
478 }
479 },
480
481 WindowEvent::CloseRequested => {
482 log::info!("Window Close requested...");
483
484 log::debug!("Destroying device handles...");
485 if let Some(render_ctx) = self.render_ctx.as_mut() {
486 for handle in &render_ctx.devices {
487 handle.device.destroy();
488 }
489 }
490
491 if self.config.window.close_on_request {
492 event_loop.exit();
493 }
494 },
495
496 WindowEvent::RedrawRequested => {
497 self.update(event_loop);
498 },
499
500 WindowEvent::CursorLeft { .. } => {
501 self.info.cursor_pos = None;
502 self.request_redraw();
503 },
504
505 WindowEvent::CursorMoved { position, .. } => {
506 self.info.cursor_pos = Some(Vector2::new(position.x, position.y));
507 self.request_redraw();
508 },
509
510 WindowEvent::KeyboardInput {
511 event,
512 device_id,
513 is_synthetic,
514 } => {
515 if !is_synthetic {
516 self.info.keys.push((device_id, event));
517 self.request_redraw();
518 }
519 },
520
521 WindowEvent::MouseInput {
522 device_id,
523 button,
524 state,
525 } => {
526 self.info.buttons.push((device_id, button, state));
527 self.request_redraw();
528 },
529
530 WindowEvent::MouseWheel { delta, .. } => {
531 self.info.mouse_scroll_delta = Some(delta);
532 self.request_redraw();
533 },
534
535 WindowEvent::Destroyed => log::info!("Window destroyed! Exiting..."),
536
537 _ => (),
538 }
539 }
540 }
541 }
542
543 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
544 log::info!("Suspending application...");
545
546 self.window = None;
547 self.surface = None;
548 self.render_ctx = None;
549 self.renderer = None;
550
551 self.plugins.run(|pl| {
552 pl.on_suspended(
553 &mut self.config,
554 &mut self.scene,
555 &mut self.taffy,
556 self.window_node,
557 &mut self.info,
558 &self.update,
559 &mut self.last_update,
560 event_loop,
561 )
562 });
563
564 self.info.reset();
565 }
566}