Widget re-use works in editor, but buttons break in packaged builds

When GSlateFastWidgetPath is set to true (e.g.: in packaged builds), widgets that are used by more than one widgetComponent only accept button input for the last widgetComponent they were assigned to, even though that works fine in Editor without warnings or errors.

I might submit a bug report too, but given that those aren’t accessible to the public, I figured it was more important to document the behavior on the forum.

The issue occurs when UWidgetInteractionComponent::PressPointerKey makes a call to

LastWidgetPath.ToWidgetPath()

Where the array of widgets gets truncated to only contain the topmost widget (a window). It goes through the widgets and checks if their children have it set as their parent.

if (ChildWidgetPtr.IsValid() && ChildWidgetPtr->GetParentWidget() == CurWidgetRef)

When that fails they just stop processing the array of widgets early. And the button click code that follows only sees the topmost widget (a window).
That’s not a check that happens in the not-fastPath version. I realize widget re-use might not the most common use case, but I can’t find any documentation on the restriction to only use widgets in one WidgetComponent, I have yet to find any other limitations (it renders just as expected), works as expected in editor, and there are no errors and warnings, so this looks like a bug to me. The bug only occurring in non-editor builds also makes it extra challenging to debug, because of the different code paths.

Unfortunately the git repository doesn’t give a lot of helpful information about the addition of the slate fast widget path, only that it was merged in from Fortnite-staging in 2018. But I guess it’s just part of an optimization that makes some assumptions that don’t hold when you use a widget in multiple WidgetComponents.

It looks like disabling the optimization requires modifying the engine code, specifically FSlateApplication::Create()

Unless I’m misreading things it looks like WidgetComponents create virtual windows and set it as parent of the added widget, partially removing it from the previous widget, which breaks the fast widget path comparisson.

This implies that One Widget Component per widget instance is simply an undocumented limitation. (This begs the question why it isn’t itself the widget component, instead of a separate thing, but I guess that goes beyond the scope of this issue)

I should have searched for text, because SlateCoreClasses.cpp has a console variable for this setting.

Using the console command:
Slate.EnableFastWidgetPath false
Works around the issue.