diff options
Diffstat (limited to 'winit/src/multi_window')
-rw-r--r-- | winit/src/multi_window/state.rs | 96 | ||||
-rw-r--r-- | winit/src/multi_window/windows.rs | 170 |
2 files changed, 230 insertions, 36 deletions
diff --git a/winit/src/multi_window/state.rs b/winit/src/multi_window/state.rs index 54a114ad..f2741c3c 100644 --- a/winit/src/multi_window/state.rs +++ b/winit/src/multi_window/state.rs @@ -1,33 +1,50 @@ -use crate::application::{self, StyleSheet as _}; use crate::conversion; +use crate::core; +use crate::core::{mouse, window}; +use crate::core::{Color, Size}; +use crate::graphics::Viewport; use crate::multi_window::Application; -use crate::window; -use crate::{Color, Debug, Point, Size, Viewport}; +use crate::style::application; +use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; +use iced_style::application::StyleSheet; use winit::event::{Touch, WindowEvent}; use winit::window::Window; /// The state of a multi-windowed [`Application`]. -#[allow(missing_debug_implementations)] pub struct State<A: Application> where - <A::Renderer as crate::Renderer>::Theme: application::StyleSheet, + <A::Renderer as core::Renderer>::Theme: application::StyleSheet, { title: String, scale_factor: f64, viewport: Viewport, - viewport_changed: bool, - cursor_position: winit::dpi::PhysicalPosition<f64>, + viewport_version: usize, + cursor_position: Option<winit::dpi::PhysicalPosition<f64>>, modifiers: winit::event::ModifiersState, - theme: <A::Renderer as crate::Renderer>::Theme, + theme: <A::Renderer as core::Renderer>::Theme, appearance: application::Appearance, - application: PhantomData<A>, +} + +impl<A: Application> Debug for State<A> +where + <A::Renderer as core::Renderer>::Theme: application::StyleSheet, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("multi_window::State") + .field("title", &self.title) + .field("scale_factor", &self.scale_factor) + .field("viewport", &self.viewport) + .field("viewport_version", &self.viewport_version) + .field("cursor_position", &self.cursor_position) + .field("appearance", &self.appearance) + .finish() + } } impl<A: Application> State<A> where - <A::Renderer as crate::Renderer>::Theme: application::StyleSheet, + <A::Renderer as core::Renderer>::Theme: application::StyleSheet, { /// Creates a new [`State`] for the provided [`Application`]'s `window`. pub fn new( @@ -53,13 +70,11 @@ where title, scale_factor, viewport, - viewport_changed: false, - // TODO: Encode cursor availability in the type-system - cursor_position: winit::dpi::PhysicalPosition::new(-1.0, -1.0), + viewport_version: 0, + cursor_position: None, modifiers: winit::event::ModifiersState::default(), theme, appearance, - application: PhantomData, } } @@ -68,9 +83,11 @@ where &self.viewport } - /// Returns whether or not the viewport changed. - pub fn viewport_changed(&self) -> bool { - self.viewport_changed + /// Returns the version of the [`Viewport`] of the [`State`]. + /// + /// The version is incremented every time the [`Viewport`] changes. + pub fn viewport_version(&self) -> usize { + self.viewport_version } /// Returns the physical [`Size`] of the [`Viewport`] of the [`State`]. @@ -89,11 +106,16 @@ where } /// Returns the current cursor position of the [`State`]. - pub fn cursor_position(&self) -> Point { - conversion::cursor_position( - self.cursor_position, - self.viewport.scale_factor(), - ) + pub fn cursor(&self) -> mouse::Cursor { + self.cursor_position + .map(|cursor_position| { + conversion::cursor_position( + cursor_position, + self.viewport.scale_factor(), + ) + }) + .map(mouse::Cursor::Available) + .unwrap_or(mouse::Cursor::Unavailable) } /// Returns the current keyboard modifiers of the [`State`]. @@ -102,7 +124,7 @@ where } /// Returns the current theme of the [`State`]. - pub fn theme(&self) -> &<A::Renderer as crate::Renderer>::Theme { + pub fn theme(&self) -> &<A::Renderer as core::Renderer>::Theme { &self.theme } @@ -121,7 +143,7 @@ where &mut self, window: &Window, event: &WindowEvent<'_>, - _debug: &mut Debug, + _debug: &mut crate::runtime::Debug, ) { match event { WindowEvent::Resized(new_size) => { @@ -132,7 +154,7 @@ where window.scale_factor() * self.scale_factor, ); - self.viewport_changed = true; + self.viewport_version = self.viewport_version.wrapping_add(1); } WindowEvent::ScaleFactorChanged { scale_factor: new_scale_factor, @@ -146,18 +168,16 @@ where new_scale_factor * self.scale_factor, ); - self.viewport_changed = true; + self.viewport_version = self.viewport_version.wrapping_add(1); } WindowEvent::CursorMoved { position, .. } | WindowEvent::Touch(Touch { location: position, .. }) => { - self.cursor_position = *position; + self.cursor_position = Some(*position); } WindowEvent::CursorLeft { .. } => { - // TODO: Encode cursor availability in the type-system - self.cursor_position = - winit::dpi::PhysicalPosition::new(-1.0, -1.0); + self.cursor_position = None; } WindowEvent::ModifiersChanged(new_modifiers) => { self.modifiers = *new_modifiers; @@ -197,16 +217,20 @@ where self.title = new_title; } - // Update scale factor + // Update scale factor and size let new_scale_factor = application.scale_factor(window_id); + let new_size = window.inner_size(); + let current_size = self.viewport.physical_size(); - if self.scale_factor != new_scale_factor { - let size = window.inner_size(); - + if self.scale_factor != new_scale_factor + || (current_size.width, current_size.height) + != (new_size.width, new_size.height) + { self.viewport = Viewport::with_physical_size( - Size::new(size.width, size.height), + Size::new(new_size.width, new_size.height), window.scale_factor() * new_scale_factor, ); + self.viewport_version = self.viewport_version.wrapping_add(1); self.scale_factor = new_scale_factor; } diff --git a/winit/src/multi_window/windows.rs b/winit/src/multi_window/windows.rs new file mode 100644 index 00000000..7b63defa --- /dev/null +++ b/winit/src/multi_window/windows.rs @@ -0,0 +1,170 @@ +use crate::core::{window, Size}; +use crate::multi_window::{Application, State}; +use iced_graphics::Compositor; +use iced_style::application::StyleSheet; +use std::fmt::{Debug, Formatter}; +use winit::monitor::MonitorHandle; + +pub struct Windows<A: Application, C: Compositor> +where + <A::Renderer as crate::core::Renderer>::Theme: StyleSheet, + C: Compositor<Renderer = A::Renderer>, +{ + pub ids: Vec<window::Id>, + pub raw: Vec<winit::window::Window>, + pub states: Vec<State<A>>, + pub viewport_versions: Vec<usize>, + pub surfaces: Vec<C::Surface>, + pub renderers: Vec<A::Renderer>, + pub pending_destroy: Vec<(window::Id, winit::window::WindowId)>, +} + +impl<A: Application, C: Compositor> Debug for Windows<A, C> +where + <A::Renderer as crate::core::Renderer>::Theme: StyleSheet, + C: Compositor<Renderer = A::Renderer>, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Windows") + .field("ids", &self.ids) + .field( + "raw", + &self + .raw + .iter() + .map(|raw| raw.id()) + .collect::<Vec<winit::window::WindowId>>(), + ) + .field("states", &self.states) + .field("viewport_versions", &self.viewport_versions) + .finish() + } +} + +impl<A: Application, C: Compositor> Windows<A, C> +where + <A::Renderer as crate::core::Renderer>::Theme: StyleSheet, + C: Compositor<Renderer = A::Renderer>, +{ + /// Creates a new [`Windows`] with a single `window::Id::MAIN` window. + pub fn new( + application: &A, + compositor: &mut C, + renderer: A::Renderer, + main: winit::window::Window, + ) -> Self { + let state = State::new(application, window::Id::MAIN, &main); + let viewport_version = state.viewport_version(); + let physical_size = state.physical_size(); + let surface = compositor.create_surface( + &main, + physical_size.width, + physical_size.height, + ); + + Self { + ids: vec![window::Id::MAIN], + raw: vec![main], + states: vec![state], + viewport_versions: vec![viewport_version], + surfaces: vec![surface], + renderers: vec![renderer], + pending_destroy: vec![], + } + } + + /// Adds a new window to [`Windows`]. Returns the size of the newly created window in logical + /// pixels & the index of the window within [`Windows`]. + pub fn add( + &mut self, + application: &A, + compositor: &mut C, + id: window::Id, + window: winit::window::Window, + ) -> (Size, usize) { + let state = State::new(application, id, &window); + let window_size = state.logical_size(); + let viewport_version = state.viewport_version(); + let physical_size = state.physical_size(); + let surface = compositor.create_surface( + &window, + physical_size.width, + physical_size.height, + ); + let renderer = compositor.renderer(); + + self.ids.push(id); + self.raw.push(window); + self.states.push(state); + self.viewport_versions.push(viewport_version); + self.surfaces.push(surface); + self.renderers.push(renderer); + + (window_size, self.ids.len() - 1) + } + + pub fn is_empty(&self) -> bool { + self.ids.is_empty() + } + + pub fn main(&self) -> &winit::window::Window { + &self.raw[0] + } + + pub fn index_from_raw(&self, id: winit::window::WindowId) -> usize { + self.raw + .iter() + .position(|window| window.id() == id) + .expect("No raw window in multi_window::Windows") + } + + pub fn index_from_id(&self, id: window::Id) -> usize { + self.ids + .iter() + .position(|window_id| *window_id == id) + .expect("No window in multi_window::Windows") + } + + pub fn last_monitor(&self) -> Option<MonitorHandle> { + self.raw.last().and_then(|w| w.current_monitor()) + } + + pub fn last(&self) -> usize { + self.ids.len() - 1 + } + + pub fn with_raw(&self, id: window::Id) -> &winit::window::Window { + let i = self.index_from_id(id); + &self.raw[i] + } + + /// Deletes the window with `id` from [`Windows`]. Returns the index that the window had. + pub fn delete(&mut self, id: window::Id) -> usize { + let i = self.index_from_id(id); + + let id = self.ids.remove(i); + let window = self.raw.remove(i); + let _ = self.states.remove(i); + let _ = self.viewport_versions.remove(i); + let _ = self.surfaces.remove(i); + + self.pending_destroy.push((id, window.id())); + + i + } + + /// Gets the winit `window` that is pending to be destroyed if it exists. + pub fn get_pending_destroy( + &mut self, + window: winit::window::WindowId, + ) -> window::Id { + let i = self + .pending_destroy + .iter() + .position(|(_, window_id)| window == *window_id) + .unwrap(); + + let (id, _) = self.pending_destroy.remove(i); + id + } +} |