PasImGui.SDL2.pas 38 KB

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