1use 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
25pub(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 })
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}