imgui_impl_glfw.cpp 22 KB

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