iced_winit/program/
window_manager.rs

1use crate::core::mouse;
2use crate::core::window::Id;
3use crate::core::{Point, Size};
4use crate::graphics::Compositor;
5use crate::program::{DefaultStyle, Program, State};
6
7use iced_futures::core::Element;
8use std::collections::BTreeMap;
9use std::sync::{Arc, Mutex};
10use winit::monitor::MonitorHandle;
11
12#[allow(missing_debug_implementations)]
13pub struct WindowManager<P, C>
14where
15    P: Program,
16    C: Compositor<Renderer = P::Renderer>,
17    P::Theme: DefaultStyle,
18{
19    pub(crate) aliases: BTreeMap<winit::window::WindowId, Id>,
20    entries: BTreeMap<Id, Window<P, C>>,
21}
22
23impl<P, C> WindowManager<P, C>
24where
25    P: Program,
26    C: Compositor<Renderer = P::Renderer>,
27    P::Theme: DefaultStyle,
28{
29    pub fn new() -> Self {
30        Self {
31            aliases: BTreeMap::new(),
32            entries: BTreeMap::new(),
33        }
34    }
35
36    pub fn insert(
37        &mut self,
38        id: Id,
39        window: Arc<dyn winit::window::Window>,
40        application: &P,
41        compositor: &mut C,
42        exit_on_close_request: bool,
43        resize_border: u32,
44    ) -> &mut Window<P, C> {
45        let state = State::new(application, id, window.as_ref());
46        let viewport_version = state.viewport_version();
47        let physical_size = state.physical_size();
48        let surface = compositor.create_surface(
49            window.clone(),
50            physical_size.width,
51            physical_size.height,
52        );
53        let renderer = compositor.create_renderer();
54
55        let _ = self.aliases.insert(window.id(), id);
56
57        let drag_resize_window_func = super::drag_resize::event_func(
58            window.as_ref(),
59            resize_border as f64 * window.scale_factor(),
60        );
61
62        let _ = self.entries.insert(
63            id,
64            Window {
65                raw: window,
66                state,
67                viewport_version,
68                exit_on_close_request,
69                drag_resize_window_func,
70                surface,
71                renderer,
72                mouse_interaction: mouse::Interaction::None,
73                prev_dnd_destination_rectangles_count: 0,
74                resize_enabled: false,
75                redraw_requested: false,
76            },
77        );
78
79        self.entries
80            .get_mut(&id)
81            .expect("Get window that was just inserted")
82    }
83
84    pub fn is_empty(&self) -> bool {
85        self.entries.is_empty()
86    }
87
88    pub fn first(&self) -> Option<&Window<P, C>> {
89        self.entries.first_key_value().map(|(_id, window)| window)
90    }
91
92    pub fn iter_mut(
93        &mut self,
94    ) -> impl Iterator<Item = (Id, &mut Window<P, C>)> {
95        self.entries.iter_mut().map(|(k, v)| (*k, v))
96    }
97
98    pub fn get(&self, id: Id) -> Option<&Window<P, C>> {
99        self.entries.get(&id)
100    }
101
102    pub fn get_mut(&mut self, id: Id) -> Option<&mut Window<P, C>> {
103        self.entries.get_mut(&id)
104    }
105
106    pub fn ids(&self) -> impl Iterator<Item = Id> + '_ {
107        self.entries.keys().cloned()
108    }
109
110    pub fn get_mut_alias(
111        &mut self,
112        id: winit::window::WindowId,
113    ) -> Option<(Id, &mut Window<P, C>)> {
114        let id = self.aliases.get(&id).copied()?;
115
116        Some((id, self.get_mut(id)?))
117    }
118
119    pub fn last_monitor(&self) -> Option<MonitorHandle> {
120        self.entries.values().last()?.raw.current_monitor()
121    }
122
123    pub fn remove(&mut self, id: Id) -> Option<Window<P, C>> {
124        let window = self.entries.remove(&id)?;
125        let _ = self.aliases.remove(&window.raw.id());
126
127        Some(window)
128    }
129}
130
131impl<P, C> Default for WindowManager<P, C>
132where
133    P: Program,
134    C: Compositor<Renderer = P::Renderer>,
135    P::Theme: DefaultStyle,
136{
137    fn default() -> Self {
138        Self::new()
139    }
140}
141
142pub(crate) enum Frame {
143    None,
144    Waiting,
145    Ready,
146}
147
148pub(crate) type ViewFn<M, T, R> = Arc<
149    Box<dyn Fn() -> Option<Element<'static, M, T, R>> + Send + Sync + 'static>,
150>;
151
152#[allow(missing_debug_implementations)]
153pub struct Window<P, C>
154where
155    P: Program,
156    C: Compositor<Renderer = P::Renderer>,
157    P::Theme: DefaultStyle,
158{
159    pub raw: Arc<dyn winit::window::Window>,
160    pub(crate) state: State<P>,
161    pub viewport_version: u64,
162    pub exit_on_close_request: bool,
163    pub drag_resize_window_func: Option<
164        Box<
165            dyn FnMut(
166                &dyn winit::window::Window,
167                &winit::event::WindowEvent,
168            ) -> bool,
169        >,
170    >,
171    pub prev_dnd_destination_rectangles_count: usize,
172    pub mouse_interaction: mouse::Interaction,
173    pub surface: C::Surface,
174    pub renderer: P::Renderer,
175    pub resize_enabled: bool,
176    pub(crate) redraw_requested: bool,
177}
178
179impl<P, C> Window<P, C>
180where
181    P: Program,
182    C: Compositor<Renderer = P::Renderer>,
183    P::Theme: DefaultStyle,
184{
185    pub fn position(&self) -> Option<Point> {
186        self.raw
187            .inner_position()
188            .ok()
189            .map(|position| position.to_logical(self.raw.scale_factor()))
190            .map(|position| Point {
191                x: position.x,
192                y: position.y,
193            })
194    }
195
196    pub fn size(&self) -> Size {
197        let size = self.raw.surface_size().to_logical(self.raw.scale_factor());
198
199        Size::new(size.width, size.height)
200    }
201
202    pub fn request_redraw(&mut self) {
203        if !self.redraw_requested {
204            self.redraw_requested = true;
205            self.raw.request_redraw();
206        }
207    }
208
209    // pub fn with_view<T>(
210    //     &self,
211    //     f: impl Fn(&ViewFn<P::Message, P::Message, P::Message>) -> T,
212    // ) -> Option<T>
213    // where
214    //     P::Message: 'static,
215    // {
216    //     self.view_fn.as_ref().and_then(|m| {
217    //         let g = m.lock().unwrap();
218    //         g.downcast_ref().map(|v| f(v))
219    //     })
220    // }
221}