Fix ImGui hover dead zones at negative canvas coordinates
Port upstream imgui-node-editor's IMGUI_HAS_VIEWPORT support into the vendored canvas: docking-branch ImGui's IsMouseHoveringRect requires rects to overlap the mouse viewport's screen-space rect, so items at canvas coordinates outside the screen range (e.g. negative) never hovered or clicked. Transform the viewport into canvas-local space in EnterLocalSpace() and restore it in LeaveLocalSpace(), like the mouse position. Fixes node hover highlight and in-node widget interaction left of / above the canvas origin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,7 @@ bool ImGuiEx::Canvas::Begin(ImGuiID id, const ImVec2& size)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
SaveInputState();
|
SaveInputState();
|
||||||
|
SaveViewportState();
|
||||||
|
|
||||||
EnterLocalSpace();
|
EnterLocalSpace();
|
||||||
|
|
||||||
@@ -319,6 +320,46 @@ void ImGuiEx::Canvas::RestoreInputState()
|
|||||||
ImGui::GetCurrentWindow()->DC.CursorMaxPos = m_WindowCursorMaxBackup;
|
ImGui::GetCurrentWindow()->DC.CursorMaxPos = m_WindowCursorMaxBackup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UsdLayerManager local patch, ported from upstream imgui-node-editor
|
||||||
|
// (see the declaration in imgui_canvas.h for why).
|
||||||
|
void ImGuiEx::Canvas::SaveViewportState()
|
||||||
|
{
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
|
||||||
|
m_WindowPosBackup = window->Pos;
|
||||||
|
m_ViewportPosBackup = viewport->Pos;
|
||||||
|
m_ViewportSizeBackup = viewport->Size;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
m_ViewportWorkPosBackup = viewport->WorkPos;
|
||||||
|
m_ViewportWorkSizeBackup = viewport->WorkSize;
|
||||||
|
# else
|
||||||
|
m_ViewportWorkOffsetMinBackup = viewport->WorkOffsetMin;
|
||||||
|
m_ViewportWorkOffsetMaxBackup = viewport->WorkOffsetMax;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiEx::Canvas::RestoreViewportState()
|
||||||
|
{
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
|
||||||
|
window->Pos = m_WindowPosBackup;
|
||||||
|
viewport->Pos = m_ViewportPosBackup;
|
||||||
|
viewport->Size = m_ViewportSizeBackup;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
viewport->WorkPos = m_ViewportWorkPosBackup;
|
||||||
|
viewport->WorkSize = m_ViewportWorkSizeBackup;
|
||||||
|
# else
|
||||||
|
viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup;
|
||||||
|
viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
void ImGuiEx::Canvas::EnterLocalSpace()
|
void ImGuiEx::Canvas::EnterLocalSpace()
|
||||||
{
|
{
|
||||||
// Prepare ImDrawList for drawing in local coordinate system:
|
// Prepare ImDrawList for drawing in local coordinate system:
|
||||||
@@ -374,6 +415,38 @@ void ImGuiEx::Canvas::EnterLocalSpace()
|
|||||||
for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
|
for (auto i = 0; i < IM_ARRAYSIZE(m_MouseClickedPosBackup); ++i)
|
||||||
io.MouseClickedPos[i] = (m_MouseClickedPosBackup[i] - m_ViewTransformPosition) * m_View.InvScale;
|
io.MouseClickedPos[i] = (m_MouseClickedPosBackup[i] - m_ViewTransformPosition) * m_View.InvScale;
|
||||||
|
|
||||||
|
// UsdLayerManager local patch, ported from upstream imgui-node-editor:
|
||||||
|
// move the viewport rect into local space too, so IsMouseHoveringRect's
|
||||||
|
// screen-space viewport overlap check (docking-branch ImGui) passes for
|
||||||
|
// items at canvas coordinates outside the screen range (e.g. negative).
|
||||||
|
// See SaveViewportState() declaration for the full story.
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
{
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
window->Pos = ImVec2(0.0f, 0.0f);
|
||||||
|
|
||||||
|
auto viewport_min = m_ViewportPosBackup;
|
||||||
|
auto viewport_max = m_ViewportPosBackup + m_ViewportSizeBackup;
|
||||||
|
|
||||||
|
viewport_min.x = (viewport_min.x - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
viewport_min.y = (viewport_min.y - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
viewport_max.x = (viewport_max.x - m_ViewTransformPosition.x) * m_View.InvScale;
|
||||||
|
viewport_max.y = (viewport_max.y - m_ViewTransformPosition.y) * m_View.InvScale;
|
||||||
|
|
||||||
|
auto viewport = ImGui::GetWindowViewport();
|
||||||
|
viewport->Pos = viewport_min;
|
||||||
|
viewport->Size = viewport_max - viewport_min;
|
||||||
|
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
viewport->WorkPos = m_ViewportWorkPosBackup * m_View.InvScale;
|
||||||
|
viewport->WorkSize = m_ViewportWorkSizeBackup * m_View.InvScale;
|
||||||
|
# else
|
||||||
|
viewport->WorkOffsetMin = m_ViewportWorkOffsetMinBackup * m_View.InvScale;
|
||||||
|
viewport->WorkOffsetMax = m_ViewportWorkOffsetMaxBackup * m_View.InvScale;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
m_ViewRect = CalcViewRect(m_View);;
|
m_ViewRect = CalcViewRect(m_View);;
|
||||||
|
|
||||||
auto& fringeScale = ImFringeScaleRef(m_DrawList);
|
auto& fringeScale = ImFringeScaleRef(m_DrawList);
|
||||||
@@ -449,4 +522,5 @@ void ImGuiEx::Canvas::LeaveLocalSpace()
|
|||||||
ImGui::PopClipRect();
|
ImGui::PopClipRect();
|
||||||
|
|
||||||
RestoreInputState();
|
RestoreInputState();
|
||||||
|
RestoreViewportState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,18 @@ private:
|
|||||||
void SaveInputState();
|
void SaveInputState();
|
||||||
void RestoreInputState();
|
void RestoreInputState();
|
||||||
|
|
||||||
|
// UsdLayerManager local patch, ported from upstream imgui-node-editor:
|
||||||
|
// with a viewport-enabled ImGui (IMGUI_HAS_VIEWPORT, i.e. the docking
|
||||||
|
// branch), ImGui::IsMouseHoveringRect() — and therefore every item's
|
||||||
|
// hover test — requires the rect to overlap the mouse viewport's rect,
|
||||||
|
// which is in *screen* space. Inside the canvas, rects are in canvas
|
||||||
|
// space, so anything at canvas coordinates outside the screen-space
|
||||||
|
// range (e.g. negative) went hover/click-dead. Fix: transform the
|
||||||
|
// viewport rect into canvas-local space while inside EnterLocalSpace()
|
||||||
|
// and restore it on LeaveLocalSpace(), exactly like the mouse position.
|
||||||
|
void SaveViewportState();
|
||||||
|
void RestoreViewportState();
|
||||||
|
|
||||||
void EnterLocalSpace();
|
void EnterLocalSpace();
|
||||||
void LeaveLocalSpace();
|
void LeaveLocalSpace();
|
||||||
|
|
||||||
@@ -243,6 +255,19 @@ private:
|
|||||||
ImVec2 m_MousePosPrevBackup;
|
ImVec2 m_MousePosPrevBackup;
|
||||||
ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
|
ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
|
||||||
ImVec2 m_WindowCursorMaxBackup;
|
ImVec2 m_WindowCursorMaxBackup;
|
||||||
|
|
||||||
|
# if defined(IMGUI_HAS_VIEWPORT)
|
||||||
|
ImVec2 m_WindowPosBackup;
|
||||||
|
ImVec2 m_ViewportPosBackup;
|
||||||
|
ImVec2 m_ViewportSizeBackup;
|
||||||
|
# if IMGUI_VERSION_NUM > 18002
|
||||||
|
ImVec2 m_ViewportWorkPosBackup;
|
||||||
|
ImVec2 m_ViewportWorkSizeBackup;
|
||||||
|
# else
|
||||||
|
ImVec2 m_ViewportWorkOffsetMinBackup;
|
||||||
|
ImVec2 m_ViewportWorkOffsetMaxBackup;
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ImGuiEx
|
} // namespace ImGuiEx
|
||||||
|
|||||||
Reference in New Issue
Block a user