Crate dear_imgui_reflect

Crate dear_imgui_reflect 

Source
Expand description

Reflection-based helpers for dear-imgui-rs.

This crate provides traits, derive macros, and helpers to automatically generate Dear ImGui widgets for your Rust types, in the spirit of the C++ ImReflect library.

At a high level:

The goal is to let you build “data inspector” style UIs quickly without hand-writing widgets for every field.

§Quick start

Derive ImGuiReflect for your type and use input_reflect:

use dear_imgui_reflect as reflect;
use reflect::ImGuiReflectExt;

#[derive(reflect::ImGuiReflect, Default)]
struct Player {
    #[imgui(slider, min = 0.0, max = 100.0)]
    health: f32,
    #[imgui(multiline, lines = 3)]
    notes: String,
    inventory: Vec<String>,
}

fn draw_ui(ui: &reflect::imgui::Ui, player: &mut Player) {
    // Returns true if any field changed this frame.
    if ui.input_reflect("Player", player) {
        // React to edits (save, mark dirty, etc).
    }
}

§Supported patterns (what this crate is good at)

This crate is designed around a few common use cases:

  • Configuration panels / settings windows: derive ImGuiReflect for your config structs and call ImGuiReflectExt::input_reflect each frame to build a live editor.
  • Game/engine inspectors: derive ImGuiReflect for components or resource types, then render inspectors for the currently selected entity/resource inside a docked window.
  • Collection-heavy UIs: use the built-in support for Vec<T>, [T; N], Option<T>, HashMap<String, V> and BTreeMap<String, V> to build list views, property bags and key/value editors with insertion/removal/reordering.
  • Tooling and data browsers: combine input_with_response and ReflectResponse to track when items are inserted/removed/reordered, and synchronize those changes back into your engine or persistence layer.
  • Math-heavy editors: enable the glam or mint features to edit vector, quaternion and matrix types using familiar ImGui input_float* widgets.

The derive macro understands a subset of field attributes inspired by ImReflect, such as:

  • #[imgui(skip)] – do not generate any UI for this field;
  • #[imgui(name = "Custom Label")] – override the field label;
  • numeric helpers like #[imgui(slider, min = 0.0, max = 1.0, format = "%.2f")], #[imgui(as_drag, speed = 0.1)], #[imgui(as_input, step = 1)];
  • text helpers like #[imgui(multiline, lines = 4, hint = "Search...")], #[imgui(read_only)], #[imgui(display_only)];
  • tuple layout helpers such as #[imgui(tuple_render = "grid", tuple_columns = 3)].

See the documentation on the re-exported [ImGuiReflect derive macro] for the full list of supported attributes and validation rules.

§Settings and per-field overrides

The global ReflectSettings object controls how generic containers are rendered (for example, whether Vec<T> is insertable/reorderable, or how numeric sliders behave). You can adjust it at startup:

use dear_imgui_reflect as reflect;

fn configure_reflect() {
    reflect::with_settings(|s| {
        // Make all Vec<T> non-reorderable by default.
        s.vec_mut().reorderable = false;

        // Use a 0..1 slider for all f32 values by default.
        let f32_settings = s.numerics_f32().clone().slider_0_to_1(2); // "%.2f"
        *s.numerics_f32_mut() = f32_settings;
    });
}

For finer control, MemberSettings lets you override behavior for a specific field, identified by type and field name:

#[derive(reflect::ImGuiReflect)]
struct Settings {
    weights: Vec<f32>,
}

fn configure_per_field() {
    reflect::with_settings(|s| {
        // For Settings::weights, allow reordering only.
        s.for_member::<Settings>("weights")
            .vec_reorder_only()
            .numerics_f32_slider_0_to_1(3);
    });
}

The with_settings_scope helper lets you temporarily override global settings for a single panel or widget subtree and automatically restore the previous configuration afterwards.

§Collecting structural change events

The input and ImGuiReflectExt::input_reflect helpers return a simple bool indicating whether any field changed. If you also want to react to container-structure changes (insert/remove/reorder/rename), use input_with_response and inspect the resulting ReflectResponse:

use dear_imgui_reflect as reflect;

#[derive(reflect::ImGuiReflect, Default)]
struct AppState {
    tags: Vec<String>,
}

fn draw_tags(ui: &reflect::imgui::Ui, state: &mut AppState) {
    let mut resp = reflect::ReflectResponse::default();
    let _changed = reflect::input_with_response(ui, "Tags", state, &mut resp);

    for event in resp.events() {
        match event {
            reflect::ReflectEvent::VecInserted { path, index } => {
                // path is "tags" when generated via the derive macro.
                println!("Inserted element at {index} in {:?}", path);
            }
            _ => {}
        }
    }
}

§Math integrations

When the glam feature is enabled, this crate implements ImGuiValue for glam::Vec2/Vec3/Vec4, glam::Quat, and glam::Mat4, using the corresponding input_float* widgets for inspection and editing.

When the mint feature is enabled, mint::Vector2/Vector3/Vector4<f32> are also editable via input_float* controls. This is useful when your engine uses mint as a math interop layer.

§Example: simple inspector-style UI

The following example shows how you might use dear-imgui-reflect to build a small “inspector” for a list of game entities. Each entity is a struct with nested fields, and the inspector lets you select an entity from a list and edit its properties in place:

use dear_imgui_reflect as reflect;
use reflect::ImGuiReflectExt;

#[derive(reflect::ImGuiReflect, Default)]
struct Transform {
    #[imgui(tuple_render = "grid", tuple_columns = 3)]
    position: (f32, f32, f32),
    #[imgui(tuple_render = "grid", tuple_columns = 3)]
    rotation_euler: (f32, f32, f32),
    #[imgui(slider, min = 0.1, max = 10.0)]
    uniform_scale: f32,
}

#[derive(reflect::ImGuiReflect, Default)]
struct Enemy {
    #[imgui(name = "Name")]
    name: String,
    #[imgui(slider, min = 0, max = 100)]
    health: i32,
    #[imgui(slider, min = 0.0, max = 1.0)]
    aggression: f32,
    #[imgui(name = "Waypoints")]
    patrol_points: Vec<(f32, f32)>,
    transform: Transform,
}

#[derive(Default)]
struct EnemyInspector {
    enemies: Vec<Enemy>,
    selected: usize,
}

impl EnemyInspector {
    fn ui(&mut self, ui: &reflect::imgui::Ui) {
        ui.window("Enemies").build(|| {
            // Left side: list of enemies with selection.
            ui.child_window("EnemyList")
                .size([200.0, 0.0])
                .build(ui, || {
                    for (i, enemy) in self.enemies.iter().enumerate() {
                        let label = format!("{i}: {}", enemy.name);
                        if ui.selectable_config(&label)
                            .selected(self.selected == i)
                            .build()
                        {
                            self.selected = i;
                        }
                    }
                });

            ui.same_line();

            // Right side: reflected editor for the selected enemy.
            ui.child_window("EnemyInspector")
                .size([0.0, 0.0])
                .build(ui, || {
                    if let Some(enemy) = self.enemies.get_mut(self.selected) {
                        ui.input_reflect("Enemy", enemy);
                    } else {
                        ui.text("No enemy selected");
                    }
                });
        });
    }
}

This pattern generalizes well to component-based engines, material editors, and other data-driven UIs: derive ImGuiReflect for the types you care about, then compose editors using input_reflect inside whatever layout best fits your application.

Re-exports§

pub use dear_imgui_rs as imgui;

Structs§

ArraySettings
Settings controlling how fixed-size arrays like [T; N] are edited.
BoolSettings
Settings controlling how bool fields are edited when no per-field attributes are provided.
MapSettings
Settings controlling how string-keyed maps like HashMap<String, V> and BTreeMap<String, V> are edited.
MemberSettings
Per-member override settings layered on top of global ReflectSettings.
NumericTypeSettings
Type-level settings controlling how a particular numeric primitive type is rendered.
ReflectResponse
High-level response information collected during a reflection-driven UI pass.
ReflectSettings
Settings that control how certain types are rendered by dear-imgui-reflect.
TupleSettings
Settings controlling how tuple-like values such as (A, B) and (A, B, C) are rendered.
VecSettings
Settings controlling how Vec<T> containers are edited.

Enums§

BoolStyle
Preferred widget style for boolean fields.
NumericRange
Range configuration for numeric sliders and drags.
NumericWidgetKind
Preferred widget style for numeric fields of a given primitive type.
ReflectEvent
A single structural change observed while rendering reflected UI.
TupleRenderMode
Preferred render mode for tuple-like values.

Traits§

ImGuiReflect
Trait for complex types (structs/enums) that can generate ImGui controls for all of their fields.
ImGuiReflectExt
Extension methods on Ui for reflection-based widgets.
ImGuiValue
Trait for values that can render themselves as a single ImGui input widget.
NumericDefaultRange
Trait providing a default numeric range for slider widgets when no explicit min/max are given.

Functions§

current_settings
Returns a clone of the current global ReflectSettings.
imgui_array_with_settings
Public helper for rendering fixed-size arrays using explicit ArraySettings.
imgui_btree_map_with_settings
Public helper for rendering BTreeMap<String, V> using explicit MapSettings.
imgui_hash_map_with_settings
Public helper for rendering HashMap<String, V, S> using explicit MapSettings.
imgui_tuple_body
Tuple and pair-style values rendered in line or grid mode.
imgui_vec_with_settings
Public helper for rendering Vec<T> using explicit VecSettings.
input
Render ImGui controls for a value that implements ImGuiReflect.
input_with_response
Variant of input that additionally collects container-level change events into the provided ReflectResponse.
with_settings
Mutates the global ReflectSettings in place.
with_settings_scope
Executes a closure with a temporary modification of the global ReflectSettings, restoring the previous settings afterwards.

Derive Macros§

ImGuiReflect
Derive macro for ImGuiReflect, re-exported for convenience.