IsItemHovered(): fixed return value false positive when used after EndChild(), EndGroup() or widgets using either... (#3851, #1370)

...when the hovered location is located within a child window, e.g. InputTextMultiline().
This is intended to have no side effects, but brace yourself for the possible comeback..
This essentially makes IsItemHovered() not accept hover from child windows, but EndChild/EndGroup are forwarded.
More or less should fix/revert c76f014292 which was a revert of 344d48be3
This commit is contained in:
ocornut
2021-03-04 19:59:59 +01:00
parent b53b8f58df
commit ee643b2ad9
3 changed files with 26 additions and 11 deletions

View File

@ -3122,20 +3122,22 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return IsItemFocused();
// Test for bounding box overlap, as updated as ItemAdd()
if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
ImGuiItemStatusFlags status_flags = window->DC.LastItemStatusFlags;
if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
return false;
IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
// Test if we are hovering the right window (our window could be behind another window)
// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
// Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
//if (g.HoveredWindow != window)
// return false;
if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
return false;
// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
// to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
// the test that has been running for a long while.
if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
return false;
// Test if another item is active (e.g. being dragged)
if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
return false;
@ -5014,6 +5016,8 @@ void ImGui::EndChild()
// Not navigable into
ItemAdd(bb, 0);
}
if (g.HoveredWindow == window)
parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
}
g.WithinEndChild = false;
g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
@ -7647,6 +7651,7 @@ void ImGui::BeginGroup()
group_data.BackupCurrLineSize = window->DC.CurrLineSize;
group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
group_data.BackupHoveredIdIsAlive = g.HoveredId != 0;
group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
group_data.EmitItem = true;
@ -7700,6 +7705,11 @@ void ImGui::EndGroup()
window->DC.LastItemId = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb;
// Forward Hovered flag
const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
if (group_contains_curr_hovered_id)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
// Forward Edited flag
if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;