#slate
1 messages Β· Page 27 of 1
Hey folks, I'm having a theory problem here over what's the best way to implement data tables, their structs, and just general data management, I'm afraid I've never properly studied this aspect before.
My issue ultimately is in trying to see the data referenced nested farther down the line, so I figured that's a slate-centric-issue? Apologies if elsewhere is better, please let me know!
The issue: Basically I have a masterlist of data, in a data table.
I want to make a data table that pulls references from that data table at will, and shows me all the data contained on that row in that data table, without me having to go to that data table in the editor and find the reference myself.
But I don't want to double the data just to get it to be visible in the subset data table. The closest I've gotten is if I make a struct with a single variable; "Data Table Reference Row" and then a Data Table containing a bunch of those structs, but it looks like this:
dear community, I was wondering if anyone here has experience in building the game UI with web tech. I have many years of web based dev experience and would love the creative freedom of it ontop of our project
I have read this: https://unrealcommunity.wiki/web-browser-widget-13f406, but there is no information about getting or sending events to a blueprint for example
maybe someone could point me in the right direction ?
It's called "GameFace" now
It's also "call us to get a quote" pricing though
Hmm
@quaint zealot "call us to get a quote" sounds expensive ^^
Yes usually means 5 figures stuff
The web browser is probably usable with some work
Usually there's some kind of callback for URLs when web browsers get integrated
So you can then plug your own event system
Like, SWebBrowser has OnBeforeNavigation etc
I'd simply plug every callback with a nice print and experiment to see what gets called with which parameters
If you don't need extensive interaction it should work well
do you have have experience with this stuff ?
when taking performace into perspective, I assume Canvas / UMG is the way to go, I just dont know how "custom" it can be which is why we are even discussing the subject
YEs, UMG is the way to go in Unreal, and Web stuff is usually both slower and harder to interface with the game
It'll also have a completely separate resource system and won't have materials
But like, you asked about Web tech so it's possible
Outriders went with UE4+Coherent for example
@quaint zealot the main question if we go with UMG is how customizable it is - becuase from initial research, it looks like building custom elements is not supposed to be done
I sent you a FA where I could show you something we currently have build on a different platform
UMG is quite customizable since you can build Slate elements for it
If you need completely custom elements, yes, sure
If you're going Blueprint only UMG is pretty much the only choice anyway
ok thanks
I'm making a UI that displays data from a dynamic number of assets, which can be toggled in a view similar to the Actors in the scene outliner. I want the toggled states to persist between closing and re-opening the window as well as restarting the editor. Is there a system which I can use to store these states or would a UObject with the Config specifier be my best bet?
Im trying to get a dialogue plugin to work, but I'm getting an error error C2440: 'initializing': cannot convert from 'SConstraintCanvas::FSlot::FSlotArguments *' to 'SConstraintCanvas::FSlot *' on the line:
SConstraintCanvas::FSlot* tempSlot = &CanvasPanel->AddSlot()
UE5 right?
yeah its a 4.27 and trying to get it to run in 5.0.
AddSlot() seems to be SConstraintCanvas::FScopedWidgetSlotArguments SConstraintCanvas::AddSlot()
auto where?
SConstraintCanvas::FSlot* tempSlot = &CanvasPanel->AddSlot()
Since the type is the issue
Failing that, well, it gets complicated
Slots essentially moved to a more Slate-y approach
So they're arguments now, not FSlots
not really sure how to use auto, but I tried in a few spots and none worked π¦
Essentially you can't work with FSlot* anymore, since that'll get constructed later
You should ask the plugin author
Hm. Well I postedin the forum thread, but not sure how to get a hold of him directly. There were posts about it working in 5.0 with minimal problems, so the code must have changed since those posts
Ahh ok. All this slate stuff is waay beyond my current skill so I guess I'll have to wait till he's able to update the plugin for 5.0
I figure the Slate slot stuff is gonna hurt a lot of people, I do Slate on the daily and I didn't even correctly port them in DLSS to 5.0
Thanks for the help π
Hi guys i have posted in C++ section and they have redirected me here to search for some answers:
https://discordapp.com/channels/187217643009212416/221799439008923648/936314486783115295
What i'm trying to do is to just get the reference to my software cursor which is a UUserWidget... so i have no idea how to cast SWidget to UUserWidget.
I'm having this error today
Unrecognized type 'FReply' - type must be a UCLASS, USTRUCT or UENUM
I have the Slate and SlateCore modules on build.cs
Someone knows why this is happening?
Fixed.. I removed the UFUNCTION()
How can I create an edit text? Essentially I want to create Slate's version of Qt QLineEdit
I found SEditableTextBox, but I think this is multi-lined. I want one line.
I feel like Slate is literally based on Qt conceptually lol
Looks like it is that
is there a way to get the like, "overall" visibility of a userwidget
like, if MyUserWidget's parent is hidden, then it returns hidden regardless MyUserWidget's actual Visibility
Looking to copy some data from my custom data asset into my slate plugin, is there a simple way of doing this? I've looked into SDetailTree, but I have no idea how to implement it
I'm just looking into replicating exactly whats in there into my plugin
decided to write my own, works by calling ->GetParent() iteratively until it finds something that's Hidden
problem is, that only gets you to the root of whatever widget blueprint its inside. I assumed it would take you all the way to the viewport
so: when this button here only gets up to the root CanvasPanel...
and that entire widget gets hidden in a different blueprint...
I can't detect that
{
// if this widget is itself already ~hidden, just return that
switch (this->GetVisibility())
{
case ESlateVisibility::Collapsed:
case ESlateVisibility::Hidden:
return this->GetVisibility();
}
// search up the ownership tree until we find something ~hidden
UWidget* Current = this;
while (Current)
{
switch (Current->GetVisibility())
{
case ESlateVisibility::Collapsed:
case ESlateVisibility::Hidden:
return Current->GetVisibility();
}
Current = Current->GetParent();
}
// if nothing in the tree was ~hidden, return our own visibility (assumed ~visible)
return this->GetVisibility();
}```
Probably pretty simple question, but is there a good example for doing ~~StrikeThru ~~on a simple STextBox?
I see it has support for a StrikeBrush but Im not entirely sure what that is looking for and how to set that up
Hello everyone! Not sure if it's a UI issue, most likely confused about inheritance and don't see an obvious error. UE crashes on any attempt to access WBP widget:
AmmoCrate.h
UCLASS() class PR_API AAmmoCrate : public AActor { GENERATED_BODY() public: AAmmoCrate(); virtual void Tick(float DeltaTime) override; protected: UPROPERTY(EditAnywhere, Category="Components") UHealthBarWidget* WBP; }
AmmoCrate.cpp
AAmmoCrate::AAmmoCrate() { PrimaryActorTick.bCanEverTick = true; WBP->SetHealthPercent(1.0); //**crash here!** ... }
UHealthBarWidget.h
class UProgressBar; UCLASS() class PR_API UHealthBarWidget : public UUserWidget { GENERATED_BODY() public: UFUNCTION() void SetHealthPercent(float Percent); protected: UPROPERTY(meta=(BindWidget)) UProgressBar* HealthProgressBar; }
UHealthBarWidget.cpp
#include "UI/HealthBarWidget.h" #include "Components/ProgressBar.h" void UHealthBarWidget::SetHealthPercent(float Percent) { if (!HealthProgressBar) return; const auto HealthBarVisibility = (Percent > PercentVisibilityThreshold || FMath::IsNearlyZero(Percent) ? ESlateVisibility::Hidden : ESlateVisibility::Visible); HealthProgressBar->SetVisibility(HealthBarVisibility); const auto HealthBarColor = Percent > PercentColorThreshold ? GoodColor : BadColor; HealthProgressBar->SetFillColorAndOpacity(HealthBarColor); HealthProgressBar->SetPercent(Percent); }
Oooops.
It was SO stupid xD Thanks! Stuck on this for a couple of hours...
And I'm sorry for mixing up the channels
I'm working on a 'function dispatcher' system that lists UFUNCTIONs and stores them on an array. I took GAS' attribute system's dropdown menu logic and it's working fine so far. Would it be possible to create new widgets based on listed function's params? Like if the function has an int32 param I want to add new widget dynamically.
if you have the data available you can visualize it however you want
I'm not familiar with the systems you are talking about, but if you have ufunctions and you are able to access a function's signature, you naturally can parse it and add additional widgets based on parameter type in your widgets via one of the many access points to add customized widgets for data
Alright, thanks a lot
How do I pass parameters to a SButton's OnClicked() event?
I see this link everywhere when I try to understand how to make a custom graph editor...but it doesn't really help since there is soooo much code to understand in one go. Is there any tutorial/lesson about custom graph for beginners anywhere ? Best I found so far is this one : https://easycomplex-tech.com/blog/Unreal/AssetEditor/UEAssetEditorDev-AssetEditorGraph/
But it's very incomplete (missing big chunks of code) and very old (some code is deprecated)...so really not ideal xD
Any help would be greatly appreciated.
1 Overview --- Graph view is very important in UE4 development, it can make development conveniently. For example: + Blueprint Event Graph + Blueprint Function Graph + Behavior Tree --- ## 2 Critical Class To creat a graph view in UE4, you'll need to derive from two basic classes....
That is what my kittengraph is intended to be, a fully documented version of GenericGraph.
But no, Slate and Editor Extentions is like, the least documented part of all of Unreal Engine. Haven't been able to find anything.
Yeah it's not part of the game facing API and thus Epic considers there's no way to document it as fast as it changes, since it's internal stuff
Soooo, is kittengraph available anywhere ? π
I googled but no result...
That's awesome to know that I'm struggling for a reason and that someone is trying to document this :p
I found some of your stuff. You are awesome. Thank you for taking the time to make tutorials and making learning easier for us noobs. Hope you are having a fantastic day ! <sending positive waves>
Very same
If only I had found your link to the tutorial about custom thumbnail for custom assets, I would have saved a week of work in 10 minutes xD
Is there any way to go from a slate widget back up to its parent UUserWidget?
There must be, the widget reflector knows what each slate widget is insdie
I saw something like
Swidget->PersistentState->ParentWidget while debugging some days ago. I'll check tomorrow on PC
It's OK I managed to find a way to do it
Did you ever find a solution to this? I have exactly the same problem ...
How do I make an SButton change to a little loading spinner when they are clicked, until a delegate fires?
// Login and registration buttons
+ SVerticalBox::Slot()
.Padding(Uniform_Padding)
.AutoHeight()
[
SAssignNew(LoginButton, SButton)
.Text(NSLOCTEXT("LoginScreen", "LoginButton", "Login"))
.OnClicked(this, &SUGH1LoginWidget::OnLoginClicked)
]
+ SVerticalBox::Slot()
.Padding(Uniform_Padding)
.AutoHeight()
[
SAssignNew(RegistrationButton, SButton)
.Text(NSLOCTEXT("LoginScreen", "RegistrationButton", "Register"))
]```
this is what i have
Add an SWidgetSwitcher, in it you add the login button and an SCircularThrobber
Based on your login logic switch between the two
Thanks, that works!
New to slate. Any quick ways to make the add and clear buttons for arrays? Or do I have to make SButton and set everything myself? In the reflector I see they're SPropertyEditorButtons, but not sure how it can be used. Can't even find out how to include it, looks to only exist in a .cpp file.
no idea if I should post this here or in editor scripting to be honest, but is there a way of hiding categories in a DetailTree?
so this is how it looks in my slate
I want it to be like this
Are you trying to use an array property in a random bit of UI?
the property editor module has like a MakeSingleWidget (or something) call that might work for you.
I don't think you can get rid of the categories in the details panel
Ah dang alright thanks!
Is there no way of just having a slate widget that changes depending on the variable you make it? Like DetailTree but with single widgets?
A bit like what CustomDataAssets and the details panel has
See this ^
I've never used it, so I'm not sure exactly what it'll do, but I figure it has to be something like what you want.
Can I programmatically expand a collapsed (sub)category?
yes just change it's widget visibility from collapsed to visible (and vice versa)
that will work for any type of widget btw
Help with some editor tools. Im using SObjectPropertyEntryBox and i can "do" what i need to: Select an animation asset and set a variable value on the class of the component i need to modify
but 2 things are broken:
- The value doesn't change on the SObjectPropertyEntryBox
- The blueprint is not marked as dirty
if i do mark it somehow and save everything serialize as expected
void FNPCSplinePointDetails::OnSetAnimationAsset(const FAssetData& assetData)
{
if (UAnimationAsset* animAsset = Cast<UAnimationAsset>(assetData.GetAsset()))
{
const FScopedTransaction Transaction(LOCTEXT("SetAnimationAsset", "Set Animation Asset"));
const int32 Index = *SelectedKeys.CreateConstIterator();
if (UNPCSplineData* splineData = SplineComp->GetComplexDataAt<UNPCSplineData>(Index))
{
splineData->AnimAssetToPlay = animAsset;
}
if (ComplexDataProperty)
FComponentVisualizer::NotifyPropertyModified(SplineComp, ComplexDataProperty);
UpdateValues();
}
}
this is basically what i'm doing
it's details for a splinecomponent which has metadata to store aditional values on some points
i think the main issue is that im not linking the property handle with the entry box
but for some reason i can't really seem to be able to do that
the handle is always invalid
Have you tried adding a breakpoint and stepping through the code?
Blah->Modify() will mark it dirty.
What's the "correct" way to tell if a modifier is being pressed in editor code? I see there's a bunch of keybindings for actions in the editor but I'm not really sure how to check in editor code for if shift (or whatever the action is bound to) is being held down
Are you implementing your own keybinding system for a widget? Or are you changing behaviour when shift is held down?
Anyone know how to force focus on SMultiLineEditableText? I'm creating new EditableText and when user create it I want to move the focus right into it so he don't need to right click to the widget to start typing. This is editor widget created with slate.
This isn't working:
MultiEditableTextGlobalNote->SetText(FText::FromString("Temp")); MultiEditableTextGlobalNote->Refresh(); MultiEditableTextGlobalNote->GoTo(FTextLocation(1, 0));
This isn't working as well
FVector2D Pos = MultiEditableTextGlobalNote->GetCachedGeometry().GetAbsolutePositionAtCoordinates(FVector2D(1.f, 1.f)); const FPointerEvent& SimulatedPointer = FPointerEvent(uint32(0), uint32(0), Pos, FVector2D::ZeroVector, TSet<FKey>(), EKeys::LeftMouseButton, 0.0f, FModifierKeysState()); MultiEditableTextGlobalNote->OnMouseButtonDown(MultiEditableTextGlobalNote->GetCachedGeometry(), SimulatedPointer);
Edit:
Nvm. This is working:
FSlateApplication::Get().SetUserFocus(0, MultiEditableTextGlobalNote, EFocusCause::SetDirectly);
<@&213101288538374145>
Trying to make a RichText decorator that can display a UserWidget inline in the text and not just an image. I'm really close to make it work, just got one problem:cpp const FRichWidgetRow* RichWidgetData = Decorator->FindRichWidgetRow(*RunInfo.MetaData[TEXT("id")], bWarnIfMissing); UUserWidget* WidgetPtr = CreateWidget((UWidget*)Owner, RichWidgetData->WidgetToDisplay); //Problem is that GetCachedWidget returns NULL... TSharedPtr<SWidget> RichWidget = WidgetPtr->GetCachedWidget();
I did it! In this case instead of cpp WidgetPtr->GetCachedWidget(); you should use cpp WidgetPtr->TakeWidget();the functions have comments explaining their usecases
How do I make the inline widget have vertical alignment in center instead of at bottom?
So that the middle of the widget is in the middle of the text vertically, could I perhaps take the the text's lineheight / 2 and offset the widget up as a hax?
whatβs the difference between UMG and slate
Iβve only used the umg channel but I thought Iβd see what this is too
Umg is the uobject based wrapper around slate. They are not different systems. Slate is just the lower level that you can use if you need it. Since slate is just regular old code, the editor cannot use it, so you are forced to write it in cpp. The primary use case for learning slate it to make editor plugins, or to customize the editor in general. The only reason to use it in game code is if you really need to add something to umg that it cannot do natively. Only worry about that if you already have a good handle on umg, since it can do most things decently if you learn it well.
It's also infamously incomprehensibly difficult to use, due to the syntax being especially strange, despite being normal c++, but once you get used to it, it's not that bad really. It just gets a bad rep sometimes.
Once you get used to it, it's actually pretty easy to work with.
The barrier to entry is very high, though.
the barrier is "that looks a bit odd but ok"
Compared to the rest of UE, it's pretty high.
The main barrier is more that since it's not for game use, there's little documentation other than 8 year old hacks and the editor source
Hi,
When you start a blank project, pressing play, it gives you a simple free-camera to go around. This is all i really require for the app I am making; except for that the mouse is locked as soon as you right click.
What I would like to do though, is have a button press that lets you move the mouse (no camera movement) and interact with the UI.
i thought it would be simple but idk where to start
what are workspaces from the FTabManager?
You can use it for games, stranger.
not openly intended* for games. (I know Stranger has used it in games before himself and was just having a slip of words π )
I made a whole game in Slate!
It was excruciating. But a good learning experience.
(And by whole game, I mean the game was literally 100% slate ui, no actors, etc.)
i guess life itself wasn't depressing enough for you already?
π
so looks like Tile View is quite useless. There is no Multi Toggle selection mode and I don't see way to limit number of selections (it is either none, one or anything in list).
can you at least unselect something during selection of that same thing? that would be enough to simulate limited amount of selectable items
Couldn't you use the selection changed delegate to do that? Or override Private_SetItemSelection?
Could anyone help me understand what the difference is between SLATE_BEGIN_ARGS / SLATE_ATTRIBUTE and regular Construct parameters? E.g., when is it preferred to use one or the other? Does the SLATE_ATTRIBUTE provide any additional magic beyond enabling the builder-style syntax?
Have you looked through a bunch of examples in the engine?
How much is a bunch? π I've looked through a few that roughly match what I'm trying to do, but it's kind of... a lot
How can I do conditional creation of slate widgets based on argument input in Construct()
Like this little edit text, how could i make it so that this only gets created if an argument is true
To get more specific, I'm trying to build a tree view. And currently I'm just passing a const reference to a flat array as a second Construct param, and then building the nested data structure inside Construct. But if the array isn't populated when I first construct the widget, it doesn't update when the array changes (no surprises there, since I'm not reconstructing the widget). I could sort of cowboy-code it by just adding an update method to my widget that I can call with the new data, but I guess what I'm wondering is if there's a more idiomatic or built-in way to handle that sort of thing.
I did notice that when you create a SLATE_ATTRIBUTE it wraps your data in a TAttribute with a Get method, so I was thinking... maybe that creates some sort of dynamic/observed binding? Somehow? But I really have no idea, that's just a wild guess. So I figured I'd ask to see what it actually does.
@keen swift you don't have to add slots and such within a giant slate constructor, you can do ->AddSlot() at a later point
That's basically what it does, @zinc reef
TAttribute allows you to either specify a value, bind to a function or not specify it at all.
Awesome, thank you!
.HAlign(HAlign_Right)
.VAlign(VAlign_Bottom)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
[
SNew(SBox)
.WidthOverride(600)
.HeightOverride(300)
[
SNew(SImage)
.ColorAndOpacity(FColor::Black)
]
]
]```
How can I add items to be within the SBox? It's only letting me add the SImage and nothing else. I'm just trying to make a small chat box on the bottom right of my screen which should have a tinted black background (black is fine for now) and a SEditText and a list of chat messages, not sure if there's a SListView or something
If I add a new vertical box slot it's putting the text ousdie of the black background
i want it to be inside of the black background lol
SBox doesn't have a Slot sadly
If something only has a single child slot, you need to add a widget rthat has multiple slots into that single child slot
Like an SCanvas or SConstraintCanvas
How do I do that?
Things with a single slot usaully have a ChildSlot
What you can do as well is use SAssignNew instead of SNew too
TSharedPtr<SMyWidget> MyWidget; (before your layout code)
Then SAssignNew( MyWidget, SMyWidget ) (inside your layout code)
Then you can manipulate the widget however you like after layout
Like adding dynamic content
How do I do that though?
(dynamic based on your construct vars)
I understand how SAssignNew works, just creates the new slate object and assigns it to the variable you pass, right?
replace SMyWidget in the above example with SConstraintCanvas
Then later you can do MyWidget->AddSlot() [ details here ]
Or whatever your layout widget of choice is
i'm not sure which slate widget only has one child slot
SBox?
In fact, I'm not sure why you're using SVerticalBox right now. It's not necessary for that black box, it should be deeper in your layout
Go prototype your layout in UMG and then convert it to slate.
How do I make it repaint a SCompoundWidget? It seems like it's not repainting my widget when I add a new slot to the SConstraintCanvas
SConstraintCanvas::FSlot* tempSlot = &ChatConstraintCanvas->AddSlot()
[
SNew(STextBlock).Text(NSLOCTEXT("MenuWidget", "PublicChatBox", "Public Chat"))
];```
nevermind looks like it was created but its super small
Hey people, I am losing a button down/clicked event. I tracked it down to SlateApplication.cpp line 4341
But I cannot trace along that lambda. The click event gets "handled" somewhere there but even after I placed a breakpoint on every single OnKeyDown implementation I do not get a breakpoint hit.
Anyway. It occurs when I launch the game and click the confirm button on the face of my controller. When I press it quickly the button that is focused in UMG is not clicked. Instead only on the second try will I get a click callback.
It would seem like the switch from keyboard/mouse to controller consumes the input π€
But when I long press the button the clicked event gets sent out as normal.
Any ideas on how to fix this inconsistency?
how do I get local cursor position in OnMouseMove event of my custom widget ?
Are you using a node "SetInputModeUIOnly"?
I had same issue when only 2nd click was recognized correctly and that node was causing the issue, even if my Project was UMG based only
If you're using this node - remove it and replace with "SetInputModeGameAndUI", I used it to restrict the mouse within Viewport and after change the issue was gone
and just btw - I am working with UE 4.27
or maybe you have focus on something different at the beginplay and you have to make focus on a part you want to click and then it's being recognized afterwards
@eternal wave use the GetScreenSpacePosition() from the pointer event and the GetAbsolutePosition() of the geometry thing, that's how I usually do it anyway.
You may need to adjust for UI scale and such if you want coordinates accurate (compare GetAbsoluteSize() with GetLocalSize()) in local space
so ( PointerEvent.GetScreenSpacePosition() - Geometry.GetAbsolutePosition() ) * Geometry().GetLocalSize() / Geometry().GetAbsoluteSize() unless I've missed a handy function for this.
i'm running into an issue where invisible/disabled widgets are slipping through here despite checking for it, is there something i'm missing?
What are the visibility states of the visible invisible widgets?
typically i'd collapse the containing widget, i assume that leaves the child widget in a visible state technically?
i'm using the found widget's geometry (size & pos) further in the function, the issue is it's operating on geometry that isn't visible to the user
Are you trying to find the widget under the cursor or anything?
not exactly - i'm trying to find the nearest widget to the cursor
to be specific, the nearest SButton to the cursor (getting the cached widget from the found widget and checking SWidget type)
You could try IsFastPathVisible
sounds promising but i can't seem to find it, is it a widget member function?
It's a base SWidget function
ah i see, found it in the SWidget documentation although it's still not showing up - am i doing something wrong here?
->
same thing
yeah that's likely what's going on, i'm on a modified 4.26
might be able to backport the change if it's new in 4.27
Yeah, isn't on 4.26.
appreciate the help π
I'd just check each parent widget until you hit a specified root widget.
that makes sense, will give it a try
thanks again for the help, was pretty lost with this one
Np
I'm sure there's a better way, you could, for instance, set a "group" on your widgets and then check if that group's parent widget is visible to speed things up. Depends how deep your widget hierarchy goes.
backported the SWidget::IsFastPathVisible functionality and unfortunately it doesn't seem to work - still getting widgets with collapsed parents slipping passed
π¦
how to pass FArguments& Arguments to an SCompoundWidget when building it through SNew?
its constructor is void Construct(const FArguments& Arguments, const TSharedRef<IEditableTextProperty>& InEditableTextProperty);
but I only see examples of usage:
SNew(STextPropertyEditableTextBox, EditableTextProperty) with no FArguments
.SomeProperty( value )
.SomeOtherProperty( othervalue )```
thanks but I did it by MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
Fantastic. π
Something is eating my inputs.
How can I find out what is consuming inputs?
Something is putting my game into a state where it ignores VR controller inputs.
They don't make it to the player controller, and they don't even make it to UGameViewportClient::InputKey . They are definitely making it to FSlateApplication::ProcessKeyDownEvent, I do hit a break point in that function.
Once I click on the game viewport, the VR controls respond normally again.
(At this point I'm tempted to just find a way to force input back to the main viewport)
Got it! If anyone's curious,
- To figure out what had the focus, I called "Set Focus to Game Viewport" in BP, and put a break point in FSlateApplication::SetAllUserFocusToGameViewport . It runs a function to get the OldFocus and OldFocusPath, which helped me figure out where the focus was.
- The offending widget had a call of UWidget::SetKeyboardFocus . Worked fine when not using VR, but in VR would take the focus away from the game viewport.
managing widget focus can be a pain - next time you can try using the widget reflector to help debug them by enabling the focus events in the filter
same with inputs, etc
Nifty, thanks for the tip @weak fiber !
Does the OnIsSelectableOrNavigable delegate for STreeView or SListView actually do anything? I've set it but it doesn't seem to properly limit item selections in my tree. A breakpoint would seem to indicate that it's not even being called as I click around my tree.
Check where it's called in the source and figure out the conditions for it.
It may not behaving exactly as you expect.
Hi everyone, how can i make my slate widget not fullscreen? I have this code:
`ChildSlot
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SBox)
.WidthOverride(256)
.HeightOverride(100)
[
....`
You could use a constraint canvas with the anchors set to 0.5f, 0.5f, 0.5f, 0.5f and the alignment set to 0.5, 0.5f, then the offset set to half size (width/2, height/2, width/2, height/2.)
(I overuse constraint canvases, I think)
Thanks @grave hatch , now I have
`ChildSlot
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
[
SNew(SConstraintCanvas)
+ SConstraintCanvas::Slot()
.Anchors(FAnchors(0.5,0.5,0.5,0.5))
.Alignment(FVector2D(0.5,0.5))
.Offset(FMargin(50,50))
...but it's still fullscreen. in the HUD I haveRightDistanceWidget = SNew(SDistanceWidget).OwningHud(this).Space(0);
GEngine->GameViewport->AddViewportWidgetContent(SAssignNew(RightDistanceContainer, SWeakWidget).PossiblyNullContent(RightDistanceWidget.ToSharedRef()));
`
Is this correct?
You wouldn't need the valign and halign
That's handled by the constraint canvas.
Looks about right. π¦
The anchors anchor it to the centre of the screen, at zero size, the alignment makes it use the centre of the widget to calculate its location and the offset should make it 100x100 :/
Oh, the offset should be negative for left and top.
-128,-50,128,50 or so
But that isn't your problem right now!
The constraint canvas will still cover the entire screen, but the slot should only be in the middle.
what if i use .AutoSize(true) con SConstrainCanvas?
Maybe?
But it's the constraint canvas's parent that's the issue. That's going to cover the entire screen regardless.
(it will just do it transparently)
@unkempt moss any luck?
I'm still trying. I'm having lunch right now, I'll let you know.
So I'm having a weird callstack like this and dont know where to start debugging. Engine crashes at SImage::ComputeDesiredSize when I place a node to my custom graph
Probably this is invalid but..
Alright fixed, I was using invalid Pin class
When using style sets... how can i probably use other styles as attributes of a new style?
So what i want is following:
I have a SlateStyle-Struct that will be used in two other Styles, its called "NumericKeyframeIcons"
One of those other styles is called "KeyframeControl"
How Can I tell in the Cpp code, that the default KeyframeControl should use the NumircKeyframeIcons from the style set?
The image shows the "Numeric Keyframe Icons" Attribute of the "Keyframe Control" style in the style set doesnt have the same values as the "Numeric Keyframe Icons" style in the style set...
I dont want to have to manually copy it over, because if i have later multiple styles that rely on the "numeric keyframe icons" style in the style set, and i change it, it would cause inconsistencies... so best would be if the system somehow understands that it should do the C&P automatically
Hi,
How do I get the UUserWidget from a SWidget?
Good question.
Get all objects of class and check the swidget on each of them?
I don't see an easy way to do it.
If you're using a custom uuserwidget, you could extend the swidget you're using to add a reference to the uuserwidget. But that's not really a general solution.
The FindWidgetFromSlate() function here might help: https://github.com/sinbad/StevesUEHelpers/blob/master/Source/StevesUEHelpers/Private/StevesUI/StevesUI.cpp
Thank you! Iβll try it out at work tomorrow!
Kinda of only works if you already have a UWidget reference, though...
if(widget->GetType() == "SObjectWidget")
{
SObjectWidget* objectWidget = static_cast<SObjectWidget*>(widget.Get());
UUSerWidget* userWidget = objectWidget->GetWidgetObject();
}```
your UUSerWidget should always have an SObjectWidget backing it I believe
I have a property customization that's basically a header with a SExpandableArea (containing whatever) and I'm using it to render the value in a UPROPERTY(meta=(ForceInLine)) TMap.
It works fine except sometimes the outer containers doesn't know it should render a scroll bar.
What is the best way of having it notify/invalidate an unknown ancestor OnAreaExpansionChanged (or is there a better approach)?
@warm vault π
I'm trying to create a plugin with C++ that pops up a window with some basic slate UI components such as text boxes, drop down lists and buttons. Any particular slate tutorial I can refer to that covers all the basics?
Slate... tutorial?! Are you mad?!
Sorry, Slate is notoriously bad at documentation. I don't know a tutorial off hand!
Take a plugin that does it and look at the source.
Haha yeah, couldn't find anything myself which is why I asked here
This should work, time to scour the market
I suggest the Linter plugin as a good free example of a plugin with a pop up window.
Thanks! Iβll check it out
I got it, gonna check the source out π¬
Thank you! This worked π
If you use qt I wrote this qt to slate guide a while back
https://minimaleffort.tech/qt-to-slate-transition-guide/
I'm new myself too but there isn't a lot out there
Awesome, I got a lot of insight from the linter plugin but this should help too! Thank you
That's really good!
Hey all. Im trying to figure out how slate works with the garbage collection system these days. Any insight?
I see. That makes sense. If I have a UProperty for a UObject inside a slate widget that should be garbage collected though right?
slate can't have UPROPERTY
Hey guys, how would I either, draw slate over the UMG, so that I can draw my dynamic crosshair over the widget or Create some sort of slate object in UMG
It can have a UPROPERTY, but the UPROPERTY will just not do anything.
All of UMG is Slate
UMG objects are just a Blueprint layer over Slate objects for GC support, UPROPERTY, content linking
If you need slate to keep a UObject around that would otherwise be garbage collected, you can make your widget inherit from FGCObject and override the "AddReferencingCollector" (or similar, don't recall) function and keep it around that way. This should generally only be done if you know what you are doing however.
Hola π
I'm pretty sure I had this figured out a year ago or two, but I can't find the code and now I cannot for the life of me get a widget redraw to work. I spawn an editorwindow OnSpawnPluginTab and add a custom widget. The custom widget has some buttons that calls a childprocess. Upon exit of the childprocess I change the state of the widget.
So far so good, but now I would like to draw the updated state (layout and values) within the editorwindow. Is there any way to flag the widget dirty, force the editor to redraw etc?
Cheers, Daniel
Is this for a custom painted component?
You can trigger Invalidate when you need to clear the cache, if it's for existing components then just setting the data should do the trick (not always but I don't have much context)
https://docs.unrealengine.com/4.27/en-US/API/Runtime/SlateCore/Widgets/SWidget/Invalidate/
Invalidates the widget from the view of a layout caching widget that may own this widget.
Thanks for the pointer π I believe I got it working π
To double check my workings (as I'm new to UE4) is the following considered a decent approach?
- Create
SMyWidgetinheriting fromSCompoundWidget - Build widget
ChildSlotinConstructmethod with some buttons and bind to class methods - methods access and rebuild
ChildSlot - call
Invalidate()
Is this the way to go? I was expecting a virtual method along the lines of "OnStructureLayout", but directly editing the childslot seems to work for me so far.
Seems about right.
Is there any specific reason you need to completely rebuild the childslot?
I am launching a childprocess and pushing/receiving data to that process through stdin and stdout. Every stdout is a complete state, formatted as json. The widget should reflect the state of the childprocess. Hence, I don't want to be too clever with caching any "frontend" and just rebuild the widget whenever I receive data π
Fair
Still looking for help if anybody has some clues....
#slate message
It seems the issue happens with any property customization that can change size (header row or child row) if it's used in a map (with or without meta=(ForceInLine)).
What is happening is when the SExpandableArea (or whatever size changing element) in the customization changes size, the parent SDetailsView won't properly calculate the scrollbar.
There's even more weirdness going on with scroll just having items expanded. And sometimes cannot make it through the full map. Here's some gifs and an example!
Hopefully it peaks somebody's interest cause I'm stumped π
To get a dropdown list like below using slate, should I use listview?
SComboBox
Hello folks!
I have a weird issue hehe
we implemented a loading screen with a umg widget , using the video module. It's a basic widget that has a simple throbber. The throbbers all work... excepting on the 1st loading screen (the one where the engine loads I guess?)
/UE_LOG(LogTemp, Warning, TEXT("OnPreLoadMap: %s"), *mapName);
bIsLoadingLevel = true;
if (!IsRunningDedicatedServer())
{
FLoadingScreenAttributes LoadingScreen;
LoadingScreen.bAutoCompleteWhenLoadingCompletes = false;
LoadingScreen.PlaybackType = EMoviePlaybackType::MT_LoadingLoop;
LoadingScreen.bMoviesAreSkippable = false;
LoadingScreen.bAllowEngineTick = true;
UUserWidget*loadingWidget;
if(bStartupVideoShown)
{
loadingWidget = CreateWidget<UUserWidget, UGameInstance>(this, LoadingWidgets[FMath::RandRange(0,6)]);
}
else
{
loadingWidget = CreateWidget<UUserWidget, UGameInstance>(this, LoadingWidgets[7]);
bStartupVideoShown = true;
}
if (loadingWidget!=nullptr)
{
//LoadingScreen.WidgetLoadingScreen = FLoadingScreenAttributes::NewTestLoadingScreenWidget();
LoadingScreen.WidgetLoadingScreen = loadingWidget->TakeWidget( );
GetMoviePlayer()->SetupLoadingScreen(LoadingScreen);
}
}
is there a particular reason why the first loading doesn't animate the throbber and all other widgets do?
Did you mean if (!bStartupVideoShown) ?
So In CoreStyle.cpp there is this.
Style->Set( "ToolBar.Button", FButtonStyle(Button)
.SetNormal ( FSlateNoResource() )
.SetPressed( BOX_BRUSH( "Common/RoundedSelection_16x", 4.0f/16.0f, SelectionColor_Pressed ) )
.SetHovered( BOX_BRUSH( "Common/RoundedSelection_16x", 4.0f/16.0f, SelectionColor ))
.SetNormalForeground(FSlateColor::UseForeground())
.SetPressedForeground(FSlateColor::UseForeground())
.SetHoveredForeground(FSlateColor::UseForeground())
.SetDisabledForeground(FSlateColor::UseForeground())
);
I am trying to use this style but it's not working. I just want the style of button that toolbars use
const auto Widget = SNew(SButton)
.ButtonStyle(&FCoreStyle::Get().GetWidgetStyle<FButtonStyle>("ToolBar.Button"))
//.TextStyle( FEditorStyle::Get(), "FlatButton.DefaultTextStyle")
//.OnPressed( &FluidNarratorLocalizationEditor::HandelToolbarNamespaceComboBoxAdd)
[
...
...
...
]
Its just a white background
I tried AppStyle as well. I will look into Starship
That'd be the FSlateNoResource() I imagine.
Ok
Okay, I understand that when creating a slate combobox, it takes an argument for type data. I want to use the combo box to display some names that I have inside a TArray, what would my ComboBox declaration look like then?
Should I use FAssetData since the TArray type is also FAssetData?
So my ComboBox declaration would look like SNew(SComboBox<TSharedPtr<FAssetData>>)
Okay tried the combobox, my popup window remains empty, at first I thought maybe the combobox wasn't populated so I just put a piece of text, that didn't work either
Nothing in Unreal Engine has ever pissed me off before
Slate : So I took that personally
Lol
If I'd used them before. :(
Have you tried looking at how the engine uses them?
Or a plug in?
I got you
.h
TSharedRef<SWidget> HandelNamespaceComboBoxMakeWidget(TSharedPtr<FString> InOption) const;
void HandelNamespaceComboBoxSelectionChanged(TSharedPtr<FString> SelectedValue, ESelectInfo::Type);
FText HandelNamespaceComboBoxCurrentItemLabel() const;
TSharedPtr<SComboBox<TSharedPtr<FString>>> NamespaceComboBox;
TArray<TSharedPtr<FString>> NamespaceComboBoxOptions;
TSharedPtr<FString> NamespaceComboBoxOptionSelected;
.cpp
SAssignNew(NamespaceComboBox,SComboBox<TSharedPtr<FString>>)
.OptionsSource(&NamespaceComboBoxOptions)
.OnSelectionChanged(this, &SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxSelectionChanged)
.OnGenerateWidget(this, &SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxMakeWidget)
.InitiallySelectedItem(NamespaceComboBoxOptionSelected)
[
SNew(STextBlock)
.Text(this, &SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxCurrentItemLabel)
]
TSharedRef<SWidget> SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxMakeWidget(TSharedPtr<FString> InOption) const
{
return SNew(STextBlock).Text(FText::FromString(*InOption));
}
void SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxSelectionChanged(TSharedPtr<FString> SelectedValue, ESelectInfo::Type)
{
NamespaceComboBoxOptionSelected = SelectedValue;
HandelRows();
}
FText SFluidNarratorLocalizationTextsSlateWidget::HandelNamespaceComboBoxCurrentItemLabel() const
{
if (NamespaceComboBoxOptionSelected.IsValid())
{
return FText::FromString(*NamespaceComboBoxOptionSelected);
}
return FText::FromString("NULL");
}
Yes because the data is shared between NamespaceComboBox (List), NamespaceComboBoxOptions (What you add and remove to add elements), and Selected
To fill combo box you use the options variable
Here is example from my code
//Add Namespaces
NamespaceComboBoxOptions.Empty();
for (int i = 0; i < LocalizationAsset->Namespaces.Num(); i++)
NamespaceComboBoxOptions.Add((MakeShareable(new FString (LocalizationAsset->Namespaces[i].ToString()))));
//Set Selected
NamespaceComboBoxOptionSelected = NamespaceComboBoxOptions[0];
Examples I saw used FString. FString is less memory also.
But you're converting to ftext anyway!
If he wants to use FText than he should be able to.
I'm not quite sure you need to worry about memory for a combo box. That's a little overoptimisation!
Where?
I save namespace data in asset as FName for better memory and performance.
Oh it's an fname, nvm then!
Yha, this is for my dialogue system and this is part of my localization editor.
Ah. You're the one that did the custom localisation stuff?
Yes
It still seems weird to me that you're storing text as an fname, instead of just a key.
Maybe you're selecting a key there...
I even got google translate working with it to auto translate text
It's 2am. I'm going to sleep!
Sure
I am
goodnight
Ahhhhhh okay! Once I solve this problem with nothing appearing in my window then I can use the example youβve given. Thanks! God bless me with some luck to do this
Hey guys.. Just trying to learn more about PollGameDeviceState
right now I'm doing a VR project and i'm spending about 24ms on FEngineLoop_Tick_PollGameDeviceState
when I use the CPU profiler.. that's in a packaged build too.. so no editor stuff getting in the way
we're in UE4.27
Gotta give credit where it's due, this guide is magnificent
Not only have you explained Qt and Slate but the surrounding classes as well which will give a hella lot of insight to a complete newbie
@shrewd finch it may be that it's blocking somewhere?
yea not sure... I did more reading on PollGameDeviceState and I guess it stalls if you aren't making your device's target frame rate.. so that the input can catch the next frame or something
so like.. if you don't make 80 fps.. it drops to 40
and that's where it clogs
that's what I saw someone saying on Reddit or something.. it was all a haze last night when I was searchign lol
thanks though @grave hatch
Okay when you make changes to a slate component in visual studio, what exactly should you do to make those changes reflect within unreal engine?
I made the mistake of rebuilding which took eons
Why I'm asking is because I made some changes but I'm still seeing what was there before
It's cool, all I had to do was recompile, totally forgot that! π
I have a TArray containing Asset Data but this same TArray is required as the options list in the SComboBox but I get an issue here because I'm using TArray<FAssetData> instead of TArray<TSharedPtr<FAssetData>>
Yup, need to make them into a shared pointer
On the other hand, the GetAssetsByClass() method from the Assets Registry requires a TArray if I'm not mistaken which is why I cannot include TSharedPtr
Need to keep two separate arrays and convert
Ah dammit, I knew I'd have to do this. How do I do that? π
For loop, MakeShared
Okay I'm not exactly sure what that is but I shall check it out now
Hey! Is there any way to extend this name area to add a button? Ty
Have you looked at the property editor module and IDetailView ?
What is the order for padding in slate? Top, left, right, bottom?
The margin is Left, top, right, bottom.
Check the FMargin constructor
You can also do just 1 number for uniform padding or 2 numbers for different horitzonal and vertical padding
Great, that's perfect! Thank you
Yep but didn't get too much... The only thing that I managed to achieve was overriding it (losing the original widget) but for all the classes, not just the one I want
So you can place something there for a generic details panel, but not on a per-selection basis?
Yes, just for one class
If you want to place something on the details panel for a specific class, you can add class-specific details customisations and just add something right at hte top (or even to the transform section) of the panel.
By at the top, I mean the details property tree!
By creating a new category row you mean?
New row, or editing existing rows.
You can get a row by name.
My question is actually really similar. What I'm trying to do is customize how a class is displayed, when used as an instance.
So right now I have it customizing when the asset is being edited, but instead I want to customize when it's inside of Instanced UPROPERTY field.
There seems to be only these three
I figured out how to do it on a per-asset bases, but that's not great :/
DetailBuilder.GetDetailsView() has this but idk if any of this is what you need
You could use a custom property layout.
But that would be specific to a property on a class
I'm just trying to fix an engine bug xD
What's the bug?
One sec, will find link
Hi! I want to hide non-editable variables (which were created in the blueprint) in the instance of the payload object in the details panel in the class where I selected that object. The solution with hiding the category is not quite suitable, since after that it is impossible to get the variable in the blueprints. Payload class has specifiers:...
Here is what I have:
// This is customizing ClassA, which I know contains ClassB
for (const ClassB* classB: ClassA->ClassBArray)
{
for (TFieldIterator<FProperty> propIt(classB->GetClass()); propIt; ++propIt)
{
const FProperty* property = *propIt;
const FName propertyName = property->GetFName();
const TSharedPtr<IPropertyHandle> propertyHandle = detailBuilder.GetProperty(propertyName, property->GetOwnerClass());
// Might change this flag later
if (property->HasAnyPropertyFlags(CPF_AdvancedDisplay))
{
detailBuilder.HideProperty(propertyHandle); //hope it works :)
// propertyHandle->MarkHiddenByCustomization(); //didn't work
}
}
}
Neither work to hide the prop :/
I get the correct name though
@grave hatch Any thoughts on why I can get the handle, but not hide it?
detailBuilder.HideCategory doesn't work either.
Are you sure it's actually executing?
Say I want to make a button green in colour, what is zee property I gotta use?
Both OnClicked and OnClicked_Raw give me the error "no instance of overloaded function matches the argument list"
But I used the right code according to an example I saw
I got a function named TestMap in the module FTestPluginModule
My OnClicked function is as follows
Paste function signature and your line of code binding it.
.OnClicked(this, &FTestPlugin::TestMap)
Is "this" an FTestPlugin ?
Yes
And the function signature?
void FTestPlugin::TestMap()
The return type should be FReply
Welcome to Slate.
Oh it has been HELL
Once you get used to it, it's pretty neat.
There's one man, he has a large beard, who is used to Slate. The creator.
I'm starting to get the hang of it little by little and honestly I don't mind it
That Qt to Slate guide has been really helpful too
Your solution worked by the way, thanks. Any reason why FReply is a necessity in this occassion?
Urgh, reminds me, I need to extend SButton to allow long clicks
Because it determines whether the mouse click was handled or not.
If it isn't handled, I assume it's passed up the chain to the next widget.
You also use FReply to start drag operations.
Okay, now I understand a little bit more
Using FReply and .OnClicked gives me an error when recompiling but using .OnClicked_Raw is alright
You know how we get a small message at the bottom right stating that shaders are compiling with a loading sign? Is it possible to create a loading sign like that for my plugin too? Until whichever function has completed?
Yes. How you specifically do it, though, not sure.
Plus you'd probably have to implement an asynctask or threading with progress features!
Is there a way to make a subclass of, say, SButton inherit from SButton's FArgs? The standard macros don't seem to allow it.
Implemented it, but it's a little shitty!
If it works, it works xD
I have to go by a higher standard than that, unfortunately. π¦
You can't do that cleanly, sadly.
What I did was add an argument with the type SButton::FArguments
Then passed then to the button construct
Aye, I did this recently as well after asking internally if there was some way to make it work properly
It starts looking funky if you have content slots as well in the base args, but that's the best way currently possible I believe
The alternative seemed to be not using the macros... which seemed wrong.
Yeah, that's what I end up having. Looks very weird, but it works.
You can do that, if it's just needed on your own end
The macros only define the fargs struct after all
Yeah.
I just didn't like the idea of it breaking when the macro changed for some reason.
However, the problem lies with the fact that the builder pattern will return the base fargs struct once you start configuring it
Sure
I.e. if you have struct A inheriting from B
And you call SNew(SMyButton).ASomething().BSomething() and you want to add another .ASomethingElse() it won't work since the BSomething will return a B type args that is no longer aware of all the A members
It is not! π but sadly nothing can be done now
How do I get a heading style font size like that?
And also that little horizontal rule they've used?
I tried most of the other slate components but changing font sizes seemed kinda shady to me π¦
Search the code base for FEditorStyle or GetFontStyle, you'll find a million sprinkled around the engine, I can't remember exactly where these font styles are defined - but it's definitely in that module.
Is it possible to create a new custom "Section" here for my categories?
Hi, Do you guys know how I would make a combo box with textures?
Doesn't the combo box widget take a widget construction callback?
Sure, I'll try it out, thanks!
Lemmie check
_
Sorry new to slate
That's also UMG stuff
Combo boxes are (I think) notoriously difficult in slate.
Yeah, I was actually wanting to have it in UMG, I dunno specifically the difference ><
UMG is a wrapper around slate.
The engine is made with Slate
The in-game UI is "UMG", although you can also drop down to slate for that if you want.
(by in-game, I mean that UE4 offers a slate-builder-wrapper called UMG, which people use to make their games HUD/menus/etc)
Yeah I thought something like that
So is this not Slate?
That's the UMG source code
I would drop my question quickly as well, in case anyone has an answer: What is the best way to customize the details view of an instanced UObject?
I have a class MyClass with an instanced TArray of MyChildClass. I want to customize MyChildClass EVERYWHERE that it appears, but I'm also willing to target MyClass directly.
Current approach is customizing MyClass, getting the TArray of MyChildClass, iterating its properties, and then doing stuff w/ them.
The issue is that the details view for MyClass isn't letting me hide properties for MyChildClass, even though I have a handle to them.
I think I need to somehow get a detailBuilder for MyChildClass, but I don't see how to do that from the scope of MyClass.
*customizing MyChildClass is a no-go, since it only customizes the details view of the asset, NOT the instanced view that shows in other classes.
TLDR: I have a valid handle to a property of an instanced UClass, but I can't hide it, because I think I don't have a handle to the correct details view.
I was hoping propertyHandle->MarkHiddenByCustomization(); would work, but no luck π¦
Is SNew slate?
SNew(SComboBox< TSharedPtr<FString> >)
.ComboBoxStyle(&WidgetStyle)
.ItemStyle(&ItemStyle)
.ForegroundColor(ForegroundColor)
.OptionsSource(&Options)
.InitiallySelectedItem(CurrentOptionPtr)
.ContentPadding(ContentPadding)
.MaxListHeight(MaxListHeight)
.HasDownArrow(HasDownArrow)
.EnableGamepadNavigationMode(EnableGamepadNavigationMode)
.OnGenerateWidget(BIND_UOBJECT_DELEGATE(SComboBox< TSharedPtr<FString> >::FOnGenerateWidget, HandleGenerateWidget))
.OnSelectionChanged(BIND_UOBJECT_DELEGATE(SComboBox< TSharedPtr<FString> >::FOnSelectionChanged, HandleSelectionChanged))
.OnComboBoxOpening(BIND_UOBJECT_DELEGATE(FOnComboBoxOpening, HandleOpening))
.IsFocusable(bIsFocusable)
[
SAssignNew(ComboBoxContent, SBox)
];```
So how would I modify this for textures
You should get comfortable with the Widget Reflector.
Oftentimes you can find something similar in the engine, and therefor find some code example of something you want to do.
From what I recall though, most texture selection widgets are not done with dropdown, but rather some other asset selector, which isn't easily broken down into its components.
PropertyModule.FindOrCreateSection
Modify HandleGenerateWidget to return a SImage, replace FString* by some texture handle
Yup! Thank you very much!
@quaint zealot not really sure how to use makeshared and convert tarray<fassetdata> into tarray<tsharedptr<fassetdata>> like you suggested
Tried looking around for an example code but didn't find anything
You can't convert shit, have to create a new array and add pointer-ized entries to it
Okay, which is why I have 2 arrays already, just not sure how to pass the contents of one into the other π¦
for loop, Add()
They don't have the same type, one stores instances and one shared pointers
That's why you have to copy everything element by element
Got you, thanks!
So I used a for each loop to iterate through the TArray if it isn't null, but the Add() function keeps throwing this error about argument lists not matching π₯Ί
Read the compiler output to understand why they don't
I'm trying to add text to a textbox with .Text(TEXT("")) but when I do that I get an error saying 'FText::FText': cannot access private member declared in class 'FText'
but if I do LOCTEXT it works fine
Yes, that's normal, TEXT() is just for regular C strings
Use LOCTEXT, or add FText::FromString around TEXT
but in the documentation TEXT("") works? https://docs.unrealengine.com/4.27/en-US/ProgrammingAndScripting/Slate/Widgets/
if you scroll down to List Views
Gonna guess that this page hasn't been updated since 2013
It's purely engine internal so there's no documenting that
Study the editor UI to make your own editor UI, essentially
Yeah, that's what i'm doing but as a noobie its a lot easier when their are resources showing you the basics. Saves so much time and confusion
The docs do help
Also I haven't tried getting the engine source code yet so I can't look at the files shown in the Widget Reflector
Obviously a me problem. Ill figure that out soon lol
Yeah learning Slate is really just reading the editor code
Source code here we come
Somebody posted a good qt to slate guide which covered the basics, even if you're not familiar with qt
Do you have a link? I checked the pins but theirs only one comment
thanks sm!
My Bible
nvm
I'm not understanding why the size of a child component will effect the size of other child components when the alignment isn't set to fill or center. It should just effect its own box right??
Its like the child component size is effecting the parent box size which is moving each child component farther to the right. Which means the child components content doesn't effect its own size, only the size of its parent. Which makes no sense because why would the default functionality be that each child component has a uniform length / percentage of its owners space and how could you change it to fit the content
Some are top-down, some are bottom-up. It's annoying at times.
Yeah I had a big hierarchy and it was really confusing me. It wasn't smart as a noob slate user to create a bunch of sections and then try to align / fix them lol. I figured it out now though. Finally.
Good!
I'm an idiot
Oh? What did you do?
It took me 2 hours to figure out I needed to put AutoWidth() on every slot to stop sections from clipping each other and have my desired spacing. Just frustrating. Yes I learned a lot about how slate works with all the different things I tried but Iβm upset at how long it took me to isolate the problem. I made so many stupid mistakes
At least you won't make them in the future!
until tomorrow
cough lol
I donβt think Iβll use that as much because it can look weird if lines arenβt uniform. It does depend on what your trying to do though
I'm currently wondering about a layout issue myself, actaully
I have a grid panel, 3 columns wide. The second 2 columns are of unknown width (sized to content.)
I want to be able to have a mouseover background tint on the row when I mouse over any part of it.
Ah Iβm going to work on something super similar tomorrow. I havenβt gotten to that yet though sorry.
Iβd assume theirs a function for hover and then you can bind a delegate?
I'm sure I could do some sort of "Check size of parent grid, use that" type of thing, but eh.
But thatβs total guesswork
It's the width size that I'm wondering about and the placement in the hierarchy.
Do grid cells even have backgrounds? Or will I have to add something? All that sorta stuff.
Iβm pretty sure you have to add something
Just add a SImage as a child slot for each of the grids
Then on hover access that child and change the color
Yeah, that's the easy part! Making it not change the size of the gird might be more difficult.
If itβs a child slot I think if you set it to FillWidth(1) it will stay in the bounds of its parent
But the child slots are all used by other things.
I don't want the slot at 0,0, for instance, to use the entire row.
I could add something that goes out of the cell bounds to cover the row, but then am I going to hit z-order issues with the contents of the other cells?
(that's probably easy to fix)
So your grid has an item in it that you want to use to change the width right? its contents? But you dont want anything else effecting the grid width besides that one content item?
Moment
I can just bind the width of a color block in column 1 (and use an overlay to put the icon on top of it) to the width of the grid
It seems a little cheap, though.
Have ur grid, set grid to HAlign(HAlign_Fill). Then for each grid slot: Add a SImage child (for background color). Add a SBox child to the SImage. Fill that child with (Icon, or Deskcription, or Keybind)) Set that child to AutoWidth
Yes. Use 3 images!
I haven't used a grid yet so their might be something im not thinking of
I'm trying to add .OnClicked to a button but im getting an error that I can't seem to wrap my head around
SNew(SButton).OnClicked(this, &FTestPluginModule::CreateMinefieldSection)
The errors are a lot of text but they are mostly like this:
'SButton::FArguments::WidgetArgsType &SButton::FArguments::OnClicked<FTestPluginModule>(UserClass ,FReply (__cdecl FTestPluginModule:: )(void))' being compiled
with
[
UserClass=FTestPluginModule
]
'TDelegate<FReply (void),FDefaultDelegateUserPolicy>::CreateSP': no matching overloaded function found
'StaticCastSharedRef': no matching overloaded function found
Once I completely separated plugin and slate functionality this got so easy lmao. I didn't know that was allowed.
Hey people, I was trying to implement GameplayTag to my slate which I use for my struct. I couldn't find an easy way to display GameplayTag as it is, so I had to copy everything in GameplayTagCustomization.h / .cpp and that way I get the same look.
Is this the only solution? Is there a way to let the slate display default slate look? Or I need to create every functionality if I want to have them in my structure?
Need some more context to answer that really
Where does the tag live? Is it a UPROPERTY? Where are you displaying it etc?
Of course, the tag lives in my structure. Here's the structure.
USTRUCT(BlueprintType)
struct BLINDDESCENT_API FBehaviorTreeNodeStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Amount")
FGameplayTag Amount;
}
I created a customization class which is inherited from IPropertyTypeCustomization
I'm basically following a tutorial, I couldn't find a way to display GameplayTag as it is and started copying everthing in GameplayTagCustomization.h and it looks like this now
I'm not sure if this is the only way. The customization is already done so there should be a way to pass all of this and display it in my own structure.
Yeah you don't need to do that, you can just create the default property widget for that property
Sounds great, thanks! How can I do that? I've been searching the Discord and the internet for hours now. π
Get the property handle, then call 'CreatePropertyValueWidget' or 'CreatePropertyTitleWidget'
I do something similar in a detail customisation I have to force struct values to display in non-expandable row
You can do that in either CustomizeHeader or CustomizeChildren
Thanks, I'm trying it right now
Snippet if it helps:
{
// Gather Children
uint32 NumChildren = 0;
StructPropertyHandle->GetNumChildren(NumChildren);
ChildHandles.Reset(NumChildren);
for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ChildIndex++)
{
ChildHandles.Add(StructPropertyHandle->GetChildHandle(ChildIndex).ToSharedRef());
}
for (uint32 ChildIndex = 0; ChildIndex < NumChildren; ChildIndex++)
{
ValueGrid->AddSlot(Column, Row)
.VAlign(VAlign_Top)
.HAlign(HAlign_Fill)
[
SNew(SVerticalBox)
+SVerticalBox::Slot().VAlign(VAlign_Top).HAlign(HAlign_Fill)
[
ChildHandle->CreatePropertyValueWidget(true)
]
];
}
};```
Thanks! I didn't want to waste your time so I tried to check everything. But unfortunately it doesn't work. Only one what works is the name variable. Here's what I did;
My structure;
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FGameplayTag MyTag;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FTransform Transform;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName MyName = "MyNameDeneme";
};
Customization
{
const TSharedPtr<IPropertyHandle> GameplayTag = StructPropertyHandle->GetChildHandle(0).ToSharedRef();
const TSharedPtr<IPropertyHandle> Transform = StructPropertyHandle->GetChildHandle(1).ToSharedRef();
const TSharedPtr<IPropertyHandle> Name = StructPropertyHandle->GetChildHandle(2).ToSharedRef();
check(GameplayTag.IsValid() && Transform.IsValid() && Name.IsValid());
StructBuilder.AddCustomRow(LOCTEXT("BehaviorTreeNodeStructRow", "BehaviorTreeNodeStruct"))
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.BorderBackgroundColor(FLinearColor(255.f, 152.f, 0))
.Content()
[
SNew(SWrapBox)
.UseAllottedWidth(true)
+ SWrapBox::Slot()
.Padding(5.f, 0.f)
[
GameplayTag->CreatePropertyValueWidget(true)
]
+ SWrapBox::Slot()
.Padding(5.f, 0.f)
[
Transform->CreatePropertyValueWidget(true)
]
+ SWrapBox::Slot()
.Padding(5.f, 0.f)
[
Name->CreatePropertyValueWidget(true)
]
]
];
}
Wow, didn't think it would be this huge. Anyway this is the result:
Am I missing something?
Hmm that's odd. It should go through the usual channels and find the customisation
You could try getting the customisation instance from the property editor module
Not sure if it's related but I'm doing this in a newly created Engine module. MyGameEngine to be specifically. Can that be related to that?
PropertyModule.FindPropertyTypeLayoutCallback(FName("GameplayTag"));```
Don't think so
But from that, you can get the callback and execute the delegate
But there shouldn't be any reason to, so it's a bit strange
Thanks, I will try this! Hopefully this will work
You may need to step through and debug it otherwise, but AFAIK it should pick up other customisations so not sure why it isn't in this case
Just pass in an empty/default value for the last param of that function
IDK, something like this perhaps. Might give you something to debug with anyway
if (Callback.IsValid())
{
const TSharedRef<class IPropertyTypeCustomization> Customisation = Callback.GetCustomizationInstance();
Customisation->CustomizeHeader(ChildHandle, HeaderRow, StructCustomizationUtils);
}```
Can't help much beyond that I'm afraid
Will this be correct? @quaint zealot
Or should I replace "new FAssetData(Level)" with "&Level" ?
Thanks for sharing, couldn't test it because it's not compiling. I tried to add modules and include couple of things but had no luck
I'm curious about something. I have some semi complex UWidgets. I'm wondering if these are usable in slate? I'm more or less wondering about some basic wrapping for some UserWidgets. I know I can create slate directly in a UserWidget's RebuildWidget, but can I use a UWidget in the same manner?
EG, simplifying things a lot. I know that I can wrap a UserWidget's content in an SBorder. Is it possible to use a UWidget, get it's slate, and wrap the UserWidget's content in the UBorder's SBorder?
Does anyone know any information on generating slate slots based on cpp / procedurally gererating slate slots? ChildSlot[].AttachWidget(TSharedRef<SWidget>(SNew())) will overite the existing widget, which makes no sense to me. I can't add a widget slot with c++ bc adding an extra ChildSlot[]; will just overwrite the previous one. Also I obviously can't have a cpp function that uses slate syntax because that syntax would need to be outside a Childslot[] to work with c++ so it doesn't overwrite the previous ChildSlot[]
If something only has a single slot, you can't add more slots.
Add a child with supports more slots and add things to that.
Hmm. Getting the impression that I can't do what I want. Am probably going to need to recreate my UWidget as an SWidget and just use the SWidget in both cases. :/
Yeah that was what I was thinking. I didn't know enough about UWidgets to comment
Oh I know, im trying to add more slots based on variables. So I can't write that function inside of a ChildSlot
I dont want to manually write the code is what i'm saying
Yeah. I'm kinda learning in reverse. π Know enough to alter and muddle slate, but am used to making UWidget wrappers that extend things rather than actual slate.
Store a reference to the child widget (or just get it from the children array) and do ->AddSlot(...) on it.
Ooh I didn't know about child widgets, child arrays, or ->AddSlot(). Thanks!
I think most people start with UWidget and then work into slate as they find the need for more functionality tbh. I've heard it makes learning slate easier too
What is the WITH_ACCESSIBILITY by the way? The in engine description for it is kinda vague.
@grave hatch ```
TSharedRef<SMinefieldStartupWidget> MineWidgetSharedRef = SNew(SMinefieldStartupWidget);
MineWidgetSharedRef.AddSlot
Btw, mugs, are you doing ChildSlot[].AttachWidget everywhere?!
Can you give me an example? Or resources about this subject? I didn't see anything about it in the documentation
Normally it'd be ChildSlot[ SNew(something) ]
You can only add slots to container that support adding new slots.
So it would be ChildSlot[SNew()].AddSlot()?
If something has ChildSlot, it doesn't support multiple slots.
You need to put something in that child slot that supports multiple slots.
Like a vertical box or constraint canvas
TSharedPtr<SVerticalBox> MyVerticalBox; in your header. Then SAssignNew(MyVerticalBox, SVerticalBox); and MyContainer->AddSlot()[ MyVerticalBox ]; Then you can add slots to it with MyVerticalBox += SVerticalBox::Slot() [ some widget here ]; or MyVerticalBox->AddSlot()[ some widget here ];
//Ok I know I can do
ChildSlot
[
SNew(SVerticalBox)
+SVerticalBox::Slot()
[
]
]
//but I want to do
for(int i = 0; i <= 10; i++)
{
+SVerticalBox::Slot()
}
Does that make sense?
Wait let me read what you said lol
Yes but id still have to write VerticalBox manually which won't work with data that changes
Or combine it up with ChildSlot[ SAssignNew( MyVerticalBox, SVerticalBox ) ];
Yeah let me read what you said about SAssignNew
That's why you empty the vertical box (remove all teh slots) when your data changes
I havent processed it yet
Oohh I think I get it
Does MyContainer have to be a special widget type? I don't see .AddSlot() in a normal SCompound widget.
Because SCompoundWidget isn't a multi-slot container.
I thought as much. Thanks so much for the help!
Took me a bit to get what you meant when you said that earlier my b
I am having some trouble with some nesting. Trying to follow source code. But not having a lot of luck with it. Just trying to do something super simple by nesting a Border inside of a blur, and set the content inside of the border.
MyBlur = SNew(SBackgroundBlur)
.Content()
[
MyBorder = SNew(SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.Content()
[
InArgs._Content.Widget
]
];```
SCompoundWidget inheritor's Construct function.
This works with only the border, or only the blur. Unsure of why it isn't working with both?
What's the question here?
If you're trying to add 2 widgets to a compound widget, it won't work. Try adding an intermediary SOverlay or something
I'm trying to add a blur to a compound widget, and add a border inside of the blur. And add the content inside of the border.
Add an overlay widget with 3 slots, blur, border, content
Unless you want the blur on top of the contents, then add it last?
But why? Blur has a slot. Border has a slot. Why does this require an overlay?
This is perfectly doable
The syntax with MyBorder here is the only weird thing
I'vs only ever seen SAssignNew
Do you have any particular issue other than code ?
Good point.
Have you used the widget reflector to check the size of the widgets?
What is the issue ?
I think I derped that. Creating the border first with the content, then the blur with the border works.
I was getting confused with Mugs problem |:
.Content()
[
InArgs._Content.Widget
];
MyBlur = SNew(SBackgroundBlur)
.Content()
[
MyBorder.Get()->AsShared()
];
ChildSlot
[
MyBlur.ToSharedRef()
];```
Ended up at that. Still getting used to using shared refs and pointers.
That seems... like it should work with nesting.
The main difference I can see is that you've removed your alignment properties.
SAssignNew(MyBlur, SBackgroundBlur)
[
SAssignNew(MyBorder, SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
InArgs._Content.Widget
]
];```
Oh. That works. π Thank you. Forgot about that creation macro.
hey guys idk if you can help me but im trying to make a loading screen for a multiplayer game. I need to do it for the non-seamless travel part when a client connects to a server. I've made a slate and added it to viewport, and when I do a client travel the slate does persist across levels, however it disappears for a few frames right as the client loads into the server then reappears.
I highly recommend you check out the MoviePlayer implementation for this. Technically it doesn't even require slate. Epic's ActionRPG has a good implementation for it. It works on any hard loaded map very nicely.
I have a combo box, I have a function as well. I want the function to be called each time the selection is changed (using OnSelectionChanged). Letβs say I want to pass the option that is currently chosen in the combo box into the function that Iβm callingβ¦.how in UE4βs name do I do that π₯Ή
I'm not sure how that particular delegate works, but you could, in your first function, set up the call to a second function, passing the select element as a parameter.
How you get the selected element, however... Shrug
you can extend or create a custom comboBox that have a custom delegate with the info you need to pass. Then when combo box changes, you bind it to a Lambda function that captures it and it calls the custom delegate plus the data
i did something like that with a checkbox. I needed to pass data to know what the checkbox was for. The oiginal callback just says if the checkbox changes, so i overloaded teh callback with a lambda that calls both, the "Normal" callback and my custom callback
examples in engine of how they use lambda and combo box to send extra data on change
Great, I shall try it this way
Thank you
So I understand I can save a slate variable by using AssignNew(). But how can I call that variable again with changes ive made to it?
//for example
SAssignNew(SavedVariableWidget, SWidgetType)
SavedVariabled->Slots->AddSlot(SNew(EditableTextBox))
//How can I post this new Saved variabled widget to the screen?
If I try to AssignNew() the same variable again, it just overwrites it and everything I modified it with disappears
SAssignNew creates a new widget and assigns that pointer property, so that makes sense.
The only way I know how to add widgets to a childslot is with SNew() and SAssignNew() but I dont want a new one
That's the correct way to do it, you can't have the same widget instance displaying multiple times
Well how can I dynamically edit a widget and then post it
if it has to be new everytime that means its impossible to add or use variables
You just modify the existing instance like you would any other variable/instance
FReply SMinefieldGridWidget::CreateMinefieldBaseGrid()
{
if (OwningWidget != nullptr && OwningWidget->MinefieldHeight && OwningWidget->MinefieldWidth)
{
for (int i = 0; i <= OwningWidget->MinefieldHeight; i++)
{
for (int j = 0; j <= OwningWidget->MinefieldWidth; i++)
{
GridPanelContainer->AddSlot(i, j).AttachWidget(SNew(SButton).ContentPadding(3.f));
}
}
}
return FReply::Handled();
}
I tried this but this doesnt show up at all
Okay first of all, why are you making a game-level UI in slate - use UMG
void SMinefieldGridWidget::Construct(const FArguments& InArgs)
{
OwningWidget = InArgs._OwningWidget;
ChildSlot
[
SAssignNew(GridPanelContainer, SGridPanel)
+SGridPanel::Slot(0,0)
[
SNew(SEditableTextBox)
]
];
CreateMinefieldBaseGrid();
}
Slate is for editor/tooling stuff only - or for very rare cases when you can't do what you need with the existing UMG wrapper widgets
this isn't game level UI
its editor level UI
im making a plugin
specifically a tool
What you've done there should work just fine
thats what I thought.. hmmm
let me think some more
thnx for the validation
Ah obviously my OwningWidget is coming back as a nullptr facepalm
Why are you using AttachWidget instead of the [ ] notation?!
Because I need to do it dynamically
[] doesn't allow for that because its outside c++
[
...
]```
No you don't.
why wouldnt you?
its not inside another widget
But you're using ; anyway
you cant do dynamic allocation inside another widget
[
SNew(SButton).ContentPadding(3.f)
];``` It is identical to this
oh wut
GridPanelContainer->AddSlot(i, j).AttachWidget(SNew(SButton).ContentPadding(3.f));
Same!
To be honest, I have no idea what attachwidget does internally, but it's not how you're meant to do it, I'm sure...
let me try that out
omg thats so much better lmao
okay ill use that then thanks
I thought the [] was only for inside ChildSlot[];
Nope!
//The only function this widget class server is passing in the StartupWidget reference
ChildSlot
[
//I'm getting a nullptr for MinefieldStartupContainer
SAssignNew(MinefieldStartupContainer, SMinefieldStartupWidget).SelfReference(MinefieldStartupContainer)
];
//this says the class is incomplete and thus can't have a pointer
MinefieldStartupContainer->SelfReference(MinefieldStartupContainer);
ChildSlot
[
//This won't convert because its not a UObject
SAssignNew(MinefieldStartupContainer, SMinefieldStartupWidget).SelfReference(this)
];
//--------------
ChildSlot
[
SAssignNew(GridPanelContainer, SGridPanel)
];
// this works fine
GridPanelContainer->AddSlot(0,0)
I've tried everything. How can I get a reference to the owning widget???
It won't work for custom classes
I can't use this to pass it in
What are you trying to pass to MinefieldStartupContainer?
A reference to its parent widget?
I'm trying to pass itself
so it has a reference to itself
its going to pass that reference again to another widget it calls
So you want your MinefieldStartupContainer to have a reference to its parent?
Basically yes
Okay, and what are your slate parameters for SMinefieldStartupContainer?
SLATE_ARGUMENT(TSharedPtr<SMinefieldStartupWidget>, OwningWidget)
Try passing SharedThis(this)
SharedThis?
omg
Hold on while trying to explain my problem I messed something up
gotta fix it real quick before i test
Btw, try not to use TSharedPtr to refer to your parent, you'll end up with objectings keeping each other alive.
Use TWeakPtr in the child class
FReply SMinefieldGridWidget::CreateMinefieldBaseGrid()
{
if (OwningWidget != nullptr && OwningWidget->MinefieldHeight && OwningWidget->MinefieldWidth)
{
for (int i = 0; i <= OwningWidget->MinefieldHeight; i++)
{
for (int j = 0; j <= OwningWidget->MinefieldWidth; i++)
{
//GridPanelContainer->AddSlot(i, j).AttachWidget(SNew(SButton).ContentPadding(3.f));
GridPanelContainer->AddSlot(i, j)
[
SNew(SButton).ContentPadding(3.f)
];
}
}
}
return FReply::Handled();
}
Yeah I was just about to say that this is causing unreal to crash
but it is working!
Its coming through
so let me try changing it to weak ptr
im not used to working with the heap so this whole smart pointer thing is a little confusing to me
even though I understand the concepts
I had no idea this was a thing tysm oml
I spent so long trying to get the reference to pass through lol
Instead of spending 3 hours on it. Spend 10m. Do some googling and then ask!
what would I google though? Information on slate is like non existant
I didn't know what the problem was I just knew that it wasnt converting properly
Try googling the error message!
oh true haha
Just take out your class name and put in SImage or SButton or something
yeah I shouldn't have assumed I wouldn't be able to find anything. Always good to try. Good point
my b
Also i'm really trying not to just ask until i've really tried everything I could think of. Tbh I learned a lot trying to solve this problem
Can I get a Slot that an SWidget is in? I have a TSharedPtr, need to get the SOverlay slot that contains it.
Iβm not exactly sure on exactly what you mean but to access an SWidget you need to save it as a variable then you can get its slot and replace it or do whatever else
If you have a reference to the overlay, you can do Overlay->GetChildren()->GetSlotFor(x) I think. Something along those lines.
Or do GetParentWidget()->GetChildren() etc
FChildren's slot references are protected. I can't access that in a UserWidget.
Hmm. Can call remove slot on the overlay with the widget pointer, and then add a new slot with the widget in it. Feels bad to do that just to set VAlign for the slot though. :/
How do I set it through the pointer? That was my original question. I need the slot object that the widget is in to set that.
Basically I have a border inside of an overlay. Runtime code needs to dictate it's VAlign, whether it's on top or bottom of the widget. I can't get the overlay slot that the border is in to do this.
I know how to do this with grids because you can just get the grid at a specific slot using its column and row numbers
but i'm not sure with other widgets
I'm trying with vertical box but I don't see a Slot array
//if you do this it shows
ChildSlot
[
SAssignNew(VerticalBoxContainer, SVerticalBox).Slots
];
//Doesn't show here
VerticalBoxContainer->(No Slots Array)
I'm not sure why this is
Verticalbox should function the same as overlay
in terms of getting the slot
oh to answer your question. To set it through a pointer you do AssignNew. Then OverlayContainer->AddSlot
which is what we said in our first answer
but yeah if you cant find the slots array youd have to overwrite it everytime
with a new slot
Yeah, I figured that part out. Feels odd replacing the slot though. :/
Still faster than umg π€·ββοΈ
You can iterate through them with GetSlotAt(index)
Starts at 0, but yeah.
oh cool
I'm still confused as to how to do this. I'm working in a UserWidget. GetChildAt is a protected function in FChildren.
The class structure is the same, UserWidgets should just be a wrapper
I dont see why it would be different
GetChildAt isn't protected in 4.27 at least.
In FChildren in 4.27.2 it is.
in 5.0 it's public
just post the code your writing
In 5.0 GetSlotAt is public too
Oh. Sorry I said wrong. GetSlotAt is protected.
It is.
GetChildAt doesn't help, it just circles me back around to having a pointer to the child I had when I started. I still can't affect the slot with it.
You could access it with some pointer hackery π¦
where are you finding GetSlotAt? I can't find that function
Oh it must not be showing bc its protected
GetChildAt() returns an SWidget. Your saying that SWidget isnt the slot itself ?
No, that's the SWidget in the slot.
What you can do, and tihs is total hackery, is create a class called FChildrenSubClass, inherit from FChildren, add a method that returns GetSlotAt() and then cast FChildren to that (even though it isn't an FChildrenSubClass) and then call your method.
May look into that. You said that was public in 5.0 though?
Something like this: ```class FChildrenSub : public FChildren
{
public:
const FSlotBase& GetSlotAtPublic(int32 ChildIndex) const
{
return GetSlotAt(ChildIndex);
}
};
FSlotBase& MySlot = static_cast<FChildrenSub*>(Blah->GetChildren())->GetSlotAtPublic(Index);
I dont think that would work though, because the returned class is still a FChildren?
Doesn't matter.
You're casting it to a different class, even though it's an FChildren object.
woah
Virtual function pointers will do the rest for you.
my mind is being blown rn
It's super hacky, though. And probably bordering on undefined behaviour.
Yeah. Started messing around with rewriting some major game widgets into actual slate this weekend. Been loving it. But the random private/protected walls are getting old, fast. Pretty on par with creating a new UWidget to slightly alter behavior and having to copy three entire classes just to do it.
Be careful about switching from UMG to slate for game UI. Jambax said that slate is really only for editor UI stuff or if you really need some of that extra functionality
UMG is basically just a wrapper for Slate, but it also makes it much more convenient to work with
It's totally feasible to use Slate for game UI but in most cases it's when you need to do something "special" or because some part of the UMG API is stupid
Slate isn't "just" for editor UI. Slate is great (ish.) You can use it for your game if you want. It's just easier to make UI in UMG mostly.
Okay yeah that makes sense
Slate is also a lot faster in some cases even with same implementations. I've cut this one widget's tick and paint time down by half in most frames. I wouldn't bother with this under normal circumstances.
Oh absolutely. BP and UMG are atrocious for performance π
I wouldn't say atrocious at all. Blueprints being "bad for performance" is over exaggerated and really only an issue when you call more complex functions
If you say so.
Here's a very good deep dive into it
It's not an either/or decision. Learn what makes C++ and Blueprints different, what they have in common, and how to use them together effectively. We'll also learn a thing or two about performance optimization and some basic software design concepts.
Read the article version: http://awforsythe.com/unreal/blueprints_vs_cpp/
00:00 - Introduction...
the TLDR is people enjoy jumping on the "Blueprints is bad!" train and they're best used in conjunction
GridPanelContainer->AddSlot(i, j)
[
SNew(SButton).ContentPadding(3.f).OnClicked_Lambda([]
(TSharedPtr<SGridPanel> GridPanelContainer, int i, int j)
{
GridPanelContainer->AddSlot(i, j)
[
SNew(SOverlay)
];
return FReply::Handled();
})
];
maybe more of a c++ question but why isn't it allowing me to input parameters into a lambda?
errors: 'Invoke': no matching overloaded function found
Failed to specialize function template
It doesn't look like you passed any inputs into the lambda's capture clause
oh I thought the () was the capture clause
this is my first lambda lol
let me do more research my b
I don't think blueprints are bad. I think they're great... for what they're great at. As you pointed out, complex functionality and harsh limitations are their drawbacks.
and that's true! But to say blueprint performance is "atrocious" just isn't correct
I guess it goes by what you consider "atrocious."
of a very poor quality; extremely bad or unpleasant.
I consider it extremely bad, like the definition
I'm sure they've improved blueprints over the years but I remember seeing a test done about 5 years ago where blueprints where around 5x less efficient than c++
Again, it depends on what you define as "extremely bad."
I can't remember the exact results
they address that in the video I shared above
ohh okay ill check that out then thnx
While I agree with you about this matter in general, this only applies to projects that either don't have a heavy game thread, or have very simple UI. When slate takes up >5ms on your game thread, you have to start cutting all of the corners you can. I just finished rewriting one of our widgets at work into slate. Same identical widget, identical functionality. 230ish micro seconds to 90ish microseconds. Which isn't a ton. 0.14ms. But it adds up. I do that for a couple more of our more complex widgets and I can probably drop a good millisecond off of the game thread on average.
The guy cutting his ui processing time by half by converting some of it to c++ is a good example of "bad." Though I'm not sure if that's his BP coding or BPs themselves.
And bindings are pretty expensive, too.
I just finished rewriting one of our widgets at work into slate. Same identical widget, identical functionality.
Did you move it from UMG/BP to Slate, or UMG/C to Slate?
because we're talking about BP to C++, not UMG to Slate
That's not the fault of blueprints though
It's an intrinsic problem of blueprints.
You could be doing the same binding call in C++ and it would be just as bad. The issue with bindings is they're called every tick
And that BP adds overheads to those bindings.
UMG to Slate. Only blueprint stuff was initial setup that wasn't ran every frame. There was no tick in BP.
The bindings were a poor design choice from Unreal. You can do the same alternatives in blueprints as you can in C++ (ie. making it event based, not every tick)
I just think that logic should be done in C++ and any variable setting / visual things can be done in blueprint
I found it quite funny that just hiding the content browser gave me a 10-20% fps boost in the editor window. I don't wnat to imagine what they'd be like if it were implemented in BP.
Mugs: named slots are good for that.
oh? ill look that up
Like don't get me wrong, I much prefer writing in C++ than Blueprints.
The issue is there's a huge negative stigma around using blueprints, and all you did was lay a blanket statement down that "blueprint performance is atrocious". If you explained that in some cases it is, but most of the time it's fine, I wouldn't of cared.
I know what you were trying to say, and I know you weren't meaning that Blueprints are just bad in general, but we're in a discord server where people read these channels to learn stuff
and they wouldn't know what you meant, which would give them the wrong idea
tbh i'm in the blueprints should be mostly avoided camp. So your definitely right about the sentiment lol. But ill definitely check that video out cade
Well, there are some cases were performance doesn't matter.
BPs are great for that!
Setting up input bindings and stuff is great, I imagine. Doing advanced matrix math and processing arrays, probably not.
Yeah and like I said, I know what you meant when you said that, but you didn't explain that
Blueprints should never be avoided. In fact use them often. They're fantastic and will get you a lot of work done fast. Delegate binding, async stuff, and asset referencing are a ton easier in blueprints.
Yeah input bindings / locomotion / animation montages / exposing variables for in editor testing so you dont have to recompile, Creating blueprint child classes where you can again change variables is such a time saver. UMG where you can visually layout button widgets
all those things i think blueprints are amazing for
also for very quick one time logic
everything else I think c++
yeah asset referencing is amazing
Above is the reason I generally don't create widgets in C++. BIE events in AHUD are much easier to both call from C++ and easier to change out widget usage or disable if plans change.
Yeah I think its when data from c++ has a hard time being accessed from blueprints or vice versa is where some of the real problems happen. Then you have to do stuff like checking for those variables on tick in blueprint to say, update your animation. Ugh.
This is usually how I layout my UI work,
View - UMG
ViewModel - Blueprint
Model - C++
Basically following the MVVM architecture that most software's use, which I think applies to UI in UE4 as well.
The Model contains and handles all of the heavy logic and data, and the ViewModel works with the View to display that information
UMG isn't bad enough for performance that you should punish yourself by writing a game UI in slate though
UMG is just slate with some UObject wrappers after all - if you use it purely for the WYSIWYG editor the actual performance is near enough the same. and your UI will almost certainly look better. If you do your UI logic in BP that's a different story - but that's also easily transferrable to C++.
Plus, once you start working with designers, Slate is just not an option
If it's any consolation, every game I've worked on in UE has been with UMG and there have been some extremely dense/heavy UI's - it was never the bottleneck
Super helpful to know, thank you
GridPanelContainer->AddSlot(CurrentGridSlotInfo->ColumnNumber, CurrentGridSlotInfo->RowNumber)
[
SNew(STextBlock)
.Text(FText::FromString("5"))
];
I'm not understanding why this wont show
GridPanelContainer->AddSlot(CurrentGridSlotInfo->ColumnNumber, CurrentGridSlotInfo->RowNumber)
[
SNew(SImage)
];
but this will??
its just STextBlock that won't show in this slot
Try setting a font?
Ah, I have a grid. I'm spawning a button for every grid slot. Then I call the functions above. For some reason SImage spawns on top of the button, and STextBlock spawns below the button. Both remove hit testable for the button. Which is fine. I found this out by changing the opacity of the button. Is there a way to move SText to the top of the button?
Grid slots have a layer parameter too
Try setting the text to a higher layer?!
...I think
Yes, ty. I'm an idiot. I forgot about that parameter
Idk, I think it was some glitch because all i've done is add and remove .RenderOpacity and now its showing fine
Hot reload?
Ah maybe. I don't think I turned on Live Compile, however im pretty sure ive only been building from the editor.
Oh I meant visual studio. Sorry my brother was talking to me
but its possible I compiled with the editor by accident
bc I didn't turn live compile on
Yeah nvm. I've only been building using the local windows debugger so that shouldn't be it
SNew() won't take SNumericEntryBox as an argument even with its header included. Is this because it inherits from SCompoundWidget? But why can't I used it the same as I can use my custom classes that are made from SCompoundWidget?
I'm assuming ill have to make my own SNumericEntryBox subclass
Show errors.
ok 1 sec
It's likely a circular dependency of some kind if you definitely have the header included
#include "SlateFwd.h"
+ SHorizontalBox::Slot()
.Padding(0)
.HAlign(HAlign_Left)
.AutoWidth()
.MaxWidth(TextInputWidth)
.Padding(HorizontalContentPadding)
[
SNew(SNumericEntryBox)
]
this is all i'm doing though
its all inside a ChildSlot
Error log, not errors window
Why does everyone say this, its always the same lol
1 sec
error C2672: 'MakeTDecl': no matching overloaded function found
error C3206: 'MakeTDecl': invalid template argument for 'WidgetType', missing template argument list on class template 'SNumericEntryBox'
error C2955: 'SNumericEntryBox': use of class template requires template argument list
In the docs in syntax, the difference it has from other widgets is this line on top:
template<typename NumericType>
but im not sure what that means
Got it SNew(NumericEntryBox<int>) worked. Im just not used to working with templates outside of StaticClass and stuff like TArrays<>
How dare you summon me to this barren wasteland insolent fool
I know fuck all about slate itself other than masking border boxes with stencil :P don't think I can help here
srry
I'd take a stab at FGameplayTagContainerCustomization
I'm sure there was a widget that provided a collapseable content type thing, like the details panel
I can't for the life of me remember what it is, though...
SExpandableArea !
heya, how does one do tweening in Unreal Engine 4 C++? (Most importantly, using them with Slate)
Use Tick?
heya, is this the correct way to set up an event handler in slate?
oh oki, ill try to research about how tweens work first and then I might make a simple system
sorry for the super late reply btw
No worries!