PasImGui.Backend.SDL2.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139
  1. {
  2. FreePascal / Delphi bindings for ImGui
  3. Copyright (C) 2023 Coldzer0 <Coldzer0 [at] protonmail.ch>
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the MIT License.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. MIT License for more details.
  10. }
  11. Unit PasImGui.Backend.SDL2;
  12. {$IFDEF FPC}
  13. {$mode objfpc}{$H+}{$J-}
  14. {$PackRecords C}
  15. {$ENDIF}
  16. {$POINTERMATH ON}
  17. {$Define SDL_HINT_IME_SHOW_UI}
  18. {$Define SDL_HINT_MOUSE_AUTO_CAPTURE}
  19. {$Define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH}
  20. {$Define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE}
  21. Interface
  22. Uses
  23. {$IfDef MSWINDOWS}
  24. Windows,
  25. {$EndIf}
  26. SDL2,
  27. PasImGui,
  28. PasImGui.Utils;
  29. Function ImGui_ImplSDL2_InitForOpenGL_Pas(window: PSDL_Window; sdl_gl_context: Pointer): Boolean;
  30. Function ImGui_ImplSDL2_ProcessEvent_Pas(event: PSDL_Event): Boolean;
  31. Procedure ImGui_ImplSDL2_NewFrame_Pas();
  32. Procedure ImGui_ImplSDL2_Shutdown_Pas();
  33. Type
  34. PImGui_ImplSDL2_Data = ^ImGui_ImplSDL2_Data;
  35. ImGui_ImplSDL2_Data = Record
  36. Window: PSDL_Window;
  37. Renderer: PSDL_Renderer;
  38. Time: Uint64;
  39. MouseWindowID: Uint32;
  40. MouseButtonsDown: Integer;
  41. MouseCursors: Array [0..Ord(ImGuiMouseCursor_COUNT) - 1] Of PSDL_Cursor;
  42. LastMouseCursor: PSDL_Cursor;
  43. PendingMouseLeaveFrame: Integer;
  44. ClipboardTextData: Pansichar;
  45. MouseCanUseGlobalState: Boolean;
  46. MouseCanReportHoveredViewport: Boolean;
  47. UseVulkan: Boolean;
  48. WantUpdateMonitors: Boolean;
  49. End;
  50. PImGui_ImplSDL2_ViewportData = ^ImGui_ImplSDL2_ViewportData;
  51. ImGui_ImplSDL2_ViewportData = Record
  52. Window: PSDL_Window;
  53. WindowID: Uint32;
  54. WindowOwned: Boolean;
  55. GLContext: TSDL_GLContext;
  56. End;
  57. Implementation
  58. Uses
  59. SysUtils;
  60. // Done
  61. Function ImGui_ImplSDL2_GetBackendData(): PImGui_ImplSDL2_Data;
  62. Begin
  63. If ImGui.GetCurrentContext() <> nil Then
  64. Result := PImGui_ImplSDL2_Data(ImGui.GetIO()^.BackendPlatformUserData)
  65. Else
  66. Result := nil;
  67. End;
  68. //--------------------------------------------------------------------------------------------------------
  69. // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
  70. // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
  71. // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
  72. //--------------------------------------------------------------------------------------------------------
  73. // Done
  74. Procedure ImGui_ImplSDL2_CreateWindow(viewport: PImGuiViewport); Cdecl;
  75. Var
  76. bd: PImGui_ImplSDL2_Data;
  77. main_viewport: PImGuiViewport;
  78. main_viewport_data, vd: PImGui_ImplSDL2_ViewportData;
  79. use_opengl: Boolean;
  80. backup_context: TSDL_GLContext;
  81. sdl_flags: Uint32;
  82. info: TSDL_SysWMinfo;
  83. Begin
  84. Initialize(info);
  85. bd := ImGui_ImplSDL2_GetBackendData();
  86. vd := AllocMem(SizeOf(ImGui_ImplSDL2_ViewportData));
  87. viewport^.PlatformUserData := vd;
  88. main_viewport := ImGui.GetMainViewport();
  89. main_viewport_data := main_viewport^.PlatformUserData;
  90. // Share GL resources with main context
  91. use_opengl := (main_viewport_data^.GLContext <> nil);
  92. backup_context := nil;
  93. If use_opengl Then
  94. Begin
  95. backup_context := SDL_GL_GetCurrentContext();
  96. SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
  97. SDL_GL_MakeCurrent(main_viewport_data^.Window, main_viewport_data^.GLContext);
  98. End;
  99. sdl_flags := SDL_WINDOW_ALLOW_HIGHDPI;
  100. If use_opengl Then
  101. sdl_flags := sdl_flags Or SDL_WINDOW_OPENGL;
  102. { TODO: SDL Unit needs update - Time : 11/7/2023 7:26:01 PM }
  103. //if bd^.UseVulkan then
  104. // sdl_flags := sdl_flags or SDL_WINDOW_VULKAN;
  105. sdl_flags := sdl_flags Or (SDL_GetWindowFlags(bd^.Window) And SDL_WINDOW_ALLOW_HIGHDPI);
  106. sdl_flags := sdl_flags Or SDL_WINDOW_HIDDEN;
  107. If (viewport^.Flags And ImGuiViewportFlags_NoDecoration) <> 0 Then
  108. sdl_flags := sdl_flags Or SDL_WINDOW_BORDERLESS
  109. Else
  110. sdl_flags := sdl_flags Or SDL_WINDOW_RESIZABLE;
  111. {$IfNDef MSWINDOWS}
  112. if (viewport^.Flags and ImGuiViewportFlags_NoTaskBarIcon) <> 0 then
  113. sdl_flags := sdl_flags or SDL_WINDOW_SKIP_TASKBAR;
  114. {$EndIf}
  115. If SDL_VERSION_ATLEAST(2, 0, 5) Then
  116. Begin
  117. If (viewport^.Flags And ImGuiViewportFlags_TopMost) <> 0 Then
  118. sdl_flags := sdl_flags Or SDL_WINDOW_ALWAYS_ON_TOP;
  119. End;
  120. vd^.Window := SDL_CreateWindow('No Title Yet', Trunc(viewport^.Pos.x), Trunc(viewport^.Pos.y),
  121. Trunc(viewport^.Size.x), Trunc(viewport^.Size.y), sdl_flags);
  122. vd^.WindowOwned := True;
  123. If use_opengl Then
  124. Begin
  125. vd^.GLContext := SDL_GL_CreateContext(vd^.Window);
  126. SDL_GL_SetSwapInterval(0);
  127. End;
  128. If use_opengl And (backup_context <> nil) Then
  129. SDL_GL_MakeCurrent(vd^.Window, backup_context);
  130. viewport^.PlatformHandle := vd^.Window;
  131. viewport^.PlatformHandleRaw := nil;
  132. FillChar(info, SizeOf(TSDL_SysWMinfo), 0);
  133. SDL_VERSION(info.version);
  134. If SDL_GetWindowWMInfo(vd^.window, @info) = SDL_TRUE Then
  135. Begin
  136. {$IfDef MSWINDOWS}
  137. viewport^.PlatformHandleRaw := {%H-}Pointer(info.win.window);
  138. {$ElseIf defined(DARWIN)}
  139. viewport^.PlatformHandleRaw = {%H-}
  140. Pointer(info.cocoa.window);
  141. {$EndIf}
  142. End;
  143. End;
  144. // Done
  145. Procedure ImGui_ImplSDL2_DestroyWindow(viewport: PImGuiViewport); Cdecl;
  146. Var
  147. vd: PImGui_ImplSDL2_ViewportData;
  148. Begin
  149. vd := viewport^.PlatformUserData;
  150. If vd <> nil Then
  151. Begin
  152. If (vd^.GLContext <> nil) And vd^.WindowOwned Then
  153. SDL_GL_DeleteContext(vd^.GLContext);
  154. If (vd^.Window <> nil) And vd^.WindowOwned Then
  155. SDL_DestroyWindow(vd^.Window);
  156. vd^.GLContext := nil;
  157. vd^.Window := nil;
  158. Freemem(vd);
  159. End;
  160. viewport^.PlatformHandle := nil;
  161. viewport^.PlatformUserData := nil;
  162. End;
  163. // Done
  164. Procedure ImGui_ImplSDL2_ShowWindow(viewport: PImGuiViewport); Cdecl;
  165. Var
  166. vd: PImGui_ImplSDL2_ViewportData;
  167. {$IfDef MSWINDOWS}
  168. _hwnd: Windows.HWND;
  169. ex_style: LONG;
  170. {$EndIf}
  171. Begin
  172. vd := viewport^.PlatformUserData;
  173. {$IfDef MSWINDOWS}
  174. _hwnd := {%H-}Windows.HWND(viewport^.PlatformHandleRaw);
  175. // SDL hack: Hide icon from task bar
  176. // Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported
  177. // under Windows but the way it create the window breaks our seamless transition.
  178. If (viewport^.Flags And ImGuiViewportFlags_NoTaskBarIcon) <> 0 Then
  179. Begin
  180. ex_style := GetWindowLong(_hwnd, GWL_EXSTYLE);
  181. ex_style := ex_style And Not WS_EX_APPWINDOW;
  182. ex_style := ex_style Or WS_EX_TOOLWINDOW;
  183. SetWindowLong(_hwnd, GWL_EXSTYLE, ex_style);
  184. End;
  185. // SDL hack: SDL always activate/focus windows :/
  186. If (viewport^.Flags And ImGuiViewportFlags_NoFocusOnAppearing) <> 0 Then
  187. Begin
  188. ShowWindow(_hwnd, SW_SHOWNA);
  189. Exit;
  190. End;
  191. {$EndIf}
  192. SDL_ShowWindow(vd^.Window);
  193. End;
  194. // Done
  195. Function ImGui_ImplSDL2_GetWindowPos(viewport: PImGuiViewport): ImVec2; Cdecl;
  196. Var
  197. vd: PImGui_ImplSDL2_ViewportData;
  198. x, y: Integer;
  199. Begin
  200. vd := viewport^.PlatformUserData;
  201. x := 0;
  202. y := 0;
  203. SDL_GetWindowPosition(vd^.Window, @x, @y);
  204. Result := ImVec2.New(Single(x), Single(y));
  205. End;
  206. // Done
  207. Procedure ImGui_ImplSDL2_SetWindowPos(viewport: PImGuiViewport; pos: ImVec2); Cdecl;
  208. Var
  209. vd: PImGui_ImplSDL2_ViewportData;
  210. Begin
  211. vd := viewport^.PlatformUserData;
  212. SDL_SetWindowPosition(vd^.Window, Trunc(pos.x), Trunc(pos.y));
  213. End;
  214. // Done
  215. Function ImGui_ImplSDL2_GetWindowSize(viewport: PImGuiViewport): ImVec2; Cdecl;
  216. Var
  217. vd: PImGui_ImplSDL2_ViewportData;
  218. w, h: Integer;
  219. Begin
  220. vd := viewport^.PlatformUserData;
  221. w := 0;
  222. h := 0;
  223. SDL_GetWindowSize(vd^.Window, @w, @h);
  224. Result := ImVec2.New(Single(w), Single(h));
  225. End;
  226. // Done
  227. Procedure ImGui_ImplSDL2_SetWindowSize(viewport: PImGuiViewport; size: ImVec2); Cdecl;
  228. Var
  229. vd: PImGui_ImplSDL2_ViewportData;
  230. Begin
  231. vd := viewport^.PlatformUserData;
  232. SDL_SetWindowSize(vd^.Window, Trunc(size.x), Trunc(size.y));
  233. End;
  234. // Done
  235. Procedure ImGui_ImplSDL2_SetWindowTitle(viewport: PImGuiViewport; Const title: PAnsiChar); Cdecl;
  236. Var
  237. vd: PImGui_ImplSDL2_ViewportData;
  238. Begin
  239. vd := viewport^.PlatformUserData;
  240. SDL_SetWindowTitle(vd^.Window, title);
  241. End;
  242. // Done
  243. Procedure ImGui_ImplSDL2_SetWindowAlpha(viewport: PImGuiViewport; alpha: Single); Cdecl;
  244. Var
  245. vd: PImGui_ImplSDL2_ViewportData;
  246. Begin
  247. vd := viewport^.PlatformUserData;
  248. SDL_SetWindowOpacity(vd^.Window, alpha);
  249. End;
  250. // Done
  251. Procedure ImGui_ImplSDL2_SetWindowFocus(viewport: PImGuiViewport); Cdecl;
  252. Var
  253. vd: PImGui_ImplSDL2_ViewportData;
  254. Begin
  255. vd := viewport^.PlatformUserData;
  256. SDL_RaiseWindow(vd^.Window);
  257. End;
  258. // Done
  259. Function ImGui_ImplSDL2_GetWindowFocus(viewport: PImGuiViewport): Boolean; Cdecl;
  260. Var
  261. vd: PImGui_ImplSDL2_ViewportData;
  262. Begin
  263. vd := viewport^.PlatformUserData;
  264. Result := (SDL_GetWindowFlags(vd^.Window) And SDL_WINDOW_INPUT_FOCUS) <> 0;
  265. End;
  266. // Done
  267. Function ImGui_ImplSDL2_GetWindowMinimized(viewport: PImGuiViewport): Boolean; Cdecl;
  268. Var
  269. vd: PImGui_ImplSDL2_ViewportData;
  270. Begin
  271. vd := viewport^.PlatformUserData;
  272. Result := (SDL_GetWindowFlags(vd^.Window) And SDL_WINDOW_MINIMIZED) <> 0;
  273. End;
  274. // Done
  275. Procedure ImGui_ImplSDL2_RenderWindow(viewport: PImGuiViewport;
  276. {%H-}render_arg: Pointer); Cdecl;
  277. Var
  278. vd: PImGui_ImplSDL2_ViewportData;
  279. Begin
  280. vd := viewport^.PlatformUserData;
  281. If vd^.GLContext <> nil Then
  282. SDL_GL_MakeCurrent(vd^.Window, vd^.GLContext);
  283. End;
  284. // Done
  285. Procedure ImGui_ImplSDL2_SwapBuffers(viewport: PImGuiViewport;
  286. {%H-}render_arg: Pointer); Cdecl;
  287. Var
  288. vd: PImGui_ImplSDL2_ViewportData;
  289. Begin
  290. vd := viewport^.PlatformUserData;
  291. If vd^.GLContext <> nil Then
  292. Begin
  293. SDL_GL_MakeCurrent(vd^.Window, vd^.GLContext);
  294. SDL_GL_SwapWindow(vd^.Window);
  295. End;
  296. End;
  297. // Done
  298. Procedure ImGui_ImplSDL2_InitPlatformInterface(window: PSDL_Window; sdl_gl_context: Pointer);
  299. Var
  300. platform_io: PImGuiPlatformIO;
  301. main_viewport: PImGuiViewport;
  302. vd: PImGui_ImplSDL2_ViewportData;
  303. Begin
  304. platform_io := ImGui.GetPlatformIO();
  305. platform_io^.Platform_CreateWindow := @ImGui_ImplSDL2_CreateWindow;
  306. platform_io^.Platform_DestroyWindow := @ImGui_ImplSDL2_DestroyWindow;
  307. platform_io^.Platform_ShowWindow := @ImGui_ImplSDL2_ShowWindow;
  308. platform_io^.Platform_SetWindowPos := @ImGui_ImplSDL2_SetWindowPos;
  309. platform_io^.Platform_GetWindowPos := @ImGui_ImplSDL2_GetWindowPos;
  310. platform_io^.Platform_SetWindowSize := @ImGui_ImplSDL2_SetWindowSize;
  311. platform_io^.Platform_GetWindowSize := @ImGui_ImplSDL2_GetWindowSize;
  312. platform_io^.Platform_SetWindowFocus := @ImGui_ImplSDL2_SetWindowFocus;
  313. platform_io^.Platform_GetWindowFocus := @ImGui_ImplSDL2_GetWindowFocus;
  314. platform_io^.Platform_GetWindowMinimized := @ImGui_ImplSDL2_GetWindowMinimized;
  315. platform_io^.Platform_SetWindowTitle := @ImGui_ImplSDL2_SetWindowTitle;
  316. platform_io^.Platform_RenderWindow := @ImGui_ImplSDL2_RenderWindow;
  317. platform_io^.Platform_SwapBuffers := @ImGui_ImplSDL2_SwapBuffers;
  318. If SDL_VERSION_ATLEAST(2, 0, 5) Then
  319. Begin
  320. platform_io^.Platform_SetWindowAlpha := @ImGui_ImplSDL2_SetWindowAlpha;
  321. End;
  322. {$IfDef SDL_HAS_VULKAN}
  323. platform_io^.Platform_CreateVkSurface := ImGui_ImplSDL2_CreateVkSurface;
  324. {$EndIf}
  325. // Register main window handle (which is owned by the main application, not by us)
  326. // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
  327. main_viewport := ImGui.GetMainViewport();
  328. vd := AllocMem(SizeOf(ImGui_ImplSDL2_ViewportData));
  329. vd^.Window := window;
  330. vd^.WindowID := SDL_GetWindowID(window);
  331. vd^.WindowOwned := False;
  332. vd^.GLContext := sdl_gl_context;
  333. main_viewport^.PlatformUserData := vd;
  334. main_viewport^.PlatformHandle := vd^.Window;
  335. End;
  336. // Done
  337. Procedure ImGui_ImplSDL2_ShutdownPlatformInterface;
  338. Begin
  339. ImGui.DestroyPlatformWindows();
  340. End;
  341. //------------------------------------------------------------------------------
  342. // Frame Generation
  343. //------------------------------------------------------------------------------
  344. // Done
  345. Function ImGui_ImplSDL2_GetClipboardText({%H-}user_data: Pointer): PAnsiChar; Cdecl;
  346. Var
  347. bd: PImGui_ImplSDL2_Data;
  348. Begin
  349. bd := ImGui_ImplSDL2_GetBackendData();
  350. If bd^.ClipboardTextData <> nil Then
  351. SDL_free(bd^.ClipboardTextData);
  352. bd^.ClipboardTextData := SDL_GetClipboardText();
  353. Result := bd^.ClipboardTextData;
  354. End;
  355. // Done
  356. Procedure ImGui_ImplSDL2_SetClipboardText({%H-}user_data: Pointer; Const Text: PAnsiChar); Cdecl;
  357. Begin
  358. SDL_SetClipboardText(Text);
  359. End;
  360. // Done
  361. // Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
  362. Procedure ImGui_ImplSDL2_SetPlatformImeData(ctx: PImGuiContext; viewport: PImGuiViewport; data: PImGuiPlatformImeData); Cdecl;
  363. Var
  364. r: TSDL_Rect;
  365. Begin
  366. If Data^.WantVisible Then
  367. Begin
  368. r.x := Trunc(Data^.InputPos.x - viewport^.Pos.x);
  369. r.y := Trunc(Data^.InputPos.y - viewport^.Pos.y + Data^.InputLineHeight);
  370. r.w := 1;
  371. r.h := Trunc(Data^.InputLineHeight);
  372. SDL_SetTextInputRect(@r);
  373. End;
  374. End;
  375. // Done
  376. Function ImGui_ImplSDL2_KeycodeToImGuiKey(keycode: TSDL_KeyCode): ImGuiKey;
  377. Begin
  378. Case keycode Of
  379. SDLK_TAB: Result := ImGuiKey_Tab;
  380. SDLK_LEFT: Result := ImGuiKey_LeftArrow;
  381. SDLK_RIGHT: Result := ImGuiKey_RightArrow;
  382. SDLK_UP: Result := ImGuiKey_UpArrow;
  383. SDLK_DOWN: Result := ImGuiKey_DownArrow;
  384. SDLK_PAGEUP: Result := ImGuiKey_PageUp;
  385. SDLK_PAGEDOWN: Result := ImGuiKey_PageDown;
  386. SDLK_HOME: Result := ImGuiKey_Home;
  387. SDLK_END: Result := ImGuiKey_End;
  388. SDLK_INSERT: Result := ImGuiKey_Insert;
  389. SDLK_DELETE: Result := ImGuiKey_Delete;
  390. SDLK_BACKSPACE: Result := ImGuiKey_Backspace;
  391. SDLK_SPACE: Result := ImGuiKey_Space;
  392. SDLK_RETURN: Result := ImGuiKey_Enter;
  393. SDLK_ESCAPE: Result := ImGuiKey_Escape;
  394. SDLK_QUOTE: Result := ImGuiKey_Apostrophe;
  395. SDLK_COMMA: Result := ImGuiKey_Comma;
  396. SDLK_MINUS: Result := ImGuiKey_Minus;
  397. SDLK_PERIOD: Result := ImGuiKey_Period;
  398. SDLK_SLASH: Result := ImGuiKey_Slash;
  399. SDLK_SEMICOLON: Result := ImGuiKey_Semicolon;
  400. SDLK_EQUALS: Result := ImGuiKey_Equal;
  401. SDLK_LEFTBRACKET: Result := ImGuiKey_LeftBracket;
  402. SDLK_BACKSLASH: Result := ImGuiKey_Backslash;
  403. SDLK_RIGHTBRACKET: Result := ImGuiKey_RightBracket;
  404. SDLK_BACKQUOTE: Result := ImGuiKey_GraveAccent;
  405. SDLK_CAPSLOCK: Result := ImGuiKey_CapsLock;
  406. SDLK_SCROLLLOCK: Result := ImGuiKey_ScrollLock;
  407. SDLK_NUMLOCKCLEAR: Result := ImGuiKey_NumLock;
  408. SDLK_PRINTSCREEN: Result := ImGuiKey_PrintScreen;
  409. SDLK_PAUSE: Result := ImGuiKey_Pause;
  410. SDLK_KP_0: Result := ImGuiKey_Keypad0;
  411. SDLK_KP_1: Result := ImGuiKey_Keypad1;
  412. SDLK_KP_2: Result := ImGuiKey_Keypad2;
  413. SDLK_KP_3: Result := ImGuiKey_Keypad3;
  414. SDLK_KP_4: Result := ImGuiKey_Keypad4;
  415. SDLK_KP_5: Result := ImGuiKey_Keypad5;
  416. SDLK_KP_6: Result := ImGuiKey_Keypad6;
  417. SDLK_KP_7: Result := ImGuiKey_Keypad7;
  418. SDLK_KP_8: Result := ImGuiKey_Keypad8;
  419. SDLK_KP_9: Result := ImGuiKey_Keypad9;
  420. SDLK_KP_PERIOD: Result := ImGuiKey_KeypadDecimal;
  421. SDLK_KP_DIVIDE: Result := ImGuiKey_KeypadDivide;
  422. SDLK_KP_MULTIPLY: Result := ImGuiKey_KeypadMultiply;
  423. SDLK_KP_MINUS: Result := ImGuiKey_KeypadSubtract;
  424. SDLK_KP_PLUS: Result := ImGuiKey_KeypadAdd;
  425. SDLK_KP_ENTER: Result := ImGuiKey_KeypadEnter;
  426. SDLK_KP_EQUALS: Result := ImGuiKey_KeypadEqual;
  427. SDLK_LCTRL: Result := ImGuiKey_LeftCtrl;
  428. SDLK_LSHIFT: Result := ImGuiKey_LeftShift;
  429. SDLK_LALT: Result := ImGuiKey_LeftAlt;
  430. SDLK_LGUI: Result := ImGuiKey_LeftSuper;
  431. SDLK_RCTRL: Result := ImGuiKey_RightCtrl;
  432. SDLK_RSHIFT: Result := ImGuiKey_RightShift;
  433. SDLK_RALT: Result := ImGuiKey_RightAlt;
  434. SDLK_RGUI: Result := ImGuiKey_RightSuper;
  435. SDLK_APPLICATION: Result := ImGuiKey_Menu;
  436. SDLK_0: Result := ImGuiKey_0;
  437. SDLK_1: Result := ImGuiKey_1;
  438. SDLK_2: Result := ImGuiKey_2;
  439. SDLK_3: Result := ImGuiKey_3;
  440. SDLK_4: Result := ImGuiKey_4;
  441. SDLK_5: Result := ImGuiKey_5;
  442. SDLK_6: Result := ImGuiKey_6;
  443. SDLK_7: Result := ImGuiKey_7;
  444. SDLK_8: Result := ImGuiKey_8;
  445. SDLK_9: Result := ImGuiKey_9;
  446. SDLK_a: Result := ImGuiKey_A;
  447. SDLK_b: Result := ImGuiKey_B;
  448. SDLK_c: Result := ImGuiKey_C;
  449. SDLK_d: Result := ImGuiKey_D;
  450. SDLK_e: Result := ImGuiKey_E;
  451. SDLK_f: Result := ImGuiKey_F;
  452. SDLK_g: Result := ImGuiKey_G;
  453. SDLK_h: Result := ImGuiKey_H;
  454. SDLK_i: Result := ImGuiKey_I;
  455. SDLK_j: Result := ImGuiKey_J;
  456. SDLK_k: Result := ImGuiKey_K;
  457. SDLK_l: Result := ImGuiKey_L;
  458. SDLK_m: Result := ImGuiKey_M;
  459. SDLK_n: Result := ImGuiKey_N;
  460. SDLK_o: Result := ImGuiKey_O;
  461. SDLK_p: Result := ImGuiKey_P;
  462. SDLK_q: Result := ImGuiKey_Q;
  463. SDLK_r: Result := ImGuiKey_R;
  464. SDLK_s: Result := ImGuiKey_S;
  465. SDLK_t: Result := ImGuiKey_T;
  466. SDLK_u: Result := ImGuiKey_U;
  467. SDLK_v: Result := ImGuiKey_V;
  468. SDLK_w: Result := ImGuiKey_W;
  469. SDLK_x: Result := ImGuiKey_X;
  470. SDLK_y: Result := ImGuiKey_Y;
  471. SDLK_z: Result := ImGuiKey_Z;
  472. SDLK_F1: Result := ImGuiKey_F1;
  473. SDLK_F2: Result := ImGuiKey_F2;
  474. SDLK_F3: Result := ImGuiKey_F3;
  475. SDLK_F4: Result := ImGuiKey_F4;
  476. SDLK_F5: Result := ImGuiKey_F5;
  477. SDLK_F6: Result := ImGuiKey_F6;
  478. SDLK_F7: Result := ImGuiKey_F7;
  479. SDLK_F8: Result := ImGuiKey_F8;
  480. SDLK_F9: Result := ImGuiKey_F9;
  481. SDLK_F10: Result := ImGuiKey_F10;
  482. SDLK_F11: Result := ImGuiKey_F11;
  483. SDLK_F12: Result := ImGuiKey_F12;
  484. Else
  485. Result := ImGuiKey_None;
  486. End;
  487. End;
  488. // Done
  489. Procedure ImGui_ImplSDL2_UpdateKeyModifiers(sdl_key_mods: TSDL_KeyMod);
  490. Begin
  491. ImGui.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods And KMOD_CTRL) <> 0);
  492. ImGui.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods And KMOD_SHIFT) <> 0);
  493. ImGui.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods And KMOD_ALT) <> 0);
  494. ImGui.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods And KMOD_GUI) <> 0);
  495. End;
  496. // FIXME
  497. Function ImGui_ImplSDL2_Init(window: PSDL_Window; renderer: PSDL_Renderer; sdl_gl_context: Pointer): Boolean;
  498. Var
  499. io: PImGuiIO;
  500. bd: PImGui_ImplSDL2_Data;
  501. main_viewport: PImGuiViewport;
  502. mouse_can_use_global_state: Boolean;
  503. sdl_backend: Pansichar;
  504. I: Integer;
  505. info: TSDL_SysWMinfo;
  506. Const
  507. global_mouse_whitelist: Array[0..4] Of
  508. PAnsiChar = ('windows', 'cocoa', 'x11', 'DIVE', 'VMAN');
  509. Begin
  510. io := ImGui.GetIO();
  511. Assert(io^.BackendPlatformUserData = nil, 'Already initialized a platform backend!');
  512. // Check and store if we are on a SDL backend that supports global mouse position
  513. // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
  514. mouse_can_use_global_state := False;
  515. sdl_backend := SDL_GetCurrentVideoDriver();
  516. For I := 0 To High(global_mouse_whitelist) Do
  517. Begin
  518. If StrIComp(sdl_backend, global_mouse_whitelist[I]) = 0 Then
  519. Begin
  520. mouse_can_use_global_state := True;
  521. Break; // Break the loop early if a match is found
  522. End;
  523. End;
  524. // Setup backend capabilities flags
  525. bd := AllocMem(SizeOf(ImGui_ImplSDL2_Data));
  526. io^.BackendPlatformUserData := bd;
  527. io^.BackendPlatformName := PAnsiChar('imgui_impl_sdl2_pascal');
  528. // We can honor GetMouseCursor() values (optional)
  529. io^.BackendFlags := io^.BackendFlags Or ImGuiBackendFlags_HasMouseCursors;
  530. // We can honor io.WantSetMousePos requests (optional, rarely used)
  531. io^.BackendFlags := io^.BackendFlags Or ImGuiBackendFlags_HasSetMousePos;
  532. If mouse_can_use_global_state Then
  533. Begin
  534. // We can create multi-viewports on the Platform side (optional)
  535. io^.BackendFlags := io^.BackendFlags Or ImGuiBackendFlags_PlatformHasViewports;
  536. End;
  537. bd^.Window := window;
  538. bd^.Renderer := renderer;
  539. // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
  540. // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
  541. bd^.MouseCanUseGlobalState := mouse_can_use_global_state;
  542. {$IfnDef DARWIN}
  543. bd^.MouseCanReportHoveredViewport := bd^.MouseCanUseGlobalState;
  544. {$ELSE}
  545. bd^.MouseCanReportHoveredViewport := False;
  546. {$EndIf}
  547. bd^.WantUpdateMonitors := True;
  548. io^.SetClipboardTextFn := @ImGui_ImplSDL2_SetClipboardText;
  549. io^.GetClipboardTextFn := @ImGui_ImplSDL2_GetClipboardText;
  550. io^.ClipboardUserData := nil;
  551. io^.PlatformSetImeDataFn := @ImGui_ImplSDL2_SetPlatformImeData;
  552. // Load mouse cursors
  553. bd^.MouseCursors[ImGuiMouseCursor_Arrow] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
  554. bd^.MouseCursors[ImGuiMouseCursor_TextInput] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
  555. bd^.MouseCursors[ImGuiMouseCursor_ResizeAll] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
  556. bd^.MouseCursors[ImGuiMouseCursor_ResizeNS] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
  557. bd^.MouseCursors[ImGuiMouseCursor_ResizeEW] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
  558. bd^.MouseCursors[ImGuiMouseCursor_ResizeNESW] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
  559. bd^.MouseCursors[ImGuiMouseCursor_ResizeNWSE] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
  560. bd^.MouseCursors[ImGuiMouseCursor_Hand] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
  561. bd^.MouseCursors[ImGuiMouseCursor_NotAllowed] := SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
  562. main_viewport := ImGui.GetMainViewport();
  563. main_viewport^.PlatformHandle := window;
  564. main_viewport^.PlatformHandleRaw := nil;
  565. Initialize(info);
  566. SDL_VERSION(info.version);
  567. If SDL_GetWindowWMInfo(window, @info) = SDL_TRUE Then
  568. Begin
  569. {$IfDef MSWINDOWS}
  570. main_viewport^.PlatformHandleRaw := {%H-}Pointer(info.win.window);
  571. {$ElseIf defined(DARWIN)}
  572. main_viewport^.PlatformHandleRaw = Pointer(info.cocoa.window);
  573. {$EndIf}
  574. End;
  575. // From 2.0.5 only
  576. {$IfDef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH}
  577. If SDL_VERSION_ATLEAST(2, 0, 5) Then
  578. SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, '1');
  579. {$EndIf}
  580. // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
  581. {$IfDef SDL_HINT_IME_SHOW_UI}
  582. If SDL_VERSION_ATLEAST(2, 0, 22) Then
  583. SDL_SetHint(SDL_HINT_IME_SHOW_UI, '1');
  584. {$ENDIF}
  585. // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
  586. {$IfDef SDL_HINT_MOUSE_AUTO_CAPTURE}
  587. If SDL_VERSION_ATLEAST(2, 0, 22) Then
  588. SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, '0');
  589. {$EndIf}
  590. If ((io^.ConfigFlags And ImGuiConfigFlags_ViewportsEnable) <> 0) And
  591. ((io^.BackendFlags And ImGuiBackendFlags_PlatformHasViewports) <> 0) Then
  592. Begin
  593. ImGui_ImplSDL2_InitPlatformInterface(window, sdl_gl_context);
  594. End;
  595. Result := True;
  596. End;
  597. // Done
  598. Function ImGui_ImplSDL2_InitForOpenGL_Pas(window: PSDL_Window; sdl_gl_context: Pointer): Boolean;
  599. Begin
  600. Result := ImGui_ImplSDL2_Init(window, nil, sdl_gl_context);
  601. End;
  602. // FIXME: Note that doesn't update with DPI/Scaling
  603. // change only as SDL2 doesn't have an event for it (SDL3 has).
  604. Procedure ImGui_ImplSDL2_UpdateMonitors;
  605. Var
  606. platform_io: PImGuiPlatformIO;
  607. bd: PImGui_ImplSDL2_Data;
  608. display_count, n: Integer;
  609. monitor: ImGuiPlatformMonitor;
  610. r: TSDL_Rect;
  611. dpi: Single;
  612. Begin
  613. bd := ImGui_ImplSDL2_GetBackendData();
  614. platform_io := ImGui.GetPlatformIO();
  615. bd^.WantUpdateMonitors := False;
  616. display_count := SDL_GetNumVideoDisplays();
  617. // Allocate Monitors Vector
  618. If platform_io^.Monitors.Data = nil Then
  619. Begin
  620. platform_io^.Monitors.Data := AllocMem(SizeOf(ImGuiPlatformMonitor) * 8);
  621. platform_io^.Monitors.Capacity := 8;
  622. End;
  623. For n := 0 To Pred(display_count) Do
  624. Begin
  625. FillChar(monitor, SizeOf(ImGuiPlatformMonitor), 0);
  626. SDL_GetDisplayBounds(n, @r);
  627. monitor.WorkPos := ImVec2.New(Single(r.x), Single(r.y));
  628. monitor.WorkSize := ImVec2.New(Single(r.w), Single(r.h));
  629. monitor.MainPos := monitor.WorkPos;
  630. monitor.MainSize := monitor.WorkSize;
  631. If SDL_VERSION_ATLEAST(2, 0, 5) Then
  632. Begin
  633. SDL_GetDisplayUsableBounds(n, @r);
  634. monitor.WorkPos := ImVec2.New(Single(r.x), Single(r.y));
  635. monitor.WorkSize := ImVec2.New(Single(r.w), Single(r.h));
  636. End;
  637. If SDL_VERSION_ATLEAST(2, 0, 4) Then
  638. Begin
  639. // FIXME-VIEWPORT: On MacOS SDL reports actual monitor DPI scale,
  640. // ignoring OS configuration. We may want to set
  641. // DpiScale to cocoa_window.backingScaleFactor here.
  642. dpi := 0.0;
  643. If Not Boolean(SDL_GetDisplayDPI(n, @dpi, nil, nil)) Then
  644. monitor.DpiScale := dpi / 96.0;
  645. End;
  646. monitor.PlatformHandle := {%H-}Pointer(UIntPtr(n));
  647. platform_io^.Monitors.Data[n] := monitor;
  648. Inc(platform_io^.Monitors.Size, 1);
  649. End;
  650. End;
  651. // Done
  652. Procedure ImGui_ImplSDL2_UpdateMouseData;
  653. Var
  654. bd: PImGui_ImplSDL2_Data;
  655. io: PImGuiIO;
  656. focused_window: PSDL_Window;
  657. is_app_focused: Boolean;
  658. mouse_x, mouse_y, window_x, window_y: Integer;
  659. mouse_viewport_id: ImGuiID;
  660. mouse_viewport: PImGuiViewport;
  661. mouse_btn: TSDL_bool;
  662. sdl_mouse_window: PSDL_Window;
  663. Begin
  664. bd := ImGui_ImplSDL2_GetBackendData;
  665. io := ImGui.GetIO;
  666. // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
  667. {$IfDef SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE}
  668. // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
  669. mouse_btn := SDL_FALSE;
  670. If bd^.MouseButtonsDown <> 0 Then
  671. mouse_btn := SDL_TRUE;
  672. SDL_CaptureMouse(mouse_btn);
  673. focused_window := SDL_GetKeyboardFocus;
  674. is_app_focused := (focused_window <> nil) And ((bd^.Window = focused_window) Or
  675. (ImGui.FindViewportByPlatformHandle(focused_window) <> nil));
  676. {$ELSE}
  677. focused_window := bd^.Window;
  678. // SDL 2.0.3 and non-windowed systems: single-viewport only
  679. is_app_focused := (SDL_GetWindowFlags(bd^.Window) And SDL_WINDOW_INPUT_FOCUS) <> 0;
  680. {$EndIf}
  681. If is_app_focused Then
  682. Begin
  683. // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
  684. If io^.WantSetMousePos Then
  685. Begin
  686. {$IfDef SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE}
  687. If (io^.ConfigFlags And ImGuiConfigFlags_ViewportsEnable) <> 0 Then
  688. SDL_WarpMouseGlobal(Trunc(io^.MousePos.x), Trunc(io^.MousePos.y))
  689. Else
  690. {$EndIf}
  691. SDL_WarpMouseInWindow(bd^.Window, Trunc(io^.MousePos.x),
  692. Trunc(io^.MousePos.y));
  693. End;
  694. // (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
  695. If bd^.MouseCanUseGlobalState And (bd^.MouseButtonsDown = 0) Then
  696. Begin
  697. // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
  698. // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
  699. SDL_GetGlobalMouseState(@mouse_x, @mouse_y);
  700. If (io^.ConfigFlags And ImGuiConfigFlags_ViewportsEnable) = 0 Then
  701. Begin
  702. SDL_GetWindowPosition(focused_window, @window_x, @window_y);
  703. Dec(mouse_x, window_x);
  704. Dec(mouse_y, window_y);
  705. End;
  706. ImGui.AddMousePosEvent(Single(mouse_x), Single(mouse_y));
  707. End;
  708. End;
  709. // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
  710. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear ImGui will ignore this field and infer the information using its flawed heuristic.
  711. // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
  712. // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
  713. // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
  714. // by the backend, and use its flawed heuristic to guess the viewport behind.
  715. // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
  716. If (io^.BackendFlags And ImGuiBackendFlags_HasMouseHoveredViewport) <> 0 Then
  717. Begin
  718. mouse_viewport_id := 0;
  719. sdl_mouse_window := SDL_GetWindowFromID(bd^.MouseWindowID);
  720. If sdl_mouse_window <> nil Then
  721. Begin
  722. mouse_viewport := ImGui.FindViewportByPlatformHandle(sdl_mouse_window);
  723. If mouse_viewport <> nil Then
  724. Begin
  725. mouse_viewport_id := mouse_viewport^.ID;
  726. End;
  727. End;
  728. ImGui.AddMouseViewportEvent(mouse_viewport_id);
  729. End;
  730. End;
  731. // Done
  732. Procedure ImGui_ImplSDL2_UpdateMouseCursor;
  733. Var
  734. io: PImGuiIO;
  735. bd: PImGui_ImplSDL2_Data;
  736. imgui_cursor: ImGuiMouseCursor;
  737. expected_cursor: PSDL_Cursor;
  738. Begin
  739. io := ImGui.GetIO;
  740. If (io^.ConfigFlags And ImGuiConfigFlags_NoMouseCursorChange) <> 0 Then
  741. Exit;
  742. bd := ImGui_ImplSDL2_GetBackendData;
  743. imgui_cursor := ImGui.GetMouseCursor;
  744. If io^.MouseDrawCursor Or (imgui_cursor = ImGuiMouseCursor_None) Then
  745. Begin
  746. // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
  747. SDL_ShowCursor(Ord(SDL_FALSE));
  748. End
  749. Else
  750. Begin
  751. // Show OS mouse cursor
  752. expected_cursor := bd^.MouseCursors[imgui_cursor];
  753. If expected_cursor = nil Then
  754. expected_cursor := bd^.MouseCursors[ImGuiMouseCursor_Arrow];
  755. If bd^.LastMouseCursor <> expected_cursor Then
  756. Begin
  757. SDL_SetCursor(expected_cursor);
  758. // SDL function doesn't have an early out (see #6113)
  759. bd^.LastMouseCursor := expected_cursor;
  760. End;
  761. SDL_ShowCursor(Ord(SDL_TRUE));
  762. End;
  763. End;
  764. { TODO: Implement this ^_^ - Time : 11/8/2023 1:06:27 AM }
  765. Procedure ImGui_ImplSDL2_UpdateGamepads;
  766. Begin
  767. { TODO: Implement this :V - Time : 11/9/2023 5:12:29 PM }
  768. End;
  769. // Done
  770. Procedure ImGui_ImplSDL2_NewFrame_Pas();
  771. Var
  772. io: PImGuiIO;
  773. bd: PImGui_ImplSDL2_Data;
  774. w, h: Integer;
  775. display_w, display_h: Integer;
  776. frequency, current_time: Uint64;
  777. Begin
  778. bd := ImGui_ImplSDL2_GetBackendData();
  779. Assert(bd <> nil, 'Did you call ImGui_ImplSDL2_Init()?');
  780. io := imgui.GetIO();
  781. // Setup display size (every frame to accommodate for window resizing)
  782. SDL_GetWindowSize(bd^.Window, @w, @h);
  783. If (SDL_GetWindowFlags(bd^.Window) And SDL_WINDOW_MINIMIZED) <> 0 Then
  784. Begin
  785. w := 0;
  786. h := 0;
  787. End;
  788. If bd^.Renderer <> nil Then
  789. SDL_GetRendererOutputSize(bd^.Renderer, @display_w, @display_h)
  790. Else
  791. SDL_GL_GetDrawableSize(bd^.Window, @display_w, @display_h);
  792. io^.DisplaySize := ImVec2.New(Single(w), Single(h));
  793. If (w > 0) And (h > 0) Then
  794. io^.DisplayFramebufferScale := ImVec2.New(Single(display_w) / w, Single(display_h) / h);
  795. // Update monitors
  796. If bd^.WantUpdateMonitors Then
  797. ImGui_ImplSDL2_UpdateMonitors();
  798. // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
  799. // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value.
  800. // Happens in VMs and Emscripten, see #6189, #6114, #3644)
  801. frequency := SDL_GetPerformanceFrequency;
  802. current_time := SDL_GetPerformanceCounter;
  803. If current_time <= bd^.Time Then
  804. current_time := bd^.Time + 1;
  805. If bd^.Time > 0 Then
  806. io^.DeltaTime := Single(double(current_time - bd^.Time) / frequency)
  807. Else
  808. io^.DeltaTime := Single(1.0 / 60.0);
  809. bd^.Time := current_time;
  810. If ((bd^.PendingMouseLeaveFrame > 0) And (bd^.PendingMouseLeaveFrame >= ImGui.GetFrameCount()) And
  811. (bd^.MouseButtonsDown = 0)) Then
  812. Begin
  813. bd^.MouseWindowID := 0;
  814. bd^.PendingMouseLeaveFrame := 0;
  815. ImGui.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
  816. End;
  817. // Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
  818. // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rygorous,
  819. // but testing for payload reduces noise and potential side-effects.
  820. If (bd^.MouseCanReportHoveredViewport And (ImGui.GetDragDropPayload() = nil)) Then
  821. io^.BackendFlags := io^.BackendFlags Or ImGuiBackendFlags_HasMouseHoveredViewport
  822. Else
  823. io^.BackendFlags := io^.BackendFlags And Not ImGuiBackendFlags_HasMouseHoveredViewport;
  824. ImGui_ImplSDL2_UpdateMouseData();
  825. ImGui_ImplSDL2_UpdateMouseCursor();
  826. // Update game controllers (if enabled and available)
  827. ImGui_ImplSDL2_UpdateGamepads();
  828. End;
  829. // Done
  830. Procedure ImGui_ImplSDL2_Shutdown_Pas();
  831. Var
  832. platform_io: PImGuiPlatformIO;
  833. bd: PImGui_ImplSDL2_Data;
  834. io: PImGuiIO;
  835. cursor_n: Integer;
  836. Begin
  837. bd := ImGui_ImplSDL2_GetBackendData();
  838. Assert(bd <> nil, 'No platform backend to shutdown, or already shutdown?');
  839. io := imgui.GetIO();
  840. ImGui_ImplSDL2_ShutdownPlatformInterface();
  841. If bd^.ClipboardTextData <> nil Then
  842. SDL_free(bd^.ClipboardTextData);
  843. For cursor_n := 0 To Pred(ImGuiMouseCursor_COUNT) Do
  844. Begin
  845. SDL_FreeCursor(bd^.MouseCursors[cursor_n]);
  846. End;
  847. bd^.LastMouseCursor := nil;
  848. io^.BackendPlatformName := nil;
  849. io^.BackendPlatformUserData := nil;
  850. io^.BackendFlags := io^.BackendFlags And Not (ImGuiBackendFlags_HasMouseCursors Or
  851. ImGuiBackendFlags_HasSetMousePos Or ImGuiBackendFlags_HasGamepad Or ImGuiBackendFlags_PlatformHasViewports Or
  852. ImGuiBackendFlags_HasMouseHoveredViewport);
  853. // Free Allocated Monitors
  854. platform_io := ImGui.GetPlatformIO();
  855. platform_io^.Monitors.Size := 0;
  856. platform_io^.Monitors.Capacity := 0;
  857. Freemem(platform_io^.Monitors.Data);
  858. platform_io^.Monitors.Data := nil;
  859. Freemem(bd);
  860. End;
  861. // Done
  862. Function ImGui_ImplSDL2_ProcessEvent_Pas(event: PSDL_Event): Boolean;
  863. Var
  864. ImKey: ImGuiKey;
  865. mouse_pos: ImVec2;
  866. window_x, window_y: Integer;
  867. wheel_x, wheel_y: Single;
  868. MouseSrc: ImGuiMouseSource;
  869. mouse_button: Integer;
  870. bd: PImGui_ImplSDL2_Data;
  871. io: PImGuiIO;
  872. window_event: Uint8;
  873. viewport: PImGuiViewport;
  874. Begin
  875. Result := False;
  876. io := ImGui.GetIO();
  877. bd := ImGui_ImplSDL2_GetBackendData();
  878. Case event^.type_ Of
  879. SDL_MOUSEMOTION:
  880. Begin
  881. mouse_pos := ImVec2.New(Single(event^.motion.x), Single(event^.motion.y));
  882. If Int64(io^.ConfigFlags And ImGuiConfigFlags_ViewportsEnable) <> 0 Then
  883. Begin
  884. SDL_GetWindowPosition(SDL_GetWindowFromID(event^.motion.windowID), @window_x, @window_y);
  885. mouse_pos.x := mouse_pos.x + window_x;
  886. mouse_pos.y := mouse_pos.y + window_y;
  887. End;
  888. If event^.motion.which = SDL_TOUCH_MOUSEID Then
  889. ImGui.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen)
  890. Else
  891. ImGui.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
  892. ImGui.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
  893. Result := True;
  894. End;
  895. SDL_MOUSEWHEEL:
  896. Begin
  897. wheel_x := -Single(event^.wheel.x);
  898. wheel_y := Single(event^.wheel.y);
  899. If event^.wheel.which = SDL_TOUCH_MOUSEID Then
  900. MouseSrc := ImGuiMouseSource_TouchScreen
  901. Else
  902. MouseSrc := ImGuiMouseSource_Mouse;
  903. ImGui.AddMouseSourceEvent(MouseSrc);
  904. ImGui.AddMouseWheelEvent(wheel_x, wheel_y);
  905. Result := True;
  906. End;
  907. SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP:
  908. Begin
  909. mouse_button := -1;
  910. If (event^.button.button = SDL_BUTTON_LEFT) Then
  911. mouse_button := 0;
  912. If (event^.button.button = SDL_BUTTON_RIGHT) Then
  913. mouse_button := 1;
  914. If (event^.button.button = SDL_BUTTON_MIDDLE) Then
  915. mouse_button := 2;
  916. If (event^.button.button = SDL_BUTTON_X1) Then
  917. mouse_button := 3;
  918. If (event^.button.button = SDL_BUTTON_X2) Then
  919. mouse_button := 4;
  920. If (mouse_button = -1) Then
  921. Exit;
  922. If event^.wheel.which = SDL_TOUCH_MOUSEID Then
  923. MouseSrc := ImGuiMouseSource_TouchScreen
  924. Else
  925. MouseSrc := ImGuiMouseSource_Mouse;
  926. ImGui.AddMouseSourceEvent(MouseSrc);
  927. ImGui.AddMouseButtonEvent(mouse_button, (event^.type_ = SDL_MOUSEBUTTONDOWN));
  928. If (event^.type_ = SDL_MOUSEBUTTONDOWN) Then
  929. bd^.MouseButtonsDown := bd^.MouseButtonsDown Or (1 Shl mouse_button)
  930. Else
  931. bd^.MouseButtonsDown := bd^.MouseButtonsDown And Not (1 Shl mouse_button);
  932. Result := True;
  933. End;
  934. SDL_TEXTINPUT:
  935. Begin
  936. ImGui.AddInputCharactersUTF8(event^.Text.Text);
  937. Result := True;
  938. End;
  939. SDL_KEYDOWN, SDL_KEYUP:
  940. Begin
  941. ImGui_ImplSDL2_UpdateKeyModifiers(event^.key.keysym.mod_);
  942. ImKey := ImGui_ImplSDL2_KeycodeToImGuiKey(event^.key.keysym.sym);
  943. ImGui.AddKeyEvent(ImKey, (event^.type_ = SDL_KEYDOWN));
  944. // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
  945. ImGui.SetKeyEventNativeData(ImKey, event^.key.keysym.sym,
  946. event^.key.keysym.scancode, event^.key.keysym.scancode);
  947. Result := True;
  948. End;
  949. // SDL_VERSION_ATLEAST(2,0,9) >> SDL_DISPLAYEVENT
  950. SDL_DISPLAYEVENT:
  951. Begin
  952. bd^.WantUpdateMonitors := True;
  953. Result := True;
  954. End;
  955. SDL_WINDOWEVENT:
  956. Begin
  957. // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER
  958. // event on every mouse move, but the final ENTER tends to be right.
  959. // - However we won't get a correct LEAVE event for a captured window.
  960. // - In some cases, when detaching a window from main viewport SDL may
  961. // send SDL_WINDOWEVENT_ENTER one frame too late,
  962. // causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag
  963. // operation by clear mouse position. This is why
  964. // we delay process the SDL_WINDOWEVENT_LEAVE events by one frame.
  965. // See issue #5012 for details.
  966. window_event := event^.window.event;
  967. If window_event = SDL_WINDOWEVENT_ENTER Then
  968. Begin
  969. bd^.MouseWindowID := event^.window.windowID;
  970. bd^.PendingMouseLeaveFrame := 0;
  971. End;
  972. If window_event = SDL_WINDOWEVENT_LEAVE Then
  973. bd^.PendingMouseLeaveFrame := ImGui.GetFrameCount() + 1;
  974. If window_event = SDL_WINDOWEVENT_FOCUS_GAINED Then
  975. ImGui.AddFocusEvent(True)
  976. Else If window_event = SDL_WINDOWEVENT_FOCUS_LOST Then
  977. ImGui.AddFocusEvent(False);
  978. If (window_event = SDL_WINDOWEVENT_CLOSE) Or (window_event = SDL_WINDOWEVENT_MOVED) Or
  979. (window_event = SDL_WINDOWEVENT_RESIZED) Then
  980. Begin
  981. viewport := ImGui.FindViewportByPlatformHandle(SDL_GetWindowFromID(event^.window.windowID));
  982. If viewport <> nil Then
  983. Begin
  984. If window_event = SDL_WINDOWEVENT_CLOSE Then
  985. viewport^.PlatformRequestClose := True;
  986. If window_event = SDL_WINDOWEVENT_MOVED Then
  987. viewport^.PlatformRequestMove := True;
  988. If window_event = SDL_WINDOWEVENT_RESIZED Then
  989. viewport^.PlatformRequestResize := True;
  990. Exit(True);
  991. End;
  992. End;
  993. Result := True;
  994. End;
  995. Else
  996. Result := False;
  997. End;
  998. End;
  999. End.