-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DragXYZ mouse wrap around (warping) #228
Comments
When this is desired, would the user want to hide the cursor or not ? |
well i know what the use case in unity3D is and i guess it could be called a well known one: |
Quick note to mention that the gamepad/keyboard navigation branch #323 introduces a |
Edit: It's not wrapping but locking, but wrapping can be achieved the same way. My implementation: static bool pressed = false;
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && m_ViewportHovered)
{
ImGui::SetMouseCursor(ImGuiMouseCursor_None); // Hide cursor
ImVec2 newMousePosition = ImGui::GetMousePos();
if (!pressed)
{
pressed = true;
m_LockedMousePosition = newMousePosition;
}
Input::SetMousePosition(m_LockedMousePosition); // Call to glfwSetCursorPos();
// use the new mouse position and old one (m_LockedMousePosition) if desired.
// I use it for my Viewport
const ImVec2 change = (newMousePosition - m_LockedMousePosition) * m_MouseSensitivity;
yaw += change.x;
pitch = glm::clamp(pitch - change.y, -89.9f, 89.9f);
} But there is one problem here. As ImGui doesn't provide an API for SetMousePosition, I had to implement it the glfw way and with Multi viewports, glfw doesn't pass the events or handle input from any viewport outside of Main Window. Video attached for reference. 2022-09-15.01-28-02.mp4Edit 2: Fixed it by removing these two lines in GLFW/src/input.c // Remove or comment these lines
if (!_glfw.platform.windowFocused(window))
return; |
It does.
|
I don't think you should be using mouse global wrapping for a FPS camera view. |
Didn't knew it existed, Thanks for the info, switched to it and works like charm.
It's not wrapping, it's locking, mouse cursor is being tracked, the change/direction is passed further and then setting a new position on mouse cursor is called. Hence mouse cursor stays where it is and change/direction is consumed. |
Just wanted to add that some apps move the mouse back to where it was (on click release). E.g. Unity does not do it, but Blender does and moves it exactly to where is was clicked down. It's a nice addition when you have to tweak a bunch of stacked drags. So if there were to be warping maybe there could be a flag for that too. |
I will add another use case. In audio plugins, sometimes there are knobs that go from 0 to 1 where 1 and 0 produce the same result, and some audio hardware interfaces have continuous knobs that may control values in software, so in other words, certain values can be dragged infinitively. |
Here are proof of concept function relying on backend supporting Usage, e.g. in if (g.ActiveId == id)
WrapMousePos(1 << ImGuiAxis_X); Would be interested in feedback on multi-monitors with multi-viewports enabled, and in particular when there's monitor gaps. My intuition is that this counter-intuitively V2 may behave better in more situations: (V1) void WrapMousePosEx(int axises_mask, const ImRect& wrap_rect)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(axises_mask == 1 || axises_mask == 2 || axises_mask == (1 | 2));
ImVec2 p_mouse = g.IO.MousePos;
for (int axis = 0; axis < 2; axis++)
{
if ((axises_mask & (1 << axis)) == 0)
continue;
float size = wrap_rect.Max[axis] - wrap_rect.Min[axis];
while (p_mouse[axis] >= wrap_rect.Max[axis])
p_mouse[axis] -= size - 1.0f;
while (p_mouse[axis] <= wrap_rect.Min[axis])
p_mouse[axis] += size - 1.0f;
}
if (p_mouse.x != g.IO.MousePos.x || p_mouse.y != g.IO.MousePos.y)
ImGui::TeleportMousePos(p_mouse);
}
// When multi-viewports are disabled: wrap in main viewport.
// When multi-viewports are enabled: wrap in monitor.
// FIXME: Experimental: not sure how this behaves with multi-monitor and monitor coordinates gaps.
void WrapMousePos(int axises_mask)
{
ImGuiContext& g = *GImGui;
#ifdef IMGUI_HAS_DOCK
if (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
const ImGuiPlatformMonitor* monitor = GetViewportPlatformMonitor(g.MouseViewport);
WrapMousePosEx(axises_mask, ImRect(monitor->MainPos, monitor->MainPos + monitor->MainSize));
}
else
#endif
{
ImGuiViewport* viewport = GetMainViewport();
WrapMousePosEx(axises_mask, ImRect(viewport->Pos, viewport->Pos + viewport->Size));
}
} (V2) // When multi-viewports are disabled: wrap in main viewport.
// When multi-viewports are enabled: wrap in monitor.
// FIXME: Experimental: not sure how this behaves with multi-monitor and monitor coordinates gaps.
void ImGui::WrapMousePos(int axises_mask)
{
ImGuiContext& g = *GImGui;
#ifdef IMGUI_HAS_DOCK
if (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
const ImGuiPlatformMonitor* monitor = GetViewportPlatformMonitor(g.MouseViewport);
WrapMousePosEx(axises_mask, ImRect(monitor->MainPos, monitor->MainPos + monitor->MainSize));
}
else
#endif
{
ImGuiViewport* viewport = GetMainViewport();
WrapMousePosEx(axises_mask, ImRect(viewport->Pos, viewport->Pos + viewport->Size));
}
}
void ImGui::WrapMousePosEx(int axises_mask, const ImRect& wrap_rect)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(axises_mask == 1 || axises_mask == 2 || axises_mask == (1 | 2));
ImVec2 p_mouse = g.IO.MousePos;
for (int axis = 0; axis < 2; axis++)
{
if ((axises_mask & (1 << axis)) == 0)
continue;
float size = wrap_rect.Max[axis] - wrap_rect.Min[axis];
if (p_mouse[axis] >= wrap_rect.Max[axis])
p_mouse[axis] = wrap_rect.Min[axis] + 1.0f;
else if (p_mouse[axis] <= wrap_rect.Min[axis])
p_mouse[axis] = wrap_rect.Max[axis] - 1.0f;
}
if (p_mouse.x != g.IO.MousePos.x || p_mouse.y != g.IO.MousePos.y)
TeleportMousePos(p_mouse);
} |
I used your functions to create a cursor lock, akin to what Blender does. However, the wrapping was only working on the negative side of each axis. This was due to the cursor position being 0-based and unable to reach the screen size, so I had to subtract 1 from the screen size to fix it.
This function hide the cursor when an item is activated and use your wrapping function to allow infinite scrolling. When the item is deactivated, the cursor is shown again and reset to its position at the time the widget was initially clicked. I tried to handle widgets with support for both dragging an text input editing (e.g. DragFloat) since we don't want to lock the cursor for the latter. It seems to work well for my use case, although there's probably a lot of room for improvements. Unfortunately, I can't test your wrapping function with multiples monitors as I only own one. |
Both versions worked equally well for me with two monitors and multi-viewport enabled (I was not able to properly test with coordinates gap between monitors though). But I had to tweak void ImGui::WrapMousePos(int axes_mask)
{
ImGuiContext& g = *GImGui;
#ifdef IMGUI_HAS_DOCK
if (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Changed from here ...
const int monitor_index = FindPlatformMonitorForPos(g.IO.MousePosPrev);
if (monitor_index == -1)
return;
const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_index];
WrapMousePosEx(axes_mask, ImRect(monitor.MainPos, monitor.MainPos + monitor.MainSize - ImVec2(1.0f, 1.0f)));
// ... to here
}
else
#endif
{
ImGuiViewport* viewport = GetMainViewport();
WrapMousePosEx(axes_mask, ImRect(viewport->Pos, viewport->Pos + viewport->Size - ImVec2(1.0f, 1.0f)));
}
} Without my change: My fork of Dear Imgui for reference: https://github.com/CoolLibs/imgui/blob/docking/imgui.cpp#L9679 |
Includes my merged PRs and everything in my dev branch. Haven't tested with it yet. Changelog: Test case for clip rect HACK: more recent Windows SDK and VS2017; disable graph Set size to amount of space required Merge pull request ocornut#349 from maksw2/master Merge pull request ocornut#347 from mgerhardy/341 Merge pull request ocornut#348 from mgerhardy/fixed-warning Merge pull request ocornut#346 from mgerhardy/280 Merge pull request ocornut#345 from mgerhardy/322 Merge pull request ocornut#344 from rherilier/fix-gcc-warnings Merge pull request ocornut#336 from rherilier/add-isusingviewmanipulate Merge pull request ocornut#335 from RedSkittleFox/alternative_window Merge pull request ocornut#334 from ocornut/fix-beginchildframe dear imgui update and small fixes Merge pull request ocornut#316 from Batres3/2DSupport Merge pull request ocornut#326 from Sayama3/use-push-pop-id Merge pull request ocornut#328 from georgeto/master Merge pull request ocornut#330 from maritim/master Merge pull request ocornut#331 from GiovanyH/patch-1 Merge pull request ocornut#318 from dougbinks/imgui_math_operators Merge pull request ocornut#312 from kimidaisuki22/master div 0 fixed Merge pull request ocornut#301 from ZingBallyhoo/using-any Merge pull request ocornut#300 from Clog41200/Configurable-limits Merge pull request ocornut#298 from xDUDSSx/fix/rotation_circles Merge pull request ocornut#297 from xDUDSSx/fix/vertical-aspect-scaling Merge pull request ocornut#289 from ComputationalBiomechanicsLab/fix_isusing-ignores-setid Merge pull request ocornut#291 from ocornut/fix_math_operators_include Merge pull request ocornut#282 from MohitSethi99/master Merge pull request ocornut#276 from pthom/virtual_destructors Merge pull request ocornut#271 from idbrii/clip-parent Merge pull request ocornut#270 from idbrii/btn-behaviour Merge pull request ocornut#265 from mgerhardy/pr/fix-minor-formatting Merge pull request ocornut#264 from mgerhardy/pr/div0 Merge pull request ocornut#269 from peter1745/hatched-line-thickness-enhancement Merge pull request ocornut#259 from miyanyan/master Merge branch 'master' of https://github.com/CedricGuillemet/ImGuizmo update dear imgui Merge pull request ocornut#256 from Aidiakapi/patch-1 Merge pull request ocornut#252 from aaronkirkham/master Merge pull request ocornut#249 from rokups/rk/mouse-capture Merge pull request ocornut#246 from mgerhardy/pr/viewmanipulate removed commented code fix click view cube Merge pull request ocornut#231 from mgerhardy/master Merge pull request ocornut#230 from mgerhardy/master Merge pull request ocornut#228 from longod/master Merge pull request ocornut#227 from madeso/master AddBezierCubic Merge pull request ocornut#226 from sherief/master revert culling test commit Merge pull request ocornut#203 from rokups/rk/misc-fixes Merge pull request ocornut#212 from zhaijialong/fix-behind-camera-cull Merge pull request ocornut#209 from VictorFouquet/fix_normalize scale is always local Merge pull request ocornut#202 from pezy/master imguizmo namespace Merge pull request ocornut#194 from JonathanHiggs/vcpkg-example 1.84 WIP Merge pull request ocornut#197 from idbrii/seq-btn-color Merge pull request ocornut#196 from idbrii/seq-big-handles
a spinoff from here: #180 (comment)
what do you think about implementing this using a callback in the IO-structure? unfortunately imgui has to trigger the mouse warping itself to be able to adjust the DragXYZ values accordingly..
The text was updated successfully, but these errors were encountered: