imgui-bindings 0.0.2.rc1 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 # 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