From 8a6db1c401b59582d1fb06d11f671455329978e9 Mon Sep 17 00:00:00 2001 From: Nemirtingas Date: Sat, 31 Aug 2019 20:49:20 +0200 Subject: [PATCH] ImGui X11 impl --- ImGui/impls/imgui_impl_x11.cpp | 302 +++++++++++++++++++++++++++++++++ ImGui/impls/imgui_impl_x11.h | 21 +++ 2 files changed, 323 insertions(+) create mode 100644 ImGui/impls/imgui_impl_x11.cpp create mode 100644 ImGui/impls/imgui_impl_x11.h diff --git a/ImGui/impls/imgui_impl_x11.cpp b/ImGui/impls/imgui_impl_x11.cpp new file mode 100644 index 00000000..1065ae4a --- /dev/null +++ b/ImGui/impls/imgui_impl_x11.cpp @@ -0,0 +1,302 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [?] Platform: Clipboard support +// [?] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [?] Platform: Keyboard arrays indexed using +// [?] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#include "imgui.h" +#include "imgui_impl_x11.h" + +#include +#include +#include +#include + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2019-08-31: Initial X11 implementation + +// X11 Data +static Display* g_Display = nullptr; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; +static bool g_HasGamepad = false; +static bool g_WantUpdateHasGamepad = true; + +// Functions +bool ImGui_ImplX11_Init(void *display) +{ + //if (!::QueryPerformanceFrequency((LARGE_INTEGER *)&g_TicksPerSecond)) + // return false; + //if (!::QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) + // return false; + + // Setup back-end capabilities flags + g_Display = reinterpret_cast(display); + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_x11"; + io.ImeWindowHandle = nullptr; + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_Tab] = -1; + io.KeyMap[ImGuiKey_LeftArrow] = -1; + io.KeyMap[ImGuiKey_RightArrow] = -1; + io.KeyMap[ImGuiKey_UpArrow] = -1; + io.KeyMap[ImGuiKey_DownArrow] = -1; + io.KeyMap[ImGuiKey_PageUp] = -1; + io.KeyMap[ImGuiKey_PageDown] = -1; + io.KeyMap[ImGuiKey_Home] = -1; + io.KeyMap[ImGuiKey_End] = -1; + io.KeyMap[ImGuiKey_Insert] = -1; + io.KeyMap[ImGuiKey_Delete] = -1; + io.KeyMap[ImGuiKey_Backspace] = -1; + io.KeyMap[ImGuiKey_Space] = -1; + io.KeyMap[ImGuiKey_Enter] = -1; + io.KeyMap[ImGuiKey_Escape] = -1; + io.KeyMap[ImGuiKey_A] = -1; + io.KeyMap[ImGuiKey_C] = -1; + io.KeyMap[ImGuiKey_V] = -1; + io.KeyMap[ImGuiKey_X] = -1; + io.KeyMap[ImGuiKey_Y] = -1; + io.KeyMap[ImGuiKey_Z] = -1; + return true; +} + +void ImGui_ImplX11_Shutdown() +{ + g_Display = nullptr; +} + +static bool ImGui_ImplWin32_UpdateMouseCursor() +{ + /* + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return false; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } + else + { + // Show OS mouse cursor + LPTSTR win32_cursor = IDC_ARROW; + switch (imgui_cursor) + { + case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; + case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; + case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; + case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; + case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; + case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; + case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } + */ + return true; +} + +static void ImGui_ImplWin32_UpdateMousePos() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + //if (io.WantSetMousePos) + //{ + // POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + // ::ClientToScreen(g_hWnd, &pos); + // ::SetCursorPos(pos.x, pos.y); + //} + + // Set mouse position + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + + +} + +/* TODO: support linux gamepad ? +#ifdef _MSC_VER +#pragma comment(lib, "xinput") +#endif + +// Gamepad navigation mapping +static void ImGui_ImplWin32_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (g_WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps; + g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); + g_WantUpdateHasGamepad = false; + } + + XINPUT_STATE xinput_state; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) + { + const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } + #define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } + MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); + #undef MAP_BUTTON + #undef MAP_ANALOG + } +} +*/ + +void ImGui_ImplX11_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + Window rootWnd = DefaultRootWindow(g_Display); + + // Todo: use X11 to get this value + GLint m_viewport[4]; + glGetIntegerv( GL_VIEWPORT, m_viewport ); + io.DisplaySize.x = m_viewport[2]; + io.DisplaySize.y = m_viewport[3]; + + + /* + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + + // Setup time step + INT64 current_time; + ::QueryPerformanceCounter((LARGE_INTEGER *)¤t_time); + io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; + g_Time = current_time; + + // Read keyboard modifiers inputs + io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0; + io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0; + io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0; + io.KeySuper = false; + // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below. + + // Update OS mouse position + ImGui_ImplWin32_UpdateMousePos(); + + // Update OS mouse cursor with the cursor requested by imgui + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (g_LastMouseCursor != mouse_cursor) + { + g_LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } + */ + + // Update game controllers (if enabled and available) + //ImGui_ImplWin32_UpdateGamepads(); +} + +// Process Win32 mouse/keyboard inputs. +// 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. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent &event) +{ + if (ImGui::GetCurrentContext() == NULL) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + switch (event.type) + { + case ButtonPress: + switch(event.xbutton.button ) + { + case Button1: case Button2: case Button3: + io.MouseDown[event.xbutton.button-1] = true; + break; + + case Button4: // Mouse wheel up + event.xbutton.button = Button4; + //io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + + case Button5: // Mouse wheel down + event.xbutton.button = Button5; + //io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA; + return 0; + } + + break; + + case ButtonRelease: + switch(event.xbutton.button ) + { + case Button1: case Button2: case Button3: + io.MouseDown[event.xbutton.button-1] = false; + break; + } + break; + + case KeyPress: + case KeyRelease: + break; + + case MotionNotify: + io.MousePos.x = event.xmotion.x; + io.MousePos.y = event.xmotion.y; + break; + } + /* + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (wParam < 256) + io.KeysDown[wParam] = 1; + return 0; + case WM_KEYUP: + case WM_SYSKEYUP: + if (wParam < 256) + io.KeysDown[wParam] = 0; + return 0; + case WM_CHAR: + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + io.AddInputCharacter((unsigned int)wParam); + return 0; + case WM_DEVICECHANGE: + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + g_WantUpdateHasGamepad = true; + return 0; + } + */ + return 0; +} + diff --git a/ImGui/impls/imgui_impl_x11.h b/ImGui/impls/imgui_impl_x11.h new file mode 100644 index 00000000..387609a3 --- /dev/null +++ b/ImGui/impls/imgui_impl_x11.h @@ -0,0 +1,21 @@ +// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core imgui) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + +#pragma once + +IMGUI_IMPL_API bool ImGui_ImplX11_Init(void* display); +IMGUI_IMPL_API void ImGui_ImplX11_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplX11_NewFrame(); + +// Handler for Win32 messages, update mouse/keyboard data. +// You may or not need this for your implementation, but it can serve as reference for handling inputs. +// Intentionally commented out to avoid dragging dependencies on types. You can COPY this line into your .cpp code instead. +/* +IMGUI_IMPL_API int ImGui_ImplX11_EventHandler(XEvent *event); +*/