Crates.io | imgui-inspect-derive |
lib.rs | imgui-inspect-derive |
version | 0.8.0 |
source | src |
created_at | 2019-09-01 06:11:56.686945 |
updated_at | 2021-02-06 22:42:47.452502 |
description | Traits and default implementations for inspecting values with imgui. |
homepage | https://github.com/aclysma/imgui-inspect |
repository | https://github.com/aclysma/imgui-inspect |
max_upload_size | |
id | 161283 |
size | 22,484 |
Oversimplified, this is an implementation of a property editor using ImGui
and Rust
.
More specifically, this crate aims to be a serde
for inspecting with imgui. It defines a common interface for getting values into imgui and back out.
There are some default implementations for certain types to be drawn as certain widgets, but the primary goal is to make it easy to implement your own preferred way of rendering values.
InspectRenderSlider
)f32
)If you'd like to see this crate in action, check out imgui-inspect-demo. A cargo run
from within that directory will
launch it.
You could also refer to code in minimum. The property editor in this video shows this library being used within it.
Many of the more complex use-cases, such as custom types and handling multiple selected values, are implemented there.
The overall design of this crate is unlikely to change, but very few imgui widget types and value types are implemented.
Most of the future work will be:
It's a fairly straightforward process and basic examples exist, but it does take time to add them.
I'll be extending this as I need support for more types, but if you need something that's missing, PR it! There are detailed instructions below.
For default rendering behavior, derive Inspect on your struct
#[derive(Inspect)]
pub struct MyStruct {
pub first_value: f32,
pub second_value: f32,
}
To draw, Call it with the UI window and a reference to an instance of your struct:
// ....
ui.text(im_str!("This...is...imgui!"));
ui.separator();
let my_struct = MyStruct::default(); // example, maybe get it from somewhere else instead
<MyStruct as InspectRenderDefault<MyStruct>>::render(
&[&my_struct],
&"my_struct_test",
ui,
&InspectArgsDefault::default()
);
The reason my_struct is being passed as &[&my_struct] is because it's common to select multiple objects. In this case, the rendering code could compare if the values are consistent across all selected items, or in the case of rendering mutably, apply the change to all selected values.
You can get slightly different behavior by marking up the struct members. This can choose what widgets to draw and tweak their settings.
#[derive(Inspect)]
pub struct MyStruct {
// Use a slider widget with the given min/max values
#[inspect_slider(min_value = 5.0, max_value = 53.0)]
pub sliding_value: f32,
}
Internally, deriving Inspect implements InspectRenderDefault
for MyStruct. But you can implement it manually if you need to do something custom.
impl InspectRenderDefault<MyStruct> for MyStruct {
fn render(data: &[&MyStruct], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault) {
ui.text("custom rendering is easy!");
}
fn render_mut(data: &mut [&mut MyStruct], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault) {
ui.text("custom rendering is easy!");
}
}
The API allows mixing and matching Render traits and types that are being rendered. A single type can be renderered multiple ways by overriding the render_trait
pub trait InspectRenderMyCustomWidgetType<T> {
fn render(data: &[&T], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault);
fn render_mut(data: &mut [&mut T], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault);
}
#[derive(Inspect)]
pub struct MyStruct {
#[inspect(render_trait = "InspectRenderMyCustomWidgetType")]
pub a_value: f32,
}
This will call <f32 as InspectRenderMyCustomWidgetType>::render(...)
. This is useful for rendering the same type a few different ways.
Sometimes you want to implement your own rendering for a type in some other crate. But there's a problem.. traits can only be implemented in the same crate as the trait or the type itself.
You can either wrap the type yourself (i.e. struct MyVec2(glm::Vec2)
) or you can use a dummy type and override the proxy_type
.
struct ImGlmVec2;
impl InspectRenderDefault<glm::Vec2> for ImGlmVec2 {
fn render(data: &[&glm::Vec2], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault) {
// ...
}
fn render_mut(data: &mut [&mut glm::Vec2], label: &'static str, ui: &imgui::Ui, args: &InspectArgsDefault) {
// ...
}
}
#[derive(Inspect, Clone)]
pub struct MyStruct {
#[inspect(proxy_type = "ImGlmVec2")]
pub position: glm::Vec2,
}
This type is never instantiated. It's just used to resolve the function that should be called: <ImGlmVec2 as InspectRenderDefault>::render(...)
Remember you can always use a proxy type if you don't want to upstream changes, or if you dislike the default implementation!
This is easy to do and only requires changing imgui-inspect
[WIDGET]/[WIDGET]_[TYPE]
slider/slider_f32.rs
impl InspectRender[WIDGET]<[TYPE]> for [TYPE]
impl InspectRenderSlider<f32> for f32
In summary, we need to add a trait for the widget, implement the trait for some types, and add widget/config options to the proc macro
InspectArgs[WIDGET]
and InspectRender[WIDGET]
to imgui-inspect/src/[WIDGET]/mod.rs
InspectArgsSlider
and InspectRenderSlider
in imgui-inspect/src/slider
InspectArgs[WIDGET]
are the options that can be fed into imguiInspectArgs[WIDGET]
should pipe these values into the imgui widgetInspectFieldArgs[WIDGET]
and InspectArgs[WIDGET]
to imgui-inspect-derive/src/inspect_macro/args/[WIDGET]_args.rs
InspectFieldArgsSlider
and InspectFieldArgsSlider
in slider_args.rs
InspectArgs[WIDGET]
is a copy-paste of the same struct in inspect-imgui. (It's duplicated because a proc_macro crate cannot export a type)InspectArgs[WIDGET]
are the values unique to the widget, and InspectFieldArgs[WIDGET]
is every single property that can be changed via the macroInspectArgsDefault
and InspectFieldArgsDefault
should be a superset of all args possible for any widget. Update:
imgui-inspect-derive/src/inspect_macro/args/default_args.rs
imgui-inspect/src/default/mod.rs
handle_inspect_types()
in imgui-inspect-derive/src/inspect_macro/mod.rs
imgui-inspect-derive/src/lib.rs
Generally, you don't want to ship imgui in your end product. However, conditionally including the proc_macro is awkward. Rust will complain about any macros that it isn't told about, so removing the imgui-inspect-derive dependency from a project conditionally requires noisy markup.
To solve this, the imgui-inspect-derive macro uses a feature "generate_code." Disabling default features will prevent code from being generated.
Steps:
imgui-inspect = { version = "...", optional = true }
imgui-inspect-derive = { version = "...", default-features = false }
imgui-inspect-derive generates boilerplate code but doesn't actually depend on imgui. Disabling default features means the generate_code feature will be disabled, causing the macros to be parsed, but no code to be emitted.
All contributions are assumed to be dual-licensed under MIT/Apache-2.
Distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT.
The fonts directory contains several fonts under their own licenses:
mplus-1p-regular.ttf
, available under its own license.