diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index d3ccffd23..62f7af672 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -215,6 +215,7 @@ bool ImGui_ImplA5_ProcessEvent(ALLEGRO_EVENT *ev) { case ALLEGRO_EVENT_MOUSE_AXES: io.MouseWheel += ev->mouse.dz; + io.MouseWheelH += ev->mouse.dw; return true; case ALLEGRO_EVENT_KEY_CHAR: if (ev->keyboard.display == g_Display) diff --git a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm index 9db45d0f2..5b56d3ca3 100644 --- a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm +++ b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm @@ -587,9 +587,9 @@ void ImGui_ClipboardCallback(uSynergyCookie cookie, enum uSynergyClipboardFormat io.MouseDown[i] = g_MousePressed[i]; } - // This is an arbitrary scaling factor that works for me. Not sure what units these - // mousewheel values from synergy are supposed to be in + // This is an arbitrary scaling factor that works for me. Not sure what units these mousewheel values from synergy are supposed to be in. io.MouseWheel = g_mouseWheelY / 500.0; + io.MouseWheelH = g_mouseWheelX / 500.0; } else { diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index 4f7117a7b..14a47c4af 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -275,6 +275,9 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa case WM_MOUSEWHEEL: io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return 0; case WM_MOUSEMOVE: io.MousePos.x = (signed short)(lParam); io.MousePos.y = (signed short)(lParam >> 16); diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 5df7bf1f0..4963fc12e 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -282,6 +282,9 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa case WM_MOUSEWHEEL: io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return 0; case WM_MOUSEMOVE: io.MousePos.x = (signed short)(lParam); io.MousePos.y = (signed short)(lParam >> 16); diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 18ec0d9b5..a4e676914 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -221,6 +221,9 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa case WM_MOUSEWHEEL: io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return 0; case WM_MOUSEMOVE: io.MousePos.x = (signed short)(lParam); io.MousePos.y = (signed short)(lParam >> 16); diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index 39623cc4d..36fc8328c 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -21,7 +21,6 @@ // Data static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; static CIwTexture* g_FontTexture = NULL; static char* g_ClipboardText = NULL; static bool g_osdKeyboardEnabled = false; @@ -128,9 +127,9 @@ int32 ImGui_Marmalade_PointerButtonEventCallback(void* SystemData, void* pUserDa if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE) g_MousePressed[2] = true; if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP) - g_MouseWheel += pEvent->m_y; + io.MouseWheel += pEvent->m_y; if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN) - g_MouseWheel += pEvent->m_y; + io.MouseWheel += pEvent->m_y; } return 0; @@ -282,9 +281,6 @@ void ImGui_Marmalade_NewFrame() g_MousePressed[i] = false; } - io.MouseWheel = g_MouseWheel; - g_MouseWheel = 0.0f; - // TODO: Hide OS mouse cursor if ImGui is drawing it // s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1)); diff --git a/examples/opengl2_example/imgui_impl_glfw_gl2.cpp b/examples/opengl2_example/imgui_impl_glfw_gl2.cpp index 4ce831d9b..e5fe2f47b 100644 --- a/examples/opengl2_example/imgui_impl_glfw_gl2.cpp +++ b/examples/opengl2_example/imgui_impl_glfw_gl2.cpp @@ -31,7 +31,6 @@ static GLFWwindow* g_Window = NULL; static double g_Time = 0.0f; static bool g_MouseJustPressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; static GLuint g_FontTexture = 0; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) @@ -134,9 +133,11 @@ void ImGui_ImplGlfwGL2_MouseButtonCallback(GLFWwindow*, int button, int action, g_MouseJustPressed[button] = true; } -void ImGui_ImplGlfwGL2_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) +void ImGui_ImplGlfwGL2_ScrollCallback(GLFWwindow*, double xoffset, double yoffset) { - g_MouseWheel += (float)yoffset; // Use fractional mouse wheel. + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; } void ImGui_ImplGlfwGL2_KeyCallback(GLFWwindow*, int key, int, int action, int mods) @@ -295,9 +296,6 @@ void ImGui_ImplGlfwGL2_NewFrame() g_MouseJustPressed[i] = false; } - io.MouseWheel = g_MouseWheel; - g_MouseWheel = 0.0f; - // Hide OS mouse cursor if ImGui is drawing it glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index f35b2654c..a71fc515d 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -25,7 +25,6 @@ static GLFWwindow* g_Window = NULL; static double g_Time = 0.0f; static bool g_MouseJustPressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; static GLuint g_FontTexture = 0; static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; @@ -155,9 +154,11 @@ void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow*, int button, int action, g_MouseJustPressed[button] = true; } -void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) +void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double xoffset, double yoffset) { - g_MouseWheel += (float)yoffset; // Use fractional mouse wheel. + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; } void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods) @@ -407,9 +408,6 @@ void ImGui_ImplGlfwGL3_NewFrame() g_MouseJustPressed[i] = false; } - io.MouseWheel = g_MouseWheel; - g_MouseWheel = 0.0f; - // Hide OS mouse cursor if ImGui is drawing it glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl_gl2.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl_gl2.cpp index 6bcd4c388..76def29c3 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl_gl2.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl_gl2.cpp @@ -24,7 +24,6 @@ // Data static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; static GLuint g_FontTexture = 0; // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) @@ -132,10 +131,10 @@ bool ImGui_ImplSdlGL2_ProcessEvent(SDL_Event* event) { case SDL_MOUSEWHEEL: { - if (event->wheel.y > 0) - g_MouseWheel = 1; - if (event->wheel.y < 0) - g_MouseWheel = -1; + if (event->wheel.x > 0) io.MouseWheelH += 1; + if (event->wheel.x < 0) io.MouseWheelH -= 1; + if (event->wheel.y > 0) io.MouseWheel += 1; + if (event->wheel.y < 0) io.MouseWheel -= 1; return true; } case SDL_MOUSEBUTTONDOWN: @@ -274,12 +273,10 @@ void ImGui_ImplSdlGL2_NewFrame(SDL_Window *window) int mx, my; Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - io.MouseWheel = g_MouseWheel; io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; - g_MouseWheel = 0.0f; // We need to use SDL_CaptureMouse() to easily retrieve mouse coordinates outside of the client area. This is only supported from SDL 2.0.4 (released Jan 2016) #if (SDL_MAJOR_VERSION >= 2) && (SDL_MINOR_VERSION >= 0) && (SDL_PATCHLEVEL >= 4) diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index ef1957a5d..35d9cdde1 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -19,7 +19,6 @@ // Data static double g_Time = 0.0f; static bool g_MousePressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; static GLuint g_FontTexture = 0; static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; @@ -154,10 +153,10 @@ bool ImGui_ImplSdlGL3_ProcessEvent(SDL_Event* event) { case SDL_MOUSEWHEEL: { - if (event->wheel.y > 0) - g_MouseWheel = 1; - if (event->wheel.y < 0) - g_MouseWheel = -1; + if (event->wheel.x > 0) io.MouseWheelH += 1; + if (event->wheel.x < 0) io.MouseWheelH -= 1; + if (event->wheel.y > 0) io.MouseWheel += 1; + if (event->wheel.y < 0) io.MouseWheel -= 1; return true; } case SDL_MOUSEBUTTONDOWN: @@ -385,12 +384,10 @@ void ImGui_ImplSdlGL3_NewFrame(SDL_Window* window) int mx, my; Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - io.MouseWheel = g_MouseWheel; io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; - g_MouseWheel = 0.0f; // We need to use SDL_CaptureMouse() to easily retrieve mouse coordinates outside of the client area. This is only supported from SDL 2.0.4 (released Jan 2016) #if (SDL_MAJOR_VERSION >= 2) && (SDL_MINOR_VERSION >= 0) && (SDL_PATCHLEVEL >= 4) diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 0af380cc6..b9e6d78f2 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -24,8 +24,7 @@ // GLFW Data static GLFWwindow* g_Window = NULL; static double g_Time = 0.0f; -static bool g_MousePressed[3] = { false, false, false }; -static float g_MouseWheel = 0.0f; +static bool g_MouseJustPressed[3] = { false, false, false }; // Vulkan Data static VkAllocationCallbacks* g_Allocator = NULL; @@ -327,12 +326,14 @@ static void ImGui_ImplGlfwVulkan_SetClipboardText(void* user_data, const char* t void ImGui_ImplGlfwVulkan_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) { if (action == GLFW_PRESS && button >= 0 && button < 3) - g_MousePressed[button] = true; + g_MouseJustPressed[button] = true; } -void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) +void ImGui_ImplGlfwVulkan_ScrollCallback(GLFWwindow*, double xoffset, double yoffset) { - g_MouseWheel += (float)yoffset; // Use fractional mouse wheel. + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; } void ImGui_ImplGlfwVulkan_KeyCallback(GLFWwindow*, int key, int, int action, int mods) @@ -821,13 +822,10 @@ void ImGui_ImplGlfwVulkan_NewFrame() for (int i = 0; i < 3; i++) { - io.MouseDown[i] = g_MousePressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. - g_MousePressed[i] = false; + io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. + g_MouseJustPressed[i] = false; } - io.MouseWheel = g_MouseWheel; - g_MouseWheel = 0.0f; - // Hide OS mouse cursor if ImGui is drawing it glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); diff --git a/imgui.cpp b/imgui.cpp index 62f86342c..d2d81ef86 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -169,7 +169,7 @@ - A minimal render function skeleton may be: - void void MyRenderFunction(ImDrawData* draw_data)(ImDrawData* draw_data) + void void MyRenderFunction(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled // TODO: Setup viewport, orthographic projection matrix @@ -3061,8 +3061,8 @@ void ImGui::NewFrame() // (We pass an error message in the assert expression as a trick to get it visible to programmers who are not using a debugger, as most assert handlers display their argument) IM_ASSERT(g.IO.DeltaTime >= 0.0f && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)"); IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value"); - IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?"); - IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?"); + IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); + IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?"); IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)"); IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); @@ -3277,38 +3277,46 @@ void ImGui::NewFrame() if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload) g.HoveredWindow = g.HoveredRootWindow = NULL; - // Scale & Scrolling - if (g.HoveredWindow && g.IO.MouseWheel != 0.0f && !g.HoveredWindow->Collapsed) + // Mouse wheel scrolling, scale + if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f)) { + // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set). ImGuiWindow* window = g.HoveredWindow; - if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling) - { - // Zoom / Scale window - const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); - const float scale = new_font_scale / window->FontWindowScale; - window->FontWindowScale = new_font_scale; + ImGuiWindow* scroll_window = window; + while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow) + scroll_window = scroll_window->ParentWindow; + const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs); - const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; - window->Pos += offset; - window->PosFloat += offset; - window->Size *= scale; - window->SizeFull *= scale; - } - else if (!g.IO.KeyCtrl) + if (g.IO.MouseWheel != 0.0f) { - // Mouse wheel Scrolling - // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set). - ImGuiWindow* scroll_window = window; - while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow) - scroll_window = scroll_window->ParentWindow; - - if (!(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs)) + if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling) { + // Zoom / Scale window + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + window->Pos += offset; + window->PosFloat += offset; + window->Size *= scale; + window->SizeFull *= scale; + } + else if (!g.IO.KeyCtrl && scroll_allowed) + { + // Mouse wheel vertical scrolling float scroll_amount = 5 * scroll_window->CalcFontSize(); scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f); SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount); } } + if (g.IO.MouseWheelH != 0.0f && scroll_allowed) + { + // Mouse wheel horizontal scrolling (for hardware that supports it) + float scroll_amount = scroll_window->CalcFontSize(); + if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse)) + SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_amount); + } } // Pressing TAB activate widget focus @@ -3839,7 +3847,7 @@ void ImGui::EndFrame() g.Windows.swap(g.WindowsSortBuffer); // Clear Input data for next frame - g.IO.MouseWheel = 0.0f; + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); g.FrameCountEnded = g.FrameCount; @@ -3872,17 +3880,16 @@ void ImGui::Render() g.DrawDataBuilder.FlattenIntoSingleLayer(); // Draw software mouse cursor if requested - if (g.IO.MouseDrawCursor) + ImVec2 offset, size, uv[4]; + if (g.IO.MouseDrawCursor && g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &offset, &size, &uv[0], &uv[2])) { - const ImGuiMouseCursorData& cursor_data = g.MouseCursorData[g.MouseCursor]; - const ImVec2 pos = g.IO.MousePos - cursor_data.HotOffset; - const ImVec2 size = cursor_data.Size; + const ImVec2 pos = g.IO.MousePos - offset; const ImTextureID tex_id = g.IO.Fonts->TexID; g.OverlayDrawList.PushTextureID(tex_id); - g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow - g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow - g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,255)); // Black border - g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], IM_COL32(255,255,255,255)); // White fill + g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow + g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, uv[2], uv[3], IM_COL32(0,0,0,48)); // Shadow + g.OverlayDrawList.AddImage(tex_id, pos, pos + size, uv[2], uv[3], IM_COL32(0,0,0,255)); // Black border + g.OverlayDrawList.AddImage(tex_id, pos, pos + size, uv[0], uv[1], IM_COL32(255,255,255,255)); // White fill g.OverlayDrawList.PopTextureID(); } if (!g.OverlayDrawList.VtxBuffer.empty()) @@ -4345,9 +4352,7 @@ bool ImGui::IsKeyReleased(int user_key_index) ImGuiContext& g = *GImGui; if (user_key_index < 0) return false; IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown)); - if (g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]) - return true; - return false; + return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index]; } bool ImGui::IsMouseDown(int button) @@ -5476,12 +5481,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { - const bool is_pinned_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) // Initialize window->ParentWindow = parent_window; window->RootWindow = window->RootNonPopupWindow = window; - if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !is_pinned_child_tooltip) + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !window_is_child_tooltip) window->RootWindow = parent_window->RootWindow; if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) window->RootNonPopupWindow = parent_window->RootNonPopupWindow; @@ -5600,7 +5605,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); - if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !is_pinned_child_tooltip) + if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) window->Pos = window->PosFloat = parent_window->DC.CursorPos; } @@ -5631,7 +5636,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } // Position tooltip (always follows mouse) - if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !is_pinned_child_tooltip) + if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) { ImVec2 ref_pos = (!g.NavDisableHighlight && g.NavDisableMouseHover) ? NavCalcPreferredMousePos() : g.IO.MousePos; ImRect rect_to_avoid(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24, ref_pos.y + 24); // FIXME: Completely hard-coded. Store boxes in mouse cursor data? Scale? Center on cursor hit-point? @@ -5689,7 +5694,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); ImRect fullscreen_rect(GetVisibleRect()); - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !is_pinned_child_tooltip) + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true); else PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true); diff --git a/imgui.h b/imgui.h index 377d2ff86..156cb5375 100644 --- a/imgui.h +++ b/imgui.h @@ -966,7 +966,8 @@ struct ImGuiIO 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: left, right, middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). 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: 1 unit scrolls about 5 lines text. + float MouseWheel; // Mouse wheel: 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 back ends. bool MouseDrawCursor; // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyShift; // Keyboard modifier pressed: Shift @@ -1651,9 +1652,12 @@ struct ImFontAtlas IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font. - IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } + // Internals + IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); + IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + //------------------------------------------- // Members //------------------------------------------- @@ -1668,6 +1672,7 @@ struct ImFontAtlas unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 int TexWidth; // Texture width calculated during Build(). int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a622d544b..1d21db461 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1358,7 +1358,6 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_Count_][ { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE }; - ImFontAtlas::ImFontAtlas() { TexID = NULL; @@ -1367,7 +1366,8 @@ ImFontAtlas::ImFontAtlas() TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; TexWidth = TexHeight = 0; - TexUvWhitePixel = ImVec2(0, 0); + TexUvScale = ImVec2(0.0f, 0.0f); + TexUvWhitePixel = ImVec2(0.0f, 0.0f); for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) CustomRectIds[n] = -1; } @@ -1611,8 +1611,27 @@ void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, I { IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed - *out_uv_min = ImVec2((float)rect->X / TexWidth, (float)rect->Y / TexHeight); - *out_uv_max = ImVec2((float)(rect->X + rect->Width) / TexWidth, (float)(rect->Y + rect->Height) / TexHeight); + *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); +} + +bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +{ + if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_Count_) + return false; + + ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]]; + IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y); + ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; + *out_size = size; + *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; + out_uv_border[0] = (pos) * TexUvScale; + out_uv_border[1] = (pos + size) * TexUvScale; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; + out_uv_fill[0] = (pos) * TexUvScale; + out_uv_fill[1] = (pos + size) * TexUvScale; + return true; } bool ImFontAtlas::Build() @@ -1645,7 +1664,8 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) atlas->TexID = NULL; atlas->TexWidth = atlas->TexHeight = 0; - atlas->TexUvWhitePixel = ImVec2(0, 0); + atlas->TexUvScale = ImVec2(0.0f, 0.0f); + atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); atlas->ClearTexData(); // Count glyphs/ranges @@ -1754,6 +1774,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Create texture atlas->TexHeight = ImUpperPowerOfTwo(atlas->TexHeight); + atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); spc.pixels = atlas->TexPixelsAlpha8; @@ -1895,24 +1916,7 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00; atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00; } - const ImVec2 tex_uv_scale(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * tex_uv_scale.x, (r.Y + 0.5f) * tex_uv_scale.y); - - // Setup mouse cursors - for (int type = 0; type < ImGuiMouseCursor_Count_; type++) - { - ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type]; - ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][0] + ImVec2((float)r.X, (float)r.Y); - const ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][1]; - cursor_data.Type = type; - cursor_data.Size = size; - cursor_data.HotOffset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][2]; - cursor_data.TexUvMin[0] = (pos) * tex_uv_scale; - cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale; - pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; - cursor_data.TexUvMin[1] = (pos) * tex_uv_scale; - cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale; - } + atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y); } void ImFontAtlasBuildFinish(ImFontAtlas* atlas) diff --git a/imgui_internal.h b/imgui_internal.h index aaaa2c37b..27b10a71c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -39,7 +39,6 @@ struct ImGuiGroupData; struct ImGuiMenuColumns; struct ImGuiDrawContext; struct ImGuiTextEditState; -struct ImGuiMouseCursorData; struct ImGuiPopupRef; struct ImGuiWindow; struct ImGuiWindowSettings; @@ -400,16 +399,6 @@ struct ImGuiSettingsHandler ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } }; -// Mouse cursor data (used when io.MouseDrawCursor is set) -struct ImGuiMouseCursorData -{ - ImGuiMouseCursor Type; - ImVec2 HotOffset; - ImVec2 Size; - ImVec2 TexUvMin[2]; - ImVec2 TexUvMax[2]; -}; - // Storage for current popup stack struct ImGuiPopupRef { @@ -612,7 +601,6 @@ struct ImGuiContext float ModalWindowDarkeningRatio; ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays ImGuiMouseCursor MouseCursor; - ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]; // Drag and Drop bool DragDropActive; @@ -726,7 +714,6 @@ struct ImGuiContext OverlayDrawList._Data = &DrawListSharedData; OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging MouseCursor = ImGuiMouseCursor_Arrow; - memset(MouseCursorData, 0, sizeof(MouseCursorData)); DragDropActive = false; DragDropSourceFlags = 0;