mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
Imgui (#20)
* vendor/cimgui * Add a "dev mode" window which for now is just imgui demo
This commit is contained in:

committed by
GitHub

parent
ddfb1dec4b
commit
f29393bca6
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -28,3 +28,6 @@
|
||||
[submodule "vendor/zig-libxml2"]
|
||||
path = vendor/zig-libxml2
|
||||
url = https://github.com/mitchellh/zig-libxml2.git
|
||||
[submodule "vendor/cimgui"]
|
||||
path = vendor/cimgui
|
||||
url = https://github.com/cimgui/cimgui.git
|
||||
|
13
build.zig
13
build.zig
@ -6,6 +6,7 @@ const glfw = @import("vendor/mach/libs/glfw/build.zig");
|
||||
const fontconfig = @import("pkg/fontconfig/build.zig");
|
||||
const freetype = @import("pkg/freetype/build.zig");
|
||||
const harfbuzz = @import("pkg/harfbuzz/build.zig");
|
||||
const imgui = @import("pkg/imgui/build.zig");
|
||||
const libxml2 = @import("vendor/zig-libxml2/libxml2.zig");
|
||||
const libuv = @import("pkg/libuv/build.zig");
|
||||
const libpng = @import("pkg/libpng/build.zig");
|
||||
@ -189,6 +190,7 @@ fn addDeps(
|
||||
if (enable_fontconfig) step.addPackage(fontconfig.pkg);
|
||||
step.addPackage(freetype.pkg);
|
||||
step.addPackage(harfbuzz.pkg);
|
||||
step.addPackage(imgui.pkg);
|
||||
step.addPackage(glfw.pkg);
|
||||
step.addPackage(libuv.pkg);
|
||||
step.addPackage(utf8proc.pkg);
|
||||
@ -214,10 +216,15 @@ fn addDeps(
|
||||
_ = try utf8proc.link(b, step);
|
||||
|
||||
// Glfw
|
||||
try glfw.link(b, step, .{
|
||||
.metal = false,
|
||||
.opengl = false, // Found at runtime
|
||||
const glfw_opts: glfw.Options = .{ .metal = false, .opengl = false };
|
||||
try glfw.link(b, step, glfw_opts);
|
||||
|
||||
// Imgui
|
||||
const imgui_backends = [_][]const u8{ "glfw", "opengl3" };
|
||||
const imgui_step = try imgui.link(b, step, .{
|
||||
.backends = &imgui_backends,
|
||||
});
|
||||
try glfw.link(b, imgui_step, glfw_opts);
|
||||
|
||||
// Dynamic link
|
||||
if (!static) {
|
||||
|
93
pkg/imgui/build.zig
Normal file
93
pkg/imgui/build.zig
Normal file
@ -0,0 +1,93 @@
|
||||
const std = @import("std");
|
||||
|
||||
/// Directories with our includes.
|
||||
const root = thisDir() ++ "../../../vendor/cimgui/";
|
||||
pub const include_paths = [_][]const u8{
|
||||
root,
|
||||
root ++ "imgui",
|
||||
root ++ "imgui/backends",
|
||||
};
|
||||
|
||||
pub const pkg = std.build.Pkg{
|
||||
.name = "imgui",
|
||||
.source = .{ .path = thisDir() ++ "/main.zig" },
|
||||
};
|
||||
|
||||
fn thisDir() []const u8 {
|
||||
return std.fs.path.dirname(@src().file) orelse ".";
|
||||
}
|
||||
|
||||
pub const Options = struct {
|
||||
backends: ?[]const []const u8 = null,
|
||||
};
|
||||
|
||||
pub fn link(
|
||||
b: *std.build.Builder,
|
||||
step: *std.build.LibExeObjStep,
|
||||
opt: Options,
|
||||
) !*std.build.LibExeObjStep {
|
||||
const lib = try buildImgui(b, step, opt);
|
||||
step.linkLibrary(lib);
|
||||
inline for (include_paths) |path| step.addIncludePath(path);
|
||||
return lib;
|
||||
}
|
||||
|
||||
pub fn buildImgui(
|
||||
b: *std.build.Builder,
|
||||
step: *std.build.LibExeObjStep,
|
||||
opt: Options,
|
||||
) !*std.build.LibExeObjStep {
|
||||
const target = step.target;
|
||||
const lib = b.addStaticLibrary("imgui", null);
|
||||
lib.setTarget(step.target);
|
||||
lib.setBuildMode(step.build_mode);
|
||||
|
||||
// Include
|
||||
inline for (include_paths) |path| lib.addIncludePath(path);
|
||||
|
||||
// Link
|
||||
lib.linkLibC();
|
||||
|
||||
// Compile
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
defer flags.deinit();
|
||||
try flags.appendSlice(&.{
|
||||
"-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1",
|
||||
|
||||
//"-fno-sanitize=undefined",
|
||||
});
|
||||
switch (target.getOsTag()) {
|
||||
.windows => try flags.appendSlice(&.{
|
||||
"-DIMGUI_IMPL_API=extern\t\"C\"\t__declspec(dllexport)",
|
||||
}),
|
||||
else => try flags.appendSlice(&.{
|
||||
"-DIMGUI_IMPL_API=extern\t\"C\"\t",
|
||||
}),
|
||||
}
|
||||
|
||||
// C files
|
||||
lib.addCSourceFiles(srcs, flags.items);
|
||||
if (opt.backends) |backends| {
|
||||
for (backends) |backend| {
|
||||
var buf: [4096]u8 = undefined;
|
||||
const path = try std.fmt.bufPrint(
|
||||
&buf,
|
||||
"{s}imgui/backends/imgui_impl_{s}.cpp",
|
||||
.{ root, backend },
|
||||
);
|
||||
|
||||
lib.addCSourceFile(path, flags.items);
|
||||
}
|
||||
}
|
||||
|
||||
return lib;
|
||||
}
|
||||
|
||||
const srcs = &.{
|
||||
root ++ "cimgui.cpp",
|
||||
root ++ "imgui/imgui.cpp",
|
||||
root ++ "imgui/imgui_demo.cpp",
|
||||
root ++ "imgui/imgui_draw.cpp",
|
||||
root ++ "imgui/imgui_tables.cpp",
|
||||
root ++ "imgui/imgui_widgets.cpp",
|
||||
};
|
4
pkg/imgui/c.zig
Normal file
4
pkg/imgui/c.zig
Normal file
@ -0,0 +1,4 @@
|
||||
pub usingnamespace @cImport({
|
||||
@cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", "");
|
||||
@cInclude("cimgui.h");
|
||||
});
|
28
pkg/imgui/context.zig
Normal file
28
pkg/imgui/context.zig
Normal file
@ -0,0 +1,28 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Context = opaque {
|
||||
pub fn create() Allocator.Error!*Context {
|
||||
return @ptrCast(
|
||||
?*Context,
|
||||
c.igCreateContext(null),
|
||||
) orelse Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Context) void {
|
||||
c.igDestroyContext(self.cval());
|
||||
}
|
||||
|
||||
pub inline fn cval(self: *Context) *c.ImGuiContext {
|
||||
return @ptrCast(
|
||||
*c.ImGuiContext,
|
||||
@alignCast(@alignOf(c.ImGuiContext), self),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
test {
|
||||
var ctx = try Context.create();
|
||||
defer ctx.destroy();
|
||||
}
|
20
pkg/imgui/core.zig
Normal file
20
pkg/imgui/core.zig
Normal file
@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const imgui = @import("main.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub fn newFrame() void {
|
||||
c.igNewFrame();
|
||||
}
|
||||
|
||||
pub fn endFrame() void {
|
||||
c.igEndFrame();
|
||||
}
|
||||
|
||||
pub fn render() void {
|
||||
c.igRender();
|
||||
}
|
||||
|
||||
pub fn showDemoWindow(open: ?*bool) void {
|
||||
c.igShowDemoWindow(@ptrCast([*c]bool, if (open) |v| v else null));
|
||||
}
|
20
pkg/imgui/draw_data.zig
Normal file
20
pkg/imgui/draw_data.zig
Normal file
@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const imgui = @import("main.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const DrawData = opaque {
|
||||
pub fn get() Allocator.Error!*DrawData {
|
||||
return @ptrCast(
|
||||
?*DrawData,
|
||||
c.igGetDrawData(),
|
||||
) orelse Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub inline fn cval(self: *DrawData) *c.ImGuiDrawData {
|
||||
return @ptrCast(
|
||||
*c.ImGuiDrawData,
|
||||
@alignCast(@alignOf(c.ImGuiDrawData), self),
|
||||
);
|
||||
}
|
||||
};
|
28
pkg/imgui/impl_glfw.zig
Normal file
28
pkg/imgui/impl_glfw.zig
Normal file
@ -0,0 +1,28 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const imgui = @import("main.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const ImplGlfw = struct {
|
||||
pub const GLFWWindow = opaque {};
|
||||
|
||||
pub fn initForOpenGL(win: *GLFWWindow, install_callbacks: bool) bool {
|
||||
// https://github.com/ocornut/imgui/issues/5785
|
||||
defer _ = glfwGetError(null);
|
||||
|
||||
return ImGui_ImplGlfw_InitForOpenGL(win, install_callbacks);
|
||||
}
|
||||
|
||||
pub fn shutdown() void {
|
||||
return ImGui_ImplGlfw_Shutdown();
|
||||
}
|
||||
|
||||
pub fn newFrame() void {
|
||||
return ImGui_ImplGlfw_NewFrame();
|
||||
}
|
||||
|
||||
extern "c" fn glfwGetError(?*const anyopaque) c_int;
|
||||
extern "c" fn ImGui_ImplGlfw_InitForOpenGL(*GLFWWindow, bool) bool;
|
||||
extern "c" fn ImGui_ImplGlfw_Shutdown() void;
|
||||
extern "c" fn ImGui_ImplGlfw_NewFrame() void;
|
||||
};
|
30
pkg/imgui/impl_opengl3.zig
Normal file
30
pkg/imgui/impl_opengl3.zig
Normal file
@ -0,0 +1,30 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const imgui = @import("main.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const ImplOpenGL3 = struct {
|
||||
pub fn init(glsl_version: ?[:0]const u8) bool {
|
||||
return ImGui_ImplOpenGL3_Init(
|
||||
if (glsl_version) |s| s.ptr else null,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn shutdown() void {
|
||||
return ImGui_ImplOpenGL3_Shutdown();
|
||||
}
|
||||
|
||||
pub fn newFrame() void {
|
||||
return ImGui_ImplOpenGL3_NewFrame();
|
||||
}
|
||||
|
||||
pub fn renderDrawData(data: *imgui.DrawData) void {
|
||||
ImGui_ImplOpenGL3_RenderDrawData(data);
|
||||
}
|
||||
|
||||
extern "c" fn glfwGetError(?*const anyopaque) c_int;
|
||||
extern "c" fn ImGui_ImplOpenGL3_Init([*c]const u8) bool;
|
||||
extern "c" fn ImGui_ImplOpenGL3_Shutdown() void;
|
||||
extern "c" fn ImGui_ImplOpenGL3_NewFrame() void;
|
||||
extern "c" fn ImGui_ImplOpenGL3_RenderDrawData(*imgui.DrawData) void;
|
||||
};
|
26
pkg/imgui/io.zig
Normal file
26
pkg/imgui/io.zig
Normal file
@ -0,0 +1,26 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const imgui = @import("main.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const IO = opaque {
|
||||
pub fn get() Allocator.Error!*IO {
|
||||
return @ptrCast(
|
||||
?*IO,
|
||||
c.igGetIO(),
|
||||
) orelse Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub inline fn cval(self: *IO) *c.ImGuiIO {
|
||||
return @ptrCast(
|
||||
*c.ImGuiIO,
|
||||
@alignCast(@alignOf(c.ImGuiIO), self),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
test {
|
||||
const ctx = try imgui.Context.create();
|
||||
defer ctx.destroy();
|
||||
_ = try IO.get();
|
||||
}
|
13
pkg/imgui/main.zig
Normal file
13
pkg/imgui/main.zig
Normal file
@ -0,0 +1,13 @@
|
||||
pub const c = @import("c.zig");
|
||||
pub usingnamespace @import("context.zig");
|
||||
pub usingnamespace @import("core.zig");
|
||||
pub usingnamespace @import("draw_data.zig");
|
||||
pub usingnamespace @import("io.zig");
|
||||
pub usingnamespace @import("style.zig");
|
||||
|
||||
pub usingnamespace @import("impl_glfw.zig");
|
||||
pub usingnamespace @import("impl_opengl3.zig");
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
}
|
35
pkg/imgui/style.zig
Normal file
35
pkg/imgui/style.zig
Normal file
@ -0,0 +1,35 @@
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Style = opaque {
|
||||
pub fn get() Allocator.Error!*Style {
|
||||
return @ptrCast(
|
||||
?*Style,
|
||||
c.igGetStyle(),
|
||||
) orelse Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub fn colorsDark(self: *Style) void {
|
||||
c.igStyleColorsDark(self.cval());
|
||||
}
|
||||
|
||||
pub fn colorsLight(self: *Style) void {
|
||||
c.igStyleColorsLight(self.cval());
|
||||
}
|
||||
|
||||
pub fn colorsClassic(self: *Style) void {
|
||||
c.igStyleColorsClassic(self.cval());
|
||||
}
|
||||
|
||||
pub fn scaleAllSizes(self: *Style, factor: f32) void {
|
||||
c.ImGuiStyle_ScaleAllSizes(self.cval(), factor);
|
||||
}
|
||||
|
||||
pub inline fn cval(self: *Style) *c.ImGuiStyle {
|
||||
return @ptrCast(
|
||||
*c.ImGuiStyle,
|
||||
@alignCast(@alignOf(c.ImGuiStyle), self),
|
||||
);
|
||||
}
|
||||
};
|
38
src/DevMode.zig
Normal file
38
src/DevMode.zig
Normal file
@ -0,0 +1,38 @@
|
||||
//! This file implements the "dev mode" interface for the terminal. This
|
||||
//! includes state managements and rendering.
|
||||
const DevMode = @This();
|
||||
|
||||
const imgui = @import("imgui");
|
||||
|
||||
/// If this is false, the rest of the terminal will be compiled without
|
||||
/// dev mode support at all.
|
||||
pub const enabled = true;
|
||||
|
||||
/// The global DevMode instance that can be used app-wide. Assume all functions
|
||||
/// are NOT thread-safe unless otherwise noted.
|
||||
pub var instance: DevMode = .{};
|
||||
|
||||
/// Whether to show the dev mode UI currently.
|
||||
visible: bool = false,
|
||||
|
||||
/// Update the state associated with the dev mode. This should generally
|
||||
/// only be called paired with a render since it otherwise wastes CPU
|
||||
/// cycles.
|
||||
pub fn update(self: DevMode) void {
|
||||
_ = self;
|
||||
imgui.ImplOpenGL3.newFrame();
|
||||
imgui.ImplGlfw.newFrame();
|
||||
imgui.newFrame();
|
||||
|
||||
// Just demo for now
|
||||
imgui.showDemoWindow(null);
|
||||
}
|
||||
|
||||
/// Render the scene and return the draw data. The caller must be imgui-aware
|
||||
/// in order to render the draw data. This lets this file be renderer/backend
|
||||
/// agnostic.
|
||||
pub fn render(self: DevMode) !*imgui.DrawData {
|
||||
_ = self;
|
||||
imgui.render();
|
||||
return try imgui.DrawData.get();
|
||||
}
|
@ -12,6 +12,7 @@ const Allocator = std.mem.Allocator;
|
||||
const Grid = @import("Grid.zig");
|
||||
const glfw = @import("glfw");
|
||||
const gl = @import("opengl.zig");
|
||||
const imgui = @import("imgui");
|
||||
const libuv = @import("libuv");
|
||||
const Pty = @import("Pty.zig");
|
||||
const font = @import("font/main.zig");
|
||||
@ -22,6 +23,7 @@ const max_timer = @import("max_timer.zig");
|
||||
const terminal = @import("terminal/main.zig");
|
||||
const Config = @import("config.zig").Config;
|
||||
const input = @import("input.zig");
|
||||
const DevMode = @import("DevMode.zig");
|
||||
|
||||
const RenderTimer = max_timer.MaxTimer(renderTimerCallback);
|
||||
|
||||
@ -45,6 +47,9 @@ window: glfw.Window,
|
||||
/// The glfw mouse cursor handle.
|
||||
cursor: glfw.Cursor,
|
||||
|
||||
/// Imgui context
|
||||
imgui_ctx: if (DevMode.enabled) *imgui.Context else void,
|
||||
|
||||
/// Whether the window is currently focused
|
||||
focused: bool,
|
||||
|
||||
@ -475,7 +480,10 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
||||
.bg_g = @intToFloat(f32, config.background.g) / 255.0,
|
||||
.bg_b = @intToFloat(f32, config.background.b) / 255.0,
|
||||
.bg_a = 1.0,
|
||||
|
||||
.imgui_ctx = if (!DevMode.enabled) void else try imgui.Context.create(),
|
||||
};
|
||||
errdefer if (DevMode.enabled) self.imgui_ctx.destroy();
|
||||
|
||||
// Setup our callbacks and user data
|
||||
window.setUserPointer(self);
|
||||
@ -499,10 +507,37 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
||||
@intCast(i32, window_size.height),
|
||||
);
|
||||
|
||||
// Load imgui. This must be done LAST because it has to be done after
|
||||
// all our GLFW setup is complete.
|
||||
if (DevMode.enabled) {
|
||||
const io = try imgui.IO.get();
|
||||
io.cval().IniFilename = "ghostty_dev_mode.ini";
|
||||
|
||||
// On Mac imgui handles scaling automatically just fine. On Linux
|
||||
// and other platforms we need to apply a scaling factor.
|
||||
if (builtin.os.tag != .macos) io.cval().FontGlobalScale = content_scale.x_scale;
|
||||
|
||||
const style = try imgui.Style.get();
|
||||
style.colorsDark();
|
||||
|
||||
assert(imgui.ImplGlfw.initForOpenGL(
|
||||
@ptrCast(*imgui.ImplGlfw.GLFWWindow, window.handle),
|
||||
true,
|
||||
));
|
||||
assert(imgui.ImplOpenGL3.init("#version 330 core"));
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Window) void {
|
||||
if (DevMode.enabled) {
|
||||
// Uninitialize imgui
|
||||
imgui.ImplOpenGL3.shutdown();
|
||||
imgui.ImplGlfw.shutdown();
|
||||
self.imgui_ctx.destroy();
|
||||
}
|
||||
|
||||
// Deinitialize the pty. This closes the pty handles. This should
|
||||
// cause a close in the our subprocess so just wait for that.
|
||||
self.pty.deinit();
|
||||
@ -747,6 +782,7 @@ fn keyCallback(
|
||||
.F10 => .f10,
|
||||
.F11 => .f11,
|
||||
.F12 => .f12,
|
||||
.grave_accent => .grave_accent,
|
||||
else => .invalid,
|
||||
},
|
||||
};
|
||||
@ -795,6 +831,11 @@ fn keyCallback(
|
||||
log.err("error queueing write in keyCallback err={}", .{err});
|
||||
}
|
||||
},
|
||||
|
||||
.toggle_dev_mode => if (DevMode.enabled) {
|
||||
DevMode.instance.visible = !DevMode.instance.visible;
|
||||
win.render_timer.schedule() catch unreachable;
|
||||
} else log.warn("dev mode was not compiled into this binary", .{}),
|
||||
}
|
||||
|
||||
// Bindings always result in us ignoring the char if printable
|
||||
@ -1109,6 +1150,13 @@ fn mouseButtonCallback(
|
||||
|
||||
const win = window.getUserPointer(Window) orelse return;
|
||||
|
||||
// If our dev mode window is visible then we always schedule a render on
|
||||
// cursor move because the cursor might touch our windows.
|
||||
if (DevMode.enabled and DevMode.instance.visible) {
|
||||
win.render_timer.schedule() catch |err|
|
||||
log.err("error scheduling render timer in cursorPosCallback err={}", .{err});
|
||||
}
|
||||
|
||||
// Convert glfw button to input button
|
||||
const button: input.MouseButton = switch (glfw_button) {
|
||||
.left => .left,
|
||||
@ -1186,6 +1234,13 @@ fn cursorPosCallback(
|
||||
|
||||
const win = window.getUserPointer(Window) orelse return;
|
||||
|
||||
// If our dev mode window is visible then we always schedule a render on
|
||||
// cursor move because the cursor might touch our windows.
|
||||
if (DevMode.enabled and DevMode.instance.visible) {
|
||||
win.render_timer.schedule() catch |err|
|
||||
log.err("error scheduling render timer in cursorPosCallback err={}", .{err});
|
||||
}
|
||||
|
||||
// Do a mouse report
|
||||
if (win.terminal.modes.mouse_event != .none) {
|
||||
// We use the first mouse button we find pressed in order to report
|
||||
@ -1525,6 +1580,12 @@ fn renderTimerCallback(t: *libuv.Timer) void {
|
||||
return;
|
||||
};
|
||||
|
||||
if (DevMode.enabled and DevMode.instance.visible) {
|
||||
DevMode.instance.update();
|
||||
const data = DevMode.instance.render() catch unreachable;
|
||||
imgui.ImplOpenGL3.renderDrawData(data);
|
||||
}
|
||||
|
||||
// Swap
|
||||
win.window.swapBuffers() catch |err| {
|
||||
log.err("error swapping buffers: {}", .{err});
|
||||
|
@ -120,6 +120,13 @@ pub const Config = struct {
|
||||
try result.keybind.set.put(alloc, .{ .key = .f11 }, .{ .csi = "23~" });
|
||||
try result.keybind.set.put(alloc, .{ .key = .f12 }, .{ .csi = "24~" });
|
||||
|
||||
// Dev Mode
|
||||
try result.keybind.set.put(
|
||||
alloc,
|
||||
.{ .key = .grave_accent, .mods = .{ .shift = true, .super = true } },
|
||||
.{ .toggle_dev_mode = 0 },
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,9 @@ pub const Action = union(enum) {
|
||||
/// Copy and paste.
|
||||
copy_to_clipboard: Void,
|
||||
paste_from_clipboard: Void,
|
||||
|
||||
/// Dev mode
|
||||
toggle_dev_mode: Void,
|
||||
};
|
||||
|
||||
/// Trigger is the associated key state that can trigger an action.
|
||||
|
@ -49,6 +49,9 @@ pub const Key = enum {
|
||||
y,
|
||||
z,
|
||||
|
||||
// other
|
||||
grave_accent, // `
|
||||
|
||||
// control
|
||||
up,
|
||||
down,
|
||||
|
1
vendor/cimgui
vendored
Submodule
1
vendor/cimgui
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 9ce2c32dada1e1fcb90f2c9bab2568895db719f5
|
Reference in New Issue
Block a user