How to detect true widget visibility

I can’t seem to find any way to detect whether a given widget is visible. IsVisible() just checks the widget’s own visibility status, but doesn’t take into account its hierarchy, which may include a parent that is hidden.

There are 2 ways you could go about it:

the clunky way: (although you could write a macro)

  • GetParent of the widget
  • check if it’s valid
  • check if it’s the one you’re looking for
  • if yes → check visiblity
  • if no → rinse & repeat

use Rama’s plugin:

227538-capture.png

Fetch the desired parent and check its visibility. This is still not ideal but should work better. The downside is that you need the plugin.

I wrote something like this as a function, but I wish there’d be such functionality cached from the engine already, since it’s needed and used somewhere in the underlying slate anyway I believe (for layout/visibility invalidation etc.). I didn’t dive deeper into it yet, though. So, for now this works for me:

bool resultVisibility = true;

UWidget* hierarchyWidget = this;
while (hierarchyWidget)
{
	// WARNING: don't use outerWidget->IsVisible() since that uses inner slate widget which might not yet be initialized here!
	// GetVisibility uses the UMG defined visibility which is exactly what we want and need here.
	bool isCurrentVisible = hierarchyWidget->GetVisibility() == ESlateVisibility::Visible ||
							  hierarchyWidget->GetVisibility() == ESlateVisibility::HitTestInvisible ||
							  hierarchyWidget->GetVisibility() == ESlateVisibility::SelfHitTestInvisible;

	resultVisibility = resultVisibility && isCurrentVisible;

	if (!resultVisibility)
	{
		break;
	}

	UWidget* nextHierarchyWidget = hierarchyWidget->GetParent();

	// if outerWidget is nullptr it means we reached the root container of the current UserWidget...
	if (!nextHierarchyWidget)
	{
		//...Get the WidgetTree...
		if (UWidgetTree* currentWidgetTree = Cast<UWidgetTree>(hierarchyWidget->GetOuter()))
		{
			//...and the corresponding parent UserWidget...
			if (UUserWidget* currentUserWidget = Cast<UUserWidget>(currentWidgetTree->GetOuter()))
			{
				//...and take it as UWidget to consider in next loop
				nextHierarchyWidget = currentUserWidget;
			}
		}
	}

	hierarchyWidget = nextHierarchyWidget;
}

Thanks, this works pretty good! :slight_smile: