diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 0d09abc81..1d6ae2d09 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -455,8 +455,8 @@ mod glow_integration { }; use egui::{ - epaint::ahash::HashMap, NumExt as _, ViewportIdMap, ViewportIdPair, ViewportIdSet, - ViewportOutput, ViewportUiCallback, + epaint::ahash::HashMap, ImmediateViewport, NumExt as _, ViewportIdMap, ViewportIdPair, + ViewportIdSet, ViewportOutput, ViewportUiCallback, }; use egui_winit::{create_winit_window_builder, process_viewport_commands, EventResponse}; @@ -1362,7 +1362,7 @@ mod glow_integration { let event_loop: *const EventLoopWindowTarget = event_loop; egui::Context::set_immediate_viewport_renderer( - move |egui_ctx, viewport_builder, ids, viewport_ui_cb| { + move |egui_ctx, immediate_viewport| { if let (Some(glutin), Some(painter)) = (glutin.upgrade(), painter.upgrade()) { // SAFETY: the event loop lives longer than @@ -1373,12 +1373,10 @@ mod glow_integration { render_immediate_viewport( event_loop, egui_ctx, - viewport_builder, - ids, - viewport_ui_cb, &glutin, &painter, beginning, + immediate_viewport, ); } else { log::warn!("render_sync_callback called after window closed"); @@ -1400,28 +1398,30 @@ mod glow_integration { /// This is called (via a callback) by user code to render immediate viewports, /// i.e. viewport that are directly nested inside a parent viewport. - #[inline(always)] - #[allow(clippy::too_many_arguments)] fn render_immediate_viewport( event_loop: &EventLoopWindowTarget, egui_ctx: &egui::Context, - mut viewport_builder: ViewportBuilder, - ids: ViewportIdPair, - viewport_ui_cb: Box, glutin: &RefCell, painter: &RefCell, beginning: Instant, + immediate_viewport: ImmediateViewport<'_>, ) { crate::profile_function!(); + let ImmediateViewport { + ids, + mut builder, + viewport_ui_cb, + } = immediate_viewport; + if !glutin.borrow().viewports.contains_key(&ids.this) { // A new viewport - create a window for it! let mut glutin = glutin.borrow_mut(); // Inherit parent icon if none - if viewport_builder.icon.is_none() && glutin.builders.get(&ids.this).is_none() { - viewport_builder.icon = glutin + if builder.icon.is_none() && glutin.builders.get(&ids.this).is_none() { + builder.icon = glutin .builders .get(&ids.parent) .and_then(|b| b.icon.clone()); @@ -1432,7 +1432,7 @@ mod glow_integration { .entry(ids.this) .or_insert(Viewport::new(ids)); - glutin.builders.entry(ids.this).or_insert(viewport_builder); + glutin.builders.entry(ids.this).or_insert(builder); glutin .init_viewport(ids.this, event_loop) @@ -1820,8 +1820,8 @@ mod wgpu_integration { use parking_lot::Mutex; use egui::{ - FullOutput, ViewportIdMap, ViewportIdPair, ViewportIdSet, ViewportOutput, - ViewportUiCallback, + FullOutput, ImmediateViewport, ViewportIdMap, ViewportIdPair, ViewportIdSet, + ViewportOutput, ViewportUiCallback, }; use egui_winit::{create_winit_window_builder, process_viewport_commands}; @@ -2075,7 +2075,7 @@ mod wgpu_integration { let event_loop: *const EventLoopWindowTarget = event_loop; egui::Context::set_immediate_viewport_renderer( - move |egui_ctx, viewport_builder, ids, viewport_ui_cb| { + move |egui_ctx, immediate_viewport| { if let Some(shared) = shared.upgrade() { // SAFETY: the event loop lives longer than // the Rc:s we just upgraded above. @@ -2085,11 +2085,9 @@ mod wgpu_integration { render_immediate_viewport( event_loop, egui_ctx, - viewport_builder, - ids, - viewport_ui_cb, beginning, &shared, + immediate_viewport, ); } else { log::warn!("render_sync_callback called after window closed"); @@ -2125,19 +2123,21 @@ mod wgpu_integration { Ok((window, window_builder)) } - #[inline(always)] - #[allow(clippy::too_many_arguments)] fn render_immediate_viewport( event_loop: &EventLoopWindowTarget, egui_ctx: &egui::Context, - mut viewport_builder: ViewportBuilder, - ids: ViewportIdPair, - viewport_ui_cb: Box, beginning: Instant, shared: &RefCell, + immediate_viewport: ImmediateViewport<'_>, ) { crate::profile_function!(); + let ImmediateViewport { + ids, + mut builder, + viewport_ui_cb, + } = immediate_viewport; + let input = { let mut shared = shared.borrow_mut(); let SharedState { @@ -2148,15 +2148,15 @@ mod wgpu_integration { // Creating a new native window if is needed if !viewports.contains_key(&ids.this) { - if viewport_builder.icon.is_none() { - viewport_builder.icon = viewports + if builder.icon.is_none() { + builder.icon = viewports .get(&ids.parent) .and_then(|vp| vp.builder.icon.clone()); } let viewport = viewports.entry(ids.this).or_insert(Viewport { ids, - builder: viewport_builder, + builder, viewport_ui_cb: None, window: None, egui_winit: None, @@ -2586,16 +2586,16 @@ mod wgpu_integration { // Add new viewports, and update existing ones: for ViewportOutput { - builder: mut new_builder, ids, + mut builder, viewport_ui_cb, } in out_viewports { active_viewports_ids.insert(ids.this); - if new_builder.icon.is_none() { + if builder.icon.is_none() { // Inherit icon from parent - new_builder.icon = viewports + builder.icon = viewports .get_mut(&ids.parent) .and_then(|vp| vp.builder.icon.clone()); } @@ -2605,7 +2605,7 @@ mod wgpu_integration { // New viewport: entry.insert(Viewport { ids, - builder: new_builder, + builder, viewport_ui_cb, window: None, egui_winit: None, @@ -2619,7 +2619,7 @@ mod wgpu_integration { viewport.ids.parent = ids.parent; viewport.viewport_ui_cb = viewport_ui_cb; - let (commands, recreate) = viewport.builder.patch(&new_builder); + let (commands, recreate) = viewport.builder.patch(&builder); if recreate { if let Some(viewport) = viewports.get_mut(&ids.this) { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 54b493623..716d8f884 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -2517,8 +2517,7 @@ impl Context { /// Look in `crates/eframe/native/run.rs` and search for `set_immediate_viewport_renderer` to see for what is used. #[allow(clippy::unused_self)] pub fn set_immediate_viewport_renderer( - callback: impl for<'a> Fn(&Context, ViewportBuilder, ViewportIdPair, Box) - + 'static, + callback: impl for<'a> Fn(&Context, ImmediateViewport<'a>) + 'static, ) { let callback = Box::new(callback); IMMEDIATE_VIEWPORT_RENDERER.with(|render_sync| { @@ -2628,7 +2627,7 @@ impl Context { /// `ctx.viewport_id() != ctx.parent_viewport_id` if false you should create a [`crate::Window`]. pub fn show_viewport_immediate( &self, - viewport_builder: &ViewportBuilder, + builder: ViewportBuilder, viewport_ui_cb: impl FnOnce(&Context) -> T, ) -> T { crate::profile_function!(); @@ -2647,9 +2646,9 @@ impl Context { let ids = self.write(|ctx| { let parent = ctx.viewport_id(); - if let Some(window) = ctx.viewports.get_mut(&viewport_builder.id) { + if let Some(window) = ctx.viewports.get_mut(&builder.id) { // Existing - window.builder = viewport_builder.clone(); + window.builder = builder.clone(); window.ids.parent = parent; window.used = true; window.viewport_ui_cb = None; @@ -2657,13 +2656,13 @@ impl Context { } else { // New let ids = ViewportIdPair { - this: viewport_builder.id, + this: builder.id, parent, }; ctx.viewports.insert( - viewport_builder.id, + builder.id, ViewportState { - builder: viewport_builder.clone(), + builder: builder.clone(), ids, used: true, viewport_ui_cb: None, @@ -2677,12 +2676,13 @@ impl Context { { let out = &mut out; - immediate_viewport_renderer( - self, - viewport_builder.clone(), + let viewport = ImmediateViewport { ids, - Box::new(move |context| *out = Some(viewport_ui_cb(context))), - ); + builder, + viewport_ui_cb: Box::new(move |context| *out = Some(viewport_ui_cb(context))), + }; + + immediate_viewport_renderer(self, viewport); } out.expect( diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index a01fbeb07..299df57ee 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -89,8 +89,7 @@ impl ViewportIdPair { pub type ViewportUiCallback = dyn Fn(&Context) + Sync + Send; /// Render the given viewport, calling the given ui callback. -pub type ImmediateViewportRendererCallback = - dyn for<'a> Fn(&Context, ViewportBuilder, ViewportIdPair, Box); +pub type ImmediateViewportRendererCallback = dyn for<'a> Fn(&Context, ImmediateViewport<'a>); /// Control the building of a new egui viewport (i.e. native window). /// @@ -734,3 +733,14 @@ impl ViewportOutput { self.ids.this } } + +/// Viewport for immediate rendering. +pub struct ImmediateViewport<'a> { + /// Id of us and our parent. + pub ids: ViewportIdPair, + + pub builder: ViewportBuilder, + + /// The user-code that shows the GUI. + pub viewport_ui_cb: Box, +} diff --git a/examples/test_viewports/src/main.rs b/examples/test_viewports/src/main.rs index 9cbdad035..0de38c0ce 100644 --- a/examples/test_viewports/src/main.rs +++ b/examples/test_viewports/src/main.rs @@ -72,7 +72,7 @@ impl ViewportState { if immediate { let mut vp_state = vp_state.write(); - ctx.show_viewport_immediate(&vp_builder, move |ctx| { + ctx.show_viewport_immediate(vp_builder, move |ctx| { show_as_popup(ctx, &title, vp_id.into(), |ui: &mut egui::Ui| { generic_child_ui(ui, &mut vp_state); });