Zig build package and bindings for Dear Imgui & extras.
Easy to use, hand-crafted API with default arguments, named parameters and Zig style text formatting. Here is a simple sample application, and here is a full one.
- Most public dear imgui API exposed
- All memory allocations go through user provided Zig allocator
- DrawList API for vector graphics, text rendering and custom widgets
- Test engine API for automatic testing
- Plot API for advanced data visualizations
- Gizmo API for gizmo
- Node editor API for node based stuff
- Knobs API for knobs
- ImGui
1.92.1-docking - ImGui test engine
1.91.8 - ImPlot
O.17 - ImGuizmo
1.92.5 WIP - ImGuiNodeEditor
O.9.3 - imgui-knobs
main - commit 8a43bf7b31c4166ec50f3a52c382c2cc66a91516
Example build.zig:
pubfnbuild(b: *std.Build) void {
constexe=b.addExecutable(.{ ... });
constzgui=b.dependency("zgui", .{
.shared=false,
.with_implot=true,
});
exe.root_module.addImport("zgui", zgui.module("root"));
exe.linkLibrary(zgui.artifact("imgui"));
{ // Needed for glfw/wgpu rendering backendconstzglfw=b.dependency("zglfw", .{});
exe.root_module.addImport("zglfw", zglfw.module("root"));
exe.linkLibrary(zglfw.artifact("glfw"));
constzpool=b.dependency("zpool", .{});
exe.root_module.addImport("zpool", zpool.module("root"));
constzgpu=b.dependency("zgpu", .{});
exe.root_module.addImport("zgpu", zgpu.module("root"));
exe.linkLibrary(zgpu.artifact("zdawn"));
}
}Now in your code you may import and use zgui:
constzgui=@import("zgui");
zgui.init(allocator);
_=zgui.io.addFontFromFile(content_dir++"Roboto-Medium.ttf", 16.0);
zgui.backend.init(
window,
demo.gctx.device,
@enumToInt(swapchain_format),
@enumToInt(depth_format),
);// Main loopwhile (...) {
zgui.backend.newFrame(framebuffer_width, framebuffer_height);
zgui.bulletText(
"Average : {d:.3} ms/frame ({d:.1} fps)",
.{ demo.gctx.stats.average_cpu_time, demo.gctx.stats.fps },
);
zgui.bulletText("W, A, S, D : move camera", .{});
zgui.spacing();
if (zgui.button("Setup Scene", .{})) {
// Button pressed.
}
if (zgui.dragFloat("Drag 1", .{ .v=&value0 })) {
// value0 has changed
}
if (zgui.dragFloat("Drag 2", .{ .v=&value0, .min=-1.0, .max=1.0 })) {
// value1 has changed
}
// Setup wgpu render pass herezgui.backend.draw(pass);
}If your project spans multiple zig modules that both use ImGui, such as an exe paired with a dll, you may want to build the zgui dependencies (zgui_pkg.zgui_c_cpp) as a shared library. This can be enabled with the shared build option. Then, in build.zig, use zgui_pkg.link to link zgui to all the modules that use ImGui.
When built this way, the ImGui context will be located in the shared library. However, the zgui zig code (which is compiled separately into each module) requires its own memory buffer which has to be initialized separately with initNoContext.
In your executable:
constzgui=@import("zgui");
zgui.init(allocator);
deferzgui.deinit();In your shared library:
constzgui=@import("zgui");
zgui.initNoContext();
deferzgui.deinitNoContxt();draw_list.addQuad(.{
.p1= .{ 170, 420 },
.p2= .{ 270, 420 },
.p3= .{ 220, 520 },
.p4= .{ 120, 520 },
.col=0xff_00_00_ff,
.thickness=3.0,
});
draw_list.addText(.{ 130, 130 }, 0xff_00_00_ff, "The number is: {}", .{7});
draw_list.addCircleFilled(.{ .p= .{ 200, 600 }, .r=50, .col=0xff_ff_ff_ff });
draw_list.addCircle(.{ .p= .{ 200, 600 }, .r=30, .col=0xff_00_00_ff, .thickness=11 });
draw_list.addPolyline(
&.{ .{ 100, 700 }, .{ 200, 600 }, .{ 300, 700 }, .{ 400, 600 } },
.{ .col=0xff_00_aa_11, .thickness=7 },
);Zig wraper for ImGUI test engine.
varcheck_b=false;
var_te: *zgui.te.TestEngine=zgui.te.getTestEngine().?;
fnregisterTests() void {
_=_te.registerTest(
"Awesome",
"should_do_some_another_magic",
@src(),
struct {
pubfngui(ctx: *zgui.te.TestContext) !void {
_=ctx; // autofix_=zgui.begin("Test Window", .{ .flags= .{ .no_saved_settings=true } });
deferzgui.end();
zgui.text("Hello, automation world", .{});
_=zgui.button("Click Me", .{});
if (zgui.treeNode("Node")) {
deferzgui.treePop();
_=zgui.checkbox("Checkbox", .{ .v=&check_b });
}
}
pubfnrun(ctx: *zgui.te.TestContext) !void {
ctx.setRef("/Test Window");
ctx.windowFocus("");
ctx.itemAction(.click, "Click Me", .{}, null);
ctx.itemAction(.open, "Node", .{}, null);
ctx.itemAction(.check, "Node/Checkbox", .{}, null);
ctx.itemAction(.uncheck, "Node/Checkbox", .{}, null);
std.testing.expect(true) catch|err| {
zgui.te.checkTestError(@src(), err);
return;
};
}
},
);
}if (zgui.plot.beginPlot("Line Plot", .{ .h=-1.0 })) {
zgui.plot.setupAxis(.x1, .{ .label="xaxis" });
zgui.plot.setupAxisLimits(.x1, .{ .min=0, .max=5 });
zgui.plot.setupLegend(.{ .south=true, .west=true }, .{});
zgui.plot.setupFinish();
zgui.plot.plotLineValues("y data", i32, .{ .v= &.{ 0, 1, 0, 1, 0, 1 } });
zgui.plot.plotLine("xy data", f32, .{
.xv= &.{ 0.1, 0.2, 0.5, 2.5 },
.yv= &.{ 0.1, 0.3, 0.5, 0.9 },
});
zgui.plot.endPlot();
}Zig wraper for ImGuizmo.
Zig wraper for ImGuiNodeEditor.
varnode_editor=zgui.node_editor.EditorContext.create(.{ .enable_smooth_zoom=true }),
zgui.node_editor.setCurrentEditor(node_editor);
deferzgui.node_editor.setCurrentEditor(null);
{
zgui.node_editor.begin("NodeEditor", .{ 0, 0 });
deferzgui.node_editor.end();
zgui.node_editor.beginNode(1);
{
deferzgui.node_editor.endNode();
zgui.textUnformatted("Node A");
zgui.node_editor.beginPin(1, .input);
{
deferzgui.node_editor.endPin();
zgui.textUnformatted("-> In");
}
zgui.sameLine(.{});
zgui.node_editor.beginPin(2, .output);
{
deferzgui.node_editor.endPin();
zgui.textUnformatted("Out ->");
}
}
}zig wrapper for imgui-knobs
// Minimal knob function call_=zgui.knobs.knob("Minimal", .{
.v=&v_knob,
.v_min=0,
.v_max=1.0,
});
zgui.sameLine(.{});
// Styled f32 knob_=zgui.knobs.knob("f32 Knob", .{
.v=&v_knob,
.v_min=0,
.v_max=1.0,
.size=200,
.speed=0.0005,
.angle_min=std.math.pi,
.angle_max=2*std.math.pi,
.variant= .{ .stepped=true },
.steps=5,
});
zgui.sameLine(.{});
// Styled i32 knob (applied color)zgui.pushStyleColor4f(.{ .idx=zgui.StyleCol.button_active, .c= .{ 0.6, 0.2, 0.2, 1 } });
zgui.pushStyleColor4f(.{ .idx=zgui.StyleCol.button_hovered, .c= .{ 0.6, 0.4, 0.4, 1 } });
zgui.pushStyleColor4f(.{ .idx=zgui.StyleCol.button, .c= .{ 0.4, 0, 0, 1 } });
_=zgui.knobs.knobInt("i32 Knob", .{
.v=&v_knob_int,
.v_min=-10,
.v_max=10,
.size=250,
.variant=zgui.knobs.KnobVariant{ .wiper_dot=true },
.flags=zgui.knobs.KnobFlags{
.drag_horizontal=true,
.no_input=true,
},
});
zgui.popStyleColor(.{ .count=3 });