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/window.rs
1//! Window management
2 
3use std::sync::Arc;
4use strato_core::{types::Point, Size};
5 
6/// Window identifier
7pub type WindowId = u64;
8 
9/// Window handle
10pub struct Window {
11 pub id: WindowId,
12 pub(crate) inner: WindowInner,
13}
14 
15pub(crate) enum WindowInner {
16 #[cfg(not(target_arch = "wasm32"))]
17 Desktop(Arc<winit::window::Window>),
18 #[cfg(target_arch = "wasm32")]
19 Web(web_sys::HtmlCanvasElement),
20}
21 
22impl Window {
23 /// Get window ID
24 pub fn id(&self) -> WindowId {
25 self.id
26 }
27 
28 /// Get window size
29 pub fn size(&self) -> Size {
30 match &self.inner {
31 #[cfg(not(target_arch = "wasm32"))]
32 WindowInner::Desktop(window) => {
33 let size = window.inner_size();
34 Size::new(size.width as f32, size.height as f32)
35 }
36 #[cfg(target_arch = "wasm32")]
37 WindowInner::Web(canvas) => Size::new(canvas.width() as f32, canvas.height() as f32),
38 }
39 }
40 
41 /// Set window size
42 pub fn set_size(&self, size: Size) {
43 match &self.inner {
44 #[cfg(not(target_arch = "wasm32"))]
45 WindowInner::Desktop(window) => {
46 let _ = window
47 .request_inner_size(winit::dpi::LogicalSize::new(size.width, size.height));
48 }
49 #[cfg(target_arch = "wasm32")]
50 WindowInner::Web(canvas) => {
51 canvas.set_width(size.width as u32);
52 canvas.set_height(size.height as u32);
53 }
54 }
55 }
56 
57 /// Get window position
58 pub fn position(&self) -> Point {
59 match &self.inner {
60 #[cfg(not(target_arch = "wasm32"))]
61 WindowInner::Desktop(window) => window
62 .outer_position()
63 .map(|pos| Point::new(pos.x as f32, pos.y as f32))
64 .unwrap_or(Point::zero()),
65 #[cfg(target_arch = "wasm32")]
66 WindowInner::Web(_) => Point::zero(),
67 }
68 }
69 
70 /// Set window title
71 pub fn set_title(&self, title: &str) {
72 match &self.inner {
73 #[cfg(not(target_arch = "wasm32"))]
74 WindowInner::Desktop(window) => {
75 window.set_title(title);
76 }
77 #[cfg(target_arch = "wasm32")]
78 WindowInner::Web(_) => {
79 if let Some(document) = web_sys::window().and_then(|w| w.document()) {
80 document.set_title(title);
81 }
82 }
83 }
84 }
85 
86 /// Request redraw
87 pub fn request_redraw(&self) {
88 match &self.inner {
89 #[cfg(not(target_arch = "wasm32"))]
90 WindowInner::Desktop(window) => {
91 window.request_redraw();
92 }
93 #[cfg(target_arch = "wasm32")]
94 WindowInner::Web(_) => {
95 // Web platform handles this differently
96 }
97 }
98 }
99}
100 
101/// Window builder
102#[derive(Debug, Clone)]
103pub struct WindowBuilder {
104 pub title: String,
105 pub size: Size,
106 pub position: Option<Point>,
107 pub resizable: bool,
108 pub decorations: bool,
109 pub transparent: bool,
110 pub always_on_top: bool,
111 pub fullscreen: bool,
112 pub min_size: Option<Size>,
113 pub max_size: Option<Size>,
114}
115 
116impl WindowBuilder {
117 /// Create a new window builder
118 pub fn new() -> Self {
119 Self::default()
120 }
121 
122 /// Set window title
123 pub fn with_title(mut self, title: impl Into<String>) -> Self {
124 self.title = title.into();
125 self
126 }
127 
128 /// Set window size
129 pub fn with_size(mut self, width: f32, height: f32) -> Self {
130 self.size = Size::new(width, height);
131 self
132 }
133 
134 /// Set window position
135 pub fn with_position(mut self, x: f32, y: f32) -> Self {
136 self.position = Some(Point::new(x, y));
137 self
138 }
139 
140 /// Set resizable
141 pub fn resizable(mut self, resizable: bool) -> Self {
142 self.resizable = resizable;
143 self
144 }
145 
146 /// Set decorations
147 pub fn decorations(mut self, decorations: bool) -> Self {
148 self.decorations = decorations;
149 self
150 }
151 
152 /// Set transparent
153 pub fn transparent(mut self, transparent: bool) -> Self {
154 self.transparent = transparent;
155 self
156 }
157 
158 /// Set always on top
159 pub fn always_on_top(mut self, always_on_top: bool) -> Self {
160 self.always_on_top = always_on_top;
161 self
162 }
163 
164 /// Set fullscreen
165 pub fn fullscreen(mut self, fullscreen: bool) -> Self {
166 self.fullscreen = fullscreen;
167 self
168 }
169 
170 /// Set minimum size
171 pub fn min_size(mut self, width: f32, height: f32) -> Self {
172 self.min_size = Some(Size::new(width, height));
173 self
174 }
175 
176 /// Set maximum size
177 pub fn max_size(mut self, width: f32, height: f32) -> Self {
178 self.max_size = Some(Size::new(width, height));
179 self
180 }
181 
182 /// Build winit window
183 #[cfg(not(target_arch = "wasm32"))]
184 pub(crate) fn build_winit(
185 &self,
186 event_loop: &winit::event_loop::EventLoopWindowTarget<crate::event_loop::CustomEvent>,
187 ) -> Result<winit::window::Window, winit::error::OsError> {
188 let mut builder = winit::window::WindowBuilder::new()
189 .with_title(&self.title)
190 .with_inner_size(winit::dpi::LogicalSize::new(
191 self.size.width,
192 self.size.height,
193 ))
194 .with_resizable(self.resizable)
195 .with_decorations(self.decorations)
196 .with_transparent(self.transparent)
197 .with_window_level(if self.always_on_top {
198 winit::window::WindowLevel::AlwaysOnTop
199 } else {
200 winit::window::WindowLevel::Normal
201 });
202 
203 if let Some(pos) = self.position {
204 builder = builder.with_position(winit::dpi::LogicalPosition::new(pos.x, pos.y));
205 }
206 
207 if let Some(min) = self.min_size {
208 builder =
209 builder.with_min_inner_size(winit::dpi::LogicalSize::new(min.width, min.height));
210 }
211 
212 if let Some(max) = self.max_size {
213 builder =
214 builder.with_max_inner_size(winit::dpi::LogicalSize::new(max.width, max.height));
215 }
216 
217 if self.fullscreen {
218 builder = builder.with_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));
219 }
220 
221 builder.build(event_loop)
222 }
223}
224 
225impl Default for WindowBuilder {
226 fn default() -> Self {
227 Self {
228 title: "StratoUI Application".to_string(),
229 size: Size::new(800.0, 600.0),
230 position: None,
231 resizable: true,
232 decorations: true,
233 transparent: false,
234 always_on_top: false,
235 fullscreen: false,
236 min_size: Some(Size::new(200.0, 100.0)),
237 max_size: None,
238 }
239 }
240}
241