diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 40e756c0..efd8135c 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -229,8 +229,9 @@ impl EpiIntegration { pub fn on_window_event( &mut self, - event: &winit::event::WindowEvent<'_>, + window: &winit::window::Window, egui_winit: &mut egui_winit::State, + event: &winit::event::WindowEvent<'_>, ) -> EventResponse { crate::profile_function!(egui_winit::short_window_event_description(event)); @@ -254,6 +255,7 @@ impl EpiIntegration { _ => {} } + egui_winit.update_pixels_per_point(&self.egui_ctx, window); egui_winit.on_window_event(&self.egui_ctx, event) } diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 9a820bec..4a975401 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -18,10 +18,6 @@ use egui::{ }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; -use egui_winit::{ - apply_viewport_builder_to_new_window, create_winit_window_builder, process_viewport_commands, - EventResponse, -}; use crate::{ native::{epi_integration::EpiIntegration, winit_integration::create_egui_context}, @@ -513,11 +509,13 @@ impl GlowWinitRunning { let (raw_input, viewport_ui_cb) = { let mut glutin = self.glutin.borrow_mut(); + let egui_ctx = glutin.egui_ctx.clone(); let viewport = glutin.viewports.get_mut(&viewport_id).unwrap(); - viewport.update_viewport_info(); let window = viewport.window.as_ref().unwrap(); + egui_winit::update_viewport_info(&mut viewport.info, &egui_ctx, window); let egui_winit = viewport.egui_winit.as_mut().unwrap(); + egui_winit.update_pixels_per_point(&egui_ctx, window); let mut raw_input = egui_winit.take_egui_input(window); let viewport_ui_cb = viewport.viewport_ui_cb.clone(); @@ -744,15 +742,17 @@ impl GlowWinitRunning { return EventResult::Exit; } - let mut event_response = EventResponse { + let mut event_response = egui_winit::EventResponse { consumed: false, repaint: false, }; if let Some(viewport_id) = viewport_id { if let Some(viewport) = glutin.viewports.get_mut(&viewport_id) { - event_response = self - .integration - .on_window_event(event, viewport.egui_winit.as_mut().unwrap()); + if let (Some(window), Some(egui_winit)) = + (&viewport.window, &mut viewport.egui_winit) + { + event_response = self.integration.on_window_event(window, egui_winit, event); + } } } @@ -823,7 +823,7 @@ impl GlutinWindowContext { let display_builder = glutin_winit::DisplayBuilder::new() // we might want to expose this option to users in the future. maybe using an env var or using native_options. .with_preference(glutin_winit::ApiPrefence::FallbackEgl) // https://github.com/emilk/egui/issues/2520#issuecomment-1367841150 - .with_window_builder(Some(create_winit_window_builder( + .with_window_builder(Some(egui_winit::create_winit_window_builder( egui_ctx, event_loop, viewport_builder.clone(), @@ -849,7 +849,7 @@ impl GlutinWindowContext { .map_err(|e| crate::Error::NoGlutinConfigs(config_template_builder.build(), e))? }; if let Some(window) = &window { - apply_viewport_builder_to_new_window(window, &viewport_builder); + egui_winit::apply_viewport_builder_to_window(egui_ctx, window, &viewport_builder); } let gl_display = gl_config.display(); @@ -981,12 +981,18 @@ impl GlutinWindowContext { window } else { log::trace!("Window doesn't exist yet. Creating one now with finalize_window"); - let window = glutin_winit::finalize_window( + let window_builder = egui_winit::create_winit_window_builder( + &self.egui_ctx, event_loop, - create_winit_window_builder(&self.egui_ctx, event_loop, viewport.builder.clone()), - &self.gl_config, - )?; - apply_viewport_builder_to_new_window(&window, &viewport.builder); + viewport.builder.clone(), + ); + let window = + glutin_winit::finalize_window(event_loop, window_builder, &self.gl_config)?; + egui_winit::apply_viewport_builder_to_window( + &self.egui_ctx, + &window, + &viewport.builder, + ); viewport.info.minimized = window.is_minimized(); viewport.info.maximized = Some(window.is_maximized()); viewport.window.insert(Rc::new(window)) @@ -1167,19 +1173,6 @@ impl GlutinWindowContext { } } -impl Viewport { - /// Update the stored `ViewportInfo`. - fn update_viewport_info(&mut self) { - let Some(window) = &self.window else { - return; - }; - let Some(egui_winit) = &self.egui_winit else { - return; - }; - egui_winit.update_viewport_info(&mut self.info, window); - } -} - fn initialize_or_update_viewport<'vp>( egu_ctx: &'_ egui::Context, viewports: &'vp mut ViewportIdMap, @@ -1235,7 +1228,7 @@ fn initialize_or_update_viewport<'vp>( viewport.egui_winit = None; } else if let Some(window) = &viewport.window { let is_viewport_focused = focused_viewport == Some(ids.this); - process_viewport_commands( + egui_winit::process_viewport_commands( egu_ctx, &mut viewport.info, delta_commands, @@ -1294,15 +1287,16 @@ fn render_immediate_viewport( let Some(viewport) = glutin.viewports.get_mut(&ids.this) else { return; }; - viewport.update_viewport_info(); - let Some(winit_state) = &mut viewport.egui_winit else { + let Some(egui_winit) = &mut viewport.egui_winit else { return; }; let Some(window) = &viewport.window else { return; }; + egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window); - let mut raw_input = winit_state.take_egui_input(window); + egui_winit.update_pixels_per_point(egui_ctx, window); + let mut raw_input = egui_winit.take_egui_input(window); raw_input.viewports = glutin .viewports .iter() diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index 07e36f96..044f86dd 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -14,9 +14,6 @@ use egui::{ }; #[cfg(feature = "accesskit")] use egui_winit::accesskit_winit; -use egui_winit::{ - apply_viewport_builder_to_new_window, create_winit_window_builder, process_viewport_commands, -}; use crate::{ native::{epi_integration::EpiIntegration, winit_integration::EventResult}, @@ -485,7 +482,10 @@ impl WgpuWinitRunning { let mut shared_lock = shared.borrow_mut(); let SharedState { - viewports, painter, .. + egui_ctx, + viewports, + painter, + .. } = &mut *shared_lock; if viewport_id != ViewportId::ROOT { @@ -508,12 +508,12 @@ impl WgpuWinitRunning { let Some(viewport) = viewports.get_mut(&viewport_id) else { return EventResult::Wait; }; - viewport.update_viewport_info(); let Viewport { viewport_ui_cb, window, egui_winit, + info, .. } = viewport; @@ -522,6 +522,7 @@ impl WgpuWinitRunning { let Some(window) = window else { return EventResult::Wait; }; + egui_winit::update_viewport_info(info, &integration.egui_ctx, window); { crate::profile_scope!("set_window"); @@ -531,7 +532,9 @@ impl WgpuWinitRunning { } } - let mut raw_input = egui_winit.as_mut().unwrap().take_egui_input(window); + let egui_winit = egui_winit.as_mut().unwrap(); + egui_winit.update_pixels_per_point(egui_ctx, window); + let mut raw_input = egui_winit.take_egui_input(window); integration.pre_update(); @@ -745,10 +748,11 @@ impl WgpuWinitRunning { let event_response = viewport_id .and_then(|viewport_id| { shared.viewports.get_mut(&viewport_id).and_then(|viewport| { - viewport - .egui_winit - .as_mut() - .map(|egui_winit| integration.on_window_event(event, egui_winit)) + Some(integration.on_window_event( + viewport.window.as_deref()?, + viewport.egui_winit.as_mut()?, + event, + )) }) }) .unwrap_or_default(); @@ -779,12 +783,8 @@ impl Viewport { let viewport_id = self.ids.this; - match create_winit_window_builder(egui_ctx, event_loop, self.builder.clone()) - .build(event_loop) - { + match egui_winit::create_window(egui_ctx, event_loop, &self.builder) { Ok(window) => { - apply_viewport_builder_to_new_window(&window, &self.builder); - windows_id.insert(window.id(), viewport_id); if let Err(err) = pollster::block_on(painter.set_window(viewport_id, Some(&window))) @@ -809,18 +809,6 @@ impl Viewport { } } } - - /// Update the stored `ViewportInfo`. - pub fn update_viewport_info(&mut self) { - crate::profile_function!(); - let Some(window) = &self.window else { - return; - }; - let Some(egui_winit) = &self.egui_winit else { - return; - }; - egui_winit.update_viewport_info(&mut self.info, window); - } } fn create_window( @@ -840,12 +828,7 @@ fn create_window( ) .with_visible(false); // Start hidden until we render the first frame to fix white flash on startup (https://github.com/emilk/egui/pull/3631) - let window = { - crate::profile_scope!("WindowBuilder::build"); - create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone()) - .build(event_loop)? - }; - apply_viewport_builder_to_new_window(&window, &viewport_builder); + let window = egui_winit::create_window(egui_ctx, event_loop, &viewport_builder)?; epi_integration::apply_window_settings(&window, window_settings); Ok((window, viewport_builder)) } @@ -885,12 +868,13 @@ fn render_immediate_viewport( if viewport.window.is_none() { viewport.init_window(egui_ctx, viewport_from_window, painter, event_loop); } - viewport.update_viewport_info(); let (Some(window), Some(winit_state)) = (&viewport.window, &mut viewport.egui_winit) else { return; }; + egui_winit::update_viewport_info(&mut viewport.info, egui_ctx, window); + winit_state.update_pixels_per_point(egui_ctx, window); let mut input = winit_state.take_egui_input(window); input.viewports = viewports .iter() @@ -1056,7 +1040,7 @@ fn initialize_or_update_viewport<'vp>( viewport.egui_winit = None; } else if let Some(window) = &viewport.window { let is_viewport_focused = focused_viewport == Some(ids.this); - process_viewport_commands( + egui_winit::process_viewport_commands( egui_ctx, &mut viewport.info, delta_commands, diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index e00083c5..f22dd81d 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -38,6 +38,13 @@ pub fn screen_size_in_pixels(window: &Window) -> egui::Vec2 { egui::vec2(size.width as f32, size.height as f32) } +/// Calculate the `pixels_per_point` for a given window, given the current egui zoom factor +pub fn pixels_per_point(egui_ctx: &egui::Context, window: &Window) -> f32 { + let native_pixels_per_point = window.scale_factor() as f32; + let egui_zoom_factor = egui_ctx.zoom_factor(); + egui_zoom_factor * native_pixels_per_point +} + // ---------------------------------------------------------------------------- #[must_use] @@ -70,7 +77,7 @@ pub struct State { current_cursor_icon: Option, /// What egui uses. - current_pixels_per_point: f32, + current_pixels_per_point: f32, // TODO: remove - calculate with [`pixels_per_point`] instead clipboard: clipboard::Clipboard, @@ -164,9 +171,8 @@ impl State { self.egui_input.max_texture_side = Some(max_texture_side); } - /// The number of physical pixels per logical point, - /// as configured on the current egui context (see [`egui::Context::pixels_per_point`]). #[inline] + #[deprecated = "Use egui_winit::pixels_per_point instead"] pub fn pixels_per_point(&self) -> f32 { self.current_pixels_per_point } @@ -186,10 +192,9 @@ impl State { } /// Update the given viewport info with the current state of the window. - /// - /// Call before [`Self::update_viewport_info`] + #[deprecated = "Use egui_winit::update_viewport_info instead"] pub fn update_viewport_info(&self, info: &mut ViewportInfo, window: &Window) { - update_viewport_info(info, window, self.current_pixels_per_point); + update_viewport_info_impl(info, window, self.current_pixels_per_point); } /// Prepare for a new frame by extracting the accumulated input, @@ -226,6 +231,12 @@ impl State { self.egui_input.take() } + // TODO(emilk): remove asap. + #[doc(hidden)] + pub fn update_pixels_per_point(&mut self, egui_ctx: &egui::Context, window: &Window) { + self.current_pixels_per_point = pixels_per_point(egui_ctx, window); + } + /// Call this when there is a new event. /// /// The result can be found in [`Self::egui_input`] and be extracted with [`Self::take_egui_input`]. @@ -511,8 +522,8 @@ impl State { fn on_cursor_moved(&mut self, pos_in_pixels: winit::dpi::PhysicalPosition) { let pos_in_points = egui::pos2( - pos_in_pixels.x as f32 / self.pixels_per_point(), - pos_in_pixels.y as f32 / self.pixels_per_point(), + pos_in_pixels.x as f32 / self.current_pixels_per_point, + pos_in_pixels.y as f32 / self.current_pixels_per_point, ); self.pointer_pos_in_points = Some(pos_in_points); @@ -549,8 +560,8 @@ impl State { winit::event::TouchPhase::Cancelled => egui::TouchPhase::Cancel, }, pos: egui::pos2( - touch.location.x as f32 / self.pixels_per_point(), - touch.location.y as f32 / self.pixels_per_point(), + touch.location.x as f32 / self.current_pixels_per_point, + touch.location.y as f32 / self.current_pixels_per_point, ), force: match touch.force { Some(winit::event::Force::Normalized(force)) => Some(force as f32), @@ -610,7 +621,7 @@ impl State { y, }) => ( egui::MouseWheelUnit::Point, - egui::vec2(x as f32, y as f32) / self.pixels_per_point(), + egui::vec2(x as f32, y as f32) / self.current_pixels_per_point, ), }; let modifiers = self.egui_input.modifiers; @@ -626,7 +637,7 @@ impl State { egui::vec2(x, y) * points_per_scroll_line } winit::event::MouseScrollDelta::PixelDelta(delta) => { - egui::vec2(delta.x as f32, delta.y as f32) / self.pixels_per_point() + egui::vec2(delta.x as f32, delta.y as f32) / self.current_pixels_per_point } }; @@ -758,7 +769,18 @@ impl State { } } -fn update_viewport_info(viewport_info: &mut ViewportInfo, window: &Window, pixels_per_point: f32) { +/// Update the given viewport info with the current state of the window. +/// +/// Call before [`State::take_egui_input`]. +pub fn update_viewport_info(info: &mut ViewportInfo, egui_ctx: &egui::Context, window: &Window) { + update_viewport_info_impl(info, window, pixels_per_point(egui_ctx, window)); +} + +fn update_viewport_info_impl( + viewport_info: &mut ViewportInfo, + window: &Window, + pixels_per_point: f32, +) { crate::profile_function!(); let has_a_position = match window.is_minimized() { @@ -1072,8 +1094,7 @@ fn process_viewport_command( log::debug!("Processing ViewportCommand::{command:?}"); - let egui_zoom_factor = egui_ctx.zoom_factor(); - let pixels_per_point = egui_zoom_factor * window.scale_factor() as f32; + let pixels_per_point = pixels_per_point(egui_ctx, window); match command { ViewportCommand::Close => { @@ -1244,6 +1265,26 @@ fn process_viewport_command( } } +/// Build and intitlaize a window. +/// +/// Wrapper around `create_winit_window_builder` and `apply_viewport_builder_to_window`. +pub fn create_window( + egui_ctx: &egui::Context, + event_loop: &EventLoopWindowTarget, + viewport_builder: &ViewportBuilder, +) -> Result { + crate::profile_function!(); + + let window_builder = + create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone()); + let window = { + crate::profile_scope!("WindowBuilder::build"); + window_builder.build(event_loop)? + }; + apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder); + Ok(window) +} + pub fn create_winit_window_builder( egui_ctx: &egui::Context, event_loop: &EventLoopWindowTarget, @@ -1253,6 +1294,8 @@ pub fn create_winit_window_builder( // We set sizes and positions in egui:s own ui points, which depends on the egui // zoom_factor and the native pixels per point, so we need to know that here. + // We don't know what monitor the window will appear on though, but + // we'll try to fix that after the window is created in the vall to `apply_viewport_builder_to_window`. let native_pixels_per_point = event_loop .primary_monitor() .or_else(|| event_loop.available_monitors().next()) @@ -1297,7 +1340,7 @@ pub fn create_winit_window_builder( // wayland: app_id: _app_id, - mouse_passthrough: _, // handled in `apply_viewport_builder_to_new_window` + mouse_passthrough: _, // handled in `apply_viewport_builder_to_window` } = viewport_builder; let mut window_builder = winit::window::WindowBuilder::new() @@ -1330,31 +1373,31 @@ pub fn create_winit_window_builder( }) .with_active(active.unwrap_or(true)); - if let Some(inner_size) = inner_size { + if let Some(size) = inner_size { window_builder = window_builder.with_inner_size(PhysicalSize::new( - pixels_per_point * inner_size.x, - pixels_per_point * inner_size.y, + pixels_per_point * size.x, + pixels_per_point * size.y, )); } - if let Some(min_inner_size) = min_inner_size { + if let Some(size) = min_inner_size { window_builder = window_builder.with_min_inner_size(PhysicalSize::new( - pixels_per_point * min_inner_size.x, - pixels_per_point * min_inner_size.y, + pixels_per_point * size.x, + pixels_per_point * size.y, )); } - if let Some(max_inner_size) = max_inner_size { + if let Some(size) = max_inner_size { window_builder = window_builder.with_max_inner_size(PhysicalSize::new( - pixels_per_point * max_inner_size.x, - pixels_per_point * max_inner_size.y, + pixels_per_point * size.x, + pixels_per_point * size.y, )); } - if let Some(position) = position { + if let Some(pos) = position { window_builder = window_builder.with_position(PhysicalPosition::new( - pixels_per_point * position.x, - pixels_per_point * position.y, + pixels_per_point * pos.x, + pixels_per_point * pos.y, )); } @@ -1391,6 +1434,7 @@ pub fn create_winit_window_builder( } /// Applies what `create_winit_window_builder` couldn't +#[deprecated = "Use apply_viewport_builder_to_window instead"] pub fn apply_viewport_builder_to_new_window(window: &Window, builder: &ViewportBuilder) { if let Some(mouse_passthrough) = builder.mouse_passthrough { if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) { @@ -1399,6 +1443,51 @@ pub fn apply_viewport_builder_to_new_window(window: &Window, builder: &ViewportB } } +/// Applies what `create_winit_window_builder` couldn't +pub fn apply_viewport_builder_to_window( + egui_ctx: &egui::Context, + window: &Window, + builder: &ViewportBuilder, +) { + if let Some(mouse_passthrough) = builder.mouse_passthrough { + if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) { + log::warn!("set_cursor_hittest failed: {err}"); + } + } + + { + // In `create_winit_window_builder` we didn't know + // on what monitor the window would appear, so we didn't know + // how to translate egui ui point to native physical pixels. + // Now we do know: + + let pixels_per_point = pixels_per_point(egui_ctx, window); + + if let Some(size) = builder.inner_size { + window.set_inner_size(PhysicalSize::new( + pixels_per_point * size.x, + pixels_per_point * size.y, + )); + } + if let Some(size) = builder.min_inner_size { + window.set_min_inner_size(Some(PhysicalSize::new( + pixels_per_point * size.x, + pixels_per_point * size.y, + ))); + } + if let Some(size) = builder.max_inner_size { + window.set_max_inner_size(Some(PhysicalSize::new( + pixels_per_point * size.x, + pixels_per_point * size.y, + ))); + } + if let Some(pos) = builder.position { + let pos = PhysicalPosition::new(pixels_per_point * pos.x, pixels_per_point * pos.y); + window.set_outer_position(pos); + } + } +} + // --------------------------------------------------------------------------- /// Short and fast description of an event. diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 45d2e535..f811f95e 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -262,6 +262,7 @@ pub struct ViewportBuilder { /// This is wayland only. See [`Self::with_app_id`]. pub app_id: Option, + /// The desired outer position of the window. pub position: Option, pub inner_size: Option, pub min_inner_size: Option, @@ -506,7 +507,8 @@ impl ViewportBuilder { self } - /// This will probably not work as expected! + /// The initial "outer" position of the window, + /// i.e. where the top-left corner of the frame/chrome should be. #[inline] pub fn with_position(mut self, pos: impl Into) -> Self { self.position = Some(pos.into()); diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index 1ec54856..653aef07 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -40,7 +40,6 @@ impl EguiGlow { native_pixels_per_point, Some(painter.max_texture_side()), ); - let pixels_per_point = egui_winit.pixels_per_point(); Self { egui_ctx: Default::default(), @@ -48,7 +47,7 @@ impl EguiGlow { painter, viewport_info: Default::default(), shapes: Default::default(), - pixels_per_point, + pixels_per_point: native_pixels_per_point.unwrap_or(1.0), textures_delta: Default::default(), } } diff --git a/crates/epaint/src/util/ordered_float.rs b/crates/epaint/src/util/ordered_float.rs index 2c348e59..5223bd45 100644 --- a/crates/epaint/src/util/ordered_float.rs +++ b/crates/epaint/src/util/ordered_float.rs @@ -55,6 +55,13 @@ impl Hash for OrderedFloat { } } +impl From for OrderedFloat { + #[inline] + fn from(val: T) -> Self { + OrderedFloat(val) + } +} + // ---------------------------------------------------------------------------- /// Extension trait to provide `ord()` method. diff --git a/examples/test_viewports/src/main.rs b/examples/test_viewports/src/main.rs index 94bc46c2..f004d1ac 100644 --- a/examples/test_viewports/src/main.rs +++ b/examples/test_viewports/src/main.rs @@ -68,11 +68,14 @@ impl ViewportState { let viewport = ViewportBuilder::default() .with_title(&title) - .with_inner_size([450.0, 400.0]); + .with_inner_size([500.0, 500.0]); if immediate { let mut vp_state = vp_state.write(); ctx.show_viewport_immediate(vp_id, viewport, move |ctx, class| { + if ctx.input(|i| i.viewport().close_requested()) { + vp_state.visible = false; + } show_as_popup(ctx, class, &title, vp_id.into(), |ui: &mut egui::Ui| { generic_child_ui(ui, &mut vp_state); }); @@ -81,6 +84,9 @@ impl ViewportState { let count = Arc::new(RwLock::new(0)); ctx.show_viewport_deferred(vp_id, viewport, move |ctx, class| { let mut vp_state = vp_state.write(); + if ctx.input(|i| i.viewport().close_requested()) { + vp_state.visible = false; + } let count = count.clone(); show_as_popup( ctx, @@ -220,22 +226,36 @@ fn generic_ui(ui: &mut egui::Ui, children: &[Arc>]) { ctx.parent_viewport_id() )); - ui.add_space(8.0); + ui.collapsing("Info", |ui| { + ui.label(format!("zoom_factor: {}", ctx.zoom_factor())); + ui.label(format!("pixels_per_point: {}", ctx.pixels_per_point())); - if let Some(inner_rect) = ctx.input(|i| i.viewport().inner_rect) { - ui.label(format!( - "Inner Rect: Pos: {:?}, Size: {:?}", - inner_rect.min, - inner_rect.size() - )); - } - if let Some(outer_rect) = ctx.input(|i| i.viewport().outer_rect) { - ui.label(format!( - "Outer Rect: Pos: {:?}, Size: {:?}", - outer_rect.min, - outer_rect.size() - )); - } + if let Some(native_pixels_per_point) = ctx.input(|i| i.viewport().native_pixels_per_point) { + ui.label(format!( + "native_pixels_per_point: {native_pixels_per_point:?}" + )); + } + if let Some(monitor_size) = ctx.input(|i| i.viewport().monitor_size) { + ui.label(format!("monitor_size: {monitor_size:?} (points)")); + } + if let Some(screen_rect) = ui.input(|i| i.raw.screen_rect) { + ui.label(format!("Screen rect size: Pos: {:?}", screen_rect.size())); + } + if let Some(inner_rect) = ctx.input(|i| i.viewport().inner_rect) { + ui.label(format!( + "Inner Rect: Pos: {:?}, Size: {:?} (points)", + inner_rect.min, + inner_rect.size() + )); + } + if let Some(outer_rect) = ctx.input(|i| i.viewport().outer_rect) { + ui.label(format!( + "Outer Rect: Pos: {:?}, Size: {:?} (points)", + outer_rect.min, + outer_rect.size() + )); + } + }); if ctx.viewport_id() != ctx.parent_viewport_id() { let parent = ctx.parent_viewport_id();