From c2644cb0bedf8168930636531dd3b5b32c1fe996 Mon Sep 17 00:00:00 2001 From: Robin Quint Date: Fri, 4 Mar 2022 13:10:43 +0100 Subject: [PATCH] imgui-winit-support now uses external storage for extra windows --- imgui-winit-support/src/lib.rs | 171 ++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 75 deletions(-) diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 6955544..a7a14b6 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -189,8 +189,8 @@ use winit_20 as winit; use winit_19 as winit; use imgui::{self, BackendFlags, ConfigFlags, Context, Io, Key, Ui}; -use std::{cell::Cell, collections::HashMap}; use std::cmp::Ordering; +use std::{cell::Cell, collections::HashMap}; use winit::dpi::{LogicalPosition, LogicalSize}; #[cfg(all( @@ -342,9 +342,6 @@ pub struct WinitPlatform { hidpi_factor: f64, cursor_cache: Option, mouse_buttons: [Button; 5], - - #[cfg(feature = "viewports")] - windows: HashMap, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -476,47 +473,47 @@ impl imgui::PlatformViewportBackend for ViewportBackend { } fn show_window(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_show = true; } fn set_window_pos(&mut self, viewport: &mut imgui::Viewport, pos: [f32; 2]) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_pos = Some(pos); } fn get_window_pos(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.pos } fn set_window_size(&mut self, viewport: &mut imgui::Viewport, size: [f32; 2]) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_size = Some(size); } fn get_window_size(&mut self, viewport: &mut imgui::Viewport) -> [f32; 2] { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.size } fn set_window_focus(&mut self, viewport: &mut imgui::Viewport) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_focus = true; } fn get_window_focus(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.focus } fn get_window_minimized(&mut self, viewport: &mut imgui::Viewport) -> bool { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.minimized } fn set_window_title(&mut self, viewport: &mut imgui::Viewport, title: &str) { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; state.set_title = Some(title.to_string()); } @@ -528,7 +525,14 @@ impl imgui::PlatformViewportBackend for ViewportBackend { fn swap_buffers(&mut self, _viewport: &mut imgui::Viewport) {} - fn create_vk_surface(&mut self, _viewport: &mut imgui::Viewport, _instance: u64, _out_surface: &mut u64) -> i32 { 0 } + fn create_vk_surface( + &mut self, + _viewport: &mut imgui::Viewport, + _instance: u64, + _out_surface: &mut u64, + ) -> i32 { + 0 + } } #[cfg(feature = "viewports")] @@ -548,6 +552,18 @@ struct ViewportState { minimized: bool, } +#[cfg(feature = "viewports")] +pub trait WinitPlatformViewportStorage { + fn create_window(&mut self, id: imgui::Id, flags: imgui::ViewportFlags); + fn remove_windows(&mut self, filter: impl Fn(imgui::Id) -> bool); + fn get_window( + &mut self, + id: winit::window::WindowId, + ) -> Option<(imgui::Id, &winit::window::Window)>; + + fn for_each(&mut self, func: impl FnMut(imgui::Id, &winit::window::Window)); +} + impl WinitPlatform { /// Initializes a winit platform instance and configures imgui. /// @@ -593,17 +609,19 @@ impl WinitPlatform { hidpi_factor: 1.0, cursor_cache: None, mouse_buttons: [Button::INIT; 5], - - #[cfg(feature = "viewports")] - windows: HashMap::new(), } } #[cfg(feature = "viewports")] - pub fn init_viewports(imgui: &mut Context, main_window: &winit::window::Window, event_loop: &winit::event_loop::EventLoop) { + pub fn init_viewports( + imgui: &mut Context, + main_window: &winit::window::Window, + event_loop: &winit::event_loop::EventLoop, + ) { let io = imgui.io_mut(); - io.backend_flags.insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); + io.backend_flags + .insert(BackendFlags::PLATFORM_HAS_VIEWPORTS); imgui.set_platform_backend(ViewportBackend {}); @@ -617,7 +635,10 @@ impl WinitPlatform { dpi_scale: 1.0, }); } - imgui.platform_io_mut().monitors.replace_from_slice(&monitors); + imgui + .platform_io_mut() + .monitors + .replace_from_slice(&monitors); let pos = main_window.inner_position().unwrap(); let pos = [pos.x as f32, pos.y as f32]; @@ -641,42 +662,38 @@ impl WinitPlatform { } #[cfg(feature = "viewports")] - pub fn update_viewports(&mut self, imgui: &mut Context, window_target: &winit::event_loop::EventLoopWindowTarget) { + pub fn update_viewports( + &mut self, + imgui: &mut Context, + storage: &mut impl WinitPlatformViewportStorage, + ) { // remove destroyed windows - self.windows.retain(|id, _| { - imgui.viewports().any(|vp| vp.id == *id) - }); + storage.remove_windows(|id| !imgui.viewports().any(|vp| vp.id == id)); // handle new viewports for viewport in imgui.viewports_mut() { - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; if state.create { - let window = winit::window::WindowBuilder::new() - .with_always_on_top(state.create_flags.contains(imgui::ViewportFlags::TOP_MOST)) - // .with_decorations(!state.create_flags.contains(imgui::ViewportFlags::NO_DECORATION)) - .with_resizable(true) - .with_visible(false) - .build(window_target) - .unwrap(); - - self.windows.insert(viewport.id, window); - + storage.create_window(viewport.id, viewport.flags); state.create = false; } } // handle other viewport events - for (id, wnd) in &self.windows { - let viewport = imgui.viewport_by_id_mut(*id).unwrap(); - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + storage.for_each(|id, wnd| { + let viewport = imgui.viewport_by_id_mut(id).unwrap(); + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; if let Some(pos) = &state.set_pos { let wnd_pos = wnd.outer_position().unwrap(); let inner_pos = wnd.inner_position().unwrap(); let decoration_size = [inner_pos.x - wnd_pos.x, inner_pos.y - wnd_pos.y]; - wnd.set_outer_position(winit::dpi::LogicalPosition::new(pos[0] - decoration_size[0] as f32, pos[1] - decoration_size[1] as f32)); + wnd.set_outer_position(winit::dpi::LogicalPosition::new( + pos[0] - decoration_size[0] as f32, + pos[1] - decoration_size[1] as f32, + )); state.set_pos = None; } if let Some(size) = &state.set_size { @@ -695,7 +712,7 @@ impl WinitPlatform { wnd.set_title(title); state.set_title = None; } - } + }); } /// Attaches the platform instance to a winit window. @@ -1055,33 +1072,33 @@ impl WinitPlatform { } } #[cfg(feature = "viewports")] - pub fn handle_viewport_event(&mut self, imgui: &mut imgui::Context, main_window: &Window, event: &Event) { - if let Event::WindowEvent { window_id, ref event } = *event { - let window = if window_id == main_window.id() { - Some(main_window) + pub fn handle_viewport_event( + &mut self, + imgui: &mut imgui::Context, + main_window: &Window, + storage: &mut impl WinitPlatformViewportStorage, + event: &Event, + ) { + if let Event::WindowEvent { + window_id, + ref event, + } = *event + { + let (viewport, window) = if window_id == main_window.id() { + (imgui.main_viewport_mut(), main_window) } else { - self.windows.iter().find_map(|(_, wnd)| (wnd.id() == window_id).then(|| wnd)) - }; - let window = if let Some(window) = window { - window - } else { - return; - }; - - let viewport = { - if window_id == main_window.id() { - Some(imgui.main_viewport_mut()) + if let Some((viewport_id, window)) = storage.get_window(window_id) { + if let Some(viewport) = imgui.viewport_by_id_mut(viewport_id) { + (viewport, window) + } else { + return; + } } else { - self.windows.iter().find(|(_, wnd)| wnd.id() == window_id).map(|(id, _)| *id).and_then(|id| imgui.viewport_by_id_mut(id)) + return; } }; - let viewport = if let Some(viewport) = viewport { - viewport - } else { - return; - }; - let state = unsafe{&mut *(viewport.platform_user_data as *mut ViewportState)}; + let state = unsafe { &mut *(viewport.platform_user_data as *mut ViewportState) }; match *event { WindowEvent::Resized(new_size) => { @@ -1091,22 +1108,25 @@ impl WinitPlatform { } else { state.minimized = false; } - }, + } WindowEvent::Moved(_new_pos) => { let pos = window.inner_position().unwrap(); state.pos = [pos.x as f32, pos.y as f32]; - }, + } WindowEvent::CloseRequested => { viewport.platform_request_close = true; - }, + } WindowEvent::Focused(focus) => { state.focus = focus; - }, + } WindowEvent::CursorMoved { position, .. } => { let wnd_pos = window.inner_position().unwrap(); - let pos = [wnd_pos.x as f32 + position.x as f32, wnd_pos.y as f32 + position.y as f32]; + let pos = [ + wnd_pos.x as f32 + position.x as f32, + wnd_pos.y as f32 + position.y as f32, + ]; imgui.io_mut().mouse_pos = pos; - }, + } WindowEvent::KeyboardInput { input: KeyboardInput { @@ -1120,19 +1140,21 @@ impl WinitPlatform { let pressed = state == ElementState::Pressed; io.keys_down[key as usize] = pressed; - + // This is a bit redundant here, but we'll leave it in. The OS occasionally // fails to send modifiers keys, but it doesn't seem to send false-positives, // so double checking isn't terrible in case some system *doesn't* send // device events sometimes. match key { VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed, - VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed, + VirtualKeyCode::LControl | VirtualKeyCode::RControl => { + io.key_ctrl = pressed + } VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed, VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed, _ => (), } - }, + } WindowEvent::ReceivedCharacter(ch) if window_id != main_window.id() => { let io = imgui.io_mut(); @@ -1141,7 +1163,7 @@ impl WinitPlatform { if ch != '\u{7f}' { io.add_input_character(ch) } - }, + } WindowEvent::MouseWheel { delta, phase: TouchPhase::Moved, @@ -1178,13 +1200,12 @@ impl WinitPlatform { } _ => (), } - }, - _ => {}, + } + _ => {} } } } - #[cfg(all( not(any( feature = "winit-26",