1#[cfg(target_os = "windows")]
2use crate::window::set_cloak;
3use crate::{
4 convert::{winit_key_code_to_code, winit_key_to_key},
5 window::{WinState, Window},
6 window_modifiers::WindowModifiers,
7};
8#[cfg(feature = "accesskit")]
9use accesskit_winit::Adapter;
10use hashbrown::HashMap;
11use std::{error::Error, fmt::Display, sync::Arc};
12use vizia_input::ImeState;
13
14use vizia_core::context::EventProxy;
20use vizia_core::prelude::*;
21use vizia_core::{backend::*, events::EventManager};
22use winit::{
23 application::ApplicationHandler,
24 dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
25 error::EventLoopError,
26 event::ElementState,
27 event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy},
28 keyboard::{NativeKeyCode, PhysicalKey},
29 window::{CursorIcon, CustomCursor, WindowAttributes, WindowId, WindowLevel},
30};
31
32use vizia_window::{Anchor, AnchorTarget, WindowPosition};
45
46#[derive(Debug)]
47pub enum UserEvent {
48 Event(Event),
49 #[cfg(feature = "accesskit")]
50 AccessKitEvent(accesskit_winit::Event),
51}
52
53#[cfg(feature = "accesskit")]
54impl From<accesskit_winit::Event> for UserEvent {
55 fn from(action_request_event: accesskit_winit::Event) -> Self {
56 UserEvent::AccessKitEvent(action_request_event)
57 }
58}
59
60impl From<vizia_core::events::Event> for UserEvent {
61 fn from(event: vizia_core::events::Event) -> Self {
62 UserEvent::Event(event)
63 }
64}
65
66type IdleCallback = Option<Box<dyn Fn(&mut Context)>>;
67
68#[derive(Debug)]
69pub enum ApplicationError {
70 EventLoopError(EventLoopError),
71 LogError,
72}
73
74impl Display for ApplicationError {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 match self {
77 ApplicationError::EventLoopError(ele) => write!(f, "{}", ele),
78 ApplicationError::LogError => write!(f, "log error"),
79 }
80 }
81}
82
83impl std::error::Error for ApplicationError {}
84
85pub struct Application {
98 cx: BackendContext,
99 event_manager: EventManager,
100 pub(crate) event_loop: Option<EventLoop<UserEvent>>,
101 on_idle: IdleCallback,
102 window_description: WindowDescription,
103 control_flow: ControlFlow,
104 event_loop_proxy: EventLoopProxy<UserEvent>,
105 windows: HashMap<WindowId, WinState>,
106 window_ids: HashMap<Entity, WindowId>,
107 #[cfg(feature = "accesskit")]
108 accesskit_adapter: Option<accesskit_winit::Adapter>,
109 #[cfg(feature = "accesskit")]
110 adapter_initialized: bool,
111}
112
113pub struct WinitEventProxy(EventLoopProxy<UserEvent>);
114
115impl EventProxy for WinitEventProxy {
116 fn send(&self, event: Event) -> Result<(), ()> {
117 self.0.send_event(UserEvent::Event(event)).map_err(|_| ())
118 }
119
120 fn make_clone(&self) -> Box<dyn EventProxy> {
121 Box::new(WinitEventProxy(self.0.clone()))
122 }
123}
124
125impl Application {
126 pub fn new<F>(content: F) -> Self
127 where
128 F: 'static + FnOnce(&mut Context),
129 {
130 let context = Context::new();
131
132 let event_loop =
133 EventLoop::<UserEvent>::with_user_event().build().expect("Failed to create event loop");
134
135 let mut cx = BackendContext::new(context);
136 let event_proxy_obj = event_loop.create_proxy();
137 cx.set_event_proxy(Box::new(WinitEventProxy(event_proxy_obj)));
138
139 cx.renegotiate_language();
140 cx.0.remove_user_themes();
141 (content)(cx.context());
142
143 let proxy = event_loop.create_proxy();
144
145 Self {
146 cx,
147 event_manager: EventManager::new(),
148 event_loop: Some(event_loop),
149 on_idle: None,
150 window_description: WindowDescription::new(),
151 control_flow: ControlFlow::Wait,
152 event_loop_proxy: proxy,
153 windows: HashMap::new(),
154 window_ids: HashMap::new(),
155 #[cfg(feature = "accesskit")]
156 accesskit_adapter: None,
157 #[cfg(feature = "accesskit")]
158 adapter_initialized: false,
159 }
160 }
161
162 fn create_window(
163 &mut self,
164 event_loop: &ActiveEventLoop,
165 window_entity: Entity,
166 window_description: &WindowDescription,
167 #[allow(unused_variables)] owner: Option<Arc<winit::window::Window>>,
168 ) -> Result<Arc<winit::window::Window>, Box<dyn Error>> {
169 #[allow(unused_mut)]
170 let mut window_attributes = apply_window_description(window_description);
171
172 let window_state = WinState::new(event_loop, window_entity, window_attributes, owner)?;
173 let window = window_state.window.clone();
174
175 if let Some(position) = window_description.position {
176 window.set_outer_position(LogicalPosition::new(position.x, position.y));
177 } else {
178 let (anchor, mut parent_anchor) =
179 match (window_description.anchor, window_description.parent_anchor) {
180 (Some(a), None) => (Some(a), Some(a)),
181 (None, Some(b)) => (Some(b.opposite()), Some(b)),
182 t => t,
183 };
184
185 if let Some(anchor) = anchor {
186 let (y, x) = match anchor {
187 Anchor::TopLeft => (0.0, 0.0),
188 Anchor::TopCenter => (0.0, 0.5),
189 Anchor::TopRight => (0.0, 1.0),
190 Anchor::Left => (0.5, 0.0),
191 Anchor::Center => (0.5, 0.5),
192 Anchor::Right => (0.5, 1.0),
193 Anchor::BottomLeft => (1.0, 0.0),
194 Anchor::BottomCenter => (1.0, 0.5),
195 Anchor::BottomRight => (1.0, 1.0),
196 };
197
198 let window_size = window.inner_size();
199
200 let anchor_target = window_description.anchor_target.unwrap_or_default();
201 let parent = match anchor_target {
202 AnchorTarget::Monitor => window
203 .current_monitor()
204 .map(|monitor| (PhysicalPosition::default(), monitor.size())),
205 AnchorTarget::Window => self
206 .cx
207 .0
208 .tree
209 .get_parent_window(window_entity)
210 .and_then(|parent_window| self.window_ids.get(&parent_window))
211 .and_then(|id| self.windows.get(id))
212 .map(|win_state| {
213 (
214 win_state.window.outer_position().unwrap(),
215 win_state.window.inner_size(),
216 )
217 }),
218 AnchorTarget::Mouse => self
219 .cx
220 .0
221 .tree
222 .get_parent_window(window_entity)
223 .and_then(|parent_window| self.window_ids.get(&parent_window))
224 .and_then(|id| self.windows.get(id))
225 .map(|win_state| {
226 let pos = win_state.window.outer_position().unwrap();
227 (
228 PhysicalPosition::new(
229 pos.x + self.cx.0.mouse.cursor_x as i32,
230 pos.y + self.cx.0.mouse.cursor_y as i32,
231 ),
232 PhysicalSize::new(0, 0),
233 )
234 }),
235 };
236
237 if let Some((parent_position, parent_size)) = parent {
238 if anchor_target != AnchorTarget::Window {
239 parent_anchor = Some(anchor);
240 }
241
242 let (py, px) = match parent_anchor.unwrap_or_default() {
243 Anchor::TopLeft => (0.0, 0.0),
244 Anchor::TopCenter => (0.0, 0.5),
245 Anchor::TopRight => (0.0, 1.0),
246 Anchor::Left => (0.5, 0.0),
247 Anchor::Center => (0.5, 0.5),
248 Anchor::Right => (0.5, 1.0),
249 Anchor::BottomLeft => (1.0, 0.0),
250 Anchor::BottomCenter => (1.0, 0.5),
251 Anchor::BottomRight => (1.0, 1.0),
252 };
253
254 let x = (((parent_size.width as f32 * px) as i32
255 - (window_size.width as f32 * x) as i32)
256 as f32) as i32;
257 let y = (((parent_size.height as f32 * py) as i32
258 - (window_size.height as f32 * y) as i32)
259 as f32) as i32;
260
261 let offset = window_description.offset.unwrap_or_default();
262 let offset: PhysicalPosition<i32> = PhysicalPosition::from_logical(
263 LogicalPosition::new(offset.x, offset.y),
264 window.scale_factor(),
265 );
266
267 window.set_outer_position(PhysicalPosition::new(
268 parent_position.x + x as i32 + offset.x,
269 parent_position.y + y as i32 + offset.y,
270 ));
271 }
272 }
273 }
274
275 let window_id = window_state.window.id();
276 self.windows.insert(window_id, window_state);
277 self.window_ids.insert(window_entity, window_id);
278 Ok(window)
279 }
280
281 pub fn ignore_default_theme(mut self) -> Self {
283 self.cx.context().ignore_default_theme = true;
284 self
285 }
286
287 pub fn should_poll(mut self) -> Self {
288 self.control_flow = ControlFlow::Poll;
289
290 self
291 }
292
293 pub fn on_idle<F: 'static + Fn(&mut Context)>(mut self, callback: F) -> Self {
314 self.on_idle = Some(Box::new(callback));
315
316 self
317 }
318
319 pub fn get_proxy(&self) -> ContextProxy {
321 self.cx.0.get_proxy()
322 }
323
324 pub fn run(mut self) -> Result<(), ApplicationError> {
325 self.event_loop.take().unwrap().run_app(&mut self).map_err(ApplicationError::EventLoopError)
326 }
327}
328
329impl ApplicationHandler<UserEvent> for Application {
330 fn user_event(&mut self, _event_loop: &ActiveEventLoop, user_event: UserEvent) {
331 match user_event {
332 UserEvent::Event(event) => {
333 self.cx.send_event(event);
334 }
335
336 #[cfg(feature = "accesskit")]
337 UserEvent::AccessKitEvent(access_event) => {
338 match access_event.window_event {
339 accesskit_winit::WindowEvent::InitialTreeRequested => {
340 let tree_update = self.cx.init_accessibility_tree();
341 if let Some(adapter) = &mut self.accesskit_adapter {
342 adapter.update_if_active(|| {
343 self.adapter_initialized = true;
344 tree_update
345 });
346 }
347 }
348 accesskit_winit::WindowEvent::ActionRequested(action_request) => {
349 let node_id = action_request.target;
350
351 if action_request.action != Action::ScrollIntoView {
352 let entity = Entity::new(node_id.0, 0);
353
354 if action_request.action == Action::Focus {
356 self.cx.0.with_current(entity, |cx| {
357 cx.focus();
358 });
359 }
360
361 self.cx.send_event(
362 Event::new(WindowEvent::ActionRequest(action_request))
363 .direct(entity),
364 );
365 }
366 }
367 accesskit_winit::WindowEvent::AccessibilityDeactivated => todo!(),
368 }
369 }
370 }
371 }
372
373 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
374 if self.windows.is_empty() {
375 let main_window: Arc<winit::window::Window> = self
377 .create_window(event_loop, Entity::root(), &self.window_description.clone(), None)
378 .expect("failed to create initial window");
379 let custom_cursors = Arc::new(load_default_cursors(event_loop));
380 self.cx.add_main_window(
381 Entity::root(),
382 &self.window_description,
383 main_window.scale_factor() as f32,
384 );
385 self.cx.add_window(Window {
386 window: Some(main_window.clone()),
387 on_close: None,
388 on_create: None,
389 should_close: false,
390 custom_cursors: custom_cursors.clone(),
391 });
392
393 self.cx.0.windows.insert(
394 Entity::root(),
395 WindowState {
396 window_description: self.window_description.clone(),
397 ..Default::default()
398 },
399 );
400
401 #[cfg(feature = "accesskit")]
402 {
403 self.accesskit_adapter = Some(Adapter::with_event_loop_proxy(
404 event_loop,
405 &main_window,
406 self.event_loop_proxy.clone(),
407 ));
408 }
409
410 main_window.set_visible(self.window_description.visible);
411
412 if let Some(theme) = main_window.theme() {
414 let theme = match theme {
415 winit::window::Theme::Light => ThemeMode::LightMode,
416 winit::window::Theme::Dark => ThemeMode::DarkMode,
417 };
418 self.cx.emit_origin(WindowEvent::ThemeChanged(theme));
419 }
420
421 self.cx.0.remove_user_themes();
422
423 for (window_entity, window_state) in self.cx.0.windows.clone().into_iter() {
425 if window_entity == Entity::root() {
426 continue;
427 }
428 let owner = window_state.owner.and_then(|entity| {
429 self.window_ids
430 .get(&entity)
431 .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
432 });
433
434 let window = self
435 .create_window(
436 event_loop,
437 window_entity,
438 &window_state.window_description,
439 owner,
440 )
441 .expect("Failed to create window");
442
443 self.cx.add_main_window(
444 window_entity,
445 &window_state.window_description,
446 window.scale_factor() as f32,
447 );
448
449 self.cx.0.with_current(window_entity, |cx| {
450 if let Some(content) = &window_state.content {
451 (content)(cx)
452 }
453 });
454 self.cx.mutate_window(window_entity, |cx, win: &mut Window| {
455 win.window = Some(window.clone());
456 win.custom_cursors = custom_cursors.clone();
457 if let Some(callback) = &win.on_create {
458 (callback)(&mut EventContext::new_with_current(
459 cx.context(),
460 window_entity,
461 ));
462 }
463 });
464 self.cx.needs_refresh(window_entity);
465 }
466 }
467 }
468
469 fn window_event(
470 &mut self,
471 _event_loop: &ActiveEventLoop,
472 window_id: WindowId,
473 event: winit::event::WindowEvent,
474 ) {
475 let window = match self.windows.get_mut(&window_id) {
476 Some(window) => window,
477 None => return,
478 };
479
480 match event {
481 winit::event::WindowEvent::Resized(size) => {
482 window.resize(size);
483 self.cx.set_window_size(window.entity, size.width as f32, size.height as f32);
484 self.cx.needs_refresh(window.entity);
485 window.window().request_redraw();
486
487 #[cfg(target_os = "windows")]
488 {
489 self.event_manager.flush_events(self.cx.context(), |_| {});
490
491 self.cx.process_style_updates();
492
493 if self.cx.process_animations() {
494 window.window().request_redraw();
495 }
496
497 self.cx.process_visual_updates();
498
499 window.window().request_redraw();
519 }
520 }
521
522 winit::event::WindowEvent::Moved(position) => {
523 let window_entity = window.entity;
524 self.cx.emit_window_event(
525 window_entity,
526 WindowEvent::WindowMoved(WindowPosition { x: position.x, y: position.y }),
527 );
528
529 #[cfg(target_os = "windows")]
530 {
531 self.event_manager.flush_events(self.cx.context(), |_| {});
532
533 self.cx.process_style_updates();
534
535 if self.cx.process_animations() {
536 window.window().request_redraw();
537 }
538
539 self.cx.process_visual_updates();
540
541 window.window().request_redraw();
561 }
562 }
563
564 winit::event::WindowEvent::CloseRequested | winit::event::WindowEvent::Destroyed => {
565 let window_entity = window.entity;
566 self.cx.emit_window_event(window_entity, WindowEvent::WindowClose);
567 }
568 winit::event::WindowEvent::DroppedFile(path) => {
569 self.cx.emit_window_event(window.entity, WindowEvent::Drop(DropData::File(path)));
570 }
571
572 winit::event::WindowEvent::HoveredFile(_) => {}
573 winit::event::WindowEvent::HoveredFileCancelled => {}
574 winit::event::WindowEvent::Focused(is_focused) => {
575 self.cx.emit_window_event(window.entity, WindowEvent::WindowFocused(is_focused));
576
577 self.cx.0.window_has_focus = is_focused;
578 }
585 winit::event::WindowEvent::KeyboardInput { device_id: _, event, is_synthetic: _ } => {
586 let code = match event.physical_key {
587 PhysicalKey::Code(code) => winit_key_code_to_code(code),
588 PhysicalKey::Unidentified(native) => match native {
589 NativeKeyCode::Windows(_scancode) => return,
590 _ => return,
591 },
592 };
593
594 let key = match event.logical_key {
595 winit::keyboard::Key::Named(named_key) => winit_key_to_key(named_key),
596 _ => None,
597 };
598
599 if let winit::keyboard::Key::Character(character) = event.logical_key {
600 if event.state == ElementState::Pressed {
601 self.cx.emit_window_event(
602 window.entity,
603 WindowEvent::CharInput(character.as_str().chars().next().unwrap()),
604 );
605 }
606 }
607
608 let event = match event.state {
609 winit::event::ElementState::Pressed => WindowEvent::KeyDown(code, key),
610 winit::event::ElementState::Released => WindowEvent::KeyUp(code, key),
611 };
612
613 self.cx.emit_window_event(window.entity, event);
614 window.window().request_redraw();
615 }
616 winit::event::WindowEvent::ModifiersChanged(modifiers) => {
617 self.cx.modifiers().set(Modifiers::SHIFT, modifiers.state().shift_key());
618
619 self.cx.modifiers().set(Modifiers::ALT, modifiers.state().alt_key());
620
621 self.cx.modifiers().set(Modifiers::CTRL, modifiers.state().control_key());
622
623 self.cx.modifiers().set(Modifiers::SUPER, modifiers.state().super_key());
624
625 window.window().request_redraw();
626 }
627 winit::event::WindowEvent::Ime(ime) => match ime {
628 winit::event::Ime::Enabled => {
629 self.cx.0.set_ime_state(ImeState::StartComposition);
630 self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(true));
631 }
632 winit::event::Ime::Preedit(text, cursor) => {
633 self.cx.0.set_ime_state(ImeState::Composing {
634 preedit: Some(text.clone()),
635 cursor_pos: cursor,
636 });
637 self.cx.emit_window_event(window.entity, WindowEvent::ImePreedit(text, cursor));
638 }
639 winit::event::Ime::Commit(text) => {
640 self.cx.0.set_ime_state(ImeState::EndComposition);
641 self.cx.emit_window_event(window.entity, WindowEvent::ImeCommit(text));
642 }
643 winit::event::Ime::Disabled => {
644 self.cx.0.set_ime_state(ImeState::Inactive);
645 self.cx.emit_window_event(window.entity, WindowEvent::ImeActivate(false));
646 }
647 },
648 winit::event::WindowEvent::CursorMoved { device_id: _, position } => {
649 self.cx.emit_window_event(
650 window.entity,
651 WindowEvent::MouseMove(position.x as f32, position.y as f32),
652 );
653 window.window().request_redraw();
654 }
655 winit::event::WindowEvent::CursorEntered { device_id: _ } => {
656 self.cx.emit_window_event(window.entity, WindowEvent::MouseEnter);
657 window.window().request_redraw();
658 }
659 winit::event::WindowEvent::CursorLeft { device_id: _ } => {
660 self.cx.emit_window_event(window.entity, WindowEvent::MouseLeave);
661 window.window().request_redraw();
662 }
663 winit::event::WindowEvent::MouseWheel { device_id: _, delta, phase: _ } => {
664 let out_event = match delta {
665 winit::event::MouseScrollDelta::LineDelta(x, y) => {
666 WindowEvent::MouseScroll(x, y)
667 }
668 winit::event::MouseScrollDelta::PixelDelta(pos) => {
669 WindowEvent::MouseScroll(
670 pos.x as f32 / 20.0,
671 pos.y as f32 / 20.0, )
673 }
674 };
675
676 self.cx.emit_window_event(window.entity, out_event);
677 window.window().request_redraw();
678 }
679 winit::event::WindowEvent::MouseInput { device_id: _, state, button } => {
680 let button = match button {
681 winit::event::MouseButton::Left => MouseButton::Left,
682 winit::event::MouseButton::Right => MouseButton::Right,
683 winit::event::MouseButton::Middle => MouseButton::Middle,
684 winit::event::MouseButton::Other(val) => MouseButton::Other(val),
685 winit::event::MouseButton::Back => MouseButton::Back,
686 winit::event::MouseButton::Forward => MouseButton::Forward,
687 };
688
689 let event = match state {
690 winit::event::ElementState::Pressed => WindowEvent::MouseDown(button),
691 winit::event::ElementState::Released => WindowEvent::MouseUp(button),
692 };
693
694 self.cx.emit_window_event(window.entity, event);
695 window.window().request_redraw();
696 }
697
698 winit::event::WindowEvent::ScaleFactorChanged {
699 scale_factor,
700 inner_size_writer: _,
701 } => {
702 self.cx.set_scale_factor(scale_factor);
703 self.cx.needs_refresh(window.entity);
704 }
705 winit::event::WindowEvent::ThemeChanged(theme) => {
706 let theme = match theme {
707 winit::window::Theme::Light => ThemeMode::LightMode,
708 winit::window::Theme::Dark => ThemeMode::DarkMode,
709 };
710 self.cx.emit_window_event(window.entity, WindowEvent::ThemeChanged(theme));
711 }
712 winit::event::WindowEvent::Occluded(_) => {}
713 winit::event::WindowEvent::RedrawRequested => {
714 for window in self.windows.values_mut() {
715 window.make_current();
716 if self.cx.draw(window.entity, &mut window.surface, &mut window.dirty_surface) {
718 window.swap_buffers();
719 }
720
721 #[cfg(target_os = "windows")]
723 if window.is_initially_cloaked {
724 window.is_initially_cloaked = false;
725 set_cloak(window.window(), false);
726 }
727 }
728 }
729
730 _ => {}
731 }
732 }
733
734 fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
735 if self.windows.is_empty() {
736 event_loop.exit();
737 return;
738 }
739
740 event_loop.set_control_flow(self.control_flow);
741
742 self.event_manager.flush_events(self.cx.context(), |_| {});
743
744 self.cx.process_style_updates();
745
746 if self.cx.process_animations() {
747 for window in self.windows.values() {
748 window.window().request_redraw();
749 }
750 }
751
752 self.cx.process_visual_updates();
753
754 #[cfg(feature = "accesskit")]
755 {
756 self.cx.process_tree_updates();
757
758 if self.adapter_initialized {
759 for update in self.cx.0.tree_updates.iter_mut() {
760 self.accesskit_adapter
761 .as_mut()
762 .unwrap()
763 .update_if_active(|| update.take().unwrap());
764 }
765 }
766
767 self.cx.0.tree_updates.clear();
768 }
769
770 if let Some(idle_callback) = &self.on_idle {
771 self.cx.set_current(Entity::root());
772 (idle_callback)(self.cx.context());
773 }
774
775 if self.cx.has_queued_events() {
776 self.event_loop_proxy
777 .send_event(UserEvent::Event(Event::new(())))
778 .expect("Failed to send event");
779 }
780
781 if self.cx.0.windows.iter().any(|(_, window_state)| !window_state.redraw_list.is_empty()) {
782 for window in self.windows.values() {
783 window.window().request_redraw();
784 }
785 }
786
787 if self.control_flow != ControlFlow::Poll {
788 if let Some(timer_time) = self.cx.get_next_timer_time() {
789 event_loop.set_control_flow(ControlFlow::WaitUntil(timer_time));
790 } else {
791 event_loop.set_control_flow(ControlFlow::Wait);
792 }
793 }
794
795 let window_entities = self
796 .cx
797 .0
798 .windows
799 .iter()
800 .filter_map(|(entity, state)| state.should_close.then_some(*entity))
801 .collect::<Vec<_>>();
802
803 for window_entity in window_entities {
804 self.cx.0.remove(window_entity);
805 }
806
807 self.windows.retain(|_, win| self.cx.0.windows.contains_key(&win.entity));
809 self.window_ids.retain(|e, _| self.cx.0.windows.contains_key(e));
810
811 if self.windows.len() != self.cx.0.windows.len() {
812 for (window_entity, window_state) in self.cx.0.windows.clone().iter() {
813 if !self.window_ids.contains_key(window_entity) {
814 let owner = window_state.owner.and_then(|entity| {
815 self.window_ids
816 .get(&entity)
817 .and_then(|id| self.windows.get(id).map(|ws| ws.window.clone()))
818 });
819
820 let window = self
821 .create_window(
822 event_loop,
823 *window_entity,
824 &window_state.window_description,
825 owner,
826 )
827 .expect("Failed to create window");
828
829 self.cx.add_main_window(
830 *window_entity,
831 &window_state.window_description,
832 window.scale_factor() as f32,
833 );
834
835 self.cx.0.with_current(*window_entity, |cx| {
836 if let Some(content) = &window_state.content {
837 (content)(cx)
838 }
839 });
840
841 self.cx.mutate_window(*window_entity, |cx, win: &mut Window| {
842 win.window = Some(window.clone());
843 if let Some(callback) = &win.on_create {
844 (callback)(&mut EventContext::new_with_current(
845 cx.context(),
846 *window_entity,
847 ));
848 }
849 });
850 }
851 }
852 }
853
854 if self.windows.is_empty() {
855 event_loop.exit();
856 }
857 }
858
859 fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: winit::event::StartCause) {
860 self.cx.process_timers();
861 self.cx.emit_scheduled_events();
862 }
863
864 fn exiting(&mut self, _event_loop: &ActiveEventLoop) {}
865}
866
867impl WindowModifiers for Application {
868 fn title<T: ToString>(mut self, title: impl Res<T>) -> Self {
869 self.window_description.title = title.get(&self.cx.0).to_string();
870
871 title.set_or_bind(&mut self.cx.0, Entity::root(), |cx, title| {
872 cx.emit(WindowEvent::SetTitle(title.get(cx).to_string()));
873 });
874
875 self
876 }
877
878 fn inner_size<S: Into<WindowSize>>(mut self, size: impl Res<S>) -> Self {
879 self.window_description.inner_size = size.get(&self.cx.0).into();
880
881 size.set_or_bind(&mut self.cx.0, Entity::root(), |cx, size| {
882 cx.emit(WindowEvent::SetSize(size.get(cx).into()));
883 });
884
885 self
886 }
887
888 fn min_inner_size<S: Into<WindowSize>>(mut self, size: impl Res<Option<S>>) -> Self {
889 self.window_description.min_inner_size = size.get(&self.cx.0).map(|s| s.into());
890
891 size.set_or_bind(&mut self.cx.0, Entity::root(), |cx, size| {
892 cx.emit(WindowEvent::SetMinSize(size.get(cx).map(|s| s.into())));
893 });
894
895 self
896 }
897
898 fn max_inner_size<S: Into<WindowSize>>(mut self, size: impl Res<Option<S>>) -> Self {
899 self.window_description.max_inner_size = size.get(&self.cx.0).map(|s| s.into());
900
901 size.set_or_bind(&mut self.cx.0, Entity::root(), |cx, size| {
902 cx.emit(WindowEvent::SetMaxSize(size.get(cx).map(|s| s.into())));
903 });
904 self
905 }
906
907 fn position<P: Into<WindowPosition>>(mut self, position: impl Res<P>) -> Self {
908 self.window_description.position = Some(position.get(&self.cx.0).into());
909
910 position.set_or_bind(&mut self.cx.0, Entity::root(), |cx, size| {
911 cx.emit(WindowEvent::SetPosition(size.get(cx).into()));
912 });
913
914 self
915 }
916
917 fn offset<P: Into<WindowPosition>>(mut self, offset: impl Res<P>) -> Self {
918 self.window_description.offset = Some(offset.get(&self.cx.0).into());
919
920 self
921 }
922
923 fn anchor<P: Into<Anchor>>(mut self, anchor: impl Res<P>) -> Self {
924 self.window_description.anchor = Some(anchor.get(&self.cx.0).into());
925
926 self
927 }
928
929 fn anchor_target<P: Into<AnchorTarget>>(mut self, anchor_target: impl Res<P>) -> Self {
930 self.window_description.anchor_target = Some(anchor_target.get(&self.cx.0).into());
931
932 self
933 }
934
935 fn parent_anchor<P: Into<Anchor>>(mut self, parent_anchor: impl Res<P>) -> Self {
936 self.window_description.parent_anchor = Some(parent_anchor.get(&self.cx.0).into());
937
938 self
939 }
940
941 fn resizable(mut self, flag: impl Res<bool>) -> Self {
942 self.window_description.resizable = flag.get(&self.cx.0);
943
944 flag.set_or_bind(&mut self.cx.0, Entity::root(), |cx, flag| {
945 cx.emit(WindowEvent::SetResizable(flag.get(cx)));
946 });
947
948 self
949 }
950
951 fn minimized(mut self, flag: impl Res<bool>) -> Self {
952 self.window_description.minimized = flag.get(&self.cx.0);
953
954 flag.set_or_bind(&mut self.cx.0, Entity::root(), |cx, flag| {
955 cx.emit(WindowEvent::SetMinimized(flag.get(cx)));
956 });
957 self
958 }
959
960 fn maximized(mut self, flag: impl Res<bool>) -> Self {
961 self.window_description.maximized = flag.get(&self.cx.0);
962
963 flag.set_or_bind(&mut self.cx.0, Entity::root(), |cx, flag| {
964 cx.emit(WindowEvent::SetMaximized(flag.get(cx)));
965 });
966
967 self
968 }
969
970 fn visible(mut self, flag: impl Res<bool>) -> Self {
971 self.window_description.visible = flag.get(&self.cx.0);
972
973 flag.set_or_bind(&mut self.cx.0, Entity::root(), |cx, flag| {
974 cx.emit(WindowEvent::SetVisible(flag.get(cx)));
975 });
976
977 self
978 }
979
980 fn transparent(mut self, flag: bool) -> Self {
981 self.window_description.transparent = flag;
982
983 self
984 }
985
986 fn decorations(mut self, flag: bool) -> Self {
987 self.window_description.decorations = flag;
988
989 self
990 }
991
992 fn always_on_top(mut self, flag: bool) -> Self {
993 self.window_description.always_on_top = flag;
994 self
995 }
996
997 fn vsync(mut self, flag: bool) -> Self {
998 self.window_description.vsync = flag;
999
1000 self
1001 }
1002
1003 fn icon(mut self, width: u32, height: u32, image: Vec<u8>) -> Self {
1004 self.window_description.icon = Some(image);
1005 self.window_description.icon_width = width;
1006 self.window_description.icon_height = height;
1007
1008 self
1009 }
1010
1011 fn on_close(self, _callback: impl Fn(&mut EventContext)) -> Self {
1012 self
1013 }
1014
1015 fn on_create(self, _callback: impl Fn(&mut EventContext)) -> Self {
1016 self
1017 }
1018
1019 fn enabled_window_buttons(mut self, window_buttons: WindowButtons) -> Self {
1020 self.window_description.enabled_window_buttons = window_buttons;
1021
1022 self
1023 }
1024}
1025
1026fn apply_window_description(description: &WindowDescription) -> WindowAttributes {
1027 let mut window_attributes = winit::window::Window::default_attributes();
1028
1029 window_attributes = window_attributes.with_title(&description.title).with_inner_size(
1030 LogicalSize::new(description.inner_size.width, description.inner_size.height),
1031 );
1032
1033 if let Some(min_inner_size) = description.min_inner_size {
1034 window_attributes = window_attributes
1035 .with_min_inner_size(LogicalSize::new(min_inner_size.width, min_inner_size.height));
1036 }
1037
1038 if let Some(max_inner_size) = description.max_inner_size {
1039 window_attributes = window_attributes
1040 .with_max_inner_size(LogicalSize::new(max_inner_size.width, max_inner_size.height));
1041 }
1042
1043 if let Some(position) = description.position {
1044 window_attributes =
1045 window_attributes.with_position(LogicalPosition::new(position.x, position.y));
1046 }
1047
1048 window_attributes
1049 .with_resizable(description.resizable)
1050 .with_maximized(description.maximized)
1051 .with_visible(false)
1053 .with_window_level(if description.always_on_top {
1054 WindowLevel::AlwaysOnTop
1055 } else {
1056 WindowLevel::Normal
1057 })
1058 .with_transparent(description.transparent)
1059 .with_decorations(description.decorations)
1060 .with_window_icon(description.icon.as_ref().map(|icon| {
1061 winit::window::Icon::from_rgba(
1062 icon.clone(),
1063 description.icon_width,
1064 description.icon_height,
1065 )
1066 .unwrap()
1067 }))
1068 .with_enabled_buttons(
1069 winit::window::WindowButtons::from_bits(description.enabled_window_buttons.bits())
1070 .unwrap(),
1071 )
1072}
1073
1074#[allow(unused_variables)]
1075pub fn load_default_cursors(event_loop: &ActiveEventLoop) -> HashMap<CursorIcon, CustomCursor> {
1076 #[allow(unused_mut)]
1077 let mut custom_cursors = HashMap::new();
1078
1079 #[cfg(target_os = "windows")]
1080 {
1081 let mut load_cursor = |cursor, bytes, x, y| {
1082 custom_cursors.insert(
1083 cursor,
1084 event_loop.create_custom_cursor(
1085 CustomCursor::from_rgba(bytes, 32, 32, x, y)
1086 .expect("Failed to create custom cursor"),
1087 ),
1088 );
1089 };
1090
1091 load_cursor(
1092 CursorIcon::Alias, include_bytes!("../resources/cursors/windows/aliasb"),
1094 0,
1095 0,
1096 );
1097 load_cursor(
1098 CursorIcon::Cell, include_bytes!("../resources/cursors/windows/cell"),
1100 7,
1101 7,
1102 );
1103 load_cursor(
1104 CursorIcon::ColResize,
1105 include_bytes!("../resources/cursors/windows/col_resize"),
1106 10,
1107 8,
1108 );
1109 load_cursor(
1110 CursorIcon::Copy, include_bytes!("../resources/cursors/windows/copy"),
1112 0,
1113 0,
1114 );
1115 load_cursor(
1116 CursorIcon::Grab, include_bytes!("../resources/cursors/windows/grab"),
1118 6,
1119 0,
1120 );
1121 load_cursor(
1122 CursorIcon::Grabbing, include_bytes!("../resources/cursors/windows/grabbing"),
1124 6,
1125 0,
1126 );
1127 load_cursor(
1128 CursorIcon::RowResize, include_bytes!("../resources/cursors/windows/row_resize"),
1130 9,
1131 10,
1132 );
1133 load_cursor(
1134 CursorIcon::VerticalText, include_bytes!("../resources/cursors/windows/vertical_text"),
1136 9,
1137 3,
1138 );
1139 load_cursor(
1140 CursorIcon::ZoomIn, include_bytes!("../resources/cursors/windows/zoom_in"),
1142 6,
1143 6,
1144 );
1145 load_cursor(
1146 CursorIcon::ZoomOut, include_bytes!("../resources/cursors/windows/zoom_out"),
1148 6,
1149 6,
1150 );
1151 }
1152
1153 custom_cursors
1154}