From 5f8f1494446dfc486ea12c00fa9c9cd818a38d78 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 1 Oct 2024 10:39:44 +0200 Subject: Add `UiBuilder::layer_id`, and remove `layer_id` from `Ui::new` (#5195) This adds `UiBuilder::layer_id` to replace `ui.with_layer_id` --- crates/egui/src/containers/area.rs | 3 ++- crates/egui/src/containers/panel.rs | 18 +++++++++--------- crates/egui/src/painter.rs | 3 +++ crates/egui/src/ui.rs | 22 ++++++++++++++-------- crates/egui/src/ui_builder.rs | 10 +++++++++- crates/egui/src/widget_rect.rs | 8 ++++++++ tests/test_viewports/src/main.rs | 2 +- 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/crates/egui/src/containers/area.rs b/crates/egui/src/containers/area.rs index fa8e5fc2..b0cb0330 100644 --- a/crates/egui/src/containers/area.rs +++ b/crates/egui/src/containers/area.rs @@ -540,6 +540,7 @@ impl Prepared { let mut ui_builder = UiBuilder::new() .ui_stack_info(UiStackInfo::new(self.kind)) + .layer_id(self.layer_id) .max_rect(max_rect); if !self.enabled { @@ -549,7 +550,7 @@ impl Prepared { ui_builder = ui_builder.sizing_pass().invisible(); } - let mut ui = Ui::new(ctx.clone(), self.layer_id, self.layer_id.id, ui_builder); + let mut ui = Ui::new(ctx.clone(), self.layer_id.id, ui_builder); ui.set_clip_rect(self.constrain_rect); // Don't paint outside our bounds if self.fade_in { diff --git a/crates/egui/src/containers/panel.rs b/crates/egui/src/containers/panel.rs index ee510457..7cf22a69 100644 --- a/crates/egui/src/containers/panel.rs +++ b/crates/egui/src/containers/panel.rs @@ -372,14 +372,14 @@ impl SidePanel { ctx: &Context, add_contents: Box R + 'c>, ) -> InnerResponse { - let layer_id = LayerId::background(); let side = self.side; let available_rect = ctx.available_rect(); let mut panel_ui = Ui::new( ctx.clone(), - layer_id, self.id, - UiBuilder::new().max_rect(available_rect), + UiBuilder::new() + .layer_id(LayerId::background()) + .max_rect(available_rect), ); panel_ui.set_clip_rect(ctx.screen_rect()); @@ -864,15 +864,15 @@ impl TopBottomPanel { ctx: &Context, add_contents: Box R + 'c>, ) -> InnerResponse { - let layer_id = LayerId::background(); let available_rect = ctx.available_rect(); let side = self.side; let mut panel_ui = Ui::new( ctx.clone(), - layer_id, self.id, - UiBuilder::new().max_rect(available_rect), + UiBuilder::new() + .layer_id(LayerId::background()) + .max_rect(available_rect), ); panel_ui.set_clip_rect(ctx.screen_rect()); @@ -1131,14 +1131,14 @@ impl CentralPanel { add_contents: Box R + 'c>, ) -> InnerResponse { let available_rect = ctx.available_rect(); - let layer_id = LayerId::background(); let id = Id::new((ctx.viewport_id(), "central_panel")); let mut panel_ui = Ui::new( ctx.clone(), - layer_id, id, - UiBuilder::new().max_rect(available_rect), + UiBuilder::new() + .layer_id(LayerId::background()) + .max_rect(available_rect), ); panel_ui.set_clip_rect(ctx.screen_rect()); diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index feefe47d..5b8ae77d 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -74,6 +74,9 @@ impl Painter { } /// Redirect where you are painting. + /// + /// It is undefined behavior to change the [`LayerId`] + /// of [`crate::Ui::painter`]. pub fn set_layer_id(&mut self, layer_id: LayerId) { self.layer_id = layer_id; } diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index ee77888f..9db1404d 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -120,10 +120,11 @@ impl Ui { /// /// Normally you would not use this directly, but instead use /// [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`]. - pub fn new(ctx: Context, layer_id: LayerId, id: Id, ui_builder: UiBuilder) -> Self { + pub fn new(ctx: Context, id: Id, ui_builder: UiBuilder) -> Self { let UiBuilder { id_salt, ui_stack_info, + layer_id, max_rect, layout, disabled, @@ -133,6 +134,8 @@ impl Ui { sense, } = ui_builder; + let layer_id = layer_id.unwrap_or(LayerId::background()); + debug_assert!( id_salt.is_none(), "Top-level Ui:s should not have an id_salt" @@ -170,7 +173,7 @@ impl Ui { }; // Register in the widget stack early, to ensure we are behind all widgets we contain: - let start_rect = Rect::NOTHING; // This will be overwritten when/if `remember_min_rect` is called + let start_rect = Rect::NOTHING; // This will be overwritten when `remember_min_rect` is called ui.ctx().create_widget( WidgetRect { id: ui.unique_id, @@ -247,6 +250,7 @@ impl Ui { let UiBuilder { id_salt, ui_stack_info, + layer_id, max_rect, layout, disabled, @@ -262,6 +266,9 @@ impl Ui { let max_rect = max_rect.unwrap_or_else(|| self.available_rect_before_wrap()); let mut layout = layout.unwrap_or(*self.layout()); let enabled = self.enabled && !disabled && !invisible; + if let Some(layer_id) = layer_id { + painter.set_layer_id(layer_id); + } if invisible { painter.set_invisible(); } @@ -310,7 +317,7 @@ impl Ui { }; // Register in the widget stack early, to ensure we are behind all widgets we contain: - let start_rect = Rect::NOTHING; // This will be overwritten when/if `remember_min_rect` is called + let start_rect = Rect::NOTHING; // This will be overwritten when `remember_min_rect` is called child_ui.ctx().create_widget( WidgetRect { id: child_ui.unique_id, @@ -2306,15 +2313,13 @@ impl Ui { /// }); /// # }); /// ``` + #[deprecated = "Use ui.scope_builder(UiBuilder::new().layer_id(…), …) instead"] pub fn with_layer_id( &mut self, layer_id: LayerId, add_contents: impl FnOnce(&mut Self) -> R, ) -> InnerResponse { - self.scope(|ui| { - ui.painter.set_layer_id(layer_id); - add_contents(ui) - }) + self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents) } /// A [`CollapsingHeader`] that starts out collapsed. @@ -2760,7 +2765,8 @@ impl Ui { // Paint the body to a new layer: let layer_id = LayerId::new(Order::Tooltip, id); - let InnerResponse { inner, response } = self.with_layer_id(layer_id, add_contents); + let InnerResponse { inner, response } = + self.scope_builder(UiBuilder::new().layer_id(layer_id), add_contents); // Now we move the visuals of the body to where the mouse is. // Normally you need to decide a location for a widget first, diff --git a/crates/egui/src/ui_builder.rs b/crates/egui/src/ui_builder.rs index 33a48dbd..e1075a9e 100644 --- a/crates/egui/src/ui_builder.rs +++ b/crates/egui/src/ui_builder.rs @@ -1,6 +1,6 @@ use std::{hash::Hash, sync::Arc}; -use crate::{Id, Layout, Rect, Sense, Style, UiStackInfo}; +use crate::{Id, LayerId, Layout, Rect, Sense, Style, UiStackInfo}; #[allow(unused_imports)] // Used for doclinks use crate::Ui; @@ -15,6 +15,7 @@ use crate::Ui; pub struct UiBuilder { pub id_salt: Option, pub ui_stack_info: UiStackInfo, + pub layer_id: Option, pub max_rect: Option, pub layout: Option, pub disabled: bool, @@ -48,6 +49,13 @@ impl UiBuilder { self } + /// Show the [`Ui`] in a different [`LayerId`] from its parent. + #[inline] + pub fn layer_id(mut self, layer_id: LayerId) -> Self { + self.layer_id = Some(layer_id); + self + } + /// Set the max rectangle, within which widgets will go. /// /// New widgets will *try* to fit within this rectangle. diff --git a/crates/egui/src/widget_rect.rs b/crates/egui/src/widget_rect.rs index 91924352..dd900af1 100644 --- a/crates/egui/src/widget_rect.rs +++ b/crates/egui/src/widget_rect.rs @@ -139,6 +139,14 @@ impl WidgetRects { // e.g. calling `response.interact(…)` to add more interaction. let (idx_in_layer, existing) = entry.get_mut(); + debug_assert!( + existing.layer_id == widget_rect.layer_id, + "Widget {:?} changed layer_id during the frame from {:?} to {:?}", + widget_rect.id, + existing.layer_id, + widget_rect.layer_id + ); + // Update it: existing.rect = widget_rect.rect; // last wins existing.interact_rect = widget_rect.interact_rect; // last wins diff --git a/tests/test_viewports/src/main.rs b/tests/test_viewports/src/main.rs index 24046e04..9d06db43 100644 --- a/tests/test_viewports/src/main.rs +++ b/tests/test_viewports/src/main.rs @@ -433,7 +433,7 @@ fn drag_source( // Paint the body to a new layer: let layer_id = egui::LayerId::new(egui::Order::Tooltip, id); - let res = ui.with_layer_id(layer_id, body); + let res = ui.scope_builder(UiBuilder::new().layer_id(layer_id), body); if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() { let delta = pointer_pos - res.response.rect.center(); -- cgit v1.2.3-70-g09d2