How to detect mouse is over any Widget?

I have a main GUI widget and many child widgets and I set my input to InputModeGameAndUI.
However whenever I click on a readonly-textbox (like the chatbox) or on the inventory, my character also receives this as input and starts walking.

It get’s more complicated with widgets that are not rectangular (like a widget with a border for the background but the image is circular and etc) and some also have drag&drop functionality.

How is this best solved?

There is a node called Is Hovered, which returns a boolean with true if the current widget is hovered.

What Unzkilled suggested would work just fine. Another alternative is to swtich to UI mode in onMouseEnter and back to Game and UI in onMouseLeave.

1 Like

So I have to add an OnHover() to every single (child-)widget (there are a lot)? And then it would also count as "onhover"when the mouse is over a transparent area (because non-rectangular UI’s would then bug).

I don’t think I can just use a boolean. I would have to have a list of userwidgets in the main-widget and when I hover over a widget, that widget is then added to the list of widgets. If the list is empty, that means that the player should receive input. Because what if widgets were to overlap each other and other exceptional cases? And when destroying widgets I also would have to check that list and if that specific widget is on it, remove it. Because I’m not sure if the OnMouseLeave() is then triggered. But I’m not sure.

No I sadly can’t set the gamemode to UIOnly. I tried that before but it also blocks UI input from the playercontroller (in my case).

Is there no better alternative?

Maybe I could make a base class for all of my userwidgets and inherit from that. Then put this onhover/onmouseleave code in there so that every widget get’s it. But still not… ideal… (very dirty)

in my opinion “IsHovered” is a little buggy.
look when bIsHovered flag is set:

void SWidget::OnMouseEnter( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bIsHovered = true;

	if (MouseEnterHandler.IsBound())
	{
		// A valid handler is assigned; let it handle the event.
		MouseEnterHandler.Execute(MyGeometry, MouseEvent);
	}
}

void SWidget::OnMouseLeave( const FPointerEvent& MouseEvent )
{
	bIsHovered = false;

	if (MouseLeaveHandler.IsBound())
	{
		// A valid handler is assigned; let it handle the event.
		MouseLeaveHandler.Execute(MouseEvent);
	}
}

this means that if you fire an “OnMouseEnter” and, for example, change your mode to “GameOnly”, move the mouse outside widget area and then switch back to the “UIOnly” or “GameAndUI” modes, even if mouse is outside the widget, this still result as hovered.
and there is no way to turn manually that “bIsHovered” flag back, because it is not exposed in blueprint…

FWidgetPath Path = FSlateApplication::Get().LocateWindowUnderMouse(FSlateApplication::Get().GetCursorPos(), FSlateApplication::Get().GetInteractiveTopLevelWindows(), true);
TSharedPtr vp = FSlateApplication::Get().GetGameViewport();
bool overViewPort = Path.IsValid() && (Path.GetLastWidget() == vp.ToSharedRef());

You can use that bool overViewPort to check if the mouse is over the game viewport or any UI.

1 Like

For whoever trying the great solution above but is getting complication errors.

Don’t forget to include:
include “Widgets/SWidget.h”
include “Widgets/SViewport.h”

Otherwise complier can’t know how to compare the two. Good luck!

1 Like