#slate

1 messages · Page 15 of 1

broken hemlock
#

This is problematic if the callbacks don't remove the window appropriately. As far as I can tell it's not causing a drag on anything... I'm not sure how else to say that.. If this window is open, don't return the delegate until the Slate widgets handle their stuff

low bluff
#

Aren't you just trying to stop the underlying Window/Editor from being interacted with while that Modal is open?

broken hemlock
#

Yes essentially

#

I want there to be no option but to complete that modal window

low bluff
#

If you have encountered that behavior in UE before, I would suggest you check how they did that.

broken hemlock
#

I haven't encountered that yet really

#

Everything I've seen has a valid Cancel operation basically

#

mmmmm

#

Inside the content widgets I've handled most cases I can find of losing focus, submitting text other than pressing Enter, clicking off buttons

low bluff
#

Thing is, the Modal function of GEditor says that the function doesn't return until the Modal window gets closed.

broken hemlock
#

So... I could literally just not have that loop potentially? I'll try without

low bluff
#

fwiw SlateApps Modal function says the same

#

Well, yeah.

#

The while loop is sketchy af :D

broken hemlock
low bluff
#

Yeah teh Modal code even has a while loop

#

Yours is never hit anyway

broken hemlock
#

Man I'm trying so hard with this Slate

low bluff
broken hemlock
#

this is literally my first

broken hemlock
#

omfg

#

You know the worst part

#

I read every single function other than that one

#

the AddWindowNative

#

AddWindow

#

why did I not

#

omfg

low bluff
#
void UEditorEngine::EditorAddModalWindow( TSharedRef<SWindow> InModalWindow ) const
{
    // If there is already a window active, parent this new modal window to the existing window so that it doesnt fall behind
    TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().GetActiveTopLevelRegularWindow();

    if( !ParentWindow.IsValid() )
    {
        // Parent to the main frame window
        if(FModuleManager::Get().IsModuleLoaded("MainFrame"))
        {
            IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame");
            ParentWindow = MainFrame.GetParentWindow();
        }
    }

    FSlateApplication::Get().AddModalWindow( InModalWindow, ParentWindow );
}
broken hemlock
#

Ye and then it while

#

ok]

#

zzzzz

low bluff
#
void SGameplayTagPicker::OpenRenameGameplayTagDialog(TSharedPtr<FGameplayTagNode> GameplayTagNode) const
{
    TSharedRef<SWindow> RenameTagWindow =
        SNew(SWindow)
        .Title(LOCTEXT("RenameTagWindowTitle", "Rename Gameplay Tag"))
        .SizingRule(ESizingRule::Autosized)
        .SupportsMaximize(false)
        .SupportsMinimize(false);

    TSharedRef<SRenameGameplayTagDialog> RenameTagDialog =
        SNew(SRenameGameplayTagDialog)
        .GameplayTagNode(GameplayTagNode)
        .OnGameplayTagRenamed(const_cast<SGameplayTagPicker*>(this), &SGameplayTagPicker::OnGameplayTagRenamed);

    RenameTagWindow->SetContent(SNew(SBox)
        .MinDesiredWidth(320.0f)
        [
            RenameTagDialog
        ]);

    TSharedPtr<SWindow> CurrentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared() );

    FSlateApplication::Get().AddModalWindow(RenameTagWindow, CurrentWindow);
}
#

Just as an example.

broken hemlock
#

In my title I use FText::FromString() is there an issue vs using LOCTEXT

low bluff
#

Helps just checking how Epic uses it in various places and picking the code that is the simplest.

#

FText is localizable. FString is not.

#

If you use FText::FromString, you basically skip the localization feature.

#

LOCTEXT is used if you want to have your stuff localized.

broken hemlock
#

Ahhhhhhhh

low bluff
#

There is a LOCTEXT_NAMESPACE defined in that class that I copied the code from.

broken hemlock
#

Well this is for a plugin I'd like to not assume people don't want localization

low bluff
#

That is used hand in hand with the LOCTEXT macro.

#

The Namespace is grouping the Text Keys.

#

And the first param of LOCTEXT is the Key.

#

here "RenameTagWindowTitle".

broken hemlock
#

In my UAssetDefinition and UFactory i used NSLOCTEXT

#

hmm

low bluff
#

The second param is the default value that can be localized later.

low bluff
#

If you have multiple, then you should wrap them all with the #define and use LOCTEXT.

broken hemlock
#

Ok that makes sense

low bluff
#

I usually argue that it doesn't hurt setting up LOCTEXT properly from the start. One can still just not localize the text, but at least it's possible if it's ever needed.

#

For things that won't ever get a translation, using FromString is valid though.

broken hemlock
#

I would like to allow for it to be a possibility not a requirement

#

I'll try the making the define

low bluff
#

Then stick to proper LOCTEXT usage. Might also want to read the docs about this a bit, because there is a bit more to it.

broken hemlock
#

o

#

naturally

#

There's so much to this

low bluff
#

But even if you set up the LOCTEXTs wrong initially, having them as LOCTEXT will make it easier to fix them later.

#

"wrong" here being something like not taking into account that a word could be spelled differently when more than one element is used.

#

E.g. 1 Task vs 2 Tasks.

#

Cause FText supports that automatically too.

broken hemlock
#

that would be isnane

low bluff
#

You won't die from having 1 Tasks or 2 Task in there for a while

#

But you can at least search for the LOCTEXT macro in your code base to fix them later.

broken hemlock
#

ye that sounds nice

broken hemlock
low bluff
broken hemlock
#

LMAO

#

I was in the .h

low bluff
#

I see it right below the includes.

broken hemlock
#

Omfg

#

its the first line

low bluff
#

Yeah that's in the .cpp
having it in the .h would be troublesome

broken hemlock
#

under the includes

#

My problem is I understand that. I should have known that. Why that just never registered in my head.... is... idk how to explain

#

So it looks like I need to define just the one part of the LOCTEXT and then the rest of it I don't even have to make that's just built in already...

#

just define the namespace

#

That's nifty

low bluff
#

Yeah, don't forget to undef it at the bottom of the .cpp again

broken hemlock
#

idk how that's Thank You

#

but it's from this discord so

low bluff
#

That's Keanu Reeves saying thank you in some changing room of some evening show.

#

And no, it's not the "You are breathtaking" scene.

broken hemlock
#

Wow that's so nice with this loctext

#

... can I use ternary operators inside this macro to set these strings

#

also no

low bluff
#

There is more than LOCTEXT you can use, hence the suggestion to please read the docs.

broken hemlock
#

am doing now

#

"{NumCats} {NumCats}|plural(one=cat,other=cats)"

broken hemlock
#

Ok so I found out this is how you deal with delays properly.... while the top modal window is going, there's a special tick delegate that broadcasts out deltatime, so I can just create a little 1 second delay, call to destroy the ResultWindow modal, which then after that just calls to destroy the original modal window added

    ResultWindow->SetContent(Container);
    FSlateApplication& SlateApp = FSlateApplication::Get();
                                
    float DisplayCounter = 0.f;
    FDelegateHandle Handle = SlateApp.GetOnModalLoopTickEvent().AddWeakLambda(this,
        [this, &ResultWindow, &DisplayCounter, &Handle] (float DeltaTime)
           {
            DisplayCounter += DeltaTime;
            if (DisplayCounter > 1.f)
            {
               FSlateApplication::Get().GetOnModalLoopTickEvent().Remove(Handle);
               ResultWindow->RequestDestroyWindow();
            }
        });
                                
    SlateApp.AddModalWindow(ResultWindow, Window);
                                
    Window->RequestDestroyWindow();
#

I wanted a pop up that reads out success or not

#

ok this smooth

#

Everything is special in slate

low bluff
#

Doesn't have to be a modal window

broken hemlock
#

I only read about windows and adding children to them and whatnot

low bluff
#

Depends on what exactly you want to do.

broken hemlock
#

and if I just call AddWindow or AddWindowAsNativeChild it won't render

low bluff
#

There is, e.g., FMessageDialog::Open(..)

broken hemlock
#

But that doesn't allow me decent formatting

#

It just Pop up with this FText

#

Just kidding

#

Ye it's just this basic stuff

low bluff
#

Which also just uses the ModalWindow in the end I guess.

broken hemlock
#

umm how do I find in rider what's bound to that

#

I can only see where it's declared and where it's executed

low bluff
#

FCoreDelegates::ModalMessageDialog.BindUObject(this, &UEditorEngine::OnModalMessageDialog);

broken hemlock
#

thank you

#

Ohhhhhhhhhh

#

The delegate is in runtime

#

the binding is in Editor

low bluff
#

Yeah, it comes from Dialogs.h/.cpp

#

There are some classes you can extend from, however.

broken hemlock
#

hmm it creates an SChoiceDialog

#

never seen that

low bluff
#

SModalEditorDialog also looks interesting

#

Is templated, so you can define what the return is

#

Can only find one example, however.

#

class SControlRigDismissDependencyDialog : public SModalEditorDialog<bool>

broken hemlock
#

man this stuff is wild

low bluff
#

ProvideResult(false);

#

Guess that is also templated and then can be used to return

#
    // Derived classes call this function from their widget events to close the dialog and return the result to the calling context
    void ProvideResult(ResultType InResult)
    {
        Window->RequestDestroyWindow();
        Window.Reset();
        OnFinished.ExecuteIfBound(MoveTemp(InResult));
        OnFinished = {};
    }
#

Ah there is a second usage of it

#

class SFixupRedirectorsReport : public SModalEditorDialog<bool>

#

But they are both so simple.

#

Like, in a good way

broken hemlock
#

How can you say Result.GetValue() if for example I want the result to be a USTRUCT


    ResultType ShowModalDialog(const FText& InTitle)
    {
        Window = UE::Private::CreateModalDialogWindow(InTitle, AsShared(), Sizing, MinDimensions);
        Window->SetWidgetToFocusOnActivate(GetWidgetToFocusOnActivate());
        TOptional<ResultType> Result;
        OnFinished.BindLambda([&Result](ResultType InResult) { Result.Emplace(MoveTemp(InResult)); });
        UE::Private::ShowModalDialogWindow(Window.ToSharedRef());
        return MoveTemp(Result.GetValue());
    }
low bluff
#
bool ControlRigDismissDependencyDialog::LaunchDismissDependencyDialog(const URigHierarchy* InHierarchy, const FRigElementKey& InChild, const FRigElementKey& InParent, const FRigHierarchyDependencyChain& InDependencyChain)
{
    // todo?: compute a key to remember this setting and don't ask in the future
    TSharedPtr<SControlRigDismissDependencyDialog> Dialog = SNew(SControlRigDismissDependencyDialog, InHierarchy, InChild, InParent, InDependencyChain);
    const bool bDismissed = Dialog->ShowModalDialog(NSLOCTEXT("ControlRig", "DismissDependencyDialogTitle","Cyclic Dependency Found"));
    return bDismissed;
}
broken hemlock
#

Do I have to make sure I write a GetValue() override?

#

how does that work with a boolean

#

what boolean can GetValue

low bluff
#

You might want to read that function once more

broken hemlock
#

Oh

#

damn missed the TOptional

#

ye

low bluff
#

You should be able to do class SMyCustomEditorDialog : public SModaleEditorDialog<FMyStruct>

broken hemlock
#

That's what I thought at first, but then I just missed the TOptional that just includes the template as well

#

And it's kinda cool it gives you a Lambda as well

low bluff
#

And then:

TSharedPtr<SMyCustomEditorDialog> Dialog = SNew(SMyCustomEditorDialog, ..);
const FMyStruct Result = Dialog->ShowModalDialog(...);
broken hemlock
#

yeeee

#

That would be wild

low bluff
#

Hope that helps, cause you should be quite free in how you can design that dialog due it being its own widget.

#

Should be able to just implement the Construct method as usual

broken hemlock
#

Not the regular way with the slatapplication

low bluff
#

Ehhhh

#

No, it still uses the same underlying stuff for that

broken hemlock
#

lmao did I not keep going enough

low bluff
#

It still creates a Window and tells the SlateApp to add it as modal

#

But it removes all the management of that for you

broken hemlock
#

void UE::Private::ShowModalDialogWindow(TSharedRef<SWindow> Window)
{
GEditor->EditorAddModalWindow(Window);
}

#

Just a GEditor now

low bluff
#

Yop

broken hemlock
#

void UEditorEngine::EditorAddModalWindow( TSharedRef<SWindow> InModalWindow ) const
{
    // If there is already a window active, parent this new modal window to the existing window so that it doesnt fall behind
    TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().GetActiveTopLevelRegularWindow();

    if( !ParentWindow.IsValid() )
    {
        // Parent to the main frame window
        if(FModuleManager::Get().IsModuleLoaded("MainFrame"))
        {
            IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame");
            ParentWindow = MainFrame.GetParentWindow();
        }
    }

    FSlateApplication::Get().AddModalWindow( InModalWindow, ParentWindow );
}
#

There it isssssssssssssss

#

add modal

#

finally

low bluff
#
TSharedRef<SWindow> UE::Private::CreateModalDialogWindow(
    const FText& InTitle,
    TSharedRef<SWidget> Contents,
    ESizingRule Sizing,
    FVector2D MinDimensions)
{
    // clang-format off
    return SNew(SWindow)
        .Title(InTitle)
        .SizingRule(Sizing)
        .MinWidth(MinDimensions.X)
        .MinHeight(MinDimensions.Y)
        .ClientSize(MinDimensions)
        .SupportsMaximize(false)
        .SupportsMinimize(false)
        .HasCloseButton(false)
        [
            SNew(SBorder)
            .Padding(4.f)
            .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
            [
                MoveTemp(Contents)
            ]
        ];
    // clang-format on
}
broken hemlock
#

Ye and then it goes through and adds the TOptional and gives it to the lambda then calls that

low bluff
#

Like, you can do all that yourself too

#

You are already doing that partially anyway

#

But this would remove the need of manually householding the window etc.

broken hemlock
#

Hey look at that... it says false to minimize, maximize, close button

#

imagine

low bluff
#

Yeah, cause it handles the actual closing through the content of the window

broken hemlock
#

ye

low bluff
#

I think the Delete Redirectors Dialog is using this

broken hemlock
#

What's the difference between MainFrame parent window and the FGlobalTabmanager::Get()->GetRootWindow()

#

I use the root window which always returns the editor

#

in all this in the engine already uses this MainFrame

#

idk it has to load the module every time vs this little static getter

low bluff
#

It returns the Editor because you are only one level deep.

#

And you are calling it from "within" the main editor window

#

If you were to undock a window and create a dialog from that, then the RootWindow would probably be that new window

#

Or if you start nesting dialogs.

#

While the MainFrame should always be the Editor iirc

#

Actually, maybe that's wrong.

#

Not 100% sur. MainFrame does set its own Windows as th RootWindow

broken hemlock
low bluff
#

Th other cases where it's used are for tooling windows.

#

Like, UE has standalone programs

#
void FTraceInsightsModule::CreateSessionViewer(bool bAllowDebugTools)
{
    RegisterTabSpawners();

#if !WITH_EDITOR || defined(__INTELLISENSE__)

    //////////////////////////////////////////////////
    // Create the main window.

#if PLATFORM_MAC
    const bool bEmbedTitleAreaContent = true;
#else
    const bool bEmbedTitleAreaContent = false;
#endif

    // Get desktop metrics. It also ensures the correct metrics will be used later in SWindow.
    FDisplayMetrics DisplayMetrics;
    FSlateApplication::Get().GetDisplayMetrics(DisplayMetrics);
    const float DPIScaleFactor = FPlatformApplicationMisc::GetDPIScaleFactorAtPoint(
        static_cast<float>(DisplayMetrics.PrimaryDisplayWorkAreaRect.Left),
        static_cast<float>(DisplayMetrics.PrimaryDisplayWorkAreaRect.Top));

    const FVector2D ClientSize(1280.f * DPIScaleFactor, 720.0f * DPIScaleFactor);

    TSharedRef<SWindow> RootWindow = SNew(SWindow)
        .Title(NSLOCTEXT("TraceInsightsModule", "UnrealInsightsAppName", "Unreal Insights"))
        .CreateTitleBar(!bEmbedTitleAreaContent)
        .SupportsMaximize(true)
        .SupportsMinimize(true)
        .IsInitiallyMaximized(false)
        .IsInitiallyMinimized(false)
        .SizingRule(ESizingRule::UserSized)
        .AutoCenter(EAutoCenter::PreferredWorkArea)
        .ClientSize(ClientSize)
        .AdjustInitialSizeAndPositionForDPIScale(false);

    const bool bShowRootWindowImmediately = false;
    FSlateApplication::Get().AddWindow(RootWindow, bShowRootWindowImmediately);

    FGlobalTabmanager::Get()->SetRootWindow(RootWindow);
broken hemlock
#

lmao the mainframe sets it as the same

low bluff
#

Yeah, I don#t think the MainFrameModule is used within standalone programs.

#

Or if you were to spawn a fully standalone window

broken hemlock
#

mehhhhh idk if I'm doing all that

low bluff
#

You aren't.

#

Even if you don't use the template dialog class, you should jsut use the GEditor call to add the modal window tbh

broken hemlock
#

instead of through SlateApp

#

I mean I have to use SlateApp to get the ActiveTopMostWindow to add the primary Modal to it

low bluff
#

Yeah, I would try to let UE do as much as possible

broken hemlock
#

Unless that's in GEditor as well

low bluff
#

Ensures you can't forget about anything

#

Well you posted what GEditor does earlier

low bluff
#

Well that is GEditor

#

GEditor is just a global pointer to the UEditorEngine singleton.

broken hemlock
low bluff
#

Boilerplate code in general

broken hemlock
#

Ohhhhhh like isntead of manually managing the popup window

#

Really extend the MessageDialogue templated

#

and let that fire

low bluff
#

Yeah, cause you might be missing something that they do but don't explain properly

broken hemlock
#

gotcha

low bluff
#

Like setting some property, passing some stuff etc.

#

E.g. Window->SetWidgetToFocusOnActivate(GetWidgetToFocusOnActivate());

#

(from the templated dialog class)

broken hemlock
#

but isn't for focus only for input routing

low bluff
#

It's just an example

broken hemlock
#

oh

low bluff
#

I would just use that template class unless it does something you don't want or lacks something you need.

broken hemlock
#

well ye just stuff like that

low bluff
#

And if that's the case I would try to just duplicate their stuff and stick to what they do as much as possible

broken hemlock
#

some random edge case ruins the whole thing cuz 1 function or value I didn't set somewhere along this exact input click and results just doesn't handle this 1 specific case

#

vs using the UE stuff auto and it JustWorks™

low bluff
#

Yeah, it can backfire if UE assumes that everyone wants the dialog to work like they think it should.

#

Which happens more often than not

#

But if it's doing what you want then use it

broken hemlock
#

Well ye cuz actually

#

If I did that dialogue with the extended class

#

It would actually remove a ton of lines inside my lambda

#

well not a ton but still

#

But you're right I could ez format the extended dialogue widget

#

Those popups with the results is what I was trying to get properly

#

Your telling me that when the modal is active that it locks it up was the biggest help of this all because that was my whole concern was that it doesn't execute the next line until the modal is gone

#

Just this


SlateApp.AddModalWindow(ResultWindow, Window);
Window->RequestDestroyWindow();
#

Allows that main input window to stay alive until the ResultWindow is gone

#

which is literally the end of my lambda...

                            SlateApp.AddModalWindow(ResultWindow, Window);
                            Window->RequestDestroyWindow();
                        })));

            FSlateApplication& SlateApp = FSlateApplication::Get();
            SlateApp.AddModalWindow(Window, FGlobalTabmanager::Get()->GetRootWindow());
            return bConfirmedPassword;
#

So then when that Window is destroyed, it immediately then returns the result

#

Can I ask why does UE sometimes to namespace enums like this? This is my first one I've made like this, but I've seen them all in my GAS code... like the EAbilityGenericReplicatedEvent::InputPressed for example... why use these over a standard regular enum?

low bluff
#

Just use normal enum/enum classes

broken hemlock
#

ahhhhhhhhhhhh

#

lmao

#

nice so then I can turn them back into bitflags

#

Idk why I don't like switch I like Result & Success

tribal bolt
#

@grave hatch hey happy new year! I just wanted to follow up as you mentioned this ages ago now.

Are you still working on a slate WYSIWYG project or is it mothballed? Been thinking about it for a while 😄

grave hatch
#

Mothballed for now. I've been thinking about it a lot recently, though, and I'd do it completely differently now.

grave hatch
#

What key were you hoping for?

hallow frost
hallow frost
#

i will switch on the other #umg

grave hatch
#

UMG is the in-editor Blueprint wrapper for Slate.

#

So if you're doing things with widget blueprints and nodes and things, you're using UMG.

#

If you're doing things with c++, you're using Slate.

#

(with some exceptions!)

stuck jewel
#

learn UMG to make a game
learn slate to make editor customizations, or to make special custom things for UMG

tepid furnace
#

Hello Everyone!

I'm trying to set the position of a widget to be the exact same as another widget, and in order to do that, I call Get Cached Geometry, and then call Local to Viewport on it to set the other widget position. Yet the blueprint hover over sign specifically advises against using get cached geometry

And the blueprint hover tip does not say much about how to actually implement the alternative as someone who has not used slate before.

So my question is what is the alternative that solves the mentioned hysteresis problem, and how do I implement it. I have used both BP and C++ before.

Help is greatly appreciated!

grave hatch
#

You make the widget a child of the other widget.

tepid furnace
#

And this results in?

grave hatch
#

You know how you have widgets with child widgets in the umg editor?

#

That.

tepid furnace
#

Yes, but I know from experience that bugs have shown up when I used this in the same frame that the parent widget was instantiated

stuck jewel
#

more context needed... is this a widget that normally floats elsewhere, and now you want it to follow another widget for a bit?

tepid furnace
#

No I have a parent widget. Inside there are a bunch of widgets in a horizontal box. On spawn I want another widget to be positioned in the same position as it. Both are parented to the same canvas

#

I think I might have confused myself now

grave hatch
#

Why not just always have the widget there with an overlay and just hide it when it's not needed?

tepid furnace
#

Because I have no idea how many of them will be needed at design time

grave hatch
#

So how do you know how many widgets there will be in the horizontal box?

stuck jewel
#

you can add or remove things to a horizontal box, to an overlay, etc, whenever you want

tepid furnace
#

I'm mainly also just trying to understand what the tool tip means as it specifically tells me to only use it as a last resort so I'm trying to figure out the intended way to do things

stuck jewel
#

it just means that value will be old when you use it

grave hatch
#

It means that you don't position a widget programmatically with tickspace geometry, you use the proper hierarchy.

tepid furnace
#

So basically just avoid setting widget positions with code?

#

feels like a major oversight with the UI tools then

stuck jewel
#

well, you run into this in every walk of game dev... what's the position of something moving? it's always changing, if you aren't careful you might draw something based on last frame's data

#

putting stuff into a hierarchy lets the program simply update it in an order that (hopefully) works

#

whether or not that is the correct solution will, naturally, depend on the problem 😄

tepid furnace
#

So does this basically mean that the tooltip overexaggerates the severity of the frame behind problem?

stuck jewel
#

i would happily use cached geometry without any concerns at all if i needed to read the location of a widget that A) i know has existed for a while already and B) i know is not moving

#

mind you that still can result in visual uggers - e.g. if the user resizes the game exe window, that might cause an unexpected "movement" of widgets

tepid furnace
#

So basically: Cached geometry is fine for widgets that are ticked, and that are still in movement. If a widget is moving, cached can cause it to lag behind.

And the tooltip exaggerates the problem

stuck jewel
#

but everyone has a different threshold for "jank i am willing to accept to get this game shipped"

grave hatch
#

I don't understand why you can't put it into a proper hierarchy.

stuck jewel
#

i would say the tooltip is perfectly accurate - you should NOT use this unless you have to

#

and i also still don't know what is stopping you from using hierarchy organization

grave hatch
#

Instead of putting widgets on a canvas that you need to place things on top of. Place overlays on teh canvas which have the base widget and add an overlayed widget on top when you need.

tepid furnace
#

Alright I looked up information about the overlay widget and I think I know what you mean now.

Thanks @grave hatch and @stuck jewel for the assistance

round cipher
#

What is the preferred way of binding enhanced input actions to slate UI navigation?

#

or triggering slate UI navigation at all besides what is defined in the FNavigationConfig class

meager mason
meager mason
#

Did anyone ever encounter NativePaint being called each tick? I am drawing some lines with slate in NativePaint, but only change what needs to be drawn very infrequently and call Invalidate only on changes. However, NativePaint is still called every tick, while I would have expected it to cache the painted geometry and only call NativePaint again after any Invalidate calls. I also verified that Invalidate is indeed never called and none of my widgets in the widgettree are set to Volatile. What could cause the repainting every tick?

river thunder
#

as a quick idea i would look at how retainer boxes handle NativePaint()

#

quite possible that it's intended to be called each tick and that you have to check if it was invalidated 🤷

atomic goblet
#

When my widget (action menu) is created, I manually set the focus to the first button, and HasFocus returns true on tick, but the 'OnClicked' event won't trigger with the Enter key until I navigate up/down once. Mouse clicks work immediately, but keyboard input seems ignored for the initial focused state. I've already set the Input Mode to UI Only and tried different 'Press Methods' like 'Button Press' in the interaction settings. How can I make the button recognize the Enter/Accept key immediately upon focus without requiring manual navigation first?

My suspicion is, it has something to do with the mouse cursor. I set it to not show, but it still kinda flies around.

broken hemlock
#

This is the coolest slate widget

           SNew(SObjectPropertyEntryBox)
            .AllowedClass(InArgs._FoundAsset.GetClass())
            .DisplayThumbnail(true)
            .ThumbnailPool(MakeShareable(new FAssetThumbnailPool(64)))
            .DisplayBrowse(true)
            .EnableContentPicker(true)
            .OnObjectChanged(FOnSetObject::CreateLambda(
            [this] (const FAssetData& SelectedAsset)
            {
                OnNoteSelected.ExecuteIfBound(Cast<UUnrealNote>(SelectedAsset.GetAsset()));
            }))```
atomic goblet
#

I just created a target list that is being populatet from an array, and here the Enter Button works instantly. I cannot see any difference, other then the action menu described above is created manually in the designer because I know the items.

atomic goblet
#

in case it helps, this is what the button widget looks like. maybe you see something suspicious.

broken hemlock
#

widget blueprints can't run in slate because the world clock isn't running or rendering

#

Also how big of a deal is it that I'm not using the construct in the .cpp file with these macros


BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION

END_SLATE_FUNCTION_BUILD_OPTIMIZATION
#

I just use the construct in the .h file

broken hemlock
# atomic goblet in case it helps, this is what the button widget looks like. maybe you see somet...

This is slate

TSharedRef<SWindow> Window = SNew(SWindow)
            .SupportsMaximize(false)
            .SupportsMinimize(false)
            .HasCloseButton(false)
            .Title(LOCTEXT("NoteActor", "Choose Your Note"))
            .SizingRule(ESizingRule::FixedSize)
            .AutoCenter(EAutoCenter::PreferredWorkArea)
            .ClientSize(FVector2D(250.f, 125.f));
        
        Window->SetContent(
            SNew(SBorder)
                .VAlign(VAlign_Center)
                .HAlign(HAlign_Center)
                .Padding(5.f)
                [
                    SNew(SNoteActorNoteSelect)
                        .NoteSelected(FNoteActorNoteSelected::CreateLambda(
                    [&] (UUnrealNote* SelectedNote)
                    {
                        Note = SelectedNote;
                        Window->RequestDestroyWindow();
                    }))
                ]);

FSlateApplication::Get().AddModalWindow(Window, FGlobalTabmanager::Get()->GetRootWindow());
meager mason
#

What is the best way to profile and optimize my Slate widgets? The question probably also applies to UMG the same way and one might use the same tools, I just have no idea where to start really, as Unreal Insights doesn't give sufficient information for UI I feel. I have a Slate widget which gets redrawn constantly and I just can't figure out why and before figuring that out I thought i should check if its even worth optimizing that or if its basically "free" anyway.

grave hatch
#

Add scoped profiling stuff to your tick and paint functions.

wispy bramble
#

I'm not sure if I should be asking in here or in #animation : I have a curve on my anim montages that changes the playrate dynamically. Is it possible to make an editor extension to modify the playrate of the Montage Preview so it matches the curve?

limpid ridge
#

How can I add rounded corners to my widget? I've tried looking at how buttons/tabs do it but I can't seem to find anything useful

#

figured it out!

#

The secret sauce is FSlateRoundedBoxBrush:

    ToolkitWidget =
        SNew(SOverlay)
        + SOverlay::Slot()
        .HAlign(HAlign_Right)
        .VAlign(VAlign_Center)
        .Padding(FMargin(4.0f))
        [
            SNew(SBox)
            .MinDesiredHeight(600.f)
            [
                SNew(SBorder)
                .BorderImage(new FSlateRoundedBoxBrush(FStyleColors::Panel, 16.f))
                [
                    SNew(SVerticalBox)
                    + SVerticalBox::Slot()
                    [
                        SNew(STextBlock)
                        .Text(INVTEXT("ToolkitWidget"))
                    ]
                ]
            ]
        ];

grave hatch
#

An alternative is to use a 9-slice texture with rounded corners. That's basically what FSlateRoundedBoxBrush does.

limpid ridge
#

This tool is part of an extension to the Static mesh editor that works with data in a UAssetUserData instance on the static mesh, and when the mode is entered I would like the details panel to show the details view for the AssetUserData. Is that possible to do without too much fuss?

#

like if it's possible I'd be fine with just slapping it in with GetInlineContent()

grave hatch
#

Yeah, it's pretty easy.

#

Just use the Property Editor Module to create a details panel.

#

Make sure it doesn't follow selection.

limpid ridge
#

Cool, I'll give it a shot once I'm on lunch

#

is it just a matter of creating a TSharedPtr<IDetailsView> and slapping some widget it produces into GetInlineContent()?

grave hatch
#

No. You only need to create an IDetailsView. It will generate the entire details panel for you.

#

Unless you want to customise a property on your class.

limpid ridge
#

I'm confused, how does the details view know to occupy this area if I'm not inserting it via GetInlineContent?

grave hatch
#

Well, I'm not sure what GetInlineContent() you're referring to.

#

If that's what puts a widget in that space... then yes, do that.

limpid ridge
grave hatch
#

So replace that.

#

(that sounded a bit more hostile than I intended...)

limpid ridge
#

so it looks like IDetailsView is actually a subclass of SCompoundWidget. So would it literally just be like this?

TSharedRef<SWidget> FMyToolkit::GetInlineContent()
{
    UObject* MyUserData = /* grab the UAssetUserData */;

    return SNew(IDetailsView) //Don't I need a concrete implementation?
        .SetObject(MyUserData);
}
limpid ridge
grave hatch
#

The property editor module creates the implementation for you.

#

There's a method on the module.

limpid ridge
#

ah okay

#

I think I can figure it out from there. Thank you!

grave hatch
#

Search the engine source for PropertyEditorModule.CreateDetailView

#

Plenty of examples you can just copy+paste.

limpid ridge
#

sweet, thanks!

grave hatch
#

Np

limpid ridge
#

Ugh, tried to do it on my lunch break but couldn't quite figure out how to get a pointer to the current asset. I'll have to figure it out after my dayjob

limpid ridge
#

@grave hatch hate to poke you again over this but I am slamming my head against trying to get a reference to the current asset inside the static mesh editor. Would you happen to know anything about how to go about it? Clearly things like UV editor and Static Mesh Modeling mode do it

grave hatch
#

I don't know anything about the SM editor, sadly.

#

What's your entry point into it?

limpid ridge
#

I'm not sure about it being the static mesh editor specifically is relevant. But TL;DR I have a UEdMode that is activated by a button on the top toolbar, and all the UI I've shown is hosted in an FModeToolkit that is created by the EdMode when the EdMode is activated

#

As part of integrating Jolt Physics into UE I have to make an equivalent of UBodySetup and associate it with a StaticMesh just like you would with a normal UBodySetup. For simplicity I'm just doing that as UAssetUserData that is associated with the static mesh, and I was hoping I could just extend the Static Mesh Editor with my UEdMode in a pretty straightforward way. (and if I could just get a pointer to the damn asset that's open in the hosting FAssetEditor, it would be very straightforward!)

grave hatch
#

What's the actual class of editor you have access to?

#

FAssetEditor probably isn't it.

#

As in, how are you adding your stuff in to the editor?

limpid ridge
#

lemme grab my code

grave hatch
#

The stuff you have isn't really relevant. It's what it's being added to!

limpid ridge
#

So I register the extensions in StartupModule:

void FJoltPhysicsEditorModule::StartupModule()
{
    RegisterDetailsCustomization<FJoltStaticMeshComponentDetails>();

    auto& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");

    PropertyModule.RegisterCustomPropertyTypeLayout(
        FJoltBodyCollisionSettings::StaticStruct()->GetFName(),
        FOnGetPropertyTypeCustomizationInstance::CreateLambda([](){ return MakeShared<FJoltCollisionLayersCustomization>(); })
    );

    PropertyModule.NotifyCustomizationModuleChanged();

    FJoltStaticMeshCollisionEditorCommands::Register();

    UToolMenus::RegisterStartupCallback(
        FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FJoltPhysicsEditorModule::RegisterStaticMeshCollisionMenusAndToolbars)
    );

    auto& StaticMeshEditorModule = FModuleManager::LoadModuleChecked<IStaticMeshEditorModule>("StaticMeshEditor");
    auto& ToolbarExtenders = StaticMeshEditorModule.GetAllStaticMeshEditorToolbarExtenders();

    auto ExtendStaticMeshEditorToolbar = [this](const TSharedRef<FUICommandList> InCommandList, TSharedRef<IStaticMeshEditor> Editor) -> TSharedRef<FExtender>
    {
        TSharedPtr<FExtender> ToolbarExtender = MakeShared<FExtender>();
        TWeakPtr<IStaticMeshEditor> WeakEditor { Editor };

        // Command to enter/exit collision editing mode
        InCommandList->MapAction(
            FJoltStaticMeshCollisionEditorCommands::Get().ToggleJoltStaticMeshCollisionEditorMode,
            FExecuteAction::CreateStatic(&FJoltPhysicsEditorModule::OnToggleStaticMeshCollisionEditor, WeakEditor),
            FCanExecuteAction(),
            FIsActionChecked::CreateStatic(&FJoltPhysicsEditorModule::IsStaticMeshCollisionEditorActive, WeakEditor)
        );
        
        return ToolbarExtender.ToSharedRef();
    };

    ToolbarExtenders.Add(IStaticMeshEditorModule::FStaticMeshEditorToolbarExtender::CreateLambda(ExtendStaticMeshEditorToolbar));
}

void FJoltPhysicsEditorModule::OnToggleStaticMeshCollisionEditor(TWeakPtr<IStaticMeshEditor> InEditor)
{
    const auto PinnedEditor = InEditor.Pin();
    if (PinnedEditor.IsValid())
    {
        if (!IsStaticMeshCollisionEditorActive(PinnedEditor))
        {
            PinnedEditor->GetEditorModeManager().ActivateMode(UJoltStaticMeshCollisionEditorMode::Id, true);  // This is where my actual UEdMode gets turned on
        }
        else
        {
            PinnedEditor->GetEditorModeManager().ActivateDefaultMode();
        }
    }
    
}
#

oh

#

oh wait

#

OnToggleStaticMeshCollisionEditor might be the perfect place to try and inject a reference to the actual static mesh editor

#

and if so IStaticMeshEditor::GetStaticMesh() is exactly the function I've been trying to get my hands on

#

let me try that

grave hatch
#

Have you tried subscribing to virtual FStaticMeshEditorOpenedEvent& OnStaticMeshEditorOpened()

#

and then getting the mesh from that?

limpid ridge
#

that is an idea as well

#

the only thing is I'm not sure if that would cause an issue if a designer opens two different static mesh editors at once

#

and actually that makes me wonder if there is a single UEdMode that all static mesh editors share or if each one gets its own copy of my EdMode, which could also throw a wrench into things

#

let me try some stuff

#

thanks for being a rubber duck lol

grave hatch
#

Wait wait wait

limpid ridge
#

waiting

grave hatch
#

Why aren't you using auto ExtendStaticMeshEditorToolbar = [this](const TSharedRef<FUICommandList> InCommandList, TSharedRef<IStaticMeshEditor> Editor) -> TSharedRef<FExtender> to get the editor and mesh?

#

I mean, you are.

#

I don't see the issue!

limpid ridge
#

that doesn't instantiate my UEdMode or or FModeToolkit which is where I need the data

#

literally all that does is make this button

grave hatch
#

But that is triggering your second function?

#

Which also has a ref to the editor.

#

Can you not get a reference to your uedmode there and set the mesh on it?

limpid ridge
#

oh yeah that's exactly what I'm saying

grave hatch
#

Ah ha!

limpid ridge
#

lemme go give it a shot

limpid ridge
#

hmm, so I'm having issues with GetStaticMesh() being nullptr, but this is definitely a step in the right direction

limpid ridge
#
void FJoltPhysicsEditorModule::OnToggleStaticMeshCollisionEditor(TSharedRef<IStaticMeshEditor> InEditor)
{
    if (!IsStaticMeshCollisionEditorActive(InEditor))
    {
        InEditor->GetEditorModeManager().ActivateMode(UJoltStaticMeshCollisionEditorMode::Id, true);
        auto Foo = InEditor->GetEditorModeManager().GetActiveScriptableMode(UJoltStaticMeshCollisionEditorMode::Id);
        UJoltStaticMeshCollisionEditorMode* Bar = Cast<UJoltStaticMeshCollisionEditorMode>(Foo);
        checkf(InEditor.ToSharedPtr().IsValid(), TEXT("%hs 1"), __FUNCTION__); // Passes
        Bar->ActiveEditor = InEditor.ToSharedPtr();
        checkf(Bar->ActiveEditor.IsValid(), TEXT("%hs 2"), __FUNCTION__); // Passes
        checkf(Bar->ActiveEditor.Get() == InEditor.ToSharedPtr().Get(), TEXT("%hs 3"), __FUNCTION__); // Passes
    }
    else
    {
        auto Foo = InEditor->GetEditorModeManager().GetActiveScriptableMode(UJoltStaticMeshCollisionEditorMode::Id);
        UJoltStaticMeshCollisionEditorMode* Bar = Cast<UJoltStaticMeshCollisionEditorMode>(Foo);
        Bar->ActiveEditor = nullptr;
        InEditor->GetEditorModeManager().ActivateDefaultMode();
    }
}

TSharedPtr<SWidget> FJoltStaticMeshEditorModeToolkit::GetInlineContent() const
{
    const auto& PropertyEditor = FModuleManager::Get().LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
    FDetailsViewArgs DetailsViewArgs;

    checkf(OwningMode->ActiveEditor.IsValid(), TEXT("%hs"), __FUNCTION__); // Fails

    return SNew(STextBlock).Text(INVTEXT("GetInlineContent"));
}

so for some reason the reference to the editor instance is valid when we activate the EdMode, but becomes invalid by the time we get to GetInlineContent 😓

#

I'm running on ~4 hours of sleep so this may just have to be something I pick up tomorrow

limpid ridge
grave hatch
#

What did you do?

#

And np!

limpid ridge
#

the problem was I was trying to do this:

InEditor->GetEditorModeManager().ActivateMode(MyMode::Id, true);
MyMode-ActiveEditor = InEditor;

but by the time we get to the second line MyMode has already called Init, Enter etc, and it has to set up the inline content at that point, so of course ActiveEditor was null at that point!

#

so instead I just made it tolerate not having a valid ActiveEditor and made a setter function that propagates it to the toolkit, sets up the details panel etc and calls FModeToolkit::UpdatePrimaryModePanel()

#

I also had a weird issue with what I can only guess was a TSharedPtr cycle that was preventing me from opening reopening an asset that was previously open in the static mesh editor

#

It was probably the UEdMode holding a TSharedPtr to its toolkit and the toolkit holding a TSharedPtr back to the UEdMode

#

but idk it works now so I'm not touching it 😆

grave hatch
#

Ah ha. Nice.

grave hatch
vale stump
#

hello again slate. i dread coming back here.
does anyone know where the text of a SET key is altered in UInputKeySelector, and its inner widget, the SInputKeySelector?
ive been trying to dive into it, and i dont see a function where the text is actually set. I only see that the FInputChord is sent into a chain of delegates and FieldNotifications and cant find the actual meat and potatoes.
Id appreciate if someone with deeper knowledge would look into it for me.

dont get fooled by the SetKeySelectionText() method, which is for the actual selection system and not where the final selected key is set.

grave hatch
#

I'd advise putting a breakpoint wherever the delegates start popping off.

#

See what sets them.

vale stump
#

that would make sense, but i was too lazy to dig into it further tbh. i cant find any way to manually set the text, and i dont wanna go through whatever detail customization override i would probably need to do to set the underlying slate text.

for now, i made the font size 1 (so it doesnt impact the sizing), set all its color options to 0 opacity and overlayed it with my own textblock. had to also copy the methods in the FInputChord over to my widget, and now i can manually alter the text however i wish

rancid lintel
#

I made a custom radial panel on Slatelurkin
same logic as overlay or canvas with panel + panel slot, but for radial menus

mystic zephyr
#

Hi, how i can find is cursor is over UI? I hace a camera system that move camera when cursor is near borders but i need to avoid that if there are UI on borders

vale stump
# mystic zephyr Hi, how i can find is cursor is over UI? I hace a camera system that move camera...
Epic Developer Community Forums

For people Goolging this, also consider taking a look at FSlateApplication::LocateWindowUnderMouse void ReportWidgetsUnderMouse() { // Get a reference to the singleton instance of the slate application. FSlateApplication& MySlateApplication = FSlateApplication::Get(); // Find a "widget tree path" of all widgets under the mouse cursor. // T...

#

Works for any widget. It has to be hit testable I think

little mauve
#

Is it hard to make XY plot or bar plots widgets in slate? 🤔

river thunder
#

no, but if you don't have too many data points you might aswell do it in UMG

#

make a blank widget and override the OnPaint function and use DrawLine method to draw the graph

#

pretty similar in Slate (onPaint/DrawLine(s))

wispy bramble
#

I am getting started with editor extensions and plugins. Right now, I'm trying to figure out how to add a command when right clicking a Sequence Section in the Montage Editor.

#

How is it best done?

wispy bramble
#

Segments, I think they are called?

stuck jewel
#

is there any other menu entries with clear names to search for in the context menu?

wispy bramble
#

I think I found my problem. I was trying to add to Animation Editor, but I searched for the menu I wanted, AnimSegmentsLabel, and see it's actually in the Persona module instead.

#

Hmm. It's still not working.

#

I am trying to add a new option to Here:

#
{
    FPersonaModule& PersonaModule = FModuleManager::Get().LoadModuleChecked<FPersonaModule>(TEXT("Persona"));

    TSharedRef<FExtender> SegmentMenuExtender(new FExtender());

    SegmentMenuExtender->AddMenuExtension(FName("AnimSegmentsLabel"), EExtensionHook::After, TSharedPtr<FUICommandList>(),
        FMenuExtensionDelegate::CreateRaw(this, &FSuperManagerModule::SegmentMenuBuilder));

    PersonaModule.GetMenuExtensibilityManager()->AddExtender(SegmentMenuExtender);
}
    
void FSuperManagerModule::SegmentMenuBuilder(FMenuBuilder& MenuBuilder)
{
    MenuBuilder.AddMenuEntry
    (
        FText::FromString(TEXT("Split")),
        FText::FromString(TEXT("Split into two identical sections.")),
        FSlateIcon(),
        FExecuteAction::CreateRaw(this, &FSuperManagerModule::HandleSplitButtonClicked)
    );
}``` Here is my code.
#

The SegmentMenuBuilder() function never runs, even if I right click the segment.

wispy bramble
#

Maybe I am binding to the wrong thing?

stuck jewel
#

hmm

#

this menu isn't registered through UToolMenu, it's just manually created on the spot

#

maybe this system is supposed to work... i'm not sure, i have extended menus differently before than this

wispy bramble
#

It looks like it checks for extensions in SAnimSegmentsPanel.cpp line 308, so there must be some way to get access to the menu builder.

#

I'll check deeper in the stack to see.

#

I see you're right, that it just creates a new MenuBuilder within STrack::SummonContextMenu and doesn't seem to have any external calls or delegates.

stuck jewel
#

i looked around for a few minutes to see if i could find any FExtenders that were beign used with menus just push raw to FSlateApplication like this... i didn't find any but i only looked at like three or four, like 1% of the engine's examples

#

if true could be a case where this would require engine mods grumpy

wispy bramble
#

There is a member variable called EditorActions that might be a way to add new actions? Except it's protected and no accessors anywhere.

#

That makes me very mad!

#

@stuck jewel Is there another place I can add a tool to persona to acces the Segments?

stuck jewel
#

afraid i have never even opened persona before let alone looked at its source code 😄

wispy bramble
#

Persona is the standard Unreal animation editor/previewer 😮

stuck jewel
#

ah, then i have opened it before, but barely used it edboy

#

i wish you luck whylikethis

grave hatch
wispy bramble
#

I submitted a bug to Epic. Can't do much else at this point. 😠

wispy bramble
#

Wow am I steamed about this.

grave hatch
#

Are you sure you've got the right hook?

#

You can turn on a display of all menu hooks in situ.

wispy bramble
#

Yes, I have the right hook. But examining the code shows that the persona module doesn't access external hooks when initializing the context menu,

#

SAnimSegmentsPanel.cpp line 742

#

Creates a FMenuBuilder within the function, with no external access

grave hatch
#

Yeah...

#

It has an menu extensibility thing.

#

And never uses it 😂

little mauve
#

hey, is there quick way to navigate from widget to file in CPP? some quick button, like F12 for functions or classes 😛

grave hatch
#

I'd generally do ctrl+, type something like "ScatterPlot" and let visual studio tell me where it is.

brisk nova
#

Just realized this would probably fit in this channel

brisk nova
#

Oh I figured it out, it's caused by retainer boxes, after disabling them it works now. But they are quite important for the visuals of the game... What am I supposed to do???

mental badge
#

@obtuse prairie did you ever solve the issue with tables and slateim?

#

and dont know why

obtuse prairie
#

ha x)

mental badge
#

i mean

#

even if i just strip it just to call that its happenign

#

i think

#

se

#

even in a very simplistic thing

#

@drowsy galleon not sure if you are around, sorry for the ping

#

i put this to a very simple test case

#
FKaosGameplayDebuggerWidgetTest::FKaosGameplayDebuggerWidgetTest()
    : FSlateIMNomadTabBase(TEXT("Kaos Gameplay Debugger Test"), TEXT("KaosDebugger.ShowTest"), TEXT("Opens the Kaos gameplay debugger"))
{
    for (int32 i = 0; i < 1000; i++)
    {
        ReplicatedActors.Add({ TEXT("TestActor"), TEXT("TestActorClass"), TEXT("Dormant"), 1.f, 1.f });
    }
}

void FKaosGameplayDebuggerWidgetTest::DrawContent(float DeltaTime)
{
    DrawTable(this);
    DrawTable(this);
}```
#

static void DrawTable(FKaosGameplayDebuggerWidgetTest* TestWidget)
{
    SlateIM::MaxHeight(200.f);
    SlateIM::BeginTable({ .SelectionMode = ESelectionMode::Single });
    SlateIM::BeginTableHeader();
    SlateIM::NextTableColumn(TEXT("Actor"));
    SlateIM::Text(TEXT("Actor"));
    SlateIM::Maximize();
    SlateIM::Padding(FMargin(0));
    SlateIM::InitialTableColumnWidth(80.f);
    SlateIM::Maximize();
    SlateIM::HAlign(HAlign_Center);
    SlateIM::AddTableColumn(TEXT("Class"), TEXT("Class"));
    SlateIM::Maximize();
    SlateIM::HAlign(HAlign_Center);
    SlateIM::AddTableColumn(TEXT("Dormancy"), TEXT("Dormancy"));
    SlateIM::Maximize();
    SlateIM::HAlign(HAlign_Center);
    SlateIM::AddTableColumn(TEXT("Upd. Frequency"), TEXT("Upd. Frequency"));
    SlateIM::Maximize();
    SlateIM::HAlign(HAlign_Center);
    SlateIM::AddTableColumn(TEXT("Upd. Priority"), TEXT("Upd. Priority"));
    SlateIM::EndTableHeader();
    SlateIM::BeginTableBody();
    
    for (const FKaosGameplayDebuggerWidgetTest::FKaosReplicatedActorInfo& Info : TestWidget->ReplicatedActors)
    {
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.ActorName);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.ClassName);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.Dormancy);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(FString::Printf(TEXT("%.1f"), Info.NetUpdateFreq));
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(FString::Printf(TEXT("%.1f"), Info.NetUpdatePriority));
        }
    }

    SlateIM::EndTableBody();
    SlateIM::EndTable();
    
}```
#

even happens with a single table

#

if i just do SlateIM::Fill(); DrawTable(this); it fills and doesnt cause the jumping

#
    SlateIM::BeginVerticalStack();
    SlateIM::Fill();
    DrawTable(this);
    SlateIM::Fill();
    DrawTable(this);
    SlateIM::EndVerticalStack();``` doing this, the jumping comes back
drowsy galleon
#

The vertical stack also needs to fill its container

grave hatch
#

I'm also doing some work on slate im these days, @mental badge, if you have any issues.

mental badge
mental badge
grave hatch
#

You're using the source from git?

obtuse prairie
#

it reminds me of an issue but cant remember

mental badge
#

Yes

#

I even grabbed latest slateim

grave hatch
#

So, to be sure, it's trying to draw the same table twice in the video? But it also happens if you just draw it once?

mental badge
#

Issue was still there so I assume it's something I'm doing wrong.

#

Yes

grave hatch
#

Did you include the vertical stack when drawing the table once?

mental badge
#

No but if i draw a single table with fill above it. It does work

#

If i draw two tables then it bugs again

grave hatch
#

Have you tried fill, vertical stack, fill, table, fill, table?

mental badge
#

Yes. Sec

grave hatch
#

I think that's what Mr Deez was suggesting.

mental badge
#
{
    SlateIM::Fill();
    SlateIM::BeginVerticalStack();

    SlateIM::Fill();
    DrawTable(this);

    SlateIM::Fill();
    DrawTable(this);
    SlateIM::EndVerticalStack();
}```
#

i did this

grave hatch
#

Alright.

#

Have you checked that the data is actually the same each time the table is drawn?

mental badge
#

but this causes a diff issue

#

let me record

grave hatch
#

Alright

mental badge
#

the data is always the same]

#

its static 1000 entries, same data both tables

grave hatch
#

Hmm. I got this issue when I was playing around with something where it wasn't rendering rows (at all) that weren't visible.

mental badge
#

but i am showing all rows

grave hatch
#

Does the example stuff work?

mental badge
#

its all very fixed data here

#

yes

grave hatch
#

SlateIM.Toggle something something

#

Alrighty.

mental badge
#

but

#

which makes me think something weird is going on if even the examples is causing some weirdness

#

look at the bit towards bottom

grave hatch
#

That does look weird. I'll have a look tonight / tomorrow and see if I can find any issues.

mental badge
#

but i couldnt get any simpler

#

than my test case window

#

there nothing else going on

#

static void DrawTable(FKaosGameplayDebuggerWidgetTest* TestWidget)
{
    SlateIM::BeginTable({ .SelectionMode = ESelectionMode::Single });
    SlateIM::BeginTableHeader();
    SlateIM::NextTableColumn(TEXT("Actor"));
    SlateIM::Text(TEXT("Actor"));
    SlateIM::Maximize();
    SlateIM::Padding(FMargin(0));
    SlateIM::AddTableColumn(TEXT("Class"), TEXT("Class"));
    SlateIM::AddTableColumn(TEXT("Dormancy"), TEXT("Dormancy"));
    SlateIM::AddTableColumn(TEXT("Upd. Frequency"), TEXT("Upd. Frequency"));
    SlateIM::AddTableColumn(TEXT("Upd. Priority"), TEXT("Upd. Priority"));
    SlateIM::EndTableHeader();
    
    SlateIM::BeginTableBody();
    for (const FKaosGameplayDebuggerWidgetTest::FKaosReplicatedActorInfo& Info : TestWidget->ReplicatedActors)
    {
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.ActorName);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.ClassName);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(Info.Dormancy);
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(FString::Printf(TEXT("%.1f"), Info.NetUpdateFreq));
        }
        if (SlateIM::NextTableCell())
        {
            SlateIM::Text(FString::Printf(TEXT("%.1f"), Info.NetUpdatePriority));
        }
    }

    SlateIM::EndTableBody();
    SlateIM::EndTable();
    
}

FKaosGameplayDebuggerWidgetTest::FKaosGameplayDebuggerWidgetTest()
    : FSlateIMNomadTabBase(TEXT("Kaos Gameplay Debugger Test"), TEXT("KaosDebugger.ShowTest"), TEXT("Opens the Kaos gameplay debugger"))
{
    for (int32 i = 0; i < 1000; i++)
    {
        ReplicatedActors.Add({ TEXT("TestActor"), TEXT("TestActorClass"), TEXT("Dormant"), 1.f, 1.f });
    }
}

void FKaosGameplayDebuggerWidgetTest::DrawContent(float DeltaTime)
{
    SlateIM::Fill();
    SlateIM::BeginVerticalStack();

    SlateIM::Fill();
    DrawTable(this);

    SlateIM::Fill();
    DrawTable(this);
    SlateIM::EndVerticalStack();
}```
#

its literally this

drowsy galleon
mental badge
#

i mean am i doing anything wrong with my table setup?

#

would be the first thing

drowsy galleon
#

Nothing stands out, but the fact that there's an issue in the example makes me think something got introduced in the recent changes to tables, since you're running latest

mental badge
#

it was happening even in 5.7 released version

#

thats why i tried updating

drowsy galleon
#

Oh really... I hadn't seen that

mental badge
#

let me boot up 5.7

#

original, and see

#

but it didnt happen, when i took slateim

#

before 5.7

#

cause i pulled it from main before 5.7 was released

#

and i remember my tables working

#

so it doesnt happen in the example on 5.7 release

#

but i remember my version i pulled from main never had flickering tables

#

but when we upgraded to 5.7 and i ditched the plugin we pulled from main, it started happening

#

SlateIM: Fix Viewport roots preventing mouse input for the whole viewport
DoubleDeez
DoubleDeez
committed
on Jul 16, 2025 < this commit was the last we had from UE5-main

#

cause this fixed a bug i had with viewport widgets

#

so something past this commit, caused my issues, and something very recently has broken it in main on the examples

#

the issue doesnt happen if you dont render a whole bunch of items

#

@grave hatch ^

#

maybe that gives some more insight

grave hatch
#

Yeah. Thank you.

#

The strange thing is - I unfurled every single thing in the location table.

#

It didn't flitter about even with a scrollbar.

#

And it was doing this way back before the recent table changes, so we may need to go back even further to find the cause

#

@mental badge Do you happen to know the date when you checked out a working version? Like from 5.6 or something?

#

Even going back to the CL when that dynamic table was added, it was already flickering. 🙁

mental badge
#

hmm

#

it was this one

#

SlateIM: Fix Viewport roots preventing mouse input for the whole viewport

#

the last change i pulled in

#

maybe slate under the hood is broken

#

they did all that invalidation stuff in 5.7

#

maybe thats whats causing it(?)

#

i bet its underlying slate issue

#

and my money is on invalidation stuff

#

@grave hatch^

grave hatch
#

Thanks!

mental badge
#

its weird cause i see no issues with slatim itself

#

like nothing i can see

grave hatch
#

Yeah. That's what I'm thinking.

#

I went back with just SlateIM over 6 months.

mental badge
#

yeah its 100% a slate issue, i think its linked to invalidation stuff

#

cause it feels like the widgets are being invalidate

#

strange thing is

#

the sample works fine

#

even with 500 items

stuck jewel
#

More and more and more janky behavior with slate as 5 progresses. Opening instanced struct dropdowns is a freaking travesty

grave hatch
mental badge
#

yeah

#

which makes me think its some underlying issue with slate in 5.7

grave hatch
#

Okay. I'll see what I can find out. Thank you!

#

Any suggestions or anything for SlateIM btw?

grave hatch
river thunder
#

it likes those belly rubs

drowsy galleon
#

What the hell

obtuse prairie
#

after updating an STextBlock do I have to do something so its width changes to fit ?

grave hatch
#

That'd depend on its container/slot.

#

It should get a different requested size and it may or may not change size depending on the container.

obtuse prairie
#

im trying to use .HAlign(HAlign_Fill) on parents but i cant get the correct behavior

grave hatch
#

One think I do notice about the above issue, back in the "working" CL, when you regenerate the items, they don't bunch up. But on the later CLs you get 2 lines and they change size when you scroll. Maybe it's the scrollbox not updating correctly?

grave hatch
#

Have you used the widget debugger to check what the size actually is?

obtuse prairie
#

well, stuff gets stretch to fill but the textblock in the border is still cut

grave hatch
#

The switcher slot doesn't have an HAlign.

#

Other than that, not sure.

obtuse prairie
grave hatch
#

What fixed it?

obtuse prairie
#

nothing

#

cant make the textblock change size

grave hatch
#

Oh. Mixed, not fixed!

obtuse prairie
#

uh, if i add extra characters it increases in size

#

feel like it matchs size, but with a few slate units smaller

grave hatch
obtuse prairie
#

i mean that "Hello" with have "llo" cuted, so if i want to show anything i have to add a few empty spaces

stuck jewel
#

it's going to tell you (well, strongly hint) what is governing size

obtuse prairie
#

how ?

grave hatch
#

Desired Size = the size it wants to be.
Actual Size = the size allotted to it by its container/slot.

#

If AS < DS, the container is the issue.

obtuse prairie
#

well text isnt at desired
border isnt to
parent HBox is

#

border and HBox has HAlign(HAlign_Fill)

grave hatch
#

Can't say what the issue is, only that it's a container issue.

stuck jewel
#

go up the hierarchy until you find out what is forcing it down to 70 width

#

usually without any constraints, desired sizes "bubble upwards"

#

if child's desired size is 69, the container above it probably has a desired size of 69... unless that container is inside a box with a max width

obtuse prairie
#

every container has a AS higher then DS

#

except the widget switcher

grave hatch
#

Then it'll be the widget switcher or its container.

obtuse prairie
#

its alredy with fill HAlign

stuck jewel
#

(this might not be what you want, but just to learn if nothing else)

obtuse prairie
#

worked

#

thanks

stuck jewel
#

Autowidth = make my desired size whatever size my contents want... often for horizontal boxes you want everything autowidth, with one HAlign(Fill) somewhere to stretch

#

or, everything AutoWidth and then the horizontal box just floats with some extra space left or right in its higher-level container

grave hatch
#

And same for vertical boxes, you want autoheight.

little mauve
#

im more familiar with slate now
but still don't know how to add new category sections 🤔
is it part of IDetailLayoutBuilder?

stuck jewel
#

sometimes if you use too many "fill" settings, slate might have trouble figuring out how big to actually make them. being explicit about some items reduces the amount of crap to solve sizes for

#

what is a "category section" to you

grave hatch
#

Which appears to be that class, yes.

#

virtual IDetailCategoryBuilder& EditCategory(FName CategoryName, const FText& NewLocalizedDisplayName = FText::GetEmpty(), ECategoryPriority::Type CategoryType = ECategoryPriority::Default) = 0;

little mauve
# grave hatch You'd add a customisation and inside the customisation you get the option to edi...

I got category, but its just "row"

void FSplineMeshedDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
    DetailBuilder.GetObjectsBeingCustomized(SelectedComponents);

    // Gather the selected components

    // Create a custom "Spline" category
    IDetailCategoryBuilder& SplineCategory = DetailBuilder.EditCategory(
        "SplineMeshedComponent",
        FText::FromString("SplineMeshedComponent"),
        ECategoryPriority::Important
    );

    auto& grpPoints = SplineCategory.AddGroup("Points", FText::FromString("Points"), false, true);
    auto& grpTangs = SplineCategory.AddGroup("Tangents", FText::FromString("Tangents"), false, true);

    SplineCategory.SetSortOrder(0);
// adding buttons and members below 
#

I would like button like "General" or "rendering"

grave hatch
#

At the top? The blue ones?

little mauve
#

ye

grave hatch
#

That's done through details panel sections. You can add your own and specify which categories go into it.

#

I'm forget if you can do that per details panel (with a custom panel) or jsut globally.

little mauve
grave hatch
#

FPropertyEditorModule::FindOrCreateSection

#

I think.

stuck jewel
grave hatch
#
        Section->AddCategory("Shape");``` is an example of what we did.
#

If you want to add them to every type of object, you can make the first parameter "Object"

little mauve
#

thanks 🤔

#

should I add 2 sections for actor component and actor or AC is enough? 🤔

#

nope, its propagated up :d

#

thanks ❤️

grave hatch
#

Adding too many sections is gonna piss people off.

little mauve
little mauve
grave hatch
#

😛

little mauve
#

hey, quick question,

do I need to store refs to all slate objects? Or is it fine to do operations on copy? 🤔

    auto& TangModify = grpTangs.AddGroup("Custom", FText::FromString("Custom"), false);
grave hatch
#

If it returns by ref, store it by ref.

#

Unless it's some simple POD class, like FVector2D.

#

("simple")

stuck jewel
#

as Daekesh said, look at what it returns. if it's returning a ref, it's (very very very likely) giving you the actual instance you need to work on

#

so if you decide to make a copy of that, well

little mauve
little mauve
#

I customized everything almost, Component works fine, params and fuctions.

But for actor I can't make it work to cast to actor and trigger function :/

    CollisionRow.AddWidgetRow().WholeRowContent()[SNew(SButton).Text(FText::FromString("Overlap test")).OnClicked_Lambda(
        [this]()-> FReply {
            for ( auto& ob : this->SelectedActors ) {
                if ( auto act = Cast<ASplineMeshed>(ob.Get()) ) {
                    act->OverlapActorAlongSpline();
                }

            }

            return FReply::Handled();
        }
    )];
grave hatch
#

@mental badge could I ask you to test something your end, see if it stops the tables going nuts?

little mauve
stuck jewel
#

are you using your debugger

#

logging is for watching things that progress over time (or consolidating info to compare lots of event data easier), not checking instant "bang" logic

little mauve
#

I mean actor function works fine.

But this slate button does not trigger it

#

it just calls function on component ;d

void ASplineMeshed::OverlapActorAlongSpline()
{
    TArray<FSplineMeshedOverlapResult> result{};
    SplineMeshedComponent->DetectObjectsAlongSpline(result, CollisionParams);
    YASIUSPLINELOG_FNAME(Log, "Manual collision check found: {0} overlap/blocked objects", result.Num());
}
stuck jewel
#

so use your debugger

#

do you know how to use breakpoints

#

and stepping over/into/out of

little mauve
#

yes, does it work for lambdas?

stuck jewel
#

rider works pretty well, can't remember if VS does

little mauve
#

oke gonna see

stuck jewel
#

unless you're on a very old version of rider

grave hatch
#

VS works fine.

#

Debugs better than Rider, in fact!

stuck jewel
#

that's it, time to initiate r v vs war #82127

#

(i would not enter this fight, rider does a couple of very small but very very annoying things with debugging that it has absolutely no excuse to be doing lol)

little mauve
#

array is emptyl ol

stuck jewel
#

debugger wins again!

little mauve
#

I forget how strong is this mythical technology

#

I have no idea, is there problme cause I did register two layouts? 🤔

    FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");

    PropertyModule.RegisterCustomClassLayout(
        USplineMeshedComponent::StaticClass()->GetFName(),
        FOnGetDetailCustomizationInstance::CreateStatic(&FSplineMeshedDetails::MakeInstance)
    );

    PropertyModule.RegisterCustomClassLayout(
        ASplineMeshed::StaticClass()->GetFName(),
        FOnGetDetailCustomizationInstance::CreateStatic(&FSplineMeshedActorDetails::MakeInstance)
    );

    TSharedRef<FPropertySection> Section = PropertyModule.FindOrCreateSection(
        "ActorComponent",
        "YasiuSpline",
        FText::FromString("YasiuSpline")
    );
    Section->AddCategory("YasiuSpline");
grave hatch
#

Is it being registered?

little mauve
stuck jewel
#

i think i would expect the actor one to display when you click on the actor, and i would expect the component one to display when you click on the component...

#

are you just asking if registering more than one is allowed? yes the engine has a million of these registered at any given time
(what problem are you having)

little mauve
#

still the same, empty array for ActorDetailCustomization

#
class FSplineMeshedDetails : public IDetailCustomization {
public:
    static TSharedRef<IDetailCustomization> MakeInstance();

    virtual void CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) override;

protected:
    TArray<TWeakObjectPtr<UObject>> SelectedComponents;
};


class FSplineMeshedActorDetails : public IDetailCustomization {
public:
    static TSharedRef<IDetailCustomization> MakeInstance();

    virtual void CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) override;

protected:
    TArray<TWeakObjectPtr<UObject>> SelectedComponents;
};
stuck jewel
#

so where do you populate it

little mauve
#

i think i found mistake

#
    DetailBuilder.GetObjectsBeingCustomized(SelectedComponents);

magic line 🤔

grave hatch
#

So... you weren't populating the array?

little mauve
grave hatch
#

Did you expect it to magically fill itself? 🙂

little mauve
#

Ye, I was thinking how does it know how to populate variable with changed name

#

👏 works

#

thanks for something

#

😄

little mauve
#

Somehow, My child actors got reversed order of properties 🤔

#

Component is shown first, then child variable and then parent variables

#

Ok

#

Im reading variable from Child class USplineMeshedComponent_Extension but I hold that object as parent pointer 🤔 , any suggestions how to get that property?

    UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category="YasiuSpline")
    TObjectPtr<USplineMeshedComponent> SplineMeshedComponent;
    TSharedRef<IPropertyHandle> ExtendedParams = DetailBuilder.GetProperty(
        GET_MEMBER_NAME_CHECKED(USplineMeshedComponent_Extension, ExtendedSpline)
    );
    if ( ExtendedParams->IsValidHandle() ) {
        CmpRow.AddPropertyRow(ExtendedParams);
    }
grave hatch
#

Get the child property handle?

little mauve
grave hatch
#

The current property.

#

You'll need to be more specific about what you mean by "I hold that object as parent pointer"

#

Youi mean the property is for a parent class?

little mauve
#

In actor I got component of type USplineMeshedComponent

but for child actors classes I also put USplineMeshedComponent_Extension into that pointer in CDO

    UPROPERTY(BlueprintReadWrite, VisibleInstanceOnly, Category="YasiuSpline")
    TObjectPtr<USplineMeshedComponent> SplineMeshedComponent;
#

Maybe I could loop Array and get properties but im not sure if thats valid way

grave hatch
#

The property handle has a way to get the object it's a property handle for.

#

Get that object, try to cast to the subclass you want. If successful, add the subclass property?

little mauve
#
    TArray<UObject*> ExternalObjects;
    for ( TWeakObjectPtr<UObject> ob : SelectedComponents ) {
        if ( auto cmp = Cast<USplineMeshedComponent_Extension>(ob.Get()) ) {
            ExternalObjects.Add(cmp);
        }
    };
    if ( ExternalObjects.Num() >= 1 ) {
        SplineCategory.AddExternalObjectProperty(
            ExternalObjects,
            GET_MEMBER_NAME_CHECKED(USplineMeshedComponent_Extension, ExtendedSpline)
        );
    }

External works

#

yup, works fine for multiple selection

#

and adding to group works too

        FAddPropertyParams params{};
        CmpRow.AddExternalObjectProperty(
            ExternalObjects,
            GET_MEMBER_NAME_CHECKED(USplineMeshedComponent_Extension, ExtendedSpline),
            EPropertyLocation::Common,
            params
        );
grave hatch
#

👍

grave hatch
#

Just submitted (about an hour ago) a potential fix, it's pretty simple. It was still misbehaving a little when I was testing last night, but today it's not. So shrug.

#

Not sure how long these things take to get on git, but the change was moving a couple of lines inside FSlateIMTableRow::UpdateChild

#
    else
    {
        Children.Add(Child);

        // Modifying the child count requires a rebuild to handle the case where we need to create/destroy the expander arrow and child widgets
        if (OwningTable)
        {
            OwningTable->RequestRebuild();
        }
    }``` is how the function now ends if you wanna test it.
#

@mental badge

drowsy galleon
#

It's only a partial fix, there's still some jittering to solve

river thunder
#

did anyone mess with the major pita to have a custom default tooltip widget? patched my engine -_-

mental badge
#

void FSlateIMTableRow::UpdateChild(FSlateIMChild Child, int32 Index, const FSlateIMSlotData& AlignmentData)
{
    if (TSharedPtr<FSlateIMTableRow> ChildRow = Child.GetChild<FSlateIMTableRow>())
    {
        ChildRow->UpdateColumnCount(ColumnCount);
        ChildRow->SetOwningTable(OwningTable);
    }

    if (Children.IsValidIndex(Index))
    {
        Children[Index] = Child;
    }
    else
    {
        Children.Add(Child);
    }

    // Modifying the child count requires a rebuild to handle the case where we need to create/destroy the expander arrow and child widgets
    if (OwningTable)
    {
        OwningTable->RequestRebuild();
    }
}
``` what was the change?
#

oh only on adding

#

instead of outside

#

will try it

#

if it works better than it did, ill be happy and can finish off my changes

#

that is a lot better @grave hatch

#

i can actually work with this, thanks

#

still some little issues

#

but this at least makes it usable

grave hatch
#

I noticed issues when expanding and collapsing tree rows, too, but not sure how to fix that one.

#

Will need to prod the tree class a bit I think.

mental badge
#

YEAH

#

oops

#

least its usable now

#

that is minor compared to what i was seeig

grave hatch
#

Great!

little mauve
#

lol, how do I hide button in BP? 🤨

#

i did world check and its fine

#

but hiding button would be better I think

grave hatch
mental badge
#

you work for Epic ?

grave hatch
#

Contractor.

mental badge
#

ah i see

#

yeah i saw the commit

#

already pulled it

grave hatch
#

Great!

mental badge
#

just need to find out why my table is no longer scrollable

#

something is wonky haha

#

wish there was an easy way to see all the stuff

#

like a SlateIM visualizer

#

or something

drowsy galleon
#

Widget reflector works on SlateIM stuff

#

You have to mentally remap the swidgets to SlateIM calls though

worn nebula
#

**Question: **Is there a way I can convert

FVector2D MousePos = FSlateApplication::Get().GetCursorPos();

to viewport coordinates?

Background:

Currently I am using this but it fails to take into account my os taskbar and top bar, so its throwing off my calculations for the current mouse position because my coordinate space starts at the top left of the ue application window not the top left of the screen (os window space)

Attached is an annotated screenshot of the issue I am trying to solve

So far I have 2 possible approaches.

  1. Get slate cursor position in the correct coordinate space
  2. Cache UMG base mouse position (Viewport + dpi scaled) -> convert it to slate position and paint that (I tried this and so far I have failed.)

WIdget is placed based on umg coordinates retrieved like so :

    FVector2D ScaledMousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(GetWorld());

**
Ideal solution: **
Get the cursor position relative to the correct coordinate system, this makes the widget api a little nicer as I dont have to manually continually update the mouse position externally

stuck jewel
# worn nebula **Question: **Is there a way I can convert ```cpp FVector2D MousePos =...

first we should ask: what exactly are you drawing - are you drawing stuff "in game"? or is it more like an editor debug overlay, to be drawn over top of the editor viewport?

for the latter, this is some code i am using

if (World->IsPlayInEditor())
{
    UGameViewportClient* GameViewportClient = GEditor->GameViewport;
    
    if (!GameViewportClient)
    {
        return;
    }
        
    TSharedPtr<SViewport> ViewportWidget = GameViewportClient->GetGameViewportWidget();
        
    if (!ViewportWidget.IsValid())
    {
        return;
    }

    FVector2D GlobalMousePos = FSlateApplication::Get().GetCursorPos();
        
    // Check if mouse is within viewport
    const FVector2D AbsoluteMousePos = FSlateApplication::Get().GetCursorPos();
    if (!GameViewportClient->GetGameViewportWidget()->GetCachedGeometry().IsUnderLocation(AbsoluteMousePos))
    {
        return;
    }
        
    FVector2f MouseScreenPos = GlobalMousePos - ViewportWidget->GetCachedGeometry().GetAbsolutePosition();
        ...
    ```
worn nebula
#

Lots of debug logic to try to figure out wtf is causing my math to be wrong.

What I actually want to make ultimately is a radial menu like this:

stuck jewel
#

if this is for a normal "game feature" like an in-game radial menu then i think you shouldn't be trying your approach at all

worn nebula
#

Ingame radial menu. It should be programmable, context sensitive and nestable

stuck jewel
#

you should just e.g. be using player controller to project/deproject world locations to screen locations

worn nebula
#

This makes sense for spawning the actual widget. I am planning to do this later to seed the button data based on the actor and a trace of the hit target

However I still need to be able to draw a line from the center of the radial to the current mouse pos, which is widget space only and not world based

I will examine the code you posted for a bit, It may be helpful . I appreciate the feedback

#

Also I am trying to make it umg friendly so my specific use case based on world coordinates in a specific not general case. I inted to package this up in a plugin give it a few skins, and put it up on fab as well so there is that too

stuck jewel
#

you need to take 5 minutes and skim-read the whole header of APlayerController

#

look at all the functions it has, and stop hurting yourself 😄

mental badge
#

also unreal has radial menus

#

exactly like this im sure in commonui or something

#

i have seen it

worn nebula
#

I could probably make it work if I wanted to but id rather do my own in slate

I dont know how far cui radial goes but I still want my own custom painting and id rather deal with slate than common ui.
Im not going to go so far as to say the cui radial is a bad solution for my use case, I would rather do slate though. Ive already dealt with common ui plenty and this way is better for me and what I am doing

mental badge
#

Past radial menu i made was just done with a material

#

Last

river thunder
#

same, for the slices

grave hatch
worn nebula
# grave hatch Don't forget to set your OS dpi to like 1.5 after you get it working so you can ...

I can totally see this. An ideal solution will just be me figuring out what magic library function I need to get the position in the correct coordinate system.

That was the solution for me spawning the widget in the correct place.

FVector2D ScaledMousePos = UWidgetLayoutLibrary::GetMousePositionOnViewport(GetWorld());

10 hours of screwing around with math and then I find this function.

Realistically it would be really freaking odd if there weren't a way to go from umg coordinates -> slate coordinates at all in the engine. umg widgets are just wrappers around slate, so there has to be a freaking way to do it easy-peasy. I just havent found it and noones told me. That just means noone knows the answer though, not that there is no answer.

worn nebula
#

When I call:

    FVector2D GlobalMousePos = FSlateApplication::Get().GetCursorPos();

It does:

GetCursorPos() Function description:
Absolute coordinates could be either desktop or window space depending on what space the root of the widget hierarchy is in.
Returns:
Transforms AbsoluteCoordinate into the local space of this Geometry

This means is can return coordinates relative to A or B in the picture

When I call:

FVector2D GlobalMousePos = FSlateApplication::Get().GetCursorPos();
auto LocalPos = AllottedGeometry.AbsoluteToLocal(GlobalMousePos);

AllottedGeometry.AbsoluteToLocal(GlobalMousePos) corrects assuming that GetCursorPos() is returning based on B as the base coordinate space.

For my case GetCursorPos() is returning based on A. This results in my corrected cursor position being off based on the position of the editor window.

This is what is killing my math.

I am quite close to the solution, just not quite there yet. I still need to understand slate root widgets and this GetCursorPos() function. Once I have the understanding the fix will take 1 line I bet.

stuck jewel
#

is there a reason why you don't want to just use the simple tools in player controller? (e.g. for mouse cursor position)

#

is there a specific reason why you want to do custom drawing in slate?

grave hatch
#

He's a masochist!

worn nebula
#

Solution:

TSharedPtr<SWindow> Window = FSlateApplication::Get().FindWidgetWindow(AsShared());

if (Window.IsValid())
{
    FVector2D MousePos = FSlateApplication::Get().GetCursorPos();
    FVector2D WindowSpace = MousePos - Window->GetPositionInScreen();
    FVector2D Local = AllottedGeometry.AbsoluteToLocal(WindowSpace);
}

I have a high tolerance for friction.

worn nebula
#

PC get position I screwed around with so much yesterday

stuck jewel
#

trying to draw in-game widgets by running your OS's game window position manually is psychotic

worn nebula
#

It should be fine because I already have dpi running. I can tell when I am not taking dpi into account correctly because as I change the position of the mouse on the screen it will skew based on where it is in the viewport

The further I get from the top left the farther it will drift, either to the top left of where it should be or to the bottom right of where it should be.

I will screw around with my dpi settings though to satisfy you ❤️

grave hatch
#

🙂

#

Good!

stuck jewel
#

that's uhh... a description of engine DPI

grave hatch
#

I also now have a permanent 200% dpi. Helps when looking at these things.

stuck jewel
#

and actually now i realize i didn't test my own plugin's popup menus at other DPIs, away i go KEKW

grave hatch
#

Hehe. Good luck!

worn nebula
#

Set application scale to 2.0, it works flawlessly. Away to costco I go!

grave hatch
#

I'd try OS dpi scaling if. It already.

stuck jewel
#

the OS viewport math position still works fine but other things break, bleh

#

ok 200% is painful to look at and i am not looking forwards to getting old and needing this sorry lol

grave hatch
#

Lol

stuck jewel
#

oh man this is gross. GetDesiredSize returns an unscaled value... and GetApplicationScale returns 1.0 when OS is set to 200%

#

sounds like a problem for future me

grave hatch
#

Application scale isn't the OS value, tis the one from the editor settings.

#

The scale on the geometry takes into account OS dpi.

#

(good stuff, right?)

stuck jewel
#

No, not good stuff lmao

stuck jewel
#

thank heck, pretty easy fix.

TSharedRef<SWidget> MyWidget = ...
MenuWidget->SlatePrepass();

FVector2D WidgetSize = MenuWidget->GetDesiredSize();
        
// The widget draw size needs to be multiplied by DPI to obtain the size the widget would have on screen.
const TSharedPtr<SWindow> TopLevelWindow = FSlateApplication::Get().GetActiveTopLevelWindow();
const float ScaleDPI = TopLevelWindow ? TopLevelWindow->GetDPIScaleFactor() : 1.f;
WidgetSize *= ScaleDPI;```
worn nebula
#

I have the same problem too also. it isnt scaling up. I will probably need to fix that. I didnt even notice. My get desired size isnt multiplying in the scaling

worn nebula
stuck jewel
#

ah thanks good to know, in my case no i'm drawing from "higher up"

grave hatch
#

With a really long pencil.

vapid vigil
#

im in dire need of help on setting up a widget cause its driving me crazy at this point. Is this the right place to ask

grave hatch
#

For a c++ widget, sure.

#

If you're making it in the editor, in UMG, then #umg

vapid vigil
paper gale
#

Here is example, actually it's done via ⁨⁨GetRenderBoundingRect()⁩⁩:
⁨⁨```
AllottedGeometry.GetRenderBoundingRect(FSlateRect(0.f, 0.f, DesiredSizeLocal.X, DesiredSizeLocal.Y));


Upd: nevermind, it's a bit different⁩, BoundingRect makes a rect big enough to "contain" passed rect after rotation.

Anyway I think LocalToAbsolute() is the key
#

BoundingRect (red),
InputRect - grey

#

IIRC you just need to make extra call to LocalToAbsolute() with Rect(0,0) so it would be TopLeft corner, while Desired size is BottomRIght.
Finally to get scaled size just do the ⁨Right - Left⁩ and ⁨Bottom - Top⁩ to get rid off the ⁨offset⁩ part of the Allotted/CachedGeometry internal Transform. CoolStoryBob

#

Btw ⁨Absolute DesiredSize⁩ doesn't mean actual size on screen, it's indeed ⁨⁨desired⁩⁩ and may be clipped still

keen wedge
#

Has anyone ever made a dashed line / dashed box outline in Slate? This is for an editor widget.

stuck jewel
#

there's the built-in marquee brush, what are you doing

keen wedge
paper gale
little mauve
# little mauve ```cpp TArray<UObject*> ExternalObjects; for ( TWeakObjectPtr<UObject> o...

⁨```cpp
auto ExtendedHandle = DetailBuilder.GetProperty(
GET_MEMBER_NAME_CHECKED(USplineMeshedComponent_Extension, ExtendedSpline),
USplineMeshedComponent_Extension::StaticClass()
);

if ( ExtendedHandle->IsValidHandle() ) {
    CmpRow.AddPropertyRow(ExtendedHandle);
}

Found better way to get properties from child classes.

Previous solution was still showing duplicate properties in detail window :d ( i missed it cuz It was wrong category)
obtuse prairie
#

so here i got a button, which is inside a horizontal box that is inside a grid (no the one you can above)

im setting the max width of the button so it matchs the other grid, but i cannot find how to let the button/horizontal box take vertical space to fit the text

#

end goal is to allow the text to warp and take more space vertically

grave hatch
#

Have you set the text to allow wrapping?

obtuse prairie
#

how do i do that with slate ?

#

is it on the slate text style ?

grave hatch
#

On the STextBox

obtuse prairie
#

its a sbutton

grave hatch
#

Which contains text?

obtuse prairie
#

i was using the SButton Text method

#

i switch to Content then add a STextblock inside that allows wrapping, but didnt exapanded

#

it removed the "..." tho

#

nvm, missed AutoWraping with policy

#

thanks !

grave hatch
#

Np

obtuse prairie
#

is there a slate widget to have 2 scrollbox so i can move around like in a graph ?

grave hatch
#

You can put a scorllbox inside another scrollbox.

#

I would advise using external scrollbars for that.

#

Something like this.

#

I don't recall if there's a built-in widget that does it. But you can do this.

obtuse prairie
grave hatch
#

An SScrollBar external to the scrollbox widget.

#

A separate widget.

little mauve
#

can scrollbox scrol content of other slot ?

grave hatch
#

A scrollbar can...

#

Of a scrollbox.

#

Use a grid if you want. I'd use a set of vertical/horizontal boxes.

#

Don't use a wrap box?

#

It'll wrap when it reaches its width limit.

chrome narwhal
#

Can someone tell me how to separate the icon & text from the three dots?
The compile button is a good example. Should I use something else and not InitComboButton?

grave hatch
#

Suggestion: Check teh tooltip for that button, find it in the engine source, find out where either that command or that button is created. See what they do.

kindred nova
#

yea, use widget explorer to find that widget

#

it is just two buttons. one with image-text content, another with image

chrome narwhal
#

I think it's just a HorizontalBox that contains another Horizontal box for the icon and text, + a button slot.

#

Damn this tool is cool

grave hatch
#

That doesn't tell the whole story (it's a horizontal block, etc.)

#

It's part of a menu which isn't usually created with slate.

#

(directly)

#

It's, as you said, create with InitComboButton or some other menu method.

halcyon flume
#

I'm looking to do the following, and having a hard time figuring it out - it seems like it may actually be impossible without engine changes??

I'm looking to -

  1. Remove any default call backs for buttons when dealing with widget focus and navigation. By default, arrow keys will call navigation by a certain direction and such. I want to remove this functionality (which I think can be done by overwriting NavigationConfig so that the keys aren't associated with anything).

  2. Create a way to do the same navigation logic, but from a function somewhere else. I want to be able to call some function like Navigate(EDirection::Right) and it tries to move right from the currently focused widget just like the current keypresses do. I don't want to create my own grid / widget tracking / whatever system to call 'set focus' on, I just want to mimic existing functionality.

It seems that slate is super engrained with the input system for whatever silly reason, and that a lot of these functions are not actually exposed publicly, but I may be missing something.

Can anyone advise?

solar plaza
#

I'm not on my PC but you can overidde a virtual function OnNavigationSomething in c++ when using CommonUI. It allows you to redefine what happen when going left/right

I've used it for example to change slider/enum values in many project settings

#

You can use interface functions OnNext / On previous called on the widget you have the focus. It will allow to easily define such behavior

#

(Sorry if I have misunderstandood @halcyon flume )

halcyon flume
#

Like when you press the right arrow, slate changes focus to the widget to the right of the current focused widget.

I want to do that, but from a public function

obtuse prairie
#

what should i extend to add a new menu and entries in the Content Browser "Create" asset menu ?

grave hatch
#

It's done through the asset definition.

#

Iirc.

#

Check out UAssetDefinition and its subclasses. I may be getting the names slightly wrong...

stuck jewel
#

yeah. you often want to inherit yours from UAssetDefinitionDefault, or look at other existing base classes nearby

#

you may also still need a UFactory? i can't remember (yeah pretty sure you do)

#

the AssetDefinition system replaces AssetTypeActions mostly

grave hatch
#

I think you may need a UFactory too, yeah.

obtuse prairie
#

important part for my case is that im not doing that for a custom asset

stuck jewel
#

eh?

obtuse prairie
#

and iirc you can inject menu entries to create w/e you want

#

seen it in the past, but didnt save the blog post

#

like for e.g i want a menu entry to create a BP subclass and a data asset object instance

stuck jewel
#

have you turned on the menu extension points viewer to see if it gives you any hint

obtuse prairie
#

ill check that tmrw back at work

obtuse prairie
#

got it

#

will share a note soon

obtuse prairie
#

can i tell a container slot to fill space, but inner content like a textblock stays at desired size ?

#

got a slot i want to fill space, but button fills the space instead of keeping desired size

stuck jewel
vague mural
#

how could i use two elements on a button at once?

#

ok i found a way to do it

#

😭

kindred nova
golden elm
#

Hey everyone 👋
I'm having an issue that I was hoping someone could help me with 🙏
Basically I have a 3D widget (using a Widget Component with a World Space widget) and I'm trying to navigate it using the focus system, but also while listening to input actions from an input context.
After digging through the internals a bit, I realized that the Input Actions callbacks are never called when focus is on a 3D widget because that happens when the focus is on the Game Viewport (which isn't the case when focus goes to a WidgetComponent widget apparently).

Has anyone faced this issue before and, if so, have you found a way to solve it or work around it?
Thanks in advance!

grave hatch
#

Sounds like a #umg problem!

wispy bramble
#

Can anyone point me towards a tutorial for Slate Styles?

grave hatch
#

Not off hand, but the engine styles are pretty good sources. Just avoid the starship file... there's so much stuff in it you'll drown.

#

FAvaMediaStyle is one I just randomly looked at that's pretty short and gives you the basics.

wispy bramble
#

Thanks. If I search that name I'll see how it's made and also how it's applied?

#

I want to be able to change the background color of a property editor based on the content's values.

grave hatch
#

Styles can't really do that. You'd need something custom for that

#

Depending on what it is, of course.

#

Styles are just static values. The background image or colour or something.

#

They can't, themselves, respond to the dynamic values in a widget.

wispy bramble
#

Gotcha. So I should be working directly with a color attribute?

#

I found a way to change text color (foreground) but not background color.

grave hatch
#

You could use a FSlateColorBrush as the background image and then change the colour.

#

@wispy bramble

wispy bramble
#

Okay. Background image is an existing property of Detail View?

grave hatch
#

No

#

You want to change the background of the entire detail view or just 1 property?

wispy bramble
#

Just one property, for example.

grave hatch
#

And you want the entire row to change, or just the value part (on the right)?

wispy bramble
#

How could I do both?

#

Sorry, was doing tutorials./

grave hatch
#

Or customise the name and value widgets independently.

#

You'd get a break in between them there, though, where the splitter is.

wispy bramble
#

Understood. If I wanted the entire row I'd need to do a full override and rebuild along with a background?

grave hatch
#

You can get the default widgets that it would have used and place them on to a widget that you make... but you can't access the splitter location (it's private iirc) so you can't make it work nicely with the rest of the panel.

#

I'd go with just customising the name and value separately.

wispy bramble
#

I can edit the engine if I need to.

#

I still need to find how to layer elements on top of eachother. I found the FColorBlock

stuck jewel
#

it would help if you described where you're starting from... a custom class containing these? a struct type you can add to anything else as a property? something else?

a details customization, which can be created for any class, can be used to control the drawing of the whole details panel row by row

a property type customization, which can also be created for any struct or class, can be used to control the drawing of the property itself within a containing row widget

wispy bramble
#

@stuck jewel Let's say I'm making a details customization for a particular class. I have a subset of particular properties that I need to have their background colored differently based on if their value is within a particular range.

stuck jewel
#

so working "from above" (details customization) you would look at each property as you draw it, either drawing it normally, or doing something custom

wispy bramble
#

Yes. How does one properly do "layering" in a slate widget?

stuck jewel
#

are you looking for SOverlay?

grave hatch
#

If you're looking to put a background behind something, SBorder is also an option.

wispy bramble
#

I'll look at both. Thank you.

#

I assume that SBorder has a single child slot but allows formatting of the edges and back of the child?

#

there are UMG equivalents, right? I could try making something in UMG first

misty summit
#

hey all, i'm looking at FSlateVertex and can't figure out how to access the SecondaryColor in material editor?

#

so, looking at SlateVertex.usf and SlateElementPixelShader.usf it seems like SecondaryColor is not passed to the FMaterialPixelParameters(maybe i'm missing it though?) so i noticed in SlateVertex.usf that UVArrays 0's out uv channel 5-7, so i just added the secondary color there so i can access it.

wispy bramble
#

TIL that if you make a custom details view widget it inherits the default elements but not the default formatting of the elements. 😠

#

So I have to make a custom widget, then copy the default row values into the custom widget, then make whatever additions I want.

gleaming warren
#

How is the logical viewport resolution, in the editor preferences for the new window in pie, being calculated?

For example Samsung Galaxy S9 (Adreno) has it set to 624x1280 although the resolution is at 1440x2960. I can't find a single formula or whatever that leads to that result. Additionally, I have tried setting my scale setting on windows to 100% instead of 125% and restarting but that didn't change anything. On top of that, The DPI Curve also doesn't seem to be the missing puzzle piece.

If anyone knows even a tiny thing to guide me into the right direction, I would appreciate it a lot! Thanks in advance

#

I believe it has something to do with the device profiles, in this case "Android_High", but that doesnt change the fact that these logical resolutions are coming from somewhere

obtuse prairie
#

are there any events on FSlateApplication or else to listen to global OnMouseXXX events ?

kindred nova
obtuse prairie
#

no, will look at it

#

although im not sure its a valid place to change the mouse event data

obtuse prairie
#

so UGameViewportClient::CreateGameViewport is only called in GameEngine

#

how can i override the viewport client in editor engine to ?

#

because it seems like its not possible because SPIEViewport subclasses it

grave hatch
#

You'll have to find where the viewport is instantiated and backtrack

tepid furnace
#

Hello Everyone!
Quickly would like to ask if anyone knows how to set the font size of a STextBlock
Help is greatly appreciated!

river thunder
#

it's part of the FontInfo iirc!?

kindred nova
#

yeah, you can get base Font from textblock style, set size and assign it to textblock

tepid furnace
#

Wait can I get more details

kindred nova
#

if you have TSharedPtr<STextBlock> - GetFont - set size - SetFont

#

if you making new block - SNew(STextBlock).Font( font with size set )

tepid furnace
#

And apparently it is deprecated

kindred nova
#

in case you used some deprecated constructor

tepid furnace
#

I typed SNew(STextBlock)
.Font(FSlateFontInfo("Roboto", 56)) inside the construct for a SCompoundWidget

kindred nova
#

so constructor taking font name is deprecated

#
FSlateFontInfo LayoutFont = FAppStyle::Get().GetFontStyle("NormalFont");
LayoutFont.Size = 56;
now use it 
tepid furnace
#

Okay now it works, although FontSize is now known as just Size
Thanks for the help!

visual thorn
#

Hey, i don't know if this is the best place for this, but I've been losing my sanity to this bug for a few days and it seems to be traceable to slate.

When using both mouse/keyboard and gamepad (at least on Xbox controller) the OnInputModeChanged delegate from CommonInput returns some weird results. First found this issue in my project, then in Lyra too. So you start by using the mouse to look around, and then you open the menu in lyra from the gamepad (tapping the menu button illustrates this; holding it makes the input mode makes it fire 3 times and settles on gamepad). At first it returns Gamepad input method, but when you release the button it returns keyboard again, thus the UI indicators still show keyboard instead of gamepad and doesnt focus the widget for gamepad. Pressing any gamepad button again fixes it for that instance. However, if you use the mouse to look again, the issue returns. At first i thought it was because of the way focus uses the synthetic cursor behind the scenes, but then it should've happened at every focus change.

Ultimately I found someone else on the forums with the same issue here and then tested with printing the cursor position in viewport. It seems that windows moves the cursor in the backend and Unreal detects this as moving back to keyboard in FSlateApplication::OnMouseMove ? I hope this helps somebody not lose 3 days debugging crying .

grave hatch
#

It's actually totally impossible to detect whether it was a gamepad virtual move or a cursor one.

#

It's really frustrating.

#

Like I was trying to find a way to completely block certain inputs (actually just limit it to 1 type, e.g. mouse or gamepad) but it was impossible to fix the actual issue being reported. Moving the mouse from the game viewport over to another tab/app (without even alt tabbing) triggered virtual events that you couldn't determine the source of, unless you started capturing raw input.

#

And even if you did, you'd have to change how the mouse events worked to include the source of the input (gamepad vs mouse) in the mouse events.

#

And it'd involve a lot of individual widget code to detect whether you cared which input it was.

#

A whole shitshow.

#

(i was trying to prevent focus loss from common widgets when you alt-tabbed or were forcibly tabbed out by a debugger etc.)

visual thorn
#

That's even worse than I imagined laughcry . I started adding gamepad support to our game early on and it kinda worked, but now, when getting into the small details (i.e. UI indicators and navigation paths in the menus) I'm getting second thoughts. In-game it just works, but the navigation and focus path just seem stuck together with hopes and dreams, most of the times it works, and sometimes it just shits the bed whycry . I honestly expected control mappings for both gamepad and keyboard to be the worst part, but that worked a lot better than I thought.

#

I also found that it's really complicated to add a modal character window like in diablo 3/4, in which you can use mouse/gamepad to navigate character screen while also moving in-game. And after searching a lot for a solution to that I also found out that not many UE projects use that kind of approach. Instead they clearly delimit between UI only and Game only, with very little hybrid input.

grave hatch
#

Honestly for that kind of approach, I would treat menu navigation like enhanced input binds and perform manual navigation.

#

Solves every headache.

#

We have a similar system with text chat. And a keybind-like menu system where you can quickly go through options like a gamepad radial menu.

#

For both those system we don't leave game-only mode, we just use an input preprocessor to intercept the valid "temporary ui input" so it never gets to the game inputs.

#

So you can type 'w' but the action bound to 'w' never occurs if you have text chat open.

#

The one caveat for that is that virtual mouse movements (from the mouse or gamepad) completely ignore input preprocessors.

#

THANKS EPIC!

visual thorn
#

Many things to thank epic for 😂

#

I still remember when navigation rules in the design view would randomly reset on recompile and I had to manually init all of those rules with the set rule nodes. Fun times

grave hatch
#

Lol

visual thorn
#

For a second there I thought I simply forgot to add them

grave hatch
#

Question: in 5.7, what happens if you recompile a umg widget you're actively using in a PIE session?

#

Does it just disappear?

visual thorn
#

As far as I've done that it mostly crashes my engine

#

I make it a point to stop anything I'm doing in pie before modifying Umg stuff

#

I've had the reflector crash the engine quite a lot too

#

🤷‍♂️ I just work around that now, not much lost but I'd rather the feature didn't exist instead of it being sometimes fine and sometimes not

grave hatch
#

Oof

tepid furnace
#

Hello everyone!
I'm currently trying to draw a User Widget inside of a editor tab. I want to draw it in a 16x9 aspect ratio, representative of how it would look if drawn in a 1920x1080 resolution, but scaled to fit the tab. However no matter what I do, it seems to always scale to fill the editor tab instead. I have tried using scale boxes but it still fills the entire tab.

Help will be greatly appreciated!

grave hatch
#

Sounds like you need to set the scale box's min and max aspect ratio to 16/9

tepid furnace
#

I have tried it but the widget is still not representative of how it would look at 1920x1080. As for why I posted it in slate instead of UMG, this is more slate than UMG because I'm using slate to draw a UMG widget, which for these purposes it does not matter much the settings of the UMG widget

kindred nova
#

if you have umg widget - all you need is call TakeWidget, which will construct and return the SObjectWidget that can be used in slate
there was an article on unreal garden on how to make aspect ratio box - that will constrict content to specific aspect ratio and align it

#

but isn't the umg preview panel can change the canvas size to specific for preview purposes?

tepid furnace
#

I have looked at the UMG widget preview and its ability to lock the widget size seems to be what I'm looking for. However since I'm trying to show the widget inside a different editor tab, it isn't really a solution and more of a reference for what I'm trying to make

kindred nova
#

by using https://unreal-garden.com/tutorials/ultrawide-ui/ as reference make custom SBox with customized OnArrangeChildren with ratio constratint, for example my impl was like this:

SNew(SAspectRatioConstraintBox)
   .AspectRatio(FIntPoint(16, 9))
   .ContentAlign(HAlign_Center, VAlign_Center)
[
   MyWidgetPreview->TakeWidget()
]
tepid furnace
#

@kindred nova I have now managed to set it to be 16x9 properly. However the problem now is that the widget shown is always the wrong size, so elements drawn on it will be way bigger than if they are drawn in the player viewport. It also does not change size when the panel size is changed, which is a problem

For context, this is the code that lays out the panel with the UserWidget, located in registerTabSpawners

InTabManager->RegisterTabSpawner("WidgetPreview", FOnSpawnTab::CreateLambda([=, this](const FSpawnTabArgs&)
{
    return SNew(SDockTab)
    [
        SNew(SBox)
        .HAlign(HAlign_Fill)
        .VAlign(VAlign_Fill)
        .MinAspectRatio(1.77f) //AKA 16x9
        .MaxAspectRatio(1.77f)
        .WidthOverride(1920)
        .HeightOverride(1080.0f)
        [
            SNew(SOverlay)
            +SOverlay::Slot()
            [
                //Background image
                SNew(SImage)
            ]
            +SOverlay::Slot()
            [    
                widgetToDisplay->TakeWidget()
            ]
        ]
    ];
}))

Help is again very appreciated

kindred nova
#

yeah, pretty much you do what i expected.
thats why i said i had own slate widget with layouting children

#

just using SBox as is won't give result

#

also you don't want to Fill but Center

#

because after aspect ratio adjustement you will end up with blank spaces and need to align content

#
SDockTab 
  SBox with Width/Height set for dock tab itself or min/max desired size
     SOverlay 
        SImage for background
        SAspectConstraintBox or try SBox(for align) + SBox with AspectRatio
           Content
#

there is no need to cheap out on slate widgets when prototyping layout, you can have more nested boxes then compress things

tepid furnace
#

@kindred nova Not sure if this is the correct implementation but here it is, furthermore the problem of the contained widget in the panel being bigger compared to the player viewport is still present, and a critical flaw here

        [
            SNew(SBox)
            .WidthOverride(1920)
            .HeightOverride(1080.0f)
            [
                SNew(SOverlay)
                +SOverlay::Slot()
                [
                    //Background image
                    SNew(SImage)
                ]
                +SOverlay::Slot()
                [
                    SNew(SBox)
                    .HAlign(HAlign_Center)
                    .VAlign(VAlign_Center)
                    .MinAspectRatio(1.77f) //AKA 16x9
                    .MaxAspectRatio(1.77f)
                    [                
                    widgetToDisplay->TakeWidget()
                    ]
                ]
            ]

kindred nova
#

use ```cpp ``` to format