appscale_core/
platform_windows.rs1use crate::platform::*;
14use crate::tree::NodeId;
15use std::sync::Mutex;
16use std::collections::HashMap;
17
18pub struct WindowsPlatform {
23 next_handle: Mutex<u64>,
24 views: Mutex<HashMap<u64, ViewRecord>>,
25 screen: ScreenSize,
26 scale: f32,
27}
28
29struct ViewRecord {
30 view_type: ViewType,
31 node_id: NodeId,
32 children: Vec<NativeHandle>,
33}
34
35impl WindowsPlatform {
36 pub fn new() -> Self {
37 Self {
38 next_handle: Mutex::new(1),
39 views: Mutex::new(HashMap::new()),
40 screen: ScreenSize { width: 1280.0, height: 720.0 },
42 scale: 1.5,
43 }
44 }
45
46 pub fn with_screen(mut self, width: f32, height: f32, scale: f32) -> Self {
47 self.screen = ScreenSize { width, height };
48 self.scale = scale;
49 self
50 }
51
52 pub fn view_count(&self) -> usize {
53 self.views.lock().unwrap().len()
54 }
55}
56
57impl Default for WindowsPlatform {
58 fn default() -> Self { Self::new() }
59}
60
61impl PlatformBridge for WindowsPlatform {
62 fn platform_id(&self) -> PlatformId {
63 PlatformId::Windows
64 }
65
66 fn create_view(&self, view_type: ViewType, node_id: NodeId) -> NativeHandle {
67 let mut h = self.next_handle.lock().unwrap();
68 let handle = NativeHandle(*h);
69 *h += 1;
70
71 self.views.lock().unwrap().insert(handle.0, ViewRecord {
72 view_type,
73 node_id,
74 children: Vec::new(),
75 });
76
77 handle
78 }
79
80 fn update_view(&self, handle: NativeHandle, _props: &PropsDiff) -> Result<(), PlatformError> {
81 let views = self.views.lock().unwrap();
82 if !views.contains_key(&handle.0) {
83 return Err(PlatformError::ViewNotFound(handle));
84 }
85 Ok(())
87 }
88
89 fn remove_view(&self, handle: NativeHandle) {
90 self.views.lock().unwrap().remove(&handle.0);
91 }
92
93 fn insert_child(&self, parent: NativeHandle, child: NativeHandle, index: usize) {
94 let mut views = self.views.lock().unwrap();
95 if let Some(parent_record) = views.get_mut(&parent.0) {
96 let idx = index.min(parent_record.children.len());
97 parent_record.children.insert(idx, child);
98 }
99 }
100
101 fn remove_child(&self, parent: NativeHandle, child: NativeHandle) {
102 let mut views = self.views.lock().unwrap();
103 if let Some(parent_record) = views.get_mut(&parent.0) {
104 parent_record.children.retain(|c| *c != child);
105 }
106 }
107
108 fn measure_text(&self, text: &str, style: &TextStyle, max_width: f32) -> TextMetrics {
109 let font_size = style.font_size.unwrap_or(14.0); let char_width = font_size * 0.52; let line_height = style.line_height.unwrap_or(font_size * 1.33);
114 let total_width = char_width * text.len() as f32;
115
116 let lines = if max_width > 0.0 && total_width > max_width {
117 (total_width / max_width).ceil() as u32
118 } else {
119 1
120 };
121
122 TextMetrics {
123 width: if lines > 1 { max_width } else { total_width },
124 height: line_height * lines as f32,
125 baseline: font_size * 0.78,
126 line_count: lines,
127 }
128 }
129
130 fn screen_size(&self) -> ScreenSize {
131 self.screen
132 }
133
134 fn scale_factor(&self) -> f32 {
135 self.scale
136 }
137
138 fn supports(&self, capability: PlatformCapability) -> bool {
139 matches!(capability,
140 PlatformCapability::SystemTray
141 | PlatformCapability::MultiWindow
142 | PlatformCapability::DragAndDrop
143 | PlatformCapability::ContextMenu
144 | PlatformCapability::NativeFilePicker
145 | PlatformCapability::NativeDatePicker
146 | PlatformCapability::PushNotifications
147 )
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_windows_create_and_remove() {
157 let platform = WindowsPlatform::new();
158 assert_eq!(platform.platform_id(), PlatformId::Windows);
159
160 let h1 = platform.create_view(ViewType::Container, NodeId(1));
161 let h2 = platform.create_view(ViewType::Button, NodeId(2));
162 assert_eq!(platform.view_count(), 2);
163
164 platform.insert_child(h1, h2, 0);
165 platform.remove_child(h1, h2);
166 platform.remove_view(h2);
167 assert_eq!(platform.view_count(), 1);
168 }
169
170 #[test]
171 fn test_windows_capabilities() {
172 let platform = WindowsPlatform::new();
173 assert!(platform.supports(PlatformCapability::SystemTray));
174 assert!(platform.supports(PlatformCapability::MultiWindow));
175 assert!(platform.supports(PlatformCapability::DragAndDrop));
176 assert!(platform.supports(PlatformCapability::PushNotifications));
177 assert!(!platform.supports(PlatformCapability::MenuBar)); assert!(!platform.supports(PlatformCapability::Haptics));
179 }
180
181 #[test]
182 fn test_windows_screen_info() {
183 let platform = WindowsPlatform::new();
184 let screen = platform.screen_size();
185 assert_eq!(screen.width, 1280.0);
186 assert_eq!(screen.height, 720.0);
187 assert_eq!(platform.scale_factor(), 1.5);
188 }
189
190 #[test]
191 fn test_windows_custom_screen() {
192 let platform = WindowsPlatform::new().with_screen(2560.0, 1440.0, 2.0);
193 let screen = platform.screen_size();
194 assert_eq!(screen.width, 2560.0);
195 assert_eq!(platform.scale_factor(), 2.0);
196 }
197
198 #[test]
199 fn test_windows_text_measurement() {
200 let platform = WindowsPlatform::new();
201 let style = TextStyle { font_size: Some(16.0), ..TextStyle::default() };
202 let metrics = platform.measure_text("Hello Windows", &style, 200.0);
203 assert!(metrics.width > 0.0);
204 assert!(metrics.height > 0.0);
205 assert_eq!(metrics.line_count, 1);
206 }
207
208 #[test]
209 fn test_windows_update_missing_view() {
210 let platform = WindowsPlatform::new();
211 let result = platform.update_view(NativeHandle(999), &PropsDiff::new());
212 assert!(result.is_err());
213 }
214}