imgui-bindings 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,511 +1,511 @@
1
- require 'ffi'
2
- require 'opengl'
3
- require 'glfw'
4
-
5
- require_relative 'imgui'
6
-
7
- module ImGui
8
-
9
- @@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_glfw")
10
-
11
- # ImGui::GetCurrentContext().address => ImGui_ImplGlfw_Data
12
- @@g_BackendData = Hash.new
13
-
14
- class ImGui_ImplGlfw_Data
15
- attr_accessor :window, :time, :mouseWindow, :mouseCursors, :lastValidMousePos, :installedCallbacks
16
- attr_accessor :prevUserCallbackWindowFocus, :prevUserCallbackCursorPos, :prevUserCallbackCursorEnter, :prevUserCallbackMousebutton, :prevUserCallbackScroll, :prevUserCallbackKey, :prevUserCallbackChar, :prevUserCallbackMonitor
17
-
18
- def initialize
19
- @window = nil # GLFWwindow*
20
- @time = 0.0 # double
21
- @mouseWindow = nil # GLFWwindow*
22
- @mouseCursors = Array.new(ImGuiMouseCursor_COUNT) { 0 } # GLFWcursor*
23
- @lastValidMousePos = ImVec2.create # ImVec2
24
- @installedCallbacks = false # bool
25
-
26
- # Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
27
- @prevUserCallbackWindowFocus = nil # GLFWwindowfocusfun
28
- @prevUserCallbackCursorPos = nil # GLFWcursorposfun
29
- @prevUserCallbackCursorEnter = nil # GLFWcursorenterfun
30
- @prevUserCallbackMousebutton = nil # GLFWmousebuttonfun
31
- @prevUserCallbackScroll = nil # GLFWscrollfun
32
- @prevUserCallbackKey = nil # GLFWkeyfun
33
- @prevUserCallbackChar = nil # GLFWcharfun
34
- @prevUserCallbackMonitor = nil # GLFWmonitorfun
35
- end
36
- end
37
-
38
- # Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
39
- # It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
40
- # FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
41
- # - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
42
- # (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
43
- # - 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.
44
- # FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
45
- def self.ImGui_ImplGlfw_GetBackendData()
46
- if ImGui::GetCurrentContext() != nil
47
- return @@g_BackendData[ImGui::GetCurrentContext().address]
48
- # io = ImGuiIO.new(ImGui::GetIO())
49
- # return ImGui_ImplGlfw_Data.new(io[:BackendPlatformUserData])
50
- else
51
- nil
52
- end
53
- end
54
-
55
- def self.ImGui_ImplGlfw_GetClipboardText(user_data)
56
- glfwGetClipboardString(user_data)
57
- end
58
-
59
- def self.ImGui_ImplGlfw_SetClipboardText(user_data, text)
60
- glfwSetClipboardString(user_data, text)
61
- end
62
-
63
- def self.ImGui_ImplGlfw_KeyToImGuiKey(key)
64
- case key
65
- when GLFW::KEY_TAB then ImGuiKey_Tab
66
- when GLFW::KEY_LEFT then ImGuiKey_LeftArrow
67
- when GLFW::KEY_RIGHT then ImGuiKey_RightArrow
68
- when GLFW::KEY_UP then ImGuiKey_UpArrow
69
- when GLFW::KEY_DOWN then ImGuiKey_DownArrow
70
- when GLFW::KEY_PAGE_UP then ImGuiKey_PageUp
71
- when GLFW::KEY_PAGE_DOWN then ImGuiKey_PageDown
72
- when GLFW::KEY_HOME then ImGuiKey_Home
73
- when GLFW::KEY_END then ImGuiKey_End
74
- when GLFW::KEY_INSERT then ImGuiKey_Insert
75
- when GLFW::KEY_DELETE then ImGuiKey_Delete
76
- when GLFW::KEY_BACKSPACE then ImGuiKey_Backspace
77
- when GLFW::KEY_SPACE then ImGuiKey_Space
78
- when GLFW::KEY_ENTER then ImGuiKey_Enter
79
- when GLFW::KEY_ESCAPE then ImGuiKey_Escape
80
- when GLFW::KEY_APOSTROPHE then ImGuiKey_Apostrophe
81
- when GLFW::KEY_COMMA then ImGuiKey_Comma
82
- when GLFW::KEY_MINUS then ImGuiKey_Minus
83
- when GLFW::KEY_PERIOD then ImGuiKey_Period
84
- when GLFW::KEY_SLASH then ImGuiKey_Slash
85
- when GLFW::KEY_SEMICOLON then ImGuiKey_Semicolon
86
- when GLFW::KEY_EQUAL then ImGuiKey_Equal
87
- when GLFW::KEY_LEFT_BRACKET then ImGuiKey_LeftBracket
88
- when GLFW::KEY_BACKSLASH then ImGuiKey_Backslash
89
- when GLFW::KEY_RIGHT_BRACKET then ImGuiKey_RightBracket
90
- when GLFW::KEY_GRAVE_ACCENT then ImGuiKey_GraveAccent
91
- when GLFW::KEY_CAPS_LOCK then ImGuiKey_CapsLock
92
- when GLFW::KEY_SCROLL_LOCK then ImGuiKey_ScrollLock
93
- when GLFW::KEY_NUM_LOCK then ImGuiKey_NumLock
94
- when GLFW::KEY_PRINT_SCREEN then ImGuiKey_PrintScreen
95
- when GLFW::KEY_PAUSE then ImGuiKey_Pause
96
- when GLFW::KEY_KP_0 then ImGuiKey_Keypad0
97
- when GLFW::KEY_KP_1 then ImGuiKey_Keypad1
98
- when GLFW::KEY_KP_2 then ImGuiKey_Keypad2
99
- when GLFW::KEY_KP_3 then ImGuiKey_Keypad3
100
- when GLFW::KEY_KP_4 then ImGuiKey_Keypad4
101
- when GLFW::KEY_KP_5 then ImGuiKey_Keypad5
102
- when GLFW::KEY_KP_6 then ImGuiKey_Keypad6
103
- when GLFW::KEY_KP_7 then ImGuiKey_Keypad7
104
- when GLFW::KEY_KP_8 then ImGuiKey_Keypad8
105
- when GLFW::KEY_KP_9 then ImGuiKey_Keypad9
106
- when GLFW::KEY_KP_DECIMAL then ImGuiKey_KeypadDecimal
107
- when GLFW::KEY_KP_DIVIDE then ImGuiKey_KeypadDivide
108
- when GLFW::KEY_KP_MULTIPLY then ImGuiKey_KeypadMultiply
109
- when GLFW::KEY_KP_SUBTRACT then ImGuiKey_KeypadSubtract
110
- when GLFW::KEY_KP_ADD then ImGuiKey_KeypadAdd
111
- when GLFW::KEY_KP_ENTER then ImGuiKey_KeypadEnter
112
- when GLFW::KEY_KP_EQUAL then ImGuiKey_KeypadEqual
113
- when GLFW::KEY_LEFT_SHIFT then ImGuiKey_LeftShift
114
- when GLFW::KEY_LEFT_CONTROL then ImGuiKey_LeftCtrl
115
- when GLFW::KEY_LEFT_ALT then ImGuiKey_LeftAlt
116
- when GLFW::KEY_LEFT_SUPER then ImGuiKey_LeftSuper
117
- when GLFW::KEY_RIGHT_SHIFT then ImGuiKey_RightShift
118
- when GLFW::KEY_RIGHT_CONTROL then ImGuiKey_RightCtrl
119
- when GLFW::KEY_RIGHT_ALT then ImGuiKey_RightAlt
120
- when GLFW::KEY_RIGHT_SUPER then ImGuiKey_RightSuper
121
- when GLFW::KEY_MENU then ImGuiKey_Menu
122
- when GLFW::KEY_0 then ImGuiKey_0
123
- when GLFW::KEY_1 then ImGuiKey_1
124
- when GLFW::KEY_2 then ImGuiKey_2
125
- when GLFW::KEY_3 then ImGuiKey_3
126
- when GLFW::KEY_4 then ImGuiKey_4
127
- when GLFW::KEY_5 then ImGuiKey_5
128
- when GLFW::KEY_6 then ImGuiKey_6
129
- when GLFW::KEY_7 then ImGuiKey_7
130
- when GLFW::KEY_8 then ImGuiKey_8
131
- when GLFW::KEY_9 then ImGuiKey_9
132
- when GLFW::KEY_A then ImGuiKey_A
133
- when GLFW::KEY_B then ImGuiKey_B
134
- when GLFW::KEY_C then ImGuiKey_C
135
- when GLFW::KEY_D then ImGuiKey_D
136
- when GLFW::KEY_E then ImGuiKey_E
137
- when GLFW::KEY_F then ImGuiKey_F
138
- when GLFW::KEY_G then ImGuiKey_G
139
- when GLFW::KEY_H then ImGuiKey_H
140
- when GLFW::KEY_I then ImGuiKey_I
141
- when GLFW::KEY_J then ImGuiKey_J
142
- when GLFW::KEY_K then ImGuiKey_K
143
- when GLFW::KEY_L then ImGuiKey_L
144
- when GLFW::KEY_M then ImGuiKey_M
145
- when GLFW::KEY_N then ImGuiKey_N
146
- when GLFW::KEY_O then ImGuiKey_O
147
- when GLFW::KEY_P then ImGuiKey_P
148
- when GLFW::KEY_Q then ImGuiKey_Q
149
- when GLFW::KEY_R then ImGuiKey_R
150
- when GLFW::KEY_S then ImGuiKey_S
151
- when GLFW::KEY_T then ImGuiKey_T
152
- when GLFW::KEY_U then ImGuiKey_U
153
- when GLFW::KEY_V then ImGuiKey_V
154
- when GLFW::KEY_W then ImGuiKey_W
155
- when GLFW::KEY_X then ImGuiKey_X
156
- when GLFW::KEY_Y then ImGuiKey_Y
157
- when GLFW::KEY_Z then ImGuiKey_Z
158
- when GLFW::KEY_F1 then ImGuiKey_F1
159
- when GLFW::KEY_F2 then ImGuiKey_F2
160
- when GLFW::KEY_F3 then ImGuiKey_F3
161
- when GLFW::KEY_F4 then ImGuiKey_F4
162
- when GLFW::KEY_F5 then ImGuiKey_F5
163
- when GLFW::KEY_F6 then ImGuiKey_F6
164
- when GLFW::KEY_F7 then ImGuiKey_F7
165
- when GLFW::KEY_F8 then ImGuiKey_F8
166
- when GLFW::KEY_F9 then ImGuiKey_F9
167
- when GLFW::KEY_F10 then ImGuiKey_F10
168
- when GLFW::KEY_F11 then ImGuiKey_F11
169
- when GLFW::KEY_F12 then ImGuiKey_F12
170
- else ImGuiKey_None
171
- end
172
- end
173
-
174
- def self.ImGui_ImplGlfw_UpdateKeyModifiers(mods)
175
- io = ImGuiIO.new(ImGui::GetIO())
176
- io.AddKeyEvent(ImGuiMod_Ctrl, (mods & GLFW::MOD_CONTROL) != 0)
177
- io.AddKeyEvent(ImGuiMod_Shift, (mods & GLFW::MOD_SHIFT) != 0)
178
- io.AddKeyEvent(ImGuiMod_Alt, (mods & GLFW::MOD_ALT) != 0)
179
- io.AddKeyEvent(ImGuiMod_Super, (mods & GLFW::MOD_SUPER) != 0)
180
- end
181
-
182
- @@ImplGlfw_MouseButtonCallback = GLFW::create_callback(:GLFWmousebuttonfun) do |window, button, action, mods|
183
- bd = ImGui_ImplGlfw_GetBackendData()
184
- unless bd.prevUserCallbackMousebutton.null?
185
- userfunc = Fiddle::Function.new(bd.prevUserCallbackMousebutton, GLFW::GLFWmousebuttonfun_cb_args, GLFW::GLFWmousebuttonfun_cb_retval)
186
- userfunc.call(window, button, action, mods)
187
- end
188
-
189
- ImGui_ImplGlfw_UpdateKeyModifiers(mods)
190
-
191
- io = ImGuiIO.new(ImGui::GetIO())
192
- if button >= 0 && button < ImGuiMouseButton_COUNT
193
- io.AddMouseButtonEvent(button, action == GLFW::PRESS)
194
- end
195
- end
196
-
197
- @@ImplGlfw_ScrollCallback = GLFW::create_callback(:GLFWscrollfun) do |window, xoffset, yoffset|
198
- bd = ImGui_ImplGlfw_GetBackendData()
199
- unless bd.prevUserCallbackScroll.null?
200
- userfunc = Fiddle::Function.new(bd.prevUserCallbackScroll, GLFW::GLFWscrollfun_cb_args, GLFW::GLFWscrollfun_cb_retval)
201
- userfunc.call(window, xoffset, yoffset)
202
- end
203
-
204
- io = ImGuiIO.new(ImGui::GetIO())
205
- io.AddMouseWheelEvent(xoffset.to_f, yoffset.to_f)
206
- end
207
-
208
- def self.ImGui_ImplGlfw_TranslateUntranslatedKey(key, scancode)
209
-
210
- # GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
211
- # (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
212
- # See https://github.com/glfw/glfw/issues/1502 for details.
213
- # Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
214
- # This won't cover edge cases but this is at least going to cover common cases.
215
- return key if key >= GLFW::KEY_KP_0 && key <= GLFW::KEY_KP_EQUAL
216
-
217
- key_name_ptr = GLFW.GetKeyName(key, scancode)
218
- unless key_name_ptr.null?
219
- key_name = key_name_ptr.to_s
220
- if key_name[0] != 0 && key_name[1] == 0
221
- char_names = "`-=[]\\,;\'./".chars
222
- char_keys = [GLFW::KEY_GRAVE_ACCENT, GLFW::KEY_MINUS, GLFW::KEY_EQUAL, GLFW::KEY_LEFT_BRACKET, GLFW::KEY_RIGHT_BRACKET, GLFW::KEY_BACKSLASH, GLFW::KEY_COMMA, GLFW::KEY_SEMICOLON, GLFW::KEY_APOSTROPHE, GLFW::KEY_PERIOD, GLFW::KEY_SLASH]
223
-
224
- if key_name[0] >= '0' && key_name[0] <= '9'
225
- key = GLFW::KEY_0 + (key_name[0] - '0')
226
- elsif key_name[0] >= 'A' && key_name[0] <= 'Z'
227
- key = GLFW::KEY_A + (key_name[0] - 'A')
228
- elsif char_names.include? key_name[0]
229
- key = char_keys[char_names.index(key_name[0])]
230
- end
231
- end
232
- end
233
-
234
- return key
235
- end
236
-
237
- @@ImplGlfw_KeyCallback = GLFW::create_callback(:GLFWkeyfun) do |window, keycode, scancode, action, mods|
238
- bd = ImGui_ImplGlfw_GetBackendData()
239
- unless bd.prevUserCallbackKey.null?
240
- userfunc = Fiddle::Function.new(bd.prevUserCallbackKey, GLFW::GLFWkeyfun_cb_args, GLFW::GLFWkeyfun_cb_retval)
241
- userfunc.call(window, keycode, scancode, action, mods)
242
- end
243
-
244
- return if (action != GLFW::PRESS && action != GLFW::RELEASE)
245
-
246
- ImGui_ImplGlfw_UpdateKeyModifiers(mods)
247
-
248
- keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode)
249
-
250
- io = ImGuiIO.new(ImGui::GetIO())
251
- imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode)
252
- io.AddKeyEvent(imgui_key, (action == GLFW::PRESS))
253
- io.SetKeyEventNativeData(imgui_key, keycode, scancode) # To support legacy indexing (<1.87 user code)
254
- end
255
-
256
- @@ImplGlfw_WindowFocusCallback = GLFW::create_callback(:GLFWwindowfocusfun) do |window, focused|
257
- bd = ImGui_ImplGlfw_GetBackendData()
258
- unless bd.prevUserCallbackWindowFocus.null?
259
- userfunc = Fiddle::Function.new(bd.prevUserCallbackWindowFocus, GLFW::GLFWwindowfocusfun_cb_args, GLFW::GLFWwindowfocusfun_cb_retval)
260
- userfunc.call(window, focused)
261
- end
262
-
263
- io = ImGuiIO.new(ImGui::GetIO())
264
- io.AddFocusEvent(focused != 0)
265
- end
266
-
267
- @@ImplGlfw_CursorPosCallback = GLFW::create_callback(:GLFWcursorposfun) do |window, x, y|
268
- bd = ImGui_ImplGlfw_GetBackendData()
269
- unless bd.prevUserCallbackCursorPos.null?
270
- userfunc = Fiddle::Function.new(bd.prevUserCallbackCursorPos, GLFW::GLFWcursorposfun_cb_args, GLFW::GLFWcursorposfun_cb_retval)
271
- userfunc.call(window, x, y)
272
- end
273
-
274
- io = ImGuiIO.new(ImGui::GetIO())
275
- io.AddMousePosEvent(x.to_f, y.to_f)
276
- bd.lastValidMousePos[:x] = x.to_f
277
- bd.lastValidMousePos[:y] = y.to_f
278
- end
279
-
280
- # Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
281
- # so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
282
- @@ImplGlfw_CursorEnterCallback = GLFW::create_callback(:GLFWcursorenterfun) do |window, entered|
283
- bd = ImGui_ImplGlfw_GetBackendData()
284
- unless bd.prevUserCallbackCursorEnter.null?
285
- userfunc = Fiddle::Function.new(bd.prevUserCallbackCursorEnter, GLFW::GLFWcursorenterfun_cb_args, GLFW::GLFWcursorenterfun_cb_retval)
286
- userfunc.call(window, entered)
287
- end
288
-
289
- io = ImGuiIO.new(ImGui::GetIO())
290
- if entered
291
- bd.mouseWindow = window
292
- io.AddMousePosEvent(bd.lastValidMousePos[:x], bd.lastValidMousePos[:y])
293
- elsif !entered && bd.mouseWindow == window
294
- bd.lastValidMousePos[:x] = io[:MousePos][:x]
295
- bd.lastValidMousePos[:y] = io[:MousePos][:y]
296
- bd.mouseWindow = nil
297
- io.AddMousePosEvent(-Float::MAX, -Float::MAX)
298
- end
299
- end
300
-
301
- @@ImplGlfw_CharCallback = GLFW::create_callback(:GLFWcharfun) do |window, c|
302
- bd = ImGui_ImplGlfw_GetBackendData()
303
- unless bd.prevUserCallbackChar.null?
304
- bd.prevUserCallbackChar.call(window, c)
305
- end
306
-
307
- io = ImGuiIO.new(ImGui::GetIO())
308
- io.AddInputCharacter(c);
309
- end
310
-
311
- @@ImplGlfw_MonitorCallback = GLFW::create_callback(:GLFWmonitorfun) do |monitor, event|
312
- # 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.
313
-
314
- # bd = ImGui_ImplGlfw_GetBackendData()
315
- # unless bd.prevUserCallbackMonitor.null?
316
- # bd.prevUserCallbackMonitor.call(monitor, event)
317
- # end
318
- end
319
-
320
- def self.ImGui_ImplGlfw_InstallCallbacks(window)
321
- bd = ImGui_ImplGlfw_GetBackendData()
322
-
323
- bd.prevUserCallbackWindowFocus = GLFW.SetWindowFocusCallback(window, @@ImplGlfw_WindowFocusCallback)
324
- bd.prevUserCallbackCursorEnter = GLFW.SetCursorEnterCallback(window, @@ImplGlfw_CursorEnterCallback)
325
- bd.prevUserCallbackCursorPos = GLFW.SetCursorPosCallback(window, @@ImplGlfw_CursorPosCallback)
326
- bd.prevUserCallbackMousebutton = GLFW.SetMouseButtonCallback(window, @@ImplGlfw_MouseButtonCallback)
327
- bd.prevUserCallbackScroll = GLFW.SetScrollCallback(window, @@ImplGlfw_ScrollCallback)
328
- bd.prevUserCallbackKey = GLFW.SetKeyCallback(window, @@ImplGlfw_KeyCallback)
329
- bd.prevUserCallbackChar = GLFW.SetCharCallback(window, @@ImplGlfw_CharCallback)
330
- bd.prevUserCallbackMonitor = GLFW.SetMonitorCallback(@@ImplGlfw_MonitorCallback)
331
- bd.installedCallbacks = true
332
- end
333
-
334
- def self.ImGui_ImplGlfw_RestoreCallbacks(window)
335
- bd = ImGui_ImplGlfw_GetBackendData()
336
- GLFW.SetWindowFocusCallback(window, bd.prevUserCallbackWindowFocus)
337
- GLFW.SetCursorEnterCallback(window, bd.prevUserCallbackCursorEnter)
338
- GLFW.SetCursorPosCallback(window, bd.prevUserCallbackCursorPos)
339
- GLFW.SetMouseButtonCallback(window, bd.prevUserCallbackMousebutton)
340
- GLFW.SetScrollCallback(window, bd.prevUserCallbackScroll)
341
- GLFW.SetKeyCallback(window, bd.prevUserCallbackKey)
342
- GLFW.SetCharCallback(window, bd.prevUserCallbackChar)
343
- GLFW.SetMonitorCallback(bd.prevUserCallbackMonitor)
344
-
345
- bd.installedCallbacks = false
346
- bd.prevUserCallbackWindowFocus = nil
347
- bd.prevUserCallbackCursorEnter = nil
348
- bd.prevUserCallbackCursorPos = nil
349
- bd.prevUserCallbackMousebutton = nil
350
- bd.prevUserCallbackScroll = nil
351
- bd.prevUserCallbackKey = nil
352
- bd.prevUserCallbackChar = nil
353
- bd.prevUserCallbackMonitor = nil
354
- end
355
-
356
- def self.ImplGlfw_InitForOpenGL(window, install_callbacks)
357
- return ImplGlfw_Init(window, install_callbacks, :GlfwClientApi_OpenGL)
358
- end
359
-
360
- def self.ImplGlfw_Shutdown()
361
- bd = ImGui_ImplGlfw_GetBackendData()
362
- io = ImGuiIO.new(ImGui::GetIO())
363
-
364
- ImGui_ImplGlfw_RestoreCallbacks(bd.window) if bd.installedCallbacks
365
-
366
- ImGuiMouseCursor_COUNT.times do |cursor_n|
367
- GLFW.DestroyCursor(bd.mouseCursors[cursor_n])
368
- bd.mouseCursors[cursor_n] = nil
369
- end
370
-
371
- io[:BackendPlatformName] = nil
372
- io[:BackendPlatformUserData] = nil
373
- @@g_BackendData[ImGui::GetCurrentContext()] = nil
374
- end
375
-
376
- def self.ImplGlfw_UpdateMouseData()
377
- bd = ImGui_ImplGlfw_GetBackendData()
378
- io = ImGuiIO.new(ImGui::GetIO())
379
-
380
- is_app_focused = GLFW.GetWindowAttrib(bd.window, GLFW::FOCUSED) != 0
381
- if is_app_focused
382
- # (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
383
- if io[:WantSetMousePos]
384
- GLFW.SetCursorPos(bd.window, io[:MousePos][:x].to_f, io[:MousePos][:y].to_f)
385
- elsif bd.mouseWindow != nil
386
- mouse_x = ' ' * 8
387
- mouse_y = ' ' * 8
388
- GLFW.GetCursorPos(bd.window, mouse_x, mouse_y)
389
- io[:MousePos][:x] = mouse_x.unpack1('d')
390
- io[:MousePos][:y] = mouse_y.unpack1('d')
391
- end
392
- end
393
- end
394
-
395
- def self.ImplGlfw_UpdateMouseCursor()
396
- io = ImGuiIO.new(ImGui::GetIO())
397
- bd = ImGui_ImplGlfw_GetBackendData()
398
- return if ((io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange) || GLFW.GetInputMode(bd.window, GLFW::CURSOR) == GLFW::CURSOR_DISABLED)
399
-
400
- imgui_cursor = ImGui::GetMouseCursor()
401
- if imgui_cursor == ImGuiMouseCursor_None || io[:MouseDrawCursor]
402
- # Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
403
- GLFW.SetInputMode(bd.window, GLFW::CURSOR, GLFW::CURSOR_HIDDEN)
404
- else
405
- # Show OS mouse cursor
406
- # FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
407
- GLFW.SetCursor(bd.window, bd.mouseCursors[imgui_cursor] ? bd.mouseCursors[imgui_cursor] : bd.mouseCursors[ImGuiMouseCursor_Arrow])
408
- GLFW.SetInputMode(bd.window, GLFW::CURSOR, GLFW::CURSOR_NORMAL)
409
- end
410
- end
411
-
412
- def self.ImplGlfw_NewFrame()
413
- bd = ImGui_ImplGlfw_GetBackendData()
414
- io = ImGuiIO.new(ImGui::GetIO())
415
- # unless io[:Fonts].IsBuilt()
416
- # puts "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."
417
- # end
418
-
419
- # Setup display size (every frame to accommodate for window resizing)
420
- w = ' ' * 4
421
- h = ' ' * 4
422
- display_w = ' ' * 4
423
- display_h = ' ' * 4
424
- GLFW.GetWindowSize(bd.window, w, h)
425
- GLFW.GetFramebufferSize(bd.window, display_w, display_h)
426
-
427
- w = w.unpack1('L')
428
- h = h.unpack1('L')
429
- io[:DisplaySize][:x] = w
430
- io[:DisplaySize][:y] = h
431
-
432
- if w > 0 && h > 0
433
- io[:DisplayFramebufferScale][:x] = display_w.unpack1('L') / w
434
- io[:DisplayFramebufferScale][:y] = display_h.unpack1('L') / h
435
- end
436
-
437
- # Setup time step
438
- current_time = GLFW.GetTime()
439
- io[:DeltaTime] = bd.time > 0.0 ? (current_time - bd.time).to_f : (1.0/60.0)
440
- bd.time = current_time
441
-
442
- ImplGlfw_UpdateMouseData()
443
- ImplGlfw_UpdateMouseCursor()
444
-
445
- # TODO update gamepads
446
- # Update game controllers (if enabled and available)
447
- # ImGui_ImplGlfw_UpdateGamepads();
448
- end
449
-
450
- # private
451
-
452
- def self.ImplGlfw_Init(window, install_callbacks, client_api)
453
- # Setup backend capabilities flags
454
- bd = ImGui_ImplGlfw_Data.new
455
- @@g_BackendData[ImGui::GetCurrentContext().address] = bd
456
-
457
- io = ImGuiIO.new(ImGui::GetIO())
458
- io[:BackendPlatformName] = @@g_BackendPlatformName
459
- io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
460
- io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
461
-
462
- bd.window = window
463
- bd.time = 0.0
464
-
465
- # [TODO] Support ClipboardText & IME on Windows
466
- # io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
467
- # io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
468
- # io.ClipboardUserData = g_Window;
469
- # #if defined(_WIN32)
470
- # io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
471
- # #endif
472
-
473
- # GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
474
-
475
- # Create mouse cursors
476
- # (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
477
- # GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
478
- # Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
479
- bd.mouseCursors[ImGuiMouseCursor_Arrow] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
480
- bd.mouseCursors[ImGuiMouseCursor_TextInput] = GLFW.CreateStandardCursor(GLFW::IBEAM_CURSOR)
481
- bd.mouseCursors[ImGuiMouseCursor_ResizeNS] = GLFW.CreateStandardCursor(GLFW::VRESIZE_CURSOR)
482
- bd.mouseCursors[ImGuiMouseCursor_ResizeEW] = GLFW.CreateStandardCursor(GLFW::HRESIZE_CURSOR)
483
- bd.mouseCursors[ImGuiMouseCursor_Hand] = GLFW.CreateStandardCursor(GLFW::HAND_CURSOR)
484
-
485
- # GLFW_HAS_NEW_CURSORS == false
486
- bd.mouseCursors[ImGuiMouseCursor_ResizeAll] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
487
- bd.mouseCursors[ImGuiMouseCursor_ResizeNESW] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
488
- bd.mouseCursors[ImGuiMouseCursor_ResizeNWSE] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
489
- bd.mouseCursors[ImGuiMouseCursor_NotAllowed] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
490
-
491
- # glfwSetErrorCallback(prev_error_callback)
492
-
493
- # Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
494
- ImGui_ImplGlfw_InstallCallbacks(window) if install_callbacks
495
-
496
- # @@g_PrevUserCallbackMousebutton = nil
497
- # @@g_PrevUserCallbackScroll = nil
498
- # @@g_PrevUserCallbackKey = nil
499
- # @@g_PrevUserCallbackChar = nil
500
- # if install_callbacks
501
- # @@g_PrevUserCallbackCursorEnter = GLFW.SetCursorEnterCallback(window, @@ImGui_ImplGlfw_CursorEnterCallback)
502
- # @@g_PrevUserCallbackMousebutton = GLFW.SetMouseButtonCallback(window, @@ImplGlfw_MouseButtonCallback)
503
- # @@g_PrevUserCallbackScroll = GLFW.SetScrollCallback(window, @@ImplGlfw_ScrollCallback)
504
- # @@g_PrevUserCallbackKey = GLFW.SetKeyCallback(window, @@ImplGlfw_KeyCallback)
505
- # @@g_PrevUserCallbackChar = GLFW.SetCharCallback(window, @@ImplGlfw_CharCallback)
506
- # end
507
-
508
- return true
509
- end
510
-
511
- end
1
+ require 'ffi'
2
+ require 'opengl'
3
+ require 'glfw'
4
+
5
+ require_relative 'imgui'
6
+
7
+ module ImGui
8
+
9
+ @@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_glfw")
10
+
11
+ # ImGui::GetCurrentContext().address => ImGui_ImplGlfw_Data
12
+ @@g_BackendData = Hash.new
13
+
14
+ class ImGui_ImplGlfw_Data
15
+ attr_accessor :window, :time, :mouseWindow, :mouseCursors, :lastValidMousePos, :installedCallbacks
16
+ attr_accessor :prevUserCallbackWindowFocus, :prevUserCallbackCursorPos, :prevUserCallbackCursorEnter, :prevUserCallbackMousebutton, :prevUserCallbackScroll, :prevUserCallbackKey, :prevUserCallbackChar, :prevUserCallbackMonitor
17
+
18
+ def initialize
19
+ @window = nil # GLFWwindow*
20
+ @time = 0.0 # double
21
+ @mouseWindow = nil # GLFWwindow*
22
+ @mouseCursors = Array.new(ImGuiMouseCursor_COUNT) { 0 } # GLFWcursor*
23
+ @lastValidMousePos = ImVec2.create # ImVec2
24
+ @installedCallbacks = false # bool
25
+
26
+ # Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
27
+ @prevUserCallbackWindowFocus = nil # GLFWwindowfocusfun
28
+ @prevUserCallbackCursorPos = nil # GLFWcursorposfun
29
+ @prevUserCallbackCursorEnter = nil # GLFWcursorenterfun
30
+ @prevUserCallbackMousebutton = nil # GLFWmousebuttonfun
31
+ @prevUserCallbackScroll = nil # GLFWscrollfun
32
+ @prevUserCallbackKey = nil # GLFWkeyfun
33
+ @prevUserCallbackChar = nil # GLFWcharfun
34
+ @prevUserCallbackMonitor = nil # GLFWmonitorfun
35
+ end
36
+ end
37
+
38
+ # Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
39
+ # It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
40
+ # FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
41
+ # - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
42
+ # (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
43
+ # - 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.
44
+ # FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
45
+ def self.ImGui_ImplGlfw_GetBackendData()
46
+ if ImGui::GetCurrentContext() != nil
47
+ return @@g_BackendData[ImGui::GetCurrentContext().address]
48
+ # io = ImGuiIO.new(ImGui::GetIO())
49
+ # return ImGui_ImplGlfw_Data.new(io[:BackendPlatformUserData])
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ def self.ImGui_ImplGlfw_GetClipboardText(user_data)
56
+ glfwGetClipboardString(user_data)
57
+ end
58
+
59
+ def self.ImGui_ImplGlfw_SetClipboardText(user_data, text)
60
+ glfwSetClipboardString(user_data, text)
61
+ end
62
+
63
+ def self.ImGui_ImplGlfw_KeyToImGuiKey(key)
64
+ case key
65
+ when GLFW::KEY_TAB then ImGuiKey_Tab
66
+ when GLFW::KEY_LEFT then ImGuiKey_LeftArrow
67
+ when GLFW::KEY_RIGHT then ImGuiKey_RightArrow
68
+ when GLFW::KEY_UP then ImGuiKey_UpArrow
69
+ when GLFW::KEY_DOWN then ImGuiKey_DownArrow
70
+ when GLFW::KEY_PAGE_UP then ImGuiKey_PageUp
71
+ when GLFW::KEY_PAGE_DOWN then ImGuiKey_PageDown
72
+ when GLFW::KEY_HOME then ImGuiKey_Home
73
+ when GLFW::KEY_END then ImGuiKey_End
74
+ when GLFW::KEY_INSERT then ImGuiKey_Insert
75
+ when GLFW::KEY_DELETE then ImGuiKey_Delete
76
+ when GLFW::KEY_BACKSPACE then ImGuiKey_Backspace
77
+ when GLFW::KEY_SPACE then ImGuiKey_Space
78
+ when GLFW::KEY_ENTER then ImGuiKey_Enter
79
+ when GLFW::KEY_ESCAPE then ImGuiKey_Escape
80
+ when GLFW::KEY_APOSTROPHE then ImGuiKey_Apostrophe
81
+ when GLFW::KEY_COMMA then ImGuiKey_Comma
82
+ when GLFW::KEY_MINUS then ImGuiKey_Minus
83
+ when GLFW::KEY_PERIOD then ImGuiKey_Period
84
+ when GLFW::KEY_SLASH then ImGuiKey_Slash
85
+ when GLFW::KEY_SEMICOLON then ImGuiKey_Semicolon
86
+ when GLFW::KEY_EQUAL then ImGuiKey_Equal
87
+ when GLFW::KEY_LEFT_BRACKET then ImGuiKey_LeftBracket
88
+ when GLFW::KEY_BACKSLASH then ImGuiKey_Backslash
89
+ when GLFW::KEY_RIGHT_BRACKET then ImGuiKey_RightBracket
90
+ when GLFW::KEY_GRAVE_ACCENT then ImGuiKey_GraveAccent
91
+ when GLFW::KEY_CAPS_LOCK then ImGuiKey_CapsLock
92
+ when GLFW::KEY_SCROLL_LOCK then ImGuiKey_ScrollLock
93
+ when GLFW::KEY_NUM_LOCK then ImGuiKey_NumLock
94
+ when GLFW::KEY_PRINT_SCREEN then ImGuiKey_PrintScreen
95
+ when GLFW::KEY_PAUSE then ImGuiKey_Pause
96
+ when GLFW::KEY_KP_0 then ImGuiKey_Keypad0
97
+ when GLFW::KEY_KP_1 then ImGuiKey_Keypad1
98
+ when GLFW::KEY_KP_2 then ImGuiKey_Keypad2
99
+ when GLFW::KEY_KP_3 then ImGuiKey_Keypad3
100
+ when GLFW::KEY_KP_4 then ImGuiKey_Keypad4
101
+ when GLFW::KEY_KP_5 then ImGuiKey_Keypad5
102
+ when GLFW::KEY_KP_6 then ImGuiKey_Keypad6
103
+ when GLFW::KEY_KP_7 then ImGuiKey_Keypad7
104
+ when GLFW::KEY_KP_8 then ImGuiKey_Keypad8
105
+ when GLFW::KEY_KP_9 then ImGuiKey_Keypad9
106
+ when GLFW::KEY_KP_DECIMAL then ImGuiKey_KeypadDecimal
107
+ when GLFW::KEY_KP_DIVIDE then ImGuiKey_KeypadDivide
108
+ when GLFW::KEY_KP_MULTIPLY then ImGuiKey_KeypadMultiply
109
+ when GLFW::KEY_KP_SUBTRACT then ImGuiKey_KeypadSubtract
110
+ when GLFW::KEY_KP_ADD then ImGuiKey_KeypadAdd
111
+ when GLFW::KEY_KP_ENTER then ImGuiKey_KeypadEnter
112
+ when GLFW::KEY_KP_EQUAL then ImGuiKey_KeypadEqual
113
+ when GLFW::KEY_LEFT_SHIFT then ImGuiKey_LeftShift
114
+ when GLFW::KEY_LEFT_CONTROL then ImGuiKey_LeftCtrl
115
+ when GLFW::KEY_LEFT_ALT then ImGuiKey_LeftAlt
116
+ when GLFW::KEY_LEFT_SUPER then ImGuiKey_LeftSuper
117
+ when GLFW::KEY_RIGHT_SHIFT then ImGuiKey_RightShift
118
+ when GLFW::KEY_RIGHT_CONTROL then ImGuiKey_RightCtrl
119
+ when GLFW::KEY_RIGHT_ALT then ImGuiKey_RightAlt
120
+ when GLFW::KEY_RIGHT_SUPER then ImGuiKey_RightSuper
121
+ when GLFW::KEY_MENU then ImGuiKey_Menu
122
+ when GLFW::KEY_0 then ImGuiKey_0
123
+ when GLFW::KEY_1 then ImGuiKey_1
124
+ when GLFW::KEY_2 then ImGuiKey_2
125
+ when GLFW::KEY_3 then ImGuiKey_3
126
+ when GLFW::KEY_4 then ImGuiKey_4
127
+ when GLFW::KEY_5 then ImGuiKey_5
128
+ when GLFW::KEY_6 then ImGuiKey_6
129
+ when GLFW::KEY_7 then ImGuiKey_7
130
+ when GLFW::KEY_8 then ImGuiKey_8
131
+ when GLFW::KEY_9 then ImGuiKey_9
132
+ when GLFW::KEY_A then ImGuiKey_A
133
+ when GLFW::KEY_B then ImGuiKey_B
134
+ when GLFW::KEY_C then ImGuiKey_C
135
+ when GLFW::KEY_D then ImGuiKey_D
136
+ when GLFW::KEY_E then ImGuiKey_E
137
+ when GLFW::KEY_F then ImGuiKey_F
138
+ when GLFW::KEY_G then ImGuiKey_G
139
+ when GLFW::KEY_H then ImGuiKey_H
140
+ when GLFW::KEY_I then ImGuiKey_I
141
+ when GLFW::KEY_J then ImGuiKey_J
142
+ when GLFW::KEY_K then ImGuiKey_K
143
+ when GLFW::KEY_L then ImGuiKey_L
144
+ when GLFW::KEY_M then ImGuiKey_M
145
+ when GLFW::KEY_N then ImGuiKey_N
146
+ when GLFW::KEY_O then ImGuiKey_O
147
+ when GLFW::KEY_P then ImGuiKey_P
148
+ when GLFW::KEY_Q then ImGuiKey_Q
149
+ when GLFW::KEY_R then ImGuiKey_R
150
+ when GLFW::KEY_S then ImGuiKey_S
151
+ when GLFW::KEY_T then ImGuiKey_T
152
+ when GLFW::KEY_U then ImGuiKey_U
153
+ when GLFW::KEY_V then ImGuiKey_V
154
+ when GLFW::KEY_W then ImGuiKey_W
155
+ when GLFW::KEY_X then ImGuiKey_X
156
+ when GLFW::KEY_Y then ImGuiKey_Y
157
+ when GLFW::KEY_Z then ImGuiKey_Z
158
+ when GLFW::KEY_F1 then ImGuiKey_F1
159
+ when GLFW::KEY_F2 then ImGuiKey_F2
160
+ when GLFW::KEY_F3 then ImGuiKey_F3
161
+ when GLFW::KEY_F4 then ImGuiKey_F4
162
+ when GLFW::KEY_F5 then ImGuiKey_F5
163
+ when GLFW::KEY_F6 then ImGuiKey_F6
164
+ when GLFW::KEY_F7 then ImGuiKey_F7
165
+ when GLFW::KEY_F8 then ImGuiKey_F8
166
+ when GLFW::KEY_F9 then ImGuiKey_F9
167
+ when GLFW::KEY_F10 then ImGuiKey_F10
168
+ when GLFW::KEY_F11 then ImGuiKey_F11
169
+ when GLFW::KEY_F12 then ImGuiKey_F12
170
+ else ImGuiKey_None
171
+ end
172
+ end
173
+
174
+ def self.ImGui_ImplGlfw_UpdateKeyModifiers(mods)
175
+ io = ImGuiIO.new(ImGui::GetIO())
176
+ io.AddKeyEvent(ImGuiMod_Ctrl, (mods & GLFW::MOD_CONTROL) != 0)
177
+ io.AddKeyEvent(ImGuiMod_Shift, (mods & GLFW::MOD_SHIFT) != 0)
178
+ io.AddKeyEvent(ImGuiMod_Alt, (mods & GLFW::MOD_ALT) != 0)
179
+ io.AddKeyEvent(ImGuiMod_Super, (mods & GLFW::MOD_SUPER) != 0)
180
+ end
181
+
182
+ @@ImplGlfw_MouseButtonCallback = GLFW::create_callback(:GLFWmousebuttonfun) do |window, button, action, mods|
183
+ bd = ImGui_ImplGlfw_GetBackendData()
184
+ unless bd.prevUserCallbackMousebutton.null?
185
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackMousebutton, GLFW::GLFWmousebuttonfun_cb_args, GLFW::GLFWmousebuttonfun_cb_retval)
186
+ userfunc.call(window, button, action, mods)
187
+ end
188
+
189
+ ImGui_ImplGlfw_UpdateKeyModifiers(mods)
190
+
191
+ io = ImGuiIO.new(ImGui::GetIO())
192
+ if button >= 0 && button < ImGuiMouseButton_COUNT
193
+ io.AddMouseButtonEvent(button, action == GLFW::PRESS)
194
+ end
195
+ end
196
+
197
+ @@ImplGlfw_ScrollCallback = GLFW::create_callback(:GLFWscrollfun) do |window, xoffset, yoffset|
198
+ bd = ImGui_ImplGlfw_GetBackendData()
199
+ unless bd.prevUserCallbackScroll.null?
200
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackScroll, GLFW::GLFWscrollfun_cb_args, GLFW::GLFWscrollfun_cb_retval)
201
+ userfunc.call(window, xoffset, yoffset)
202
+ end
203
+
204
+ io = ImGuiIO.new(ImGui::GetIO())
205
+ io.AddMouseWheelEvent(xoffset.to_f, yoffset.to_f)
206
+ end
207
+
208
+ def self.ImGui_ImplGlfw_TranslateUntranslatedKey(key, scancode)
209
+
210
+ # GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
211
+ # (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
212
+ # See https://github.com/glfw/glfw/issues/1502 for details.
213
+ # Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
214
+ # This won't cover edge cases but this is at least going to cover common cases.
215
+ return key if key >= GLFW::KEY_KP_0 && key <= GLFW::KEY_KP_EQUAL
216
+
217
+ key_name_ptr = GLFW.GetKeyName(key, scancode)
218
+ unless key_name_ptr.null?
219
+ key_name = key_name_ptr.to_s
220
+ if key_name[0] != 0 && key_name[1] == 0
221
+ char_names = "`-=[]\\,;\'./".chars
222
+ char_keys = [GLFW::KEY_GRAVE_ACCENT, GLFW::KEY_MINUS, GLFW::KEY_EQUAL, GLFW::KEY_LEFT_BRACKET, GLFW::KEY_RIGHT_BRACKET, GLFW::KEY_BACKSLASH, GLFW::KEY_COMMA, GLFW::KEY_SEMICOLON, GLFW::KEY_APOSTROPHE, GLFW::KEY_PERIOD, GLFW::KEY_SLASH]
223
+
224
+ if key_name[0] >= '0' && key_name[0] <= '9'
225
+ key = GLFW::KEY_0 + (key_name[0] - '0')
226
+ elsif key_name[0] >= 'A' && key_name[0] <= 'Z'
227
+ key = GLFW::KEY_A + (key_name[0] - 'A')
228
+ elsif char_names.include? key_name[0]
229
+ key = char_keys[char_names.index(key_name[0])]
230
+ end
231
+ end
232
+ end
233
+
234
+ return key
235
+ end
236
+
237
+ @@ImplGlfw_KeyCallback = GLFW::create_callback(:GLFWkeyfun) do |window, keycode, scancode, action, mods|
238
+ bd = ImGui_ImplGlfw_GetBackendData()
239
+ unless bd.prevUserCallbackKey.null?
240
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackKey, GLFW::GLFWkeyfun_cb_args, GLFW::GLFWkeyfun_cb_retval)
241
+ userfunc.call(window, keycode, scancode, action, mods)
242
+ end
243
+
244
+ return if (action != GLFW::PRESS && action != GLFW::RELEASE)
245
+
246
+ ImGui_ImplGlfw_UpdateKeyModifiers(mods)
247
+
248
+ keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode)
249
+
250
+ io = ImGuiIO.new(ImGui::GetIO())
251
+ imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode)
252
+ io.AddKeyEvent(imgui_key, (action == GLFW::PRESS))
253
+ io.SetKeyEventNativeData(imgui_key, keycode, scancode) # To support legacy indexing (<1.87 user code)
254
+ end
255
+
256
+ @@ImplGlfw_WindowFocusCallback = GLFW::create_callback(:GLFWwindowfocusfun) do |window, focused|
257
+ bd = ImGui_ImplGlfw_GetBackendData()
258
+ unless bd.prevUserCallbackWindowFocus.null?
259
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackWindowFocus, GLFW::GLFWwindowfocusfun_cb_args, GLFW::GLFWwindowfocusfun_cb_retval)
260
+ userfunc.call(window, focused)
261
+ end
262
+
263
+ io = ImGuiIO.new(ImGui::GetIO())
264
+ io.AddFocusEvent(focused != 0)
265
+ end
266
+
267
+ @@ImplGlfw_CursorPosCallback = GLFW::create_callback(:GLFWcursorposfun) do |window, x, y|
268
+ bd = ImGui_ImplGlfw_GetBackendData()
269
+ unless bd.prevUserCallbackCursorPos.null?
270
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackCursorPos, GLFW::GLFWcursorposfun_cb_args, GLFW::GLFWcursorposfun_cb_retval)
271
+ userfunc.call(window, x, y)
272
+ end
273
+
274
+ io = ImGuiIO.new(ImGui::GetIO())
275
+ io.AddMousePosEvent(x.to_f, y.to_f)
276
+ bd.lastValidMousePos[:x] = x.to_f
277
+ bd.lastValidMousePos[:y] = y.to_f
278
+ end
279
+
280
+ # Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
281
+ # so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
282
+ @@ImplGlfw_CursorEnterCallback = GLFW::create_callback(:GLFWcursorenterfun) do |window, entered|
283
+ bd = ImGui_ImplGlfw_GetBackendData()
284
+ unless bd.prevUserCallbackCursorEnter.null?
285
+ userfunc = Fiddle::Function.new(bd.prevUserCallbackCursorEnter, GLFW::GLFWcursorenterfun_cb_args, GLFW::GLFWcursorenterfun_cb_retval)
286
+ userfunc.call(window, entered)
287
+ end
288
+
289
+ io = ImGuiIO.new(ImGui::GetIO())
290
+ if entered
291
+ bd.mouseWindow = window
292
+ io.AddMousePosEvent(bd.lastValidMousePos[:x], bd.lastValidMousePos[:y])
293
+ elsif !entered && bd.mouseWindow == window
294
+ bd.lastValidMousePos[:x] = io[:MousePos][:x]
295
+ bd.lastValidMousePos[:y] = io[:MousePos][:y]
296
+ bd.mouseWindow = nil
297
+ io.AddMousePosEvent(-Float::MAX, -Float::MAX)
298
+ end
299
+ end
300
+
301
+ @@ImplGlfw_CharCallback = GLFW::create_callback(:GLFWcharfun) do |window, c|
302
+ bd = ImGui_ImplGlfw_GetBackendData()
303
+ unless bd.prevUserCallbackChar.null?
304
+ bd.prevUserCallbackChar.call(window, c)
305
+ end
306
+
307
+ io = ImGuiIO.new(ImGui::GetIO())
308
+ io.AddInputCharacter(c);
309
+ end
310
+
311
+ @@ImplGlfw_MonitorCallback = GLFW::create_callback(:GLFWmonitorfun) do |monitor, event|
312
+ # 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.
313
+
314
+ # bd = ImGui_ImplGlfw_GetBackendData()
315
+ # unless bd.prevUserCallbackMonitor.null?
316
+ # bd.prevUserCallbackMonitor.call(monitor, event)
317
+ # end
318
+ end
319
+
320
+ def self.ImGui_ImplGlfw_InstallCallbacks(window)
321
+ bd = ImGui_ImplGlfw_GetBackendData()
322
+
323
+ bd.prevUserCallbackWindowFocus = GLFW.SetWindowFocusCallback(window, @@ImplGlfw_WindowFocusCallback)
324
+ bd.prevUserCallbackCursorEnter = GLFW.SetCursorEnterCallback(window, @@ImplGlfw_CursorEnterCallback)
325
+ bd.prevUserCallbackCursorPos = GLFW.SetCursorPosCallback(window, @@ImplGlfw_CursorPosCallback)
326
+ bd.prevUserCallbackMousebutton = GLFW.SetMouseButtonCallback(window, @@ImplGlfw_MouseButtonCallback)
327
+ bd.prevUserCallbackScroll = GLFW.SetScrollCallback(window, @@ImplGlfw_ScrollCallback)
328
+ bd.prevUserCallbackKey = GLFW.SetKeyCallback(window, @@ImplGlfw_KeyCallback)
329
+ bd.prevUserCallbackChar = GLFW.SetCharCallback(window, @@ImplGlfw_CharCallback)
330
+ bd.prevUserCallbackMonitor = GLFW.SetMonitorCallback(@@ImplGlfw_MonitorCallback)
331
+ bd.installedCallbacks = true
332
+ end
333
+
334
+ def self.ImGui_ImplGlfw_RestoreCallbacks(window)
335
+ bd = ImGui_ImplGlfw_GetBackendData()
336
+ GLFW.SetWindowFocusCallback(window, bd.prevUserCallbackWindowFocus)
337
+ GLFW.SetCursorEnterCallback(window, bd.prevUserCallbackCursorEnter)
338
+ GLFW.SetCursorPosCallback(window, bd.prevUserCallbackCursorPos)
339
+ GLFW.SetMouseButtonCallback(window, bd.prevUserCallbackMousebutton)
340
+ GLFW.SetScrollCallback(window, bd.prevUserCallbackScroll)
341
+ GLFW.SetKeyCallback(window, bd.prevUserCallbackKey)
342
+ GLFW.SetCharCallback(window, bd.prevUserCallbackChar)
343
+ GLFW.SetMonitorCallback(bd.prevUserCallbackMonitor)
344
+
345
+ bd.installedCallbacks = false
346
+ bd.prevUserCallbackWindowFocus = nil
347
+ bd.prevUserCallbackCursorEnter = nil
348
+ bd.prevUserCallbackCursorPos = nil
349
+ bd.prevUserCallbackMousebutton = nil
350
+ bd.prevUserCallbackScroll = nil
351
+ bd.prevUserCallbackKey = nil
352
+ bd.prevUserCallbackChar = nil
353
+ bd.prevUserCallbackMonitor = nil
354
+ end
355
+
356
+ def self.ImplGlfw_InitForOpenGL(window, install_callbacks)
357
+ return ImplGlfw_Init(window, install_callbacks, :GlfwClientApi_OpenGL)
358
+ end
359
+
360
+ def self.ImplGlfw_Shutdown()
361
+ bd = ImGui_ImplGlfw_GetBackendData()
362
+ io = ImGuiIO.new(ImGui::GetIO())
363
+
364
+ ImGui_ImplGlfw_RestoreCallbacks(bd.window) if bd.installedCallbacks
365
+
366
+ ImGuiMouseCursor_COUNT.times do |cursor_n|
367
+ GLFW.DestroyCursor(bd.mouseCursors[cursor_n])
368
+ bd.mouseCursors[cursor_n] = nil
369
+ end
370
+
371
+ io[:BackendPlatformName] = nil
372
+ io[:BackendPlatformUserData] = nil
373
+ @@g_BackendData[ImGui::GetCurrentContext()] = nil
374
+ end
375
+
376
+ def self.ImplGlfw_UpdateMouseData()
377
+ bd = ImGui_ImplGlfw_GetBackendData()
378
+ io = ImGuiIO.new(ImGui::GetIO())
379
+
380
+ is_app_focused = GLFW.GetWindowAttrib(bd.window, GLFW::FOCUSED) != 0
381
+ if is_app_focused
382
+ # (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
383
+ if io[:WantSetMousePos]
384
+ GLFW.SetCursorPos(bd.window, io[:MousePos][:x].to_f, io[:MousePos][:y].to_f)
385
+ elsif bd.mouseWindow != nil
386
+ mouse_x = ' ' * 8
387
+ mouse_y = ' ' * 8
388
+ GLFW.GetCursorPos(bd.window, mouse_x, mouse_y)
389
+ io[:MousePos][:x] = mouse_x.unpack1('d')
390
+ io[:MousePos][:y] = mouse_y.unpack1('d')
391
+ end
392
+ end
393
+ end
394
+
395
+ def self.ImplGlfw_UpdateMouseCursor()
396
+ io = ImGuiIO.new(ImGui::GetIO())
397
+ bd = ImGui_ImplGlfw_GetBackendData()
398
+ return if ((io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange) || GLFW.GetInputMode(bd.window, GLFW::CURSOR) == GLFW::CURSOR_DISABLED)
399
+
400
+ imgui_cursor = ImGui::GetMouseCursor()
401
+ if imgui_cursor == ImGuiMouseCursor_None || io[:MouseDrawCursor]
402
+ # Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
403
+ GLFW.SetInputMode(bd.window, GLFW::CURSOR, GLFW::CURSOR_HIDDEN)
404
+ else
405
+ # Show OS mouse cursor
406
+ # FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
407
+ GLFW.SetCursor(bd.window, bd.mouseCursors[imgui_cursor] ? bd.mouseCursors[imgui_cursor] : bd.mouseCursors[ImGuiMouseCursor_Arrow])
408
+ GLFW.SetInputMode(bd.window, GLFW::CURSOR, GLFW::CURSOR_NORMAL)
409
+ end
410
+ end
411
+
412
+ def self.ImplGlfw_NewFrame()
413
+ bd = ImGui_ImplGlfw_GetBackendData()
414
+ io = ImGuiIO.new(ImGui::GetIO())
415
+ # unless io[:Fonts].IsBuilt()
416
+ # puts "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."
417
+ # end
418
+
419
+ # Setup display size (every frame to accommodate for window resizing)
420
+ w = ' ' * 4
421
+ h = ' ' * 4
422
+ display_w = ' ' * 4
423
+ display_h = ' ' * 4
424
+ GLFW.GetWindowSize(bd.window, w, h)
425
+ GLFW.GetFramebufferSize(bd.window, display_w, display_h)
426
+
427
+ w = w.unpack1('L')
428
+ h = h.unpack1('L')
429
+ io[:DisplaySize][:x] = w
430
+ io[:DisplaySize][:y] = h
431
+
432
+ if w > 0 && h > 0
433
+ io[:DisplayFramebufferScale][:x] = display_w.unpack1('L') / w
434
+ io[:DisplayFramebufferScale][:y] = display_h.unpack1('L') / h
435
+ end
436
+
437
+ # Setup time step
438
+ current_time = GLFW.GetTime()
439
+ io[:DeltaTime] = bd.time > 0.0 ? (current_time - bd.time).to_f : (1.0/60.0)
440
+ bd.time = current_time
441
+
442
+ ImplGlfw_UpdateMouseData()
443
+ ImplGlfw_UpdateMouseCursor()
444
+
445
+ # TODO update gamepads
446
+ # Update game controllers (if enabled and available)
447
+ # ImGui_ImplGlfw_UpdateGamepads();
448
+ end
449
+
450
+ # private
451
+
452
+ def self.ImplGlfw_Init(window, install_callbacks, client_api)
453
+ # Setup backend capabilities flags
454
+ bd = ImGui_ImplGlfw_Data.new
455
+ @@g_BackendData[ImGui::GetCurrentContext().address] = bd
456
+
457
+ io = ImGuiIO.new(ImGui::GetIO())
458
+ io[:BackendPlatformName] = @@g_BackendPlatformName
459
+ io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
460
+ io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
461
+
462
+ bd.window = window
463
+ bd.time = 0.0
464
+
465
+ # [TODO] Support ClipboardText & IME on Windows
466
+ # io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
467
+ # io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
468
+ # io.ClipboardUserData = g_Window;
469
+ # #if defined(_WIN32)
470
+ # io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
471
+ # #endif
472
+
473
+ # GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL);
474
+
475
+ # Create mouse cursors
476
+ # (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
477
+ # GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
478
+ # Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
479
+ bd.mouseCursors[ImGuiMouseCursor_Arrow] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
480
+ bd.mouseCursors[ImGuiMouseCursor_TextInput] = GLFW.CreateStandardCursor(GLFW::IBEAM_CURSOR)
481
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNS] = GLFW.CreateStandardCursor(GLFW::VRESIZE_CURSOR)
482
+ bd.mouseCursors[ImGuiMouseCursor_ResizeEW] = GLFW.CreateStandardCursor(GLFW::HRESIZE_CURSOR)
483
+ bd.mouseCursors[ImGuiMouseCursor_Hand] = GLFW.CreateStandardCursor(GLFW::HAND_CURSOR)
484
+
485
+ # GLFW_HAS_NEW_CURSORS == false
486
+ bd.mouseCursors[ImGuiMouseCursor_ResizeAll] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
487
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNESW] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
488
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNWSE] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
489
+ bd.mouseCursors[ImGuiMouseCursor_NotAllowed] = GLFW.CreateStandardCursor(GLFW::ARROW_CURSOR)
490
+
491
+ # glfwSetErrorCallback(prev_error_callback)
492
+
493
+ # Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
494
+ ImGui_ImplGlfw_InstallCallbacks(window) if install_callbacks
495
+
496
+ # @@g_PrevUserCallbackMousebutton = nil
497
+ # @@g_PrevUserCallbackScroll = nil
498
+ # @@g_PrevUserCallbackKey = nil
499
+ # @@g_PrevUserCallbackChar = nil
500
+ # if install_callbacks
501
+ # @@g_PrevUserCallbackCursorEnter = GLFW.SetCursorEnterCallback(window, @@ImGui_ImplGlfw_CursorEnterCallback)
502
+ # @@g_PrevUserCallbackMousebutton = GLFW.SetMouseButtonCallback(window, @@ImplGlfw_MouseButtonCallback)
503
+ # @@g_PrevUserCallbackScroll = GLFW.SetScrollCallback(window, @@ImplGlfw_ScrollCallback)
504
+ # @@g_PrevUserCallbackKey = GLFW.SetKeyCallback(window, @@ImplGlfw_KeyCallback)
505
+ # @@g_PrevUserCallbackChar = GLFW.SetCharCallback(window, @@ImplGlfw_CharCallback)
506
+ # end
507
+
508
+ return true
509
+ end
510
+
511
+ end