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