egui/
debug_text.rs

1//! This is an example of how to create a plugin for egui.
2//!
3//! A plugin is a struct that implements the [`Plugin`] trait and holds some state.
4//! The plugin is registered with the [`Context`] using [`Context::add_plugin`]
5//! to get callbacks on certain events ([`Plugin::on_begin_pass`], [`Plugin::on_end_pass`]).
6
7use crate::{
8    Align, Align2, Color32, Context, FontFamily, FontId, Plugin, Rect, Shape, Vec2, WidgetText,
9    text,
10};
11
12/// Print this text next to the cursor at the end of the pass.
13///
14/// If you call this multiple times, the text will be appended.
15///
16/// This only works if compiled with `debug_assertions`.
17///
18/// ```
19/// # let ctx = &egui::Context::default();
20/// # let state = true;
21/// egui::debug_text::print(ctx, format!("State: {state:?}"));
22/// ```
23#[track_caller]
24pub fn print(ctx: &Context, text: impl Into<WidgetText>) {
25    if !cfg!(debug_assertions) {
26        return;
27    }
28
29    let location = std::panic::Location::caller();
30    let location = format!("{}:{}", location.file(), location.line());
31
32    let plugin = ctx.plugin::<DebugTextPlugin>();
33    let mut state = plugin.lock();
34    state.entries.push(Entry {
35        location,
36        text: text.into(),
37    });
38}
39
40#[derive(Clone)]
41struct Entry {
42    location: String,
43    text: WidgetText,
44}
45
46/// A plugin for easily showing debug-text on-screen.
47///
48/// This is a built-in plugin in egui, automatically registered during [`Context`] creation.
49#[derive(Clone, Default)]
50pub struct DebugTextPlugin {
51    // This gets re-filled every pass.
52    entries: Vec<Entry>,
53}
54
55impl Plugin for DebugTextPlugin {
56    fn debug_name(&self) -> &'static str {
57        "DebugTextPlugin"
58    }
59
60    fn on_end_pass(&mut self, ctx: &Context) {
61        let entries = std::mem::take(&mut self.entries);
62        Self::paint_entries(ctx, entries);
63    }
64}
65
66impl DebugTextPlugin {
67    fn paint_entries(ctx: &Context, entries: Vec<Entry>) {
68        if entries.is_empty() {
69            return;
70        }
71
72        // Show debug-text next to the cursor.
73        let mut pos = ctx
74            .input(|i| i.pointer.latest_pos())
75            .unwrap_or_else(|| ctx.content_rect().center())
76            + 8.0 * Vec2::Y;
77
78        let painter = ctx.debug_painter();
79        let where_to_put_background = painter.add(Shape::Noop);
80
81        let mut bounding_rect = Rect::from_points(&[pos]);
82
83        let color = Color32::GRAY;
84        let font_id = FontId::new(10.0, FontFamily::Proportional);
85
86        for Entry { location, text } in entries {
87            {
88                // Paint location to left of `pos`:
89                let location_galley =
90                    ctx.fonts_mut(|f| f.layout(location, font_id.clone(), color, f32::INFINITY));
91                let location_rect =
92                    Align2::RIGHT_TOP.anchor_size(pos - 4.0 * Vec2::X, location_galley.size());
93                painter.galley(location_rect.min, location_galley, color);
94                bounding_rect |= location_rect;
95            }
96
97            {
98                // Paint `text` to right of `pos`:
99                let available_width = ctx.content_rect().max.x - pos.x;
100                let galley = text.into_galley_impl(
101                    ctx,
102                    &ctx.style(),
103                    text::TextWrapping::wrap_at_width(available_width),
104                    font_id.clone().into(),
105                    Align::TOP,
106                );
107                let rect = Align2::LEFT_TOP.anchor_size(pos, galley.size());
108                painter.galley(rect.min, galley, color);
109                bounding_rect |= rect;
110            }
111
112            pos.y = bounding_rect.max.y + 4.0;
113        }
114
115        painter.set(
116            where_to_put_background,
117            Shape::rect_filled(
118                bounding_rect.expand(4.0),
119                2.0,
120                Color32::from_black_alpha(192),
121            ),
122        );
123    }
124}