Open englercj opened 3 years ago
You are correct... maybe IsAnyItemHovered()
should be reformulated.
I however need to ask why you are interested in IsAnyItemHovered()
?
95%+ of people who claim they want to use IsAnyItemHovered()
would be better using io.WantCaptureMouse
.
I'm spawning a borderless window and implementing a custom title bar with ImGui. To do so I need to implement WM_NCHITTEST
and tell Windows what part of the title bar is currently being hovered.
Basically what I do is check if any item is being hovered in the menu, and if not return HTCAPTION
which lets the user drag the window around. It ends up looking something like this (simplified) example:
m_menuHitArea = HTCLIENT;
if (ImGui::BeginMainMenuBar())
{
ImGui::TextUnformatted(ICON_FA_HOUSE);
if (ImGui::IsItemHovered())
m_menuHitArea = HTSYSMENU;
// All the menu items and stuff
if (ImGui::BeginMenu("File")) { /* ... */ }
if (ImGui::BeginMenu("Edit")) { /* ... */ }
// Setup right alignment of system buttons
const float targetSysButtonWidth = 30.0f * ImGui::GetWindowDpiScale();
const float sysButtonPadding = targetSysButtonWidth - ImGui::GetFontSize();
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, { 0, 0 });
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { sysButtonPadding, menubarPadding * 2.0f });
const float sysButtonWidth = ImGui::CalcTextSize(ICON_FA_SQUARE).x + (sysButtonPadding * 2.0f);
const float windowWidth = ImGui::GetWindowWidth() + ((ImGui::GetStyle().FramePadding.x / 2.0f) * ImGui::GetWindowDpiScale());
ImGui::SameLine(windowWidth - (sysButtonWidth * 3));
// Minimize
ImGui::MenuItem(ICON_FA_WINDOW_MINIMIZE, nullptr, nullptr, true);
if (ImGui::IsItemHovered())
m_menuHitArea = HTMINBUTTON;
// Maximize & Restore
ImGui::MenuItem(ICON_FA_SQUARE_FULL, nullptr, nullptr, true);
if (ImGui::IsItemHovered())
m_menuHitArea = HTMAXBUTTON;
// Close
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, { 1.0f, 0.0f, 0.0f, 0.9f });
ImGui::MenuItem("\xe2\x9c\x96", nullptr, nullptr, true);
if (ImGui::IsItemHovered())
m_menuHitArea = HTCLOSE;
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
// If we're in the main menu bar, not over anything more specific, let the user drag the window
if (ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered())
m_menuHitArea = HTCAPTION;
ImGui::EndMainMenuBar();
}
Elsewhere I may return the cached m_menuHitArea
value to Windows when it asks for a hit test.
Well you should use io.WantCaptureMouse then.
Can you elaborate? I'm not sure how WantCaptureMouse
helps the situation?
Looks like ImGui::GetIO().WantCaptureMouse
is always true when my mouse is over anywhere in the main menu bar and the window has focus. But I want to know specifically when the menu bar is hovered, and nothing in the menu bar (like a button, menu item, or text) is.
Right, sorry I misread the code snippet. This is equivalent to the test done to enable moving a window on dear imgui side.
In that specific snippet the only "offender" is the ImGui::TextUnformatted(ICON_FA_HOUSE);
call, as you mention raw Text()
elements are not claiming HoveredId
.
For that specific purpose, since your menu bar is likely going to be fairly contained, would suggest using either:
InvisibleButton()
+ draw text using the ImDrawList
API, and use that instead of Text elements, then IsAnyItemHovered()
will do what you need.bool over_caption = ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered()
+ over_caption |= ImGui::IsItemHovered()
after each Text()
call.Down the line it should be possible to provide some kind of state/flags to allow elements like Text() - which normally don't call ItemHoverable() and not have an ID to do the equivalent to prevent moving window.
Also note that your call to IsWindowHovered()
might want to use the ImGuiHoveredFlags_AllowWhenBlockedByPopup
to support moving via that native title bar when a popup or modal are open.
I ended up using a custom styled Button()
because I wanted an easier way to control the sizing of the widget, which has the side effect of skipping the text hover issue. Basically, your first recommendation.
I still wanted to open this issue because IsItemHovered()
not matching IsAnyItemHovered()
was unexpected behavior when I hit it.
Also note that your call to IsWindowHovered() might want to use the ImGuiHoveredFlags_AllowWhenBlockedByPopup to support moving via that native title bar when a popup or modal are open.
Good call, I'll make that change. Thanks!
Version/Branch of Dear ImGui:
Version: 1.84 WIP Branch: docking
Back-end/Renderer/Compiler/OS
Back-ends: custom Compiler: msvc Operating System: windows
My Issue/Question:
It seems like
IsItemHovered()
andIsAnyItemHovered()
don't agree on how to handle text. The former returns true when the text is hovered, but the later returns false.Standalone, minimal, complete and verifiable example:
My use-case is in a menu bar so I'm including that if it is relevant: