1 // dear imgui: Platform Backend for GLFW
2 // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
3 // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
4 // (Requires: GLFW 3.1+)
5
6 // Implemented features:
7 // [X] Platform: Clipboard support.
8 // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9 // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
10 // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
11
12 // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
13 // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
14 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
15 // Read online: https://github.com/ocornut/imgui/tree/master/docs
16
17 // CHANGELOG
18 // (minor and older changes stripped away, please see git history for details)
19 // 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
20 // 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
21 // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
22 // 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
23 // 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
24 // 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
25 // 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
26 // 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
27 // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
28 // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
29 // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
30 // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
31 // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
32 // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
33 // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
34 // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
35 // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
36 // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
37 // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
38 // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
39 // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
40 // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
41 // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
42 // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
43
44 #include "imgui.h"
45 #include "imgui_impl_glfw.h"
46
47 // GLFW
48 #include <GLFW/glfw3.h>
49 #ifdef _WIN32
50 #undef APIENTRY
51 #define GLFW_EXPOSE_NATIVE_WIN32
52 #include <GLFW/glfw3native.h> // for glfwGetWin32Window
53 #endif
54 #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
55 #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
56 #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
57 #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
58 #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
59 #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
60 #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
61 #else
62 #define GLFW_HAS_NEW_CURSORS (0)
63 #endif
64
65 // GLFW data
66 enum GlfwClientApi
67 {
68 GlfwClientApi_Unknown,
69 GlfwClientApi_OpenGL,
70 GlfwClientApi_Vulkan
71 };
72
73 struct ImGui_ImplGlfw_Data
74 {
75 GLFWwindow* Window;
76 GlfwClientApi ClientApi;
77 double Time;
78 GLFWwindow* MouseWindow;
79 bool MouseJustPressed[ImGuiMouseButton_COUNT];
80 GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
81 bool InstalledCallbacks;
82
83 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
84 GLFWwindowfocusfun PrevUserCallbackWindowFocus;
85 GLFWcursorenterfun PrevUserCallbackCursorEnter;
86 GLFWmousebuttonfun PrevUserCallbackMousebutton;
87 GLFWscrollfun PrevUserCallbackScroll;
88 GLFWkeyfun PrevUserCallbackKey;
89 GLFWcharfun PrevUserCallbackChar;
90 GLFWmonitorfun PrevUserCallbackMonitor;
91
ImGui_ImplGlfw_DataImGui_ImplGlfw_Data92 ImGui_ImplGlfw_Data() { memset(this, 0, sizeof(*this)); }
93 };
94
95 // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
96 // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
97 // FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
98 // - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
99 // (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
100 // - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
101 // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
ImGui_ImplGlfw_GetBackendData()102 static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
103 {
104 return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
105 }
106
107 // Functions
ImGui_ImplGlfw_GetClipboardText(void * user_data)108 static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
109 {
110 return glfwGetClipboardString((GLFWwindow*)user_data);
111 }
112
ImGui_ImplGlfw_SetClipboardText(void * user_data,const char * text)113 static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
114 {
115 glfwSetClipboardString((GLFWwindow*)user_data, text);
116 }
117
ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow * window,int button,int action,int mods)118 void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
119 {
120 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
121 if (bd->PrevUserCallbackMousebutton != NULL && window == bd->Window)
122 bd->PrevUserCallbackMousebutton(window, button, action, mods);
123
124 if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
125 bd->MouseJustPressed[button] = true;
126 }
127
ImGui_ImplGlfw_ScrollCallback(GLFWwindow * window,double xoffset,double yoffset)128 void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
129 {
130 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
131 if (bd->PrevUserCallbackScroll != NULL && window == bd->Window)
132 bd->PrevUserCallbackScroll(window, xoffset, yoffset);
133
134 ImGuiIO& io = ImGui::GetIO();
135 io.MouseWheelH += (float)xoffset;
136 io.MouseWheel += (float)yoffset;
137 }
138
ImGui_ImplGlfw_KeyCallback(GLFWwindow * window,int key,int scancode,int action,int mods)139 void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
140 {
141 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
142 if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
143 bd->PrevUserCallbackKey(window, key, scancode, action, mods);
144
145 ImGuiIO& io = ImGui::GetIO();
146 if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
147 {
148 if (action == GLFW_PRESS)
149 io.KeysDown[key] = true;
150 if (action == GLFW_RELEASE)
151 io.KeysDown[key] = false;
152 }
153
154 // Modifiers are not reliable across systems
155 io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
156 io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
157 io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
158 #ifdef _WIN32
159 io.KeySuper = false;
160 #else
161 io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
162 #endif
163 }
164
ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow * window,int focused)165 void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
166 {
167 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
168 if (bd->PrevUserCallbackWindowFocus != NULL && window == bd->Window)
169 bd->PrevUserCallbackWindowFocus(window, focused);
170
171 ImGuiIO& io = ImGui::GetIO();
172 io.AddFocusEvent(focused != 0);
173 }
174
ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow * window,int entered)175 void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
176 {
177 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
178 if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
179 bd->PrevUserCallbackCursorEnter(window, entered);
180
181 if (entered)
182 bd->MouseWindow = window;
183 if (!entered && bd->MouseWindow == window)
184 bd->MouseWindow = NULL;
185 }
186
ImGui_ImplGlfw_CharCallback(GLFWwindow * window,unsigned int c)187 void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
188 {
189 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
190 if (bd->PrevUserCallbackChar != NULL && window == bd->Window)
191 bd->PrevUserCallbackChar(window, c);
192
193 ImGuiIO& io = ImGui::GetIO();
194 io.AddInputCharacter(c);
195 }
196
ImGui_ImplGlfw_MonitorCallback(GLFWmonitor *,int)197 void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
198 {
199 // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
200 }
201
ImGui_ImplGlfw_Init(GLFWwindow * window,bool install_callbacks,GlfwClientApi client_api)202 static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
203 {
204 ImGuiIO& io = ImGui::GetIO();
205 IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
206
207 // Setup backend capabilities flags
208 ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
209 io.BackendPlatformUserData = (void*)bd;
210 io.BackendPlatformName = "imgui_impl_glfw";
211 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
212 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
213
214 bd->Window = window;
215 bd->Time = 0.0;
216
217 // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
218 io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
219 io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
220 io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
221 io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
222 io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
223 io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
224 io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
225 io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
226 io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
227 io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
228 io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
229 io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
230 io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
231 io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
232 io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
233 io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
234 io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
235 io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
236 io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
237 io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
238 io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
239 io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
240
241 io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
242 io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
243 io.ClipboardUserData = bd->Window;
244 #if defined(_WIN32)
245 io.ImeWindowHandle = (void*)glfwGetWin32Window(bd->Window);
246 #endif
247
248 // Create mouse cursors
249 // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
250 // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
251 // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
252 GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
253 bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
254 bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
255 bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
256 bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
257 bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
258 #if GLFW_HAS_NEW_CURSORS
259 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
260 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
261 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
262 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
263 #else
264 bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
265 bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
266 bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
267 bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
268 #endif
269 glfwSetErrorCallback(prev_error_callback);
270
271 // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
272 bd->PrevUserCallbackWindowFocus = NULL;
273 bd->PrevUserCallbackMousebutton = NULL;
274 bd->PrevUserCallbackScroll = NULL;
275 bd->PrevUserCallbackKey = NULL;
276 bd->PrevUserCallbackChar = NULL;
277 bd->PrevUserCallbackMonitor = NULL;
278 if (install_callbacks)
279 {
280 bd->InstalledCallbacks = true;
281 bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
282 bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
283 bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
284 bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
285 bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
286 bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
287 bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
288 }
289
290 bd->ClientApi = client_api;
291 return true;
292 }
293
ImGui_ImplGlfw_InitForOpenGL(GLFWwindow * window,bool install_callbacks)294 bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
295 {
296 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
297 }
298
ImGui_ImplGlfw_InitForVulkan(GLFWwindow * window,bool install_callbacks)299 bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
300 {
301 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
302 }
303
ImGui_ImplGlfw_InitForOther(GLFWwindow * window,bool install_callbacks)304 bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
305 {
306 return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
307 }
308
ImGui_ImplGlfw_Shutdown()309 void ImGui_ImplGlfw_Shutdown()
310 {
311 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
312 IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
313 ImGuiIO& io = ImGui::GetIO();
314
315 if (bd->InstalledCallbacks)
316 {
317 glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus);
318 glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
319 glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
320 glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
321 glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
322 glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
323 glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
324 }
325
326 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
327 glfwDestroyCursor(bd->MouseCursors[cursor_n]);
328
329 io.BackendPlatformName = NULL;
330 io.BackendPlatformUserData = NULL;
331 IM_DELETE(bd);
332 }
333
ImGui_ImplGlfw_UpdateMousePosAndButtons()334 static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
335 {
336 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
337 ImGuiIO& io = ImGui::GetIO();
338
339 const ImVec2 mouse_pos_prev = io.MousePos;
340 io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
341
342 // Update mouse buttons
343 // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
344 for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
345 {
346 io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
347 bd->MouseJustPressed[i] = false;
348 }
349
350 #ifdef __EMSCRIPTEN__
351 const bool focused = true;
352 #else
353 const bool focused = glfwGetWindowAttrib(bd->Window, GLFW_FOCUSED) != 0;
354 #endif
355 GLFWwindow* mouse_window = (bd->MouseWindow == bd->Window || focused) ? bd->Window : NULL;
356
357 // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
358 if (io.WantSetMousePos && focused)
359 glfwSetCursorPos(bd->Window, (double)mouse_pos_prev.x, (double)mouse_pos_prev.y);
360
361 // Set Dear ImGui mouse position from OS position
362 if (mouse_window != NULL)
363 {
364 double mouse_x, mouse_y;
365 glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
366 io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
367 }
368 }
369
ImGui_ImplGlfw_UpdateMouseCursor()370 static void ImGui_ImplGlfw_UpdateMouseCursor()
371 {
372 ImGuiIO& io = ImGui::GetIO();
373 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
374 if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
375 return;
376
377 ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
378 if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
379 {
380 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
381 glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
382 }
383 else
384 {
385 // Show OS mouse cursor
386 // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
387 glfwSetCursor(bd->Window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
388 glfwSetInputMode(bd->Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
389 }
390 }
391
ImGui_ImplGlfw_UpdateGamepads()392 static void ImGui_ImplGlfw_UpdateGamepads()
393 {
394 ImGuiIO& io = ImGui::GetIO();
395 memset(io.NavInputs, 0, sizeof(io.NavInputs));
396 if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
397 return;
398
399 // Update gamepad inputs
400 #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
401 #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
402 int axes_count = 0, buttons_count = 0;
403 const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
404 const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
405 MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
406 MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
407 MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
408 MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
409 MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
410 MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
411 MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
412 MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
413 MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
414 MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
415 MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
416 MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
417 MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
418 MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
419 MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
420 MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
421 #undef MAP_BUTTON
422 #undef MAP_ANALOG
423 if (axes_count > 0 && buttons_count > 0)
424 io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
425 else
426 io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
427 }
428
ImGui_ImplGlfw_NewFrame()429 void ImGui_ImplGlfw_NewFrame()
430 {
431 ImGuiIO& io = ImGui::GetIO();
432 ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
433 IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?");
434
435 // Setup display size (every frame to accommodate for window resizing)
436 int w, h;
437 int display_w, display_h;
438 glfwGetWindowSize(bd->Window, &w, &h);
439 glfwGetFramebufferSize(bd->Window, &display_w, &display_h);
440 io.DisplaySize = ImVec2((float)w, (float)h);
441 if (w > 0 && h > 0)
442 io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
443
444 // Setup time step
445 double current_time = glfwGetTime();
446 io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
447 bd->Time = current_time;
448
449 ImGui_ImplGlfw_UpdateMousePosAndButtons();
450 ImGui_ImplGlfw_UpdateMouseCursor();
451
452 // Update game controllers (if enabled and available)
453 ImGui_ImplGlfw_UpdateGamepads();
454 }
455