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
|
||||
|
||||
SaveInputState();
|
||||
SaveViewportState();
|
||||
|
||||
EnterLocalSpace();
|
||||
|
||||
@@ -319,6 +320,46 @@ void ImGuiEx::Canvas::RestoreInputState()
|
||||
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()
|
||||
{
|
||||
// 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)
|
||||
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);;
|
||||
|
||||
auto& fringeScale = ImFringeScaleRef(m_DrawList);
|
||||
@@ -449,4 +522,5 @@ void ImGuiEx::Canvas::LeaveLocalSpace()
|
||||
ImGui::PopClipRect();
|
||||
|
||||
RestoreInputState();
|
||||
RestoreViewportState();
|
||||
}
|
||||
|
||||
@@ -210,6 +210,18 @@ private:
|
||||
void SaveInputState();
|
||||
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 LeaveLocalSpace();
|
||||
|
||||
@@ -243,6 +255,19 @@ private:
|
||||
ImVec2 m_MousePosPrevBackup;
|
||||
ImVec2 m_MouseClickedPosBackup[IM_ARRAYSIZE(ImGuiIO::MouseClickedPos)];
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user