1#![cfg_attr(feature = "derive", doc = "```")]
25#![cfg_attr(
26 not(feature = "derive"),
27 doc = "```ignore\n// This example requires the `derive` feature."
28)]
29#![allow(clippy::inline_always, clippy::use_self)]
97
98mod algebra;
99mod array;
100mod boolean;
101mod collections;
102mod color;
103#[cfg(feature = "hashbrown")]
104mod hashbrown;
105mod map;
106mod num;
107mod option;
108mod set;
109#[cfg(any(feature = "smallvec1", feature = "smallvec2"))]
110mod small_vec;
111mod text;
112mod ui;
113mod vec;
114mod widget;
115
116pub use egui;
117
118pub use self::{
119 boolean::toggle_switch,
120 collections::DeleteMe,
121 option::option_probe_with,
122 widget::{Probe, ProbeLayout},
123};
124
125#[derive(Clone, Copy, Debug)]
126pub enum BooleanStyle {
127 Checkbox,
128 ToggleSwitch,
129}
130
131impl Default for BooleanStyle {
132 #[inline]
133 fn default() -> Self {
134 Self::Checkbox
135 }
136}
137
138#[derive(Clone, Copy, Debug)]
139pub enum VariantsStyle {
140 Inlined,
141 ComboBox,
142}
143
144impl Default for VariantsStyle {
145 #[inline]
146 fn default() -> Self {
147 Self::ComboBox
148 }
149}
150
151#[derive(Clone, Copy, Debug)]
153pub struct Style {
154 pub boolean: BooleanStyle,
155 pub variants: VariantsStyle,
156 pub field_indent_size: Option<f32>,
157 pub add_button_char: Option<char>,
158 pub remove_button_char: Option<char>,
159}
160
161impl Default for Style {
162 #[inline]
163 fn default() -> Self {
164 Style {
165 boolean: BooleanStyle::default(),
166 variants: VariantsStyle::default(),
167 field_indent_size: None,
168 add_button_char: None,
169 remove_button_char: None,
170 }
171 }
172}
173
174impl Style {
175 #[must_use]
176 pub fn add_button_text(&self) -> String {
177 self.add_button_char.unwrap_or('+').to_string()
178 }
179
180 #[must_use]
181 pub fn remove_button_text(&self) -> String {
182 self.remove_button_char.unwrap_or('-').to_string()
183 }
184}
185
186pub trait EguiProbe {
188 fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response;
190
191 #[inline(always)]
196 fn iterate_inner(
197 &mut self,
198 ui: &mut egui::Ui,
199 f: &mut dyn FnMut(&str, &mut egui::Ui, &mut dyn EguiProbe),
200 ) {
201 let _ = (ui, f);
202 }
203}
204
205impl<P> EguiProbe for &mut P
206where
207 P: EguiProbe,
208{
209 #[inline(always)]
210 fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response {
211 P::probe(*self, ui, style)
212 }
213
214 #[inline(always)]
215 fn iterate_inner(
216 &mut self,
217 ui: &mut egui::Ui,
218 f: &mut dyn FnMut(&str, &mut egui::Ui, &mut dyn EguiProbe),
219 ) {
220 P::iterate_inner(*self, ui, f);
221 }
222}
223
224impl<P> EguiProbe for Box<P>
225where
226 P: EguiProbe,
227{
228 #[inline(always)]
229 fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response {
230 P::probe(&mut *self, ui, style)
231 }
232
233 #[inline(always)]
234 fn iterate_inner(
235 &mut self,
236 ui: &mut egui::Ui,
237 f: &mut dyn FnMut(&str, &mut egui::Ui, &mut dyn EguiProbe),
238 ) {
239 P::iterate_inner(&mut *self, ui, f);
240 }
241}
242
243#[derive(Clone, Copy)]
244#[repr(transparent)]
245pub struct EguiProbeFn<F>(pub F);
246
247impl<F> EguiProbe for EguiProbeFn<F>
248where
249 F: FnMut(&mut egui::Ui, &Style) -> egui::Response,
250{
251 #[inline(always)]
252 fn probe(&mut self, ui: &mut egui::Ui, style: &Style) -> egui::Response {
253 (self.0)(ui, style)
254 }
255}
256
257#[inline(always)]
259pub const fn probe_fn<F>(f: F) -> EguiProbeFn<F> {
260 EguiProbeFn(f)
261}
262
263#[inline(always)]
264pub fn angle(value: &mut f32) -> impl EguiProbe + '_ {
265 probe_fn(move |ui: &mut egui::Ui, _style: &Style| ui.drag_angle(value))
266}
267
268pub mod customize {
269 use std::ops::RangeFull;
270
271 use super::{
272 EguiProbe, Style,
273 boolean::ToggleSwitch,
274 collections::EguiProbeFrozen,
275 color::{
276 EguiProbeRgb, EguiProbeRgba, EguiProbeRgbaPremultiplied, EguiProbeRgbaUnmultiplied,
277 },
278 egui,
279 num::{EguiProbeRange, StepUnset},
280 probe_fn,
281 text::EguiProbeMultiline,
282 };
283
284 #[inline(always)]
285 pub fn probe_with<'a, T, F>(mut f: F, value: &'a mut T) -> impl EguiProbe + 'a
286 where
287 F: FnMut(&mut T, &mut egui::Ui, &Style) -> egui::Response + 'a,
288 {
289 probe_fn(move |ui: &mut egui::Ui, style: &Style| f(value, ui, style))
290 }
291
292 #[inline(always)]
293 pub fn probe_as<'a, T, F, R>(f: F, value: &'a mut T) -> impl EguiProbe + 'a
294 where
295 F: FnOnce(&'a mut T) -> R,
296 R: EguiProbe + 'a,
297 {
298 f(value)
299 }
300
301 #[inline(always)]
302 pub const fn probe_range<'a, T, R>(range: R, value: &'a mut T) -> EguiProbeRange<'a, T, R>
303 where
304 EguiProbeRange<'a, T, R>: EguiProbe,
305 {
306 EguiProbeRange {
307 value,
308 range,
309 step: StepUnset,
310 }
311 }
312
313 #[inline(always)]
314 pub const fn probe_range_step<'a, T, R, S>(
315 range: R,
316 step: S,
317 value: &'a mut T,
318 ) -> EguiProbeRange<'a, T, R, S>
319 where
320 EguiProbeRange<'a, T, R, S>: EguiProbe,
321 {
322 EguiProbeRange { value, range, step }
323 }
324
325 #[inline(always)]
326 pub const fn probe_step<'a, T, S>(
327 step: S,
328 value: &'a mut T,
329 ) -> EguiProbeRange<'a, T, RangeFull, S>
330 where
331 EguiProbeRange<'a, T, RangeFull, S>: EguiProbe,
332 {
333 EguiProbeRange {
334 value,
335 range: ..,
336 step,
337 }
338 }
339
340 #[inline(always)]
341 pub const fn probe_multiline<'a, T>(string: &'a mut T) -> EguiProbeMultiline<'a, T>
342 where
343 EguiProbeMultiline<'a, T>: EguiProbe,
344 {
345 EguiProbeMultiline { string }
346 }
347
348 #[inline(always)]
349 pub fn probe_toggle_switch<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
350 where
351 ToggleSwitch<'a, T>: EguiProbe,
352 {
353 ToggleSwitch(value)
354 }
355
356 #[inline(always)]
357 pub fn probe_frozen<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
358 where
359 EguiProbeFrozen<'a, T>: EguiProbe,
360 {
361 EguiProbeFrozen { value }
362 }
363
364 #[inline(always)]
365 pub fn probe_rgb<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
366 where
367 EguiProbeRgb<'a, T>: EguiProbe,
368 {
369 EguiProbeRgb { value }
370 }
371
372 #[inline(always)]
373 pub fn probe_rgba<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
374 where
375 EguiProbeRgba<'a, T>: EguiProbe,
376 {
377 EguiProbeRgba { value }
378 }
379
380 #[inline(always)]
381 pub fn probe_rgba_premultiplied<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
382 where
383 EguiProbeRgbaPremultiplied<'a, T>: EguiProbe,
384 {
385 EguiProbeRgbaPremultiplied { value }
386 }
387
388 #[inline(always)]
389 pub fn probe_rgba_unmultiplied<'a, T>(value: &'a mut T) -> impl EguiProbe + 'a
390 where
391 EguiProbeRgbaUnmultiplied<'a, T>: EguiProbe,
392 {
393 EguiProbeRgbaUnmultiplied { value }
394 }
395}
396
397#[cfg(feature = "derive")]
398pub use egui_probe_proc::EguiProbe;
399
400#[cfg(feature = "derive")]
401extern crate self as egui_probe;
402
403#[cfg(feature = "derive")]
404#[doc(hidden)]
405pub mod private {
406 pub use super::customize::*;
407 pub use core::stringify;
408}
409
410#[cfg(feature = "derive")]
411#[test]
412fn test_all_attributes() {
413 #![allow(unused)]
414
415 trait A {}
416
417 #[derive(EguiProbe)]
418 #[egui_probe(where T: EguiProbe)]
419 struct TypeAttributes<T> {
420 a: T,
421 }
422
423 struct NoProbe;
424
425 #[derive(EguiProbe)]
426 #[egui_probe(rename_all = Train-Case)]
427 struct FieldAttributes {
428 #[egui_probe(skip)]
429 skipped: NoProbe,
430
431 #[egui_probe(name = "renamed")]
432 a: u8,
433
434 #[egui_probe(with |_, ui, _| ui.label("a label"))]
435 b: u8,
436
437 #[egui_probe(as angle)]
438 c: f32,
439
440 #[egui_probe(range = 0..=100)]
441 d: u8,
442
443 #[egui_probe(multiline)]
444 e: String,
445
446 #[egui_probe(multiline)]
447 f: Option<String>,
448
449 #[egui_probe(toggle_switch)]
450 g: bool,
451
452 #[egui_probe(toggle_switch)]
453 h: Option<bool>,
454
455 #[egui_probe(frozen)]
456 i: Vec<u8>,
457
458 #[egui_probe(rgb)]
459 j: egui::Color32,
460
461 #[egui_probe(rgba)]
462 k: egui::Color32,
463
464 #[egui_probe(rgba_premultiplied)]
465 l: [u8; 4],
466
467 #[egui_probe(rgba_unmultiplied)]
468 m: [f32; 4],
469 }
470
471 #[derive(EguiProbe)]
472 #[egui_probe(tags combobox)]
473 enum EnumAttributes {
474 #[egui_probe(name = "renamed")]
475 A,
476
477 #[egui_probe(transparent)]
478 B {
479 #[egui_probe(skip)]
480 skipped: (),
481
482 b: f32,
483 },
484 }
485}