Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_glfw.cpp
#	backends/imgui_impl_sdl.cpp
#	backends/imgui_impl_vulkan.cpp
#	backends/imgui_impl_vulkan.h
#	backends/imgui_impl_win32.cpp
#	imgui.cpp
#	imgui.h
#	imgui_demo.cpp
#	imgui_internal.h
docking
ocornut 3 years ago
commit 3e0d6ec895

@ -7,8 +7,7 @@
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. // Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. // See imgui_impl_dx12.cpp file for details.
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // 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. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

@ -21,6 +21,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates. // 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). // 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
@ -83,13 +84,14 @@
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
#else #else
#define GLFW_HAS_NEW_CURSORS (0) #define GLFW_HAS_NEW_CURSORS (0)
#endif #endif
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough) #ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH #define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
#else #else
#define GLFW_HAS_MOUSE_PASSTHROUGH (0) #define GLFW_HAS_MOUSE_PASSTHROUGH (0)
#endif #endif
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName() #define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
// GLFW data // GLFW data
@ -629,41 +631,57 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
} }
} }
// Update gamepad inputs
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
static void ImGui_ImplGlfw_UpdateGamepads() static void ImGui_ImplGlfw_UpdateGamepads()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return; return;
// Update gamepad inputs io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
#define MAP_BUTTON(NAV_NO, BUTTON_NO) do { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } while (0) #if GLFW_HAS_GAMEPAD_API
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } while (0) GLFWgamepadstate gamepad;
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
return;
#define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
#define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
#else
int axes_count = 0, buttons_count = 0; int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A if (axes_count == 0 || buttons_count == 0)
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B return;
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left #endif
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
#undef MAP_BUTTON #undef MAP_BUTTON
#undef MAP_ANALOG #undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
} }
static void ImGui_ImplGlfw_UpdateMonitors() static void ImGui_ImplGlfw_UpdateMonitors()

@ -25,6 +25,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-12: Inputs: Added basic Platform IME support, hooking the io.SetPlatformImeDataFn() function. // 2022-01-12: Inputs: Added basic Platform IME support, hooking the io.SetPlatformImeDataFn() function.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
@ -504,25 +505,43 @@ static void ImGui_ImplOSX_UpdateGamepads()
GCExtendedGamepad* gp = controller.extendedGamepad; GCExtendedGamepad* gp = controller.extendedGamepad;
#define MAP_BUTTON(NAV_NO, NAME) { io.NavInputs[NAV_NO] = gp.NAME.isPressed ? 1.0 : 0.0; } // Update gamepad inputs
MAP_BUTTON(ImGuiNavInput_Activate, buttonA); #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
MAP_BUTTON(ImGuiNavInput_Cancel, buttonB); #define MAP_BUTTON(KEY_NO, BUTTON_NAME) { io.AddKeyEvent(KEY_NO, gp.BUTTON_NAME.isPressed); }
MAP_BUTTON(ImGuiNavInput_Menu, buttonX); #define MAP_ANALOG(KEY_NO, AXIS_NAME, V0, V1) { float vn = (float)(gp.AXIS_NAME.value - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
MAP_BUTTON(ImGuiNavInput_Input, buttonY); const float thumb_dead_zone = 0.0f;
MAP_BUTTON(ImGuiNavInput_DpadLeft, dpad.left); if (@available(macOS 10.15, *))
MAP_BUTTON(ImGuiNavInput_DpadRight, dpad.right); {
MAP_BUTTON(ImGuiNavInput_DpadUp, dpad.up); MAP_BUTTON(ImGuiKey_GamepadStart, buttonMenu);
MAP_BUTTON(ImGuiNavInput_DpadDown, dpad.down); MAP_BUTTON(ImGuiKey_GamepadBack, buttonOptions);
MAP_BUTTON(ImGuiNavInput_FocusPrev, leftShoulder); }
MAP_BUTTON(ImGuiNavInput_FocusNext, rightShoulder); MAP_BUTTON(ImGuiKey_GamepadFaceDown, buttonA); // Xbox A, PS Cross
MAP_BUTTON(ImGuiNavInput_TweakSlow, leftShoulder); MAP_BUTTON(ImGuiKey_GamepadFaceRight, buttonB); // Xbox B, PS Circle
MAP_BUTTON(ImGuiNavInput_TweakFast, rightShoulder); MAP_BUTTON(ImGuiKey_GamepadFaceLeft, buttonX); // Xbox X, PS Square
#undef MAP_BUTTON MAP_BUTTON(ImGuiKey_GamepadFaceUp, buttonY); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, dpad.left);
io.NavInputs[ImGuiNavInput_LStickLeft] = gp.leftThumbstick.left.value; MAP_BUTTON(ImGuiKey_GamepadDpadRight, dpad.right);
io.NavInputs[ImGuiNavInput_LStickRight] = gp.leftThumbstick.right.value; MAP_BUTTON(ImGuiKey_GamepadDpadUp, dpad.up);
io.NavInputs[ImGuiNavInput_LStickUp] = gp.leftThumbstick.up.value; MAP_BUTTON(ImGuiKey_GamepadDpadDown, dpad.down);
io.NavInputs[ImGuiNavInput_LStickDown] = gp.leftThumbstick.down.value; MAP_ANALOG(ImGuiKey_GamepadL1, leftShoulder, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadR1, rightShoulder, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadL2, leftTrigger, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadR2, rightTrigger, 0.0f, 1.0f);
if (@available(macOS 10.14.1, *))
{
MAP_BUTTON(ImGuiKey_GamepadL3, leftThumbstickButton);
MAP_BUTTON(ImGuiKey_GamepadR3, rightThumbstickButton);
}
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, leftThumbstick.xAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, leftThumbstick.xAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, leftThumbstick.yAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, leftThumbstick.yAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, rightThumbstick.xAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, rightThumbstick.xAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, rightThumbstick.yAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, rightThumbstick.yAxis, -thumb_dead_zone, -1.0f);
#undef MAP_BUTTON
#undef MAP_ANALOG
io.BackendFlags |= ImGuiBackendFlags_HasGamepad; io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
} }

@ -21,6 +21,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates. // 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. // 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
@ -559,40 +560,45 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
static void ImGui_ImplSDL2_UpdateGamepads() static void ImGui_ImplSDL2_UpdateGamepads()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return; return;
// Get gamepad // Get gamepad
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
SDL_GameController* game_controller = SDL_GameControllerOpen(0); SDL_GameController* game_controller = SDL_GameControllerOpen(0);
if (!game_controller) if (!game_controller)
{
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
return; return;
} io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
// Update gamepad inputs // Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; } #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - 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; } #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); }
#define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
io.BackendFlags |= ImGuiBackendFlags_HasGamepad; MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
#undef MAP_BUTTON #undef MAP_BUTTON
#undef MAP_ANALOG #undef MAP_ANALOG
} }

@ -4,8 +4,15 @@
// Implemented features: // Implemented features:
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). // [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// Missing features: // [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// To build this on 32-bit systems and support texture changes:
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files)
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // 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. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -59,6 +66,11 @@
#include "imgui_impl_vulkan.h" #include "imgui_impl_vulkan.h"
#include <stdio.h> #include <stdio.h>
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#endif
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
// [Please zero-clear before use!] // [Please zero-clear before use!]
struct ImGui_ImplVulkanH_FrameRenderBuffers struct ImGui_ImplVulkanH_FrameRenderBuffers
@ -101,7 +113,6 @@ struct ImGui_ImplVulkan_Data
VkPipelineCreateFlags PipelineCreateFlags; VkPipelineCreateFlags PipelineCreateFlags;
VkDescriptorSetLayout DescriptorSetLayout; VkDescriptorSetLayout DescriptorSetLayout;
VkPipelineLayout PipelineLayout; VkPipelineLayout PipelineLayout;
VkDescriptorSet DescriptorSet;
VkPipeline Pipeline; VkPipeline Pipeline;
uint32_t Subpass; uint32_t Subpass;
VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleVert;
@ -112,6 +123,7 @@ struct ImGui_ImplVulkan_Data
VkDeviceMemory FontMemory; VkDeviceMemory FontMemory;
VkImage FontImage; VkImage FontImage;
VkImageView FontView; VkImageView FontView;
VkDescriptorSet FontDescriptorSet;
VkDeviceMemory UploadBufferMemory; VkDeviceMemory UploadBufferMemory;
VkBuffer UploadBuffer; VkBuffer UploadBuffer;
@ -406,11 +418,9 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
{ {
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
// Bind pipeline and descriptor sets: // Bind pipeline:
{ {
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
VkDescriptorSet desc_set[1] = { bd->DescriptorSet };
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL);
} }
// Bind Vertex And Index Buffer: // Bind Vertex And Index Buffer:
@ -563,6 +573,16 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y); scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
vkCmdSetScissor(command_buffer, 0, 1, &scissor); vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Bind DescriptorSet with font or user texture
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
if (sizeof(ImTextureID) < sizeof(ImU64))
{
// We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
desc_set[0] = bd->FontDescriptorSet;
}
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL);
// Draw // Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
} }
@ -639,20 +659,8 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
check_vk_result(err); check_vk_result(err);
} }
// Update the Descriptor Set: // Create the Descriptor Set:
{ bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = bd->FontSampler;
desc_image[0].imageView = bd->FontView;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = bd->DescriptorSet;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Upload Buffer: // Create the Upload Buffer:
{ {
@ -730,7 +738,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
} }
// Store our identifier // Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontImage); io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet);
return true; return true;
} }
@ -969,17 +977,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
check_vk_result(err); check_vk_result(err);
} }
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &bd->DescriptorSet);
check_vk_result(err);
}
if (!bd->PipelineLayout) if (!bd->PipelineLayout)
{ {
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
@ -1143,6 +1140,41 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
bd->VulkanInitInfo.MinImageCount = min_image_count; bd->VulkanInitInfo.MinImageCount = min_image_count;
} }
// Register a texture
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
// Create Descriptor Set:
VkDescriptorSet descriptor_set;
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
check_vk_result(err);
}
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = sampler;
desc_image[0].imageView = image_view;
desc_image[0].imageLayout = image_layout;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = descriptor_set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
return descriptor_set;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers // Internal / Miscellaneous Vulkan Helpers

@ -3,9 +3,11 @@
// Implemented features: // Implemented features:
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Missing features: // [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// [ ] Platform: Multi-viewport / platform windows. // [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
// See imgui_impl_vulkan.cpp file for details.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // 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. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -63,17 +65,21 @@ struct ImGui_ImplVulkan_InitInfo
}; };
// Called by user code // Called by user code
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer); IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects(); IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
// Register a texture (VkDescriptorSet == ImTextureID)
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
// Optional: load Vulkan functions with a custom function loader // Optional: load Vulkan functions with a custom function loader
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES // This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL); IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers // Internal / Miscellaneous Vulkan Helpers

@ -36,6 +36,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before a key event (not in NewFrame) to fix input queue with very low framerates. // 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before a key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. // 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
@ -320,7 +321,6 @@ static void ImGui_ImplWin32_UpdateGamepads()
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return; return;
@ -328,39 +328,47 @@ static void ImGui_ImplWin32_UpdateGamepads()
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
if (bd->WantUpdateHasGamepad) if (bd->WantUpdateHasGamepad)
{ {
XINPUT_CAPABILITIES caps; XINPUT_CAPABILITIES caps = {};
bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
bd->WantUpdateHasGamepad = false; bd->WantUpdateHasGamepad = false;
} }
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
XINPUT_STATE xinput_state; XINPUT_STATE xinput_state;
if (bd->HasGamepad && bd->XInputGetState && bd->XInputGetState(0, &xinput_state) == ERROR_SUCCESS) XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
{ if (!bd->HasGamepad || bd->XInputGetState == NULL || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad; io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; } #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#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; } #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A #define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767); MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);
#undef MAP_BUTTON MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);
#undef MAP_ANALOG MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
} MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
#undef MAP_BUTTON
#undef MAP_ANALOG
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
} }

@ -105,6 +105,9 @@ Other changes:
Breaking Changes: Breaking Changes:
- Removed support for pre-C++11 compilers. We'll stop supporting VS2010. (#4537) - Removed support for pre-C++11 compilers. We'll stop supporting VS2010. (#4537)
- Removed support for legacy arithmetic operators (+,+-,*,/) when inputing text into a slider/drag. (#4917, #3184)
This doesn't break any api/code but a feature that was accessible by end-users (which seemingly no one used).
(Instead you may implement custom expression evaluators to provide a better version of this).
- Reworked IO mouse input API: (#4858) [@thedmd, @ocornut] - Reworked IO mouse input API: (#4858) [@thedmd, @ocornut]
- Added io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions, - Added io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions,
obsoleting writing directly to io.MousePos, io.MouseDown[], io.MouseWheel, etc. obsoleting writing directly to io.MousePos, io.MouseDown[], io.MouseWheel, etc.
@ -118,7 +121,7 @@ Breaking Changes:
- Obsoleted GetKeyIndex(): it is now unnecessary and will now return the same value. - Obsoleted GetKeyIndex(): it is now unnecessary and will now return the same value.
- All keyboard related functions taking 'int user_key_index' now take 'ImGuiKey key': - All keyboard related functions taking 'int user_key_index' now take 'ImGuiKey key':
- IsKeyDown(), IsKeyPressed(), IsKeyReleased(), GetKeyPressedAmount(). - IsKeyDown(), IsKeyPressed(), IsKeyReleased(), GetKeyPressedAmount().
- Added io.ConfigInputEventQueue (defaulting to true) to disable input queue trickling. - Added io.ConfigInputTrickleEventQueue (defaulting to true) to disable input queue trickling.
- Backward compatibility: - Backward compatibility:
- All backends updated to use new functions. - All backends updated to use new functions.
- Old backends populating those arrays should still work! - Old backends populating those arrays should still work!
@ -140,6 +143,10 @@ Breaking Changes:
- Access to full key ranges will allow us to develop a proper keyboard shortcut system. (#456) - Access to full key ranges will allow us to develop a proper keyboard shortcut system. (#456)
- io.AddKeyEvent() will later be turned into a trickling IO queue (for all inputs) to handle very low framerate better. (#2525, #2787, #3383) - io.AddKeyEvent() will later be turned into a trickling IO queue (for all inputs) to handle very low framerate better. (#2525, #2787, #3383)
- io.SetKeyEventNativeData() include native keycode/scancode which will later be exposed. (#3141, #2959) - io.SetKeyEventNativeData() include native keycode/scancode which will later be exposed. (#3141, #2959)
- Reworked IO nav/gamepad input API and unifying inputs sources: (#4858, #787)
- Added full range of ImGuiKey_GamepadXXXX enums (e.g. ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadR2) to use with
io.AddKeyEvent(), io.AddKeyAnalogEvent().
- Added io.AddKeyAnalogEvent() function, obsoleting writing directly to io.NavInputs[] arrays.
- Renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. (#2625) - Renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. (#2625)
- Backends: GLFW: backend now uses glfwSetCursorPosCallback(). - Backends: GLFW: backend now uses glfwSetCursorPosCallback().
- If calling ImGui_ImplGlfw_InitXXX with install_callbacks=true: nothing to do. is already done for you. - If calling ImGui_ImplGlfw_InitXXX with install_callbacks=true: nothing to do. is already done for you.
@ -164,10 +171,15 @@ Other Changes:
- IO: Added event based input queue API, which now trickles events to support low framerates. [@thedmd, @ocornut] - IO: Added event based input queue API, which now trickles events to support low framerates. [@thedmd, @ocornut]
Previously the most common issue case (button presses in low framerates) was handled by backend. This is now Previously the most common issue case (button presses in low framerates) was handled by backend. This is now
handled by core automatically for all kind of inputs. (#4858, #2787, #1992, #3383, #2525, #1320) handled by core automatically for all kind of inputs. (#4858, #2787, #1992, #3383, #2525, #1320)
- New IO functions for keyboard/gamepad: AddKeyEvent(), AddKeyAnalogEvent(), AddKeyModsEvent().
- New IO functions for mouse: AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent().
- Fixed a situation where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with zero triangles, - Fixed a situation where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with zero triangles,
which would makes the draw operation of some backends assert (e.g. Metal with debugging). (#4857) which would makes the draw operation of some backends assert (e.g. Metal with debugging). (#4857)
- Popups: Fixed a regression crash when a new window is created after a modal on the same frame. (#4920) [@rokups]
- Tables, ImDrawListSplitter: Fixed erroneously stripping trailing ImDrawList::AddCallback() when submitted in - Tables, ImDrawListSplitter: Fixed erroneously stripping trailing ImDrawList::AddCallback() when submitted in
last column or last channel and when there are no other drawing operation. (#4843, #4844) [@hoffstadt] last column or last channel and when there are no other drawing operation. (#4843, #4844) [@hoffstadt]
- Tables: Fixed positioning of Sort icon on right-most column with some settings (not resizable + no borders). (#4918).
- Sliders, Drags: Fixed text input of values with a leading sign, common when using a format enforcing sign. (#4917)
- Platform IME: changed io.ImeSetInputScreenPosFn() to io.SetPlatformImeDataFn() API, - Platform IME: changed io.ImeSetInputScreenPosFn() to io.SetPlatformImeDataFn() API,
now taking a ImGuiPlatformImeData structure which we can more easily extend in the future. now taking a ImGuiPlatformImeData structure which we can more easily extend in the future.
- Platform IME: moved io.ImeWindowHandle to GetMainViewport()->PlatformHandleRaw. - Platform IME: moved io.ImeWindowHandle to GetMainViewport()->PlatformHandleRaw.
@ -180,17 +192,21 @@ Other Changes:
- Backends: GLFW: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: GLFW: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: GLFW: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858) - Backends: GLFW: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: GLFW: Update mouse position using glfwSetCursorPosCallback() + fallback when focused but not hovered/captured. - Backends: GLFW: Update mouse position using glfwSetCursorPosCallback() + fallback when focused but not hovered/captured.
- Backends: GLFW: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4858)
- Backends: Win32: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: Win32: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: Win32: Update mouse position using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback when focused but not hovered/captured. - Backends: Win32: Update mouse position using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback when focused but not hovered/captured.
- Backends: Win32: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858) - Backends: Win32: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: Win32: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. - Backends: Win32: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
- Backends: Win32: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4858)
- Backends: SDL: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. - Backends: SDL: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts.
- Backends: SDL: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: SDL: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: SDL: Update mouse position using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback when focused but not hovered/captured. - Backends: SDL: Update mouse position using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback when focused but not hovered/captured.
- Backends: SDL: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858) - Backends: SDL: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: SDL: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. - Backends: SDL: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
- Backends: SDL: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4858)
- Backends: Allegro5: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: Allegro5: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: Allegro5: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858) - Backends: Allegro5: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: OSX: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4858)
- Backends: Android, GLUT, OSX: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625) - Backends: Android, GLUT, OSX: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: Android, GLUT, OSX: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858) - Backends: Android, GLUT, OSX: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: OpenGL3: Fixed a buffer overflow in imgui_impl_opengl3_loader.h init (added in 1.86). (#4468, #4830) [@dymk] - Backends: OpenGL3: Fixed a buffer overflow in imgui_impl_opengl3_loader.h init (added in 1.86). (#4468, #4830) [@dymk]
@ -201,6 +217,7 @@ Other Changes:
can theorically be created by user code manipulating a ImDrawList. (#4857) can theorically be created by user code manipulating a ImDrawList. (#4857)
- Backends: OSX: Added basic Platform IME support. (#3108, #2598) [@liuliu] - Backends: OSX: Added basic Platform IME support. (#3108, #2598) [@liuliu]
- Backends: OSX: Fix Game Controller nav mapping to use shoulder for both focusing and tweak speed. (#4759) - Backends: OSX: Fix Game Controller nav mapping to use shoulder for both focusing and tweak speed. (#4759)
- Backends: Vulkan: Added support for ImTextureID as VkDescriptorSet, add ImGui_ImplVulkan_AddTexture(). (#914) [@martty]
- Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and - Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and
wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev] wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev]

@ -222,7 +222,7 @@ If you are interested in using Cmake to build and links examples, see:
**About mouse cursor latency** **About mouse cursor latency**
Dear ImGui has no particular extra lag for most behaviors, Dear ImGui has no particular extra lag for most behaviors,
e.g. the value of 'io.MousePos' provided at the time of NewFrame() will result in windows being moved e.g. the last value passed to 'io.AddMousePosEvent()' before NewFrame() will result in windows being moved
to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant. to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant.
However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated

@ -114,7 +114,7 @@ void MyLowLevelMouseButtonHandler(int button, bool down)
{ {
// (1) ALWAYS forward mouse data to ImGui! This is automatic with default backends. With your own backend: // (1) ALWAYS forward mouse data to ImGui! This is automatic with default backends. With your own backend:
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.MouseDown[button] = down; io.AddMouseButtonEvent(button, down);
// (2) ONLY forward mouse data to your underlying app/game. // (2) ONLY forward mouse data to your underlying app/game.
if (!io.WantCaptureMouse) if (!io.WantCaptureMouse)

@ -113,7 +113,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input number: optional range min/max for Input*() functions - input number: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
- input number: use mouse wheel to step up/down - input number: use mouse wheel to step up/down
- input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack.
- layout: helper or a way to express ImGui::SameLine(ImGui::GetCursorStartPos().x + ImGui::CalcItemWidth() + ImGui::GetStyle().ItemInnerSpacing.x); in a simpler manner. - layout: helper or a way to express ImGui::SameLine(ImGui::GetCursorStartPos().x + ImGui::CalcItemWidth() + ImGui::GetStyle().ItemInnerSpacing.x); in a simpler manner.
- layout, font: horizontal tab support, A) text mode: forward only tabs (e.g. every 4 characters/N pixels from pos x1), B) manual mode: explicit tab stops acting as mini columns, no clipping (for menu items, many kind of uses, also vaguely relate to #267, #395) - layout, font: horizontal tab support, A) text mode: forward only tabs (e.g. every 4 characters/N pixels from pos x1), B) manual mode: explicit tab stops acting as mini columns, no clipping (for menu items, many kind of uses, also vaguely relate to #267, #395)

@ -238,7 +238,7 @@
UITouch *anyTouch = event.allTouches.anyObject; UITouch *anyTouch = event.allTouches.anyObject;
CGPoint touchLocation = [anyTouch locationInView:self.view]; CGPoint touchLocation = [anyTouch locationInView:self.view];
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
io.MousePos = ImVec2(touchLocation.x, touchLocation.y); io.AddMousePosEvent(touchLocation.x, touchLocation.y);
BOOL hasActiveTouch = NO; BOOL hasActiveTouch = NO;
for (UITouch *touch in event.allTouches) for (UITouch *touch in event.allTouches)
@ -249,7 +249,7 @@
break; break;
} }
} }
io.MouseDown[0] = hasActiveTouch; io.AddMouseButtonEvent(0, hasActiveTouch);
} }
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }

@ -41,3 +41,4 @@ file(GLOB sources *.cpp)
add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp) add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp)
target_link_libraries(example_glfw_vulkan ${LIBRARIES}) target_link_libraries(example_glfw_vulkan ${LIBRARIES})
target_compile_definitions(example_glfw_vulkan PUBLIC -DImTextureID=ImU64)

@ -7,8 +7,8 @@
@set OUT_DIR=Debug @set OUT_DIR=Debug
mkdir %OUT_DIR% mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
@set OUT_DIR=Release @set OUT_DIR=Release
mkdir %OUT_DIR% mkdir %OUT_DIR%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% cl /nologo /Zi /MD /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%

@ -6,8 +6,8 @@
@set OUT_DIR=Debug @set OUT_DIR=Debug
mkdir %OUT_DIR% mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
@set OUT_DIR=Release @set OUT_DIR=Release
mkdir %OUT_DIR% mkdir %OUT_DIR%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% cl /nologo /Zi /MD /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%

@ -91,6 +91,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -105,6 +106,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -122,6 +124,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -142,6 +145,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>

@ -7,4 +7,4 @@
@set OUT_DIR=Debug @set OUT_DIR=Debug
mkdir %OUT_DIR% mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console

@ -91,6 +91,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -105,6 +106,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -122,6 +124,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
@ -142,6 +145,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck> <BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>

@ -129,7 +129,6 @@ CODE
- CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
- CTRL+Z,CTRL+Y to undo/redo. - CTRL+Z,CTRL+Y to undo/redo.
- ESCAPE to revert text to its original value. - ESCAPE to revert text to its original value.
- You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
- Controls are automatically adjusted for OSX to match standard OSX text editing operations. - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
- General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
- General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets
@ -256,9 +255,9 @@ CODE
io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
io.DisplaySize.x = 1920.0f; // set the current display width io.DisplaySize.x = 1920.0f; // set the current display width
io.DisplaySize.y = 1280.0f; // set the current display height here io.DisplaySize.y = 1280.0f; // set the current display height here
io.MousePos = my_mouse_pos; // set the mouse position io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
io.MouseDown[1] = my_mouse_buttons[1]; io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
// Call NewFrame(), after this point you can use ImGui::* functions anytime // Call NewFrame(), after this point you can use ImGui::* functions anytime
// (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere) // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
@ -348,27 +347,26 @@ CODE
- You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787 - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
- The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
- Keyboard: - Keyboard:
- Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
NewFrame() will automatically fill io.NavInputs[] based on your io.AddKeyEvent() calls. - Internally: NewFrame() will automatically fill io.NavInputs[] based on backend's io.AddKeyEvent() calls.
- When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard),
will be set. For more advanced uses, you may want to read from: the io.WantCaptureKeyboard flag will be set. For more advanced uses, you may want to read from:
- io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
- io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
- or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions. - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
Please reach out if you think the game vs navigation input sharing could be improved. Please reach out if you think the game vs navigation input sharing could be improved.
- Gamepad: - Gamepad:
- Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
- Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame(). - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
Note that io.NavInputs[] is cleared by EndFrame(). For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly.
- See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values: Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks. - Internally: NewFrame() will automatically fill io.NavInputs[] based on backend's io.AddKeyEvent() + io.AddKeyAnalogEvent() calls.
- We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone. - BEFORE 1.87, BACKENDS USED TO WRITE DIRECTLY TO io.NavInputs[]. This is going to be obsoleted in the future. Please call io functions instead!
Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
- You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets
- If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing,
to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
- Mouse: - Mouse:
- PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. - PS4/PS5 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
- Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard. - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard.
- On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements. Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
@ -394,6 +392,14 @@ CODE
- likewise io.MousePos and GetMousePos() will use OS coordinates. - likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2022/01/20 (1.87) - inputs: reworded gamepad IO.
- Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
- 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
- 2022/01/17 (1.87) - inputs: reworked mouse IO.
- Backend writing to io.MousePos -> backend should call io.AddMousePosEvent()
- Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
- Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
- Backend writing to io.MouseHoveredViewpot -> backend should call io.AddMouseViewportEvent() [Docking branch only]
- 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
@ -1172,7 +1178,7 @@ ImGuiIO::ImGuiIO()
#else #else
ConfigMacOSXBehaviors = false; ConfigMacOSXBehaviors = false;
#endif #endif
ConfigInputEventQueue = true; ConfigInputTrickleEventQueue = true;
ConfigInputTextCursorBlink = true; ConfigInputTextCursorBlink = true;
ConfigWindowsResizeFromEdges = true; ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsMoveFromTitleBarOnly = false;
@ -1194,6 +1200,7 @@ ImGuiIO::ImGuiIO()
for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
BackendUsingLegacyKeyArrays = (ImS8)-1; BackendUsingLegacyKeyArrays = (ImS8)-1;
BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong
} }
// Pass in translated ASCII characters for text input. // Pass in translated ASCII characters for text input.
@ -1284,9 +1291,10 @@ void ImGuiIO::ClearInputKeys()
} }
// Queue a new key down/up event. // Queue a new key down/up event.
// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) // - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
// - bool down: Is the key down? use false to signify a key release. // - bool down: Is the key down? use false to signify a key release.
void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down) // - float analog_value: 0.0f..1.0f
void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
{ {
//if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } //if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
if (key == ImGuiKey_None) if (key == ImGuiKey_None)
@ -1303,15 +1311,23 @@ void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
BackendUsingLegacyKeyArrays = 0; BackendUsingLegacyKeyArrays = 0;
#endif #endif
if (ImGui::IsGamepadKey(key))
BackendUsingLegacyNavInputArray = false;
ImGuiInputEvent e; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_Key; e.Type = ImGuiInputEventType_Key;
e.Source = ImGuiInputSource_Keyboard; e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard;
e.Key.Key = key; e.Key.Key = key;
e.Key.Down = down; e.Key.Down = down;
e.Key.AnalogValue = analog_value;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
{
AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
}
// [Optional] Call after AddKeyEvent(). // [Optional] Call after AddKeyEvent().
// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices. // Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this. // If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
@ -1361,32 +1377,33 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context."); IM_ASSERT(&g.IO == this && "Can only add events to current context.");
if (wheel_x == 0.0f && wheel_y == 0.0f) IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
return;
ImGuiInputEvent e; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MouseWheel; e.Type = ImGuiInputEventType_MouseButton;
e.Source = ImGuiInputSource_Mouse; e.Source = ImGuiInputSource_Mouse;
e.MouseWheel.WheelX = wheel_x; e.MouseButton.Button = mouse_button;
e.MouseWheel.WheelY = wheel_y; e.MouseButton.Down = down;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) // Queue a mouse wheel event (most mouse/API will only have a Y component)
void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context."); IM_ASSERT(&g.IO == this && "Can only add events to current context.");
IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); if (wheel_x == 0.0f && wheel_y == 0.0f)
return;
ImGuiInputEvent e; ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MouseButton; e.Type = ImGuiInputEventType_MouseWheel;
e.Source = ImGuiInputSource_Mouse; e.Source = ImGuiInputSource_Mouse;
e.MouseButton.Button = mouse_button; e.MouseWheel.WheelX = wheel_x;
e.MouseButton.Down = down; e.MouseWheel.WheelY = wheel_y;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
@ -3410,7 +3427,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
if (id) if (id)
{ {
g.ActiveIdIsAlive = id; g.ActiveIdIsAlive = id;
g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? (ImGuiInputSource)ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
} }
// Clear declaration of inputs claimed by the widget // Clear declaration of inputs claimed by the widget
@ -4076,6 +4093,14 @@ static void ImGui::UpdateKeyboardInputs()
} }
#endif #endif
// Clear gamepad data if disabled
if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)
for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
{
io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false;
io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f;
}
// Update keys // Update keys
for (int i = 0; i < IM_ARRAYSIZE(io.KeysData); i++) for (int i = 0; i < IM_ARRAYSIZE(io.KeysData); i++)
{ {
@ -4455,7 +4480,7 @@ void ImGui::NewFrame()
// Process input queue (trickle as many events as possible) // Process input queue (trickle as many events as possible)
g.InputEventsTrail.resize(0); g.InputEventsTrail.resize(0);
UpdateInputEvents(g.IO.ConfigInputEventQueue); UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue);
// Update keyboard input state // Update keyboard input state
UpdateKeyboardInputs(); UpdateKeyboardInputs();
@ -6246,7 +6271,9 @@ static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--) for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
{ {
ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
if (popup_window == NULL || !popup_window->WasActive || !(popup_window->Flags & ImGuiWindowFlags_Modal)) // Check WasActive, because this code may run before popup renders on current frame. if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
continue;
if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
continue; continue;
if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
break; break;
@ -8036,7 +8063,7 @@ bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c
return true; return true;
} }
const ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key) ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
int index; int index;
@ -8068,22 +8095,27 @@ static const char* const GKeyNames[] =
{ {
"Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown", "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown",
"Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape", "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape",
"LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
"Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket", "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket",
"Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen", "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen",
"Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6",
"Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply",
"KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", "LeftCtrl", "LeftShift", "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual",
"LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu", "GamepadStart", "GamepadBack", "GamepadFaceUp", "GamepadFaceDown", "GamepadFaceLeft", "GamepadFaceRight",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "GamepadDpadUp", "GamepadDpadDown", "GamepadDpadLeft", "GamepadDpadRight",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3",
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" "GamepadLStickUp", "GamepadLStickDown", "GamepadLStickLeft", "GamepadLStickRight",
"GamepadRStickUp", "GamepadRStickDown", "GamepadRStickLeft", "GamepadRStickRight"
}; };
IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames)); IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames));
const char* ImGui::GetKeyName(ImGuiKey key) const char* ImGui::GetKeyName(ImGuiKey key)
{ {
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
#else #else
if (IsLegacyKey(key)) if (IsLegacyKey(key))
{ {
@ -8376,12 +8408,13 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
IM_ASSERT(e->Key.Key != ImGuiKey_None); IM_ASSERT(e->Key.Key != ImGuiKey_None);
const int keydata_index = (e->Key.Key - ImGuiKey_KeysData_OFFSET); const int keydata_index = (e->Key.Key - ImGuiKey_KeysData_OFFSET);
ImGuiKeyData* keydata = &io.KeysData[keydata_index]; ImGuiKeyData* keydata = &io.KeysData[keydata_index];
if (keydata->Down != e->Key.Down) if (keydata->Down != e->Key.Down || keydata->AnalogValue != e->Key.AnalogValue)
{ {
// Trickling Rule: Stop processing queued events if we got multiple action on the same button // Trickling Rule: Stop processing queued events if we got multiple action on the same button
if (trickle_fast_inputs && (key_changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0)) if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0))
break; break;
keydata->Down = e->Key.Down; keydata->Down = e->Key.Down;
keydata->AnalogValue = e->Key.AnalogValue;
key_changed = true; key_changed = true;
key_changed_mask.SetBit(keydata_index); key_changed_mask.SetBit(keydata_index);
} }
@ -8425,6 +8458,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
} }
// Record trail (for domain-specific applications wanting to access a precise trail) // Record trail (for domain-specific applications wanting to access a precise trail)
//if (event_n != 0) IMGUI_DEBUG_LOG("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
for (int n = 0; n < event_n; n++) for (int n = 0; n < event_n; n++)
g.InputEventsTrail.push_back(g.InputEventsQueue[n]); g.InputEventsTrail.push_back(g.InputEventsQueue[n]);
@ -10635,18 +10669,35 @@ static void ImGui::NavUpdate()
io.WantSetMousePos = false; io.WantSetMousePos = false;
//if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
// Update Gamepad->Nav inputs mapping
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard) // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
// (do it before we map Keyboard input!)
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad) if (nav_gamepad_active && g.IO.BackendUsingLegacyNavInputArray == false)
{ {
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f for (int n = 0; n < ImGuiNavInput_COUNT; n++)
|| io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f) IM_ASSERT(io.NavInputs[n] == 0.0f && "Backend needs to either only use io.AddKeyEvent()/io.AddKeyAnalogEvent(), either only fill legacy io.NavInputs[]. Not both!");
g.NavInputSource = ImGuiInputSource_Gamepad; #define NAV_MAP_KEY(_KEY, _NAV_INPUT, _ACTIVATE_NAV) do { io.NavInputs[_NAV_INPUT] = io.KeysData[_KEY - ImGuiKey_KeysData_OFFSET].AnalogValue; if (_ACTIVATE_NAV && io.NavInputs[_NAV_INPUT] > 0.0f) { g.NavInputSource = ImGuiInputSource_Gamepad; } } while (0)
NAV_MAP_KEY(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown, true);
NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, false);
NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, false);
NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_TweakSlow, false);
NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_TweakFast, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown, false);
#undef NAV_MAP_KEY
} }
// Update Keyboard->Nav inputs mapping // Update Keyboard->Nav inputs mapping
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
if (nav_keyboard_active) if (nav_keyboard_active)
{ {
#define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(_KEY)) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0) #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(_KEY)) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0)

@ -65,7 +65,7 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.87 WIP" #define IMGUI_VERSION "1.87 WIP"
#define IMGUI_VERSION_NUM 18608 #define IMGUI_VERSION_NUM 18612
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
@ -1404,8 +1404,8 @@ enum ImGuiSortDirection_
enum ImGuiKey_ enum ImGuiKey_
{ {
ImGuiKey_None = 0, ImGuiKey_None = 0,
ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN
ImGuiKey_LeftArrow, ImGuiKey_LeftArrow,
ImGuiKey_RightArrow, ImGuiKey_RightArrow,
ImGuiKey_UpArrow, ImGuiKey_UpArrow,
@ -1420,32 +1420,33 @@ enum ImGuiKey_
ImGuiKey_Space, ImGuiKey_Space,
ImGuiKey_Enter, ImGuiKey_Enter,
ImGuiKey_Escape, ImGuiKey_Escape,
ImGuiKey_Apostrophe, // ' ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper,
ImGuiKey_Comma, // , ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper,
ImGuiKey_Minus, // - ImGuiKey_Menu,
ImGuiKey_Period, // . ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9,
ImGuiKey_Slash, // / ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J,
ImGuiKey_Semicolon, // ; ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T,
ImGuiKey_Equal, // = ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z,
ImGuiKey_LeftBracket, // [ ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6,
ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backlash) ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12,
ImGuiKey_RightBracket, // ] ImGuiKey_Apostrophe, // '
ImGuiKey_GraveAccent, // ` ImGuiKey_Comma, // ,
ImGuiKey_Minus, // -
ImGuiKey_Period, // .
ImGuiKey_Slash, // /
ImGuiKey_Semicolon, // ;
ImGuiKey_Equal, // =
ImGuiKey_LeftBracket, // [
ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash)
ImGuiKey_RightBracket, // ]
ImGuiKey_GraveAccent, // `
ImGuiKey_CapsLock, ImGuiKey_CapsLock,
ImGuiKey_ScrollLock, ImGuiKey_ScrollLock,
ImGuiKey_NumLock, ImGuiKey_NumLock,
ImGuiKey_PrintScreen, ImGuiKey_PrintScreen,
ImGuiKey_Pause, ImGuiKey_Pause,
ImGuiKey_Keypad0, ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4,
ImGuiKey_Keypad1, ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9,
ImGuiKey_Keypad2,
ImGuiKey_Keypad3,
ImGuiKey_Keypad4,
ImGuiKey_Keypad5,
ImGuiKey_Keypad6,
ImGuiKey_Keypad7,
ImGuiKey_Keypad8,
ImGuiKey_Keypad9,
ImGuiKey_KeypadDecimal, ImGuiKey_KeypadDecimal,
ImGuiKey_KeypadDivide, ImGuiKey_KeypadDivide,
ImGuiKey_KeypadMultiply, ImGuiKey_KeypadMultiply,
@ -1453,79 +1454,51 @@ enum ImGuiKey_
ImGuiKey_KeypadAdd, ImGuiKey_KeypadAdd,
ImGuiKey_KeypadEnter, ImGuiKey_KeypadEnter,
ImGuiKey_KeypadEqual, ImGuiKey_KeypadEqual,
ImGuiKey_LeftCtrl,
ImGuiKey_LeftShift, // Gamepad (some of those are expected to be analog values from 0.0f to 1.0f) ..............// NAVIGATION action
ImGuiKey_LeftAlt, ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) // --
ImGuiKey_LeftSuper, ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) // --
ImGuiKey_RightCtrl, ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // -> ImGuiNavInput_Input
ImGuiKey_RightShift, ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // -> ImGuiNavInput_Activate
ImGuiKey_RightAlt, ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // -> ImGuiNavInput_Menu
ImGuiKey_RightSuper, ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // -> ImGuiNavInput_Cancel
ImGuiKey_Menu, ImGuiKey_GamepadDpadUp, // D-pad Up // -> ImGuiNavInput_DpadUp
ImGuiKey_0, ImGuiKey_GamepadDpadDown, // D-pad Down // -> ImGuiNavInput_DpadDown
ImGuiKey_1, ImGuiKey_GamepadDpadLeft, // D-pad Left // -> ImGuiNavInput_DpadLeft
ImGuiKey_2, ImGuiKey_GamepadDpadRight, // D-pad Right // -> ImGuiNavInput_DpadRight
ImGuiKey_3, ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // -> ImGuiNavInput_FocusPrev + ImGuiNavInput_TweakSlow
ImGuiKey_4, ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // -> ImGuiNavInput_FocusNext + ImGuiNavInput_TweakFast
ImGuiKey_5, ImGuiKey_GamepadL2, // L Trigger (Xbox) ZL (Switch) L2 (PS) [Analog]
ImGuiKey_6, ImGuiKey_GamepadR2, // R Trigger (Xbox) ZR (Switch) R2 (PS) [Analog]
ImGuiKey_7, ImGuiKey_GamepadL3, // L Thumbstick (Xbox) L3 (Switch) L3 (PS)
ImGuiKey_8, ImGuiKey_GamepadR3, // R Thumbstick (Xbox) R3 (Switch) R3 (PS)
ImGuiKey_9, ImGuiKey_GamepadLStickUp, // [Analog] // -> ImGuiNavInput_LStickUp
ImGuiKey_A, ImGuiKey_GamepadLStickDown, // [Analog] // -> ImGuiNavInput_LStickDown
ImGuiKey_B, ImGuiKey_GamepadLStickLeft, // [Analog] // -> ImGuiNavInput_LStickLeft
ImGuiKey_C, ImGuiKey_GamepadLStickRight, // [Analog] // -> ImGuiNavInput_LStickRight
ImGuiKey_D, ImGuiKey_GamepadRStickUp, // [Analog]
ImGuiKey_E, ImGuiKey_GamepadRStickDown, // [Analog]
ImGuiKey_F, ImGuiKey_GamepadRStickLeft, // [Analog]
ImGuiKey_G, ImGuiKey_GamepadRStickRight, // [Analog]
ImGuiKey_H,
ImGuiKey_I, ImGuiKey_COUNT, // No valid ImGuiKey is ever greater than this value
ImGuiKey_J,
ImGuiKey_K,
ImGuiKey_L,
ImGuiKey_M,
ImGuiKey_N,
ImGuiKey_O,
ImGuiKey_P,
ImGuiKey_Q,
ImGuiKey_R,
ImGuiKey_S,
ImGuiKey_T,
ImGuiKey_U,
ImGuiKey_V,
ImGuiKey_W,
ImGuiKey_X,
ImGuiKey_Y,
ImGuiKey_Z,
ImGuiKey_F1,
ImGuiKey_F2,
ImGuiKey_F3,
ImGuiKey_F4,
ImGuiKey_F5,
ImGuiKey_F6,
ImGuiKey_F7,
ImGuiKey_F8,
ImGuiKey_F9,
ImGuiKey_F10,
ImGuiKey_F11,
ImGuiKey_F12,
ImGuiKey_COUNT, // No valid ImGuiKey is ever greater than this value
// Legacy range used by legacy io.KeyMap[]. Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index. // Legacy range used by legacy io.KeyMap[]. Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index.
// We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE)
ImGuiKey_LegacyNativeKey_BEGIN = 0, ImGuiKey_LegacyNativeKey_BEGIN = 0,
ImGuiKey_LegacyNativeKey_END = 512, // First index after valid range ImGuiKey_LegacyNativeKey_END = 512,
ImGuiKey_NamedKey_BEGIN = 512, ImGuiKey_NamedKey_BEGIN = 512,
ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_END = ImGuiKey_COUNT,
ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN,
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys
ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN // First key stored in KeysData[0] ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // First key stored in KeysData[0]
#else #else
ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys
ImGuiKey_KeysData_OFFSET = ImGuiKey_LegacyNativeKey_BEGIN // First key stored in KeysData[0] ImGuiKey_KeysData_OFFSET = ImGuiKey_LegacyNativeKey_BEGIN, // First key stored in KeysData[0]
#endif #endif
ImGuiKey_Gamepad_BEGIN = ImGuiKey_GamepadStart,
ImGuiKey_Gamepad_END = ImGuiKey_GamepadRStickRight + 1
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
, ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter // Renamed in 1.87 , ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter // Renamed in 1.87
@ -1991,6 +1964,7 @@ struct ImGuiKeyData
bool Down; // True for if key is down bool Down; // True for if key is down
float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held)
float DownDurationPrev; // Last frame duration the key has been down float DownDurationPrev; // Last frame duration the key has been down
float AnalogValue; // 0.0f..1.0f for gamepad values
}; };
struct ImGuiIO struct ImGuiIO
@ -2034,7 +2008,7 @@ struct ImGuiIO
// Miscellaneous options // Miscellaneous options
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.
bool ConfigInputEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.
bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting).
bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard.
bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
@ -2069,34 +2043,24 @@ struct ImGuiIO
#endif #endif
//------------------------------------------------------------------ //------------------------------------------------------------------
// Input - Fill before calling NewFrame() // Input - Call before calling NewFrame()
//------------------------------------------------------------------ //------------------------------------------------------------------
ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)
bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends.
ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows).
bool KeyCtrl; // Keyboard modifier down: Control
bool KeyShift; // Keyboard modifier down: Shift
bool KeyAlt; // Keyboard modifier down: Alt
bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Input Functions // Input Functions
IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
IMGUI_API void AddKeyModsEvent(ImGuiKeyModFlags modifiers);// Queue a change of Ctrl/Shift/Alt/Super modifiers IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend.
IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) IMGUI_API void AddKeyModsEvent(ImGuiKeyModFlags modifiers); // Queue a change of Ctrl/Shift/Alt/Super modifiers
IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered)
IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change
IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this. IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update
IMGUI_API void AddFocusEvent(bool focused); // Queue an hosting application/platform windows gain or loss of focus IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this (for multi-viewport support).
IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window)
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from an UTF-16 character, it can be a surrogate
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue a new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually
IMGUI_API void ClearInputKeys(); // [Internal] Release all keys IMGUI_API void ClearInputCharacters(); // [Internal] Clear the text input buffer manually
IMGUI_API void ClearInputKeys(); // [Internal] Release all keys
IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode.
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -2131,10 +2095,24 @@ struct ImGuiIO
// [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!
//------------------------------------------------------------------ //------------------------------------------------------------------
// Main Input State
// (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead)
// (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)
ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)
bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all backends.
ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows).
bool KeyCtrl; // Keyboard modifier down: Control
bool KeyShift; // Keyboard modifier down: Shift
bool KeyAlt; // Keyboard modifier down: Alt
bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Other state maintained from data above + IO function calls
ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame() ImGuiKeyModFlags KeyMods; // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame()
ImGuiKeyModFlags KeyModsPrev; // Key mods flags (from previous frame) ImGuiKeyModFlags KeyModsPrev; // Key mods flags (from previous frame)
ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this.
bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup.
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
ImVec2 MouseClickedPos[5]; // Position at time of clicking ImVec2 MouseClickedPos[5]; // Position at time of clicking
@ -2155,6 +2133,7 @@ struct ImGuiIO
float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui.
bool AppFocusLost; bool AppFocusLost;
ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[]
bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly
ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16()
ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. ImVector<ImWchar> InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper.

@ -241,7 +241,6 @@ void ImGui::ShowUserGuide()
ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
ImGui::BulletText("ESCAPE to revert."); ImGui::BulletText("ESCAPE to revert.");
ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
ImGui::Unindent(); ImGui::Unindent();
ImGui::BulletText("With keyboard navigation enabled:"); ImGui::BulletText("With keyboard navigation enabled:");
ImGui::Indent(); ImGui::Indent();
@ -514,7 +513,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Unindent(); ImGui::Unindent();
} }
ImGui::Checkbox("io.ConfigInputEventQueue", &io.ConfigInputEventQueue); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates."); ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting).");
@ -538,6 +537,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
"Here we expose them as read-only fields to avoid breaking interactions with your backend."); "Here we expose them as read-only fields to avoid breaking interactions with your backend.");
// Make a local copy to avoid modifying actual backend flags. // Make a local copy to avoid modifying actual backend flags.
// FIXME: We don't use BeginDisabled() to keep label bright, maybe we need a BeginReadonly() equivalent..
ImGuiBackendFlags backend_flags = io.BackendFlags; ImGuiBackendFlags backend_flags = io.BackendFlags;
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad); ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &backend_flags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &backend_flags, ImGuiBackendFlags_HasMouseCursors);
@ -734,10 +734,6 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat");
static int i0 = 123; static int i0 = 123;
ImGui::InputInt("input int", &i0); ImGui::InputInt("input int", &i0);
ImGui::SameLine(); HelpMarker(
"You can apply arithmetic operators +,*,/ on numerical values.\n"
" e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n"
"Use +- to subtract.");
static float f0 = 0.001f; static float f0 = 0.001f;
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
@ -5715,7 +5711,7 @@ static void ShowDemoWindowColumns()
ImGui::TreePop(); ImGui::TreePop();
} }
namespace ImGui { extern const ImGuiKeyData* GetKeyData(ImGuiKey key); } namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); }
static void ShowDemoWindowMisc() static void ShowDemoWindowMisc()
{ {
@ -5770,22 +5766,23 @@ static void ShowDemoWindowMisc()
} }
// Display Keyboard/Mouse state // Display Keyboard/Mouse state
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard & Navigation State"); IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard, Gamepad & Navigation State");
if (ImGui::TreeNode("Keyboard & Navigation State")) if (ImGui::TreeNode("Keyboard, Gamepad & Navigation State"))
{ {
// We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allow displaying the data for old/new backends. // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allow displaying the data for old/new backends.
// User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes. // User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes.
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO #ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
struct funcs { static bool IsNativeDupe(ImGuiKey) { return false; } }; struct funcs { static bool IsNativeDupe(ImGuiKey) { return false; } };
const ImGuiKey key_first = ImGuiKey_NamedKey_BEGIN;
#else #else
struct funcs { static bool IsNativeDupe(ImGuiKey key) { return key < ImGuiKey_LegacyNativeKey_END && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array struct funcs { static bool IsNativeDupe(ImGuiKey key) { return key < ImGuiKey_LegacyNativeKey_END && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
const ImGuiKey key_first = 0;
#endif #endif
ImGui::Text("Keys down:"); for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) { ImGuiKey key = (ImGuiKey)(i + ImGuiKey_KeysData_OFFSET); if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (0x%X) (%.02f secs)", ImGui::GetKeyName(key), key, key, ImGui::GetKeyData(key)->DownDuration); } } ImGui::Text("Keys down:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (%.02f secs)", ImGui::GetKeyName(key), key, ImGui::GetKeyData(key)->DownDuration); } }
ImGui::Text("Keys pressed:"); for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) { ImGuiKey key = (ImGuiKey)(i + ImGuiKey_KeysData_OFFSET); if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyPressed(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (0x%X)", ImGui::GetKeyName(key), key, key); } } ImGui::Text("Keys pressed:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyPressed(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } }
ImGui::Text("Keys released:"); for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) { ImGuiKey key = (ImGuiKey)(i + ImGuiKey_KeysData_OFFSET); if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (0x%X)", ImGui::GetKeyName(key), key, key); } } ImGui::Text("Keys released:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (funcs::IsNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } }
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); } ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f (%.02f secs)", i, io.NavInputs[i], io.NavInputsDownDuration[i]); }
ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); } ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); }
ImGui::TreePop(); ImGui::TreePop();

@ -931,8 +931,8 @@ enum ImGuiInputSource
ImGuiInputSource_Mouse, ImGuiInputSource_Mouse,
ImGuiInputSource_Keyboard, ImGuiInputSource_Keyboard,
ImGuiInputSource_Gamepad, ImGuiInputSource_Gamepad,
ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only ImGuiInputSource_Clipboard, // Currently only used by InputText()
ImGuiInputSource_Clipboard, // Currently only used by InputText() ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only
ImGuiInputSource_COUNT ImGuiInputSource_COUNT
}; };
@ -942,7 +942,7 @@ struct ImGuiInputEventMousePos { float PosX, PosY; };
struct ImGuiInputEventMouseWheel { float WheelX, WheelY; }; struct ImGuiInputEventMouseWheel { float WheelX, WheelY; };
struct ImGuiInputEventMouseButton { int Button; bool Down; }; struct ImGuiInputEventMouseButton { int Button; bool Down; };
struct ImGuiInputEventMouseViewport { ImGuiID HoveredViewportID; }; struct ImGuiInputEventMouseViewport { ImGuiID HoveredViewportID; };
struct ImGuiInputEventKey { ImGuiKey Key; bool Down; }; struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; };
struct ImGuiInputEventKeyMods { ImGuiKeyModFlags Mods; }; struct ImGuiInputEventKeyMods { ImGuiKeyModFlags Mods; };
struct ImGuiInputEventText { unsigned int Char; }; struct ImGuiInputEventText { unsigned int Char; };
struct ImGuiInputEventAppFocused { bool Focused; }; struct ImGuiInputEventAppFocused { bool Focused; };
@ -951,7 +951,6 @@ struct ImGuiInputEvent
{ {
ImGuiInputEventType Type; ImGuiInputEventType Type;
ImGuiInputSource Source; ImGuiInputSource Source;
bool SubmittedByTestEngine;
union union
{ {
ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos
@ -963,6 +962,7 @@ struct ImGuiInputEvent
ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text
ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus
}; };
bool AddedByTestEngine;
ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } ImGuiInputEvent() { memset(this, 0, sizeof(*this)); }
}; };
@ -2561,7 +2561,7 @@ struct IMGUI_API ImGuiTable
ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is
ImRect WorkRect; ImRect WorkRect;
ImRect InnerClipRect; ImRect InnerClipRect;
ImRect BgClipRect; // We use this to cpu-clip cell background color fill ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries
ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped
ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect.
ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.
@ -2877,7 +2877,8 @@ namespace ImGui
// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; }
inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; }
IMGUI_API const ImGuiKeyData* GetKeyData(ImGuiKey key); inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; }
IMGUI_API ImGuiKeyData* GetKeyData(ImGuiKey key);
IMGUI_API void SetItemUsingMouseWheel(); IMGUI_API void SetItemUsingMouseWheel();
IMGUI_API void SetActiveIdUsingNavAndKeys(); IMGUI_API void SetActiveIdUsingNavAndKeys();
inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }
@ -3097,7 +3098,7 @@ namespace ImGui
IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type);
IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);
IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2);
IMGUI_API bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format); IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format);
IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2);
IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max);

@ -1569,18 +1569,21 @@ ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)
// Return the cell rectangle based on currently known height. // Return the cell rectangle based on currently known height.
// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. // - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. // The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height.
// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right // - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
// columns report a small offset so their CellBgRect can extend up to the outer border. // columns report a small offset so their CellBgRect can extend up to the outer border.
// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling.
ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
{ {
const ImGuiTableColumn* column = &table->Columns[column_n]; const ImGuiTableColumn* column = &table->Columns[column_n];
float x1 = column->MinX; float x1 = column->MinX;
float x2 = column->MaxX; float x2 = column->MaxX;
if (column->PrevEnabledColumn == -1) //if (column->PrevEnabledColumn == -1)
x1 -= table->CellSpacingX1; // x1 -= table->OuterPaddingX;
if (column->NextEnabledColumn == -1) //if (column->NextEnabledColumn == -1)
x2 += table->CellSpacingX2; // x2 += table->OuterPaddingX;
x1 = ImMax(x1, table->WorkRect.Min.x);
x2 = ImMin(x2, table->WorkRect.Max.x);
return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
} }
@ -1797,10 +1800,12 @@ void ImGui::TableEndRow(ImGuiTable* table)
ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent];
for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++)
{ {
// As we render the BG here we need to clip things (for layout we would not)
// FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling.
const ImGuiTableColumn* column = &table->Columns[cell_data->Column]; const ImGuiTableColumn* column = &table->Columns[cell_data->Column];
ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column);
cell_bg_rect.ClipWith(table->BgClipRect); cell_bg_rect.ClipWith(table->BgClipRect);
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling
cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX);
window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor);
} }

@ -2000,24 +2000,10 @@ void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const
// User can input math operators (e.g. +100) to edit a numerical values. // User can input math operators (e.g. +100) to edit a numerical values.
// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess..
bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format) bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format)
{ {
while (ImCharIsBlankA(*buf)) while (ImCharIsBlankA(*buf))
buf++; buf++;
// We don't support '-' op because it would conflict with inputing negative value.
// Instead you can use +-100 to subtract from an existing value
char op = buf[0];
if (op == '+' || op == '*' || op == '/')
{
buf++;
while (ImCharIsBlankA(*buf))
buf++;
}
else
{
op = 0;
}
if (!buf[0]) if (!buf[0])
return false; return false;
@ -2029,54 +2015,11 @@ bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b
if (format == NULL) if (format == NULL)
format = type_info->ScanFmt; format = type_info->ScanFmt;
// FIXME-LEGACY: The aim is to remove those operators and write a proper expression evaluator at some point.. if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64 || data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
int arg1i = 0;
if (data_type == ImGuiDataType_S32)
{
int* v = (int*)p_data;
int arg0i = *v;
float arg1f = 0.0f;
if (op && sscanf(initial_value_buf, format, &arg0i) < 1)
return false;
// Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract)
else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply
else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide
else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant
}
else if (data_type == ImGuiDataType_Float)
{
// For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
format = "%f";
float* v = (float*)p_data;
float arg0f = *v, arg1f = 0.0f;
if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
return false;
if (sscanf(buf, format, &arg1f) < 1)
return false;
if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
else if (op == '*') { *v = arg0f * arg1f; } // Multiply
else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
else { *v = arg1f; } // Assign constant
}
else if (data_type == ImGuiDataType_Double)
{ {
format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis // For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
double* v = (double*)p_data; if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
double arg0f = *v, arg1f = 0.0; format = type_info->ScanFmt;
if (op && sscanf(initial_value_buf, format, &arg0f) < 1)
return false;
if (sscanf(buf, format, &arg1f) < 1)
return false;
if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
else if (op == '*') { *v = arg0f * arg1f; } // Multiply
else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
else { *v = arg1f; } // Assign constant
}
else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
{
// All other types assign constant
// We don't bother handling support for legacy operators since they are a little too crappy. Instead we will later implement a proper expression evaluator in the future.
if (sscanf(buf, format, p_data) < 1) if (sscanf(buf, format, p_data) < 1)
return false; return false;
} }
@ -3395,8 +3338,6 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char*
// However this may not be ideal for all uses, as some user code may break on out of bound values. // However this may not be ideal for all uses, as some user code may break on out of bound values.
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max)
{ {
ImGuiContext& g = *GImGui;
char fmt_buf[32]; char fmt_buf[32];
char data_buf[32]; char data_buf[32];
format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
@ -3414,7 +3355,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
memcpy(&data_backup, p_data, data_type_size); memcpy(&data_backup, p_data, data_type_size);
// Apply new value (or operations) then clamp // Apply new value (or operations) then clamp
DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, p_data, NULL); DataTypeApplyFromText(data_buf, data_type, p_data, NULL);
if (p_clamp_min || p_clamp_max) if (p_clamp_min || p_clamp_max)
{ {
if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0)
@ -3461,7 +3402,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
PushID(label); PushID(label);
SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
// Step buttons // Step buttons
const ImVec2 backup_frame_padding = style.FramePadding; const ImVec2 backup_frame_padding = style.FramePadding;
@ -3498,7 +3439,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
else else
{ {
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format); value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
} }
if (value_changed) if (value_changed)
MarkItemEdited(g.LastItemData.ID); MarkItemEdited(g.LastItemData.ID);

Loading…
Cancel
Save