From f159eb35fb562f1c29732322f9ea0a9a2ab0cae4 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 22 Apr 2019 10:42:39 +0200 Subject: [PATCH 01/12] Examples: SDL: Removed unused code. (#2484) --- examples/example_sdl_opengl2/main.cpp | 2 -- examples/example_sdl_opengl3/main.cpp | 2 -- examples/example_sdl_vulkan/main.cpp | 2 -- 3 files changed, 6 deletions(-) diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index 029acefa..aaaf3ee7 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -28,8 +28,6 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); - SDL_DisplayMode current; - SDL_GetCurrentDisplayMode(0, ¤t); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); SDL_GLContext gl_context = SDL_GL_CreateContext(window); diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index 246449af..5b319a14 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -52,8 +52,6 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_DisplayMode current; - SDL_GetCurrentDisplayMode(0, ¤t); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); SDL_GLContext gl_context = SDL_GL_CreateContext(window); diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 812d0988..58a49949 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -326,8 +326,6 @@ int main(int, char**) } // Setup window - SDL_DisplayMode current; - SDL_GetCurrentDisplayMode(0, ¤t); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); From 16e9b8191b14d708b19263be26a1d975376b1ee4 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 22 Apr 2019 11:16:17 +0200 Subject: [PATCH 02/12] Increased IMGUI_VERSION_NUM arbitrarily, help narrowing down reports that don't include a commit hash. Add comments. --- imgui.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.h b/imgui.h index 53e17253..37640640 100644 --- a/imgui.h +++ b/imgui.h @@ -47,7 +47,7 @@ Index of this file: // 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) #define IMGUI_VERSION "1.70 WIP" -#define IMGUI_VERSION_NUM 16990 +#define IMGUI_VERSION_NUM 16991 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -212,10 +212,10 @@ namespace ImGui // Main IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame. - IMGUI_API void NewFrame(); // start a new ImGui frame, you can submit any command from this point until Render()/EndFrame(). - IMGUI_API void EndFrame(); // ends the ImGui frame. automatically called by Render(), you likely don't need to call that yourself directly. If you don't need to render data (skipping rendering) you may call EndFrame() but you'll have wasted CPU already! If you don't need to render, better to not create any imgui windows and not call NewFrame() at all! - IMGUI_API void Render(); // ends the ImGui frame, finalize the draw data. (Obsolete: optionally call io.RenderDrawListsFn if set. Nowadays, prefer calling your render function yourself.) - IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. (Obsolete: this used to be passed to your io.RenderDrawListsFn() function.) + IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). + IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(), you likely don't need to call that yourself directly. If you don't need to render data (skipping rendering) you may call EndFrame() but you'll have wasted CPU already! If you don't need to render, better to not create any imgui windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can get call GetDrawData() to obtain it and run your rendering function. (Obsolete: this used to call io.RenderDrawListsFn(). Nowadays, we allow and prefer calling your render function yourself.) + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. // Demo, Debug, Information IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! @@ -1921,7 +1921,8 @@ struct ImDrawList }; // All draw data to render an ImGui frame -// (NB: the style and the naming convention here is a little inconsistent but we preserve them for backward compatibility purpose) +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, +// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. From 994a92d79d65e71d12204b4a056c85dc84d58a61 Mon Sep 17 00:00:00 2001 From: David Amador Date: Mon, 22 Apr 2019 13:34:34 +0100 Subject: [PATCH 03/12] Added support to use controllers via SDL_GameController. (#2509) Updated sdl examples to use SDL_INIT_GAMECONTROLLER flag --- examples/example_sdl_opengl2/main.cpp | 2 +- examples/example_sdl_opengl3/main.cpp | 2 +- examples/example_sdl_vulkan/main.cpp | 2 +- examples/imgui_impl_sdl.cpp | 46 +++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index aaaf3ee7..05adfbb7 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -16,7 +16,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index 5b319a14..493b47ee 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -25,7 +25,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 58a49949..c9fa2671 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -319,7 +319,7 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return 1; diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index 10f49493..f1d6a3ba 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -266,6 +266,49 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() } } +static void ImGui_ImplSDL2_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Update gamepad inputs +#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) == 1) ? 1.0f : 0.0f; } +#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; } + + int axes_count = 0, buttons_count = 0; + SDL_GameController* game_controller = SDL_GameControllerOpen(0); + if(game_controller !=NULL) + { + const int thumb_dead_zone = 8000; + + MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); +#undef MAP_BUTTON +#undef MAP_ANALOG + } + + if (axes_count > 0 && buttons_count > 0) + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + else + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +} + void ImGui_ImplSDL2_NewFrame(SDL_Window* window) { ImGuiIO& io = ImGui::GetIO(); @@ -288,4 +331,7 @@ void ImGui_ImplSDL2_NewFrame(SDL_Window* window) ImGui_ImplSDL2_UpdateMousePosAndButtons(); ImGui_ImplSDL2_UpdateMouseCursor(); + + // Gamepad navigation mapping + ImGui_ImplSDL2_UpdateGamepads(); } From 6789ea3482d6d5f1a1dc353758f7c512f6337b78 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 23 Apr 2019 12:26:14 +0200 Subject: [PATCH 04/12] Examples: SDL: Gamepad support minor amend. Fixes ImGuiBackendFlags_HasGamepad not being set. Enable in Emscripten demo. Tweaks. (#2509, #2484). --- docs/CHANGELOG.txt | 3 +- examples/example_emscripten/main.cpp | 3 +- examples/example_sdl_opengl2/main.cpp | 3 +- examples/example_sdl_opengl3/main.cpp | 3 +- examples/example_sdl_vulkan/main.cpp | 3 +- examples/imgui_impl_glfw.cpp | 2 +- examples/imgui_impl_sdl.cpp | 67 +++++++++++++-------------- examples/imgui_impl_sdl.h | 2 +- examples/imgui_impl_win32.cpp | 2 +- 9 files changed, 46 insertions(+), 42 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 39f0da96..f982ff08 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,6 +70,7 @@ Other Changes: - Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). - Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. - Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam] +- Examples: SDL: Added support for SDL_GameController gamepads (enable with ImGuiConfigFlags_NavEnableGamepad). (#2509) [@DJLink] - Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - Examples: DirectX10/11/12, Allegro, Marmalade: Render functions early out when display size is zero (minimized). (#2496) - Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott] @@ -217,7 +218,7 @@ Other Changes: - Examples: Win32: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. (#1951, #2087, #2156, #2232) [many people] - Examples: SDL: Using the SDL_WINDOW_ALLOW_HIGHDPI flag. (#2306, #1676) [@rasky] -- Examples: Win32: Added support for XInput games (if ImGuiConfigFlags_NavEnableGamepad is enabled). +- Examples: Win32: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is enabled). - Examples: Win32: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. (#2264) - Examples: DirectX9: Explicitly disable fog (D3DRS_FOGENABLE) before drawing in case user state has it set. (#2288, #2230) - Examples: OpenGL2: Added #define GL_SILENCE_DEPRECATION to cope with newer XCode warnings. diff --git a/examples/example_emscripten/main.cpp b/examples/example_emscripten/main.cpp index fc7017d5..574e6e24 100644 --- a/examples/example_emscripten/main.cpp +++ b/examples/example_emscripten/main.cpp @@ -25,7 +25,7 @@ void main_loop(void*); int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; @@ -62,6 +62,7 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index 05adfbb7..ddefd096 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -16,7 +16,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; @@ -38,6 +38,7 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index 493b47ee..08f1bb00 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -25,7 +25,7 @@ int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return -1; @@ -78,6 +78,7 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index c9fa2671..2d49dda4 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -319,7 +319,7 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) int main(int, char**) { // Setup SDL - if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_GAMECONTROLLER) != 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); return 1; @@ -356,6 +356,7 @@ int main(int, char**) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style ImGui::StyleColorsDark(); diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 0ed40cde..0ed9f7d2 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -325,6 +325,6 @@ void ImGui_ImplGlfw_NewFrame() ImGui_ImplGlfw_UpdateMousePosAndButtons(); ImGui_ImplGlfw_UpdateMouseCursor(); - // Gamepad navigation mapping + // Update game controllers (if enabled and available) ImGui_ImplGlfw_UpdateGamepads(); } diff --git a/examples/imgui_impl_sdl.cpp b/examples/imgui_impl_sdl.cpp index f1d6a3ba..a9ff5cd8 100644 --- a/examples/imgui_impl_sdl.cpp +++ b/examples/imgui_impl_sdl.cpp @@ -7,9 +7,9 @@ // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Clipboard support. // [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // Missing features: // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. -// [ ] Platform: Gamepad support (need to use SDL_GameController API to fill the io.NavInputs[] value when ImGuiConfigFlags_NavEnableGamepad is set). // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application). // 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. // 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. @@ -272,41 +273,39 @@ static void ImGui_ImplSDL2_UpdateGamepads() memset(io.NavInputs, 0, sizeof(io.NavInputs)); if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) return; - - // Update gamepad inputs -#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) == 1) ? 1.0f : 0.0f; } -#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; } - - int axes_count = 0, buttons_count = 0; + + // Get gamepad SDL_GameController* game_controller = SDL_GameControllerOpen(0); - if(game_controller !=NULL) + if (!game_controller) { - const int thumb_dead_zone = 8000; - - MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A - MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B - MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X - MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y - MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left - MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right - MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up - MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down - MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB - MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB - MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB - MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB - MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); - MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); -#undef MAP_BUTTON -#undef MAP_ANALOG - } - - if (axes_count > 0 && buttons_count > 0) - io.BackendFlags |= ImGuiBackendFlags_HasGamepad; - else io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + return; + } + + // 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 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; } + 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(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); + MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); + MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); + MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); + + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + #undef MAP_BUTTON + #undef MAP_ANALOG } void ImGui_ImplSDL2_NewFrame(SDL_Window* window) @@ -332,6 +331,6 @@ void ImGui_ImplSDL2_NewFrame(SDL_Window* window) ImGui_ImplSDL2_UpdateMousePosAndButtons(); ImGui_ImplSDL2_UpdateMouseCursor(); - // Gamepad navigation mapping + // Update game controllers (if enabled and available) ImGui_ImplSDL2_UpdateGamepads(); } diff --git a/examples/imgui_impl_sdl.h b/examples/imgui_impl_sdl.h index ec8190cc..39cc98e5 100644 --- a/examples/imgui_impl_sdl.h +++ b/examples/imgui_impl_sdl.h @@ -6,9 +6,9 @@ // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Clipboard support. // [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE). +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // Missing features: // [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. -// [ ] Platform: Gamepad support (need to use SDL_GameController API to fill the io.NavInputs[] value when ImGuiConfigFlags_NavEnableGamepad is set). // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index 524923c3..59cf88ce 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -230,7 +230,7 @@ void ImGui_ImplWin32_NewFrame() ImGui_ImplWin32_UpdateMouseCursor(); } - // Update game controllers (if available) + // Update game controllers (if enabled and available) ImGui_ImplWin32_UpdateGamepads(); } From 6db0766564600bfb94c2cf0bb0b676c2929a92fc Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 24 Apr 2019 17:04:20 +0200 Subject: [PATCH 05/12] Misc comments, internal renaming, added disable indentation option to Columns demo section. --- docs/TODO.txt | 1 + imgui.cpp | 7 ++++--- imgui.h | 2 +- imgui_demo.cpp | 15 ++++++++++++++- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 6 +++--- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 279342ca..57845d36 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -207,6 +207,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer) - tree node: tweak color scheme to distinguish headers from selected tree node (#581) - tree node: leaf/non-leaf highlight mismatch. + - tree node: _NoIndentOnOpen flag? would require to store a per-depth bit mask to store info for pop (or whatever is cheaper) - settings: write more decent code to allow saving/loading new fields: columns, selected tree nodes? - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437) diff --git a/imgui.cpp b/imgui.cpp index 5d705e4e..7a169bf8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -393,8 +393,9 @@ CODE - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). - old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant. + old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports. when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call. + in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. @@ -5444,7 +5445,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.TextWrapPosStack.resize(0); window->DC.CurrentColumns = NULL; window->DC.TreeDepth = 0; - window->DC.TreeDepthMayJumpToParentOnPop = 0x00; + window->DC.TreeStoreMayJumpToParentOnPop = 0x00; window->DC.StateStorage = &window->StateStorage; window->DC.GroupStack.resize(0); window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user); @@ -6396,7 +6397,7 @@ void ImGui::SetNextWindowBgAlpha(float alpha) g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op) } -// FIXME: This is in window space (not screen space!) +// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions. ImVec2 ImGui::GetContentRegionMax() { ImGuiWindow* window = GImGui->CurrentWindow; diff --git a/imgui.h b/imgui.h index 37640640..d10df2f0 100644 --- a/imgui.h +++ b/imgui.h @@ -782,7 +782,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). - //ImGuITreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed + //ImGuiTreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2233eab7..695fd869 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2367,6 +2367,13 @@ static void ShowDemoWindowColumns() ImGui::PushID("Columns"); + static bool disable_indent = false; + ImGui::Checkbox("Disable tree indentation", &disable_indent); + ImGui::SameLine(); + HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width."); + if (disable_indent) + ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f); + // Basic columns if (ImGui::TreeNode("Basic")) { @@ -2472,7 +2479,10 @@ static void ShowDemoWindowColumns() if (h_borders && ImGui::GetColumnIndex() == 0) ImGui::Separator(); ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i); - ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset()); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); + ImGui::Text("Long text that is likely to clip"); + ImGui::Button("Button", ImVec2(-1.0f, 0.0f)); ImGui::NextColumn(); } ImGui::Columns(1); @@ -2540,6 +2550,9 @@ static void ShowDemoWindowColumns() ImGui::Separator(); ImGui::TreePop(); } + + if (disable_indent) + ImGui::PopStyleVar(); ImGui::PopID(); } diff --git a/imgui_internal.h b/imgui_internal.h index b0a26a95..4d8faa05 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1123,7 +1123,7 @@ struct IMGUI_API ImGuiWindowTempData ImVec2 PrevLineSize; float PrevLineTextBaseOffset; int TreeDepth; - ImU32 TreeDepthMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31 + ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. ImGuiID LastItemId; ImGuiItemStatusFlags LastItemStatusFlags; ImRect LastItemRect; // Interaction rect @@ -1165,7 +1165,7 @@ struct IMGUI_API ImGuiWindowTempData CurrentLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; TreeDepth = 0; - TreeDepthMayJumpToParentOnPop = 0x00; + TreeStoreMayJumpToParentOnPop = 0x00; LastItemId = 0; LastItemStatusFlags = 0; LastItemRect = LastItemDisplayRect = ImRect(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 82d792d6..42afb20e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5073,7 +5073,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) - window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth); + window->DC.TreeStoreMayJumpToParentOnPop |= (1 << window->DC.TreeDepth); bool item_add = ItemAdd(interact_bb, id); window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; @@ -5223,12 +5223,12 @@ void ImGui::TreePop() window->DC.TreeDepth--; if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) - if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth))) + if (g.NavIdIsAlive && (window->DC.TreeStoreMayJumpToParentOnPop & (1 << window->DC.TreeDepth))) { SetNavID(window->IDStack.back(), g.NavLayer); NavMoveRequestCancel(); } - window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; + window->DC.TreeStoreMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1; IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. PopID(); From 16b18b265ee5c9bdcc8ce7ce56a296fe76d6d602 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 11:34:07 +0200 Subject: [PATCH 06/12] MenuItem, BeginMenu: Fix undesirable tall frames in horizontal layout context, which would be visible when trying to use rounded selectable/menus. PushStyleVar: Added comments in the assert message. Minor tweaks. --- imgui.cpp | 4 ++-- imgui_widgets.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7a169bf8..888d3f49 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6006,7 +6006,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) *pvar = val; return; } - IM_ASSERT(0); // Called function with wrong-type? Variable is not a float. + IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!"); } void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) @@ -6020,7 +6020,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) *pvar = val; return; } - IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2. + IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!"); } void ImGui::PopStyleVar(int count) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 42afb20e..708bf0c3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5405,7 +5405,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bb.Max.x -= (GetContentRegionMax().x - max_x); } - if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); RenderTextClipped(bb_inner.Min, bb_inner.Max, label, NULL, &label_size, style.SelectableTextAlign, &bb); if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); @@ -5877,10 +5877,11 @@ void ImGui::EndMenuBar() { // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost) - IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check + const ImGuiNavLayer layer = ImGuiNavLayer_Menu; + IM_ASSERT(window->DC.NavLayerActiveMaskNext & (1 << layer)); // Sanity check FocusWindow(window); - SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]); - g.NavLayer = ImGuiNavLayer_Menu; + SetNavIDWithRectRel(window->NavLastIds[layer], layer, window->NavRectRel[layer]); + g.NavLayer = layer; g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; NavMoveRequestCancel(); @@ -5930,7 +5931,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() popup_pos = ImVec2(pos.x - 1.0f - (float)(int)(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); - PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); float w = label_size.x; pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f)); PopStyleVar(); @@ -6074,7 +6075,7 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, boo // Note that in this situation we render neither the shortcut neither the selected tick mark float w = label_size.x; window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); - PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); pressed = Selectable(label, false, flags, ImVec2(w, 0.0f)); PopStyleVar(); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). From 4dc4ace8644923151364fc659f0aba751667ed5e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 11:46:55 +0200 Subject: [PATCH 07/12] Window: Fixed window with the AlwaysAutoResize flag unnecessarily extending their hovering boundaries by a few pixels (this is used to facilitate resizing from borders when available for a given window). One of the noticeable minor side effect was that navigating menus would have had a tendency to disable highlight from parent menu items earlier than necessary while approaching the child menu. + Changelog fixed unfinished sentence and tweaks, --- docs/CHANGELOG.txt | 21 +++++++++++++-------- imgui.cpp | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f982ff08..97871ceb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,31 +46,36 @@ Other Changes: - InputText: Work-around for buggy standard libraries where isprint('\t') returns true. (#2467, #1336) - InputText: Fixed ImGuiInputTextFlags_AllowTabInput leading to two tabs characters being inserted if the back-end provided both Key and Character input. (#2467, #1336) -- Added SetNextItemWidth() helper to avoid using PushItemWidth/PopItemWidth() for single items. +- Layout: Added SetNextItemWidth() helper to avoid using PushItemWidth/PopItemWidth() for single items. Note that SetNextItemWidth() currently only affect the same subset of items as PushItemWidth(), - generally referred to as the large framed+labeled items. - Because the new SetNextItemWidth() function is explicit + generally referred to as the large framed+labeled items. Because the new SetNextItemWidth() + function is explicit we may later extend its effect to more items. +- Layout: Fixed PushItemWidth(-width) for right-side alignment laying out some items (button, listbox, etc.) + with negative sizes if the 'width' argument was smaller than the available width at the time of item + submission. +- Window: Fixed window with the AlwaysAutoResize flag unnecessarily extending their hovering boundaries + by a few pixels (this is used to facilitate resizing from borders when available for a given window). + One of the noticeable minor side effect was that navigating menus would have had a tendency to disable + highlight from parent menu items earlier than necessary while approaching the child menu. +- Window: Close button is horizontally aligned with style.FramePadding.x. - GetMouseDragDelta(): also returns the delta on the mouse button released frame. (#2419) - GetMouseDragDelta(): verify that mouse positions are valid otherwise returns zero. - Inputs: Also add support for horizontal scroll with Shift+Mouse Wheel. (#2424, #1463) [@LucaRood] - PlotLines, PlotHistogram: Ignore NaN values when calculating min/max bounds. (#2485) -- Window: Window close button is horizontally aligned with style.FramePadding.x. - Columns: Fixed boundary of clipping being off by 1 pixel within the left column. - Combo, Slider, Scrollbar: Improve rendering in situation when there's only a few pixels available (<3 pixels). -- Misc: Fixed PushItemWidth(-width) (for right-side alignment) laying out certain items (button, listbox, etc.) - with negative sizes if the 'width' argument was smaller than the available width at the time of item submission, - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. - Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. - Examples: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early, and help users understand what they are missing. (#2421) -- Examples: Emscripten: Added Emscripten+SDL+GLES2 example. (#2494, #2492, #2351, #336) [@nicolasnoble] +- Examples: Emscripten: Added Emscripten+SDL+GLES2 example. (#2494, #2492, #2351, #336) [@nicolasnoble, @redblobgames] +- Examples: SDL: Added support for SDL_GameController gamepads (enable with ImGuiConfigFlags_NavEnableGamepad). (#2509) [@DJLink] - Examples: OpenGL3: Minor tweaks + not calling glBindBuffer more than necessary in the render loop. - Examples: Vulkan: Fixed in-flight buffers issues when using multi-viewports. (#2461, #2348, #2378, #2097) - Examples: Vulkan: Added missing support for 32-bit indices (#define ImDrawIdx unsigned int). - Examples: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like. - Examples: Vulkan: Added ImGui_ImplVulkan_SetMinImageCount() to change min image count at runtime. (#2071) [@nathanvoglsam] -- Examples: SDL: Added support for SDL_GameController gamepads (enable with ImGuiConfigFlags_NavEnableGamepad). (#2509) [@DJLink] - Examples: DirectX9: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). (#2454) - Examples: DirectX10/11/12, Allegro, Marmalade: Render functions early out when display size is zero (minimized). (#2496) - Examples: GLUT: Fixed existing FreeGLUT example to work with regular GLUT. (#2465) [@andrewwillmott] diff --git a/imgui.cpp b/imgui.cpp index 888d3f49..c253a1c6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4067,7 +4067,7 @@ static void FindHoveredWindow() // Using the clipped AABB, a child window will typically be clipped by its parent (not always) ImRect bb(window->OuterRectClipped); - if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize)) + if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) bb.Expand(padding_regular); else bb.Expand(padding_for_resize_from_edges); From 1ca6e5b59faa72ed487e5fe17d2923c15955b8b8 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 12:01:01 +0200 Subject: [PATCH 08/12] Examples: Glut: Added note about missing cursor support. (#2375, #2465) --- examples/imgui_impl_glut.cpp | 1 + examples/imgui_impl_glut.h | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/imgui_impl_glut.cpp b/examples/imgui_impl_glut.cpp index d8bd7498..546a7b85 100644 --- a/examples/imgui_impl_glut.cpp +++ b/examples/imgui_impl_glut.cpp @@ -6,6 +6,7 @@ // Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I +// [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing clipboard support (not supported by Glut). // [ ] Platform: Missing gamepad support. diff --git a/examples/imgui_impl_glut.h b/examples/imgui_impl_glut.h index 8fde9bab..89be9993 100644 --- a/examples/imgui_impl_glut.h +++ b/examples/imgui_impl_glut.h @@ -6,6 +6,7 @@ // Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I +// [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing clipboard support (not supported by Glut). // [ ] Platform: Missing gamepad support. From 59a3f0476d0a4e6d5c294c5f2389d187c76b2c7c Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 15:21:22 +0200 Subject: [PATCH 09/12] Internals: Using more explicit PushOverrideID() helper + renamed equivalent internal tree helper. --- imgui.cpp | 7 +++++++ imgui_internal.h | 3 ++- imgui_widgets.cpp | 18 ++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c253a1c6..6eeed76b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6682,6 +6682,13 @@ void ImGui::PushID(int int_id) window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id)); } +// Push a given id value ignoring the ID stack as a seed. +void ImGui::PushOverrideID(ImGuiID id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->IDStack.push_back(id); +} + void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; diff --git a/imgui_internal.h b/imgui_internal.h index 4d8faa05..7aeaf679 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1431,6 +1431,7 @@ namespace ImGui IMGUI_API void SetHoveredID(ImGuiID id); IMGUI_API void KeepAliveID(ImGuiID id); IMGUI_API void MarkItemEdited(ImGuiID id); + IMGUI_API void PushOverrideID(ImGuiID id); // Basic Helpers for widget code IMGUI_API void ItemSize(const ImVec2& size, float text_offset_y = 0.0f); @@ -1546,7 +1547,7 @@ namespace ImGui IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f); IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging - IMGUI_API void TreePushRawID(ImGuiID id); + IMGUI_API void TreePushOverrideID(ImGuiID id); // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 708bf0c3..950c8cf9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5082,7 +5082,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (!item_add) { if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) - TreePushRawID(id); + TreePushOverrideID(id); IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5186,7 +5186,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) - TreePushRawID(id); + TreePushOverrideID(id); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); return is_open; } @@ -5207,7 +5207,7 @@ void ImGui::TreePush(const void* ptr_id) PushID(ptr_id ? ptr_id : (const void*)"#TreePush"); } -void ImGui::TreePushRawID(ImGuiID id) +void ImGui::TreePushOverrideID(ImGuiID id) { ImGuiWindow* window = GetCurrentWindow(); Indent(); @@ -6211,7 +6211,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG return false; if ((flags & ImGuiTabBarFlags_DockNode) == 0) - window->IDStack.push_back(tab_bar->ID); + PushOverrideID(tab_bar->ID); // Add to stack g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); @@ -6663,7 +6663,8 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) { ImGuiContext& g = *GImGui; - if (g.CurrentWindow->SkipItems) + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) return false; ImGuiTabBar* tab_bar = g.CurrentTabBar; @@ -6676,7 +6677,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; - g.CurrentWindow->IDStack.push_back(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) } return ret; } @@ -6684,7 +6685,8 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f void ImGui::EndTabItem() { ImGuiContext& g = *GImGui; - if (g.CurrentWindow->SkipItems) + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) return; ImGuiTabBar* tab_bar = g.CurrentTabBar; @@ -6696,7 +6698,7 @@ void ImGui::EndTabItem() IM_ASSERT(tab_bar->LastTabItemIdx >= 0); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) - g.CurrentWindow->IDStack.pop_back(); + window->IDStack.pop_back(); } bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags) From 0ca1675ff9d079fb67a377399ceea6643b4667c8 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 15:46:10 +0200 Subject: [PATCH 10/12] Internals: TempInputText: Rename InputScalarAsWidgetReplacement() -> TempInputTextScalar(), ScalarAsInputTextId -> TempInputTextId, small tidying up in affected functions. --- docs/TODO.txt | 2 +- imgui.cpp | 4 ++-- imgui_internal.h | 7 ++++--- imgui_widgets.cpp | 40 +++++++++++++++++++++------------------- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 57845d36..9e64b163 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -143,7 +143,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - image/image button: misalignment on padded/bordered button? - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that? - image button: not taking an explicit id can be problematic. (#2464, #1390) - - slider/drag: ctrl+click when format doesn't include a % character.. disable? display underlying value in default format? (see InputScalarAsWidgetReplacement) + - slider/drag: ctrl+click when format doesn't include a % character.. disable? display underlying value in default format? (see TempInputTextScalar) - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar). (#1946) - slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate. diff --git a/imgui.cpp b/imgui.cpp index 6eeed76b..2dbc4207 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3515,8 +3515,8 @@ void ImGui::NewFrame() g.ActiveIdIsAlive = 0; g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; - if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId) - g.ScalarAsInputTextId = 0; + if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId) + g.TempInputTextId = 0; // Drag and drop g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; diff --git a/imgui_internal.h b/imgui_internal.h index 7aeaf679..0cf8f03b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -938,7 +938,7 @@ struct ImGuiContext // Widget state ImGuiInputTextState InputTextState; ImFont InputTextPasswordFont; - ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets ImVec4 ColorPickerRef; bool DragCurrentAccumDirty; @@ -1075,7 +1075,7 @@ struct ImGuiContext CurrentTabBar = NULL; - ScalarAsInputTextId = 0; + TempInputTextId = 0; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; DragCurrentAccumDirty = false; DragCurrentAccum = 0.0f; @@ -1559,7 +1559,8 @@ namespace ImGui // InputText IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); + IMGUI_API bool TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); + inline bool TempInputTextIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputTextId == id); } // Color IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 950c8cf9..46eaf7f3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2000,9 +2000,10 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box - bool start_text_input = false; + bool temp_input_is_active = TempInputTextIsActive(id); + bool temp_input_start = false; const bool focus_requested = FocusableItemRegister(window, id); - if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) + if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && !temp_input_is_active)) { SetActiveID(id, window); SetFocusID(id, window); @@ -2010,15 +2011,15 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) { - start_text_input = true; - g.ScalarAsInputTextId = 0; + temp_input_start = true; + g.TempInputTextId = 0; } } - if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + if (temp_input_is_active || temp_input_start) { window->DC.CursorPos = frame_bb.Min; FocusableItemUnregister(window); - return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); + return TempInputTextScalar(frame_bb, id, label, data_type, v, format); } // Actual drag behavior @@ -2442,10 +2443,11 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Slider turns it into an input box - bool start_text_input = false; + bool temp_input_is_active = TempInputTextIsActive(id); + bool temp_input_start = false; const bool focus_requested = FocusableItemRegister(window, id); const bool hovered = ItemHoverable(frame_bb, id); - if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) + if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && !temp_input_is_active)) { SetActiveID(id, window); SetFocusID(id, window); @@ -2453,15 +2455,15 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id) { - start_text_input = true; - g.ScalarAsInputTextId = 0; + temp_input_start = true; + g.TempInputTextId = 0; } } - if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) + if (temp_input_is_active || temp_input_start) { window->DC.CursorPos = frame_bb.Min; FocusableItemUnregister(window); - return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); + return TempInputTextScalar(frame_bb, id, label, data_type, v, format); } // Draw frame @@ -2648,7 +2650,7 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, // - ImParseFormatFindEnd() [Internal] // - ImParseFormatTrimDecorations() [Internal] // - ImParseFormatPrecision() [Internal] -// - InputScalarAsWidgetReplacement() [Internal] +// - TempInputTextScalar() [Internal] // - InputScalar() // - InputScalarN() // - InputFloat() @@ -2734,16 +2736,16 @@ int ImParseFormatPrecision(const char* fmt, int default_precision) return (precision == INT_MAX) ? default_precision : precision; } -// Create text input in place of an active drag/slider (used when doing a CTRL+Click on drag/slider widgets) +// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) // FIXME: Facilitate using this in variety of other situations. -bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) +bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) { IM_UNUSED(id); ImGuiContext& g = *GImGui; - // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id. + // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. // We clear ActiveID on the first frame to allow the InputText() taking it back. - if (g.ScalarAsInputTextId == 0) + if (g.TempInputTextId == 0) ClearActiveID(); char fmt_buf[32]; @@ -2753,11 +2755,11 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c ImStrTrimBlanks(data_buf); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); - if (g.ScalarAsInputTextId == 0) + if (g.TempInputTextId == 0) { // First frame we started displaying the InputText widget, we expect it to take the active id. IM_ASSERT(g.ActiveId == id); - g.ScalarAsInputTextId = g.ActiveId; + g.TempInputTextId = g.ActiveId; } if (value_changed) return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL); From dd15b44230c7b9cad7609cedf3884aec579860dc Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 16:04:45 +0200 Subject: [PATCH 11/12] Internals: TempInputText: Tidying up DragScalar / SliderScalar / TempInputTextScalar. --- imgui_widgets.cpp | 73 +++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 46eaf7f3..9b212545 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1989,8 +1989,6 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa if (!ItemAdd(total_bb, id, &frame_bb)) return false; - const bool hovered = ItemHoverable(frame_bb, id); - // Default format string when passing NULL // Patch old "%.0f" format string to use "%d", read function comments for more details. IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); @@ -2000,38 +1998,38 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box + const bool hovered = ItemHoverable(frame_bb, id); bool temp_input_is_active = TempInputTextIsActive(id); bool temp_input_start = false; - const bool focus_requested = FocusableItemRegister(window, id); - if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && !temp_input_is_active)) + if (!temp_input_is_active) { - SetActiveID(id, window); - SetFocusID(id, window); - FocusWindow(window); - g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) + const bool focus_requested = FocusableItemRegister(window, id); + if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || g.NavInputId == id) { - temp_input_start = true; - g.TempInputTextId = 0; + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) + { + temp_input_start = true; + FocusableItemUnregister(window); + } } } if (temp_input_is_active || temp_input_start) - { - window->DC.CursorPos = frame_bb.Min; - FocusableItemUnregister(window); return TempInputTextScalar(frame_bb, id, label, data_type, v, format); - } - - // Actual drag behavior - const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None); - if (value_changed) - MarkItemEdited(id); // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + // Drag behavior + const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None); + if (value_changed) + MarkItemEdited(id); + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); @@ -2443,28 +2441,27 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Slider turns it into an input box + const bool hovered = ItemHoverable(frame_bb, id); bool temp_input_is_active = TempInputTextIsActive(id); bool temp_input_start = false; - const bool focus_requested = FocusableItemRegister(window, id); - const bool hovered = ItemHoverable(frame_bb, id); - if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && !temp_input_is_active)) + if (!temp_input_is_active) { - SetActiveID(id, window); - SetFocusID(id, window); - FocusWindow(window); - g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id) + const bool focus_requested = FocusableItemRegister(window, id); + if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) { - temp_input_start = true; - g.TempInputTextId = 0; + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id) + { + temp_input_start = true; + FocusableItemUnregister(window); + } } } if (temp_input_is_active || temp_input_start) - { - window->DC.CursorPos = frame_bb.Min; - FocusableItemUnregister(window); return TempInputTextScalar(frame_bb, id, label, data_type, v, format); - } // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); @@ -2740,12 +2737,12 @@ int ImParseFormatPrecision(const char* fmt, int default_precision) // FIXME: Facilitate using this in variety of other situations. bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format) { - IM_UNUSED(id); ImGuiContext& g = *GImGui; // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. // We clear ActiveID on the first frame to allow the InputText() taking it back. - if (g.TempInputTextId == 0) + const bool init = (g.TempInputTextId != id); + if (init) ClearActiveID(); char fmt_buf[32]; @@ -2753,9 +2750,11 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label, format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); ImStrTrimBlanks(data_buf); + + g.CurrentWindow->DC.CursorPos = bb.Min; ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); - if (g.TempInputTextId == 0) + if (init) { // First frame we started displaying the InputText widget, we expect it to take the active id. IM_ASSERT(g.ActiveId == id); From 56c3aaf6bd06bbde95138b9dad61e1fa33ccfde8 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 25 Apr 2019 16:17:48 +0200 Subject: [PATCH 12/12] Nav: Fixed Drag/Slider functions going into text input mode when keyboard CTRL is held while pressing NavActivate. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 97871ceb..dbe87c97 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,7 @@ Other Changes: - PlotLines, PlotHistogram: Ignore NaN values when calculating min/max bounds. (#2485) - Columns: Fixed boundary of clipping being off by 1 pixel within the left column. - Combo, Slider, Scrollbar: Improve rendering in situation when there's only a few pixels available (<3 pixels). +- Nav: Fixed Drag/Slider functions going into text input mode when keyboard CTRL is held while pressing NavActivate. - Misc: Added IM_MALLOC/IM_FREE macros mimicking IM_NEW/IM_DELETE so user doesn't need to revert to using the ImGui::MemAlloc()/MemFree() calls directly. - Metrics: Added "Show windows rectangles" tool to visualize the different rectangles. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9b212545..bebbf3d8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2004,13 +2004,15 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa if (!temp_input_is_active) { const bool focus_requested = FocusableItemRegister(window, id); - if (focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || g.NavInputId == id) + const bool clicked = (hovered && g.IO.MouseClicked[0]); + const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]); + if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id) { SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - if (focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id) + if (focus_requested || (clicked && g.IO.KeyCtrl) || double_clicked || g.NavInputId == id) { temp_input_start = true; FocusableItemUnregister(window); @@ -2447,13 +2449,14 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co if (!temp_input_is_active) { const bool focus_requested = FocusableItemRegister(window, id); - if (focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) + const bool clicked = (hovered && g.IO.MouseClicked[0]); + if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id) { SetActiveID(id, window); SetFocusID(id, window); FocusWindow(window); g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - if (focus_requested || g.IO.KeyCtrl || g.NavInputId == id) + if (focus_requested || (clicked && g.IO.KeyCtrl) || g.NavInputId == id) { temp_input_start = true; FocusableItemUnregister(window);