2023-06-08 05:29:16 +00:00
// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*)
2022-02-08 07:04:23 +00:00
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
2023-06-08 05:29:16 +00:00
// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (IMPORTANT: SDL 3.0.0 is NOT YET RELEASED. IT IS POSSIBLE THAT ITS SPECS/API WILL CHANGE BEFORE RELEASE)
2022-02-08 07:04:23 +00:00
// Implemented features:
// [X] Platform: Clipboard support.
2023-06-08 05:29:16 +00:00
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
2022-02-08 07:04:23 +00: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-06-08 05:29:16 +00: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.
2022-02-08 07:04:23 +00:00
// Missing features:
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
2023-06-08 05:29:16 +00:00
// [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
2022-02-08 07:04:23 +00: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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
2023-06-08 05:29:16 +00:00
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2023-05-04: Fixed build on Emscripten/iOS/Android. (#6391)
// 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: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
// 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.
2022-02-08 07:04:23 +00:00
# include "imgui.h"
2023-06-08 05:29:16 +00:00
# include "imgui_impl_sdl3.h"
// 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
2022-02-08 07:04:23 +00:00
// SDL
2023-06-08 05:29:16 +00:00
# include <SDL3/SDL.h>
# include <SDL3/SDL_syswm.h>
2022-02-08 07:04:23 +00:00
# if defined(__APPLE__)
# include <TargetConditionals.h>
# endif
2023-06-08 05:29:16 +00:00
# if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
2022-02-08 07:04:23 +00:00
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
# else
# define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
# endif
// SDL Data
2023-06-08 05:29:16 +00:00
struct ImGui_ImplSDL3_Data
2022-02-08 07:04:23 +00:00
{
SDL_Window * Window ;
SDL_Renderer * Renderer ;
Uint64 Time ;
Uint32 MouseWindowID ;
int MouseButtonsDown ;
SDL_Cursor * MouseCursors [ ImGuiMouseCursor_COUNT ] ;
2023-06-08 05:29:16 +00:00
SDL_Cursor * LastMouseCursor ;
2022-05-18 19:31:29 +00:00
int PendingMouseLeaveFrame ;
2022-02-08 07:04:23 +00:00
char * ClipboardTextData ;
bool MouseCanUseGlobalState ;
2023-06-08 05:29:16 +00:00
bool MouseCanReportHoveredViewport ; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
2022-02-08 07:04:23 +00:00
bool UseVulkan ;
2023-06-08 05:29:16 +00:00
bool WantUpdateMonitors ;
2022-02-08 07:04:23 +00:00
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data ( ) { memset ( ( void * ) this , 0 , sizeof ( * this ) ) ; }
2022-02-08 07:04:23 +00:00
} ;
// 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.
2023-06-08 05:29:16 +00:00
static ImGui_ImplSDL3_Data * ImGui_ImplSDL3_GetBackendData ( )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplSDL3_Data * ) ImGui : : GetIO ( ) . BackendPlatformUserData : nullptr ;
2022-02-08 07:04:23 +00:00
}
// Forward Declarations
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateMonitors ( ) ;
static void ImGui_ImplSDL3_InitPlatformInterface ( SDL_Window * window , void * sdl_gl_context ) ;
static void ImGui_ImplSDL3_ShutdownPlatformInterface ( ) ;
2022-02-08 07:04:23 +00:00
// Functions
2023-06-08 05:29:16 +00:00
static const char * ImGui_ImplSDL3_GetClipboardText ( void * )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
bd - > ClipboardTextData = SDL_GetClipboardText ( ) ;
return bd - > ClipboardTextData ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetClipboardText ( void * , const char * text )
2022-02-08 07:04:23 +00:00
{
SDL_SetClipboardText ( text ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetPlatformImeData ( ImGuiViewport * viewport , ImGuiPlatformImeData * data )
{
if ( data - > WantVisible )
{
SDL_Rect r ;
r . x = ( int ) ( data - > InputPos . x - viewport - > Pos . x ) ;
r . y = ( int ) ( data - > InputPos . y - viewport - > Pos . y + data - > InputLineHeight ) ;
r . w = 1 ;
r . h = ( int ) data - > InputLineHeight ;
SDL_SetTextInputRect ( & r ) ;
}
}
static ImGuiKey ImGui_ImplSDL3_KeycodeToImGuiKey ( int keycode )
2022-02-08 07:04:23 +00: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 ;
case SDLK_QUOTE : return ImGuiKey_Apostrophe ;
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 ;
case SDLK_BACKQUOTE : return ImGuiKey_GraveAccent ;
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_KP_0 : return ImGuiKey_Keypad0 ;
case SDLK_KP_1 : return ImGuiKey_Keypad1 ;
case SDLK_KP_2 : return ImGuiKey_Keypad2 ;
case SDLK_KP_3 : return ImGuiKey_Keypad3 ;
case SDLK_KP_4 : return ImGuiKey_Keypad4 ;
case SDLK_KP_5 : return ImGuiKey_Keypad5 ;
case SDLK_KP_6 : return ImGuiKey_Keypad6 ;
case SDLK_KP_7 : return ImGuiKey_Keypad7 ;
case SDLK_KP_8 : return ImGuiKey_Keypad8 ;
case SDLK_KP_9 : return ImGuiKey_Keypad9 ;
case SDLK_KP_PERIOD : return ImGuiKey_KeypadDecimal ;
case SDLK_KP_DIVIDE : return ImGuiKey_KeypadDivide ;
case SDLK_KP_MULTIPLY : return ImGuiKey_KeypadMultiply ;
case SDLK_KP_MINUS : return ImGuiKey_KeypadSubtract ;
case SDLK_KP_PLUS : return ImGuiKey_KeypadAdd ;
case SDLK_KP_ENTER : return ImGuiKey_KeypadEnter ;
case SDLK_KP_EQUALS : return ImGuiKey_KeypadEqual ;
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 ;
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 ;
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 ;
}
return ImGuiKey_None ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateKeyModifiers ( SDL_Keymod sdl_key_mods )
2022-02-08 07:04:23 +00:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00: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 ) ;
2022-02-08 07:04:23 +00:00
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
2022-05-18 19:31:29 +00:00
// - 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.
2022-02-08 07:04:23 +00:00
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_ProcessEvent ( const SDL_Event * event )
2022-02-08 07:04:23 +00:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
switch ( event - > type )
{
2023-06-08 05:29:16 +00:00
case SDL_EVENT_MOUSE_MOTION :
2022-02-08 07:04:23 +00:00
{
ImVec2 mouse_pos ( ( float ) event - > motion . x , ( float ) event - > motion . y ) ;
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-06-08 05:29:16 +00:00
io . AddMouseSourceEvent ( event - > motion . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2022-02-08 07:04:23 +00:00
io . AddMousePosEvent ( mouse_pos . x , mouse_pos . y ) ;
return true ;
}
2023-06-08 05:29:16 +00:00
case SDL_EVENT_MOUSE_WHEEL :
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00: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);
float wheel_x = - event - > wheel . x ;
float wheel_y = event - > wheel . y ;
# ifdef __EMSCRIPTEN__
wheel_x / = 100.0f ;
# endif
io . AddMouseSourceEvent ( event - > wheel . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
2022-02-08 07:04:23 +00:00
io . AddMouseWheelEvent ( wheel_x , wheel_y ) ;
return true ;
}
2023-06-08 05:29:16 +00:00
case SDL_EVENT_MOUSE_BUTTON_DOWN :
case SDL_EVENT_MOUSE_BUTTON_UP :
2022-02-08 07:04:23 +00: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 ; }
2022-05-18 19:31:29 +00:00
if ( event - > button . button = = SDL_BUTTON_X1 ) { mouse_button = 3 ; }
if ( event - > button . button = = SDL_BUTTON_X2 ) { mouse_button = 4 ; }
2022-02-08 07:04:23 +00:00
if ( mouse_button = = - 1 )
break ;
2023-06-08 05:29:16 +00:00
io . AddMouseSourceEvent ( event - > button . which = = SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse ) ;
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 ) ) ;
2022-02-08 07:04:23 +00:00
return true ;
}
2023-06-08 05:29:16 +00:00
case SDL_EVENT_TEXT_INPUT :
2022-02-08 07:04:23 +00:00
{
io . AddInputCharactersUTF8 ( event - > text . text ) ;
return true ;
}
2023-06-08 05:29:16 +00:00
case SDL_EVENT_KEY_DOWN :
case SDL_EVENT_KEY_UP :
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_UpdateKeyModifiers ( ( SDL_Keymod ) event - > key . keysym . mod ) ;
ImGuiKey key = ImGui_ImplSDL3_KeycodeToImGuiKey ( event - > key . keysym . sym ) ;
io . AddKeyEvent ( key , ( event - > type = = SDL_EVENT_KEY_DOWN ) ) ;
2022-02-08 07:04:23 +00:00
io . SetKeyEventNativeData ( key , event - > key . keysym . sym , event - > key . keysym . scancode , event - > key . keysym . scancode ) ; // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
return true ;
}
2023-06-08 05:29:16 +00:00
case SDL_EVENT_DISPLAY_ORIENTATION :
case SDL_EVENT_DISPLAY_CONNECTED :
case SDL_EVENT_DISPLAY_DISCONNECTED :
case SDL_EVENT_DISPLAY_MOVED :
case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED :
{
bd - > WantUpdateMonitors = true ;
return true ;
}
case SDL_EVENT_WINDOW_MOUSE_ENTER :
{
bd - > MouseWindowID = event - > window . windowID ;
bd - > PendingMouseLeaveFrame = 0 ;
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 :
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
bd - > PendingMouseLeaveFrame = ImGui : : GetFrameCount ( ) + 1 ;
return true ;
}
case SDL_EVENT_WINDOW_FOCUS_GAINED :
io . AddFocusEvent ( true ) ;
return true ;
case SDL_EVENT_WINDOW_FOCUS_LOST :
io . AddFocusEvent ( false ) ;
return true ;
case SDL_EVENT_WINDOW_CLOSE_REQUESTED :
case SDL_EVENT_WINDOW_MOVED :
case SDL_EVENT_WINDOW_RESIZED :
if ( ImGuiViewport * viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) SDL_GetWindowFromID ( event - > window . windowID ) ) )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
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 ;
return true ;
2022-02-08 07:04:23 +00:00
}
return true ;
}
return false ;
}
2023-06-08 05:29:16 +00:00
static bool ImGui_ImplSDL3_Init ( SDL_Window * window , SDL_Renderer * renderer , void * sdl_gl_context )
2022-02-08 07:04:23 +00:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00:00
IM_ASSERT ( io . BackendPlatformUserData = = nullptr & & " Already initialized a platform backend! " ) ;
2022-02-08 07:04:23 +00: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
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = IM_NEW ( ImGui_ImplSDL3_Data ) ( ) ;
2022-02-08 07:04:23 +00:00
io . BackendPlatformUserData = ( void * ) bd ;
2023-06-08 05:29:16 +00:00
io . BackendPlatformName = " imgui_impl_sdl3 " ;
2022-02-08 07:04:23 +00:00
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
if ( mouse_can_use_global_state )
io . BackendFlags | = ImGuiBackendFlags_PlatformHasViewports ; // We can create multi-viewports on the Platform side (optional)
bd - > Window = window ;
bd - > Renderer = renderer ;
2023-06-08 05:29:16 +00: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.
2022-02-08 07:04:23 +00:00
bd - > MouseCanUseGlobalState = mouse_can_use_global_state ;
2023-06-08 05:29:16 +00:00
# ifndef __APPLE__
bd - > MouseCanReportHoveredViewport = bd - > MouseCanUseGlobalState ;
# else
bd - > MouseCanReportHoveredViewport = false ;
# endif
bd - > WantUpdateMonitors = true ;
2022-02-08 07:04:23 +00:00
2023-06-08 05:29:16 +00:00
io . SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText ;
io . GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText ;
io . ClipboardUserData = nullptr ;
io . SetPlatformImeDataFn = ImGui_ImplSDL3_SetPlatformImeData ;
2022-02-08 07:04:23 +00:00
// Load mouse cursors
bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_ARROW ) ;
bd - > MouseCursors [ ImGuiMouseCursor_TextInput ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_IBEAM ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeAll ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_SIZEALL ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNS ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_SIZENS ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeEW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_SIZEWE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNESW ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_SIZENESW ) ;
bd - > MouseCursors [ ImGuiMouseCursor_ResizeNWSE ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_SIZENWSE ) ;
bd - > MouseCursors [ ImGuiMouseCursor_Hand ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_HAND ) ;
bd - > MouseCursors [ ImGuiMouseCursor_NotAllowed ] = SDL_CreateSystemCursor ( SDL_SYSTEM_CURSOR_NO ) ;
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
main_viewport - > PlatformHandle = ( void * ) window ;
2023-06-08 05:29:16 +00:00
main_viewport - > PlatformHandleRaw = nullptr ;
2022-02-08 07:04:23 +00:00
SDL_SysWMinfo info ;
2023-06-08 05:29:16 +00:00
if ( SDL_GetWindowWMInfo ( window , & info , SDL_SYSWM_CURRENT_VERSION ) = = 0 )
{
# if defined(SDL_ENABLE_SYSWM_WINDOWS)
2022-02-08 07:04:23 +00:00
main_viewport - > PlatformHandleRaw = ( void * ) info . info . win . window ;
2023-06-08 05:29:16 +00:00
# elif defined(__APPLE__) && defined(SDL_ENABLE_SYSWM_COCOA)
main_viewport - > PlatformHandleRaw = ( void * ) info . info . cocoa . window ;
2022-02-08 07:04:23 +00:00
# endif
2023-06-08 05:29:16 +00:00
}
2022-02-08 07:04:23 +00:00
2023-06-08 05:29:16 +00:00
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
2022-02-08 07:04:23 +00:00
// 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-06-08 05:29:16 +00:00
// you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
2022-02-08 07:04:23 +00:00
SDL_SetHint ( SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH , " 1 " ) ;
2023-06-08 05:29:16 +00:00
// 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 " ) ;
// SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659
SDL_SetHint ( " SDL_BORDERLESS_WINDOWED_STYLE " , " 0 " ) ;
2022-02-08 07:04:23 +00:00
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
2023-06-08 05:29:16 +00:00
// We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
2022-02-08 07:04:23 +00:00
if ( ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) & & ( io . BackendFlags & ImGuiBackendFlags_PlatformHasViewports ) )
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_InitPlatformInterface ( window , sdl_gl_context ) ;
2022-02-08 07:04:23 +00:00
return true ;
}
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_InitForOpenGL ( SDL_Window * window , void * sdl_gl_context )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
return ImGui_ImplSDL3_Init ( window , nullptr , sdl_gl_context ) ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_InitForVulkan ( SDL_Window * window )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
if ( ! ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) )
2022-02-08 07:04:23 +00:00
return false ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
bd - > UseVulkan = true ;
return true ;
}
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_InitForD3D ( SDL_Window * window )
2022-02-08 07:04:23 +00:00
{
# if !defined(_WIN32)
IM_ASSERT ( 0 & & " Unsupported " ) ;
# endif
2023-06-08 05:29:16 +00:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_InitForMetal ( SDL_Window * window )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
return ImGui_ImplSDL3_Init ( window , nullptr , nullptr ) ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
bool ImGui_ImplSDL3_InitForSDLRenderer ( SDL_Window * window , SDL_Renderer * renderer )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
return ImGui_ImplSDL3_Init ( window , renderer , nullptr ) ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
void ImGui_ImplSDL3_Shutdown ( )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " No platform backend to shutdown, or already shutdown? " ) ;
2022-02-08 07:04:23 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ShutdownPlatformInterface ( ) ;
2022-02-08 07:04:23 +00:00
if ( bd - > ClipboardTextData )
SDL_free ( bd - > ClipboardTextData ) ;
for ( ImGuiMouseCursor cursor_n = 0 ; cursor_n < ImGuiMouseCursor_COUNT ; cursor_n + + )
2023-06-08 05:29:16 +00:00
SDL_DestroyCursor ( bd - > MouseCursors [ cursor_n ] ) ;
bd - > LastMouseCursor = nullptr ;
2022-02-08 07:04:23 +00:00
2023-06-08 05:29:16 +00:00
io . BackendPlatformName = nullptr ;
io . BackendPlatformUserData = nullptr ;
io . BackendFlags & = ~ ( ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport ) ;
2022-02-08 07:04:23 +00:00
IM_DELETE ( bd ) ;
}
// 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-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateMouseData ( )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00:00
// We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below)
2022-02-08 07:04:23 +00: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
2023-06-08 05:29:16 +00:00
SDL_CaptureMouse ( ( bd - > MouseButtonsDown ! = 0 ) ? SDL_TRUE : SDL_FALSE ) ;
2022-02-08 07:04:23 +00:00
SDL_Window * focused_window = SDL_GetKeyboardFocus ( ) ;
const bool is_app_focused = ( focused_window & & ( bd - > Window = = focused_window | | ImGui : : FindViewportByPlatformHandle ( ( void * ) focused_window ) ) ) ;
# else
SDL_Window * focused_window = bd - > Window ;
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 )
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if ( io . WantSetMousePos )
{
# if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
2023-06-08 05:29:16 +00:00
SDL_WarpMouseGlobal ( io . MousePos . x , io . MousePos . y ) ;
2022-02-08 07:04:23 +00:00
else
# endif
2023-06-08 05:29:16 +00:00
SDL_WarpMouseInWindow ( bd - > Window , io . MousePos . x , io . MousePos . y ) ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
// (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
2022-02-08 07:04:23 +00:00
if ( bd - > MouseCanUseGlobalState & & bd - > MouseButtonsDown = = 0 )
{
// 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)
// 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)
2023-06-08 05:29:16 +00:00
float mouse_x , mouse_y ;
int window_x , window_y ;
2022-02-08 07:04:23 +00: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 ) ;
}
}
// (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 ;
if ( SDL_Window * sdl_mouse_window = SDL_GetWindowFromID ( bd - > MouseWindowID ) )
if ( ImGuiViewport * mouse_viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) sdl_mouse_window ) )
mouse_viewport_id = mouse_viewport - > ID ;
io . AddMouseViewportEvent ( mouse_viewport_id ) ;
}
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateMouseCursor ( )
2022-02-08 07:04:23 +00:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( io . ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange )
return ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
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-06-08 05:29:16 +00:00
SDL_HideCursor ( ) ;
2022-02-08 07:04:23 +00:00
}
else
{
// Show OS mouse cursor
2023-06-08 05:29:16 +00:00
SDL_Cursor * expected_cursor = bd - > MouseCursors [ imgui_cursor ] ? bd - > MouseCursors [ imgui_cursor ] : bd - > MouseCursors [ ImGuiMouseCursor_Arrow ] ;
if ( bd - > LastMouseCursor ! = expected_cursor )
{
SDL_SetCursor ( expected_cursor ) ; // SDL function doesn't have an early out (see #6113)
bd - > LastMouseCursor = expected_cursor ;
}
SDL_ShowCursor ( ) ;
2022-02-08 07:04:23 +00:00
}
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateGamepads ( )
2022-02-08 07:04:23 +00:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2023-06-08 05:29:16 +00:00
if ( ( io . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) = = 0 ) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
2022-02-08 07:04:23 +00:00
return ;
// Get gamepad
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
2023-06-08 05:29:16 +00:00
SDL_Gamepad * gamepad = SDL_OpenGamepad ( 0 ) ;
if ( ! gamepad )
2022-02-08 07:04:23 +00:00
return ;
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
// Update gamepad inputs
# define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
2023-06-08 05:29:16 +00:00
# define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GetGamepadButton(gamepad, BUTTON_NO) != 0); }
# define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GetGamepadAxis(gamepad, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
2022-02-08 07:04:23 +00:00
const int thumb_dead_zone = 8000 ; // SDL_gamecontroller.h suggests using this value.
2023-06-08 05:29:16 +00:00
MAP_BUTTON ( ImGuiKey_GamepadStart , SDL_GAMEPAD_BUTTON_START ) ;
MAP_BUTTON ( ImGuiKey_GamepadBack , SDL_GAMEPAD_BUTTON_BACK ) ;
MAP_BUTTON ( ImGuiKey_GamepadFaceLeft , SDL_GAMEPAD_BUTTON_X ) ; // Xbox X, PS Square
MAP_BUTTON ( ImGuiKey_GamepadFaceRight , SDL_GAMEPAD_BUTTON_B ) ; // Xbox B, PS Circle
MAP_BUTTON ( ImGuiKey_GamepadFaceUp , SDL_GAMEPAD_BUTTON_Y ) ; // Xbox Y, PS Triangle
MAP_BUTTON ( ImGuiKey_GamepadFaceDown , SDL_GAMEPAD_BUTTON_A ) ; // Xbox A, PS Cross
MAP_BUTTON ( ImGuiKey_GamepadDpadLeft , SDL_GAMEPAD_BUTTON_DPAD_LEFT ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadRight , SDL_GAMEPAD_BUTTON_DPAD_RIGHT ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadUp , SDL_GAMEPAD_BUTTON_DPAD_UP ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadDown , SDL_GAMEPAD_BUTTON_DPAD_DOWN ) ;
MAP_BUTTON ( ImGuiKey_GamepadL1 , SDL_GAMEPAD_BUTTON_LEFT_SHOULDER ) ;
MAP_BUTTON ( ImGuiKey_GamepadR1 , SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER ) ;
MAP_ANALOG ( ImGuiKey_GamepadL2 , SDL_GAMEPAD_AXIS_LEFT_TRIGGER , 0.0f , 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadR2 , SDL_GAMEPAD_AXIS_RIGHT_TRIGGER , 0.0f , 32767 ) ;
MAP_BUTTON ( ImGuiKey_GamepadL3 , SDL_GAMEPAD_BUTTON_LEFT_STICK ) ;
MAP_BUTTON ( ImGuiKey_GamepadR3 , SDL_GAMEPAD_BUTTON_RIGHT_STICK ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickLeft , SDL_GAMEPAD_AXIS_LEFTX , - thumb_dead_zone , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickRight , SDL_GAMEPAD_AXIS_LEFTX , + thumb_dead_zone , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickUp , SDL_GAMEPAD_AXIS_LEFTY , - thumb_dead_zone , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickDown , SDL_GAMEPAD_AXIS_LEFTY , + thumb_dead_zone , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickLeft , SDL_GAMEPAD_AXIS_RIGHTX , - thumb_dead_zone , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickRight , SDL_GAMEPAD_AXIS_RIGHTX , + thumb_dead_zone , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickUp , SDL_GAMEPAD_AXIS_RIGHTY , - thumb_dead_zone , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickDown , SDL_GAMEPAD_AXIS_RIGHTY , + thumb_dead_zone , + 32767 ) ;
2022-02-08 07:04:23 +00:00
# undef MAP_BUTTON
# undef MAP_ANALOG
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_UpdateMonitors ( )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
2022-02-08 07:04:23 +00:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Monitors . resize ( 0 ) ;
2023-06-08 05:29:16 +00:00
bd - > WantUpdateMonitors = false ;
int display_count ;
SDL_DisplayID * displays = SDL_GetDisplays ( & display_count ) ;
2022-02-08 07:04:23 +00: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.
2023-06-08 05:29:16 +00:00
SDL_DisplayID display_id = displays [ n ] ;
2022-02-08 07:04:23 +00:00
ImGuiPlatformMonitor monitor ;
SDL_Rect r ;
2023-06-08 05:29:16 +00:00
SDL_GetDisplayBounds ( display_id , & r ) ;
2022-02-08 07:04:23 +00:00
monitor . MainPos = monitor . WorkPos = ImVec2 ( ( float ) r . x , ( float ) r . y ) ;
monitor . MainSize = monitor . WorkSize = ImVec2 ( ( float ) r . w , ( float ) r . h ) ;
2023-06-08 05:29:16 +00:00
SDL_GetDisplayUsableBounds ( display_id , & r ) ;
2022-02-08 07:04:23 +00:00
monitor . WorkPos = ImVec2 ( ( float ) r . x , ( float ) r . y ) ;
monitor . WorkSize = ImVec2 ( ( float ) r . w , ( float ) r . h ) ;
2023-06-08 05:29:16 +00:00
// FIXME-VIEWPORT: On MacOS SDL reports actual monitor DPI scale, ignoring OS configuration. We may want to set
// DpiScale to cocoa_window.backingScaleFactor here.
monitor . DpiScale = SDL_GetDisplayContentScale ( display_id ) ;
monitor . PlatformHandle = ( void * ) ( intptr_t ) n ;
2022-02-08 07:04:23 +00:00
platform_io . Monitors . push_back ( monitor ) ;
}
}
2023-06-08 05:29:16 +00:00
void ImGui_ImplSDL3_NewFrame ( )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
IM_ASSERT ( bd ! = nullptr & & " Did you call ImGui_ImplSDL3_Init()? " ) ;
2022-02-08 07:04:23 +00: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 ) ;
2022-12-25 00:11:04 +00:00
if ( SDL_GetWindowFlags ( bd - > Window ) & SDL_WINDOW_MINIMIZED )
w = h = 0 ;
2023-06-08 05:29:16 +00:00
SDL_GetWindowSizeInPixels ( bd - > Window , & display_w , & display_h ) ;
io . DisplaySize = ImVec2 ( ( float ) w , ( float ) h ) ;
if ( w > 0 & & h > 0 )
2022-02-08 07:04:23 +00:00
io . DisplayFramebufferScale = ImVec2 ( ( float ) display_w / w , ( float ) display_h / h ) ;
2023-06-08 05:29:16 +00:00
// Update monitors
if ( bd - > WantUpdateMonitors )
ImGui_ImplSDL3_UpdateMonitors ( ) ;
2022-02-08 07:04:23 +00:00
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
2023-06-08 05:29:16 +00:00
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
2022-02-08 07:04:23 +00:00
static Uint64 frequency = SDL_GetPerformanceFrequency ( ) ;
Uint64 current_time = SDL_GetPerformanceCounter ( ) ;
2023-06-08 05:29:16 +00:00
if ( current_time < = bd - > Time )
current_time = bd - > Time + 1 ;
2022-02-08 07:04:23 +00:00
io . DeltaTime = bd - > Time > 0 ? ( float ) ( ( double ) ( current_time - bd - > Time ) / frequency ) : ( float ) ( 1.0f / 60.0f ) ;
bd - > Time = current_time ;
2022-05-18 19:31:29 +00:00
if ( bd - > PendingMouseLeaveFrame & & bd - > PendingMouseLeaveFrame > = ImGui : : GetFrameCount ( ) & & bd - > MouseButtonsDown = = 0 )
{
bd - > MouseWindowID = 0 ;
bd - > PendingMouseLeaveFrame = 0 ;
io . AddMousePosEvent ( - FLT_MAX , - FLT_MAX ) ;
}
2023-06-08 05:29:16 +00:00
// Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
// Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rygorous, but testing for payload reduces noise and potential side-effects.
if ( bd - > MouseCanReportHoveredViewport & & ImGui : : GetDragDropPayload ( ) = = nullptr )
io . BackendFlags | = ImGuiBackendFlags_HasMouseHoveredViewport ;
else
io . BackendFlags & = ~ ImGuiBackendFlags_HasMouseHoveredViewport ;
ImGui_ImplSDL3_UpdateMouseData ( ) ;
ImGui_ImplSDL3_UpdateMouseCursor ( ) ;
2022-02-08 07:04:23 +00:00
// Update game controllers (if enabled and available)
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_UpdateGamepads ( ) ;
2022-02-08 07:04:23 +00: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-06-08 05:29:16 +00:00
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
struct ImGui_ImplSDL3_ViewportData
2022-02-08 07:04:23 +00:00
{
SDL_Window * Window ;
Uint32 WindowID ;
bool WindowOwned ;
SDL_GLContext GLContext ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData ( ) { Window = nullptr ; WindowID = 0 ; WindowOwned = false ; GLContext = nullptr ; }
~ ImGui_ImplSDL3_ViewportData ( ) { IM_ASSERT ( Window = = nullptr & & GLContext = = nullptr ) ; }
2022-02-08 07:04:23 +00:00
} ;
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_CreateWindow ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_Data * bd = ImGui_ImplSDL3_GetBackendData ( ) ;
ImGui_ImplSDL3_ViewportData * vd = IM_NEW ( ImGui_ImplSDL3_ViewportData ) ( ) ;
2022-02-08 07:04:23 +00:00
viewport - > PlatformUserData = vd ;
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * main_viewport_data = ( ImGui_ImplSDL3_ViewportData * ) main_viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
// Share GL resources with main context
2023-06-08 05:29:16 +00:00
bool use_opengl = ( main_viewport_data - > GLContext ! = nullptr ) ;
SDL_GLContext backup_context = nullptr ;
2022-02-08 07:04:23 +00:00
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 ) ;
}
Uint32 sdl_flags = 0 ;
sdl_flags | = use_opengl ? SDL_WINDOW_OPENGL : ( bd - > UseVulkan ? SDL_WINDOW_VULKAN : 0 ) ;
2023-06-08 05:29:16 +00:00
sdl_flags | = SDL_GetWindowFlags ( bd - > Window ) ;
2022-02-08 07:04:23 +00:00
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoDecoration ) ? SDL_WINDOW_BORDERLESS : 0 ;
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoDecoration ) ? 0 : SDL_WINDOW_RESIZABLE ;
# if !defined(_WIN32)
2023-06-08 05:29:16 +00:00
// See SDL hack in ImGui_ImplSDL3_ShowWindow().
2022-02-08 07:04:23 +00:00
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_NoTaskBarIcon ) ? SDL_WINDOW_SKIP_TASKBAR : 0 ;
# endif
sdl_flags | = ( viewport - > Flags & ImGuiViewportFlags_TopMost ) ? SDL_WINDOW_ALWAYS_ON_TOP : 0 ;
2023-06-08 05:29:16 +00:00
vd - > Window = SDL_CreateWindow ( " No Title Yet " , ( int ) viewport - > Size . x , ( int ) viewport - > Size . y , sdl_flags ) ;
SDL_SetWindowPosition ( vd - > Window , ( int ) viewport - > Pos . x , ( int ) viewport - > Pos . y ) ;
2022-02-08 07:04:23 +00: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 ) ;
viewport - > PlatformHandle = ( void * ) vd - > Window ;
2023-06-08 05:29:16 +00:00
viewport - > PlatformHandleRaw = nullptr ;
2022-02-08 07:04:23 +00:00
SDL_SysWMinfo info ;
2023-06-08 05:29:16 +00:00
if ( SDL_GetWindowWMInfo ( vd - > Window , & info , SDL_SYSWM_CURRENT_VERSION ) )
{
# if defined(SDL_VIDEO_DRIVER_WINDOWS)
2022-02-08 07:04:23 +00:00
viewport - > PlatformHandleRaw = info . info . win . window ;
2023-06-08 05:29:16 +00:00
# elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
viewport - > PlatformHandleRaw = ( void * ) info . info . cocoa . window ;
2022-02-08 07:04:23 +00:00
# endif
2023-06-08 05:29:16 +00:00
}
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_DestroyWindow ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
if ( ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData )
2022-02-08 07:04:23 +00:00
{
if ( vd - > GLContext & & vd - > WindowOwned )
SDL_GL_DeleteContext ( vd - > GLContext ) ;
if ( vd - > Window & & vd - > WindowOwned )
SDL_DestroyWindow ( vd - > Window ) ;
2023-06-08 05:29:16 +00:00
vd - > GLContext = nullptr ;
vd - > Window = nullptr ;
2022-02-08 07:04:23 +00:00
IM_DELETE ( vd ) ;
}
2023-06-08 05:29:16 +00:00
viewport - > PlatformUserData = viewport - > PlatformHandle = nullptr ;
2022-02-08 07:04:23 +00:00
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_ShowWindow ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
# if defined(_WIN32)
HWND hwnd = ( HWND ) viewport - > PlatformHandleRaw ;
// SDL hack: Hide icon from task bar
// Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
if ( viewport - > Flags & ImGuiViewportFlags_NoTaskBarIcon )
{
LONG ex_style = : : GetWindowLong ( hwnd , GWL_EXSTYLE ) ;
ex_style & = ~ WS_EX_APPWINDOW ;
ex_style | = WS_EX_TOOLWINDOW ;
: : SetWindowLong ( hwnd , GWL_EXSTYLE , ex_style ) ;
}
// SDL hack: SDL always activate/focus windows :/
if ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnAppearing )
{
: : ShowWindow ( hwnd , SW_SHOWNA ) ;
return ;
}
# endif
SDL_ShowWindow ( vd - > Window ) ;
}
2023-06-08 05:29:16 +00:00
static ImVec2 ImGui_ImplSDL3_GetWindowPos ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
int x = 0 , y = 0 ;
SDL_GetWindowPosition ( vd - > Window , & x , & y ) ;
return ImVec2 ( ( float ) x , ( float ) y ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetWindowPos ( ImGuiViewport * viewport , ImVec2 pos )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
SDL_SetWindowPosition ( vd - > Window , ( int ) pos . x , ( int ) pos . y ) ;
}
2023-06-08 05:29:16 +00:00
static ImVec2 ImGui_ImplSDL3_GetWindowSize ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
int w = 0 , h = 0 ;
SDL_GetWindowSize ( vd - > Window , & w , & h ) ;
return ImVec2 ( ( float ) w , ( float ) h ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetWindowSize ( ImGuiViewport * viewport , ImVec2 size )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
SDL_SetWindowSize ( vd - > Window , ( int ) size . x , ( int ) size . y ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetWindowTitle ( ImGuiViewport * viewport , const char * title )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
SDL_SetWindowTitle ( vd - > Window , title ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetWindowAlpha ( ImGuiViewport * viewport , float alpha )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
SDL_SetWindowOpacity ( vd - > Window , alpha ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SetWindowFocus ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
SDL_RaiseWindow ( vd - > Window ) ;
}
2023-06-08 05:29:16 +00:00
static bool ImGui_ImplSDL3_GetWindowFocus ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
return ( SDL_GetWindowFlags ( vd - > Window ) & SDL_WINDOW_INPUT_FOCUS ) ! = 0 ;
}
2023-06-08 05:29:16 +00:00
static bool ImGui_ImplSDL3_GetWindowMinimized ( ImGuiViewport * viewport )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
return ( SDL_GetWindowFlags ( vd - > Window ) & SDL_WINDOW_MINIMIZED ) ! = 0 ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_RenderWindow ( ImGuiViewport * viewport , void * )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
if ( vd - > GLContext )
SDL_GL_MakeCurrent ( vd - > Window , vd - > GLContext ) ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_SwapBuffers ( ImGuiViewport * viewport , void * )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
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.
2023-06-08 05:29:16 +00:00
# include <SDL3/SDL_vulkan.h>
static int ImGui_ImplSDL3_CreateVkSurface ( ImGuiViewport * viewport , ImU64 vk_instance , const void * vk_allocator , ImU64 * out_vk_surface )
2022-02-08 07:04:23 +00:00
{
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = ( ImGui_ImplSDL3_ViewportData * ) viewport - > PlatformUserData ;
2022-02-08 07:04:23 +00:00
( void ) vk_allocator ;
SDL_bool ret = SDL_Vulkan_CreateSurface ( vd - > Window , ( VkInstance ) vk_instance , ( VkSurfaceKHR * ) out_vk_surface ) ;
return ret ? 0 : 1 ; // ret ? VK_SUCCESS : VK_NOT_READY
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_InitPlatformInterface ( SDL_Window * window , void * sdl_gl_context )
2022-02-08 07:04:23 +00:00
{
// Register platform interface (will be coupled with a renderer interface)
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
2023-06-08 05:29:16 +00:00
platform_io . Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow ;
platform_io . Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow ;
platform_io . Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow ;
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 ;
2022-02-08 07:04:23 +00:00
// 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 ( ) ;
2023-06-08 05:29:16 +00:00
ImGui_ImplSDL3_ViewportData * vd = IM_NEW ( ImGui_ImplSDL3_ViewportData ) ( ) ;
2022-02-08 07:04:23 +00:00
vd - > Window = window ;
vd - > WindowID = SDL_GetWindowID ( window ) ;
vd - > WindowOwned = false ;
vd - > GLContext = sdl_gl_context ;
main_viewport - > PlatformUserData = vd ;
main_viewport - > PlatformHandle = vd - > Window ;
}
2023-06-08 05:29:16 +00:00
static void ImGui_ImplSDL3_ShutdownPlatformInterface ( )
2022-02-08 07:04:23 +00:00
{
ImGui : : DestroyPlatformWindows ( ) ;
}
2023-06-08 05:29:16 +00:00
# if defined(__clang__)
# pragma clang diagnostic pop
# endif