imgui-bindings 0.1.17 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,599 @@
1
+ require 'ffi'
2
+ require 'sdl3'
3
+ require_relative 'imgui'
4
+
5
+ module ImGui
6
+
7
+ ImGui_ImplSDL3_MouseCaptureMode_Disabled = 0
8
+ ImGui_ImplSDL3_MouseCaptureMode_Enabled = 1
9
+ ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag = 2
10
+
11
+ ImGui_ImplSDL3_GamepadMode_AutoFirst = 0
12
+ ImGui_ImplSDL3_GamepadMode_AutoAll = 1
13
+ ImGui_ImplSDL3_GamepadMode_Manual = 2
14
+
15
+ @@g_BackendPlatformName = FFI::MemoryPointer.from_string('imgui_impl_sdl3')
16
+ @@g_BackendData = {}
17
+
18
+ # [INTERNAL]
19
+ class ImGui_ImplSDL3_Data
20
+ attr_accessor :window, :window_id, :renderer, :time, :clipboard_text_data,
21
+ :mouse_window_id, :mouse_buttons_down, :mouse_cursors, :mouse_last_cursor,
22
+ :mouse_pending_leave_frame, :mouse_can_use_global_state, :mouse_capture_mode,
23
+ :gamepads, :gamepad_mode, :want_update_gamepads_list
24
+
25
+ def initialize
26
+ @window = nil
27
+ @window_id = 0
28
+ @renderer = nil
29
+ @time = 0
30
+ @clipboard_text_data = nil
31
+ @mouse_window_id = 0
32
+ @mouse_buttons_down = 0
33
+ @mouse_cursors = Array.new(ImGuiMouseCursor_COUNT) { nil }
34
+ @mouse_last_cursor = nil
35
+ @mouse_pending_leave_frame = 0
36
+ @mouse_can_use_global_state = false
37
+ @mouse_capture_mode = ImGui_ImplSDL3_MouseCaptureMode_Disabled
38
+ @gamepads = []
39
+ @gamepad_mode = ImGui_ImplSDL3_GamepadMode_AutoFirst
40
+ @want_update_gamepads_list = true
41
+ end
42
+ end
43
+
44
+ def self.ImGui_ImplSDL3_GetBackendData()
45
+ return nil if ImGui::GetCurrentContext() == nil
46
+ @@g_BackendData[ImGui::GetCurrentContext().address]
47
+ end
48
+
49
+ def self.ImGui_ImplSDL3_IsTouchMouse(which_id)
50
+ which_id == SDL::TOUCH_MOUSEID || which_id == 0xffffffff
51
+ end
52
+
53
+ def self.ImGui_ImplSDL3_GetViewportForWindowID(window_id)
54
+ bd = ImGui_ImplSDL3_GetBackendData()
55
+ return nil if bd == nil
56
+ window_id == bd.window_id ? ImGuiViewport.new(ImGui::GetMainViewport()) : nil
57
+ end
58
+
59
+ def self.ImGui_ImplSDL3_KeyEventToImGuiKey(keycode, scancode)
60
+ case scancode
61
+ when SDL::SCANCODE_KP_0 then ImGuiKey_Keypad0
62
+ when SDL::SCANCODE_KP_1 then ImGuiKey_Keypad1
63
+ when SDL::SCANCODE_KP_2 then ImGuiKey_Keypad2
64
+ when SDL::SCANCODE_KP_3 then ImGuiKey_Keypad3
65
+ when SDL::SCANCODE_KP_4 then ImGuiKey_Keypad4
66
+ when SDL::SCANCODE_KP_5 then ImGuiKey_Keypad5
67
+ when SDL::SCANCODE_KP_6 then ImGuiKey_Keypad6
68
+ when SDL::SCANCODE_KP_7 then ImGuiKey_Keypad7
69
+ when SDL::SCANCODE_KP_8 then ImGuiKey_Keypad8
70
+ when SDL::SCANCODE_KP_9 then ImGuiKey_Keypad9
71
+ when SDL::SCANCODE_KP_PERIOD then ImGuiKey_KeypadDecimal
72
+ when SDL::SCANCODE_KP_DIVIDE then ImGuiKey_KeypadDivide
73
+ when SDL::SCANCODE_KP_MULTIPLY then ImGuiKey_KeypadMultiply
74
+ when SDL::SCANCODE_KP_MINUS then ImGuiKey_KeypadSubtract
75
+ when SDL::SCANCODE_KP_PLUS then ImGuiKey_KeypadAdd
76
+ when SDL::SCANCODE_KP_ENTER then ImGuiKey_KeypadEnter
77
+ when SDL::SCANCODE_KP_EQUALS then ImGuiKey_KeypadEqual
78
+ end
79
+
80
+ case keycode
81
+ when SDL::SDLK_TAB then ImGuiKey_Tab
82
+ when SDL::SDLK_LEFT then ImGuiKey_LeftArrow
83
+ when SDL::SDLK_RIGHT then ImGuiKey_RightArrow
84
+ when SDL::SDLK_UP then ImGuiKey_UpArrow
85
+ when SDL::SDLK_DOWN then ImGuiKey_DownArrow
86
+ when SDL::SDLK_PAGEUP then ImGuiKey_PageUp
87
+ when SDL::SDLK_PAGEDOWN then ImGuiKey_PageDown
88
+ when SDL::SDLK_HOME then ImGuiKey_Home
89
+ when SDL::SDLK_END then ImGuiKey_End
90
+ when SDL::SDLK_INSERT then ImGuiKey_Insert
91
+ when SDL::SDLK_DELETE then ImGuiKey_Delete
92
+ when SDL::SDLK_BACKSPACE then ImGuiKey_Backspace
93
+ when SDL::SDLK_SPACE then ImGuiKey_Space
94
+ when SDL::SDLK_RETURN then ImGuiKey_Enter
95
+ when SDL::SDLK_ESCAPE then ImGuiKey_Escape
96
+ when SDL::SDLK_COMMA then ImGuiKey_Comma
97
+ when SDL::SDLK_PERIOD then ImGuiKey_Period
98
+ when SDL::SDLK_SEMICOLON then ImGuiKey_Semicolon
99
+ when SDL::SDLK_CAPSLOCK then ImGuiKey_CapsLock
100
+ when SDL::SDLK_SCROLLLOCK then ImGuiKey_ScrollLock
101
+ when SDL::SDLK_NUMLOCKCLEAR then ImGuiKey_NumLock
102
+ when SDL::SDLK_PRINTSCREEN then ImGuiKey_PrintScreen
103
+ when SDL::SDLK_PAUSE then ImGuiKey_Pause
104
+ when SDL::SDLK_LCTRL then ImGuiKey_LeftCtrl
105
+ when SDL::SDLK_LSHIFT then ImGuiKey_LeftShift
106
+ when SDL::SDLK_LALT then ImGuiKey_LeftAlt
107
+ when SDL::SDLK_LGUI then ImGuiKey_LeftSuper
108
+ when SDL::SDLK_RCTRL then ImGuiKey_RightCtrl
109
+ when SDL::SDLK_RSHIFT then ImGuiKey_RightShift
110
+ when SDL::SDLK_RALT then ImGuiKey_RightAlt
111
+ when SDL::SDLK_RGUI then ImGuiKey_RightSuper
112
+ when SDL::SDLK_APPLICATION then ImGuiKey_Menu
113
+ when SDL::SDLK_0 then ImGuiKey_0
114
+ when SDL::SDLK_1 then ImGuiKey_1
115
+ when SDL::SDLK_2 then ImGuiKey_2
116
+ when SDL::SDLK_3 then ImGuiKey_3
117
+ when SDL::SDLK_4 then ImGuiKey_4
118
+ when SDL::SDLK_5 then ImGuiKey_5
119
+ when SDL::SDLK_6 then ImGuiKey_6
120
+ when SDL::SDLK_7 then ImGuiKey_7
121
+ when SDL::SDLK_8 then ImGuiKey_8
122
+ when SDL::SDLK_9 then ImGuiKey_9
123
+ when SDL::SDLK_A then ImGuiKey_A
124
+ when SDL::SDLK_B then ImGuiKey_B
125
+ when SDL::SDLK_C then ImGuiKey_C
126
+ when SDL::SDLK_D then ImGuiKey_D
127
+ when SDL::SDLK_E then ImGuiKey_E
128
+ when SDL::SDLK_F then ImGuiKey_F
129
+ when SDL::SDLK_G then ImGuiKey_G
130
+ when SDL::SDLK_H then ImGuiKey_H
131
+ when SDL::SDLK_I then ImGuiKey_I
132
+ when SDL::SDLK_J then ImGuiKey_J
133
+ when SDL::SDLK_K then ImGuiKey_K
134
+ when SDL::SDLK_L then ImGuiKey_L
135
+ when SDL::SDLK_M then ImGuiKey_M
136
+ when SDL::SDLK_N then ImGuiKey_N
137
+ when SDL::SDLK_O then ImGuiKey_O
138
+ when SDL::SDLK_P then ImGuiKey_P
139
+ when SDL::SDLK_Q then ImGuiKey_Q
140
+ when SDL::SDLK_R then ImGuiKey_R
141
+ when SDL::SDLK_S then ImGuiKey_S
142
+ when SDL::SDLK_T then ImGuiKey_T
143
+ when SDL::SDLK_U then ImGuiKey_U
144
+ when SDL::SDLK_V then ImGuiKey_V
145
+ when SDL::SDLK_W then ImGuiKey_W
146
+ when SDL::SDLK_X then ImGuiKey_X
147
+ when SDL::SDLK_Y then ImGuiKey_Y
148
+ when SDL::SDLK_Z then ImGuiKey_Z
149
+ when SDL::SDLK_F1 then ImGuiKey_F1
150
+ when SDL::SDLK_F2 then ImGuiKey_F2
151
+ when SDL::SDLK_F3 then ImGuiKey_F3
152
+ when SDL::SDLK_F4 then ImGuiKey_F4
153
+ when SDL::SDLK_F5 then ImGuiKey_F5
154
+ when SDL::SDLK_F6 then ImGuiKey_F6
155
+ when SDL::SDLK_F7 then ImGuiKey_F7
156
+ when SDL::SDLK_F8 then ImGuiKey_F8
157
+ when SDL::SDLK_F9 then ImGuiKey_F9
158
+ when SDL::SDLK_F10 then ImGuiKey_F10
159
+ when SDL::SDLK_F11 then ImGuiKey_F11
160
+ when SDL::SDLK_F12 then ImGuiKey_F12
161
+ when SDL::SDLK_F13 then ImGuiKey_F13
162
+ when SDL::SDLK_F14 then ImGuiKey_F14
163
+ when SDL::SDLK_F15 then ImGuiKey_F15
164
+ when SDL::SDLK_F16 then ImGuiKey_F16
165
+ when SDL::SDLK_F17 then ImGuiKey_F17
166
+ when SDL::SDLK_F18 then ImGuiKey_F18
167
+ when SDL::SDLK_F19 then ImGuiKey_F19
168
+ when SDL::SDLK_F20 then ImGuiKey_F20
169
+ when SDL::SDLK_F21 then ImGuiKey_F21
170
+ when SDL::SDLK_F22 then ImGuiKey_F22
171
+ when SDL::SDLK_F23 then ImGuiKey_F23
172
+ when SDL::SDLK_F24 then ImGuiKey_F24
173
+ when SDL::SDLK_AC_BACK then ImGuiKey_AppBack
174
+ when SDL::SDLK_AC_FORWARD then ImGuiKey_AppForward
175
+ else
176
+ case scancode
177
+ when SDL::SCANCODE_GRAVE then ImGuiKey_GraveAccent
178
+ when SDL::SCANCODE_MINUS then ImGuiKey_Minus
179
+ when SDL::SCANCODE_EQUALS then ImGuiKey_Equal
180
+ when SDL::SCANCODE_LEFTBRACKET then ImGuiKey_LeftBracket
181
+ when SDL::SCANCODE_RIGHTBRACKET then ImGuiKey_RightBracket
182
+ when SDL::SCANCODE_NONUSBACKSLASH then ImGuiKey_Oem102
183
+ when SDL::SCANCODE_BACKSLASH then ImGuiKey_Backslash
184
+ when SDL::SCANCODE_SEMICOLON then ImGuiKey_Semicolon
185
+ when SDL::SCANCODE_APOSTROPHE then ImGuiKey_Apostrophe
186
+ when SDL::SCANCODE_COMMA then ImGuiKey_Comma
187
+ when SDL::SCANCODE_PERIOD then ImGuiKey_Period
188
+ when SDL::SCANCODE_SLASH then ImGuiKey_Slash
189
+ else ImGuiKey_None
190
+ end
191
+ end
192
+ end
193
+
194
+ def self.ImGui_ImplSDL3_UpdateKeyModifiers(sdl_key_mods)
195
+ io = ImGuiIO.new(ImGui::GetIO())
196
+ io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & SDL::KMOD_CTRL) != 0)
197
+ io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & SDL::KMOD_SHIFT) != 0)
198
+ io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & SDL::KMOD_ALT) != 0)
199
+ io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL::KMOD_GUI) != 0)
200
+ end
201
+
202
+ def self.ImplSDL3_ProcessEvent(event)
203
+ io = ImGuiIO.new(ImGui::GetIO())
204
+ bd = ImGui_ImplSDL3_GetBackendData()
205
+ return false if bd == nil
206
+
207
+ event_type = event[:type]
208
+
209
+ case event_type
210
+ when SDL::EVENT_MOUSE_MOTION
211
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:motion][:windowID]) == nil
212
+ io.AddMouseSourceEvent(ImGui_ImplSDL3_IsTouchMouse(event[:motion][:which]) ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse)
213
+ io.AddMousePosEvent(event[:motion][:x].to_f, event[:motion][:y].to_f)
214
+ true
215
+
216
+ when SDL::EVENT_MOUSE_WHEEL
217
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:wheel][:windowID]) == nil
218
+ io.AddMouseSourceEvent(ImGui_ImplSDL3_IsTouchMouse(event[:wheel][:which]) ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse)
219
+ io.AddMouseWheelEvent(-event[:wheel][:x].to_f, event[:wheel][:y].to_f)
220
+ true
221
+
222
+ when SDL::EVENT_MOUSE_BUTTON_DOWN, SDL::EVENT_MOUSE_BUTTON_UP
223
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:button][:windowID]) == nil
224
+ mouse_button = -1
225
+ mouse_button = 0 if event[:button][:button] == SDL::BUTTON_LEFT
226
+ mouse_button = 1 if event[:button][:button] == SDL::BUTTON_RIGHT
227
+ mouse_button = 2 if event[:button][:button] == SDL::BUTTON_MIDDLE
228
+ mouse_button = 3 if event[:button][:button] == SDL::BUTTON_X1
229
+ mouse_button = 4 if event[:button][:button] == SDL::BUTTON_X2
230
+ return false if mouse_button == -1
231
+
232
+ is_down = event_type == SDL::EVENT_MOUSE_BUTTON_DOWN
233
+ io.AddMouseSourceEvent(ImGui_ImplSDL3_IsTouchMouse(event[:button][:which]) ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse)
234
+ io.AddMouseButtonEvent(mouse_button, is_down)
235
+ bd.mouse_buttons_down = is_down ? (bd.mouse_buttons_down | (1 << mouse_button)) : (bd.mouse_buttons_down & ~(1 << mouse_button))
236
+ true
237
+
238
+ when SDL::EVENT_TEXT_INPUT
239
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:text][:windowID]) == nil
240
+ io.AddInputCharactersUTF8(event[:text][:text].read_string)
241
+ true
242
+
243
+ when SDL::EVENT_KEY_DOWN, SDL::EVENT_KEY_UP
244
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:key][:windowID]) == nil
245
+ ImGui_ImplSDL3_UpdateKeyModifiers(event[:key][:mod])
246
+ key = ImGui_ImplSDL3_KeyEventToImGuiKey(event[:key][:key], event[:key][:scancode])
247
+ io.AddKeyEvent(key, event_type == SDL::EVENT_KEY_DOWN)
248
+ io.SetKeyEventNativeDataEx(key, event[:key][:key], event[:key][:scancode], event[:key][:scancode])
249
+ true
250
+
251
+ when SDL::EVENT_WINDOW_MOUSE_ENTER
252
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:window][:windowID]) == nil
253
+ bd.mouse_window_id = event[:window][:windowID]
254
+ bd.mouse_pending_leave_frame = 0
255
+ true
256
+
257
+ when SDL::EVENT_WINDOW_MOUSE_LEAVE
258
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:window][:windowID]) == nil
259
+ bd.mouse_pending_leave_frame = ImGui::GetFrameCount() + 1
260
+ true
261
+
262
+ when SDL::EVENT_WINDOW_FOCUS_GAINED, SDL::EVENT_WINDOW_FOCUS_LOST
263
+ return false if ImGui_ImplSDL3_GetViewportForWindowID(event[:window][:windowID]) == nil
264
+ io.AddFocusEvent(event_type == SDL::EVENT_WINDOW_FOCUS_GAINED)
265
+ true
266
+
267
+ when SDL::EVENT_GAMEPAD_ADDED, SDL::EVENT_GAMEPAD_REMOVED
268
+ bd.want_update_gamepads_list = true
269
+ true
270
+
271
+ else
272
+ false
273
+ end
274
+ end
275
+
276
+ def self.ImplSDL3_Init(window, renderer = nil)
277
+ io = ImGuiIO.new(ImGui::GetIO())
278
+
279
+ bd = ImGui_ImplSDL3_Data.new
280
+ bd.window = window
281
+ bd.renderer = renderer
282
+ bd.window_id = SDL.GetWindowID(window)
283
+
284
+ sdl_backend = SDL.GetCurrentVideoDriver()
285
+ sdl_backend_name = sdl_backend == nil ? '' : sdl_backend.read_string
286
+ ['windows', 'cocoa', 'x11', 'DIVE', 'VMAN'].each do |platform|
287
+ next unless sdl_backend_name.start_with?(platform)
288
+ bd.mouse_can_use_global_state = true
289
+ bd.mouse_capture_mode = (platform == 'x11') ? ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL3_MouseCaptureMode_Enabled
290
+ end
291
+
292
+ @@g_BackendData[ImGui::GetCurrentContext().address] = bd
293
+
294
+ io[:BackendPlatformUserData] = FFI::Pointer.new(ImGui::GetCurrentContext().address)
295
+ io[:BackendPlatformName] = @@g_BackendPlatformName
296
+ io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors
297
+ io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos
298
+
299
+ bd.mouse_cursors[ImGuiMouseCursor_Arrow] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_DEFAULT)
300
+ bd.mouse_cursors[ImGuiMouseCursor_TextInput] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_TEXT)
301
+ bd.mouse_cursors[ImGuiMouseCursor_ResizeAll] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_MOVE)
302
+ bd.mouse_cursors[ImGuiMouseCursor_ResizeNS] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NS_RESIZE)
303
+ bd.mouse_cursors[ImGuiMouseCursor_ResizeEW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_EW_RESIZE)
304
+ bd.mouse_cursors[ImGuiMouseCursor_ResizeNESW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NESW_RESIZE)
305
+ bd.mouse_cursors[ImGuiMouseCursor_ResizeNWSE] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NWSE_RESIZE)
306
+ bd.mouse_cursors[ImGuiMouseCursor_Hand] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_POINTER)
307
+ bd.mouse_cursors[ImGuiMouseCursor_Wait] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_WAIT)
308
+ bd.mouse_cursors[ImGuiMouseCursor_Progress] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_PROGRESS)
309
+ bd.mouse_cursors[ImGuiMouseCursor_NotAllowed] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NOT_ALLOWED)
310
+
311
+ main_viewport = ImGuiViewport.new(ImGui::GetMainViewport())
312
+ main_viewport[:PlatformHandle] = FFI::Pointer.new(bd.window_id)
313
+
314
+ SDL.SetHint(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH, '1') if defined?(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH)
315
+ SDL.SetHint(SDL::HINT_MOUSE_AUTO_CAPTURE, '0') if defined?(SDL::HINT_MOUSE_AUTO_CAPTURE)
316
+
317
+ true
318
+ end
319
+
320
+ def self.ImplSDL3_InitForOpenGL(window, sdl_gl_context = nil)
321
+ ImplSDL3_Init(window, nil)
322
+ end
323
+
324
+ def self.ImplSDL3_InitForVulkan(window)
325
+ ImplSDL3_Init(window, nil)
326
+ end
327
+
328
+ def self.ImplSDL3_InitForD3D(window)
329
+ ImplSDL3_Init(window, nil)
330
+ end
331
+
332
+ def self.ImplSDL3_InitForMetal(window)
333
+ ImplSDL3_Init(window, nil)
334
+ end
335
+
336
+ def self.ImplSDL3_InitForSDLRenderer(window, renderer)
337
+ ImplSDL3_Init(window, renderer)
338
+ end
339
+
340
+ def self.ImplSDL3_InitForSDLGPU(window)
341
+ ImplSDL3_Init(window, nil)
342
+ end
343
+
344
+ def self.ImplSDL3_InitForOther(window)
345
+ ImplSDL3_Init(window, nil)
346
+ end
347
+
348
+ def self.ImplSDL3_CloseGamepads()
349
+ bd = ImGui_ImplSDL3_GetBackendData()
350
+ return if bd == nil
351
+ if bd.gamepad_mode != ImGui_ImplSDL3_GamepadMode_Manual
352
+ bd.gamepads.each { |g| SDL.CloseGamepad(g) if g != nil }
353
+ end
354
+ bd.gamepads = []
355
+ end
356
+
357
+ def self.ImplSDL3_SetGamepadMode(mode, manual_gamepads_array = nil)
358
+ bd = ImGui_ImplSDL3_GetBackendData()
359
+ return if bd == nil
360
+
361
+ ImplSDL3_CloseGamepads()
362
+ if mode == ImGui_ImplSDL3_GamepadMode_Manual
363
+ bd.gamepads = manual_gamepads_array ? manual_gamepads_array.compact : []
364
+ else
365
+ bd.want_update_gamepads_list = true
366
+ end
367
+ bd.gamepad_mode = mode
368
+ end
369
+
370
+ def self.ImplSDL3_Shutdown()
371
+ io = ImGuiIO.new(ImGui::GetIO())
372
+ platform_io = ImGuiPlatformIO.new(ImGui::GetPlatformIO())
373
+ bd = ImGui_ImplSDL3_GetBackendData()
374
+ return if bd == nil
375
+
376
+ # Docking branch requires viewport platform handles to be cleared before DestroyContext().
377
+ main_viewport = ImGuiViewport.new(ImGui::GetMainViewport())
378
+ main_viewport[:PlatformHandle] = nil
379
+ main_viewport[:PlatformHandleRaw] = nil
380
+
381
+ bd.mouse_cursors.each { |cursor| SDL.DestroyCursor(cursor) if cursor != nil }
382
+ ImplSDL3_CloseGamepads()
383
+
384
+ io[:BackendPlatformName] = nil
385
+ io[:BackendPlatformUserData] = nil
386
+ io[:BackendFlags] &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad)
387
+ platform_io.ClearPlatformHandlers()
388
+ @@g_BackendData.delete(ImGui::GetCurrentContext().address)
389
+ end
390
+
391
+ def self.ImplSDL3_SetMouseCaptureMode(mode)
392
+ bd = ImGui_ImplSDL3_GetBackendData()
393
+ return if bd == nil
394
+ SDL.CaptureMouse(false) if mode == ImGui_ImplSDL3_MouseCaptureMode_Disabled && bd.mouse_capture_mode != ImGui_ImplSDL3_MouseCaptureMode_Disabled
395
+ bd.mouse_capture_mode = mode
396
+ end
397
+
398
+ def self.ImplSDL3_UpdateMouseData()
399
+ bd = ImGui_ImplSDL3_GetBackendData()
400
+ io = ImGuiIO.new(ImGui::GetIO())
401
+ return if bd == nil
402
+
403
+ if bd.mouse_capture_mode == ImGui_ImplSDL3_MouseCaptureMode_Enabled
404
+ SDL.CaptureMouse(bd.mouse_buttons_down != 0)
405
+ elsif bd.mouse_capture_mode == ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag
406
+ want_capture = false
407
+ ImGuiMouseButton_COUNT.times do |button_n|
408
+ if ImGui::IsMouseDragging(button_n, 1.0)
409
+ want_capture = true
410
+ break
411
+ end
412
+ end
413
+ SDL.CaptureMouse(want_capture)
414
+ end
415
+
416
+ focused_window = SDL.GetKeyboardFocus()
417
+ is_app_focused = (focused_window == bd.window)
418
+ return unless is_app_focused
419
+
420
+ if io[:WantSetMousePos]
421
+ SDL.WarpMouseInWindow(bd.window, io[:MousePos][:x], io[:MousePos][:y])
422
+ end
423
+
424
+ hovered_window = SDL.GetMouseFocus()
425
+ is_relative_mouse_mode = SDL.GetWindowRelativeMouseMode(bd.window)
426
+ if hovered_window == nil && bd.mouse_can_use_global_state && bd.mouse_buttons_down == 0 && !is_relative_mouse_mode
427
+ mx = FFI::MemoryPointer.new(:float)
428
+ my = FFI::MemoryPointer.new(:float)
429
+ wx = FFI::MemoryPointer.new(:int)
430
+ wy = FFI::MemoryPointer.new(:int)
431
+ SDL.GetGlobalMouseState(mx, my)
432
+ SDL.GetWindowPosition(focused_window, wx, wy)
433
+ io.AddMousePosEvent(mx.read_float - wx.read_int, my.read_float - wy.read_int)
434
+ end
435
+ end
436
+
437
+ def self.ImplSDL3_UpdateMouseCursor()
438
+ io = ImGuiIO.new(ImGui::GetIO())
439
+ return if (io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange) != 0
440
+
441
+ bd = ImGui_ImplSDL3_GetBackendData()
442
+ return if bd == nil
443
+
444
+ imgui_cursor = ImGui::GetMouseCursor()
445
+ if io[:MouseDrawCursor] || imgui_cursor == ImGuiMouseCursor_None
446
+ SDL.HideCursor()
447
+ else
448
+ expected_cursor = bd.mouse_cursors[imgui_cursor] || bd.mouse_cursors[ImGuiMouseCursor_Arrow]
449
+ if bd.mouse_last_cursor != expected_cursor
450
+ SDL.SetCursor(expected_cursor)
451
+ bd.mouse_last_cursor = expected_cursor
452
+ end
453
+ SDL.ShowCursor()
454
+ end
455
+ end
456
+
457
+ def self.ImplSDL3_Saturate(v)
458
+ return 0.0 if v < 0.0
459
+ return 1.0 if v > 1.0
460
+ v
461
+ end
462
+
463
+ def self.ImplSDL3_UpdateGamepadButton(bd, io, key, button_no)
464
+ merged_value = false
465
+ bd.gamepads.each do |gamepad|
466
+ merged_value ||= SDL.GetGamepadButton(gamepad, button_no)
467
+ end
468
+ io.AddKeyEvent(key, merged_value)
469
+ end
470
+
471
+ def self.ImplSDL3_UpdateGamepadAnalog(bd, io, key, axis_no, v0, v1)
472
+ merged_value = 0.0
473
+ bd.gamepads.each do |gamepad|
474
+ vn = ImplSDL3_Saturate((SDL.GetGamepadAxis(gamepad, axis_no) - v0).to_f / (v1 - v0).to_f)
475
+ merged_value = vn if merged_value < vn
476
+ end
477
+ io.AddKeyAnalogEvent(key, merged_value > 0.1, merged_value)
478
+ end
479
+
480
+ def self.ImplSDL3_UpdateGamepads()
481
+ io = ImGuiIO.new(ImGui::GetIO())
482
+ bd = ImGui_ImplSDL3_GetBackendData()
483
+ return if bd == nil
484
+
485
+ if bd.want_update_gamepads_list && bd.gamepad_mode != ImGui_ImplSDL3_GamepadMode_Manual
486
+ ImplSDL3_CloseGamepads()
487
+ count_ptr = FFI::MemoryPointer.new(:int)
488
+ gamepads_ptr = SDL.GetGamepads(count_ptr)
489
+ count = count_ptr.read_int
490
+ count.times do |n|
491
+ joystick_id = (gamepads_ptr + n * FFI.type_size(:uint)).read_uint
492
+ gamepad = SDL.OpenGamepad(joystick_id)
493
+ next if gamepad == nil
494
+ bd.gamepads << gamepad
495
+ break if bd.gamepad_mode == ImGui_ImplSDL3_GamepadMode_AutoFirst
496
+ end
497
+ bd.want_update_gamepads_list = false
498
+ SDL.free(gamepads_ptr) if gamepads_ptr != nil
499
+ end
500
+
501
+ io[:BackendFlags] &= ~ImGuiBackendFlags_HasGamepad
502
+ return if bd.gamepads.empty?
503
+ io[:BackendFlags] |= ImGuiBackendFlags_HasGamepad
504
+
505
+ dead_zone = 8000
506
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL::GAMEPAD_BUTTON_START)
507
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL::GAMEPAD_BUTTON_BACK)
508
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL::GAMEPAD_BUTTON_WEST)
509
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL::GAMEPAD_BUTTON_EAST)
510
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL::GAMEPAD_BUTTON_NORTH)
511
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL::GAMEPAD_BUTTON_SOUTH)
512
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL::GAMEPAD_BUTTON_DPAD_LEFT)
513
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL::GAMEPAD_BUTTON_DPAD_RIGHT)
514
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL::GAMEPAD_BUTTON_DPAD_UP)
515
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL::GAMEPAD_BUTTON_DPAD_DOWN)
516
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL::GAMEPAD_BUTTON_LEFT_SHOULDER)
517
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL::GAMEPAD_BUTTON_RIGHT_SHOULDER)
518
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL::GAMEPAD_AXIS_LEFT_TRIGGER, 0.0, 32767.0)
519
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL::GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0, 32767.0)
520
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL::GAMEPAD_BUTTON_LEFT_STICK)
521
+ ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL::GAMEPAD_BUTTON_RIGHT_STICK)
522
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL::GAMEPAD_AXIS_LEFTX, -dead_zone, -32768.0)
523
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL::GAMEPAD_AXIS_LEFTX, dead_zone, 32767.0)
524
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL::GAMEPAD_AXIS_LEFTY, -dead_zone, -32768.0)
525
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL::GAMEPAD_AXIS_LEFTY, dead_zone, 32767.0)
526
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL::GAMEPAD_AXIS_RIGHTX, -dead_zone, -32768.0)
527
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL::GAMEPAD_AXIS_RIGHTX, dead_zone, 32767.0)
528
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL::GAMEPAD_AXIS_RIGHTY, -dead_zone, -32768.0)
529
+ ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL::GAMEPAD_AXIS_RIGHTY, dead_zone, 32767.0)
530
+ end
531
+
532
+ def self.ImplSDL3_UpdateImeFromIO()
533
+ io = ImGuiIO.new(ImGui::GetIO())
534
+ bd = ImGui_ImplSDL3_GetBackendData()
535
+ return if bd == nil
536
+
537
+ window = SDL.GetKeyboardFocus()
538
+ return if window == nil
539
+
540
+ if io[:WantTextInput]
541
+ unless SDL.TextInputActive(window)
542
+ SDL.StartTextInput(window)
543
+ end
544
+ else
545
+ SDL.StopTextInput(window) if SDL.TextInputActive(window)
546
+ end
547
+ end
548
+
549
+ def self.ImplSDL3_GetWindowSizeAndFramebufferScale(window)
550
+ w_ptr = FFI::MemoryPointer.new(:int)
551
+ h_ptr = FFI::MemoryPointer.new(:int)
552
+ SDL.GetWindowSize(window, w_ptr, h_ptr)
553
+ w = w_ptr.read_int
554
+ h = h_ptr.read_int
555
+ if (SDL.GetWindowFlags(window) & SDL::WINDOW_MINIMIZED) != 0
556
+ w = h = 0
557
+ end
558
+
559
+ display_w_ptr = FFI::MemoryPointer.new(:int)
560
+ display_h_ptr = FFI::MemoryPointer.new(:int)
561
+ SDL.GetWindowSizeInPixels(window, display_w_ptr, display_h_ptr)
562
+ display_w = display_w_ptr.read_int
563
+ display_h = display_h_ptr.read_int
564
+
565
+ scale_x = (w > 0) ? (display_w.to_f / w.to_f) : 1.0
566
+ scale_y = (h > 0) ? (display_h.to_f / h.to_f) : 1.0
567
+ [w, h, scale_x, scale_y]
568
+ end
569
+
570
+ def self.ImplSDL3_NewFrame()
571
+ bd = ImGui_ImplSDL3_GetBackendData()
572
+ raise 'Context or backend not initialized! Did you call ImGui::ImplSDL3_Init()?' if bd == nil
573
+
574
+ io = ImGuiIO.new(ImGui::GetIO())
575
+
576
+ w, h, scale_x, scale_y = ImplSDL3_GetWindowSizeAndFramebufferScale(bd.window)
577
+ io[:DisplaySize] = ImVec2.create(w.to_f, h.to_f)
578
+ io[:DisplayFramebufferScale][:x] = scale_x
579
+ io[:DisplayFramebufferScale][:y] = scale_y
580
+
581
+ frequency = SDL.GetPerformanceFrequency()
582
+ current_time = SDL.GetPerformanceCounter()
583
+ current_time = bd.time + 1 if current_time <= bd.time
584
+ io[:DeltaTime] = bd.time > 0 ? (current_time - bd.time).to_f / frequency.to_f : (1.0 / 60.0)
585
+ bd.time = current_time
586
+
587
+ if bd.mouse_pending_leave_frame != 0 && bd.mouse_pending_leave_frame >= ImGui::GetFrameCount() && bd.mouse_buttons_down == 0
588
+ bd.mouse_window_id = 0
589
+ bd.mouse_pending_leave_frame = 0
590
+ io.AddMousePosEvent(-Float::MAX, -Float::MAX)
591
+ end
592
+
593
+ ImplSDL3_UpdateMouseData()
594
+ ImplSDL3_UpdateMouseCursor()
595
+ ImplSDL3_UpdateImeFromIO()
596
+ ImplSDL3_UpdateGamepads()
597
+ end
598
+
599
+ end