diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index 81a63eb7d..ab1d09ff2 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -492,11 +492,11 @@ impl EpiIntegration { self.frame.info.window_info = read_window_info(window, self.egui_ctx.pixels_per_point(), &self.window_state); - let mut raw_input = egui_winit.take_egui_input(window); + let mut raw_input = egui_winit.take_egui_input(window, id_pair); raw_input.time = Some(self.beginning.elapsed().as_secs_f64()); // Run user code: - let full_output = self.egui_ctx.run(raw_input, id_pair, |egui_ctx| { + let full_output = self.egui_ctx.run(raw_input, |egui_ctx| { crate::profile_scope!("App::update"); if let Some(viewport_ui_cb) = viewport_ui_cb { // Child viewport diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 11db19330..10f20f0d3 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -1196,9 +1196,9 @@ mod glow_integration { return; }; let win = win.borrow(); - let mut input = winit_state.take_egui_input(&win); + let mut input = winit_state.take_egui_input(&win, id_pair); input.time = Some(beginning.elapsed().as_secs_f64()); - let output = egui_ctx.run(input, id_pair, |ctx| { + let output = egui_ctx.run(input, |ctx| { viewport_ui_cb(ctx); }); @@ -2323,9 +2323,9 @@ mod wgpu_integration { return; }; let win = window.borrow(); - let mut input = winit_state.take_egui_input(&win); + let mut input = winit_state.take_egui_input(&win, id_pair); input.time = Some(beginning.elapsed().as_secs_f64()); - let output = egui_ctx.run(input, id_pair, |ctx| { + let output = egui_ctx.run(input, |ctx| { viewport_ui_cb(ctx); }); diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 53669cf0a..fa65cde58 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -14,7 +14,7 @@ pub use accesskit_winit; pub use egui; #[cfg(feature = "accesskit")] use egui::accesskit; -use egui::{Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId}; +use egui::{Pos2, Rect, Vec2, ViewportBuilder, ViewportCommand, ViewportId, ViewportIdPair}; pub use winit; pub mod clipboard; @@ -177,7 +177,11 @@ impl State { /// Prepare for a new frame by extracting the accumulated input, /// as well as setting [the time](egui::RawInput::time) and [screen rectangle](egui::RawInput::screen_rect). - pub fn take_egui_input(&mut self, window: &winit::window::Window) -> egui::RawInput { + pub fn take_egui_input( + &mut self, + window: &winit::window::Window, + id_pair: ViewportIdPair, + ) -> egui::RawInput { let pixels_per_point = self.pixels_per_point(); self.egui_input.time = Some(self.start_time.elapsed().as_secs_f64()); @@ -237,17 +241,20 @@ impl State { None }; - self.egui_input.inner_rect = if let (Some(pos), Some(size)) = (inner_pos, inner_size) { - Some(Rect::from_min_size(pos, size)) - } else { - None - }; + self.egui_input.viewport.id_pair = id_pair; + self.egui_input.viewport.inner_rect = + if let (Some(pos), Some(size)) = (inner_pos, inner_size) { + Some(Rect::from_min_size(pos, size)) + } else { + None + }; - self.egui_input.outer_rect = if let (Some(pos), Some(size)) = (outer_pos, outer_size) { - Some(Rect::from_min_size(pos, size)) - } else { - None - }; + self.egui_input.viewport.outer_rect = + if let (Some(pos), Some(size)) = (outer_pos, outer_size) { + Some(Rect::from_min_size(pos, size)) + } else { + None + }; self.egui_input.take() } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index fac403b99..48b911234 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -190,7 +190,9 @@ struct ContextImpl { } impl ContextImpl { - fn begin_frame_mut(&mut self, mut new_raw_input: RawInput, id_pair: ViewportIdPair) { + fn begin_frame_mut(&mut self, mut new_raw_input: RawInput) { + let id_pair = new_raw_input.viewport.id_pair; + let viewport_id = id_pair.this; self.viewport_stack.push(id_pair); self.output.entry(self.viewport_id()).or_default(); @@ -461,15 +463,10 @@ impl Context { /// // handle full_output /// ``` #[must_use] - pub fn run( - &self, - new_input: RawInput, - id_pair: ViewportIdPair, - run_ui: impl FnOnce(&Context), - ) -> FullOutput { + pub fn run(&self, new_input: RawInput, run_ui: impl FnOnce(&Context)) -> FullOutput { crate::profile_function!(); - self.begin_frame(new_input, id_pair); + self.begin_frame(new_input); run_ui(self); self.end_frame() } @@ -491,10 +488,10 @@ impl Context { /// let full_output = ctx.end_frame(); /// // handle full_output /// ``` - pub fn begin_frame(&self, new_input: RawInput, id_pair: ViewportIdPair) { + pub fn begin_frame(&self, new_input: RawInput) { crate::profile_function!(); - self.write(|ctx| ctx.begin_frame_mut(new_input, id_pair)); + self.write(|ctx| ctx.begin_frame_mut(new_input)); } } @@ -1676,18 +1673,6 @@ impl Context { self.input(|i| i.screen_rect()) } - /// Viewport inner position and size, only the drowable area - /// unit = physical pixels - pub fn inner_rect(&self) -> Rect { - self.input(|i| i.inner_rect) - } - - /// Viewport outer position and size, drowable area + decorations - /// unit = physical pixels - pub fn outer_rect(&self) -> Rect { - self.input(|i| i.outer_rect) - } - /// How much space is still available after panels has been added. /// /// This is the "background" area, what egui doesn't cover with panels (but may cover with windows). diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index e3542264b..e8ab7383e 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -1,6 +1,6 @@ //! The input needed by egui. -use crate::emath::*; +use crate::{emath::*, ViewportIdPair}; /// What the integrations provides to egui at the start of each frame. /// @@ -13,6 +13,8 @@ use crate::emath::*; #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct RawInput { + pub viewport: ViewportInfo, + /// Position and size of the area that egui should use, in points. /// Usually you would set this to /// @@ -23,14 +25,6 @@ pub struct RawInput { /// `None` will be treated as "same as last frame", with the default being a very big area. pub screen_rect: Option, - /// Viewport inner position and size, only the drowable area - /// unit = physical pixels - pub inner_rect: Option, - - /// Viewport outer position and size, drowable area + decorations - /// unit = physical pixels - pub outer_rect: Option, - /// Also known as device pixel ratio, > 1 for high resolution screens. /// If text looks blurry you probably forgot to set this. /// Set this the first frame, whenever it changes, or just on every frame. @@ -81,8 +75,6 @@ impl Default for RawInput { fn default() -> Self { Self { screen_rect: None, - inner_rect: None, - outer_rect: None, pixels_per_point: None, max_texture_side: None, time: None, @@ -91,7 +83,8 @@ impl Default for RawInput { events: vec![], hovered_files: Default::default(), dropped_files: Default::default(), - focused: true, // integrations opt into global focus tracking + focused: true, + viewport: ViewportInfo::default(), // integrations opt into global focus tracking } } } @@ -104,8 +97,6 @@ impl RawInput { pub fn take(&mut self) -> RawInput { RawInput { screen_rect: self.screen_rect.take(), - inner_rect: self.inner_rect.take(), - outer_rect: self.outer_rect.take(), pixels_per_point: self.pixels_per_point.take(), max_texture_side: self.max_texture_side.take(), time: self.time.take(), @@ -115,6 +106,7 @@ impl RawInput { hovered_files: self.hovered_files.clone(), dropped_files: std::mem::take(&mut self.dropped_files), focused: self.focused, + viewport: self.viewport.take(), } } @@ -122,8 +114,6 @@ impl RawInput { pub fn append(&mut self, newer: Self) { let Self { screen_rect, - inner_rect, - outer_rect, pixels_per_point, max_texture_side, time, @@ -133,13 +123,13 @@ impl RawInput { mut hovered_files, mut dropped_files, focused, + viewport, } = newer; self.screen_rect = screen_rect.or(self.screen_rect); - self.inner_rect = inner_rect.or(self.inner_rect); - self.outer_rect = outer_rect.or(self.outer_rect); self.pixels_per_point = pixels_per_point.or(self.pixels_per_point); self.max_texture_side = max_texture_side.or(self.max_texture_side); + self.viewport = viewport; self.time = time; // use latest time self.predicted_dt = predicted_dt; // use latest dt self.modifiers = modifiers; // use latest @@ -150,6 +140,26 @@ impl RawInput { } } +#[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub struct ViewportInfo { + pub id_pair: ViewportIdPair, + + /// Viewport inner position and size, only the drowable area + /// unit = physical pixels + pub inner_rect: Option, + + /// Viewport outer position and size, drowable area + decorations + /// unit = physical pixels + pub outer_rect: Option, +} + +impl ViewportInfo { + pub fn take(&mut self) -> Self { + core::mem::take(self) + } +} + /// A file about to be dropped into egui. #[derive(Clone, Debug, Default, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -958,8 +968,6 @@ impl RawInput { pub fn ui(&self, ui: &mut crate::Ui) { let Self { screen_rect, - inner_rect, - outer_rect, pixels_per_point, max_texture_side, time, @@ -969,11 +977,11 @@ impl RawInput { hovered_files, dropped_files, focused, + viewport, } = self; + viewport.ui(ui); ui.label(format!("screen_rect: {screen_rect:?} points")); - ui.label(format!("inner_rect: {inner_rect:?} pixels")); - ui.label(format!("outer_rect: {outer_rect:?} pixels")); ui.label(format!("pixels_per_point: {pixels_per_point:?}")) .on_hover_text( "Also called HDPI factor.\nNumber of physical pixels per each logical pixel.", @@ -997,6 +1005,14 @@ impl RawInput { } } +impl ViewportInfo { + pub fn ui(&self, ui: &mut crate::Ui) { + ui.label(format!("id_pair: {:?}", self.id_pair)); + ui.label(format!("inner_rect: {:?}", self.inner_rect)); + ui.label(format!("outer_rect: {:?}", self.outer_rect)); + } +} + /// this is a `u64` as values of this kind can always be obtained by hashing #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] diff --git a/crates/egui/src/input_state.rs b/crates/egui/src/input_state.rs index 1aceaad68..17478d17e 100644 --- a/crates/egui/src/input_state.rs +++ b/crates/egui/src/input_state.rs @@ -54,14 +54,6 @@ pub struct InputState { /// Position and size of the egui area. pub screen_rect: Rect, - /// Viewport inner position and size, only the drowable area - /// unit = physical pixels - pub inner_rect: Rect, - - /// Viewport outer position and size, drowable area + decorations - /// unit = physical pixels - pub outer_rect: Rect, - /// Also known as device pixel ratio, > 1 for high resolution screens. pub pixels_per_point: f32, @@ -146,8 +138,6 @@ impl Default for InputState { modifiers: Default::default(), keys_down: Default::default(), events: Default::default(), - inner_rect: Rect::ZERO, - outer_rect: Rect::ZERO, } } } @@ -172,8 +162,6 @@ impl InputState { }; let screen_rect = new.screen_rect.unwrap_or(self.screen_rect); - let inner_rect = new.inner_rect.unwrap_or(self.inner_rect); - let outer_rect = new.outer_rect.unwrap_or(self.outer_rect); self.create_touch_states_for_new_devices(&new.events); for touch_state in self.touch_states.values_mut() { @@ -229,8 +217,6 @@ impl InputState { scroll_delta, zoom_factor_delta, screen_rect, - inner_rect, - outer_rect, pixels_per_point: new.pixels_per_point.unwrap_or(self.pixels_per_point), max_texture_side: new.max_texture_side.unwrap_or(self.max_texture_side), time, @@ -997,8 +983,6 @@ impl InputState { scroll_delta, zoom_factor_delta, screen_rect, - inner_rect, - outer_rect, pixels_per_point, max_texture_side, time, @@ -1034,8 +1018,6 @@ impl InputState { ui.label(format!("scroll_delta: {scroll_delta:?} points")); ui.label(format!("zoom_factor_delta: {zoom_factor_delta:4.2}x")); ui.label(format!("screen_rect: {screen_rect:?} points")); - ui.label(format!("inner_rect: {inner_rect:?} pixels")); - ui.label(format!("outer_rect: {outer_rect:?} pixels")); ui.label(format!( "{pixels_per_point} physical pixels for each logical point" )); diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index 61466d597..ee44f9869 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -606,7 +606,7 @@ pub enum WidgetType { pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) { let ctx = Context::default(); ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) - let _ = ctx.run(Default::default(), ViewportIdPair::ROOT, |ctx| { + let _ = ctx.run(Default::default(), |ctx| { run_ui(ctx); }); } @@ -615,7 +615,7 @@ pub fn __run_test_ctx(mut run_ui: impl FnMut(&Context)) { pub fn __run_test_ui(mut add_contents: impl FnMut(&mut Ui)) { let ctx = Context::default(); ctx.set_fonts(FontDefinitions::empty()); // prevent fonts from being loaded (save CPU time) - let _ = ctx.run(Default::default(), ViewportIdPair::ROOT, |ctx| { + let _ = ctx.run(Default::default(), |ctx| { crate::CentralPanel::default().show(ctx, |ui| { add_contents(ui); }); diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index 928da3554..c073d9405 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -19,6 +19,7 @@ use crate::{Context, Id}; /// /// This is returned by [`Context::viewport_id`] and [`Context::parent_viewport_id`]. #[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct ViewportId(pub Id); impl Default for ViewportId { @@ -63,6 +64,7 @@ pub type ViewportIdMap = nohash_hasher::IntMap; /// A pair of [`ViewportId`], used to identify a viewport and its parent. #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct ViewportIdPair { pub this: ViewportId, pub parent: ViewportId, diff --git a/crates/egui_demo_lib/benches/benchmark.rs b/crates/egui_demo_lib/benches/benchmark.rs index 552167f85..b4e4b1678 100644 --- a/crates/egui_demo_lib/benches/benchmark.rs +++ b/crates/egui_demo_lib/benches/benchmark.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use egui::{epaint::TextShape, ViewportId, ViewportIdPair}; +use egui::{epaint::TextShape, ViewportId}; use egui_demo_lib::LOREM_IPSUM_LONG; pub fn criterion_benchmark(c: &mut Criterion) { @@ -13,7 +13,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { // The most end-to-end benchmark. c.bench_function("demo_with_tessellate__realistic", |b| { b.iter(|| { - let full_output = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| { + let full_output = ctx.run(RawInput::default(), |ctx| { demo_windows.ui(ctx); }); ctx.tessellate(full_output.shapes, ViewportId::ROOT) @@ -22,13 +22,13 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("demo_no_tessellate", |b| { b.iter(|| { - ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| { + ctx.run(RawInput::default(), |ctx| { demo_windows.ui(ctx); }) }); }); - let full_output = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| { + let full_output = ctx.run(RawInput::default(), |ctx| { demo_windows.ui(ctx); }); c.bench_function("demo_only_tessellate", |b| { @@ -42,7 +42,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut demo_windows = egui_demo_lib::DemoWindows::default(); c.bench_function("demo_full_no_tessellate", |b| { b.iter(|| { - ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| { + ctx.run(RawInput::default(), |ctx| { demo_windows.ui(ctx); }) }); @@ -51,7 +51,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let ctx = egui::Context::default(); - let _ = ctx.run(RawInput::default(), ViewportIdPair::ROOT, |ctx| { + let _ = ctx.run(RawInput::default(), |ctx| { egui::CentralPanel::default().show(ctx, |ui| { c.bench_function("label &str", |b| { b.iter(|| { @@ -69,7 +69,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { { let ctx = egui::Context::default(); - ctx.begin_frame(RawInput::default(), ViewportIdPair::ROOT); + ctx.begin_frame(RawInput::default()); egui::CentralPanel::default().show(&ctx, |ui| { c.bench_function("Painter::rect", |b| { diff --git a/crates/egui_demo_lib/src/lib.rs b/crates/egui_demo_lib/src/lib.rs index 16fa1dd6c..0c53d9f91 100644 --- a/crates/egui_demo_lib/src/lib.rs +++ b/crates/egui_demo_lib/src/lib.rs @@ -19,7 +19,7 @@ pub mod easy_mark; pub use color_test::ColorTest; pub use demo::DemoWindows; #[cfg(test)] -use egui::{ViewportId, ViewportIdPair}; +use egui::ViewportId; /// View some Rust code with syntax highlighting and selection. pub(crate) fn rust_view_ui(ui: &mut egui::Ui, code: &str) { @@ -76,7 +76,7 @@ fn test_egui_e2e() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { - let full_output = ctx.run(raw_input.clone(), ViewportIdPair::ROOT, |ctx| { + let full_output = ctx.run(raw_input.clone(), |ctx| { demo_windows.ui(ctx); }); let clipped_primitives = ctx.tessellate(full_output.shapes, ViewportId::ROOT); @@ -95,7 +95,7 @@ fn test_egui_zero_window_size() { const NUM_FRAMES: usize = 5; for _ in 0..NUM_FRAMES { - let full_output = ctx.run(raw_input.clone(), ViewportIdPair::ROOT, |ctx| { + let full_output = ctx.run(raw_input.clone(), |ctx| { demo_windows.ui(ctx); }); let clipped_primitives = ctx.tessellate(full_output.shapes, ViewportId::ROOT); diff --git a/crates/egui_glow/src/winit.rs b/crates/egui_glow/src/winit.rs index 88a074e04..54e6701c6 100644 --- a/crates/egui_glow/src/winit.rs +++ b/crates/egui_glow/src/winit.rs @@ -47,13 +47,15 @@ impl EguiGlow { /// Call [`Self::paint`] later to paint. pub fn run(&mut self, window: &winit::window::Window, run_ui: impl FnMut(&egui::Context)) { - let raw_input = self.egui_winit.take_egui_input(window); + let raw_input = self + .egui_winit + .take_egui_input(window, ViewportIdPair::ROOT); let egui::FullOutput { platform_output, textures_delta, shapes, .. - } = self.egui_ctx.run(raw_input, ViewportIdPair::ROOT, run_ui); + } = self.egui_ctx.run(raw_input, run_ui); self.egui_winit.handle_platform_output( window, diff --git a/examples/test_viewports/src/main.rs b/examples/test_viewports/src/main.rs index 6cd1bfa35..11223f902 100644 --- a/examples/test_viewports/src/main.rs +++ b/examples/test_viewports/src/main.rs @@ -197,18 +197,20 @@ fn generic_ui(ui: &mut egui::Ui, children: &[Arc>]) { ui.add_space(8.0); - let inner_rect = ctx.inner_rect(); - ui.label(format!( - "Inner Rect: Pos: {:?}, Size: {:?}", - inner_rect.min, - inner_rect.size() - )); - let outer_rect = ctx.outer_rect(); - ui.label(format!( - "Outer Rect: Pos: {:?}, Size: {:?}", - outer_rect.min, - outer_rect.size() - )); + if let Some(inner_rect) = ctx.input(|i| i.raw.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.raw.viewport.outer_rect) { + ui.label(format!( + "Outer Rect: Pos: {:?}, Size: {:?}", + outer_rect.min, + outer_rect.size() + )); + } let tmp_pixels_per_point = ctx.pixels_per_point(); let mut pixels_per_point = ui.data_mut(|data| {