Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-platform/src/desktop.rs
StratoSDK / crates / strato-platform / src / desktop.rs
1//! Desktop platform implementation
2 
3use crate::event_loop::CustomEvent;
4use crate::window::WindowInner;
5use crate::{Platform, PlatformError, Window, WindowBuilder, WindowId};
6use std::collections::HashMap;
7use std::sync::Arc;
8use strato_core::event::Event;
9 
10/// Desktop platform implementation
11pub struct DesktopPlatform {
12 event_loop: Option<winit::event_loop::EventLoop<CustomEvent>>,
13 windows: HashMap<WindowId, Arc<winit::window::Window>>,
14 next_window_id: WindowId,
15}
16 
17impl DesktopPlatform {
18 /// Create a new desktop platform
19 pub fn new() -> Self {
20 Self {
21 event_loop: Some(
22 winit::event_loop::EventLoopBuilder::with_user_event()
23 .build()
24 .expect("Failed to create event loop"),
25 ),
26 windows: HashMap::new(),
27 next_window_id: 0,
28 }
29 }
30}
31 
32impl Platform for DesktopPlatform {
33 fn init() -> Result<Self, PlatformError> {
34 Ok(Self::new())
35 }
36 
37 fn create_window(&mut self, builder: WindowBuilder) -> Result<Window, PlatformError> {
38 let event_loop = self
39 .event_loop
40 .as_ref()
41 .ok_or_else(|| PlatformError::EventLoop("Event loop not available".to_string()))?;
42 
43 let winit_window = builder
44 .build_winit(event_loop)
45 .map_err(|e| PlatformError::WindowCreation(e.to_string()))?;
46 
47 let window_arc = Arc::new(winit_window);
48 let window_id = self.next_window_id;
49 self.next_window_id += 1;
50 
51 self.windows.insert(window_id, window_arc.clone());
52 
53 Ok(Window {
54 id: window_id,
55 inner: WindowInner::Desktop(window_arc),
56 })
57 }
58 
59 fn run_event_loop(
60 &mut self,
61 mut callback: Box<dyn FnMut(Event) + 'static>,
62 ) -> Result<(), PlatformError> {
63 let event_loop = self
64 .event_loop
65 .take()
66 .ok_or_else(|| PlatformError::EventLoop("Event loop already taken".to_string()))?;
67 
68 use winit::event::{Event as WinitEvent, WindowEvent as WinitWindowEvent};
69 
70 let mut cursor_position = winit::dpi::PhysicalPosition::new(0.0, 0.0);
71 let mut scale_factor = 1.0;
72 
73 let _ = event_loop.run(move |event, elwt| {
74 elwt.set_control_flow(winit::event_loop::ControlFlow::Wait);
75 
76 match event {
77 WinitEvent::WindowEvent { event, .. } => match event {
78 WinitWindowEvent::CursorMoved {
79 position,
80 device_id,
81 ..
82 } => {
83 cursor_position = position;
84 if let Some(strato_event) = crate::event_loop::convert_window_event(
85 WinitWindowEvent::CursorMoved {
86 position,
87 device_id,
88 },
89 cursor_position,
90 scale_factor,
91 ) {
92 callback(strato_event);
93 }
94 }
95 WinitWindowEvent::ScaleFactorChanged {
96 scale_factor: sf,
97 inner_size_writer,
98 } => {
99 scale_factor = sf;
100 if let Some(strato_event) = crate::event_loop::convert_window_event(
101 WinitWindowEvent::ScaleFactorChanged {
102 scale_factor: sf,
103 inner_size_writer,
104 },
105 cursor_position,
106 scale_factor,
107 ) {
108 callback(strato_event);
109 }
110 }
111 _ => {
112 if let Some(strato_event) = crate::event_loop::convert_window_event(
113 event,
114 cursor_position,
115 scale_factor,
116 ) {
117 callback(strato_event);
118 }
119 }
120 },
121 WinitEvent::AboutToWait => {
122 // All events have been processed
123 }
124 _ => {}
125 }
126 });
127 
128 Ok(())
129 }
130 
131 fn request_redraw(&self, window_id: WindowId) {
132 if let Some(window) = self.windows.get(&window_id) {
133 window.request_redraw();
134 }
135 }
136 
137 fn exit(&mut self) {
138 std::process::exit(0);
139 }
140}
141