using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Hexa.NET.ImGui;
using SDL3;
namespace SDL3_TestingSuite.SDL3;
///
/// Implementation of SDL3 platform backend for ImGui.
/// https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl3.h
///
public unsafe static class ImGuiSDL3Platform
{
public class PlatformData
{
public nint Window;
public uint WindowID;
public nint Renderer;
public ulong Time;
public nint ClipboardTextData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
public byte[] BackendPlatformName = new byte[48];
public bool UseVulkan;
public bool WantUpdateMonitors;
// IME Handling
public nint ImeWindow;
public ImGuiPlatformImeData ImeData;
public bool ImeDirty;
// Mouse Handling
public uint MouseWindowID;
public int MouseButtonsDown;
public readonly nint[] MouseCursors = new nint[(int)ImGuiMouseCursor.Count];
public nint MouseLastCursor;
public int MouseLastLeaveFrame;
public bool MouseCanUseGlobalState;
public bool MouseCanReportHoveredViewport;
public MouseCaptureMode MouseCaptureMode;
// Gamepad Handling
public readonly nint[] Gamepads = new nint[16];
public int GamepadCount;
public GamepadMode GamepadMode;
public bool WantUpdateGamepadsList;
public PlatformData()
{
MouseLastCursor = nint.Zero;
for (int i = 0; i < MouseCursors.Length; i++)
MouseCursors[i] = nint.Zero;
for (int i = 0; i < Gamepads.Length; i++)
Gamepads[i] = nint.Zero;
}
}
public static PlatformData GetPlatformData() => ImGui.GetCurrentContext().Handle != null ? ImGuiUserData.Get(ImGui.GetIO().BackendPlatformUserData)! : null!;
public static SDL3Window? Parent;
public static bool Init(nint window, nint renderer, SDL3Window? parentWindow = null)
{
Parent = parentWindow;
ImGuiIOPtr io = ImGui.GetIO();
PlatformData data = new PlatformData
{
Window = window,
Renderer = renderer,
WindowID = SDL.GetWindowID(window)
};
io.BackendPlatformUserData = ImGuiUserData.Store(data);
io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors;
io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos;
data.MouseCanUseGlobalState = false;
data.MouseCaptureMode = MouseCaptureMode.Disabled;
string? backend = SDL.GetCurrentVideoDriver();
string[] captureAndGlobalStateWhitelist = new string[] { "windows", "cocoa", "x11", "DIVE", "VMAN" };
foreach (string item in captureAndGlobalStateWhitelist)
{
if (item != backend) continue;
data.MouseCanUseGlobalState = true;
data.MouseCaptureMode = item == "x11" ? MouseCaptureMode.EnabledAfterDrag : MouseCaptureMode.Enabled;
}
if (data.MouseCanUseGlobalState)
{
io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
}
#if __APPLE__
data.MouseCanReportHoveredViewport = false;
#else
data.MouseCanReportHoveredViewport = data.MouseCanUseGlobalState;
#endif
ImGuiPlatformIOPtr platformIo = ImGui.GetPlatformIO();
platformIo.PlatformGetClipboardTextFn = DelegateStorage.GetClipboardDelegate.GetPtrForDelegate();
platformIo.PlatformSetClipboardTextFn = DelegateStorage.SetClipboardDelegate.GetPtrForDelegate();
platformIo.PlatformSetImeDataFn = DelegateStorage.SetImeDataDelegate.GetPtrForDelegate();
platformIo.PlatformOpenInShellFn = DelegateStorage.OpenInShellDelegate.GetPtrForDelegate();
UpdateMonitors();
data.GamepadMode = GamepadMode.AutoFirst;
data.WantUpdateGamepadsList = true;
data.MouseCursors[(int)ImGuiMouseCursor.Arrow] = SDL.CreateSystemCursor(SDL.SystemCursor.Default);
data.MouseCursors[(int)ImGuiMouseCursor.TextInput] = SDL.CreateSystemCursor(SDL.SystemCursor.Text);
data.MouseCursors[(int)ImGuiMouseCursor.ResizeAll] = SDL.CreateSystemCursor(SDL.SystemCursor.Move);
data.MouseCursors[(int)ImGuiMouseCursor.ResizeNs] = SDL.CreateSystemCursor(SDL.SystemCursor.NSResize);
data.MouseCursors[(int)ImGuiMouseCursor.ResizeEw] = SDL.CreateSystemCursor(SDL.SystemCursor.EWResize);
data.MouseCursors[(int)ImGuiMouseCursor.ResizeNesw] = SDL.CreateSystemCursor(SDL.SystemCursor.NESWResize);
data.MouseCursors[(int)ImGuiMouseCursor.ResizeNwse] = SDL.CreateSystemCursor(SDL.SystemCursor.NWSEResize);
data.MouseCursors[(int)ImGuiMouseCursor.Hand] = SDL.CreateSystemCursor(SDL.SystemCursor.Pointer);
data.MouseCursors[(int)ImGuiMouseCursor.Wait] = SDL.CreateSystemCursor(SDL.SystemCursor.Wait);
data.MouseCursors[(int)ImGuiMouseCursor.Progress] = SDL.CreateSystemCursor(SDL.SystemCursor.Progress);
data.MouseCursors[(int)ImGuiMouseCursor.NotAllowed] = SDL.CreateSystemCursor(SDL.SystemCursor.NotAllowed);
SetupPlatformHandles(ImGui.GetMainViewport(), window);
SDL.SetHint(SDL.Hints.MouseFocusClickthrough, "1");
SDL.SetHint(SDL.Hints.MouseAutoCapture, "0");
SDL.SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "0");
if ((io.BackendFlags & ImGuiBackendFlags.PlatformHasViewports) != 0)
InitMultiViewportSupport(window);
return true;
}
public static void NewFrame()
{
ImGuiIOPtr io = ImGui.GetIO();
PlatformData data = GetPlatformData();
GetWindowSizeAndFramebufferScale(data.Window, out Vector2 size, out Vector2 framebufferScale);
if (data.WantUpdateMonitors)
{
UpdateMonitors();
}
ulong frequency = SDL.GetPerformanceFrequency();
ulong currentTime = SDL.GetPerformanceCounter();
if (currentTime <= data.Time)
currentTime = data.Time + 1;
io.DeltaTime = data.Time > 0 ? (float)((currentTime - data.Time) / (double)frequency) : 1.0f / 60.0f;
data.Time = currentTime;
io.DisplaySize = size;
io.DisplayFramebufferScale = framebufferScale;
if (data.MouseLastLeaveFrame > 0 && data.MouseLastLeaveFrame >= ImGui.GetFrameCount() && data.MouseButtonsDown == 0)
{
data.MouseWindowID = 0;
data.MouseLastLeaveFrame = 0;
io.AddMousePosEvent(-float.MaxValue, -float.MaxValue);
}
if (data.MouseCanReportHoveredViewport && ImGui.GetDragDropPayload().Equals(nint.Zero))
{
io.BackendFlags |= ImGuiBackendFlags.HasMouseHoveredViewport;
}
else
{
io.BackendFlags &= ~ImGuiBackendFlags.HasMouseHoveredViewport;
}
UpdateMouseData();
UpdateMouseCursor();
UpdateIme();
UpdateGamepads();
}
public static void UpdateMonitors()
{
PlatformData bd = GetPlatformData();
ImGuiPlatformIOPtr platformio = ImGui.GetPlatformIO();
platformio.Monitors.Resize(0);
bd.WantUpdateMonitors = false;
uint[] displays = SDL.GetDisplays(out int displayCount)!;
for (int n = 0; n < displayCount; 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.
uint displayID = displays[n];
ImGuiPlatformMonitor monitor = new ImGuiPlatformMonitor();
SDL.GetDisplayBounds(displayID, out SDL.Rect r);
monitor.MainPos = monitor.WorkPos = new Vector2(r.X, r.Y);
monitor.MainSize = monitor.WorkSize = new Vector2(r.W, r.H);
if (SDL.GetDisplayUsableBounds(displayID, out SDL.Rect r2) && r2.W > 0 && r2.H > 0)
{
monitor.WorkPos = new Vector2(r2.X, r2.Y);
monitor.WorkSize = new Vector2(r2.W, r2.H);
}
monitor.DpiScale = SDL.GetDisplayContentScale(displayID); // See https://wiki.libsdl.org/SDL3/README-highdpi for details.
monitor.PlatformHandle = (void*)n;
if (monitor.DpiScale <= 0.0f)
continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
platformio.Monitors.PushBack(monitor);
}
}
private static void GetWindowSizeAndFramebufferScale(nint window, out Vector2 out_size, out Vector2 out_framebuffer_scale)
{
SDL.GetWindowSize(window, out int w, out int h);
if (SDL.GetWindowFlags(window).HasFlag(SDL.WindowFlags.Minimized))
w = h = 0;
SDL.GetWindowSizeInPixels(window, out int displayW, out int displayH);
float fbScaleX = w > 0 ? displayW / (float)w : 1.0f;
float fbScaleY = h > 0 ? displayH / (float)h : 1.0f;
out_size = new Vector2(w, h);
out_framebuffer_scale = new Vector2(fbScaleX, fbScaleY);
}
public static bool ProcessEvent(SDL.Event e)
{
ImGuiIOPtr io = ImGui.GetIO();
PlatformData data = GetPlatformData();
switch ((SDL.EventType)e.Type)
{
case SDL.EventType.MouseMotion:
if (GetViewportForWindowId(e.Motion.WindowID) == null)
return false;
io.AddMouseSourceEvent(e.Motion.Which == SDL.TouchMouseID ? ImGuiMouseSource.TouchScreen : ImGuiMouseSource.Mouse);
// ImGui expects desktop/global coordinates when viewports are enabled.
SDL.GetGlobalMouseState(out float mouseX, out float mouseY);
io.AddMousePosEvent(mouseX, mouseY);
return true;
case SDL.EventType.MouseWheel:
if (GetViewportForWindowId(e.Wheel.WindowID) == null)
return false;
float wheelX = -e.Wheel.X;
float wheelY = e.Wheel.Y;
io.AddMouseSourceEvent(e.Wheel.Which == SDL.TouchMouseID ? ImGuiMouseSource.TouchScreen : ImGuiMouseSource.Mouse);
io.AddMouseWheelEvent(wheelX, wheelY);
return true;
case SDL.EventType.MouseButtonDown:
case SDL.EventType.MouseButtonUp:
if (GetViewportForWindowId(e.Button.WindowID) == null)
return false;
int mouseButton = e.Button.Button switch
{
SDL.ButtonLeft => 0,
SDL.ButtonRight => 1,
SDL.ButtonMiddle => 2,
SDL.ButtonX1 => 3,
SDL.ButtonX2 => 4,
_ => -1
};
if (mouseButton == -1) break;
io.AddMouseSourceEvent(e.Button.Which == SDL.TouchMouseID ? ImGuiMouseSource.TouchScreen : ImGuiMouseSource.Mouse);
io.AddMouseButtonEvent(mouseButton, (SDL.EventType)e.Type == SDL.EventType.MouseButtonDown);
data.MouseButtonsDown = (SDL.EventType)e.Type == SDL.EventType.MouseButtonDown ? data.MouseButtonsDown | 1 << mouseButton : data.MouseButtonsDown & ~(1 << mouseButton);
return true;
case SDL.EventType.TextInput:
if (GetViewportForWindowId(e.Text.WindowID) == null)
return false;
ImGui.GetIO().AddInputCharactersUTF8((byte*)e.Text.Text);
return true;
case SDL.EventType.KeyDown:
case SDL.EventType.KeyUp:
if (GetViewportForWindowId(e.Key.WindowID) == null)
return false;
UpdateKeyModifiers(e.Key.Mod);
ImGuiKey imguiKey = KeyEventToImGui(e.Key.Key, e.Key.Scancode);
bool pressed = (SDL.EventType)e.Type == SDL.EventType.KeyDown;
io.AddKeyEvent(imguiKey, pressed);
io.SetKeyEventNativeData(imguiKey, (int)e.Key.Key, (int)e.Key.Scancode, (int)e.Key.Scancode);
return true;
case SDL.EventType.WindowMouseEnter:
if (GetViewportForWindowId(e.Window.WindowID) == null)
return false;
data.MouseWindowID = e.Window.WindowID;
data.MouseLastLeaveFrame = 0;
return true;
case SDL.EventType.WindowMouseLeave:
if (GetViewportForWindowId(e.Window.WindowID) == null)
return false;
data.MouseLastLeaveFrame = ImGui.GetFrameCount() + 1;
return true;
case SDL.EventType.WindowFocusGained:
case SDL.EventType.WindowFocusLost:
if (GetViewportForWindowId(e.Window.WindowID) == null)
return false;
io.AddFocusEvent((SDL.EventType)e.Type == SDL.EventType.WindowFocusGained);
return true;
}
return false;
}
// This code is rather messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
internal static void UpdateMouseData()
{
PlatformData bd = GetPlatformData();
ImGuiIOPtr io = ImGui.GetIO();
// We forward mouse input when hovered or captured (via SDL.MOUSEMOTION) or when focused (below)
// - SDL.CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside.
// - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue on X11 we we wait until mouse has moved to begin capture.
if (bd.MouseCaptureMode == MouseCaptureMode.Enabled)
{
SDL.CaptureMouse(bd.MouseButtonsDown != 0 ? true : false);
}
else if (bd.MouseCaptureMode == MouseCaptureMode.EnabledAfterDrag)
{
bool wantCapture = false;
for (int buttonN = 0; buttonN < (int)ImGuiMouseButton.Count && !wantCapture; buttonN++)
{
if (ImGui.IsMouseDragging((ImGuiMouseButton)buttonN, 1.0f))
wantCapture = true;
}
SDL.CaptureMouse(wantCapture ? true : false);
}
nint focusedWindow = SDL.GetKeyboardFocus();
bool isAppFocused = focusedWindow != nint.Zero && (bd.Window == focusedWindow || GetViewportForWindowId(SDL.GetWindowID(focusedWindow)) != null);
if (isAppFocused)
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
if (io.WantSetMousePos)
{
if (io.ConfigFlags.HasFlag(ImGuiConfigFlags.ViewportsEnable))
SDL.WarpMouseGlobal((int)io.MousePos.X, (int)io.MousePos.Y);
else
SDL.WarpMouseInWindow(bd.Window, (int)io.MousePos.X, (int)io.MousePos.Y);
}
// (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL.MOUSEMOTION already provides this when hovered or captured)
// Note that SDL.GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature.
nint hoveredWindow = SDL.GetMouseFocus();
bool isRelativeMouseMode = false /*SDL.GetRelativeMouseMode() != 0*/;
if (hoveredWindow == nint.Zero && bd.MouseCanUseGlobalState && bd.MouseButtonsDown == 0 && !isRelativeMouseMode)
{
// 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)
SDL.GetGlobalMouseState(out float mouseX, out float mouseY);
if (!io.ConfigFlags.HasFlag(ImGuiConfigFlags.ViewportsEnable))
{
SDL.GetWindowPosition(focusedWindow, out int windowX, out int windowY);
mouseX -= windowX;
mouseY -= windowY;
}
io.AddMousePosEvent(mouseX, mouseY);
}
}
// (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.HasFlag(ImGuiBackendFlags.HasMouseHoveredViewport))
{
uint mouseViewportID = 0;
ImGuiViewportPtr? mouseViewport = GetViewportForWindowId(bd.MouseWindowID);
if (mouseViewport != null)
mouseViewportID = mouseViewport.Value.ID;
io.AddMouseViewportEvent(mouseViewportID);
}
}
internal static void UpdateMouseCursor()
{
ImGuiIOPtr io = ImGui.GetIO();
if (io.ConfigFlags.HasFlag(ImGuiConfigFlags.NoMouseCursorChange))
return;
PlatformData bd = GetPlatformData();
ImGuiMouseCursor imguiCursor = ImGui.GetMouseCursor();
if (io.MouseDrawCursor || imguiCursor == ImGuiMouseCursor.None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL.HideCursor();
}
else
{
// Show OS mouse cursor
nint expectedCursor = bd.MouseCursors[(int)imguiCursor] != nint.Zero ? bd.MouseCursors[(int)imguiCursor] : bd.MouseCursors[(int)ImGuiMouseCursor.Arrow];
if (bd.MouseLastCursor != expectedCursor)
{
SDL.SetCursor(expectedCursor); // SDL function doesn't have an early out (see #6113)
bd.MouseLastCursor = expectedCursor;
}
SDL.ShowCursor();
}
}
internal static void UpdateGamepads()
{
PlatformData data = GetPlatformData();
ImGuiIOPtr io = ImGui.GetIO();
if (data.WantUpdateGamepadsList && data.GamepadMode != GamepadMode.Manual)
{
CloseGamepads();
uint[] sdlGamepads = SDL.GetGamepads(out int count)!;
for (int n = 0; n < count; n++)
{
if (data.GamepadCount >= data.Gamepads.Length)
break;
data.Gamepads[data.GamepadCount++] = SDL.OpenGamepad(sdlGamepads[n]);
if (data.GamepadMode == GamepadMode.AutoFirst)
break;
}
data.WantUpdateGamepadsList = false;
}
io.BackendFlags &= ~ImGuiBackendFlags.HasGamepad;
if (data.GamepadCount == 0)
return;
io.BackendFlags |= ImGuiBackendFlags.HasGamepad;
const int thumbDeadZone = 8000;
UpdateGamepadButton(data, io, ImGuiKey.GamepadStart, SDL.GamepadButton.Start);
UpdateGamepadButton(data, io, ImGuiKey.GamepadBack, SDL.GamepadButton.Back);
UpdateGamepadButton(data, io, ImGuiKey.GamepadFaceLeft, SDL.GamepadButton.West);
UpdateGamepadButton(data, io, ImGuiKey.GamepadFaceRight, SDL.GamepadButton.East);
UpdateGamepadButton(data, io, ImGuiKey.GamepadFaceUp, SDL.GamepadButton.North);
UpdateGamepadButton(data, io, ImGuiKey.GamepadFaceDown, SDL.GamepadButton.South);
UpdateGamepadButton(data, io, ImGuiKey.GamepadDpadLeft, SDL.GamepadButton.DPadLeft);
UpdateGamepadButton(data, io, ImGuiKey.GamepadDpadRight, SDL.GamepadButton.DPadRight);
UpdateGamepadButton(data, io, ImGuiKey.GamepadDpadUp, SDL.GamepadButton.DPadUp);
UpdateGamepadButton(data, io, ImGuiKey.GamepadDpadDown, SDL.GamepadButton.DPadDown);
UpdateGamepadButton(data, io, ImGuiKey.GamepadL1, SDL.GamepadButton.LeftShoulder);
UpdateGamepadButton(data, io, ImGuiKey.GamepadR1, SDL.GamepadButton.RightShoulder);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadL2, SDL.GamepadAxis.LeftTrigger, 0.0f, 32767);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadR2, SDL.GamepadAxis.RightTrigger, 0.0f, 32767);
UpdateGamepadButton(data, io, ImGuiKey.GamepadL3, SDL.GamepadButton.LeftStick);
UpdateGamepadButton(data, io, ImGuiKey.GamepadR3, SDL.GamepadButton.RightStick);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadLStickLeft, SDL.GamepadAxis.LeftX, -thumbDeadZone, -32768);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadLStickRight, SDL.GamepadAxis.LeftX, thumbDeadZone, 32767);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadLStickUp, SDL.GamepadAxis.LeftY, -thumbDeadZone, -32768);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadLStickDown, SDL.GamepadAxis.LeftY, thumbDeadZone, 32767);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadRStickLeft, SDL.GamepadAxis.RightX, -thumbDeadZone, -32768);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadRStickRight, SDL.GamepadAxis.RightX, thumbDeadZone, 32767);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadRStickUp, SDL.GamepadAxis.RightY, -thumbDeadZone, -32768);
UpdateGamepadAnalog(data, io, ImGuiKey.GamepadRStickDown, SDL.GamepadAxis.RightY, thumbDeadZone, 32767);
}
private static void UpdateGamepadButton(PlatformData bd, ImGuiIOPtr io, ImGuiKey key, SDL.GamepadButton button_no)
{
bool mergedValue = false;
for (int i = 0; i < bd.GamepadCount; i++)
{
nint gamepad = bd.Gamepads[i];
mergedValue |= SDL.GetGamepadButton(gamepad, button_no);
}
io.AddKeyEvent(key, mergedValue);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float Saturate(float v)
{
return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v;
}
private static void UpdateGamepadAnalog(PlatformData bd, ImGuiIOPtr io, ImGuiKey key, SDL.GamepadAxis axis_no, float v0, float v1)
{
float mergedValue = 0.0f;
for (int i = 0; i < bd.GamepadCount; i++)
{
nint gamepad = bd.Gamepads[i];
float raw = SDL.GetGamepadAxis(gamepad, axis_no);
float vn = Saturate((raw - v0) / (v1 - v0));
if (mergedValue < vn)
mergedValue = vn;
}
io.AddKeyAnalogEvent(key, mergedValue > 0.1f, mergedValue);
}
internal static void SetGamepadMode(GamepadMode mode, nint[] manual_gamepads_array, int manual_gamepads_count)
{
PlatformData bd = GetPlatformData();
CloseGamepads();
if (mode == GamepadMode.Manual)
{
int count = manual_gamepads_count;
if (count > bd.Gamepads.Length)
count = bd.Gamepads.Length;
for (int n = 0; n < count; n++)
bd.Gamepads[n] = manual_gamepads_array[n];
bd.GamepadCount = count;
}
else
{
bd.WantUpdateGamepadsList = true;
}
bd.GamepadMode = mode;
}
internal static void CloseGamepads()
{
PlatformData bd = GetPlatformData();
if (bd.GamepadMode != GamepadMode.Manual)
{
for (int i = 0; i < bd.GamepadCount; i++)
{
SDL.CloseGamepad(bd.Gamepads[i]);
bd.Gamepads[i] = nint.Zero;
}
}
bd.GamepadCount = 0;
}
private static ImGuiKey KeyEventToImGui(SDL.Keycode keycode, SDL.Scancode scancode)
{
return scancode switch
{
SDL.Scancode.Kp0 => ImGuiKey.Keypad0,
SDL.Scancode.Kp1 => ImGuiKey.Keypad1,
SDL.Scancode.Kp2 => ImGuiKey.Keypad2,
SDL.Scancode.Kp3 => ImGuiKey.Keypad3,
SDL.Scancode.Kp4 => ImGuiKey.Keypad4,
SDL.Scancode.Kp5 => ImGuiKey.Keypad5,
SDL.Scancode.Kp6 => ImGuiKey.Keypad6,
SDL.Scancode.Kp7 => ImGuiKey.Keypad7,
SDL.Scancode.Kp8 => ImGuiKey.Keypad8,
SDL.Scancode.Kp9 => ImGuiKey.Keypad9,
SDL.Scancode.KpPeriod => ImGuiKey.KeypadDecimal,
SDL.Scancode.KpDivide => ImGuiKey.KeypadDivide,
SDL.Scancode.KpMultiply => ImGuiKey.KeypadMultiply,
SDL.Scancode.KpMinus => ImGuiKey.KeypadSubtract,
SDL.Scancode.KpPlus => ImGuiKey.KeypadAdd,
SDL.Scancode.KpEnter => ImGuiKey.KeypadEnter,
SDL.Scancode.KpEquals => ImGuiKey.KeypadEqual,
_ => keycode switch
{
SDL.Keycode.Tab => ImGuiKey.Tab,
SDL.Keycode.Left => ImGuiKey.LeftArrow,
SDL.Keycode.Right => ImGuiKey.RightArrow,
SDL.Keycode.Up => ImGuiKey.UpArrow,
SDL.Keycode.Down => ImGuiKey.DownArrow,
SDL.Keycode.Pageup => ImGuiKey.PageUp,
SDL.Keycode.Pagedown => ImGuiKey.PageDown,
SDL.Keycode.Home => ImGuiKey.Home,
SDL.Keycode.End => ImGuiKey.End,
SDL.Keycode.Insert => ImGuiKey.Insert,
SDL.Keycode.Delete => ImGuiKey.Delete,
SDL.Keycode.Backspace => ImGuiKey.Backspace,
SDL.Keycode.Space => ImGuiKey.Space,
SDL.Keycode.Return => ImGuiKey.Enter,
SDL.Keycode.Escape => ImGuiKey.Escape,
SDL.Keycode.Apostrophe => ImGuiKey.Apostrophe,
SDL.Keycode.Comma => ImGuiKey.Comma,
SDL.Keycode.Minus => ImGuiKey.Minus,
SDL.Keycode.Period => ImGuiKey.Period,
SDL.Keycode.Slash => ImGuiKey.Slash,
SDL.Keycode.Semicolon => ImGuiKey.Semicolon,
SDL.Keycode.Equals => ImGuiKey.Equal,
SDL.Keycode.LeftBracket => ImGuiKey.LeftBracket,
SDL.Keycode.Backslash => ImGuiKey.Backslash,
SDL.Keycode.RightBracket => ImGuiKey.RightBracket,
SDL.Keycode.Grave => ImGuiKey.GraveAccent,
SDL.Keycode.Capslock => ImGuiKey.CapsLock,
SDL.Keycode.ScrollLock => ImGuiKey.ScrollLock,
SDL.Keycode.NumLockClear => ImGuiKey.NumLock,
SDL.Keycode.PrintScreen => ImGuiKey.PrintScreen,
SDL.Keycode.Pause => ImGuiKey.Pause,
SDL.Keycode.LCtrl => ImGuiKey.LeftCtrl,
SDL.Keycode.LShift => ImGuiKey.LeftShift,
SDL.Keycode.LAlt => ImGuiKey.LeftAlt,
SDL.Keycode.LGui => ImGuiKey.LeftSuper,
SDL.Keycode.RCtrl => ImGuiKey.RightCtrl,
SDL.Keycode.RShift => ImGuiKey.RightShift,
SDL.Keycode.RAlt => ImGuiKey.RightAlt,
SDL.Keycode.RGUI => ImGuiKey.RightSuper,
SDL.Keycode.Application => ImGuiKey.Menu,
SDL.Keycode.Alpha0 => ImGuiKey.Key0,
SDL.Keycode.Alpha1 => ImGuiKey.Key1,
SDL.Keycode.Alpha2 => ImGuiKey.Key2,
SDL.Keycode.Alpha3 => ImGuiKey.Key3,
SDL.Keycode.Alpha4 => ImGuiKey.Key4,
SDL.Keycode.Alpha5 => ImGuiKey.Key5,
SDL.Keycode.Alpha6 => ImGuiKey.Key6,
SDL.Keycode.Alpha7 => ImGuiKey.Key7,
SDL.Keycode.Alpha8 => ImGuiKey.Key8,
SDL.Keycode.Alpha9 => ImGuiKey.Key9,
SDL.Keycode.A => ImGuiKey.A,
SDL.Keycode.B => ImGuiKey.B,
SDL.Keycode.C => ImGuiKey.C,
SDL.Keycode.D => ImGuiKey.D,
SDL.Keycode.E => ImGuiKey.E,
SDL.Keycode.F => ImGuiKey.F,
SDL.Keycode.G => ImGuiKey.G,
SDL.Keycode.H => ImGuiKey.H,
SDL.Keycode.I => ImGuiKey.I,
SDL.Keycode.J => ImGuiKey.J,
SDL.Keycode.K => ImGuiKey.K,
SDL.Keycode.L => ImGuiKey.L,
SDL.Keycode.M => ImGuiKey.M,
SDL.Keycode.N => ImGuiKey.N,
SDL.Keycode.O => ImGuiKey.O,
SDL.Keycode.P => ImGuiKey.P,
SDL.Keycode.Q => ImGuiKey.Q,
SDL.Keycode.R => ImGuiKey.R,
SDL.Keycode.S => ImGuiKey.S,
SDL.Keycode.T => ImGuiKey.T,
SDL.Keycode.U => ImGuiKey.U,
SDL.Keycode.V => ImGuiKey.V,
SDL.Keycode.W => ImGuiKey.W,
SDL.Keycode.X => ImGuiKey.X,
SDL.Keycode.Y => ImGuiKey.Y,
SDL.Keycode.Z => ImGuiKey.Z,
SDL.Keycode.F1 => ImGuiKey.F1,
SDL.Keycode.F2 => ImGuiKey.F2,
SDL.Keycode.F3 => ImGuiKey.F3,
SDL.Keycode.F4 => ImGuiKey.F4,
SDL.Keycode.F5 => ImGuiKey.F5,
SDL.Keycode.F6 => ImGuiKey.F6,
SDL.Keycode.F7 => ImGuiKey.F7,
SDL.Keycode.F8 => ImGuiKey.F8,
SDL.Keycode.F9 => ImGuiKey.F9,
SDL.Keycode.F10 => ImGuiKey.F10,
SDL.Keycode.F11 => ImGuiKey.F11,
SDL.Keycode.F12 => ImGuiKey.F12,
SDL.Keycode.F13 => ImGuiKey.F13,
SDL.Keycode.F14 => ImGuiKey.F14,
SDL.Keycode.F15 => ImGuiKey.F15,
SDL.Keycode.F16 => ImGuiKey.F16,
SDL.Keycode.F17 => ImGuiKey.F17,
SDL.Keycode.F18 => ImGuiKey.F18,
SDL.Keycode.F19 => ImGuiKey.F19,
SDL.Keycode.F20 => ImGuiKey.F20,
SDL.Keycode.F21 => ImGuiKey.F21,
SDL.Keycode.F22 => ImGuiKey.F22,
SDL.Keycode.F23 => ImGuiKey.F23,
SDL.Keycode.F24 => ImGuiKey.F24,
SDL.Keycode.AcBack => ImGuiKey.AppBack,
SDL.Keycode.AcForward => ImGuiKey.AppForward,
_ => ImGuiKey.None
}
};
}
public static void UpdateIme()
{
PlatformData data = GetPlatformData();
ImGuiPlatformImeData imeData = data.ImeData;
nint window = SDL.GetKeyboardFocus();
// Stop previous input
if ((imeData.WantVisible != 1 || data.ImeWindow != window) && data.ImeWindow != nint.Zero)
{
SDL.StopTextInput(data.ImeWindow);
data.ImeWindow = nint.Zero;
}
if (!data.ImeDirty && data.ImeWindow == window || window == nint.Zero)
return;
// Start/update current input
data.ImeDirty = false;
if (imeData.WantVisible == 1)
{
SDL.Rect r = new SDL.Rect
{
X = (int)imeData.InputPos.X,
Y = (int)imeData.InputPos.Y,
W = 1,
H = (int)imeData.InputLineHeight
};
SDL.SetTextInputArea(window, r, 0);
data.ImeWindow = window;
}
if (!SDL.TextInputActive(window) && imeData.WantVisible == 1)
SDL.StartTextInput(window);
}
private static void UpdateKeyModifiers(SDL.Keymod mod)
{
ImGuiIOPtr io = ImGui.GetIO();
io.AddKeyEvent(ImGuiKey.ModCtrl, (mod & SDL.Keymod.Ctrl) != 0);
io.AddKeyEvent(ImGuiKey.ModShift, (mod & SDL.Keymod.Shift) != 0);
io.AddKeyEvent(ImGuiKey.ModAlt, (mod & SDL.Keymod.Alt) != 0);
io.AddKeyEvent(ImGuiKey.ModSuper, (mod & SDL.Keymod.GUI) != 0);
}
public class ImGui_ImplSDL3_ViewportData : ViewPortData { }
public class ViewPortData
{
public nint Window;
public nint Renderer;
public nint ParentWindow;
public uint WindowID; // Stored in ImGuiViewport.PlatformHandle. Use SDL.GetWindowFromID() to get SDL.Window* from Uint32 WindowID.
public bool WindowOwned;
public bool RendererOwned;
}
private static void InitMultiViewportSupport(nint window)
{
ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO();
platformIO.PlatformCreateWindow = DelegateStorage.CreateWindowDelegate.GetPtrForDelegate();
platformIO.PlatformDestroyWindow = DelegateStorage.DestroyWindowDelegate.GetPtrForDelegate();
platformIO.PlatformShowWindow = DelegateStorage.ShowWindowDelegate.GetPtrForDelegate();
platformIO.PlatformSetWindowPos = DelegateStorage.SetWindowPosDelegate.GetPtrForDelegate();
platformIO.PlatformGetWindowPos = DelegateStorage.GetWindowPosDelegate.GetPtrForDelegate();
platformIO.PlatformSetWindowSize = DelegateStorage.SetWindowSizeDelegate.GetPtrForDelegate();
platformIO.PlatformGetWindowSize = DelegateStorage.GetWindowSizeDelegate.GetPtrForDelegate();
platformIO.PlatformSetWindowFocus = DelegateStorage.SetWindowFocusDelegate.GetPtrForDelegate();
platformIO.PlatformGetWindowFocus = DelegateStorage.GetWindowFocusDelegate.GetPtrForDelegate();
platformIO.PlatformGetWindowMinimized = DelegateStorage.GetWindowMinimizedDelegate.GetPtrForDelegate();
platformIO.PlatformSetWindowTitle = DelegateStorage.SetWindowTitleDelegate.GetPtrForDelegate();
platformIO.PlatformSetWindowAlpha = DelegateStorage.SetWindowAlphaDelegate.GetPtrForDelegate();
platformIO.PlatformUpdateWindow = DelegateStorage.UpdateWindowDelegate.GetPtrForDelegate();
platformIO.PlatformGetWindowFramebufferScale = DelegateStorage.GetWindowFramebufferScaleDelegate.GetPtrForDelegate();
ImGuiViewportPtr mainViewport = ImGui.GetMainViewport();
ViewPortData vd = new ViewPortData
{
Window = window,
Renderer = GetPlatformData().Renderer,
WindowID = SDL.GetWindowID(window),
WindowOwned = false,
RendererOwned = false
};
mainViewport.PlatformUserData = ImGuiUserData.Store(vd);
mainViewport.PlatformHandle = (void*)(nint)SDL.GetWindowID(window);
#if WINDOWS
mainViewport.PlatformHandleRaw = SDL.GetPointerProperty(
SDL.GetWindowProperties(window),
SDL.Properties.WindowWin32HWNDPointer,
nint.Zero
).ToPointer();
#endif
}
public static ImGuiViewportPtr? GetViewportForWindowId(uint id)
{
return ImGui.FindViewportByPlatformHandle((void*)(nint)id);
}
private static nint GetSDLWindowFromViewport(ImGuiViewportPtr viewport)
{
return SDL.GetWindowFromID((uint)(nint)viewport.PlatformHandle);
}
private static void SetupPlatformHandles(ImGuiViewportPtr viewport, nint window)
{
viewport.PlatformHandle = (void*)(nint)SDL.GetWindowID(window);
viewport.PlatformHandleRaw = (void*)nint.Zero;
#if _WIN32 && !__WINTR__
SDL.GetPointerProperty(SDL.GetWindowProperties(window), SDL.Props.WindowWin32HWNDPointer, 0);
#elif __APPLE__ && SDL_VIDEO_DRIVER_COCOA
SDL.GetPointerProperty(SDL.GetWindowProperties(window), SDL.Props.WindowCocoaWindow, 0);
#endif
}
public static void Dispose()
{
PlatformData? data = GetPlatformData();
if (data != null)
{
if (data.ClipboardTextData != nint.Zero)
{
Marshal.FreeHGlobal(data.ClipboardTextData);
data.ClipboardTextData = nint.Zero;
}
foreach (nint cursor in data.MouseCursors)
{
if (cursor != nint.Zero)
SDL.DestroyCursor(cursor);
}
}
ImGuiIOPtr io = ImGui.GetIO();
ImGuiPlatformIOPtr platformIo = ImGui.GetPlatformIO();
platformIo.PlatformGetClipboardTextFn = null;
platformIo.PlatformSetClipboardTextFn = null;
platformIo.PlatformSetImeDataFn = null;
platformIo.PlatformOpenInShellFn = null;
ImGuiUserData.Free(io.BackendPlatformUserData);
io.BackendPlatformUserData = null;
}
// @formatter:off — disable formatter after this line
public static class DelegateStorage
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate nint PlatformGetClipboardTextFn(nint ctx);
internal static readonly PlatformGetClipboardTextFn GetClipboardDelegate = GetClipboardText;
private static nint GetClipboardText(nint ctx)
{
PlatformData data = GetPlatformData();
if (data.ClipboardTextData != nint.Zero)
{
Marshal.FreeHGlobal(data.ClipboardTextData);
data.ClipboardTextData = nint.Zero;
}
string text = SDL.GetClipboardText();
data.ClipboardTextData = Marshal.StringToHGlobalAnsi(text ?? string.Empty);
return data.ClipboardTextData;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void PlatformSetClipboardTextFn(nint ctx, nint text);
internal static readonly PlatformSetClipboardTextFn SetClipboardDelegate = SetClipboardText;
private static void SetClipboardText(nint ctx, nint text)
{
string? managedText = Marshal.PtrToStringAnsi(text);
if (managedText != null)
{
SDL.SetClipboardText(managedText);
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void PlatformSetImeDataFn(nint ctx, nint userData, nint imeData);
internal static readonly PlatformSetImeDataFn SetImeDataDelegate = SetImeData;
private static void SetImeData(nint ctx, nint userData, nint imeData)
{
PlatformData data = GetPlatformData();
data.ImeData = Marshal.PtrToStructure(imeData);
data.ImeDirty = true;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool PlatformOpenInShellFn(nint ctx, nint url);
internal static readonly PlatformOpenInShellFn OpenInShellDelegate = OpenInShell;
private static bool OpenInShell(nint ctx, nint url)
{
string managedUrl = Marshal.PtrToStringUTF8(url) ?? string.Empty;
return SDL.OpenURL(managedUrl);
}
// // // // // // // // // // // // // //
// Below is for Multi-Viewport Support //
// //
// // // // // // // // // // // // // //
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void CreateWindowDelegateFn(ImGuiViewportPtr ctx);
internal static readonly CreateWindowDelegateFn CreateWindowDelegate = CreateWindow;
private static void CreateWindow(ImGuiViewportPtr viewport)
{
PlatformData bd = GetPlatformData();
ViewPortData vd = new ViewPortData();
viewport.PlatformUserData = ImGuiUserData.Store(vd);
SDL.WindowFlags flags = SDL.WindowFlags.Hidden;
flags |= SDL.GetWindowFlags(bd.Window) & SDL.WindowFlags.HighPixelDensity;
if (viewport.Flags.HasFlag(ImGuiViewportFlags.NoDecoration))
flags |= SDL.WindowFlags.Borderless;
else
flags |= SDL.WindowFlags.Resizable;
if (viewport.Flags.HasFlag(ImGuiViewportFlags.NoTaskBarIcon))
flags |= SDL.WindowFlags.Utility;
if (viewport.Flags.HasFlag(ImGuiViewportFlags.TopMost))
flags |= SDL.WindowFlags.AlwaysOnTop;
vd.Window = SDL.CreateWindow("Untitled", (int)viewport.Size.X, (int)viewport.Size.Y, flags);
ImGuiViewportPtr? parentViewport = viewport.ParentViewportId != 0 ? ImGui.FindViewportByID(viewport.ParentViewportId) : null;
if (parentViewport != null && parentViewport.Value.Handle != null)
{
vd.ParentWindow = GetSDLWindowFromViewport(parentViewport.Value);
if (vd.ParentWindow != nint.Zero)
SDL.SetWindowParent(vd.Window, vd.ParentWindow);
}
SDL.SetWindowPosition(vd.Window, (int)viewport.Pos.X, (int)viewport.Pos.Y);
vd.WindowOwned = true;
SetupPlatformHandles(viewport, vd.Window);
Program.Logger.Log($"New SDL Viewport: {vd.Window} {vd.WindowID} {viewport.Pos.X} {viewport.Pos.Y} {viewport.Size.X} {viewport.Size.Y}");
#if WINDOWS
viewport.PlatformHandleRaw = SDL.GetPointerProperty(
SDL.GetWindowProperties(vd.Window),
SDL.Properties.WindowWin32HWNDPointer,
nint.Zero
).ToPointer();
#endif
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void DestroyWindowDelegateFn(ImGuiViewportPtr ctx);
internal static readonly DestroyWindowDelegateFn DestroyWindowDelegate = DestroyWindow;
private static void DestroyWindow(ImGuiViewportPtr viewport)
{
ViewPortData? vd = ImGuiUserData.Get(viewport.PlatformUserData);
if (vd != null)
{
if (vd.Window != nint.Zero && vd.WindowOwned)
{
SDL.DestroyWindow(vd.Window);
}
}
ImGuiUserData.Free(viewport.PlatformUserData);
viewport.PlatformUserData = null;
viewport.PlatformHandle = null;
viewport.PlatformHandleRaw = null;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void ShowWindowDelegateFn(ImGuiViewportPtr ctx);
internal static readonly ShowWindowDelegateFn ShowWindowDelegate = ShowWindow;
private static void ShowWindow(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
string oldHint = SDL.GetHint(SDL.Hints.WindowActivateWhenShown)!;
SDL.SetHint(SDL.Hints.WindowActivateWhenShown, (viewport.Flags & ImGuiViewportFlags.NoFocusOnAppearing) != 0 ? "0" : "1");
SDL.ShowWindow(vd.Window);
SDL.SetHint(SDL.Hints.WindowActivateWhenShown, oldHint);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void UpdateWindowDelegateFn(ImGuiViewportPtr ctx);
internal static readonly UpdateWindowDelegateFn UpdateWindowDelegate = UpdateWindow;
private static void UpdateWindow(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
if ((viewport.Flags & ImGuiViewportFlags.TopMost) != 0)
{
SDL.SetWindowAlwaysOnTop(vd.Window, true);
}
else
{
SDL.SetWindowAlwaysOnTop(vd.Window, false);
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SetWindowPosDelegateFn(ImGuiViewportPtr ctx, Vector2 pos);
internal static readonly SetWindowPosDelegateFn SetWindowPosDelegate = SetWindowPos;
private static void SetWindowPos(ImGuiViewportPtr viewport, Vector2 pos)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.SetWindowPosition(vd.Window, (int)pos.X, (int)pos.Y);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Vector2 GetWindowPosDelegateFn(ImGuiViewportPtr ctx);
internal static readonly GetWindowPosDelegateFn GetWindowPosDelegate = GetWindowPos;
private static Vector2 GetWindowPos(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.GetWindowPosition(vd.Window, out int x, out int y);
return new Vector2(x, y);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SetWindowSizeDelegateFn(ImGuiViewportPtr ctx, Vector2 size);
internal static readonly SetWindowSizeDelegateFn SetWindowSizeDelegate = SetWindowSize;
private static void SetWindowSize(ImGuiViewportPtr viewport, Vector2 size)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.SetWindowSize(vd.Window, (int)size.X, (int)size.Y);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Vector2 GetWindowSizeDelegateFn(ImGuiViewportPtr ctx);
internal static readonly GetWindowSizeDelegateFn GetWindowSizeDelegate = GetWindowSize;
private static Vector2 GetWindowSize(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.GetWindowSize(vd.Window, out int w, out int h);
return new Vector2(w, h);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Vector2 GetWindowFramebufferScaleDelegateFn(ImGuiViewportPtr ctx);
internal static readonly GetWindowFramebufferScaleDelegateFn GetWindowFramebufferScaleDelegate = GetWindowFramebufferScale;
private static Vector2 GetWindowFramebufferScale(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
GetWindowSizeAndFramebufferScale(vd.Window, out Vector2 _, out Vector2 framebufferScale);
return framebufferScale;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SetWindowFocusDelegateFn(ImGuiViewportPtr ctx);
internal static readonly SetWindowFocusDelegateFn SetWindowFocusDelegate = SetWindowFocus;
private static void SetWindowFocus(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.RaiseWindow(vd.Window);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool GetWindowFocusDelegateFn(ImGuiViewportPtr ctx);
internal static readonly GetWindowFocusDelegateFn GetWindowFocusDelegate = GetWindowFocus;
private static bool GetWindowFocus(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
return (SDL.GetWindowFlags(vd.Window) & SDL.WindowFlags.InputFocus) != 0;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate bool GetWindowMinimizedDelegateFn(ImGuiViewportPtr ctx);
internal static readonly GetWindowMinimizedDelegateFn GetWindowMinimizedDelegate = GetWindowMinimized;
private static bool GetWindowMinimized(ImGuiViewportPtr viewport)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
return (SDL.GetWindowFlags(vd.Window) & SDL.WindowFlags.Minimized) != 0;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SetWindowTitleDelegateFn(ImGuiViewportPtr ctx, string title);
internal static readonly SetWindowTitleDelegateFn SetWindowTitleDelegate = SetWindowTitle;
private static void SetWindowTitle(ImGuiViewportPtr viewport, string title)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.SetWindowTitle(vd.Window, title);
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void SetWindowAlphaDelegateFn(ImGuiViewportPtr ctx, float alpha);
internal static readonly SetWindowAlphaDelegateFn SetWindowAlphaDelegate = SetWindowAlpha;
private static void SetWindowAlpha(ImGuiViewportPtr viewport, float alpha)
{
ViewPortData vd = ImGuiUserData.Get(viewport.PlatformUserData)!;
SDL.SetWindowOpacity(vd.Window, alpha);
}
}
// @formatter:on — enable formatter after this line
}
public enum GamepadMode
{
AutoFirst,
AutoAll,
Manual
}
public enum MouseCaptureMode
{
Enabled,
EnabledAfterDrag,
Disabled
}