Skip to content

zakarumych/egui-probe

Repository files navigation

Egui Probe

docs.rs Crates.io Total Downloads Discord

Effortlessly create UI widgets to display and modify value types using a derive macro with rich customization via attributes. This library is exclusively for the egui UI framework.

Features

  • πŸͺ„ Derive Macro: Automatically generate UI widgets for your types.
  • 🎨 Rich Customization: Customize the generated widgets using attributes.
  • πŸš€ Seamless Integration: Designed to work seamlessly with egui.

Getting Started

Add egui_probe to your Cargo.toml:

[dependencies]
egui_probe = "0.5.2"

Usage

Derive EguiProbe for your types. Use attributes to customize the UI:

Simple Example

#[derive(EguiProbe)]
struct SimpleValue {
    boolean: bool,
    integer: i32,
    float: f32,
}

And this is what you get:

Simple

Advanced Example

struct Foo;

fn custom_probe(_: &mut Foo, ui: &mut egui::Ui, _: &egui_probe::Style) -> egui::Response {
    ui.label("This is custom probe")
}

#[derive(EguiProbe)]
#[egui_probe(transparent)]
struct UpTo7(#[egui_probe(range = ..=7)] u32);

#[derive(EguiProbe)]
#[egui_probe(tags inlined)]
enum InlinedTags {
    Empty,

    #[egui_probe(transparent)]
    InlinedFloat(f32),

    Text {
        #[egui_probe(multiline)]
        text: String,
    },
}

#[derive(EguiProbe)]
#[egui_probe(tags combobox)]
enum ComboBoxTags {
    Empty,

    Num { value: usize },
}

impl Default for ComboBoxTags {
    fn default() -> Self {
        ComboBoxTags::Empty
    }
}

#[derive(Default, EguiProbe)]
#[egui_probe(rename_all = Train-Case)]
struct InnerValue {
    line: String,

    #[egui_probe(multiline)]
    multi_line: String,

    #[cfg(feature = "smallvec1")]
    small_vec_1: smallvec1::SmallVec<[String; 4]>,

    #[cfg(feature = "smallvec2")]
    small_vec_2: smallvec2::SmallVec<f32, 4>,

    #[cfg(feature = "hashbrown")]
    hash_brown: hashbrown::HashMap<u8, f32>,
}

#[derive(EguiProbe)]
struct DemoValue {
    boolean: bool,

    #[egui_probe(toggle_switch)]
    boolean_toggle: bool,

    float: f32,

    #[egui_probe(range = 22..=55)]
    range: usize,

    range_to: UpTo7,

    #[egui_probe(range = 50..)]
    range_from: u8,

    #[egui_probe(as angle)]
    angle: f32,

    #[egui_probe(with custom_probe)]
    custom: Foo,

    #[egui_probe(name = "renamed ^_^")]
    renamed: u8,

    maybe_boolean: Option<bool>,

    inner: InnerValue,

    inlined_tags: InlinedTags,

    option_combobox_tags: Option<ComboBoxTags>,

    array: [u8; 3],

    vector: Vec<bool>,

    #[egui_probe(frozen)]
    frozen_vector: Vec<bool>,

    map: HashMap<String, u32>,

    #[egui_probe(frozen)]
    frozen_map: HashMap<String, u32>,
}

And this is what you get:

Demo

Attributes

Type Attributes

  • #[egui_probe(rename_all = kebab-case)]: Changes default name of all fields into specified case. Available cases are:

    • snake_case
    • camelCase
    • kebab-case
    • PascalCase
    • SCREAMING_SNAKE_CASE or UPPER_SNAKE_CASE
    • Train-Case
  • #[egui_probe(where TypeA: TraitB)]: Adds where clause to the EguiProbe implementation. Predicates follow Rust syntax.

  • #[egui_probe(transparent)]: Renders entire type as its only field. Won't compile if the type doesn't have exactly one non-skipped field.

  • #[egui_probe(tags kind)]: Controls how enum variants are rendered. If kind is combobox, a combobox is used to select the variant. If kind is inlined, the variant is rendered inline using radio buttons.

Variant Attributes

  • #[egui_probe(name = "custom name")]: Rename the variant in the UI.
  • #[egui_probe(transparent)]: Renders the variant as its only field. Won't compile if the variant doesn't have exactly one non-skipped field.

Field Attributes

  • #[egui_probe(skip)]: Skip the field in the UI. No other attributes should be used with this attribute.

  • #[egui_probe(name = "custom name")]: Rename the field in the UI.

  • #[egui_probe(with probe_fn)]: Render a filed using specified probe function with signature fn(&mut FieldType, &mut Ui, &egui_probe::Style) -> egui::Response. Node that probe_fn can be an expression, so closure can be used.

  • #[egui_probe(as probe_fn)]: Render a filed using specified probe function with signature fn(&mut FieldType) -> impl EguiProbe. i.e. wrapping the field into type that implements EguiProbe.

  • #[egui_probe(range = 22..=55)]: Specify a range for numeric values. Works on optionals too.

  • #[egui_probe(multiline)]: Render a string as a multiline text box. Field must be of type String or &str. Or an option of those.

  • #[egui_probe(toggle_switch)]: Render a boolean as a toggle switch. Field must be of type bool or an optional of bool.

  • #[egui_probe(frozen)]: Renders a collection without controls to add or remove elements.

  • #[egui_probe(rgb)]: Render opaque color picker in RGB space. Field must be of type egui::Color32, egui::Rgba, [u8; 3] or [f32; 3].

  • #[egui_probe(rgba)]: Render color picker in RGB space with alpha. Field must be of type egui::Color32, egui::Rgba.

  • #[egui_probe(rgba_premultiplied)]: Render color picker in RGB space with premultiplied alpha. For egui::Color32 and egui::Rgba it is the same as #[egui_probe(rgba)]. But it can be used on [u8; 4] and [f32; 4].

  • #[egui_probe(rgba_unmultiplied)]: Render color picker in RGB space with unmultiplied alpha. It can't be used with egui::Color32 and egui::Rgba, as those are always premultiplied. But it can be used on [u8; 4] and [f32; 4].

License

This project is licensed under either of

  • MIT License
  • Apache License, Version 2.0

at your option.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Enjoy building your UI with Egui Probe! πŸš€