2023-02-07 13:49:37 +01:00
// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*)
2023-02-07 13:26:24 +01:00
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
2024-07-02 11:37:18 +02:00
2024-09-03 19:05:32 +02:00
// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**)
2023-02-07 13:26:24 +01:00
// Implemented features:
// [X] Platform: Clipboard support.
2023-04-04 19:43:51 +02:00
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
2023-02-07 13:26:24 +01:00
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
2023-02-07 16:30:58 +01:00
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
2024-02-28 11:03:44 +01:00
// Issues:
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
2023-02-07 13:26:24 +01:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
2023-09-11 13:47:08 +02:00
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
2023-02-07 13:26:24 +01:00
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
2024-02-14 14:32:17 +01:00
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2024-09-11 11:41:37 +02:00
// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973)
2024-10-24 14:47:07 +02:00
// 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten.
2024-08-25 19:07:10 +02:00
// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
2024-08-22 17:50:10 +02:00
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
2024-08-22 16:55:14 +02:00
// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
2024-08-19 14:07:25 +02:00
// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*.
2024-08-19 13:57:08 +02:00
// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853)
2024-07-22 10:49:22 +02:00
// 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807)
// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801)
2024-07-18 14:02:17 +02:00
// 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794)
2024-07-02 11:32:46 +02:00
// 2024-07-02: Update for SDL3 api changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762).
2024-07-01 00:28:53 +02:00
// 2024-07-01: Update for SDL3 api changes: SDL_SetTextInputRect() changed to SDL_SetTextInputArea().
2024-06-26 14:41:21 +02:00
// 2024-06-26: Update for SDL3 api changes: SDL_StartTextInput()/SDL_StopTextInput()/SDL_SetTextInputRect() functions signatures.
// 2024-06-24: Update for SDL3 api changes: SDL_EVENT_KEY_DOWN/SDL_EVENT_KEY_UP contents.
// 2024-06-03; Update for SDL3 api changes: SDL_SYSTEM_CURSOR_ renames.
// 2024-05-15: Update for SDL3 api changes: SDLK_ renames.
2024-03-28 21:05:44 +01:00
// 2024-04-15: Inputs: Re-enable calling SDL_StartTextInput()/SDL_StopTextInput() as SDL3 no longer enables it by default and should play nicer with IME.
2024-02-14 11:37:18 +01:00
// 2024-02-13: Inputs: Fixed gamepad support. Handle gamepad disconnection. Added ImGui_ImplSDL3_SetGamepadMode().
2023-11-13 16:20:38 +01:00
// 2023-11-13: Updated for recent SDL3 API changes.
2023-10-05 21:26:07 +02:00
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
2023-05-04 17:06:36 +02:00
// 2023-05-04: Fixed build on Emscripten/iOS/Android. (#6391)
2023-04-11 11:20:29 +02:00
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
2023-04-04 19:43:51 +02:00
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
2023-02-23 13:06:07 +01:00
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
2023-02-07 13:26:24 +01:00
// 2023-02-07: Forked "imgui_impl_sdl2" into "imgui_impl_sdl3". Removed version checks for old feature. Refer to imgui_impl_sdl2.cpp for older changelog.
# include "imgui.h"
2023-07-13 11:27:52 +02:00
# ifndef IMGUI_DISABLE
2023-02-07 13:26:24 +01:00
# include "imgui_impl_sdl3.h"
2023-03-23 18:17:45 +01:00
// Clang warnings with -Weverything
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
# endif
2023-02-07 13:26:24 +01:00
// SDL
2023-02-07 13:49:37 +01:00
# include <SDL3/SDL.h>
2023-02-07 13:26:24 +01:00
# if defined(__APPLE__)
# include <TargetConditionals.h>
# endif
2023-11-13 16:20:38 +01:00
# ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# endif
2023-02-07 13:26:24 +01:00
2023-02-07 13:49:37 +01:00
# if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
2023-02-07 13:26:24 +01:00
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
# else
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
# endif
2024-05-15 14:18:48 +02:00
// FIXME-LEGACY: remove when SDL 3.1.3 preview is released.
# ifndef SDLK_APOSTROPHE
# define SDLK_APOSTROPHE SDLK_QUOTE
# endif
# ifndef SDLK_GRAVE
# define SDLK_GRAVE SDLK_BACKQUOTE
# endif
2023-02-07 13:26:24 +01:00
// SDL Data
struct ImGui_ImplSDL3_Data
{
2024-02-13 15:49:49 +01:00
SDL_Window * Window ;
2024-08-19 13:57:08 +02:00
SDL_WindowID WindowID ;
2024-02-13 15:49:49 +01:00
SDL_Renderer * Renderer ;
Uint64 Time ;
char * ClipboardTextData ;
2024-02-14 14:32:17 +01:00
bool UseVulkan ;
bool WantUpdateMonitors ;
2024-02-13 15:49:49 +01:00
2024-06-26 14:41:21 +02:00
// IME handling
SDL_Window * ImeWindow ;
2024-02-13 15:49:49 +01:00
// Mouse handling
Uint32 MouseWindowID ;
int MouseButtonsDown ;
SDL_Cursor * MouseCursors [ ImGuiMouseCursor_COUNT ] ;
SDL_Cursor * MouseLastCursor ;
int MousePendingLeaveFrame ;
bool MouseCanUseGlobalState ;
2024-02-14 14:32:17 +01:00
bool MouseCanReportHoveredViewport ; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// Gamepad handling
2024-02-14 14:32:17 +01:00
ImVector < SDL_Gamepad * > Gamepads ;
2024-02-14 11:37:18 +01:00
ImGui_ImplSDL3_GamepadMode GamepadMode ;
2024-02-14 14:32:17 +01:00
bool WantUpdateGamepadsList ;
2023-02-07 13:26:24 +01:00
ImGui_ImplSDL3_Data ( ) { memset ( ( void * ) this , 0 , sizeof ( * this ) ) ; }
} ;
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplSDL3_Data * ImGui_ImplSDL3_GetBackendData ( )
{
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplSDL3_Data * ) ImGui : : GetIO ( ) . BackendPlatformUserData : nullptr ;
}
2023-02-07 16:30:58 +01:00
// Forward Declarations
static void ImGui_ImplSDL3_UpdateMonitors ( ) ;
2024-10-08 20:47:24 +02:00
static void ImGui_ImplSDL3_InitMultiViewportSupport ( SDL_Window * window , void * sdl_gl_context ) ;
static void ImGui_ImplSDL3_ShutdownMultiViewportSupport ( ) ;
2023-02-07 16:30:58 +01:00
2023-02-07 13:26:24 +01:00
// Functions
2024-08-22 17:50:10 +02:00
static const char * ImGui_ImplSDL3_GetClipboardText ( ImGuiContext * )
2023-02-07 13:26:24 +01:00
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
2024-07-18 14:02:17 +02:00
const char * sdl_clipboard_text = SDL_GetClipboardText ( ) ;
bd - > ClipboardTextData = sdl_clipboard_text ? SDL_strdup ( sdl_clipboard_text ) : NULL ;
2023-02-07 13:26:24 +01:00
return bd - > ClipboardTextData ;
}
2024-08-22 17:50:10 +02:00
static void ImGui_ImplSDL3_SetClipboardText ( ImGuiContext * , const char * text )
2023-02-07 13:26:24 +01:00
{
SDL_SetClipboardText ( text ) ;
}
2024-07-02 15:48:32 +02:00
static void ImGui_ImplSDL3_PlatformSetImeData ( ImGuiContext * , ImGuiViewport * viewport , ImGuiPlatformImeData * data )
2023-02-07 18:55:10 +01:00
{
2024-06-26 14:41:21 +02:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2024-08-19 14:07:25 +02:00
SDL_WindowID window_id = ( SDL_WindowID ) ( intptr_t ) viewport - > PlatformHandle ;
SDL_Window * window = SDL_GetWindowFromID ( window_id ) ;
2024-06-26 14:41:21 +02:00
if ( ( data - > WantVisible = = false | | bd - > ImeWindow ! = window ) & & bd - > ImeWindow ! = NULL )
{
SDL_StopTextInput ( bd - > ImeWindow ) ;
bd - > ImeWindow = nullptr ;
}
2023-02-07 18:55:10 +01:00
if ( data - > WantVisible )
{
SDL_Rect r ;
2023-04-06 19:18:15 +02:00
r . x = ( int ) ( data - > InputPos . x - viewport - > Pos . x ) ;
r . y = ( int ) ( data - > InputPos . y - viewport - > Pos . y + data - > InputLineHeight ) ;
2023-02-07 18:55:10 +01:00
r . w = 1 ;
r . h = ( int ) data - > InputLineHeight ;
2024-07-01 00:28:53 +02:00
SDL_SetTextInputArea ( window , & r , 0 ) ;
2024-06-26 14:41:21 +02:00
SDL_StartTextInput ( window ) ;
bd - > ImeWindow = window ;
2023-02-07 18:55:10 +01:00
}
}
2024-09-19 14:09:45 +02:00
// Not static to allow third-party code to use that if they want to (but undocumented)
2024-10-24 17:24:47 +02:00
ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey ( SDL_Keycode keycode , SDL_Scancode scancode ) ;
2024-09-19 14:09:45 +02:00
ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey ( SDL_Keycode keycode , SDL_Scancode scancode )
2023-02-07 13:26:24 +01:00
{
2024-07-02 11:32:46 +02:00
// Keypad doesn't have individual key values in SDL3
switch ( scancode )
{
case SDL_SCANCODE_KP_0 : return ImGuiKey_Keypad0 ;
case SDL_SCANCODE_KP_1 : return ImGuiKey_Keypad1 ;
case SDL_SCANCODE_KP_2 : return ImGuiKey_Keypad2 ;
case SDL_SCANCODE_KP_3 : return ImGuiKey_Keypad3 ;
case SDL_SCANCODE_KP_4 : return ImGuiKey_Keypad4 ;
case SDL_SCANCODE_KP_5 : return ImGuiKey_Keypad5 ;
case SDL_SCANCODE_KP_6 : return ImGuiKey_Keypad6 ;
case SDL_SCANCODE_KP_7 : return ImGuiKey_Keypad7 ;
case SDL_SCANCODE_KP_8 : return ImGuiKey_Keypad8 ;
case SDL_SCANCODE_KP_9 : return ImGuiKey_Keypad9 ;
case SDL_SCANCODE_KP_PERIOD : return ImGuiKey_KeypadDecimal ;
case SDL_SCANCODE_KP_DIVIDE : return ImGuiKey_KeypadDivide ;
case SDL_SCANCODE_KP_MULTIPLY : return ImGuiKey_KeypadMultiply ;
case SDL_SCANCODE_KP_MINUS : return ImGuiKey_KeypadSubtract ;
case SDL_SCANCODE_KP_PLUS : return ImGuiKey_KeypadAdd ;
case SDL_SCANCODE_KP_ENTER : return ImGuiKey_KeypadEnter ;
case SDL_SCANCODE_KP_EQUALS : return ImGuiKey_KeypadEqual ;
2024-07-02 12:12:25 +02:00
default : break ;
2024-07-02 11:32:46 +02:00
}
2023-02-07 13:26:24 +01:00
switch ( keycode )
{
case SDLK_TAB : return ImGuiKey_Tab ;
case SDLK_LEFT : return ImGuiKey_LeftArrow ;
case SDLK_RIGHT : return ImGuiKey_RightArrow ;
case SDLK_UP : return ImGuiKey_UpArrow ;
case SDLK_DOWN : return ImGuiKey_DownArrow ;
case SDLK_PAGEUP : return ImGuiKey_PageUp ;
case SDLK_PAGEDOWN : return ImGuiKey_PageDown ;
case SDLK_HOME : return ImGuiKey_Home ;
case SDLK_END : return ImGuiKey_End ;
case SDLK_INSERT : return ImGuiKey_Insert ;
case SDLK_DELETE : return ImGuiKey_Delete ;
case SDLK_BACKSPACE : return ImGuiKey_Backspace ;
case SDLK_SPACE : return ImGuiKey_Space ;
case SDLK_RETURN : return ImGuiKey_Enter ;
case SDLK_ESCAPE : return ImGuiKey_Escape ;
2024-05-14 03:44:48 +02:00
case SDLK_APOSTROPHE : return ImGuiKey_Apostrophe ;
2023-02-07 13:26:24 +01:00
case SDLK_COMMA : return ImGuiKey_Comma ;
case SDLK_MINUS : return ImGuiKey_Minus ;
case SDLK_PERIOD : return ImGuiKey_Period ;
case SDLK_SLASH : return ImGuiKey_Slash ;
case SDLK_SEMICOLON : return ImGuiKey_Semicolon ;
case SDLK_EQUALS : return ImGuiKey_Equal ;
case SDLK_LEFTBRACKET : return ImGuiKey_LeftBracket ;
case SDLK_BACKSLASH : return ImGuiKey_Backslash ;
case SDLK_RIGHTBRACKET : return ImGuiKey_RightBracket ;
2024-05-14 03:44:48 +02:00
case SDLK_GRAVE : return ImGuiKey_GraveAccent ;
2023-02-07 13:26:24 +01:00
case SDLK_CAPSLOCK : return ImGuiKey_CapsLock ;
case SDLK_SCROLLLOCK : return ImGuiKey_ScrollLock ;
case SDLK_NUMLOCKCLEAR : return ImGuiKey_NumLock ;
case SDLK_PRINTSCREEN : return ImGuiKey_PrintScreen ;
case SDLK_PAUSE : return ImGuiKey_Pause ;
case SDLK_LCTRL : return ImGuiKey_LeftCtrl ;
case SDLK_LSHIFT : return ImGuiKey_LeftShift ;
case SDLK_LALT : return ImGuiKey_LeftAlt ;
case SDLK_LGUI : return ImGuiKey_LeftSuper ;
case SDLK_RCTRL : return ImGuiKey_RightCtrl ;
case SDLK_RSHIFT : return ImGuiKey_RightShift ;
case SDLK_RALT : return ImGuiKey_RightAlt ;
case SDLK_RGUI : return ImGuiKey_RightSuper ;
case SDLK_APPLICATION : return ImGuiKey_Menu ;
case SDLK_0 : return ImGuiKey_0 ;
case SDLK_1 : return ImGuiKey_1 ;
case SDLK_2 : return ImGuiKey_2 ;
case SDLK_3 : return ImGuiKey_3 ;
case SDLK_4 : return ImGuiKey_4 ;
case SDLK_5 : return ImGuiKey_5 ;
case SDLK_6 : return ImGuiKey_6 ;
case SDLK_7 : return ImGuiKey_7 ;
case SDLK_8 : return ImGuiKey_8 ;
case SDLK_9 : return ImGuiKey_9 ;
2024-07-02 11:32:46 +02:00
case SDLK_A : return ImGuiKey_A ;
case SDLK_B : return ImGuiKey_B ;
case SDLK_C : return ImGuiKey_C ;
case SDLK_D : return ImGuiKey_D ;
case SDLK_E : return ImGuiKey_E ;
case SDLK_F : return ImGuiKey_F ;
case SDLK_G : return ImGuiKey_G ;
case SDLK_H : return ImGuiKey_H ;
case SDLK_I : return ImGuiKey_I ;
case SDLK_J : return ImGuiKey_J ;
case SDLK_K : return ImGuiKey_K ;
case SDLK_L : return ImGuiKey_L ;
case SDLK_M : return ImGuiKey_M ;
case SDLK_N : return ImGuiKey_N ;
case SDLK_O : return ImGuiKey_O ;
case SDLK_P : return ImGuiKey_P ;
case SDLK_Q : return ImGuiKey_Q ;
case SDLK_R : return ImGuiKey_R ;
case SDLK_S : return ImGuiKey_S ;
case SDLK_T : return ImGuiKey_T ;
case SDLK_U : return ImGuiKey_U ;
case SDLK_V : return ImGuiKey_V ;
case SDLK_W : return ImGuiKey_W ;
case SDLK_X : return ImGuiKey_X ;
case SDLK_Y : return ImGuiKey_Y ;
case SDLK_Z : return ImGuiKey_Z ;
2023-02-07 13:26:24 +01:00
case SDLK_F1 : return ImGuiKey_F1 ;
case SDLK_F2 : return ImGuiKey_F2 ;
case SDLK_F3 : return ImGuiKey_F3 ;
case SDLK_F4 : return ImGuiKey_F4 ;
case SDLK_F5 : return ImGuiKey_F5 ;
case SDLK_F6 : return ImGuiKey_F6 ;
case SDLK_F7 : return ImGuiKey_F7 ;
case SDLK_F8 : return ImGuiKey_F8 ;
case SDLK_F9 : return ImGuiKey_F9 ;
case SDLK_F10 : return ImGuiKey_F10 ;
case SDLK_F11 : return ImGuiKey_F11 ;
case SDLK_F12 : return ImGuiKey_F12 ;
2023-10-05 20:39:49 +02:00
case SDLK_F13 : return ImGuiKey_F13 ;
case SDLK_F14 : return ImGuiKey_F14 ;
case SDLK_F15 : return ImGuiKey_F15 ;
case SDLK_F16 : return ImGuiKey_F16 ;
case SDLK_F17 : return ImGuiKey_F17 ;
case SDLK_F18 : return ImGuiKey_F18 ;
case SDLK_F19 : return ImGuiKey_F19 ;
case SDLK_F20 : return ImGuiKey_F20 ;
case SDLK_F21 : return ImGuiKey_F21 ;
case SDLK_F22 : return ImGuiKey_F22 ;
case SDLK_F23 : return ImGuiKey_F23 ;
case SDLK_F24 : return ImGuiKey_F24 ;
2023-10-05 21:26:07 +02:00
case SDLK_AC_BACK : return ImGuiKey_AppBack ;
case SDLK_AC_FORWARD : return ImGuiKey_AppForward ;
2024-07-02 12:12:25 +02:00
default : break ;
2023-02-07 13:26:24 +01:00
}
return ImGuiKey_None ;
}
static void ImGui_ImplSDL3_UpdateKeyModifiers ( SDL_Keymod sdl_key_mods )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-02-07 13:49:37 +01:00
io . AddKeyEvent ( ImGuiMod_Ctrl , ( sdl_key_mods & SDL_KMOD_CTRL ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Shift , ( sdl_key_mods & SDL_KMOD_SHIFT ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Alt , ( sdl_key_mods & SDL_KMOD_ALT ) ! = 0 ) ;
io . AddKeyEvent ( ImGuiMod_Super , ( sdl_key_mods & SDL_KMOD_GUI ) ! = 0 ) ;
2023-02-07 13:26:24 +01:00
}
2024-08-19 13:57:08 +02:00
static ImGuiViewport * ImGui_ImplSDL3_GetViewportForWindowID ( SDL_WindowID window_id )
{
2024-08-19 14:46:53 +02:00
return ImGui : : FindViewportByPlatformHandle ( ( void * ) ( intptr_t ) window_id ) ;
2024-08-19 13:57:08 +02:00
}
2023-02-07 13:26:24 +01:00
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
bool ImGui_ImplSDL3_ProcessEvent ( const SDL_Event * event )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2024-05-07 16:53:03 +02:00
IM_ASSERT ( bd ! = nullptr & & " Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()? " ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-02-07 13:26:24 +01:00
switch ( event - > type )
{
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_MOTION :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > motion . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
ImVec2 mouse_pos ( ( float ) event - > motion . x , ( float ) event - > motion . y ) ;
2023-02-07 16:30:58 +01:00
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
{
int window_x , window_y ;
SDL_GetWindowPosition ( SDL_GetWindowFromID ( event - > motion . windowID ) , & window_x , & window_y ) ;
mouse_pos . x + = window_x ;
mouse_pos . y + = window_y ;
}
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > motion . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:26:24 +01:00
io . AddMousePosEvent ( mouse_pos . x , mouse_pos . y ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_WHEEL :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > wheel . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
2023-02-07 13:49:37 +01:00
float wheel_x = - event - > wheel . x ;
float wheel_y = event - > wheel . y ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > wheel . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:26:24 +01:00
io . AddMouseWheelEvent ( wheel_x , wheel_y ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_MOUSE_BUTTON_DOWN :
case SDL_EVENT_MOUSE_BUTTON_UP :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > button . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
int mouse_button = - 1 ;
if ( event - > button . button = = SDL_BUTTON_LEFT ) { mouse_button = 0 ; }
if ( event - > button . button = = SDL_BUTTON_RIGHT ) { mouse_button = 1 ; }
if ( event - > button . button = = SDL_BUTTON_MIDDLE ) { mouse_button = 2 ; }
if ( event - > button . button = = SDL_BUTTON_X1 ) { mouse_button = 3 ; }
if ( event - > button . button = = SDL_BUTTON_X2 ) { mouse_button = 4 ; }
if ( mouse_button = = - 1 )
break ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( event - > button . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2023-02-07 13:49:37 +01:00
io . AddMouseButtonEvent ( mouse_button , ( event - > type = = SDL_EVENT_MOUSE_BUTTON_DOWN ) ) ;
bd - > MouseButtonsDown = ( event - > type = = SDL_EVENT_MOUSE_BUTTON_DOWN ) ? ( bd - > MouseButtonsDown | ( 1 < < mouse_button ) ) : ( bd - > MouseButtonsDown & ~ ( 1 < < mouse_button ) ) ;
2023-02-07 13:26:24 +01:00
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_TEXT_INPUT :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > text . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:26:24 +01:00
io . AddInputCharactersUTF8 ( event - > text . text ) ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_KEY_DOWN :
case SDL_EVENT_KEY_UP :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > key . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2024-07-02 11:32:46 +02:00
//IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod);
2024-06-24 00:26:52 +02:00
ImGui_ImplSDL3_UpdateKeyModifiers ( ( SDL_Keymod ) event - > key . mod ) ;
2024-07-02 11:32:46 +02:00
ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey ( event - > key . key , event - > key . scancode ) ;
2023-02-07 13:49:37 +01:00
io . AddKeyEvent ( key , ( event - > type = = SDL_EVENT_KEY_DOWN ) ) ;
2024-06-24 00:26:52 +02:00
io . SetKeyEventNativeData ( key , event - > key . key , event - > key . scancode , event - > key . scancode ) ; // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
2023-02-07 13:26:24 +01:00
return true ;
}
2023-04-21 15:40:14 +02:00
case SDL_EVENT_DISPLAY_ORIENTATION :
2023-11-01 13:53:30 +01:00
case SDL_EVENT_DISPLAY_ADDED :
case SDL_EVENT_DISPLAY_REMOVED :
2023-04-21 15:40:14 +02:00
case SDL_EVENT_DISPLAY_MOVED :
2023-06-01 11:30:26 +02:00
case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED :
2023-04-21 15:40:14 +02:00
{
bd - > WantUpdateMonitors = true ;
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_WINDOW_MOUSE_ENTER :
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2023-02-07 13:49:37 +01:00
bd - > MouseWindowID = event - > window . windowID ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = 0 ;
2023-02-07 13:49:37 +01:00
return true ;
}
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
// FIXME: Unconfirmed whether this is still needed with SDL3.
case SDL_EVENT_WINDOW_MOUSE_LEAVE :
2023-02-07 13:26:24 +01:00
{
2024-08-19 13:57:08 +02:00
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = ImGui : : GetFrameCount ( ) + 1 ;
2023-02-07 13:26:24 +01:00
return true ;
}
2023-02-07 13:49:37 +01:00
case SDL_EVENT_WINDOW_FOCUS_GAINED :
case SDL_EVENT_WINDOW_FOCUS_LOST :
2024-08-19 13:57:08 +02:00
{
if ( ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) = = NULL )
2024-08-02 00:05:51 +02:00
return false ;
2024-08-19 13:57:08 +02:00
io . AddFocusEvent ( event - > type = = SDL_EVENT_WINDOW_FOCUS_GAINED ) ;
2023-02-07 13:49:37 +01:00
return true ;
2024-08-19 13:57:08 +02:00
}
2023-02-07 16:30:58 +01:00
case SDL_EVENT_WINDOW_CLOSE_REQUESTED :
case SDL_EVENT_WINDOW_MOVED :
case SDL_EVENT_WINDOW_RESIZED :
2024-08-19 14:44:35 +02:00
{
2024-08-19 14:46:53 +02:00
ImGuiViewport * viewport = ImGui_ImplSDL3_GetViewportForWindowID ( event - > window . windowID ) ;
if ( viewport = = NULL )
return false ;
if ( event - > type = = SDL_EVENT_WINDOW_CLOSE_REQUESTED )
viewport - > PlatformRequestClose = true ;
if ( event - > type = = SDL_EVENT_WINDOW_MOVED )
viewport - > PlatformRequestMove = true ;
if ( event - > type = = SDL_EVENT_WINDOW_RESIZED )
viewport - > PlatformRequestResize = true ;
2023-02-07 16:30:58 +01:00
return true ;
2024-08-19 14:44:35 +02:00
}
2024-02-14 11:37:18 +01:00
case SDL_EVENT_GAMEPAD_ADDED :
case SDL_EVENT_GAMEPAD_REMOVED :
{
bd - > WantUpdateGamepadsList = true ;
return true ;
}
2023-02-07 13:26:24 +01:00
}
return false ;
}
2023-11-13 16:20:38 +01:00
static void ImGui_ImplSDL3_SetupPlatformHandles ( ImGuiViewport * viewport , SDL_Window * window )
{
2024-08-19 14:07:25 +02:00
viewport - > PlatformHandle = ( void * ) ( intptr_t ) SDL_GetWindowID ( window ) ;
2023-11-13 16:20:38 +01:00
viewport - > PlatformHandleRaw = nullptr ;
2024-07-15 11:17:21 +02:00
# if defined(_WIN32) && !defined(__WINRT__)
2024-07-15 04:34:44 +02:00
viewport - > PlatformHandleRaw = ( HWND ) SDL_GetPointerProperty ( SDL_GetWindowProperties ( window ) , SDL_PROP_WINDOW_WIN32_HWND_POINTER , nullptr ) ;
2023-11-13 16:20:38 +01:00
# elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
2024-07-15 04:34:44 +02:00
viewport - > PlatformHandleRaw = SDL_GetPointerProperty ( SDL_GetWindowProperties ( window ) , SDL_PROP_WINDOW_COCOA_WINDOW_POINTER , nullptr ) ;
2023-11-13 16:20:38 +01:00
# endif
}
2023-02-07 16:30:58 +01:00
static bool ImGui_ImplSDL3_Init ( SDL_Window * window , SDL_Renderer * renderer , void * sdl_gl_context )
2023-02-07 13:26:24 +01:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-05-13 15:07:13 +02:00
IMGUI_CHECKVERSION ( ) ;
2023-02-07 13:26:24 +01:00
IM_ASSERT ( io . BackendPlatformUserData = = nullptr & & " Already initialized a platform backend! " ) ;
2023-11-13 16:20:38 +01:00
IM_UNUSED ( sdl_gl_context ) ; // Unused in this branch
2023-02-07 13:26:24 +01:00
// Check and store if we are on a SDL backend that supports global mouse position
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bool mouse_can_use_global_state = false ;
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char * sdl_backend = SDL_GetCurrentVideoDriver ( ) ;
const char * global_mouse_whitelist [ ] = { " windows " , " cocoa " , " x11 " , " DIVE " , " VMAN " } ;
for ( int n = 0 ; n < IM_ARRAYSIZE ( global_mouse_whitelist ) ; n + + )
if ( strncmp ( sdl_backend , global_mouse_whitelist [ n ] , strlen ( global_mouse_whitelist [ n ] ) ) = = 0 )
mouse_can_use_global_state = true ;
# endif
// Setup backend capabilities flags
ImGui_ImplSDL3_Data * bd = IM_NEW ( ImGui_ImplSDL3_Data ) ( ) ;
io . BackendPlatformUserData = ( void * ) bd ;
io . BackendPlatformName = " imgui_impl_sdl3 " ;
2023-02-07 13:49:37 +01:00
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
2023-02-07 16:30:58 +01:00
if ( mouse_can_use_global_state )
io . BackendFlags | = ImGuiBackendFlags_PlatformHasViewports ; // We can create multi-viewports on the Platform side (optional)
2023-02-07 13:26:24 +01:00
bd - > Window = window ;
2024-08-19 13:57:08 +02:00
bd - > WindowID = SDL_GetWindowID ( window ) ;
2023-02-07 13:26:24 +01:00
bd - > Renderer = renderer ;
2023-02-07 16:30:58 +01:00
// SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
// We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
2023-02-07 13:26:24 +01:00
bd - > MouseCanUseGlobalState = mouse_can_use_global_state ;
2023-02-07 16:30:58 +01:00
# ifndef __APPLE__
bd - > MouseCanReportHoveredViewport = bd - > MouseCanUseGlobalState ;
# else
bd - > MouseCanReportHoveredViewport = false ;
# endif
2023-02-07 13:26:24 +01:00
2024-08-22 16:55:14 +02:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
2024-08-22 17:50:10 +02:00
platform_io . Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText ;
platform_io . Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText ;
2024-08-22 16:55:14 +02:00
platform_io . Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData ;
2023-02-07 13:26:24 +01:00
2024-09-19 14:25:01 +02:00
// Update monitor a first time during init
ImGui_ImplSDL3_UpdateMonitors ( ) ;
2024-02-14 11:37:18 +01:00
// Gamepad handling
bd - > GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst ;
bd - > WantUpdateGamepadsList = true ;
2023-02-07 13:26:24 +01:00
// Load mouse cursors
2024-06-03 18:25:58 +02:00
bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_DEFAULT ) ;
bd - > MouseCursors [ ImGuiMouseCursor_TextInput ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_TEXT ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeAll ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_MOVE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNS ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NS_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeEW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_EW_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNESW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NESW_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNWSE ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NWSE_RESIZE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_Hand ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_POINTER ) ;
bd - > MouseCursors [ ImGuiMouseCursor_NotAllowed ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NOT_ALLOWED ) ;
2023-02-07 13:26:24 +01:00
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2023-11-13 16:20:38 +01:00
ImGui_ImplSDL3_SetupPlatformHandles ( main_viewport , window ) ;
2023-02-07 13:26:24 +01:00
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
2023-04-04 19:43:51 +02:00
// you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
2023-02-07 13:26:24 +01:00
SDL_SetHint ( SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH , " 1 " ) ;
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
SDL_SetHint ( SDL_HINT_MOUSE_AUTO_CAPTURE , " 0 " ) ;
2023-02-10 14:45:42 +01:00
// SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659
SDL_SetHint ( " SDL_BORDERLESS_WINDOWED_STYLE " , " 0 " ) ;
2023-02-07 16:30:58 +01:00
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
// We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
2024-10-08 20:47:24 +02:00
if ( io . BackendFlags & ImGuiBackendFlags_PlatformHasViewports )
ImGui_ImplSDL3_InitMultiViewportSupport ( window , sdl_gl_context ) ;
2023-02-07 16:30:58 +01:00
2023-02-07 13:26:24 +01:00
return true ;
}
2024-06-18 03:09:07 +02:00
// Should technically be a SDL_GLContext but due to typedef it is sane to keep it void* in public interface.
2023-02-07 13:26:24 +01:00
bool ImGui_ImplSDL3_InitForOpenGL ( SDL_Window * window , void * sdl_gl_context )
{
2023-02-07 16:30:58 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , sdl_gl_context ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForVulkan ( SDL_Window * window )
{
2023-02-07 16:30:58 +01:00
if ( ! ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) )
return false ;
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
bd - > UseVulkan = true ;
return true ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForD3D ( SDL_Window * window )
{
# if !defined(_WIN32)
IM_ASSERT ( 0 & & " Unsupported " ) ;
# endif
2023-02-07 16:30:58 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForMetal ( SDL_Window * window )
{
2023-02-07 16:30:58 +01:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
bool ImGui_ImplSDL3_InitForSDLRenderer ( SDL_Window * window , SDL_Renderer * renderer )
{
2023-02-07 16:30:58 +01:00
return ImGui_ImplSDL3_Init ( window , renderer , nullptr ) ;
2023-02-07 13:26:24 +01:00
}
2023-08-21 13:12:50 +02:00
bool ImGui_ImplSDL3_InitForOther ( SDL_Window * window )
2023-08-15 12:48:46 +02:00
{
2023-08-26 11:45:21 +02:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2023-08-15 12:48:46 +02:00
}
2024-02-14 11:37:18 +01:00
static void ImGui_ImplSDL3_CloseGamepads ( ) ;
2023-02-07 13:26:24 +01:00
void ImGui_ImplSDL3_Shutdown ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " No platform backend to shutdown, or already shutdown? " ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-10-08 20:47:24 +02:00
ImGui_ImplSDL3_ShutdownMultiViewportSupport ( ) ;
2023-02-07 16:30:58 +01:00
2023-02-07 13:26:24 +01:00
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
for ( ImGuiMouseCursor cursor_n = 0 ; cursor_n < ImGuiMouseCursor_COUNT ; cursor_n + + )
2023-02-07 13:49:37 +01:00
SDL_DestroyCursor ( bd - > MouseCursors [ cursor_n ] ) ;
2024-02-14 11:37:18 +01:00
ImGui_ImplSDL3_CloseGamepads ( ) ;
2023-02-07 13:26:24 +01:00
io . BackendPlatformName = nullptr ;
io . BackendPlatformUserData = nullptr ;
2023-04-19 16:40:18 +02:00
io . BackendFlags & = ~ ( ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport ) ;
2023-02-07 13:26:24 +01:00
IM_DELETE ( bd ) ;
}
2023-02-07 16:30:58 +01:00
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
2023-02-07 13:26:24 +01:00
static void ImGui_ImplSDL3_UpdateMouseData ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-04-04 19:43:51 +02:00
// We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below)
2023-02-07 13:26:24 +01:00
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
// 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
2024-09-19 16:02:23 +02:00
SDL_CaptureMouse ( bd - > MouseButtonsDown ! = 0 ) ;
2023-02-07 13:26:24 +01:00
SDL_Window * focused_window = SDL_GetKeyboardFocus ( ) ;
2024-08-19 14:46:53 +02:00
const bool is_app_focused = ( focused_window & & ( bd - > Window = = focused_window | | ImGui_ImplSDL3_GetViewportForWindowID ( SDL_GetWindowID ( focused_window ) ) ! = NULL ) ) ;
2023-02-07 13:26:24 +01:00
# else
2023-02-07 16:30:58 +01:00
SDL_Window * focused_window = bd - > Window ;
2023-02-07 13:26:24 +01:00
const bool is_app_focused = ( SDL_GetWindowFlags ( bd - > Window ) & SDL_WINDOW_INPUT_FOCUS ) ! = 0 ; // SDL 2.0.3 and non-windowed systems: single-viewport only
# endif
if ( is_app_focused )
{
2024-10-14 15:28:00 +02:00
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
2023-02-07 13:26:24 +01:00
if ( io . WantSetMousePos )
2023-02-07 16:30:58 +01:00
{
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
SDL_WarpMouseGlobal ( io . MousePos . x , io . MousePos . y ) ;
else
# endif
SDL_WarpMouseInWindow ( bd - > Window , io . MousePos . x , io . MousePos . y ) ;
}
2023-02-07 13:26:24 +01:00
2023-04-04 19:43:51 +02:00
// (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
2023-02-07 13:26:24 +01:00
if ( bd - > MouseCanUseGlobalState & & bd - > MouseButtonsDown = = 0 )
{
2023-02-07 13:49:37 +01:00
// 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)
2023-02-07 16:30:58 +01:00
// 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)
float mouse_x , mouse_y ;
2023-02-07 13:49:37 +01:00
int window_x , window_y ;
2023-02-07 16:30:58 +01:00
SDL_GetGlobalMouseState ( & mouse_x , & mouse_y ) ;
if ( ! ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) )
{
SDL_GetWindowPosition ( focused_window , & window_x , & window_y ) ;
mouse_x - = window_x ;
mouse_y - = window_y ;
}
io . AddMousePosEvent ( ( float ) mouse_x , ( float ) mouse_y ) ;
2023-02-07 13:26:24 +01:00
}
}
2023-02-07 16:30:58 +01:00
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
// 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
// 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
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [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).
if ( io . BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport )
{
ImGuiID mouse_viewport_id = 0 ;
2024-08-19 14:46:53 +02:00
if ( ImGuiViewport * mouse_viewport = ImGui_ImplSDL3_GetViewportForWindowID ( bd - > MouseWindowID ) )
mouse_viewport_id = mouse_viewport - > ID ;
2023-02-07 16:30:58 +01:00
io . AddMouseViewportEvent ( mouse_viewport_id ) ;
}
2023-02-07 13:26:24 +01:00
}
static void ImGui_ImplSDL3_UpdateMouseCursor ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange )
return ;
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGuiMouseCursor imgui_cursor = ImGui : : GetMouseCursor ( ) ;
if ( io . MouseDrawCursor | | imgui_cursor = = ImGuiMouseCursor_None )
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
2023-02-07 13:49:37 +01:00
SDL_HideCursor ( ) ;
2023-02-07 13:26:24 +01:00
}
else
{
// Show OS mouse cursor
SDL_Cursor * expected_cursor = bd - > MouseCursors [ imgui_cursor ] ? bd - > MouseCursors [ imgui_cursor ] : bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] ;
2024-02-13 15:49:49 +01:00
if ( bd - > MouseLastCursor ! = expected_cursor )
2023-02-07 13:26:24 +01:00
{
SDL_SetCursor ( expected_cursor ) ; // SDL function doesn't have an early out (see #6113)
2024-02-13 15:49:49 +01:00
bd - > MouseLastCursor = expected_cursor ;
2023-02-07 13:26:24 +01:00
}
2023-02-07 13:49:37 +01:00
SDL_ShowCursor ( ) ;
2023-02-07 13:26:24 +01:00
}
}
2024-02-14 11:37:18 +01:00
static void ImGui_ImplSDL3_CloseGamepads ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
if ( bd - > GamepadMode ! = ImGui_ImplSDL3_GamepadMode_Manual )
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
SDL_CloseGamepad ( gamepad ) ;
bd - > Gamepads . resize ( 0 ) ;
}
void ImGui_ImplSDL3_SetGamepadMode ( ImGui_ImplSDL3_GamepadMode mode , SDL_Gamepad * * manual_gamepads_array , int manual_gamepads_count )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGui_ImplSDL3_CloseGamepads ( ) ;
if ( mode = = ImGui_ImplSDL3_GamepadMode_Manual )
{
IM_ASSERT ( manual_gamepads_array ! = nullptr & & manual_gamepads_count > 0 ) ;
for ( int n = 0 ; n < manual_gamepads_count ; n + + )
bd - > Gamepads . push_back ( manual_gamepads_array [ n ] ) ;
}
else
{
IM_ASSERT ( manual_gamepads_array = = nullptr & & manual_gamepads_count < = 0 ) ;
bd - > WantUpdateGamepadsList = true ;
}
bd - > GamepadMode = mode ;
}
static void ImGui_ImplSDL3_UpdateGamepadButton ( ImGui_ImplSDL3_Data * bd , ImGuiIO & io , ImGuiKey key , SDL_GamepadButton button_no )
{
bool merged_value = false ;
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
merged_value | = SDL_GetGamepadButton ( gamepad , button_no ) ! = 0 ;
io . AddKeyEvent ( key , merged_value ) ;
}
static inline float Saturate ( float v ) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v ; }
static void ImGui_ImplSDL3_UpdateGamepadAnalog ( ImGui_ImplSDL3_Data * bd , ImGuiIO & io , ImGuiKey key , SDL_GamepadAxis axis_no , float v0 , float v1 )
{
float merged_value = 0.0f ;
for ( SDL_Gamepad * gamepad : bd - > Gamepads )
{
float vn = Saturate ( ( float ) ( SDL_GetGamepadAxis ( gamepad , axis_no ) - v0 ) / ( float ) ( v1 - v0 ) ) ;
if ( merged_value < vn )
merged_value = vn ;
}
io . AddKeyAnalogEvent ( key , merged_value > 0.1f , merged_value ) ;
}
2023-02-07 13:26:24 +01:00
static void ImGui_ImplSDL3_UpdateGamepads ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-02-14 11:37:18 +01:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// Update list of gamepads to use
if ( bd - > WantUpdateGamepadsList & & bd - > GamepadMode ! = ImGui_ImplSDL3_GamepadMode_Manual )
{
ImGui_ImplSDL3_CloseGamepads ( ) ;
int sdl_gamepads_count = 0 ;
2024-08-25 19:07:10 +02:00
SDL_JoystickID * sdl_gamepads = SDL_GetGamepads ( & sdl_gamepads_count ) ;
2024-02-14 11:37:18 +01:00
for ( int n = 0 ; n < sdl_gamepads_count ; n + + )
if ( SDL_Gamepad * gamepad = SDL_OpenGamepad ( sdl_gamepads [ n ] ) )
{
bd - > Gamepads . push_back ( gamepad ) ;
if ( bd - > GamepadMode = = ImGui_ImplSDL3_GamepadMode_AutoFirst )
break ;
}
bd - > WantUpdateGamepadsList = false ;
2024-08-25 19:07:10 +02:00
SDL_free ( sdl_gamepads ) ;
2024-02-14 11:37:18 +01:00
}
2023-02-07 13:26:24 +01:00
2024-02-14 11:37:18 +01:00
// FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
if ( ( io . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) = = 0 )
return ;
2023-02-07 13:26:24 +01:00
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
2024-02-14 11:37:18 +01:00
if ( bd - > Gamepads . Size = = 0 )
2023-02-07 13:26:24 +01:00
return ;
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
// Update gamepad inputs
2024-02-14 11:37:18 +01:00
const int thumb_dead_zone = 8000 ; // SDL_gamepad.h suggests using this value.
2024-05-07 16:53:03 +02:00
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadStart , SDL_GAMEPAD_BUTTON_START ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadBack , SDL_GAMEPAD_BUTTON_BACK ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceLeft , SDL_GAMEPAD_BUTTON_WEST ) ; // Xbox X, PS Square
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceRight , SDL_GAMEPAD_BUTTON_EAST ) ; // Xbox B, PS Circle
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceUp , SDL_GAMEPAD_BUTTON_NORTH ) ; // Xbox Y, PS Triangle
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadFaceDown , SDL_GAMEPAD_BUTTON_SOUTH ) ; // Xbox A, PS Cross
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadLeft , SDL_GAMEPAD_BUTTON_DPAD_LEFT ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadRight , SDL_GAMEPAD_BUTTON_DPAD_RIGHT ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadUp , SDL_GAMEPAD_BUTTON_DPAD_UP ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadDpadDown , SDL_GAMEPAD_BUTTON_DPAD_DOWN ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadL1 , SDL_GAMEPAD_BUTTON_LEFT_SHOULDER ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadR1 , SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadL2 , SDL_GAMEPAD_AXIS_LEFT_TRIGGER , 0.0f , 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadR2 , SDL_GAMEPAD_AXIS_RIGHT_TRIGGER , 0.0f , 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadL3 , SDL_GAMEPAD_BUTTON_LEFT_STICK ) ;
ImGui_ImplSDL3_UpdateGamepadButton ( bd , io , ImGuiKey_GamepadR3 , SDL_GAMEPAD_BUTTON_RIGHT_STICK ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickLeft , SDL_GAMEPAD_AXIS_LEFTX , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickRight , SDL_GAMEPAD_AXIS_LEFTX , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickUp , SDL_GAMEPAD_AXIS_LEFTY , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadLStickDown , SDL_GAMEPAD_AXIS_LEFTY , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickLeft , SDL_GAMEPAD_AXIS_RIGHTX , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickRight , SDL_GAMEPAD_AXIS_RIGHTX , + thumb_dead_zone , + 32767 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickUp , SDL_GAMEPAD_AXIS_RIGHTY , - thumb_dead_zone , - 32768 ) ;
ImGui_ImplSDL3_UpdateGamepadAnalog ( bd , io , ImGuiKey_GamepadRStickDown , SDL_GAMEPAD_AXIS_RIGHTY , + thumb_dead_zone , + 32767 ) ;
2023-02-07 13:26:24 +01:00
}
2023-02-07 16:30:58 +01:00
static void ImGui_ImplSDL3_UpdateMonitors ( )
{
2023-04-21 15:40:14 +02:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2023-02-07 16:30:58 +01:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Monitors . resize ( 0 ) ;
2023-04-21 15:40:14 +02:00
bd - > WantUpdateMonitors = false ;
2023-02-07 16:30:58 +01:00
int display_count ;
2024-09-03 19:13:45 +02:00
SDL_DisplayID * displays = SDL_GetDisplays ( & display_count ) ;
2023-02-07 16:30:58 +01:00
for ( int n = 0 ; n < display_count ; n + + )
{
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
SDL_DisplayID display_id = displays [ n ] ;
ImGuiPlatformMonitor monitor ;
SDL_Rect r ;
SDL_GetDisplayBounds ( display_id , & r ) ;
monitor . MainPos = monitor . WorkPos = ImVec2 ( ( float ) r . x , ( float ) r . y ) ;
monitor . MainSize = monitor . WorkSize = ImVec2 ( ( float ) r . w , ( float ) r . h ) ;
SDL_GetDisplayUsableBounds ( display_id , & r ) ;
monitor . WorkPos = ImVec2 ( ( float ) r . x , ( float ) r . y ) ;
monitor . WorkSize = ImVec2 ( ( float ) r . w , ( float ) r . h ) ;
// FIXME-VIEWPORT: On MacOS SDL reports actual monitor DPI scale, ignoring OS configuration. We may want to set
// DpiScale to cocoa_window.backingScaleFactor here.
2023-06-01 11:30:26 +02:00
monitor . DpiScale = SDL_GetDisplayContentScale ( display_id ) ;
2023-04-21 15:10:44 +02:00
monitor . PlatformHandle = ( void * ) ( intptr_t ) n ;
2024-08-19 12:18:47 +02:00
if ( monitor . DpiScale < = 0.0f )
continue ; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
2023-02-07 16:30:58 +01:00
platform_io . Monitors . push_back ( monitor ) ;
}
2024-09-03 19:13:45 +02:00
SDL_free ( displays ) ;
2023-02-07 16:30:58 +01:00
}
2023-02-07 13:26:24 +01:00
void ImGui_ImplSDL3_NewFrame ( )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2024-05-07 16:53:03 +02:00
IM_ASSERT ( bd ! = nullptr & & " Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()? " ) ;
2023-02-07 13:26:24 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
// Setup display size (every frame to accommodate for window resizing)
int w , h ;
int display_w , display_h ;
SDL_GetWindowSize ( bd - > Window , & w , & h ) ;
if ( SDL_GetWindowFlags ( bd - > Window ) & SDL_WINDOW_MINIMIZED )
w = h = 0 ;
2023-02-07 13:49:37 +01:00
SDL_GetWindowSizeInPixels ( bd - > Window , & display_w , & display_h ) ;
2023-02-07 13:26:24 +01:00
io . DisplaySize = ImVec2 ( ( float ) w , ( float ) h ) ;
if ( w > 0 & & h > 0 )
io . DisplayFramebufferScale = ImVec2 ( ( float ) display_w / w , ( float ) display_h / h ) ;
2023-04-21 15:40:14 +02:00
// Update monitors
if ( bd - > WantUpdateMonitors )
ImGui_ImplSDL3_UpdateMonitors ( ) ;
2023-02-07 13:26:24 +01:00
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
2023-02-23 13:06:07 +01:00
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
2023-02-07 13:26:24 +01:00
static Uint64 frequency = SDL_GetPerformanceFrequency ( ) ;
Uint64 current_time = SDL_GetPerformanceCounter ( ) ;
2023-02-23 13:06:07 +01:00
if ( current_time < = bd - > Time )
current_time = bd - > Time + 1 ;
2023-02-07 13:26:24 +01:00
io . DeltaTime = bd - > Time > 0 ? ( float ) ( ( double ) ( current_time - bd - > Time ) / frequency ) : ( float ) ( 1.0f / 60.0f ) ;
bd - > Time = current_time ;
2024-02-13 15:49:49 +01:00
if ( bd - > MousePendingLeaveFrame & & bd - > MousePendingLeaveFrame > = ImGui : : GetFrameCount ( ) & & bd - > MouseButtonsDown = = 0 )
2023-02-07 13:26:24 +01:00
{
bd - > MouseWindowID = 0 ;
2024-02-13 15:49:49 +01:00
bd - > MousePendingLeaveFrame = 0 ;
2023-02-07 13:26:24 +01:00
io . AddMousePosEvent ( - FLT_MAX , - FLT_MAX ) ;
}
2023-02-07 16:30:58 +01:00
// Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
2024-06-21 02:45:47 +02:00
// Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
2023-02-07 16:30:58 +01:00
if ( bd - > MouseCanReportHoveredViewport & & ImGui : : GetDragDropPayload ( ) = = nullptr )
io . BackendFlags | = ImGuiBackendFlags_HasMouseHoveredViewport ;
else
io . BackendFlags & = ~ ImGuiBackendFlags_HasMouseHoveredViewport ;
2023-02-07 13:26:24 +01:00
ImGui_ImplSDL3_UpdateMouseData ( ) ;
ImGui_ImplSDL3_UpdateMouseCursor ( ) ;
// Update game controllers (if enabled and available)
ImGui_ImplSDL3_UpdateGamepads ( ) ;
}
2023-02-07 16:30:58 +01:00
//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
// 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..
//--------------------------------------------------------------------------------------------------------
2023-04-11 16:19:59 +02:00
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
2023-02-07 16:30:58 +01:00
struct ImGui_ImplSDL3_ViewportData
{
SDL_Window * Window ;
2024-09-11 11:41:37 +02:00
SDL_Window * ParentWindow ;
2023-02-07 16:30:58 +01:00
Uint32 WindowID ;
bool WindowOwned ;
SDL_GLContext GLContext ;
2024-09-11 11:41:37 +02:00
ImGui_ImplSDL3_ViewportData ( ) { Window = ParentWindow = nullptr ; WindowID = 0 ; WindowOwned = false ; GLContext = nullptr ; }
2023-02-07 16:30:58 +01:00
~ ImGui_ImplSDL3_ViewportData ( ) { IM_ASSERT ( Window = = nullptr & & GLContext = = nullptr ) ; }
} ;
2024-09-11 11:41:37 +02:00
static SDL_Window * ImGui_ImplSDL3_GetSDLWindowFromViewportID ( ImGuiID viewport_id )
{
if ( viewport_id ! = 0 )
if ( ImGuiViewport * viewport = ImGui : : FindViewportByID ( viewport_id ) )
{
SDL_WindowID window_id = ( SDL_WindowID ) ( intptr_t ) viewport - > PlatformHandle ;
return SDL_GetWindowFromID ( window_id ) ;
}
return nullptr ;
}
2023-02-07 16:30:58 +01:00
static void ImGui_ImplSDL3_CreateWindow ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGui_ImplSDL3_ViewportData * vd = IM_NEW ( ImGui_ImplSDL3_ViewportData ) ( ) ;
viewport - > PlatformUserData = vd ;
2024-09-11 11:41:37 +02:00
vd - > ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewportID ( viewport - > ParentViewportId ) ;
2023-02-07 16:30:58 +01:00
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
ImGui_ImplSDL3_ViewportData * main_viewport_data = ( ImGui_ImplSDL3_ViewportData * ) main_viewport - > PlatformUserData ;
// Share GL resources with main context
bool use_opengl = ( main_viewport_data - > GLContext ! = nullptr ) ;
SDL_GLContext backup_context = nullptr ;
if ( use_opengl )
{
backup_context = SDL_GL_GetCurrentContext ( ) ;
SDL_GL_SetAttribute ( SDL_GL_SHARE_WITH_CURRENT_CONTEXT , 1 ) ;
SDL_GL_MakeCurrent ( main_viewport_data - > Window , main_viewport_data - > GLContext ) ;
}
2024-10-23 23:18:06 +02:00
SDL_WindowFlags sdl_flags = 0 ;
2023-02-07 16:30:58 +01:00
sdl_flags | = use_opengl ? SDL_WINDOW_OPENGL : ( bd - > UseVulkan ? SDL_WINDOW_VULKAN : 0 ) ;
2024-10-23 23:18:06 +02:00
sdl_flags | = SDL_GetWindowFlags ( bd - > Window ) & SDL_WINDOW_HIGH_PIXEL_DENSITY ;
2023-02-07 16:30:58 +01:00
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoDecoration ) ? SDL_WINDOW_BORDERLESS : 0 ;
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoDecoration ) ? 0 : SDL_WINDOW_RESIZABLE ;
2023-07-05 11:01:56 +02:00
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoTaskBarIcon ) ? SDL_WINDOW_UTILITY : 0 ;
2023-02-07 16:30:58 +01:00
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_TopMost ) ? SDL_WINDOW_ALWAYS_ON_TOP : 0 ;
2023-03-18 23:20:50 +01:00
vd - > Window = SDL_CreateWindow ( " No Title Yet " , ( int ) viewport - > Size . x , ( int ) viewport - > Size . y , sdl_flags ) ;
2024-09-11 11:41:37 +02:00
SDL_SetWindowParent ( vd - > Window , vd - > ParentWindow ) ;
2023-03-18 23:20:50 +01:00
SDL_SetWindowPosition ( vd - > Window , ( int ) viewport - > Pos . x , ( int ) viewport - > Pos . y ) ;
2023-02-07 16:30:58 +01:00
vd - > WindowOwned = true ;
if ( use_opengl )
{
vd - > GLContext = SDL_GL_CreateContext ( vd - > Window ) ;
SDL_GL_SetSwapInterval ( 0 ) ;
}
if ( use_opengl & & backup_context )
SDL_GL_MakeCurrent ( vd - > Window , backup_context ) ;
2023-11-13 16:20:38 +01:00
ImGui_ImplSDL3_SetupPlatformHandles ( viewport , vd - > Window ) ;
2023-02-07 16:30:58 +01:00
}
static void ImGui_ImplSDL3_DestroyWindow ( ImGuiViewport * viewport )
{
if ( ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData )
{
if ( vd - > GLContext & & vd - > WindowOwned )
2024-07-15 11:21:18 +02:00
SDL_GL_DestroyContext ( vd - > GLContext ) ;
2023-02-07 16:30:58 +01:00
if ( vd - > Window & & vd - > WindowOwned )
SDL_DestroyWindow ( vd - > Window ) ;
vd - > GLContext = nullptr ;
vd - > Window = nullptr ;
IM_DELETE ( vd ) ;
}
viewport - > PlatformUserData = viewport - > PlatformHandle = nullptr ;
}
static void ImGui_ImplSDL3_ShowWindow ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2024-09-23 14:03:36 +02:00
# if defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES))
2023-02-07 16:30:58 +01:00
HWND hwnd = ( HWND ) viewport - > PlatformHandleRaw ;
2024-09-15 19:57:37 +02:00
// SDL hack: Show icon in task bar (#7989)
// Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows.
if ( ! ( viewport - > Flags & ImGuiViewportFlags_NoTaskBarIcon ) )
2023-02-07 16:30:58 +01:00
{
LONG ex_style = : : GetWindowLong ( hwnd , GWL_EXSTYLE ) ;
2024-09-15 19:57:37 +02:00
ex_style | = WS_EX_APPWINDOW ;
ex_style & = ~ WS_EX_TOOLWINDOW ;
: : ShowWindow ( hwnd , SW_HIDE ) ;
2023-02-07 16:30:58 +01:00
: : SetWindowLong ( hwnd , GWL_EXSTYLE , ex_style ) ;
}
# endif
2024-08-17 13:13:10 +02:00
SDL_SetHint ( SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN , ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnAppearing ) ? " 0 " : " 1 " ) ;
2023-02-07 16:30:58 +01:00
SDL_ShowWindow ( vd - > Window ) ;
}
2024-09-11 11:41:37 +02:00
static void ImGui_ImplSDL3_UpdateWindow ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
// Update SDL3 parent if it changed _after_ creation.
// This is for advanced apps that are manipulating ParentViewportID manually.
SDL_Window * new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewportID ( viewport - > ParentViewportId ) ;
if ( new_parent ! = vd - > ParentWindow )
{
vd - > ParentWindow = new_parent ;
SDL_SetWindowParent ( vd - > Window , vd - > ParentWindow ) ;
}
}
2023-02-07 16:30:58 +01:00
static ImVec2 ImGui_ImplSDL3_GetWindowPos ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
int x = 0 , y = 0 ;
SDL_GetWindowPosition ( vd - > Window , & x , & y ) ;
return ImVec2 ( ( float ) x , ( float ) y ) ;
}
static void ImGui_ImplSDL3_SetWindowPos ( ImGuiViewport * viewport , ImVec2 pos )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
SDL_SetWindowPosition ( vd - > Window , ( int ) pos . x , ( int ) pos . y ) ;
}
static ImVec2 ImGui_ImplSDL3_GetWindowSize ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
int w = 0 , h = 0 ;
SDL_GetWindowSize ( vd - > Window , & w , & h ) ;
return ImVec2 ( ( float ) w , ( float ) h ) ;
}
static void ImGui_ImplSDL3_SetWindowSize ( ImGuiViewport * viewport , ImVec2 size )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
SDL_SetWindowSize ( vd - > Window , ( int ) size . x , ( int ) size . y ) ;
}
static void ImGui_ImplSDL3_SetWindowTitle ( ImGuiViewport * viewport , const char * title )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
SDL_SetWindowTitle ( vd - > Window , title ) ;
}
static void ImGui_ImplSDL3_SetWindowAlpha ( ImGuiViewport * viewport , float alpha )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
SDL_SetWindowOpacity ( vd - > Window , alpha ) ;
}
static void ImGui_ImplSDL3_SetWindowFocus ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
SDL_RaiseWindow ( vd - > Window ) ;
}
static bool ImGui_ImplSDL3_GetWindowFocus ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
return ( SDL_GetWindowFlags ( vd - > Window ) & SDL_WINDOW_INPUT_FOCUS ) ! = 0 ;
}
static bool ImGui_ImplSDL3_GetWindowMinimized ( ImGuiViewport * viewport )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
return ( SDL_GetWindowFlags ( vd - > Window ) & SDL_WINDOW_MINIMIZED ) ! = 0 ;
}
static void ImGui_ImplSDL3_RenderWindow ( ImGuiViewport * viewport , void * )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
if ( vd - > GLContext )
SDL_GL_MakeCurrent ( vd - > Window , vd - > GLContext ) ;
}
static void ImGui_ImplSDL3_SwapBuffers ( ImGuiViewport * viewport , void * )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
if ( vd - > GLContext )
{
SDL_GL_MakeCurrent ( vd - > Window , vd - > GLContext ) ;
SDL_GL_SwapWindow ( vd - > Window ) ;
}
}
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
# include <SDL3/SDL_vulkan.h>
static int ImGui_ImplSDL3_CreateVkSurface ( ImGuiViewport * viewport , ImU64 vk_instance , const void * vk_allocator , ImU64 * out_vk_surface )
{
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
( void ) vk_allocator ;
2024-10-03 11:56:14 +02:00
bool ret = SDL_Vulkan_CreateSurface ( vd - > Window , ( VkInstance ) vk_instance , ( VkAllocationCallbacks * ) vk_allocator , ( VkSurfaceKHR * ) out_vk_surface ) ;
2023-02-07 16:30:58 +01:00
return ret ? 0 : 1 ; // ret ? VK_SUCCESS : VK_NOT_READY
}
2024-10-08 20:47:24 +02:00
static void ImGui_ImplSDL3_InitMultiViewportSupport ( SDL_Window * window , void * sdl_gl_context )
2023-02-07 16:30:58 +01:00
{
// Register platform interface (will be coupled with a renderer interface)
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow ;
platform_io . Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow ;
platform_io . Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow ;
2024-09-11 11:41:37 +02:00
platform_io . Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow ;
2023-02-07 16:30:58 +01:00
platform_io . Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos ;
platform_io . Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos ;
platform_io . Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize ;
platform_io . Platform_GetWindowSize = ImGui_ImplSDL3_GetWindowSize ;
platform_io . Platform_SetWindowFocus = ImGui_ImplSDL3_SetWindowFocus ;
platform_io . Platform_GetWindowFocus = ImGui_ImplSDL3_GetWindowFocus ;
platform_io . Platform_GetWindowMinimized = ImGui_ImplSDL3_GetWindowMinimized ;
platform_io . Platform_SetWindowTitle = ImGui_ImplSDL3_SetWindowTitle ;
platform_io . Platform_RenderWindow = ImGui_ImplSDL3_RenderWindow ;
platform_io . Platform_SwapBuffers = ImGui_ImplSDL3_SwapBuffers ;
platform_io . Platform_SetWindowAlpha = ImGui_ImplSDL3_SetWindowAlpha ;
platform_io . Platform_CreateVkSurface = ImGui_ImplSDL3_CreateVkSurface ;
// Register main window handle (which is owned by the main application, not by us)
// 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.
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
ImGui_ImplSDL3_ViewportData * vd = IM_NEW ( ImGui_ImplSDL3_ViewportData ) ( ) ;
vd - > Window = window ;
vd - > WindowID = SDL_GetWindowID ( window ) ;
vd - > WindowOwned = false ;
2024-06-18 03:09:07 +02:00
vd - > GLContext = ( SDL_GLContext ) sdl_gl_context ;
2023-02-07 16:30:58 +01:00
main_viewport - > PlatformUserData = vd ;
2024-08-19 14:46:53 +02:00
main_viewport - > PlatformHandle = ( void * ) ( intptr_t ) vd - > WindowID ;
2023-02-07 16:30:58 +01:00
}
2024-10-08 20:47:24 +02:00
static void ImGui_ImplSDL3_ShutdownMultiViewportSupport ( )
2023-02-07 16:30:58 +01:00
{
ImGui : : DestroyPlatformWindows ( ) ;
}
2023-03-29 18:41:41 +02:00
2023-07-13 11:27:52 +02:00
//-----------------------------------------------------------------------------
2023-03-23 18:17:45 +01:00
# if defined(__clang__)
# pragma clang diagnostic pop
# endif
2023-07-13 11:27:52 +02:00
# endif // #ifndef IMGUI_DISABLE