Reflection-based ImGui wrapper.
Automatically generate ImGui widgets for your structs and types.
struct GameSettings {
int volume = 50;
float sensitivity = 1.0f;
bool fullscreen = false;
};
IMGUI_REFLECT(GameSettings, volume, sensitivity, fullscreen)
// Single Call:
ImReflect::Input("Settings", settings);
- 🎯 Less boilerplate - One macro, automatic UI
- đź”§ Configurable - Fluent builder API for customizing widgets
- 📦 Batteries included - Works with primitives, enums, STL containers, smart pointers
- 🎨 Extensible - Add your own types without modifying the library
- đź“„ Single header - Drop in and go
📖 All Types | 📦 Download Latest Release
Download the single header from releases:
#include "ImReflect.hpp"struct GameSettings {
int volume = 50;
float sensitivity = 1.0f;
bool fullscreen = false;
};
IMGUI_REFLECT(GameSettings, volume, sensitivity, fullscreen)GameSettings settings;
ImReflect::Input("Settings", settings);Done! ImReflect automatically generates appropriate widgets for each member.
Most standard types work out of the box. See Wiki for complete reference.
// Primitives
static bool my_bool = true;
ImReflect::Input("my bool", my_bool);
static int my_int = 42;
ImReflect::Input("my int", my_int);
static float my_float = 3.14f;
ImReflect::Input("my float", my_float);
static std::string my_string = "Hello ImReflect!";
ImReflect::Input("my string", my_string);
static MyEnum my_enum = MyEnum::Option1;
ImReflect::Input("my enum", my_enum);
Most of STL is also included.
std::tuple<int, float, std::string> my_tuple = { 1, 2.0f, "three" };
ImReflect::Input("my tuple", my_tuple);
std::map<std::string, float> my_map = { {"one", 1.0f}, {"two", 2.0f} };
ImReflect::Input("my map", my_map);
std::vector<int> my_vec = { 1, 2, 3 };
ImReflect::Input("my vec", my_vec);
Customize widgets using the fluent builder pattern.
Apply settings to all instances of a type:
auto config = ImSettings();
config.push<int>()
.as_slider()
.min(0)
.max(100)
.pop();
GameSettings settings;
ImReflect::Input("Settings", settings, config);
Configure specific struct members:
auto config = ImSettings();
config.push_member<&GameSettings::volume>()
.as_slider()
.min(0)
.max(100)
.pop()
.push_member<&GameSettings::sensitivity>()
.as_drag()
.min(0.1f)
.max(2.0f)
.pop();
ImReflect::Input("Settings", settings, config);Choose how enums are displayed:
enum class GraphicsQuality { Low, Medium, High, Ultra };
struct Graphics {
GraphicsQuality quality = GraphicsQuality::Medium;
GraphicsQuality shadows = GraphicsQuality::High;
GraphicsQuality textures = GraphicsQuality::High;
};
IMGUI_REFLECT(Graphics, quality, shadows, textures)
auto config = ImSettings();
config.push_member<&Graphics::quality>()
.as_dropdown() // Dropdown menu
.pop()
.push_member<&Graphics::shadows>()
.as_slider() // Slider control
.pop()
.push_member<&Graphics::textures>()
.as_radio() // Radio buttons
.pop();
static Graphics gfx;
ImReflect::Input("Graphics", gfx, config);
Track user interactions with return values:
struct GameSettings {
int volume = 50;
float sensitivity = 1.0f;
bool fullscreen = false;
};
GameSettings settings;
ImResponse response = ImReflect::Input("Settings", settings);
// Check if entire struct changed
if (response.get<GameSettings>().is_changed()) {
// settings has changed
}
// Check if any int member changed
if (response.get<int>().is_changed()) {
// any int has changed
}
// Check specific member
if (response.get_member<&GameSettings::volume>().is_changed()) {
// volume specifically has changed
}Add support for your own types using tag invoke:
struct vec3 {
float x = 0, y = 0, z = 0;
};
void tag_invoke(ImReflect::ImInput_t, const char* label, vec3& value, ImSettings& settings, ImResponse& response) {
auto& vec3_response = response.get<vec3>();
bool changed = ImGui::InputFloat3(label, &value.x);
if (changed) vec3_response.changed();
/* Check hovered, activated, etc*/
ImReflect::Detail::check_input_states(vec3_response);
}Add configurable settings for your custom types:
template<>
struct ImReflect::type_settings<vec3> : ImRequired<vec3> {
private:
bool _as_color = false;
public:
// If vec3 needs to be rendered as a color picker
type_settings<vec3>& as_color(const bool v = true) { _as_color = v; RETURN_THIS_T(vec3); }
bool is_color() { return _as_color; }
};
void tag_invoke(ImReflect::ImInput_t, const char* label, vec3& value, ImSettings& settings, ImResponse& response) {
/* Get the vec3 settings and response */
auto& vec3_settings = settings.get<vec3>();
auto& vec3_response = response.get<vec3>();
const bool render_as_color = vec3_settings.is_color();
bool changed = false;
if (render_as_color) {
changed = ImGui::ColorEdit3(label, &value.x);
} else {
changed = ImGui::InputFloat3(label, &value.x);
}
if (changed) vec3_response.changed();
/* Check hovered, activated, etc*/
ImReflect::Detail::check_input_states(vec3_response);
}
// Usage
ImSettings config;
config.push<vec3>()
.as_color()
.pop();
static vec3 my_vec3;
ImReflect::Input("my vec3", my_vec3, config);Requirements for custom settings:
- Use
template<>specialization - Define as
ImReflect::type_settings<YOUR_TYPE> - Inherit from
ImRequired - Return
type_settings<YOUR_TYPE>&from setters for chaining
Don't like the default implementation? Override it:
void tag_invoke(ImReflect::ImInput_t, const char* label, int& value, ImSettings& settings, ImResponse& response) {
// Your custom implementation for int
}When rendering a type, ImReflect searches in this order at compile time:
- User implementations - Your
tag_invokefunctions - Library implementations - Built-in ImReflect types
- Reflection - Types with
IMGUI_REFLECTmacro
This means you can always override library behavior with your own implementations.
If no implementation is found:
error C2338: No suitable Input implementation found for type T
Check the console for the missing type. If you think it should be supported, open an issue!
Download ImReflect.hpp from releases:
#include "ImReflect.hpp"Includes all dependencies except ImGui.
Clone the repository and include the main headers: ImReflect_entry.hpp, ImReflect_helper.hpp, ImReflect_primitives.hpp, ImReflect_std.hpp, and external dependencies.
- magic_enum - Included in single header
- visit_struct - Included in single header
- ImGui - You need to include this separately
- imgui_stdlib - for
std::string
- imgui_stdlib - for
- C++ 17
- Type Settings Reference - Complete API documentation
- Fluent Builder Pattern - Details on the configuration system
Feedback, issues, and pull requests are welcome! This project is part of my university work, so everything is a learning experience.
MIT License - See LICENSE
As a student, credit or a quick note about what you're using it for is greatly appreciated! It motivates me to keep contributing to open source!