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 maycoon_theme::theme::Theme;
17
18use crate::app::font_ctx::FontContext;
19use crate::app::info::AppInfo;
20use crate::app::update::Update;
21use crate::config::MayConfig;
22use crate::layout::{LayoutNode, StyleNode};
23use crate::state::State;
24use crate::widget::Widget;
25
26pub struct AppHandler<'a, T, W, S>
28where
29 T: Theme,
30 W: Widget<S>,
31 S: State,
32{
33 config: MayConfig<T>,
34 attrs: WindowAttributes,
35 window: Option<Arc<Window>>,
36 renderer: Option<Renderer>,
37 scene: Scene,
38 surface: Option<RenderSurface<'a>>,
39 taffy: TaffyTree,
40 window_node: NodeId,
41 widget: W,
42 state: S,
43 info: AppInfo,
44 render_ctx: Option<RenderContext>,
45 update: Update,
46 last_update: Instant,
47}
48
49impl<T, W, S> AppHandler<'_, T, W, S>
50where
51 T: Theme,
52 W: Widget<S>,
53 S: State,
54{
55 pub fn new(
57 attrs: WindowAttributes,
58 config: MayConfig<T>,
59 widget: W,
60 state: S,
61 font_context: FontContext,
62 ) -> Self {
63 let mut taffy = TaffyTree::with_capacity(16);
64
65 let window_node = taffy
67 .new_leaf(Style::default())
68 .expect("Failed to create window node");
69
70 let size = config.window.size;
71
72 Self {
73 attrs,
74 window: None,
75 renderer: None,
76 config,
77 scene: Scene::new(),
78 surface: None,
79 taffy,
80 state,
81 widget,
82 info: AppInfo {
83 font_context,
84 size,
85 ..Default::default()
86 },
87 window_node,
88 render_ctx: None,
89 update: Update::empty(),
90 last_update: Instant::now(),
91 }
92 }
93
94 fn layout_widget(&mut self, parent: NodeId, style: &StyleNode) -> TaffyResult<()> {
96 let node = self.taffy.new_leaf(style.style.clone().into())?;
97
98 self.taffy.add_child(parent, node)?;
99
100 for child in &style.children {
101 self.layout_widget(node, child)?;
102 }
103
104 Ok(())
105 }
106
107 fn compute_layout(&mut self) -> TaffyResult<()> {
109 self.taffy.compute_layout(
110 self.window_node,
111 Size::<AvailableSpace> {
112 width: AvailableSpace::Definite(
113 self.window.as_ref().unwrap().inner_size().width as f32,
114 ),
115 height: AvailableSpace::Definite(
116 self.window.as_ref().unwrap().inner_size().height as f32,
117 ),
118 },
119 )?;
120 Ok(())
121 }
122
123 fn collect_layout(&mut self, node: NodeId, style: &StyleNode) -> TaffyResult<LayoutNode> {
125 let mut children = Vec::with_capacity(style.children.len());
126
127 for (i, child) in style.children.iter().enumerate() {
128 children.push(self.collect_layout(self.taffy.child_at_index(node, i)?, child)?);
129 }
130
131 Ok(LayoutNode {
132 layout: *self.taffy.get_final_layout(node),
133 children,
134 })
135 }
136
137 fn request_redraw(&self) {
139 if let Some(window) = self.window.as_ref() {
140 window.request_redraw();
141 }
142 }
143
144 fn update(&mut self, _: &ActiveEventLoop) {
146 if self.taffy.child_count(self.window_node) == 0 {
148 let style = self.widget.layout_style(&self.state);
149
150 self.layout_widget(self.window_node, &style)
151 .expect("Failed to layout window");
152
153 self.compute_layout().expect("Failed to compute layout");
154
155 self.update.insert(Update::FORCE);
156 }
157
158 let style = self.widget.layout_style(&self.state);
159
160 let mut layout_node = self
161 .collect_layout(
162 self.taffy.child_at_index(self.window_node, 0).unwrap(),
163 &style,
164 )
165 .expect("Failed to collect layout");
166
167 self.update.insert(
169 self.widget
170 .update(&layout_node, &mut self.state, &self.info),
171 );
172
173 if self.update.intersects(Update::LAYOUT | Update::FORCE) {
175 self.taffy
177 .set_children(self.window_node, &[])
178 .expect("Failed to set children");
179
180 let style = self.widget.layout_style(&self.state);
181
182 self.layout_widget(self.window_node, &style)
183 .expect("Failed to layout window");
184
185 self.compute_layout().expect("Failed to compute layout");
186
187 layout_node = self
188 .collect_layout(
189 self.taffy.child_at_index(self.window_node, 0).unwrap(),
190 &style,
191 )
192 .expect("Failed to collect layout");
193 }
194
195 if self.update.intersects(Update::FORCE | Update::DRAW) {
197 self.scene.reset();
199
200 self.widget.render(
201 &mut self.scene,
202 &mut self.config.theme,
203 &self.info,
204 &layout_node,
205 &self.state,
206 );
207
208 let renderer = self.renderer.as_mut().expect("Renderer not initialized");
209 let render_ctx = self
210 .render_ctx
211 .as_ref()
212 .expect("Render context not initialized");
213 let surface = self.surface.as_ref().expect("Surface not initialized");
214 let window = self.window.as_ref().expect("Window not initialized");
215
216 let device_handle = render_ctx.devices.first().expect("No devices available");
217
218 if window.inner_size().width != 0 && window.inner_size().height != 0 {
220 let surface_texture = surface
221 .surface
222 .get_current_texture()
223 .expect("Failed to get surface texture");
224
225 window.pre_present_notify();
227
228 renderer
230 .render_to_surface(
231 &device_handle.device,
232 &device_handle.queue,
233 &self.scene,
234 &surface_texture,
235 &RenderParams {
236 base_color: self.config.theme.window_background(),
237 width: window.inner_size().width,
238 height: window.inner_size().height,
239 antialiasing_method: self.config.render.antialiasing,
240 },
241 )
242 .expect("Failed to render to surface");
243
244 surface_texture.present();
245 }
246 }
247
248 if self.update.intersects(Update::EVAL | Update::FORCE) {
250 if let Some(window) = self.window.as_ref() {
251 window.request_redraw();
252 }
253 }
254
255 self.info.reset();
257 self.update = Update::empty();
258
259 if self.last_update.elapsed() >= Duration::from_secs(1) {
261 self.last_update = Instant::now();
262
263 self.info.diagnostics.updates_per_sec =
265 (self.info.diagnostics.updates_per_sec + self.info.diagnostics.updates) / 2;
266
267 self.info.diagnostics.updates = 0;
269 } else {
270 self.info.diagnostics.updates += 1;
272 }
273 }
274}
275
276impl<T, W, S> ApplicationHandler for AppHandler<'_, T, W, S>
277where
278 T: Theme,
279 W: Widget<S>,
280 S: State,
281{
282 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
283 let mut render_ctx = RenderContext::new();
284
285 self.window = Some(Arc::new(
286 event_loop
287 .create_window(self.attrs.clone())
288 .expect("Failed to create window"),
289 ));
290
291 self.taffy
292 .set_style(
293 self.window_node,
294 Style {
295 size: Size::<Dimension> {
296 width: Dimension::Length(
297 self.window.as_ref().unwrap().inner_size().width as f32,
298 ),
299 height: Dimension::Length(
300 self.window.as_ref().unwrap().inner_size().height as f32,
301 ),
302 },
303 ..Default::default()
304 },
305 )
306 .expect("Failed to set window node style");
307
308 self.surface = Some(
309 crate::tasks::block_on(async {
310 render_ctx
311 .create_surface(
312 self.window.clone().unwrap(),
313 self.window.as_ref().unwrap().inner_size().width,
314 self.window.as_ref().unwrap().inner_size().height,
315 self.config.render.present_mode,
316 )
317 .await
318 })
319 .expect("Failed to create surface"),
320 );
321
322 let device_handle = render_ctx.devices.first().expect("Failed to select device");
325
326 self.renderer = Some(
327 Renderer::new(
328 &device_handle.device,
329 RendererOptions {
330 surface_format: Some(self.surface.as_ref().unwrap().format),
331 use_cpu: self.config.render.cpu,
332 antialiasing_support: match self.config.render.antialiasing {
333 AaConfig::Area => AaSupport::area_only(),
334
335 AaConfig::Msaa8 => AaSupport {
336 area: false,
337 msaa8: true,
338 msaa16: false,
339 },
340
341 AaConfig::Msaa16 => AaSupport {
342 area: false,
343 msaa8: false,
344 msaa16: true,
345 },
346 },
347 num_init_threads: self.config.render.init_threads,
348 },
349 )
350 .expect("Failed to create renderer"),
351 );
352
353 self.render_ctx = Some(render_ctx);
354 self.update = Update::FORCE;
355 }
356
357 fn window_event(
358 &mut self,
359 event_loop: &ActiveEventLoop,
360 window_id: WindowId,
361 event: WindowEvent,
362 ) {
363 if let Some(window) = &self.window {
364 if window.id() == window_id {
365 match event {
366 WindowEvent::Resized(new_size) => {
367 if new_size.width != 0 && new_size.height != 0 {
368 if let Some(ctx) = &self.render_ctx {
369 if let Some(surface) = &mut self.surface {
370 ctx.resize_surface(surface, new_size.width, new_size.height);
371 }
372 }
373
374 self.taffy
375 .set_style(
376 self.window_node,
377 Style {
378 size: Size::<Dimension> {
379 width: Dimension::Length(new_size.width as f32),
380 height: Dimension::Length(new_size.height as f32),
381 },
382 ..Default::default()
383 },
384 )
385 .expect("Failed to set window node style");
386
387 self.info.size =
388 Vector2::new(new_size.width as f64, new_size.height as f64);
389
390 self.request_redraw();
391
392 self.update.insert(Update::DRAW | Update::LAYOUT);
393 }
394 },
395
396 WindowEvent::CloseRequested => {
397 if let Some(render_ctx) = self.render_ctx.as_mut() {
398 for handle in &render_ctx.devices {
399 handle.device.destroy();
400 }
401 }
402
403 if self.config.window.close_on_request {
404 event_loop.exit();
405 }
406 },
407
408 WindowEvent::RedrawRequested => {
409 self.update(event_loop);
410 },
411
412 WindowEvent::CursorLeft { .. } => {
413 self.info.cursor_pos = None;
414 self.request_redraw();
415 },
416
417 WindowEvent::CursorMoved { position, .. } => {
418 self.info.cursor_pos = Some(Vector2::new(position.x, position.y));
419 self.request_redraw();
420 },
421
422 WindowEvent::KeyboardInput {
423 event,
424 device_id,
425 is_synthetic,
426 } => {
427 if !is_synthetic {
428 self.info.keys.push((device_id, event));
429 self.request_redraw();
430 }
431 },
432
433 WindowEvent::MouseInput {
434 device_id,
435 button,
436 state,
437 } => {
438 self.info.buttons.push((device_id, button, state));
439 self.request_redraw();
440 },
441
442 _ => (),
443 }
444 }
445 }
446 }
447
448 fn suspended(&mut self, _: &ActiveEventLoop) {
449 self.window = None;
450 self.surface = None;
451 self.render_ctx = None;
452 self.renderer = None;
453 self.info.reset();
454 }
455}