egui/
introspection.rs

1//! Showing UI:s for egui/epaint types.
2use crate::*;
3
4pub fn font_family_ui(ui: &mut Ui, font_family: &mut FontFamily) {
5    let families = ui.fonts(|f| f.families());
6    ui.horizontal(|ui| {
7        for alternative in families {
8            let text = alternative.to_string();
9            ui.radio_value(font_family, alternative, text);
10        }
11    });
12}
13
14pub fn font_id_ui(ui: &mut Ui, font_id: &mut FontId) {
15    let families = ui.fonts(|f| f.families());
16    ui.horizontal(|ui| {
17        ui.add(Slider::new(&mut font_id.size, 4.0..=40.0).max_decimals(1));
18        for alternative in families {
19            let text = alternative.to_string();
20            ui.radio_value(&mut font_id.family, alternative, text);
21        }
22    });
23}
24
25// Show font texture in demo Ui
26pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Response {
27    ui.vertical(|ui| {
28        let color = if ui.visuals().dark_mode {
29            Color32::WHITE
30        } else {
31            Color32::BLACK
32        };
33
34        ui.label(format!("Texture size: {width} x {height} (hover to zoom)"));
35        if width <= 1 || height <= 1 {
36            return;
37        }
38        let mut size = vec2(width as f32, height as f32);
39        if size.x > ui.available_width() {
40            size *= ui.available_width() / size.x;
41        }
42        let (rect, response) = ui.allocate_at_least(size, Sense::hover());
43        let mut mesh = Mesh::default();
44        mesh.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), color);
45        ui.painter().add(Shape::mesh(mesh));
46
47        let (tex_w, tex_h) = (width as f32, height as f32);
48
49        response
50            .on_hover_cursor(CursorIcon::ZoomIn)
51            .on_hover_ui_at_pointer(|ui| {
52                if let Some(pos) = ui.ctx().pointer_latest_pos() {
53                    let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0));
54                    let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
55                    let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);
56
57                    let texel_radius = 32.0;
58                    let u = u.at_least(texel_radius).at_most(tex_w - texel_radius);
59                    let v = v.at_least(texel_radius).at_most(tex_h - texel_radius);
60
61                    let uv_rect = Rect::from_min_max(
62                        pos2((u - texel_radius) / tex_w, (v - texel_radius) / tex_h),
63                        pos2((u + texel_radius) / tex_w, (v + texel_radius) / tex_h),
64                    );
65                    let mut mesh = Mesh::default();
66                    mesh.add_rect_with_uv(zoom_rect, uv_rect, color);
67                    ui.painter().add(Shape::mesh(mesh));
68                }
69            });
70    })
71    .response
72}
73
74impl Widget for &epaint::stats::PaintStats {
75    fn ui(self, ui: &mut Ui) -> Response {
76        ui.vertical(|ui| {
77            ui.label(
78                "egui generates intermediate level shapes like circles and text. \
79                These are later tessellated into triangles.",
80            );
81            ui.add_space(10.0);
82
83            ui.style_mut().override_text_style = Some(TextStyle::Monospace);
84
85            let epaint::stats::PaintStats {
86                shapes,
87                shape_text,
88                shape_path,
89                shape_mesh,
90                shape_vec,
91                num_callbacks,
92                text_shape_vertices,
93                text_shape_indices,
94                clipped_primitives,
95                vertices,
96                indices,
97            } = self;
98
99            ui.label("Intermediate:");
100            label(ui, shapes, "shapes").on_hover_text("Boxes, circles, etc");
101            ui.horizontal(|ui| {
102                label(ui, shape_text, "text");
103                ui.small("(mostly cached)");
104            });
105            label(ui, shape_path, "paths");
106            label(ui, shape_mesh, "nested meshes");
107            label(ui, shape_vec, "nested shapes");
108            ui.label(format!("{num_callbacks:6} callbacks"));
109            ui.add_space(10.0);
110
111            ui.label("Text shapes:");
112            label(ui, text_shape_vertices, "vertices");
113            label(ui, text_shape_indices, "indices")
114                .on_hover_text("Three 32-bit indices per triangles");
115            ui.add_space(10.0);
116
117            ui.label("Tessellated (and culled):");
118            label(ui, clipped_primitives, "primitives lists")
119                .on_hover_text("Number of separate clip rectangles");
120            label(ui, vertices, "vertices");
121            label(ui, indices, "indices").on_hover_text("Three 32-bit indices per triangles");
122            ui.add_space(10.0);
123
124            // ui.label("Total:");
125            // ui.label(self.total().format(""));
126        })
127        .response
128    }
129}
130
131fn label(ui: &mut Ui, alloc_info: &epaint::stats::AllocInfo, what: &str) -> Response {
132    ui.add(Label::new(alloc_info.format(what)).wrap_mode(TextWrapMode::Extend))
133}
134
135impl Widget for &mut epaint::TessellationOptions {
136    fn ui(self, ui: &mut Ui) -> Response {
137        ui.vertical(|ui| {
138            let epaint::TessellationOptions {
139                feathering,
140                feathering_size_in_pixels,
141                coarse_tessellation_culling,
142                prerasterized_discs,
143                round_text_to_pixels,
144                debug_paint_clip_rects,
145                debug_paint_text_rects,
146                debug_ignore_clip_rects,
147                bezier_tolerance,
148                epsilon: _,
149                parallel_tessellation,
150                validate_meshes,
151            } = self;
152
153            ui.horizontal(|ui| {
154                ui.checkbox(feathering, "Feathering (antialias)")
155                    .on_hover_text("Apply feathering to smooth out the edges of shapes. Turn off for small performance gain.");
156
157                if *feathering {
158                    ui.add(crate::DragValue::new(feathering_size_in_pixels).range(0.0..=10.0).speed(0.1).suffix(" px"));
159                }
160            });
161
162            ui.checkbox(prerasterized_discs, "Speed up filled circles with pre-rasterization");
163
164            ui.horizontal(|ui| {
165                ui.label("Spline tolerance");
166                let speed = 0.01 * *bezier_tolerance;
167                ui.add(
168                    crate::DragValue::new(bezier_tolerance).range(0.0001..=10.0)
169                        .speed(speed)
170                );
171            });
172
173            ui.add_enabled(epaint::HAS_RAYON, crate::Checkbox::new(parallel_tessellation, "Parallelize tessellation")
174                ).on_hover_text("Only available if epaint was compiled with the rayon feature")
175                .on_disabled_hover_text("epaint was not compiled with the rayon feature");
176
177            ui.checkbox(validate_meshes, "Validate meshes").on_hover_text("Check that incoming meshes are valid, i.e. that all indices are in range, etc.");
178
179            ui.collapsing("Debug", |ui| {
180                ui.checkbox(
181                    coarse_tessellation_culling,
182                    "Do coarse culling in the tessellator",
183                );
184                ui.checkbox(round_text_to_pixels, "Align text positions to pixel grid")
185                    .on_hover_text("Most text already is, so don't expect to see a large change.");
186
187                ui.checkbox(debug_ignore_clip_rects, "Ignore clip rectangles");
188                ui.checkbox(debug_paint_clip_rects, "Paint clip rectangles");
189                ui.checkbox(debug_paint_text_rects, "Paint text bounds");
190            });
191        })
192        .response
193    }
194}
195
196impl Widget for &memory::InteractionState {
197    fn ui(self, ui: &mut Ui) -> Response {
198        let memory::InteractionState {
199            potential_click_id,
200            potential_drag_id,
201        } = self;
202
203        ui.vertical(|ui| {
204            ui.label(format!("potential_click_id: {potential_click_id:?}"));
205            ui.label(format!("potential_drag_id: {potential_drag_id:?}"));
206        })
207        .response
208    }
209}