imgui-bindings 0.0.2 → 0.1.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.
@@ -1,296 +1,409 @@
1
- require 'ffi'
2
- require 'sdl2'
3
- require_relative 'imgui'
4
-
5
- module ImGui
6
-
7
- class ImGui_ImplSDL2_Data < FFI::Struct
8
- layout(
9
- :Window, :pointer,
10
- :Time, :uint64,
11
- :MousePressed, [:bool, 3],
12
- :MouseCursors, [:pointer, ImGuiMouseCursor_COUNT],
13
- :ClipboardTextData, :pointer,
14
- :MouseCanUseGlobalState, :bool
15
- )
16
- end
17
-
18
- def self.ImGui_ImplSDL2_GetBackendData()
19
- io = ImGuiIO.new(ImGui::GetIO())
20
- return ImGui_ImplSDL2_Data.new(io[:BackendPlatformUserData])
21
- end
22
-
23
- @@g_Window = nil # SDL_Window*
24
- @@g_Time = 0.0 # UInt64
25
- @@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_sdl")
26
- @@g_BackendPlatformUserData = nil
27
-
28
- # [TODO] Support ClipboardText
29
- # g_ClipboardTextData
30
- # ImplSDL2_GetClipboardText
31
- # ImplSDL2_SetClipboardText
32
-
33
- # [TODO] SDL_MOUSE
34
- def self.get_sdl2_mousebit(x); return (1 << ((x)-1)); end
35
-
36
- # [TODO] #define KMOD_CTRL, #define KMOD_SHIFT, #define KMOD_ALT and #define KMOD_GUI
37
- KMOD_CTRL = SDL2::KMOD_LCTRL|SDL2::KMOD_RCTRL
38
- KMOD_SHIFT = SDL2::KMOD_LSHIFT|SDL2::KMOD_RSHIFT
39
- KMOD_ALT = SDL2::KMOD_LALT|SDL2::KMOD_RALT
40
- KMOD_GUI = SDL2::KMOD_LGUI|SDL2::KMOD_RGUI
41
-
42
- # [INTERNAL]
43
- def self.ImplSDL2_UpdateMousePosAndButtons()
44
- # Update buttons
45
- io = ImGuiIO.new(ImGui::GetIO())
46
- bd = ImGui_ImplSDL2_GetBackendData()
47
- window = bd[:Window]
48
-
49
- # Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
50
- if io[:WantSetMousePos]
51
- SDL2::SDL_WarpMouseInWindow(window, io[:MousePos][:x].to_i, io[:MousePos][:y].to_i)
52
- else
53
- io[:MousePos][:x] = -Float::MAX
54
- io[:MousePos][:y] = -Float::MAX
55
- end
56
-
57
- mx = FFI::MemoryPointer.new(:int)
58
- my = FFI::MemoryPointer.new(:int)
59
- mouse_buttons = SDL2::SDL_GetMouseState(mx, my)
60
- io[:MouseDown][0] = bd[:MousePressed][0] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_LEFT)) != 0 # 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.
61
- io[:MouseDown][1] = bd[:MousePressed][1] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_RIGHT)) != 0
62
- io[:MouseDown][2] = bd[:MousePressed][2] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_MIDDLE)) != 0
63
- bd[:MousePressed][0] = bd[:MousePressed][1] = bd[:MousePressed][2] = false
64
-
65
- focused_window = SDL2::SDL_GetKeyboardFocus()
66
- hover_window = nil
67
- mouse_window = nil
68
- if defined?(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)
69
- hovered_window = SDL_GetMouseFocus() # This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH enabled.
70
- mouse_window = (window == focused_window || window == hovered_window) ? window : nil
71
- else
72
- mouse_window = (window == focused_window) ? window : nil
73
- end
74
- if mouse_window != nil
75
- if bd[:MouseCanUseGlobalState]
76
- # SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
77
- # The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
78
- # Won't use this workaround on SDL backends that have no global mouse position, like Wayland or RPI
79
- wx = FFI::MemoryPointer.new(:int)
80
- wy = FFI::MemoryPointer.new(:int)
81
- SDL2::SDL_GetWindowPosition(focused_window, wx, wy)
82
- SDL2::SDL_GetGlobalMouseState(mx, my)
83
- io[:MousePos][:x] = mx.read(:int).to_f - wx.read(:int).to_f
84
- io[:MousePos][:y] = my.read(:int).to_f - wy.read(:int).to_f
85
- else
86
- io[:MousePos][:x] = mx.read(:int).to_f
87
- io[:MousePos][:y] = my.read(:int).to_f
88
- end
89
- end
90
-
91
- # SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
92
- # The function is only supported from SDL 2.0.4 (released Jan 2016)
93
- any_mouse_button_down = ImGui::IsAnyMouseDown()
94
- SDL2::SDL_CaptureMouse(any_mouse_button_down ? SDL2::SDL_TRUE : SDL2::SDL_FALSE)
95
-
96
- # [TODO]
97
- #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
98
- end
99
-
100
- def self.ImplSDL2_UpdateMouseCursor()
101
- io = ImGuiIO.new(ImGui::GetIO())
102
- return if (io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange)
103
- bd = ImGui_ImplSDL2_GetBackendData()
104
-
105
- imgui_cursor = ImGui::GetMouseCursor()
106
- if io[:MouseDrawCursor] || imgui_cursor == ImGuiMouseCursor_None
107
- # Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
108
- SDL2::SDL_ShowCursor(SDL2::SDL_FALSE)
109
- else
110
- # Show OS mouse cursor
111
- SDL2::SDL_SetCursor(bd[:MouseCursors][imgui_cursor] ? bd[:MouseCursors][imgui_cursor] : bd[:MouseCursors][ImGuiMouseCursor_Arrow])
112
- SDL2::SDL_ShowCursor(SDL2::SDL_TRUE)
113
- end
114
- end
115
-
116
- #
117
- # [TODO] Support ImplSDL2_UpdateGamepads
118
- #
119
-
120
- def self.ImplSDL2_Shutdown()
121
- io = ImGuiIO.new(ImGui::GetIO())
122
- bd = ImGui_ImplSDL2_GetBackendData()
123
-
124
- # [TODO] Destroy last known clipboard data
125
-
126
- @@g_Window = nil
127
- ImGuiMouseCursor_COUNT.times do |cursor_n|
128
- SDL2::SDL_FreeCursor(bd[:MouseCursors][cursor_n])
129
- bd[:MouseCursors][cursor_n] = nil
130
- end
131
- @@g_BackendPlatformUserData = nil
132
- end
133
-
134
- def self.ImplSDL2_NewFrame()
135
- io = ImGuiIO.new(ImGui::GetIO())
136
- bd = ImGui_ImplSDL2_GetBackendData()
137
-
138
- unless io[:Fonts].IsBuilt()
139
- 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()."
140
- end
141
-
142
- # Setup display size (every frame to accommodate for window resizing)
143
- w = ' ' * 4
144
- h = ' ' * 4
145
- display_w = ' ' * 4
146
- display_h = ' ' * 4
147
- SDL2::SDL_GetWindowSize(bd[:Window], w, h)
148
- SDL2::SDL_GL_GetDrawableSize(bd[:Window], display_w, display_h)
149
-
150
- w = w.unpack1('L')
151
- h = h.unpack1('L')
152
- display_size = ImVec2.new
153
- display_size[:x] = w.to_f
154
- display_size[:y] = h.to_f
155
- io[:DisplaySize] = display_size
156
-
157
- if w > 0 && h > 0
158
- fb_scale = ImVec2.new
159
- fb_scale[:x] = display_w.unpack1('L').to_f / w
160
- fb_scale[:y] = display_h.unpack1('L').to_f / h
161
- io[:DisplayFramebufferScale] = fb_scale
162
- end
163
-
164
- # Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
165
- frequency = SDL2::SDL_GetPerformanceFrequency()
166
- current_time = SDL2::SDL_GetPerformanceCounter()
167
-
168
- io[:DeltaTime] = @@g_Time > 0 ? ((current_time - @@g_Time).to_f / frequency) : (1.0/60.0)
169
- @@g_Time = current_time
170
-
171
- ImplSDL2_UpdateMousePosAndButtons()
172
- ImplSDL2_UpdateMouseCursor()
173
-
174
- # [TODO] update gamepads
175
- end
176
-
177
- # You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
178
- # - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
179
- # - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
180
- # Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
181
- # If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
182
- def self.ImplSDL2_ProcessEvent(event)
183
- io = ImGuiIO.new(ImGui::GetIO())
184
- bd = ImGui_ImplSDL2_GetBackendData()
185
-
186
- case event[:type]
187
-
188
- when SDL2::SDL_MOUSEWHEEL
189
- io[:MouseWheelH] += 1 if (event[:wheel][:x] > 0)
190
- io[:MouseWheelH] -= 1 if (event[:wheel][:x] < 0)
191
- io[:MouseWheel] += 1 if (event[:wheel][:y] > 0)
192
- io[:MouseWheel] -= 1 if (event[:wheel][:y] < 0)
193
- return true
194
-
195
- when SDL2::SDL_MOUSEBUTTONDOWN
196
- bd[:MousePressed][0] = true if event[:button][:button] == SDL2::SDL_BUTTON_LEFT
197
- bd[:MousePressed][1] = true if event[:button][:button] == SDL2::SDL_BUTTON_RIGHT
198
- bd[:MousePressed][2] = true if event[:button][:button] == SDL2::SDL_BUTTON_MIDDLE
199
- return true
200
-
201
- when SDL2::SDL_TEXTINPUT
202
- io.AddInputCharactersUTF8(event[:text][:text])
203
- return true
204
-
205
- when SDL2::SDL_KEYDOWN, SDL2::SDL_KEYUP
206
- key = event[:key][:keysym][:scancode]
207
- # IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
208
- io[:KeysDown][key] = (event[:type] == SDL2::SDL_KEYDOWN)
209
- io[:KeyShift] = ((SDL2::SDL_GetModState() & KMOD_SHIFT) != 0)
210
- io[:KeyCtrl] = ((SDL2::SDL_GetModState() & KMOD_CTRL) != 0)
211
- io[:KeyAlt] = ((SDL2::SDL_GetModState() & KMOD_ALT) != 0)
212
- io[:KeySuper] = ((SDL2::SDL_GetModState() & KMOD_GUI) != 0) # [TODO] io.KeySuper = false on _WIN32
213
- return true
214
- end
215
-
216
- return false
217
- end
218
-
219
- def self.ImplSDL2_Init(window)
220
-
221
- @@g_Window = window
222
- @@g_Time = 0
223
-
224
- @@g_BackendPlatformUserData = ImGui_ImplSDL2_Data.new
225
- @@g_BackendPlatformUserData[:Window] = window
226
-
227
- io = ImGuiIO.new(ImGui::GetIO())
228
-
229
- io[:BackendPlatformUserData] = @@g_BackendPlatformUserData
230
- io[:BackendPlatformName] = @@g_BackendPlatformName
231
- io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
232
- io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
233
-
234
- # Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
235
- io[:KeyMap][ImGuiKey_Tab] = SDL2::SDL_SCANCODE_TAB
236
- io[:KeyMap][ImGuiKey_LeftArrow] = SDL2::SDL_SCANCODE_LEFT
237
- io[:KeyMap][ImGuiKey_RightArrow] = SDL2::SDL_SCANCODE_RIGHT
238
- io[:KeyMap][ImGuiKey_UpArrow] = SDL2::SDL_SCANCODE_UP
239
- io[:KeyMap][ImGuiKey_DownArrow] = SDL2::SDL_SCANCODE_DOWN
240
- io[:KeyMap][ImGuiKey_PageUp] = SDL2::SDL_SCANCODE_PAGEUP
241
- io[:KeyMap][ImGuiKey_PageDown] = SDL2::SDL_SCANCODE_PAGEDOWN
242
- io[:KeyMap][ImGuiKey_Home] = SDL2::SDL_SCANCODE_HOME
243
- io[:KeyMap][ImGuiKey_End] = SDL2::SDL_SCANCODE_END
244
- io[:KeyMap][ImGuiKey_Insert] = SDL2::SDL_SCANCODE_INSERT
245
- io[:KeyMap][ImGuiKey_Delete] = SDL2::SDL_SCANCODE_DELETE
246
- io[:KeyMap][ImGuiKey_Backspace] = SDL2::SDL_SCANCODE_BACKSPACE
247
- io[:KeyMap][ImGuiKey_Space] = SDL2::SDL_SCANCODE_SPACE
248
- io[:KeyMap][ImGuiKey_Enter] = SDL2::SDL_SCANCODE_RETURN
249
- io[:KeyMap][ImGuiKey_Escape] = SDL2::SDL_SCANCODE_ESCAPE
250
- io[:KeyMap][ImGuiKey_KeyPadEnter] = SDL2::SDL_SCANCODE_RETURN2
251
- io[:KeyMap][ImGuiKey_A] = SDL2::SDL_SCANCODE_A
252
- io[:KeyMap][ImGuiKey_C] = SDL2::SDL_SCANCODE_C
253
- io[:KeyMap][ImGuiKey_V] = SDL2::SDL_SCANCODE_V
254
- io[:KeyMap][ImGuiKey_X] = SDL2::SDL_SCANCODE_X
255
- io[:KeyMap][ImGuiKey_Y] = SDL2::SDL_SCANCODE_Y
256
- io[:KeyMap][ImGuiKey_Z] = SDL2::SDL_SCANCODE_Z
257
-
258
- # [TODO] Support ClipboardText
259
-
260
- bd = ImGui_ImplSDL2_GetBackendData()
261
-
262
- bd[:MouseCursors][ImGuiMouseCursor_Arrow] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_ARROW)
263
- bd[:MouseCursors][ImGuiMouseCursor_TextInput] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_IBEAM)
264
- bd[:MouseCursors][ImGuiMouseCursor_ResizeAll] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZEALL)
265
- bd[:MouseCursors][ImGuiMouseCursor_ResizeNS] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENS)
266
- bd[:MouseCursors][ImGuiMouseCursor_ResizeEW] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZEWE)
267
- bd[:MouseCursors][ImGuiMouseCursor_ResizeNESW] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENESW)
268
- bd[:MouseCursors][ImGuiMouseCursor_ResizeNWSE] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENWSE)
269
- bd[:MouseCursors][ImGuiMouseCursor_Hand] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_HAND)
270
- bd[:MouseCursors][ImGuiMouseCursor_NotAllowed] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_NO)
271
-
272
- =begin
273
- #ifdef _WIN32
274
- SDL_SysWMinfo info;
275
- SDL_VERSION(&info.version);
276
- if (SDL_GetWindowWMInfo(window, &info))
277
- io.ImeWindowHandle = info.info.win.window;
278
- #else
279
- =end
280
-
281
- =begin
282
- sdl_backend = SDL_GetCurrentVideoDriver().read_string
283
- global_mouse_whitelist = [ "windows", "cocoa", "x11", "DIVE", "VMAN" ]
284
- bd[:MouseCanUseGlobalState] = false
285
- global_mouse_whitelist.each do |elem|
286
- bd[:MouseCanUseGlobalState] = true if sdl_backend == elem
287
- end
288
- =end
289
- if defined?(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)
290
- SDL_SetHint(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")
291
- end
292
-
293
- return true
294
- end
295
-
296
- end
1
+ require 'ffi'
2
+ require 'sdl2'
3
+ require_relative 'imgui'
4
+
5
+ module ImGui
6
+
7
+ @@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_sdl")
8
+
9
+ # ImGui::GetCurrentContext().address => ImGui_ImplSDL2_Data
10
+ @@g_BackendData = Hash.new
11
+
12
+ # [INTERNAL]
13
+ class ImGui_ImplSDL2_Data
14
+ attr_accessor :window, :renderer, :time, :mouseButtonsDown, :mouseCursors, :clipboardTextData, :mouseCanUseGlobalState
15
+
16
+ def initialize
17
+ @window = nil # SDL_Window*
18
+ @renderer = nil # SDL_Renderer*
19
+ @time = 0.0 # Uint64
20
+ @mouseButtonsDown = 0 # int
21
+ @mouseCursors = Array.new(ImGuiMouseCursor_COUNT) { 0 } # SDL_Cursor*
22
+ @clipboardTextData = nil # char*
23
+ @mouseCanUseGlobalState = false # bool
24
+ end
25
+ end
26
+
27
+ # Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
28
+ # It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
29
+ # FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
30
+ # FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
31
+ # [INTERNAL]
32
+ def self.ImGui_ImplSDL2_GetBackendData()
33
+ if ImGui::GetCurrentContext() != nil
34
+ @@g_BackendData[ImGui::GetCurrentContext().address]
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ # [TODO] Support ClipboardText
41
+ # g_ClipboardTextData
42
+ # ImplSDL2_GetClipboardText
43
+ # ImplSDL2_SetClipboardText
44
+
45
+ # [INTERNAL]
46
+ def self.ImGui_ImplSDL2_GetClipboardText(user_data)
47
+ bd = ImGui_ImplSDL2_GetBackendData()
48
+ SDL.free(bd.clipboardTextData) if bd.clipboardTextData
49
+ bd.clipboardTextData = SDL.GetClipboardText()
50
+ return bd.clipboardTextData
51
+ end
52
+
53
+ # [INTERNAL]
54
+ def self.ImGui_ImplSDL2_SetClipboardText(user_data, text)
55
+ SDL.SetClipboardText(text)
56
+ end
57
+
58
+ # [INTERNAL]
59
+ def self.ImGui_ImplSDL2_KeyToImGuiKey(key)
60
+ case key
61
+ when SDL::SDLK_TAB then ImGuiKey_Tab
62
+ when SDL::SDLK_LEFT then ImGuiKey_LeftArrow
63
+ when SDL::SDLK_RIGHT then ImGuiKey_RightArrow
64
+ when SDL::SDLK_UP then ImGuiKey_UpArrow
65
+ when SDL::SDLK_DOWN then ImGuiKey_DownArrow
66
+ when SDL::SDLK_PAGEUP then ImGuiKey_PageUp
67
+ when SDL::SDLK_PAGEDOWN then ImGuiKey_PageDown
68
+ when SDL::SDLK_HOME then ImGuiKey_Home
69
+ when SDL::SDLK_END then ImGuiKey_End
70
+ when SDL::SDLK_INSERT then ImGuiKey_Insert
71
+ when SDL::SDLK_DELETE then ImGuiKey_Delete
72
+ when SDL::SDLK_BACKSPACE then ImGuiKey_Backspace
73
+ when SDL::SDLK_SPACE then ImGuiKey_Space
74
+ when SDL::SDLK_RETURN then ImGuiKey_Enter
75
+ when SDL::SDLK_ESCAPE then ImGuiKey_Escape
76
+ when SDL::SDLK_QUOTE then ImGuiKey_Apostrophe
77
+ when SDL::SDLK_COMMA then ImGuiKey_Comma
78
+ when SDL::SDLK_MINUS then ImGuiKey_Minus
79
+ when SDL::SDLK_PERIOD then ImGuiKey_Period
80
+ when SDL::SDLK_SLASH then ImGuiKey_Slash
81
+ when SDL::SDLK_SEMICOLON then ImGuiKey_Semicolon
82
+ when SDL::SDLK_EQUALS then ImGuiKey_Equal
83
+ when SDL::SDLK_LEFTBRACKET then ImGuiKey_LeftBracket
84
+ when SDL::SDLK_BACKSLASH then ImGuiKey_Backslash
85
+ when SDL::SDLK_RIGHTBRACKET then ImGuiKey_RightBracket
86
+ when SDL::SDLK_BACKQUOTE then ImGuiKey_GraveAccent
87
+ when SDL::SDLK_CAPSLOCK then ImGuiKey_CapsLock
88
+ when SDL::SDLK_SCROLLLOCK then ImGuiKey_ScrollLock
89
+ when SDL::SDLK_NUMLOCKCLEAR then ImGuiKey_NumLock
90
+ when SDL::SDLK_PRINTSCREEN then ImGuiKey_PrintScreen
91
+ when SDL::SDLK_PAUSE then ImGuiKey_Pause
92
+ when SDL::SDLK_KP_0 then ImGuiKey_Keypad0
93
+ when SDL::SDLK_KP_1 then ImGuiKey_Keypad1
94
+ when SDL::SDLK_KP_2 then ImGuiKey_Keypad2
95
+ when SDL::SDLK_KP_3 then ImGuiKey_Keypad3
96
+ when SDL::SDLK_KP_4 then ImGuiKey_Keypad4
97
+ when SDL::SDLK_KP_5 then ImGuiKey_Keypad5
98
+ when SDL::SDLK_KP_6 then ImGuiKey_Keypad6
99
+ when SDL::SDLK_KP_7 then ImGuiKey_Keypad7
100
+ when SDL::SDLK_KP_8 then ImGuiKey_Keypad8
101
+ when SDL::SDLK_KP_9 then ImGuiKey_Keypad9
102
+ when SDL::SDLK_KP_PERIOD then ImGuiKey_KeypadDecimal
103
+ when SDL::SDLK_KP_DIVIDE then ImGuiKey_KeypadDivide
104
+ when SDL::SDLK_KP_MULTIPLY then ImGuiKey_KeypadMultiply
105
+ when SDL::SDLK_KP_MINUS then ImGuiKey_KeypadSubtract
106
+ when SDL::SDLK_KP_PLUS then ImGuiKey_KeypadAdd
107
+ when SDL::SDLK_KP_ENTER then ImGuiKey_KeypadEnter
108
+ when SDL::SDLK_KP_EQUALS then ImGuiKey_KeypadEqual
109
+ when SDL::SDLK_LCTRL then ImGuiKey_LeftCtrl
110
+ when SDL::SDLK_LSHIFT then ImGuiKey_LeftShift
111
+ when SDL::SDLK_LALT then ImGuiKey_LeftAlt
112
+ when SDL::SDLK_LGUI then ImGuiKey_LeftSuper
113
+ when SDL::SDLK_RCTRL then ImGuiKey_RightCtrl
114
+ when SDL::SDLK_RSHIFT then ImGuiKey_RightShift
115
+ when SDL::SDLK_RALT then ImGuiKey_RightAlt
116
+ when SDL::SDLK_RGUI then ImGuiKey_RightSuper
117
+ when SDL::SDLK_APPLICATION then ImGuiKey_Menu
118
+ when SDL::SDLK_0 then ImGuiKey_0
119
+ when SDL::SDLK_1 then ImGuiKey_1
120
+ when SDL::SDLK_2 then ImGuiKey_2
121
+ when SDL::SDLK_3 then ImGuiKey_3
122
+ when SDL::SDLK_4 then ImGuiKey_4
123
+ when SDL::SDLK_5 then ImGuiKey_5
124
+ when SDL::SDLK_6 then ImGuiKey_6
125
+ when SDL::SDLK_7 then ImGuiKey_7
126
+ when SDL::SDLK_8 then ImGuiKey_8
127
+ when SDL::SDLK_9 then ImGuiKey_9
128
+ when SDL::SDLK_a then ImGuiKey_A
129
+ when SDL::SDLK_b then ImGuiKey_B
130
+ when SDL::SDLK_c then ImGuiKey_C
131
+ when SDL::SDLK_d then ImGuiKey_D
132
+ when SDL::SDLK_e then ImGuiKey_E
133
+ when SDL::SDLK_f then ImGuiKey_F
134
+ when SDL::SDLK_g then ImGuiKey_G
135
+ when SDL::SDLK_h then ImGuiKey_H
136
+ when SDL::SDLK_i then ImGuiKey_I
137
+ when SDL::SDLK_j then ImGuiKey_J
138
+ when SDL::SDLK_k then ImGuiKey_K
139
+ when SDL::SDLK_l then ImGuiKey_L
140
+ when SDL::SDLK_m then ImGuiKey_M
141
+ when SDL::SDLK_n then ImGuiKey_N
142
+ when SDL::SDLK_o then ImGuiKey_O
143
+ when SDL::SDLK_p then ImGuiKey_P
144
+ when SDL::SDLK_q then ImGuiKey_Q
145
+ when SDL::SDLK_r then ImGuiKey_R
146
+ when SDL::SDLK_s then ImGuiKey_S
147
+ when SDL::SDLK_t then ImGuiKey_T
148
+ when SDL::SDLK_u then ImGuiKey_U
149
+ when SDL::SDLK_v then ImGuiKey_V
150
+ when SDL::SDLK_w then ImGuiKey_W
151
+ when SDL::SDLK_x then ImGuiKey_X
152
+ when SDL::SDLK_y then ImGuiKey_Y
153
+ when SDL::SDLK_z then ImGuiKey_Z
154
+ when SDL::SDLK_F1 then ImGuiKey_F1
155
+ when SDL::SDLK_F2 then ImGuiKey_F2
156
+ when SDL::SDLK_F3 then ImGuiKey_F3
157
+ when SDL::SDLK_F4 then ImGuiKey_F4
158
+ when SDL::SDLK_F5 then ImGuiKey_F5
159
+ when SDL::SDLK_F6 then ImGuiKey_F6
160
+ when SDL::SDLK_F7 then ImGuiKey_F7
161
+ when SDL::SDLK_F8 then ImGuiKey_F8
162
+ when SDL::SDLK_F9 then ImGuiKey_F9
163
+ when SDL::SDLK_F10 then ImGuiKey_F10
164
+ when SDL::SDLK_F11 then ImGuiKey_F11
165
+ when SDL::SDLK_F12 then ImGuiKey_F12
166
+ else ImGuiKey_None
167
+ end
168
+ end
169
+
170
+ # [INTERNAL]
171
+ def self.ImGui_ImplSDL2_UpdateKeyModifiers(sdl_key_mods)
172
+ io = ImGuiIO.new(ImGui::GetIO())
173
+ io.AddKeyEvent(ImGuiKey_ModCtrl, (sdl_key_mods & SDL::KMOD_CTRL) != 0)
174
+ io.AddKeyEvent(ImGuiKey_ModShift, (sdl_key_mods & SDL::KMOD_SHIFT) != 0)
175
+ io.AddKeyEvent(ImGuiKey_ModAlt, (sdl_key_mods & SDL::KMOD_ALT) != 0)
176
+ io.AddKeyEvent(ImGuiKey_ModSuper, (sdl_key_mods & SDL::KMOD_GUI) != 0)
177
+ end
178
+
179
+ # You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
180
+ # - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
181
+ # - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
182
+ # Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
183
+ # If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
184
+ def self.ImplSDL2_ProcessEvent(event)
185
+ io = ImGuiIO.new(ImGui::GetIO())
186
+ bd = ImGui_ImplSDL2_GetBackendData()
187
+
188
+ case event[:type]
189
+
190
+ when SDL::MOUSEMOTION
191
+ io.AddMousePosEvent(event[:motion][:x].to_f, event[:motion][:y].to_f)
192
+ return true
193
+
194
+ when SDL::MOUSEWHEEL
195
+ wheel_x = (event[:wheel][:x] > 0) ? 1.0 : (event[:wheel][:x] < 0) ? -1.0 : 0.0
196
+ wheel_y = (event[:wheel][:y] > 0) ? 1.0 : (event[:wheel][:y] < 0) ? -1.0 : 0.0
197
+ io.AddMouseWheelEvent(wheel_x, wheel_y)
198
+ return true
199
+
200
+ when SDL::MOUSEBUTTONDOWN, SDL::MOUSEBUTTONUP
201
+ mouse_button = -1
202
+ mouse_button = 0 if event[:button][:button] == SDL::BUTTON_LEFT
203
+ mouse_button = 1 if event[:button][:button] == SDL::BUTTON_RIGHT
204
+ mouse_button = 2 if event[:button][:button] == SDL::BUTTON_MIDDLE
205
+ if mouse_button != -1
206
+ io.AddMouseButtonEvent(mouse_button, event[:type] == SDL::MOUSEBUTTONDOWN)
207
+ bd.mouseButtonsDown = (event[:type] == SDL::MOUSEBUTTONDOWN) ? (bd.mouseButtonsDown | (1 << mouse_button)) : (bd.mouseButtonsDown & ~(1 << mouse_button))
208
+ return true
209
+ end
210
+
211
+ when SDL::TEXTINPUT
212
+ io.AddInputCharactersUTF8(event[:text][:text])
213
+ return true
214
+
215
+ when SDL::KEYDOWN, SDL::KEYUP
216
+ ImGui_ImplSDL2_UpdateKeyModifiers(event[:key][:keysym][:mod])
217
+ key = ImGui_ImplSDL2_KeyToImGuiKey(event[:key][:keysym][:sym])
218
+ io.AddKeyEvent(key, (event[:type] == SDL::KEYDOWN))
219
+ io.SetKeyEventNativeData(key, event[:key][:keysym][:sym], event[:key][:keysym][:scancode], event[:key][:keysym][:scancode]) # To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
220
+ return true
221
+
222
+ when SDL::WINDOWEVENT
223
+ io.AddMousePosEvent(-Float::MAX, -Float::MAX) if event[:window][:event] == SDL::WINDOWEVENT_LEAVE
224
+
225
+ if event[:window][:event] == SDL::WINDOWEVENT_FOCUS_GAINED
226
+ io.AddFocusEvent(true)
227
+ elsif event[:window][:event] == SDL::WINDOWEVENT_FOCUS_LOST
228
+ io.AddFocusEvent(false)
229
+ end
230
+ return true
231
+
232
+ end
233
+
234
+ return false
235
+ end
236
+
237
+ def self.ImplSDL2_Init(window, renderer)
238
+
239
+ # Check and store if we are on a SDL backend that supports global mouse position
240
+ # ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
241
+ mouse_can_use_global_state = false
242
+ sdl_backend = SDL.GetCurrentVideoDriver().read_string
243
+ global_mouse_whitelist = ["windows", "cocoa", "x11", "DIVE", "VMAN"]
244
+ global_mouse_whitelist.each do |platform|
245
+ mouse_can_use_global_state = true if sdl_backend == platform
246
+ end
247
+
248
+ # Setup backend capabilities flags
249
+ bd = ImGui_ImplSDL2_Data.new
250
+ @@g_BackendData[ImGui::GetCurrentContext().address] = bd
251
+
252
+ io = ImGuiIO.new(ImGui::GetIO())
253
+ io[:BackendPlatformName] = @@g_BackendPlatformName
254
+ io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
255
+ io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
256
+
257
+ bd.window = window
258
+ bd.renderer = renderer
259
+ bd.mouseCanUseGlobalState = mouse_can_use_global_state
260
+
261
+ # [TODO] Support ClipboardText : pass callbacks as Proc or something
262
+ # io[:SetClipboardTextFn] = ImGui_ImplSDL2_SetClipboardText
263
+ # io[:GetClipboardTextFn] = ImGui_ImplSDL2_GetClipboardText
264
+ io[:ClipboardUserData] = nil
265
+
266
+ # Load mouse cursors
267
+ bd.mouseCursors[ImGuiMouseCursor_Arrow] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_ARROW)
268
+ bd.mouseCursors[ImGuiMouseCursor_TextInput] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_IBEAM)
269
+ bd.mouseCursors[ImGuiMouseCursor_ResizeAll] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZEALL)
270
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNS] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENS)
271
+ bd.mouseCursors[ImGuiMouseCursor_ResizeEW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZEWE)
272
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENESW)
273
+ bd.mouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENWSE)
274
+ bd.mouseCursors[ImGuiMouseCursor_Hand] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_HAND)
275
+ bd.mouseCursors[ImGuiMouseCursor_NotAllowed] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NO)
276
+
277
+ # Set platform dependent data in viewport
278
+ case RbConfig::CONFIG['host_os']
279
+ when /mswin|msys|mingw|cygwin/
280
+ info = SDL::SysWMinfo_win.new
281
+ SDL.GetVersion(info[:version])
282
+ if SDL.GetWindowWMInfo(window, info) == SDL::TRUE
283
+ viewport = ImGuiViewport.new(ImGui::GetMainViewport())
284
+ viewport[:PlatformHandleRaw] = info[:info][:win][:window]
285
+ end
286
+ end
287
+
288
+ # Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
289
+ # Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
290
+ # (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
291
+ # It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
292
+ # you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
293
+ if defined?(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH)
294
+ SDL.SetHint(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")
295
+ end
296
+
297
+ return true
298
+ end
299
+
300
+ def self.ImplSDL2_Shutdown()
301
+ io = ImGuiIO.new(ImGui::GetIO())
302
+ bd = ImGui_ImplSDL2_GetBackendData()
303
+
304
+ SDL.free(bd.clipboardTextData) if bd.clipboardTextData
305
+
306
+ ImGuiMouseCursor_COUNT.times do |cursor_n|
307
+ SDL.FreeCursor(bd.mouseCursors[cursor_n])
308
+ bd.mouseCursors[cursor_n] = nil
309
+ end
310
+
311
+ io[:BackendPlatformName] = nil
312
+ io[:BackendPlatformUserData] = nil
313
+ @@g_BackendData[ImGui::GetCurrentContext()] = nil
314
+ end
315
+
316
+ # [INTERNAL]
317
+ def self.ImplSDL2_UpdateMouseData()
318
+ bd = ImGui_ImplSDL2_GetBackendData()
319
+ io = ImGuiIO.new(ImGui::GetIO())
320
+
321
+ SDL.CaptureMouse(bd.mouseButtonsDown != 0 ? SDL::TRUE : SDL::FALSE)
322
+ focused_window = SDL.GetKeyboardFocus()
323
+ is_app_focused = (bd.window == focused_window)
324
+ if is_app_focused
325
+ # (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
326
+ if io[:WantSetMousePos]
327
+ SDL.WarpMouseInWindow(bd.window, io[:MousePos][:x].to_i, io[:MousePos][:y].to_i)
328
+ end
329
+
330
+ # (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
331
+ if bd.mouseCanUseGlobalState && bd.mouseButtonsDown == 0
332
+ wx = FFI::MemoryPointer.new(:int)
333
+ wy = FFI::MemoryPointer.new(:int)
334
+ mx = FFI::MemoryPointer.new(:int)
335
+ my = FFI::MemoryPointer.new(:int)
336
+ SDL.GetGlobalMouseState(mx, my)
337
+ SDL.GetWindowPosition(bd.window, wx, wy)
338
+ io.AddMousePosEvent(mx.read(:int).to_f - wx.read(:int).to_f, my.read(:int).to_f - wy.read(:int).to_f)
339
+ end
340
+ end
341
+ end
342
+
343
+ # [INTERNAL]
344
+ def self.ImplSDL2_UpdateMouseCursor()
345
+ io = ImGuiIO.new(ImGui::GetIO())
346
+ return if (io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange)
347
+ bd = ImGui_ImplSDL2_GetBackendData()
348
+
349
+ imgui_cursor = ImGui::GetMouseCursor()
350
+ if io[:MouseDrawCursor] || imgui_cursor == ImGuiMouseCursor_None
351
+ # Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
352
+ SDL.ShowCursor(SDL::FALSE)
353
+ else
354
+ # Show OS mouse cursor
355
+ SDL.SetCursor(bd.mouseCursors[imgui_cursor] ? bd.mouseCursors[imgui_cursor] : bd.mouseCursors[ImGuiMouseCursor_Arrow])
356
+ SDL.ShowCursor(SDL::TRUE)
357
+ end
358
+ end
359
+
360
+ #
361
+ # [TODO] Support ImplSDL2_UpdateGamepads
362
+ #
363
+
364
+ def self.ImplSDL2_NewFrame()
365
+ bd = ImGui_ImplSDL2_GetBackendData()
366
+ io = ImGuiIO.new(ImGui::GetIO())
367
+
368
+ # Setup display size (every frame to accommodate for window resizing)
369
+ w = ' ' * 4
370
+ h = ' ' * 4
371
+ display_w = ' ' * 4
372
+ display_h = ' ' * 4
373
+ SDL.GetWindowSize(bd.window, w, h)
374
+ w = w.unpack1('L')
375
+ h = h.unpack1('L')
376
+
377
+ if (SDL.GetWindowFlags(bd.window) & SDL::WINDOW_MINIMIZED) != 0
378
+ w = h = 0
379
+ end
380
+ if bd.renderer != nil
381
+ SDL.GetRendererOutputSize(bd.renderer, display_w, display_h)
382
+ else
383
+ SDL.GL_GetDrawableSize(bd.window, display_w, display_h)
384
+ end
385
+ display_w = display_w.unpack1('L')
386
+ display_h = display_h.unpack1('L')
387
+
388
+ io[:DisplaySize] = ImVec2.create(w.to_f, h.to_f)
389
+
390
+ if w > 0 && h > 0
391
+ io[:DisplayFramebufferScale][:x] = display_w.to_f / w
392
+ io[:DisplayFramebufferScale][:y] = display_h.to_f / h
393
+ end
394
+
395
+ # Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
396
+ frequency = SDL.GetPerformanceFrequency()
397
+ current_time = SDL.GetPerformanceCounter()
398
+
399
+ io[:DeltaTime] = bd.time > 0 ? ((current_time - bd.time).to_f / frequency) : (1.0/60.0)
400
+ bd.time = current_time
401
+
402
+ ImplSDL2_UpdateMouseData()
403
+ ImplSDL2_UpdateMouseCursor()
404
+
405
+ # [TODO] update gamepads
406
+ # ImGui_ImplSDL2_UpdateGamepads()
407
+ end
408
+
409
+ end