diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 8b92a945c89..99165149f1d 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -351,8 +351,6 @@ pub fn popup_above_or_below_widget( .fixed_pos(pos) .pivot(pivot) .show(ui.ctx(), |ui| { - // Note: we use a separate clip-rect for this area, so the popup can be outside the parent. - // See https://github.com/emilk/egui/issues/825 let frame = Frame::popup(ui.style()); let frame_margin = frame.total_margin(); frame diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 9b7b5220487..f1b808b765b 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -231,6 +231,11 @@ impl ViewportRepaintInfo { // ---------------------------------------------------------------------------- +struct DebugText { + location: String, + text: WidgetText, +} + #[derive(Default)] struct ContextImpl { /// Since we could have multiple viewport across multiple monitors with @@ -278,6 +283,8 @@ struct ContextImpl { accesskit_node_classes: accesskit::NodeClassSet, loaders: Arc, + + debug_texts: Vec, } impl ContextImpl { @@ -1060,6 +1067,31 @@ impl Context { Self::layer_painter(self, LayerId::debug()) } + /// Print this text next to the cursor at the end of the frame. + /// + /// If you call this multiple times, the text will be appended. + /// + /// This only works if compiled with `debug_assertions`. + /// + /// ``` + /// # let ctx = egui::Context::default(); + /// # let state = true; + /// ctx.debug_text(format!("State: {state:?}")); + /// ``` + #[track_caller] + pub fn debug_text(&self, text: impl Into) { + if cfg!(debug_assertions) { + let location = std::panic::Location::caller(); + let location = format!("{}:{}", location.file(), location.line()); + self.write(|c| { + c.debug_texts.push(DebugText { + location, + text: text.into(), + }); + }); + } + } + /// What operating system are we running on? /// /// When compiling natively, this is @@ -1578,6 +1610,63 @@ impl Context { crate::gui_zoom::zoom_with_keyboard(self); } + let debug_texts = self.write(|ctx| std::mem::take(&mut ctx.debug_texts)); + if !debug_texts.is_empty() { + // Show debug-text next to the cursor. + let mut pos = self + .input(|i| i.pointer.latest_pos()) + .unwrap_or_else(|| self.screen_rect().center()) + + 8.0 * Vec2::Y; + + let painter = self.debug_painter(); + let where_to_put_background = painter.add(Shape::Noop); + + let mut bounding_rect = Rect::from_points(&[pos]); + + let color = Color32::GRAY; + let font_id = FontId::new(10.0, FontFamily::Proportional); + + for DebugText { location, text } in debug_texts { + { + // Paint location to left of `pos`: + let location_galley = + self.fonts(|f| f.layout(location, font_id.clone(), color, f32::INFINITY)); + let location_rect = + Align2::RIGHT_TOP.anchor_size(pos - 4.0 * Vec2::X, location_galley.size()); + painter.galley(location_rect.min, location_galley, color); + bounding_rect = bounding_rect.union(location_rect); + } + + { + // Paint `text` to right of `pos`: + let wrap = true; + let available_width = self.screen_rect().max.x - pos.x; + let galley = text.into_galley_impl( + self, + &self.style(), + wrap, + available_width, + font_id.clone().into(), + Align::TOP, + ); + let rect = Align2::LEFT_TOP.anchor_size(pos, galley.size()); + painter.galley(rect.min, galley, color); + bounding_rect = bounding_rect.union(rect); + } + + pos.y = bounding_rect.max.y + 4.0; + } + + painter.set( + where_to_put_background, + Shape::rect_filled( + bounding_rect.expand(4.0), + 2.0, + Color32::from_black_alpha(192), + ), + ); + } + self.write(|ctx| ctx.end_frame()) } } diff --git a/crates/egui/src/painter.rs b/crates/egui/src/painter.rs index 962b0d3b03a..951c04478ad 100644 --- a/crates/egui/src/painter.rs +++ b/crates/egui/src/painter.rs @@ -219,7 +219,9 @@ impl Painter { self.debug_text(pos, Align2::LEFT_TOP, color, format!("🔥 {text}")) } - /// text with a background + /// Text with a background. + /// + /// See also [`Context::debug_text`]. #[allow(clippy::needless_pass_by_value)] pub fn debug_text( &self, diff --git a/crates/egui/src/widget_text.rs b/crates/egui/src/widget_text.rs index 24f4a9c1380..57643ae4576 100644 --- a/crates/egui/src/widget_text.rs +++ b/crates/egui/src/widget_text.rs @@ -649,18 +649,39 @@ impl WidgetText { fallback_font: impl Into, ) -> Arc { let wrap = wrap.unwrap_or_else(|| ui.wrap_text()); + let valign = ui.layout().vertical_align(); + let style = ui.style(); + + self.into_galley_impl( + ui.ctx(), + style, + wrap, + available_width, + fallback_font.into(), + valign, + ) + } + + pub fn into_galley_impl( + self, + ctx: &crate::Context, + style: &Style, + wrap: bool, + available_width: f32, + fallback_font: FontSelection, + default_valign: Align, + ) -> Arc { let wrap_width = if wrap { available_width } else { f32::INFINITY }; match self { Self::RichText(text) => { - let valign = ui.layout().vertical_align(); - let mut layout_job = text.into_layout_job(ui.style(), fallback_font.into(), valign); + let mut layout_job = text.into_layout_job(style, fallback_font, default_valign); layout_job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(layout_job)) + ctx.fonts(|f| f.layout_job(layout_job)) } Self::LayoutJob(mut job) => { job.wrap.max_width = wrap_width; - ui.fonts(|f| f.layout_job(job)) + ctx.fonts(|f| f.layout_job(job)) } Self::Galley(galley) => galley, }