const c = @import("c.zig"); const builtin = @import("builtin"); pub const ClientApi = enum { Unknown, OpenGL, Vulkan, }; // Data var g_Window: ?*c.GLFWwindow = null; var g_ClientApi: ClientApi = .Unknown; var g_Time: f32 = 0.0; var g_MouseJustPressed = [_]bool{ false } ** 5; var g_MouseCursors = [_]?*c.GLFWcursor{ null } ** @enumToInt(c.ImGuiMouseCursor_COUNT); var g_WantUpdateMonitors = true; // Chain GLFW callbacks for main viewport: // our callbacks will call the user's previously installed callbacks, if any. var g_PrevUserCallbackMousebutton: ?c.GLFWmousebuttonfun = null; var g_PrevUserCallbackScroll: ?c.GLFWscrollfun = null; var g_PrevUserCallbackKey: ?c.GLFWkeyfun = null; var g_PrevUserCallbackChar: ?c.GLFWcharfun = null; pub fn Init(window: *c.GLFWwindow, install_callbacks: bool, client_api: ClientApi) void { g_Window = window; g_Time = 0.0; // Setup back-end capabilities flags const io = c.igGetIO(); io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasMouseCursors); // We can honor GetMouseCursor() values (optional) io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_HasSetMousePos); // We can honor io.WantSetMousePos requests (optional, rarely used) io.*.BackendFlags |= @enumToInt(c.ImGuiBackendFlags_PlatformHasViewports); // We can create multi-viewports on the Platform side (optional) if (@hasField(c, "GLFW_HAS_GLFW_HOVERED") and builtin.os == builtin.Os.windows) { io.*.BackendFlags |= @enumToInt(ImGuiBackendFlags_HasMouseHoveredViewport); // We can set io.MouseHoveredViewport correctly (optional, not easy) } io.*.BackendPlatformName = c"imgui_impl_glfw.zig"; // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. io.*.KeyMap[@enumToInt(c.ImGuiKey_Tab)] = c.GLFW_KEY_TAB; io.*.KeyMap[@enumToInt(c.ImGuiKey_LeftArrow)] = c.GLFW_KEY_LEFT; io.*.KeyMap[@enumToInt(c.ImGuiKey_RightArrow)] = c.GLFW_KEY_RIGHT; io.*.KeyMap[@enumToInt(c.ImGuiKey_UpArrow)] = c.GLFW_KEY_UP; io.*.KeyMap[@enumToInt(c.ImGuiKey_DownArrow)] = c.GLFW_KEY_DOWN; io.*.KeyMap[@enumToInt(c.ImGuiKey_PageUp)] = c.GLFW_KEY_PAGE_UP; io.*.KeyMap[@enumToInt(c.ImGuiKey_PageDown)] = c.GLFW_KEY_PAGE_DOWN; io.*.KeyMap[@enumToInt(c.ImGuiKey_Home)] = c.GLFW_KEY_HOME; io.*.KeyMap[@enumToInt(c.ImGuiKey_End)] = c.GLFW_KEY_END; io.*.KeyMap[@enumToInt(c.ImGuiKey_Insert)] = c.GLFW_KEY_INSERT; io.*.KeyMap[@enumToInt(c.ImGuiKey_Delete)] = c.GLFW_KEY_DELETE; io.*.KeyMap[@enumToInt(c.ImGuiKey_Backspace)] = c.GLFW_KEY_BACKSPACE; io.*.KeyMap[@enumToInt(c.ImGuiKey_Space)] = c.GLFW_KEY_SPACE; io.*.KeyMap[@enumToInt(c.ImGuiKey_Enter)] = c.GLFW_KEY_ENTER; io.*.KeyMap[@enumToInt(c.ImGuiKey_Escape)] = c.GLFW_KEY_ESCAPE; io.*.KeyMap[@enumToInt(c.ImGuiKey_KeyPadEnter)] = c.GLFW_KEY_KP_ENTER; io.*.KeyMap[@enumToInt(c.ImGuiKey_A)] = c.GLFW_KEY_A; io.*.KeyMap[@enumToInt(c.ImGuiKey_C)] = c.GLFW_KEY_C; io.*.KeyMap[@enumToInt(c.ImGuiKey_V)] = c.GLFW_KEY_V; io.*.KeyMap[@enumToInt(c.ImGuiKey_X)] = c.GLFW_KEY_X; io.*.KeyMap[@enumToInt(c.ImGuiKey_Y)] = c.GLFW_KEY_Y; io.*.KeyMap[@enumToInt(c.ImGuiKey_Z)] = c.GLFW_KEY_Z; // @TODO: Clipboard // io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; // io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; // io.ClipboardUserData = g_Window; g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Arrow)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_TextInput)] = c.glfwCreateStandardCursor(c.GLFW_IBEAM_CURSOR); g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeAll)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNS)] = c.glfwCreateStandardCursor(c.GLFW_VRESIZE_CURSOR); g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeEW)] = c.glfwCreateStandardCursor(c.GLFW_HRESIZE_CURSOR); g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNESW)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_ResizeNWSE)] = c.glfwCreateStandardCursor(c.GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. g_MouseCursors[@enumToInt(c.ImGuiMouseCursor_Hand)] = c.glfwCreateStandardCursor(c.GLFW_HAND_CURSOR); // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. g_PrevUserCallbackMousebutton = null; g_PrevUserCallbackScroll = null; g_PrevUserCallbackKey = null; g_PrevUserCallbackChar = null; if (install_callbacks) { g_PrevUserCallbackMousebutton = c.glfwSetMouseButtonCallback(window, Callback_MouseButton); g_PrevUserCallbackScroll = c.glfwSetScrollCallback(window, Callback_Scroll); g_PrevUserCallbackKey = c.glfwSetKeyCallback(window, Callback_Key); g_PrevUserCallbackChar = c.glfwSetCharCallback(window, Callback_Char); } // Our mouse update function expect PlatformHandle to be filled for the main viewport const main_viewport = c.igGetMainViewport(); main_viewport.*.PlatformHandle = g_Window; if (builtin.os == builtin.Os.windows) { main_viewport.*.PlatformHandleRaw = c.glfwGetWin32Window(g_Window); } // @TODO: Platform Interface (Viewport) // if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable != 0) // ImGui_ImplGlfw_InitPlatformInterface(); g_ClientApi = client_api; } pub fn Shutdown() void { // @TODO: Platform Interface (Viewport) // ImGui_ImplGlfw_ShutdownPlatformInterface(); for (g_MouseCursors) |*cursor| { c.glfwDestroyCursor(cursor.*); cursor.* = null; } g_ClientApi = .Unknown; } pub fn NewFrame() void { const io = c.igGetIO(); // @TODO: assert font atlas var w : c_int = undefined; var h : c_int = undefined; var display_w : c_int = undefined; var display_h : c_int = undefined; c.glfwGetWindowSize(g_Window, &w, &h); c.glfwGetFramebufferSize(g_Window, &display_w, &display_h); io.*.DisplaySize = c.ImVec2{ .x = @intToFloat(f32, w), .y = @intToFloat(f32, h) }; } // GLFW Callbacks extern fn Callback_MouseButton(window: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) void { // @TODO: delegate up if (button < 0) return; const button_u = @intCast(usize, button); if (action == c.GLFW_PRESS and button_u < g_MouseJustPressed.len) g_MouseJustPressed[button_u] = true; } extern fn Callback_Scroll(window: ?*c.GLFWwindow, dx: f64, dy: f64) void { // @TODO: delegate up const io = c.igGetIO(); io.*.MouseWheelH += @floatCast(f32, dx); io.*.MouseWheel += @floatCast(f32, dy); } extern fn Callback_Key(window: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, modifiers: c_int) void { // @TODO: delegate up if (key < 0) unreachable; const key_u = @intCast(usize, key); const io = c.igGetIO(); if (action == c.GLFW_PRESS) io.*.KeysDown[key_u] = true; if (action == c.GLFW_RELEASE) io.*.KeysDown[key_u] = false; // Modifiers are not reliable across systems io.*.KeyCtrl = io.*.KeysDown[c.GLFW_KEY_LEFT_CONTROL] or io.*.KeysDown[c.GLFW_KEY_RIGHT_CONTROL]; io.*.KeyShift = io.*.KeysDown[c.GLFW_KEY_LEFT_SHIFT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SHIFT]; io.*.KeyAlt = io.*.KeysDown[c.GLFW_KEY_LEFT_ALT] or io.*.KeysDown[c.GLFW_KEY_RIGHT_ALT]; io.*.KeySuper = io.*.KeysDown[c.GLFW_KEY_LEFT_SUPER] or io.*.KeysDown[c.GLFW_KEY_RIGHT_SUPER]; } extern fn Callback_Char(window: ?*c.GLFWwindow, char: c_uint) void { // @TODO: delegate up const io = c.igGetIO(); c.ImGuiIO_AddInputCharacter(io, char); }