#slate
1 messages ยท Page 8 of 1
Whether you actually need the sbox's heightoverride is also questionable (you may still need the width override, I'm not sure if the scrollbox has a max width) - the scrollbox's maxheight may sort the height for you.
Thanks for the working example, @hexed jungle. I was searching around a lot, but apparently my Google skills aren't yet at the level of Wizard.
And thanks for the detailed explanation, @grave hatch. When I get home from work, I will implement something following the guidelines you suggested (while also comparing to the example provided by Squize). A lot of what I'm doing right now is pure trial and error, and most of my trials lead to some sort of error. I'm grateful there are people like you around willing to offer some guidance.
๐
Not sure then. Debug the source code!
Using the helpful responses [here](#slate message) and [here](#slate message), I rearranged my original code to now be what I show below, and it works as intended. ๐ฅณ
SNew(SBox)
.WidthOverride(150.0f)
.HeightOverride(150.0f)
[
SNew(SScrollBox)
.Orientation(Orient_Vertical)
.Visibility(this, &SMCTDialog::GetVisibility_AngleOfAligningAxis)
.ScrollBarAlwaysVisible(true)
.ConsumeMouseWheel(EConsumeMouseWheel::Always)
+ SScrollBox::Slot()
[
AnimContainer.ToSharedRef()
]
]
Maybe someone in the future will find my snippet helpful.
Thanks for the help, guys. I'll probably be back with more questions, but we shall see.
EDIT: Removed .MaxSize(500.0f) from the SScrollbox slot.
Why do you need a max size on the scrollbox slot?
Can I somehow set a child of an object at index 0 without having to remove the other children at runtime? Because HorizontalBox->InsertChildAt(Index, Widget) doesn't work without removing another child, if that child is already at 0.
It should ๐ฆ
Or do you mean you're inserting a widget at 0 that's already in the tree at 0?
I have 2 children in the box. Once I hover over an item icon, I remove the first child so that it sets itself at the mouse position. But once I'm done, I want to put it back at index 0. But the problem here is, the inventory widget gets put as index 0 instead.
So you want to display single widget which changes when you hover over it with the mouse?
Yeah. I might of found a work-around. Instead of calling the same widget that's in the main widget, I'll just create a new widget of that type and display that one when hovering over an icon instead. That way I won't need to reference the one in the main widget at all.
Or use a widget switcher?
What's that? ๐ฎ
It's a widget that displays 1 of its child widgets at a time.
SWidgetSwitcher I think?
You set teh active widget by index.
Oh, I'll check into that! Didn't know that was a thing ๐ Thank you
Does anyone know a course or something like that to learn slate?
Never heard of one. There are some useful pinned messages in here, though.
Whoops. I don't need that. It was left over from my previous attempt.
Is it possible to override the new line behaviour for rich text box?
If you find out...
Do you want me to let you know?
Yeah ๐
can you give me some pointers or resource link on reimplementing the stuff ???
We don't even know what stuff you're using...
i am writing a logic to handle the import of fbx in cpp slate, for which i require ImportTask and Fbc factory funcs.
If any of those functions are in Editor or Developer folders, you can't use them. Which I'm assuming they are because of UnrealEd module.
So you'd need to completely rewrite all of it.
Nobody is gonna help with that.
Or find some sort of non-gpl library that does it.
I realize this might be better suited to ask here
Have you tried TakeWidget()->GetChildren()->InsertWidget I think might be a thing
I've no idea what UMG has in that respect.
Hello Everyone,
I am having a problem with SWindow, I create a new window to show the widget(made in UE editor) on the second screen and the widget have 3 sliders, those slider control some property of the project. So the problem that I am is when I move the slider it multiplies it button. but the property changes in the game just fine, Only the Widget looked messed up.
There is one thing that I noticed when I resize the window then it corrects the sliders.
Here is the messed up widget Screenshot
It sounds like it's not clearing the background
yeah, do you have any suggestion on how to clear this? Or maybe it's not being updated frequently. There must be some boolean variable to fix this.
Is there a full-window widget?
Like a background.
Add one if not.
Something that actually renders something - like an SBorder.
There migth be an swindow option?
Something clear-related.
If you want it black, you can just use a black color block to fill the background.
@grave hatch, You are great man.
It was the background issue
I added a border and it worked.
Great. ๐
Thank you so much.
Np
Hey everyone, is there a way that we could modify the shape of a SWidget to something else rather than a rectangle? Or doing modifications like offseting the bounding box of a SWidget? 
Everything in slate is square.
You can offset the bounding box by using a render transform?
But doing that will offset the visual as well right? What I want to do is to keep the visual in the same position and only offset the bounding box of it
How can I modify the width of the black input boxes within the SNumericEntryBox and SVectorInputBox widget?
As you can see in the below picture, the black boxes for input are small, which means they don't display enough digits properly if a large number (three digits) is inputted. I've tried placing the SNumericEntryBox and SVectorInputBox widgets within an SBox, as shown in the example code below, but doing so does not seem to affect the black boxes themselves when I adjust the width.
SNew(SBox)
.HeightOverride(22.5f)
.Visibility(EVisibility::Visible)
.HAlign(HAlign_Center)
[
SNew(SVectorInputBox)
.bColorAxisLabels(true)
.X(this, &SMCTDialog::GetValue_RootRotationRoll, i)
.Y(this, &SMCTDialog::GetValue_RootRotationPitch, i)
.Z(this, &SMCTDialog::GetValue_RootRotationYaw, i)
.OnXChanged(this, &SMCTDialog::OnValueChanged_RotationRoll, i)
.OnYChanged(this, &SMCTDialog::OnValueChanged_RotationPitch, i)
.OnZChanged(this, &SMCTDialog::OnValueChanged_RotationYaw, i)
.OnXCommitted(this, &SMCTDialog::OnValueCommitted_RotationRoll, i)
.OnYCommitted(this, &SMCTDialog::OnValueCommitted_RotationPitch, i)
.OnZCommitted(this, &SMCTDialog::OnValueCommitted_RotationYaw, i)
.AllowSpin(true)
]
Any ideas?
Try changing that HAlign from Center to Fill.
Yup, that fixed the problem. I can't believe I spent hours trying all kinds of other things... ๐คฆ๐ปโโ๏ธ
๐
Hey @grave hatch as someone with very little coding knowledge but advanced UMG/scripting side of itโฆ
Is slate easy to get into without that coding foundation or should I start with the basics of c++ and then look at slate once Iโm comfortable?
If you don't know c++, you're going to struggle. Even where c++ is concerned, slate is unique and complicated. Not nearly as complicated as some, but it's not simple. You're not going to to learn how to use it with a standard c++ course.
Tons of chain methods and operator overloading. Custom macros and such.
With a good basic c++ understanding and some research on slate, though, you should be okay.
Okay so it's more complicated than I thought :D. Do you recommend any good slate courses then? I've got the usual stuff like BenUI etc but if theres a stuctured course out there I'd definitely take it
I don't know of any. There are pins here with info and guides, but no hand holding afaik.
I can't figure out how to get the Size here in C++. Once I create the slot, I want to just set the Size to Fill. I literally can't find anything about it ๐ฆ Anyone that can help?
void UEquipmentWidget::CreateSlots()
{
int8 AmountOfSlots = static_cast<int8>(EEquipmentSlotType::TotalCount) - 1;
for (int i = 0; i < AmountOfSlots + 1; ++i)
{
SlotWidget = CreateWidget<USlotWidget>(this, SlotWidgetClass);
SlotWidget->SlotType = static_cast<EEquipmentSlotType>(i);
VerticalBox->AddChildToVerticalBox(SlotWidget);
// Set Padding
if(SlotWidget)
{
FMargin CurrentPadding = SlotWidget->GetPadding();
CurrentPadding.Top = 5.0f;
CurrentPadding.Bottom = 5.0f;
CurrentPadding.Left = 5.0f;
SlotWidget->SetPadding(CurrentPadding
}
}
}```
I don't think you can add slots like this into vertical boxes or such. The AddChildToVerticalBox function takes the contents for the slot as its parameter, and returns the slot allocated for it. Also this is #umg
I mean it works. I get the SlotWidget spawned underneath the VeritcalBox and the padding is correct
You can add slots to vertical boxes with box->AddSlot()
Ah, well if it won't fill try taking the return value of the function call and set the fill settings on that
This is very much umg though
Not slate.
Sorry.
And you won't get a size unless there's a layout prepass.
And then you can only get a desired size.
You have to actually have it draw first and then you can get the geometry used in the last frame.
I figured it out. Thanks!
๐
I totally misread all that on my phone. ๐
Hello, I'm a newbie in Slate, but I would like to know how can I check whether a certain input is pressed or not.
I'm trying to make so that pressing Messages/Warnings/Errors would filter out or not the whole thing, but holding Shift would make it make so that it doesn't apply any specific filter to it. I found the piece of code that does that, but I don't know how to check whether shift is held down or not.
FSlateApplication::Get().GetModifierKeys().IsShiftDown() or so
Brilliant, thank you
There's also the input events values in certain events like keydown and stuff.
Yeah, but I don't really want to mess the SOutputLog that much, I want to make it working the way I want with minimal changes ๐
I have a ListView and UserObjectListEntry item which goes into the list and how can i update the value of text block at runtime ?
You haven't mentioned a text block.
i didnt get you
I have a ListView and UserObjectListEntry item which goes into the list
has no relation to
how can i update the value of text block at runtime ?
Item has a bindwidget UTextBlock
someone says use slate in cpp and now umg, fraustrating.
They are wrong.
Slate is for stuff starting with S. STextBlock etc
UMG is still UMG, even if it's in c++.
If somebody said "use slate in cpp" - you are not doing that. You are still using UMG.
are there any good examples of how to implement treeview?
There'll be a lot in the engine source.
Hello, which function the Undo arrow calls in c++?
OR
is there a way to tell a UWidget to redraw the style after it was created?
That's "ResetToDefault"
It's a large pain in the arse to get it to update if you set a value programmatically.
The best way to do it is to override the reset to default delegates for that property and remove the caching on the "is default value" check.
Also it's not a UWidget.
Hello there,
I'm trying to show the scene took from SceneCaptureComponent2D on UI using UImage like Picture-in-Picture Image.
However, the UI cannot show SceneTexture from TextureRenderTarget that have a material that post-processed after tone-mapping.
How could I draw the SceneTexture from TextureRenderTarget into UImage(FSlateBrush) using SetBrushFromTexture()?
Btw, when I applied the material domain to "before tonemapping", the scene shows on the UI though. Why the "after tonemapping" does not work?
Use an FSlateImgeBrush and just set the texture on it.
I don't know why tonemapping is affecting this.
Hey folks, I asked this over in Lyra Dev Net as well, but are folks familiar with a way to push a Common Activateable Widget instance instead of pushing the class? EG, Push Content to Layer for Player is awesome, and is able to push the widget class; however, it would also be awesome to be able to construct the widget, passing in needed params to the constructor in order to set variables, and the like.
As it is right now with pushing the widget class, you have to use the returned reference to perform post-constructor initialization. If that is the only way, fine. Just wanted to ask to see if I am overlooking something. Cheers
If it's a stack/Queue your pushing into, their should be a AddWidgetInstance function for pre-created widgets to add to the stack.
Nice, I'll look for that.
Thank you! I have resolved it, and It was inverted opacity problem in my post processing material ๐คฃ
having an issue with creating STreeView
.TreeItemsSource(&TreeItems)
.OnGetChildren(this, &SAssetRenamerToolWindow::OnGetChildren)
.OnGenerateRow(this, &SAssetRenamerToolWindow::OnGenerateRow)```
Is giving me this error ```10>DeclarativeSyntaxSupport.h(937): Error C2679 : binary '=': no operator found which takes a right-hand operand of type 'TSharedPtr<WidgetType,ESPMode::ThreadSafe>' (or there is no acceptable conversion)
with
[
WidgetType=STreeView<SAssetRenamerToolWindow::FRenameAssetPtr>
]```
here's how i'm storing the tree view in the header file
```typedef TSharedPtr<FRenameAsset> FRenameAssetPtr;
TSharedPtr<STreeView<FRenameAsset>> TreeTest;```
Edit Fixed: NOTE TO SELF If you are going to name your tree item just TreeItemPtr make sure you look at all the places you declare it. This should have been `TSharedPtr<STreeView<FRenameAssetPtr>> TreeTest;` not `TSharedPtr<STreeView<FRenameAsset>> TreeTest;`
Have you seen the advanced renamer plugin? ๐
Yes I've seen MORT but i'm using this project as a chance for me to learn more complex slate topics and build something on my own ๐
do you know if there is a way to hide the expansion arrow on a treeview?
once again note for self when you are creating the row inside OnGenerateWidget you have access to STableRow::SetExpanderArrowVisibility(EVisiblity InVisibility)
I'm having an issue with CommonUI where my activatable widget doesn't respond to the same keybind to close (ie escape for pause), but it will open the menu
Not sure whats happenning, I tried using the widget reflector to see if something on top of it was consuming input but idk no dice
hmm unchecking this seemed to solve it lol
Iโm having an issue with the code here <#cpp message>. I seem to have made an incorrect assumption but Iโm not sure which it is
- When a check box is clicked I will fire MarkItemForRename on the Item tied to that row.
- If this is a directory, then all of the children will also be marked. (I believe this is working properly)
- When the child has IsMarkedForRename changed then the lambda for that rowโs check state would return a different value and should be shown in the UI
However, when I click it changes only the check state for the clicked value even though all of the children items changed. Iโve tried running Invalidate() in the OnCheckStateChanged and that didnโt help
Hello, since ListView child widget has no slot, how can I control the widget position freely? RenderTransform does not works well with ListView as it does not change layout. Padding does not work well either because it affects child. Is it possible to add slot in HandleGenerateRow? OR I have a way to reuse the FWidgetGenerator in SListView?
For context, I am trying to make the UI for "Hand" in a card game and fan out the cards. With the introduction of MVVM in UE 5.3, I would like to integrate with view models and ListView have some kind of native support with MVVM. I would like to reuse that.
It will be a problem in your lambda. Step through it.
Rather than listview, you could use an SOverlay to overlay widgets on top of each other and control the position of each widget via the padding property?
Or, rather, SOverlay -* SBox -> Card and control the padding on the SBox slot.
I've seen it animated pretty well with SHorizontalBox too
(instead of SOverlay)
I agree and did the same thing with Overlay/HB. On the other hand, the virtualization in ListView helps with widget pooling and works really well with list of data. Is it possible to reuse the functionality in other slate container?
Honestly I don't know.
You're probably going to end up doing a bit of work to add it yourself.
Which features, specifically, are you looking to use in other widgets?
Just the FWidgetGenerator thing.
You can't use listview's one, but you can certainly replicate it.
Cool. Maybe I should not over complicate the issue and solve it at UMG level. Thank you.
hello i am using "SVectorInputBox" to make an entry for my vector variable , but when i edit the value on it , it returns to 0 everytime , i set the max vector value to something large and still same results, what i need to do to use this properly
Show code
sorry totally slipped out of my mind
Hmm
How are you entering the value? Are you pressing escape or hitting enter? Tabbing away?
yeah just normal putting vector values like normally do in unreal engine UI
i thought it might be something to do with the max value since it returns to zero no matter what the number i set, or maybe i need to set a variable inside it ?
You shouldn't need to
What happens if you remove all the stuff and just do SNew(SVectorInputBox) ?
humm let me try
now it gives this by default , and does the same behaviour , what ever value i put it returns to "multiple values"
if i added 3 spin boxes instead of vector now it works , i needed just to edit my logics to now read x y z separatly , but it would be great if i learnt how to use the vector one correctly
hmm
Maybe you need to bind the value to something
.Vector(this, &SValidatorWindow::GetVector) for isntance
im trying to use commonui with world space widgets, the AnalogCursor does not work as expected, it uses GetTickSpaceGeometry().GetAbsolutePositionAtCoordinates(FVector2D(0.5f, 0.5f)) and that returns coordinates in the render target more or less, not viewport as the cursor stuff expects. Seems possible to translate them with actor transform, but it is difficult to get to them in relevant spot. Is there some other way to do that im missing?
Anybody that knows how i should implement the HUD for a **local **multiplayer join screen?
Something like the image?
How can i make certain parts of the HUDonly react to a certain connected controller?
I Suspect/heard each player controller/player will have some sort of FSlateUser?
If so how can i access that an build around that?
worked around this issue by replacing FCommonAnalogCursor with my own implementation that handles that case, in a quite poor way. Maybe there is something nicer :<
The base FInputEvent class has a UserIndex value
I guess you'd use that?
I have the following slate widget which I'm trying to add to the viewport, but it's not appearing on the screen. Construct does get called since the message is logged.
void SEGDPanel::Construct(const FArguments& InArgs)
{
UE_LOG(LogTemp, Error, TEXT("Panel construct"));
ChildSlot
[
SNew(SVerticalBox)
+SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(FText::FromString("Test text"))
]
];
}
if (GEngine)
{
TSharedRef<SEGDPanel> Panel = SNew(SEGDPanel);
GEngine->GameViewport->AddViewportWidgetContent(Panel, 999);
}
According to the docs this is how a slate widget should be added to the viewport so I'm not sure why it isn't visible https://dev.epicgames.com/documentation/en-us/unreal-engine/using-slate-in-game-in-unreal-engine?application_version=5.1
Are you sure the panel isn't being destroyed when the Panel variable goes out of scope? It's unlikely, but try adding a destructor and see if it's called.
Secondly, have you used the widget reflector to check the viewport?
That was it. Thanks!
I'd have thought the viewport widget would have held a strong reference there...
Hello. If i try to add a C++ EditorUtility Widget to my Project i can compile project any more... Any idea what's is wrong?
You didn't add the right modules to your build.cs probably.
Also that looks suspiciously like #umg
@grave hatch
And where does it say UMG there?
Or whatever module the editor utility widget lives in.
@grave hatch no idea.
but i found that warning Warning: C:\UnrealEnigne\Multiplayer\MultiplayerTemplate\Multiplayer.uproject does not list plugin 'EditorScriptingUtilities' as a dependency, but module 'Multiplayer' depends on 'EditorScriptingUtilities'.
and my plugin editorscriptingutilities is cheched
ok thx
from time to time, in the current build, hardware cursors don't work at all (bug rate: 1/6 executions), any advice? thanks!
I don't have any clue to follow....
Have you overridden all the cursors?
no, just the ones in the picture
but you know, I set the cursor to Default in the controller at the beggining
when the bug happens, the default Windows mouse doesn't change at any point
like if all the Hardware Cursor settings wouldnt exist
Are you sure they're being applied?
what you mean
the bug rate is 1/6 executions
so it works the majority of the time
Honestly I have no idea what the problem could be. :/
I would track down, in the engine source, where those settings are applied and check how and when they are applied.
if I change the window and go back, it works again..,
(so If the mouse leaves the window, unreal detect it properly the next time and hardware cursor get fixed)
If anyones figurate out any workaround would be awesome
I decided to attempt to switch over to using SSplitter, but I seem to be having issues regarding resizing the slots. From what my output tells me, the slots are indeed being resized, but there is no visual representation of that resizing. In the attached video, the two values being printed in the log, which represent the slot sizes, should always add to 1. And they do. But slot doesn't seem to visually change size.
Any ideas?
I resize the slots using, for example, OnSlotResized(this, &SMCTDialog::OnSlotResized_PerAnimDetails), which directly changes the values for the widths. And I get the values via Value(GetSlotWidth_BulkAnimDetails()).
For example,
// bulk details
+ SSplitter::Slot()
.Resizable(true)
.Value(GetSlotWidth_BulkAnimDetails())
.MinSize(0.25f)
.OnSlotResized(this, &SMCTDialog::OnSlotResized_BulkAnimDetails)
[
// content
]
(Ignore the ugly separators and buttons...)
OnSlotResized isn't what you call to resize a slot.
You'd use an attribute callback on Value() iirc
So .Value(this, &SSomeWidget::GetSlotSize, /* first slot */ 0)
Something like that.
And you'd use OnSlotResized to update the source of that Value
.OnSlotResized(this, &SSomeWidget::SetSlotSize, /* first slot */ 0)
@solemn saffron
Thanks. I'll look into that and see if that is my issue. I'm currently looking at the DetailsColumnSizeData.h file and how the class is used in the Engine. I'm working to understand how the way that class is used is different than what I'm currently doing.
That's how it's used by our classes in the engine ๐
Haha. Yeah. I figured. ๐
I'm back again with another scrollbox issue. (See below picture.)
I have a resizable SDockTab, within which I have a SBorder, followed by a SSplitter. In the left SSplitter slot, I have placed a SScrollbox. The issue I'm having now is the SScrollbox is not becoming scrollable when I resize the dock tab. I see that Unreal has scrollboxes that respond to changing tab sizes, but I can't seem to figure out how Epic does it.
What am I missing?
My code for the ChildSlot is below. (The parent is the SDockTab I mentioned above.)
SNew(SBorder)
.VAlign(VAlign_Fill)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
[
// Apply and Close buttons
]
+ SVerticalBox::Slot()
.AutoHeight()
.VAlign(VAlign_Fill)
[
SNew(SBorder)
.BorderBackgroundColor(FSlateColor(FLinearColor::Black))
.VAlign(VAlign_Center)
.Padding(10.0f)
[
SNew(SSplitter)
.Orientation(Orient_Horizontal)
+ SSplitter::Slot()
.Resizable(true)
.Value(0.25f) //will fix this later
[
SNew(SScrollBox)
.Orientation(Orient_Vertical)
.ScrollBarAlwaysVisible(true)
.ConsumeMouseWheel(EConsumeMouseWheel::Always)
+ SScrollBox::Slot()
.VAlign(VAlign_Fill)
[
SNew(SGridPanel)
//===========================================
// Details On Bulk-Animation Basis
//===========================================
+ SGridPanel::Slot(0, 1)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(375.0f)
[
VerticalBoxWidget_VerticalDetails.ToSharedRef()
]
]
]
]
]
]
]
]
I realize this is similar to the question I asked [here](#slate message), but the difference now is I want the SScrollbox to respond to a SDockTab changing size. I suppose I don't conceptually understand Slate well enough to see anything beyond a shallow similarity.
Have you checked to see if the gridview is actually becoming the correct size?
And it's not just shrinking?
You do have it set to VAlign_Fill, so that's what it might be doing.
And just to be sure, you are using the widget reflector to check that?
I have not. How would I check that?
Are you saying the SScrollbox should not be set to VAlign_Fill?
I'm not sure what widget reflector is. You're quickly plunging the depths of my ignorance. ๐
Tools -> debug -> widget reflector
There's a big button at the top-left, I forget what it's called, I just click it. Then whatever you hover, it will show you the widget tree and some very useful information about those widgets.
When you've hovered the mouse over your grid view, press escape and go check out the widget tree.
The things you're looking for there are the actual size and desired size of your grid widget.
Are you saying the SScrollbox should not be set to VAlign_Fill?
Possibly
The slot should not be.
Wow. That's quite the debug tool. I'm looking at it now.
This is what I see.
DesiredSize: X=387.000 Y=691.000
ActualSize: X=385.000 Y=691.000
The desired size should be larger than the actual size, and it's basically the same right now, so I suppose that is my issue. I'm not sure how to resolve that though.
The two sizes stay the same regardless of how I resize the SDockTab.
What I showed before was for the SScrollBox itself.
I don't know why there is no SGridPanel showing up inside the SScrollBox. The only thing that shows up is the SHorizontalBox.
It'll be inside the scroll panel.
I totally knew that. Totally. ๐คซ
Then go deeper and find out what isn't the right size.
Okay, I see, so I'm looking to find the widget that has a mismatch between the ActualSize and the DesiredSize?
I do have mismatches, but those mismatches seem to be due to the fact that the corresponding widgets are conditionally visible/collapsed.
That's fine. What I mean more is why is the scrollbar not working.
It should be because the contents of that slot is, for some reason, not bigger than the slot.
What I think I'm seeing in my attached picture is the SScrollPanel does not have a shrinking ActualSize in response to the shrinking of its parents. That is, the SScrollPanel has the same ActualSize and DesiredSize regardless of what happens to the parents. I'm guessing the static nature of the sizes is the cause of the visual issue I'm facing. If I'm correct, how would I approach resolving that?
I would set whatever contains the SScrollPanel (the slot) to a VAlign_Fill
So that it fills the space and doesn't expand past it.
I have a class ManagerSubsystem which creates and stores DebugContainers. DebugContainers store a TMap of properties. For each DebugContainer, I have a slate STable in which I want to display all of the properties and update the displayed properties as their values get updated in DebugContainer. STable can be seen as a visual/widget representation of DebugContainer.
STable has a reference to its corresponding DebugContainer, however I'm unsure how I can capture the new property values as they get updated in DebugContainer to display them in STable.
I would need a way to identify the properties in DebugContainer by their key based on STextBlocks in STable
I was thinking of storing a reference to the STable in DebugContainer and pushing property values to STable as they get updated, but this would also require me to create STextBlocks in STable dynamically when a new property gets added to DebugContainer. And it would still have the same issue of identifying the STextBlock which the property belongs to
I commented out a single line that contained AutoHeight, which resolved the issue with my vertical SScrollBox, though I don't understand why. But the VAlign_Fill does not seem to have a noticeable effect.
Now I'm trying to figure out how to get my horizontal SScrollBox to work. The approach I took for resolving the vertical SScrollBox issue does not seem to apply in any obvious way to the horizontal SScrollBox. I'm truly having difficulty seeing the rhyme and reason behind why certain things work in Slate, which means debugging is mostly just shooting blindly.
Thanks for sending me down the right path. That Widget Reflector tool is helpful. I realize now that you mention it in your pinned article. ๐คฆ๐ปโโ๏ธ
My article?!
You'd use bindings instead of static values.
But I would still need an identifier for each STextBlock to retrieve the right property from DebugContainer
How are you currently populating the table?
I'm not
In STable with the id as key and the TextBlock as value?
Combined with this approach perhaps?
The property name would be the key.
What I'd do there is actually use an SListView
That takes an array of data items - in your case an array of FNames.
Each FName would be a property in your debugcontainer.
Then the SListView sends a row construct event to each row and gives it that FName from your data list.
All you have to do is change the SListView's data set (it's a pointer to TArray stored on your debugcontainer)
And use each individual row's constructor to work out how to set and keep the value updated.
Oh, I meant the article you pinned to this channel.
For some reason, I thought you wrote the article.
With the row's constructor, do you mean OnGenerateRow?
SNew(SListView<TSharedPtr<FString>>).ItemHeight(24).ListItemsSource(&Items) .OnGenerateRow(SListView<TSharedPtr<FString>>::MakeOnGenerateWidget(this, &MyClass::OnGenerateRowForList))
Yes
How can I give the FName to a row? Does it do it automatically based on the item source?
Yes
You create an array, Items, and fill it with the fnames of your choice.
Make it a class var so it doesn't go out of scope...
When another property gets added to DebugContainer, I assume it will create a new row in the SListView?
And final question, should the SListView be in the STable?
void SEGDTable::Construct(const FArguments& InArgs, EGDDebugContainer* InDebugContainer)
{
ChildSlot
[
SNew(SListView<>)
];
}
You'd have to add it to your Items array yourself and then trigger the regenerate rows method.
No. it is a replacement for the STable
If you want multiple headers you can use STableView I think
There's a specific thing for having a list with multiple headers.
Alright I'll have a look, thank you
The row you return has to extend from SMultiColumnTableRow - something like SMultiColumnTableRow<FName>
From the regenerate row method?
Yes
You'd create your own row subclass based off SMultiColumnTableRow
You can also set a header row with the .HeaderRow() property of SListView I believe
So you'd create a header row first, then create the list view and pass it your header row.
Anybody know why I'm having this issue, ( First time using Slate )
they aren't, but I'm using Uwidget with slate to try and display in this case a border with a background blur
When are you expecting the background to change?
border color doesnt change, i dont know if its the slate or UWidget
when the value is changed
I have a custom brush color here that is suppose to change the color of the slate border.
Right. Have you checked to see if RebuildWidget is called?
Yes it is being called
Then it's something to do with UMG or the SBorder. I'm not sure which honestly.
Is the background colour the right value when you're inside RebuildWidget?
It should be because i am initialising the property with a value
But then you're changing it in the details panel?
Check with the debugger what value it is.
It seems right
๐ฅฒ Unreal is killing me
I appreciate you taking the time to help
Have you tried removing the blur and seeing what happens?
oh wow there's a full guide in pinned messages
I wouldn't say "full guide". Some useful starting pointers, though!
Oh! thank you for correcting me
If you do find a full guide, we'd love to get it pinned here!
if i ever do, sure
hello, I can add a SDetailSingleItemRow to my EditorUtility widget made in CPP? If yes, how I can do it?
Probably private. The property editor module can get you the edit widget with CreateSingleSomethingSomething.
I'm back with another Slate issue.
For some reason, every time I open an Animation Sequence, Unreal attempts to open a tab with my plugin's tab ID. I even get the following message:
LogSlate: The tab "MotionCaptureTools" attempted to spawn in layout 'Standalone_AnimationEditor_Layout_v1.5' but failed for some reason. An "unrecognized tab" will be returned instead.
This only happened after my NomadTab accidentally docked within an Animation Sequence. I then undocked and continued testing. Now, however, every time I open any Animation Sequence, a tab like the one in the below picture pops up. This pop-up tab does not interfere with the behavior of my plugin, but I can't understand why this tab pops up at all. I can close everything, restart the editor, etc., but the issue persists upon opening the editor again.
You can delete the Saved folder in the project directory, or just find the relevant file within it which I don't remember.
Or since the editor isn't crashing I think there's a button in the toolbar to reset the view layout under window
Okay, I will try those things when I get home.
From what I'm gathering based on the feedback, does that mean the issue of the window popping up isn't rooted within my plugin (at least not in any obvious sense)?
It'll mean some sort of plugin that isn't enabled has its layout saved.
Okay, thanks for the info.
Or that the layout name has changed...
Does this look right to you guys?
Problem at hand: My game thread in ue4 is ~6ms and In ue5.3 fkin 12-17 ๐คฆโโ๏ธ
Prepass & Draw children seems to push the numbers up:
Is that in the editor?
Also in stand-alone... But yes, in the editor. It seems to be no different in cooked builds.
at least not by looking at a debug build with stat unit+fps. The fps in ue4 is ~110-120 and now it's down to 55-70
this makes no fkin sense, so frustrated rn!
The default render settings are way higher in ue5
But, yeah, slate in the editor is going to be massively worse.
And slate in debug is even more massively worse
For awhile I didn't even run stat unit, I was 100% sure it's gpu/rendering impacting FPS. Then I realized my changes got me .5ms at most and was like "wtf". Then ran stat unit and saw the game thread through the roof ๐ฆ
Lol
Does anybody know if there is a list of Slate button styles, like "PrimaryButton" or "NoBorder"?
hey ive been trying for two days to get my widget to be returned by visibility trace at cursor and it just isnt
id even accept doing a totally separate call to determine the widget under my cursor, though i am doing one already that works for the static mesh component's collision
i cant get a widget under any circumstances to be returned.
so i have to add a totally separate component somewhere just to do this, maybe?
Thanks i didnt know that existed, also i thought slate was every widget and apparently its not.
When it comes to learning slate, what should I know of Unreal Engine first?
I remember you said that it's like learning two separate halves, Daekesh, but I'm not aware of where I start and stop in general with going from learning UE5 itself and learning Slate
What do you wanna do with slate?
I want to be able to do things with parity in slate that I could before in Unity Engine. Custom inspectors, new editor windows for unique object classes and learning the tool creation process for UE4/5
I'd need to also generate these files as C++ .h & source files from an application, for my dissertation too, though I've seen UE5 act... uniquely to files not generated by it's own tool
It's own tool? Do you mean the editor?
If you want to learn that, you'd need to start off well before the slate part. There's a whole editor workflow thing you should look into.
Take a look at things extending from FWorkflowCentricApplication
Or FBlueprintEditor, I think? (a subclass of WCA) Or just the standard FAssetEditorToolkit.
OR if you wanna do the it the cheap way, just look at registering a nomad tab with FGlobalTabManager.
- check out the stickies here for actual slate.
what are the risks and benefits of both ways?
You can have trouble "finding" nomad tabs if they're docked in the wrong place.
And by "finding" I mean with code.
You dock one in another editor (e.g. teh blueprint editor) and the global tab manager will no longer be able to find it.
Making actual asset editors don't have this issue.
There can be layout issues to (saving/loading) with nomad tabs.
thank you, are there any special setup features required for asset editors and plugins that I'd need to be considerate of when trying to generate code files for them?
oh- uh yeah that one would be unwise even in unity sometimes
Hi, where to put FSlateApplication::Get().SetNavigationConfig(...); correctly in the code ?
at the game module's startup, it crashes when packaging the game (FSlateApplication::Get() is not initialized yet)
You could subscribe to FCoreDelegates::PostEngineInit or whatever it's called
(in your module startup)
OnPostEngineInit
Hello I can't compile my code if "TxtBlocContent" variable is refered in the .h . I need a ref to change my text when the user trigger a button.`
The errors :
0>SlateControlledConstruction.h(103): Reference C2248 : voir la dรฉclaration de 'FSlateControlledConstruction::operator new'
0>SlateControlledConstruction.h(81): Reference C2248 : voir la dรฉclaration de 'FSlateControlledConstruction'```
The cpp :
```cpp
void SChatGPTChatWindow::Construct(const FArguments& InArgs)
{
//UI
ChildSlot.VAlign(VAlign_Fill).HAlign(HAlign_Fill)
[
SNew(SOverlay)
+ SOverlay::Slot()
[
SNew(SBox)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SAssignNew(TxtBlocContent, STextBlock)
.Text(FText::FromString("Welcome on copyloteGBP assistant, how can I help you today ?"))
]
]```
The .h
#pragma once
#include "CoreMinimal.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Text/STextBlock.h"
class COPYLOTEGBP_API SChatGPTChatWindow : public SCompoundWidget
{
SLATE_BEGIN_ARGS(SChatGPTChatWindow)
{
}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
public:
void OnQuestionAskCommited(const FText& InText, ETextCommit::Type CommitInfo)
{
UE_LOG(LogTemp, Warning, TEXT("Question asked : %s"), *InText.ToString());
}
TSharedRef<STextBlock> TxtBlocContent;
};```
Oh it fixed my stuff thanks !
Is this an engine bug? Was trying to fix weird behavior with my drag widget that has a 90 degree render transform applied, where it would start at an incorrect offset when the drag operation begins. Eventually found out that ScreenDrageePosition seems to be incorrect in this case and should just be MyGeometry.AbsolutePosition instead of MyGeometry.GetAbsolutePosition() (that uses the AccumulatedRenderTransform)
FReply SObjectWidget::OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& PointerEvent)
{
if ( CanRouteEvent() )
{
UDragDropOperation* Operation = nullptr;
WidgetObject->NativeOnDragDetected( MyGeometry, PointerEvent, Operation );
if ( Operation )
{
FVector2D ScreenCursorPos = PointerEvent.GetScreenSpacePosition();
FVector2D ScreenDrageePosition = MyGeometry.GetAbsolutePosition();
float DPIScale = UWidgetLayoutLibrary::GetViewportScale(WidgetObject);
TSharedRef<FUMGDragDropOp> DragDropOp = FUMGDragDropOp::New(Operation, PointerEvent.GetPointerIndex(), ScreenCursorPos, ScreenDrageePosition, DPIScale, SharedThis(this));
return FReply::Handled().BeginDragDrop(DragDropOp);
}
}
return FReply::Unhandled();
}
I'm now just calling this nasty line in my NativeOnDragDetected to fix it ๐คฎ
const_cast<FGeometry&>(InGeometry).AppendTransform(FSlateLayoutTransform(InGeometry.AbsolutePosition - InGeometry.GetAbsolutePosition()));
Uh. FUMGDragDropOp is an engine type or your own? (i just finished implementing my own similar sort of thing, T.T)
oh this is slate anyway. thought i was in umg
UMG definitely has drop and dorp built in, though...
what controls the background style of a widget like an editable text box? how come the starship test panel SMultiLineEditableTextBox has a background but mine doesn't? 
oh, god damn i am a retard
i didn't even see the Box vs nonBoxclass
i've spent like 20 minutes on this
i spend 3 days implementing a drag operation feature that already existed
the future time that will be spent revisiting how infuriating it was forever
Created a IPropertyTypeCustomization for a UStruct, and I used it to replace the entire header row using HeaderRow.WholeRowContent() [ ]
But, if I put the customised type into an array, then this breaks the array controls for some reason - I lose that little drop-down menu with insert/duplicate/delete in it.
Any way to use WholeRowContent without breaking the array menu?
The handle to drag and drop entries is still there, as is the "reset to default" column, but the little drop-down menu on the right is gone
Thsts a problem with arrays I believe.
I think you have to customise the container types too. But I'm not 100%.
Does seem that way. It's a bit silly since the array controls don't really have anything to do with the thing you're customising. Guess it's just the way that little menu is injected
Haven't dug into the internal array Slate code properly yet, but my theory is that using WholeRowContent removes the NameContent and ValueContent sections, and the way arrays are set up injects the menu button in the the end of the ValueContent.
That sounds highly likely!
Hello, is it possible to retrieve UWidget out of an SWidget in case the Slate counterpart is wrapped by the UMG?
Usually no
Some widgets add metadata to the underlying SWidget but most of them don't
What you can do is iterate over all the potential uwidgets and check if their swidget is the widget you want to check for.
for (UWidgetType* Widget : TObjectRange<UWidgetType>())
{
if (Widget->TakeWidget() == MyWidget)
{
... stuff
break;
}
}```
That'll only work if it's the root widget for that uwidget, though. You can check if the taken widget is a parent of your widget too.
Oh, yeah, sounds like a solution, thank you
Np
While pretty bad conceptually, if there aren't many specific instances of, say, UButton, then it will actually be relatively quick.
How do you create nodes like this ?
This isn't blueprint. It's flow graph
Is it a plugin or a custom engine modification ?
It's ok github
On
My dialogue stuff above is (going to be) open source too but it won't be usable for several weeks
Is that for use in something like FlowGraph?
yes
Looks great!
Shouldn't the variables declared in a UUserWidget show up in the Graph Editor?
UCLASS(Blueprintable)
class ROGUELIKE_API ULifeBarWidget : public UUserWidget
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float Life;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
float MaxLife;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
AEntity* OwnerEntity;
};
If not, there is a way to declare and expose them?
Did you enable inherited variables?
I remember that with blueprints it has a gear on the side of the add icon which I can use to show inherited variables, but here I don't see this option, do you know how enable it in User Widget?
I kinda already solved the problem, I discovered that the variables are accessible, they just don't show up, still would be nice to see them on the "Variables" menu
Is it not on teh cog at the top-right of the details panel, next to the search bar?
Oh ok, found it, thank you
Np
does anyone happen to know where the orange border is drawn in the engine source code?
trying to do something similar to my graph nodes
wait am i being a dumbass again, the reflector should pick this up
... nope it doesn't
my god ok it's SNodePanel::GetShadowBrush graph node highlight select blah blah search keywords
Heh
typical "spend 30 minutes looking, ask for help, find it in 5 minutes" ... i need to ask for help more often even if noone is around
It does get lonely in here! :tumbleweed:
well this turned into an unhealthy obsession https://i.gyazo.com/582bd5f8ac1a2637cf7f3fee88c8294c.mp4
Yeah, it took me a while but I made a better solution for that
don't have time to test code right now but still need to plan -- can you create an invisible button in slate and have it register a click but also not capture the mouse click? like a pass-through button to give me an extra layer of detecting if you click within a region?
what i did is start using tick. in tick i check if you've selected the dialogue and if a text box has focus or not. if yes, expand the text box. on top of that, if the widget has focus and you tap CTRL key, fully expand the widget and keep it expanded until you deselect the node.
the obvious "problem" is the widget now updates in two frames - you click on the text box and i have it autoupdate its own size, and then next frame, tick sees that it is selected and opens the rest of the controls. the text block (SMultilineEditableTextBox) does not contain any kind of "OnFocused" event i can bind to do it all immediately, so i'm thinking maybe a pass-through button would?
also i know tim would never use the profanity i displayed in that video i'm sorry tim
Yeah that's why I was wondering if there was a way to detect a click and let it pass through
I'll take a look around. Probably need to do some janky manual click detection is my guess
If you return FReply::NotHandled() on teh mouse click you're good.
Ooh derp right
But, yeah, manual OnMouseDown/Up stuffs.
Hey everyone, I have a question. I have only some xp with slate. I have a multiplayer game with a dedicated server. Curious, is there a way to play the audio persistently throughout different levels? Using Wwise. Like I want to initiate that audio when the game loads up the first movie, and then gets into the level and then gets into the game using join server. But curious if it could be done? Any help would be highly appreciated ๐
Hi everybody, I'm hitting a pretty consistent breakpoint issue in UMG
whenever I'm break pointing something that goes on a tick, I get this
LogSlate: Warning: Enter Debugging Mode failed.
followed by a notification, I don't think I've seen this before in other versions, and a search doesn't yield too many results.
I found a thread on Reddit, but it offered offered no solution. Has anyone else come across this and has a workaround?
Put the player on your game instance?
The player actor gets destroyed when changing levels. I think i might have found something, I had seamless travel turned off. Iโm guessing if I turn that on and play the sound on controller that should work. Iโll try and update you if it works.
Thank you
Anyone ever forced the UComboBox to open programmatically without waiting for user input/click?
You can probably fake a click
Through slateApp?
Eh.. I'll just use a ListView ... wanted to created some menu...
I was looking for this behaviour and the list view and anchor did the job. Although it was a bit cumbersome to setup.
Weird , that the ComboBox doesn't have such a feature. The combo box is already simple and more performance, and thats the only option its missing to replace the list view
I tried getting the Slate Object with TakeWidget Casting, and then and calling SetIsOpen(true) , and it completely ignored that function call...
Wondering what else it does on click for SetIsOpen() to actually open the ComboBox.
They should expose the function to UMG and blueprints though... it would be nice to have
Why not make the little green widget a menu anchor and use it to open a menu? Or a combo button?
The little green widget is an Anchor.
It was from the get go.
Now when the Menu Anchor โOpens menuโ the menu is(was) a ComboBox. Problem: The ComboBox when triggered by the Menu Anchor , initially appears closed.
So you need to click on it. so 2 clicks to open it and get to the selection part.
So i thought, hm, let me open it automatically from code, thereโs no such function
if you instead replace the anchor with just the ComboBox , to get the 1 click requirement, youโll lose the advantage of using an icon for your dropdown. It will be a string which will take more space.
Can you not use the Content() property of SComboBox to set an icon?
Does that not replace the usual content?
Maybe that will work.
But iโve already invested time developing a ListView based menu systemโฆ it works and more flexible since you can use entire widgets for the menu entries like icon next to text. itโs cool, just cumbersome to setup
i used SComboButton for that with an FMenuBuilder
like starship does
each dropdown menu entry is a full self-defined widget
(but oh well, if it works it works)
I mean i guessโฆ
But i donโt really like non UMG Exposed Widgets with little to no documentation.
I figured it would take me less time to build my own menu system than spend time reading some other code. available through UMG, quick changes and stuffโฆ can give the system to a new-bie and theyll be fine.
The list view is virtualized so doesnโt really waste resources and has both orientations so it really isnโt a bad choice. UComboBox doesnโt seem to have Horizontal orientation. the list view does.
What is the difference between SScrollBox and SScrollBorder?
Good question
I think you're meant to use SScrollPanel at any rate.
I think? I can never remember which one you should use.
wdym?
Ignore me.
No. Genuinely, I didn't understand
I saw SScrollBorder in UE source, but idk why they preffered it over SScrollBox (or why it exists)
How many of those we need? There is also SScrollPanel??
SScrollPanel is another widget used internally by SScrollBox.
I always get them the wrong way around.
Have you looked at the class to see what it says it does?
Yeah, but this doesn't means much to me
Shows a border above and below a scrollable area
Nevermind, it just displays this little half transparent black thing
It's very hard to see
How do I access childs of SScrollBox? I keep getting crashes with this
MyScrollBox->GetChildren()->GetChildAt(Index)
I think it gets bigger if you scroll to the bottom/top I believe.
I don't think it's the correct way, but I can access it by doing this
StaticCastSharedRef<SScrollPanel>(StaticCastSharedRef<SOverlay>(StaticCastSharedRef<SHorizontalBox>(MyScrollBox->GetChildren()->GetChildAt(0))->GetChildren()->GetChildAt(0))->GetChildren()->GetChildAt(0))->Children.GetChildAt(Index)
Apparently SScrollBox stores a SHorizontalBox, a SOverlay and a SScrollPanel which contains the childs
Keywords for future search: SScrollBox child, Child SSCrollBox, C++ ScrollBox Child, Slate SScrollBox Child, ScrollBox Child Slate
It'd be better to store your own list tbh
I mean store the slots or the widgets you add to them in your own array.
I mean unless it's expensive to do GetChildAt(), I prefer not to store another array since it changes frequently in my case
I highly recommend not using ScrollBox if you intend to have multiple object in it. Use a ListView or TileView for that. ScrollBox is for monolithic widget that are too big to fit in the space allowed like a textbox or an image . The advantage of ListView over ScrollBox is that the ListView already has a way to get the entry at index and multiple utility function based on a multiple entry scrollable widgets. You can use the OnEntryInitialized, OnEntryGenerated and there's another event that I forgot the name when the entry return to the WidgetPool. The same goes for TileView since it extend the ListView.
Or you could simple store a reference to a vertical box and stick it in a scroll box.
ListViews come with a load of extra bumpf you just don't want or need for a simple scroll panel.
+1 for using ListView for 95% of the time.
Scrollbox for prototyping but just switch to list view when done
That's what I'm saying, If you want scroll capabilities to your Widget, use a ScrollBox, but as soon as you want multiple widgets scrolling, ListView/TileView is your best bet.
Also note that the Views (TableView and it's child) doesn't share the same scrolling capabilities. The ScrollBox implement it's own scrolling rules and capabilities.
Because reasons!
Can I get some more explanation on SScrollBox vs SListView?
What more do you want?
To be honest, that's first time I heard about SListView, so I don't even know what I don't know :d
The best way I can differentiate both of them... ScrollBox is for single, monolithyc Widget. ListView is for a list of Widget (horizontale or verticale).
Even if you only have 2 Widgets, the ListView is better as it allow you to control scrolling on an entry base index.
Hmm, so what it does different than SScrollBox to be a better fit for a list of widgets?
Is it only scrolling to specific widget? Because as far as I know you can do same with SScrollBox, but you do it with a pointer to the widget not with index
Like I said in my previous comment, you can get the Item at index, you get a Widget pooling system that has event OnEntryInitialized, OnEntryGenerated and OnEntryReleased to control how your Widgets behave and to save memory
You can do the same with ScrollBox... You can do the same with VerticalBox/HorizontalBot... You can do the Same with any kind of Widget only if you care to implement everything from scratch
I see, so about creating actual widgets inside of it... As far as I understand you just pass in a list of your data and you get a callback to create child widgets right? There is a few things I don't get here
1-) Why does it wants me to use TSharedPtr to pass in data? Looks wasteful
2-) Why would I pass a callback when I can just generate at constructing widget itself?
3-) What are OnSelectionChanged, SelectionMode and HeaderRow ?
I don't have my editor open in front of me so I'll go from memory...
1- Not sure what you mean. You need to provide a data type and a way to interact with the data so your list can use it to "load" anyting into your list entries.
2- So you can use the widget pool. Once a widget get out of vision, it return to the pool and let you take action when it does... Same thing when the list generate a new widget and when it initialized the widgets for the first time.
3- I'm not familiar with those as my project might have change the meaning of those. So I'd rather not say anything on that.
Anyway, even if your goal is just to scroll thing, it's WAY easier to scroll a list of Widget using a ListView than a Scrollbox.
As far as I understand from this explanation, I can't pass in a simple array of struct as data
ListView relies on the property that holding a reference to a value ensures its existence. In other words,
* neither SListView<FText> nor SListView<FText*> are valid, while SListView< TSharedPtr<FText> > and
* SListView< UObject* > are valid
(wtihout some kinda shared pointer)
You can pass in an array of shared ptrs to said structs.
That's about it.
Or pass in a list of fnames which map to keys in a map if you want to avoid sharedptrs like the plague.
(not recommended)
I mean I'm not saying it's gonna be end of the world, but do I really need a shared pointer? Weird thing is it's not an option, it's a requirement to use shared pointer
Does it somehow track changes to the specified data?
Only sane reason I can think is it needs to track the data
It might be for for template magic.
Or to make sure data isn't deleted out from under it.
Or to not have multiple sources of data.
E.g. you copy your struct into the arary for the list and now you have 2 copies.
Or to make sure the list is ordered how you want it to. I never tried it, but I guess you could re-order an array and never move the list so it will not get re-drawn and might be out of date visually.
It never blood updates anyway unless you call refresh!
I mean these are valid reasons, if it's gonna go through a pre-defined automatic generation process, but it also asks me to generate the struct itself, so it doesn't needs the data.
Why can't I pass in for example TArray<MyStruct>* ?
It get invalidate if the list scrolls.
It wants things that don't directly contain data.
UObject*, Enum, FName, TSharedPtr, etc.
That's a pointer to a TArray, if it wasn't obvious
Yes, but the members of the tarray are structs which are data.
You'd pass in a pointer to a TArray<UObject*> too
(TArray<UObject*>*)
So what do I do if I have a TArray<FMyStruct> as my data? Do I create a copy with shared pointers or do I redesign my entire dataflow?
I have done that in the past.
Other than that, I don't get this widget pooling thing also. What is it?
Sounds like some pre-determined amount of memory shared between widgets?
If you really hated yourself you could try having a tarray of structs and giving it a tarray of ints which are hte indices of the structs in the first array
The widget pool is at the Uwidget level
I would probably isntantly fire you if you did.
Yeah, then have fun when you remove elements from middle ๐
Yeah. It would get messy.
So basically it's useless for editor tooling?
Probably I don't need to state this, but I'm lost ๐
I never tried to create editor tool... So I don'T know, but it should be usefull if you have a scrolling list.
I mean I don't have a UWidget in that context, how can it work if it's designed to work with UWidgets?
So my advice about object pooling might only be for usage in game... I was under the assomption that the goal was to use your SWidget in a UWidget... Not sure about how the editor works in that regards.
Sorry if I misled you about the pooling system,
It's fine, I'm just confused about this anyways. I'll dig UE source a bit. Should have something useful
You can make a UWidget class that uses your SWidget.
All UWidgets work that way in the end.
Yeah but I don't know how the editor work... Does it only use SWidgets? That's the meaning of my comment.
You can even use UWidgets in Slate.
c++ only uses SWidgets.
SWidgets aren't available "to the editor" (i.e. bp / python) unless you wrap them in uobjects, like UWidgets.
You can make everything you want in SWidgets of course.
So the editor would use the UListView which is made of an SListView?
If that's what UListView does, yes.
But all the editor tooling uses SWidgets.
Nothing that comes with UE uses UWidgets or BP utility widgets.
That makes it all hard to access with BP.
Ok so you can't make a tool using UWidget correct?
Ok... Good to know!
I assume it creates a UWidgetTree, takes the backing SWidget and attaches that to soemthign.
It's all SWidgets somewhere.
Well... Every UMG widget is a SWidget under the hood anyway
UMG is "just a wrapper" of slate so we can have visual tooling in the editor
That's my understanding and it's correct enough for my usage for now
Pretty much
Hello, why cant I see my borders at all here? It seems like they're not even there
ChildSlot
[
SNew(SBox)
.WidthOverride(800)
.HeightOverride(400)
[
SNew(SBorder)
.BorderBackgroundColor(FLinearColor(0.82f, 0.71f, 0.55f))
.Padding(10)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.FillHeight(1.0f)
[
SNew(SBorder).BorderBackgroundColor(FLinearColor::Yellow)
.Padding(10)[
SNew(STextBlock)
.Font(CustomFontInfo)
.Text(bodyFText)
.Text(FText::FromName(message))
.Justification(ETextJustify::Center)
.ColorAndOpacity(FLinearColor::Red)
.AutoWrapText(true)
]]
+ SVerticalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Bottom)
.AutoHeight()
[
SNew(SButton)
.Text(FText::FromString("Terminate"))
.ButtonColorAndOpacity(FLinearColor(1.f, 0.57f, 0.14f))
.OnClicked(this, &SPopup::OnQuitClicked)
.TextStyle(FCoreStyle::Get(), "EmbossedText")
.ForegroundColor(FLinearColor::Red)
.ContentPadding(FMargin(10))
]
]
]
];```
Go to the tools menu -> debug -> widget reflector. Press the button at the top-left, mouse over your widget and then hit escape.
You can then examine what's actualyl going on with your widget wrt sizes and stuff.
The super helpful part of it is hovering over the class name and it tells you the widget desired size and actual size
Yup.
well this is annoying https://gyazo.com/bdec04b063eb9fc2bbd2c481754b81fd.mp4
ah. SGraphNode::Tick does some work to mostly fix this... i forgot to call base class Tick in my override
How can I make size of my checkbox bigger?
SNew(SCheckBox)
.Style(FAppStyle::Get(), "RadioButton")
[
SNew(STextBlock)
.Text(INVTEXT("Some Text"))
]
If I need to register a new style, how do I do that?
i think it should grow to fit its contents
you could wrap the STextBlock in an SBox and give that box a .MinDesiredWidth
you could set the padding of the SCheckBox to grow it around its contents
as for a custom style, there's fancypants and ghetto ways
here's a fancypants way https://minifloppy.it/posts/2023/how-to-style-slate-widgets-using-stylesets/
ghetto way/bare minimum functionality: store an FCheckBoxStyle variable somewhere (i.e. your widget), initialize it to some close defaults on construction
CheckBoxStyleName = FAppStyle::Get().GetWidgetStyle<FCheckBoxStyle>("ToggleButtonCheckBox");```
modify it as needed and just use it
That's the old bad way. The new way is to extend FSlateStyleSet?
thanks, stupid new old blogs
Whatever the class is.
A lot of the avalanche motion design modules have up to date style classes.
Does it matter, if I just wanna double the size of checkbox image?
Not overly
Great, then I'll just hold a copy of style and edit it
to be clear, using FSlateStyleRegistry::RegisterSlateStyle is the bad way? how would you extend FSlateStyleSet? or are you not sure if your terminology is correct?
class FAvaEditorStyle final : public FSlateStyleSet
{
public:
static FAvaEditorStyle& Get()
{
static FAvaEditorStyle Instance;
return Instance;
}
FAvaEditorStyle();
virtual ~FAvaEditorStyle() override;
};``` example new style header
Oh actually I have this exact way in my plugin which is auto created by plugin template
thanks, will take a looksie and learnsie
You still gotta register it apparently, but it's done in the constructor.
What is the implementation?
oh yeah these look like a bit less boilerplate, cool
It's in the engine. Just check it out.
search engine source for final : public FSlateStyleSet and you'll get a bunch of examples
Got it, thanks
Or just : public FSlateStyleSet I guess.
btw, how do I import icons, images, etc to use within editor (from plugins resources folder)
I saw IMAGE_BRUSH and IMAGE_BRUSH_SVG, but I'm not sure if those are correct ones
I'd suggest looking at the class I said earlier ๐
Makes sense, they need it for same reasons ๐
Does StyleSetName matters?
AvaEditorStyle registers as AvaEditor, but it also uses some other stuff that doesn't start with AvaEditor
FAvaEditorStyle::FAvaEditorStyle() : FSlateStyleSet(TEXT("AvaEditor"))
{
Set("Icons.Canvas", new IMAGE_BRUSH("Icons/ToolboxIcons/Canvas", Icon16));
Set("AvaEditor.PlaneTool", new IMAGE_BRUSH("Icons/ToolboxIcons/plane", Icon20));
}
I mean is it just I don't need to remember it's name as long as I do MyStyle::Get().GetStyleSetName() ?
I'm not sure why that even starts with AvaEditor. honestly.
Great. Also one more question.
These things happens at constructor, right? But who creates an instance of my style class? an automated thing? Because as far as I know CDO only works for UCLASSes
The first time you call ::Get() it will create it.
Also my old code used to call this, but new code doesn't
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
You definitely don't need to call taht.
Is it necessary?
Okay, it came with plugin template. idk why
Thanks for help ๐
Np
do you have a youtube channel so i can see more long videos about this system , it so interesting
the parent system is FlowGraph, that might be what you want to look up
the thing i'm working on, i'm calling FlowYap, which adds dialogue nodes to FlowGraph, and will add an underlying simple dialogue management system (so that a game can build its own unique dialogue UI and respond to dialogue progression events)
my addon is under dev, probably a couple months before it's worth sharing at all, only been working on it a couple weeks
https://github.com/HomerJohnston/FlowYap not usable for a game at all right now, not even close, but if you wanted to bookmark it and check later on
good luck bro, wish you all best , thanks i had a look at the flow graph, seems like a pretty good start for such systems , yet i loved your stuff that is what i wanted to see , will wait for your plugin to publish then if there is no more videos XD, you are so good bro
will look at it now , thanks for sharing
with Slate, are we just chaining construction and object decoration/styling commands on top of each other?
it's kinda like web-dev languages - HTML/CSS
If I'm inheriting from SCompoundWidget, what's causing a TSharedPtr<SMainMenuWidget> to not cast as TSharedPtr<SWidget>?
I'm using Unreal Engine 5.4 and I believe I've required the correct dependencies and have the right includes
This is pretty much the only error that comes up, outside of the usual UE5 ones for intellisense
Trying .ToSharedRef() just changes the type conversion on the left hand, but to the same error
It'll fail a cast if you haven't included the main menu widget header.
I made sure to check that and I did
yeah, just that it can't cast to SWidget
despite the header including SlateBasic and SlateExtras (MainMenuWidget)
Yes
What's the compiler output?
and each function call after, such as SWidget.HAlign(...).SWidget.VAlign(...) returns the component/object after it's been modified by that function call?
reopening the project now
Another thing: .OwneringHud(this) - is this an SWidget?
Yes. They're all chain methods.
It's not actually the widget, though. Fun thing.
no that's a uh an AHUD
would it be the reference to the component being added/modified?
It has a cosntruction object which is actually returned. And that works because the . operator is higher priority than << (or is it <=?) it uses to actually create the widget.
Ah okay, never mind then.
so it just modifies the construction object
Yes.
You'll see plenty of times that stuff is only available on the construction parameter object.
a gigantic, modular instance factory huh
And not changeable afterwards.
this is the full menu script right now (ToSharedRef does pretty much nothing)
the SMainMenuWidget.h only includes SlateBasics.h and SlateExtras.h
It defines the SMainMenuWidget class as well, I hope?
I was trying to follow BenUIs tutorial introduction but it was... a challenge
yeah, it does
ToSharedRef is definitely not needed.
I wasn't even sure why BenUI was doing TSharedPtr<class SMainMenuWidget> insetad of forward declaring SMainMenuWidget int he header
That method takes a SharedPtr
Inline type decorators are just a style. A bad one, I feel.
yeah I... don't really get it
It's less work.
ah so they do it cause it saves time, but costs maintenance
The alternative is that you have a circular dependency and it can't include the header correctly.
And thus can't determine what the class is.
are you including the uh forward declares as a whole there?
Forward declarations don't cause circular dependencies?
yeah they don't
I'm just referring to the specific in-template one. e.g. TSharedPtr<class SMainMenuWidget> instead of TSharedPtr<SMainMenuWidget> (with a forward declare)
Makes zero difference.
well yes, just was confused as to why BenUI was doing the former and not the latter at the time
this is all I see right now which is weird to me
Compile?
everything else above is just verse errors (because verse randomly triggers during compile)
SMainMenuWidget is an SCompoundWidget too
That's not good.
Don't use that view.
It's just giving you intellisense errors and hiding the actual error.
If that's Rider, you need to toggle on the raw output (it's a button on the left somewhere). In VS it's the output window.
Yeah, so that's definitely the error, okay.
And that only happens if the class can't be found to inherit from swidget.
I.e. header not included or circular dependency stopping it frm being included.
that is weird
is it something dumb?
It is. You'll kick yourself.
is it something really dumb
๐
im not even mad or kicking myself over it honestly
it's just the trials of the trade
switching languages is fun
I also did end up getting a Udemy course as a backup option
not the biggest fan of Udemy but being in a strange land with any help is better than none
(and the book i've got doesn't even cover slate- it just advertises me another book for that purpose at the end)
Yeah, thank you
I'm not too sure on the course itself, it has things I'm very interested in and seems to be fairly highly rated
it's one by Vince Petrelli
I don't think I've ever been on udemy lol
yeah i didn't even remember having an account until a few hours ago
I'd try get a link to it but it keeps sending me to my own content page on udemy
Unreal Engine 5 C++: Create Custom Editor Tools - Vince Petrelli
thought it was worth a shot because of the course content being interesting and each session was in easy chunks rather than "SCREW DA RULES I HAVE THE SHIBILIDABALADIBILIDA"
Just remember that tutorials are often very bad
yeah, I'm expecting roadblock issues
People work out how to do something, the wrong way, think it's the shit and make a tutorial.
That's a concern I have about anything with Slate because there's not nearly as much on it
Have you read through the pins in here?
Yeah, to the best of my ability
coincdentally in his latest blog post about coding standards he said himself that he doesn't do that anymore.
Yeah, I read that too
Happened to me the other day. Downside of using macros like SNew is, it won't catch things like private access
Instead you'll get some cryptic error message
I mean you'd get a similar error if you used Cast or static_cast.
(on non-snew stuff)
i just got in the habit of building often and building in very small chunks if i'm writing big layouts. add one or two things at a time and then it's easy to find nonsensical C++ build error causes
Same
Yeah, but you'd got a red underline where you try to do that.
I think UE macros hides those, at least for me
I got underline at left square bracket [ for following code
+SWidgetSwitcher::Slot()
[
SNew(SMyWidget)
}
Probably because you mismatched your brackets.
No, I mean that's when you forget to do public in : public SCompoundWidget
Anyone know if it's possible to get a tool menu context for MakeAttributeLambda or such somehow? Besides using AddDynamicEntry and creating the entries with the attributes inside that
It seems calling Section.FindContext... within the attribute lambda results in nullptr, maybe the dynamic entry is the only solution here...
FToolMenuExecutionAction passes in the context, but as far as I can tell there's no way to get the context passed into the attribute code
You'd need to add a context to find it
You can't get the context, except in dynamic menus
Well, sort of.
In fact, just ignore everything there.
I think the question is why don't you want to use a dynamic menu entry to create a dynamic menu?
Well I'm using ExtendMenu and it's less complicated to add a regular entry into it than adding a dynamic section or dynamic entry :D
Yeah I'm probably overthinking it. I noticed that if you add entries into the asset editor toolbars, it ticks all the functions every single tick which feels a liiiittle bit iffy if the button state isn't changing every frame
But in context menus doesn't seem so as those I guess only exist when the actual menu is open.
Either way the lambdas I have currently should be fairly cheap anyway so probably not a big deal
Yeah the whole binding thing is terrible in slate.
Need nice event driven stuff ๐ฆ
I guess you can do it if you included the no update thingy for every signle element...
The invalidation thing!
Hi, guys. I got crashed from FDefaultLayoutBlock::GetTextContext() when I triggered my UI visualization button repeatedly. But, I have no idea why it occurred. Which Slate function is related to the GetTextContext()?
Here's the error log.
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION writing address 0x0000008000000008
UnrealEditor_Slate!FDefaultLayoutBlock::GetTextContext() [D:\build\++UE5\Sync\Engine\Source\Runtime\Slate\Public\Framework\Text\DefaultLayoutBlock.h:22]
UnrealEditor_MyModule!AMCustomActor::PostPhysicsInternal() [F:\-\Source\-\Private\-\AMCustomActor.cpp:28]
UnrealEditor_MyModule!UCustomActorManager::PostPhysicsTick() [F:\-\Source\-\Private\-\UCustomActorManager.cpp:26]
UnrealEditor_MyModule!UTimeManager::Tick() [F:\-\Source\-\Private\-\UTimeManager.cpp:22]
UnrealEditor_MyModule!UCustomTickManager::Tick() [F:\-\Source\-\Private\-\UCustomTickManager.cpp:9]
UnrealEditor_Engine!FTickableGameObject::TickObjects() [D:\build\++UE5\Sync\Engine\Source\Runtime\Engine\Private\Tickable.cpp:153]
UnrealEditor_UnrealEd!UEditorEngine::Tick() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\EditorEngine.cpp:1977]
UnrealEditor_UnrealEd!UUnrealEdEngine::Tick() [D:\build\++UE5\Sync\Engine\Source\Editor\UnrealEd\Private\UnrealEdEngine.cpp:531]
UnrealEditor!FEngineLoop::Tick() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp:5825]
UnrealEditor!GuardedMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Launch.cpp:188]
UnrealEditor!GuardedMainWrapper() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:118]
UnrealEditor!LaunchWindowsStartup() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:258]
UnrealEditor!WinMain() [D:\build\++UE5\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:298]
UnrealEditor!__scrt_common_main_seh() [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
kernel32
ntdll
That's really weird.
I'm assuming it's some kind of dangling pointer?
Because physics should never really be directly interacting with hte UI and if it is, you're doing something wrong.
Is it possible to create an application that has panels and buttons and such around the viewport, kind of like this: https://i.ytimg.com/vi/CR4pcP32_Ug/maxresdefault.jpg instead of having the viewport fill the entire window and putting buttons and such on top of it?
So I have two exact same widget wrapped in a SBox like this:
SNew(SBox)
.HeightOverride(250.0f)
[
SNew(MyWidget)
]
It works perfectly fine and does as asked. Overrides the size of the specified widget, but as you may notice latter one can't quite fill that space. So it only makes sense to shrink it to hold all the childs
The issue is when I convert .HeightOverride to .MaxDesiredHeight, it still takes all 250 units space exact same with previous one
It seems like ScrollBox tries to get all the available space, is there any way to limit it?
(To size of its content)
VAlign(Top)
on SBox?
Well, it did kinda work, SBox and its content doesn't take unnecessary space now, but overall layout still takes the same size
I don't know what's taking that space
I can't pick it up in widget reflector
To give a bit more context all of these is a a child of SVerticalBox which is contained inside another ScrollBox
I got it
Solution was to make +SVerticalBox::Slot.AutoHeight()
Is there any kind of wysiwyg slate ui editor plugin?
You mean something like UMG editor?
It doesn't have all the UI elements, but it's pretty useful to demo existing elements
life hack: in your editor style set, use
#if WITH_LIVE_CODING
if (ILiveCodingModule* LiveCoding = FModuleManager::LoadModulePtr<ILiveCodingModule>(LIVE_CODING_MODULE_NAME))
{
OnPatchCompleteHandle = LiveCoding->GetOnPatchCompleteDelegate().AddRaw(this, &FYourSlateStyleSet::OnPatchComplete);
}
#endif```
to unregister your slate style, build your style set, and reregister your slate style... so you don't have to reboot the farking editor every single test change
(you have to make sure it's not being actively drawn during live coding though or it'll crash ๐ )
I was writing one, but never got around to finishing it.
How would you even pull something like this off? You need to compile the code at some point
Or are we talking about some pre-determined playground?
Because slate isn't reflected... you need to create reflection data.
Basically I created a set of reflection data and manually reflected useful types and widgets.
Sure, but still how would you live demo it? Like you'd need some kinda hot reloading, no?
Interesting...
Ngl, there were a lot of templates!
So, normally you can do this
TSharedRef<STextBlock> MyFunc()
{
return SNew(STextBlock);
}
ChildSlot
[
SNew(SVerticalBox)
+SVerticalBox::Slot()
[
MyFunc()
]
]
Can you somehow include +SVerticalBox::Slot() part in your function?
I only achieved returning widgets not slots
Yes
You'd need to return a SVerticalBox::FSlot object
Then do + MySlot() or whatever
Could you give an example? I can't make it work
What errors do you get?
Oh
It's SVerticalBox::FSlot::FSlotArguments
Which you create by doing cpp SVerticalBox::FSlot::FSlotArguments(SVerticalBox::FSlot()) .Arg() .Arg2() .Etc()
It doesn't work
auto MyFunc()
{
return
SVerticalBox::FSlot::FSlotArguments(SVerticalBox::FSlot())
.AutoHeight()
[
SNew(STextBlock)
];
};
Log:
Error C2440 : '<function-style-cast>': cannot convert from 'SVerticalBox::FSlot' to 'SVerticalBox::FSlot::FSlotArguments'
Reference C2440 : No constructor could take the source type, or constructor overload resolution was ambiguous
I was doing either SVerticalBox::FSlot::FSlotArguments().Arg() or SVerticalBox::FSlot().Arg() and it was complaining about deleted constructor
How are doing it?
Ah you pasted.
Try ```cpp
SVerticalBox::FSlot::FSlotArguments Slot(SVerticalBox::FSlot());
Slot.AutoHeight()
[
SNew(STextBlock)
];
return Slot;
There are shenanigans it does.
Nope, still same log
Coped it wrong!
It doesn't like SVerticalBox::FSlot as a parameter to SVerticalBox::FSlot::FSlotArguments
SHorizontalBox::FSlot::FSlotArguments Slot(SHorizontalBox::Slot());
Slot
.Padding(AddButtonPadding)
/* stuff */ ;
return Slot;```
I know this works.
At once point I was doing MoveTemp(Slot) as well.
Yeah, this one works
It works for vertical box as well, but only with exact same syntax
It also works if you do return MoveTemp( ..construct here.. );
Oh yeah, it wants SVerticalBox::Slot, not SVerticalBox::FSlot
I got it to work, thanks ๐
auto MyFunc()
{
return MoveTemp(
SVerticalBox::FSlot::FSlotArguments(SVerticalBox::Slot())
.AutoHeight()
[
SNew(STextBlock)
.Text(INVTEXT("This slot and it's widget created from a function"))
]);
};
Then:
ChildSlot
[
SNew(SVerticalBox)
+MyFunc()
];
๐
That's so gross (to me) ๐
Just keep the slot def outside and only make the inner widget...
It's so much easier to actually lay out that way... I feel like putting both of those responsibilities together is joining things that don't belong together (i am on the internet, and i have an opinion!)
Depends.
If you have a lot of things which require exactly the same slot and then exactly teh same child, but just 1 difference, it makes sense to create the entire slot and child with a single function.
Like a load of different ftexts you want to display in a uniform way or something.
There's this - https://github.com/davgmz/UE-SlateDesigner
Ooh I was seeing old messages, seems out of context now.
Is there any actual need/advantage to using the 'Slate_Declare_Widget' macro? Do I need it in order to use TSlateAttributes? I tried to implement these macros in one of my widgets and so far I'm mostly getting errors about deleted constructors being referenced, I am obviously doing something wrong but... what do I really get out of this? before making the changes the widget was declared with the module API and worked just fine in other modules, I could use TAttributes and they seemed fine.
I read the section in the slate compendium and I'm still not 100% on the differences, the compendium also only includes an example header and doesn't show what's going on in the .cpp file with the 'Slate_Implement_Widget' macro and the required overrides, so... hmm, idk, it seems like the engine slate widgets all use these macros but third party widgets largely don't bother.
The moment I have 'TSlateAttribute' members the compiler gets unhappy with me, saying I'm referencing deleted functions. TAttributes no complaints. I must be missing something.
I think I got it to work, you need to declare the member and then also pass the args in the super (?) constructor. Still not sure what the advantages of Slate Attributes are but I guess now I can experiment.
The Slate Declare Widget macro sets up the "parent" widget for your widget, basically, in teh class hierarchy.
I've not really seen any other use for it.
You have to add the function it mentions about complaining to your cpp file and just leave it empty if you want to.
(this one: void PrivateRegisterAttributes(struct FSlateAttributeDescriptor::FInitializer&))
The sad thing is, it's really useful to declare the widget because it generates reflection data about the widget so you can tell what its parent class is and such. Sadly, the if you don't specify it, it will just use the last base class that did so if you've overriden SCompoundWidget 3 classes deep and not used SLATE_DECLARE_WIDGET, then all 3 subclasses will appear as SCompoundWidget.
It's just really bad because it's so under-used in the engine.
I think it also implicitly includes the parent widget inargs in the widget's inargs? I need to test that, I was actually annoyed by that in the past.
I don't think it does that.
But it's entirely possible to do that without it.
SLATE_ARGUMENT(SParentWidget::FArguments, ParentArgs)
Then SParentWidget::Construct(InArgs._ParentArgs) in the child construct.
Thanks for the answer Daekesh! I have another question!
I think in the past you told me in this channel "never use raw pointers" in slate and that's a good cool cause they definitel like to crash but I have some confusion regarding the correct design choice here, my scenario is basically: I made a pianoroll widgets that renders MIDI data, it gotten pretty complex over time and it now basically is linked to the state of a certain UObject.
I primarily used this slate app in an asset editor toolkit, when I wanted to create a UMG variant of it things began acting pretty 'crashy', and it was pretty obvious that I coupled too much logic inside the widget with data from the uobject, so, I generally want to fix it but I am not sure what's the proper approach:
- pass all the data as attributes, don't let the widget even 'see' the external object
- make a proper 'init sequence' and 'do less' if the data object isn't instantiated?
- Figure out a way to have some safe default/placeholder object used whenever the widget is initialized without a real data object
went with 2 ๐
I would move all of your logic not directly related to the widget out of the widget.
Respond to button click? Sure. That button click response should forward the call to something else, though. You don't want actionable code in your UI.
That would mean your UMG and Slate widgets could also share a codebase.
Thank you for the reply. Yes, I know it's generally the right thing and I'm already in the process of taking out all the actual 'action logic' outside the widget, it's just that with the init sequence of it all, without the UObject to read the data from the widget kinda only draws a background grid, kinda like a movie sequence editor with no asset to edit, I'm sure this isn't the best practice but an early return if the pointer is null seems 'stable' for now.
Another example I can think of which I dealt with in recent weeks was the SGraphEditor, if it doesn't receive a UEdGraph object reference it'll throw an assert rather angrily. maybe it's not terrible in some scenarios? I probably still shoudln't use a raw pointer here.
reposting here, since this seems a more appropiate channel:
Hello, I was battling yesterday trying to get an editor mode slate UI (that I'm writing myself) to display asset thumbnails, but they always appear black. I've been able to query the assets alright, but when following the guides I've found on the internet (and chatgpt), they thumbnails appear . but appear black. Does anyone have some experience with this part of slate/editor?
Cannot seem to make threads sadly, here is the code snippet:
auto hbox = SNew(SHorizontalBox);
for (const FAssetData& asset : assets) {
auto thumbnail =
MakeShared<FAssetThumbnail>(asset,
kWidth,
kHeight,
ThumbnailPool);
// clang-format off
hbox->AddSlot()
[
SNew(SBox)
.MaxDesiredWidth(kWidth)
.MaxDesiredHeight(kHeight)
.ToolTipText(FText::FromString(asset.ToSoftObjectPath().ToString()))
.HAlign(HAlign_Left)
[
thumbnail->MakeThumbnailWidget()->AsShared()
]
];
// clang-format on
}
What are kwidth and kheight set to?
Have you used the widget reflector to check what's actually being displayed?
Have you checked the thumbnail widget to make sure it's actually getting an image?
kWidth = kHeight = 64
I don't have the editor open right now, will have it later today, but it does show the widget like box (with the color underline depending on asset and the little icon to the down-right). Just that the image is black. In the afternoon I will have more reflector data
I'd suggest TSharedRef<SWidget> ThumbnailWidget = thumbnail->MakeThumbnailWidget(); and then debugging the values in that widget from your IDE.
(after you check the reflector)
I checked with the reflector but didn't find anything super telling. I did step through the thumbnail widget construct and boiled down to the thumbnail pool having an entry for my asset, but the texture data pointer being null. Wonder if there is some pre-population to be done, or if I can use the same pool as the content browser, since I'm creating a new thumbnail pool of my own
Fucking Finally! definitively NOT worth the time invested, but I did learn a couple of stuff.
For future reference, the trick was to not create your own ThumbnailPool but use the global one that Unreal uses. I guess they do some pre-population of the textures:
UThumbnailManager::Get().GetSharedThumbnailPool()
very helpful to know, thank you
It thought it might be that.
what is the meaning of Unable to find Slate Widget Style?? where can i define a style??
Slate widget styles are registered with slate style objects.
Like button styles, etc.
The editor ones are in the starship style cpp file.
How I can divide my content area into 2 (vertically) where first area has max height of "half of the available space", but could be smaller based on its content?
That's good question
Couldn't I have a VerticalBox which wraps both and fills the available space
Then I would just set MaxSize of first one at tick
Or if it has a lambda for it
vertical box slots have a maxheight and a fill height.
Setting both of those might work.
For example:
ChildSlot
[
SNew(SVerticalBox)
...
...
+SVerticalBox::Slot()
[
SAssignNew(MyVerticalBox, SVerticalBox)
+SVerticalBox::Slot()
.AutoHeight()
[
SAssigNew(FirstContentWrapper, SBox)
[ FIRST_CONTENT ]
}
+SVerticalbox::Slot()
[ SECOND_CONTENT ]
}
...
...
}
Then at tick, I'd just get CachedGeometry from MyVerticalBox and set half of it as max size of FirstContentWrapper
I wonder if AutoHeight and MaxSize work together.
Probably does, but I need to somehow know available space for both, so I need to wrap them
Is there an appropriate delegate in Unreal that is called when the Content Browser redraws its content (folder and file icons)?
I doubt it.
There doesn't apepar to be anything in FContentBrowserModule.
You can try using the widget reflector on the content browser itself to see the widget and see if it fires any delegates in its code.
yeah :/
no it doesn't... but can i bind on a "OnPaint" method or something ?
No
๐ฅฒ
if you're using the source code (and feel like breaking something)
you could probably mod that behaviour to your copy of your UE?
Isnt slate dead
How do I handle cleanup of a slate widget class? I have some pointers i need to clean up manually
If all the tsharedptr/refs that point to a widget are destroyed, the widget is destroyed.
I need to manually clean up
is there not a function that takes care of that that can be overriden?
No.
That's not how ref counted things work. You can get the pointer and delete it manually... But whatever is still using the shared ptr will then crash the engine.
What should you call to capture the mouse and focus without relying on FReply?
just programmatically focusing on the chosen widget until its interacted with
You mean like keyboard focus?
What do you mean "capture" the mouse? Record mouse events? The mouse move event (overrideable method) would probably be the way to go. Not sure if that triggers if the mouse isn't over the widget, though.
There's a ton of events like that, button down, up, etc.
Mouse capture, all mouse events after function call should go to the widget, even if the widget is not under the mouseโฆ.
If it doesn't work when it's not over the widget, you can use an input preprocessor to worse the widget to process everything.
Look at IInputProcessor and FSlateApplication::RegisterInputPreProcessor
Is the first option in a slate combobox expected to the be the 'reset' option? I'm always having weird issues with the slate comboboxes and it feels like I'm missing something in how they're supposed to be set up
Like, when the combo box is generated if you select the first option it never does anything unless you change to a different option and then change it back.
Combo boxes have no reset option.
When you create a combo box, you give it the initially selected thing. It's expected that what you give it is already selected.
I.e. it needs no additional selection.
Hello! I would like these two values in my struct to be displayed on the same row in the editor
(Like with TMaps or TMaps which need meta=(ForceInlineRow))
I followed this tutorial: https://benui.ca/unreal/tmap-same-row/ however it doesn't seem to work with array types (I tried it with non-array variable types and it works)
Would really appreciate any help ๐
USTRUCT(BlueprintType)
struct FTaggables
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<TObjectPtr<ATaggableBase>> TaggedTaggables;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<TObjectPtr<ATaggableBase>> TaggableChain;
FTaggables();
~FTaggables();
bool operator==(const FTaggables& Other) const
{
return TaggedTaggables == Other.TaggedTaggables
&& TaggableChain == Other.TaggableChain;
}
};```
#include "TaggablesCustomization.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "PropertyHandle.h"
#include "PropertyCustomizationHelpers.h"
void FTaggablesCustomization::CustomizeHeader(TSharedRef<IPropertyHandle> InStructPropertyHandle,
FDetailWidgetRow& HeaderRow,
IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
StructPropertyHandle = InStructPropertyHandle;
// Gets TaggedTaggables Key
TSharedPtr<IPropertyHandle> Key = StructPropertyHandle->GetChildHandle(0);
// Gets TaggableChain Value
TSharedPtr<IPropertyHandle> Value = StructPropertyHandle->GetChildHandle(1);
// Setup in the header row so that we still get the TArray dropdown
HeaderRow
.NameContent()
[
Key->CreatePropertyValueWidget()
]
.ValueContent()
.MaxDesiredWidth(0.0f)
[
Value->CreatePropertyValueWidget()
];
// This avoids making duplicate reset boxes
StructPropertyHandle->MarkResetToDefaultCustomized();
}
void FTaggablesCustomization::CustomizeChildren(TSharedRef<IPropertyHandle> InStructPropertyHandle,
IDetailChildrenBuilder& StructBuilder,
IPropertyTypeCustomizationUtils& StructCustomizationUtils)
{
}
Have you looked atg the array customisation itself? There's probably some kind of extra call to make. Or a different one
https://ikrima.dev/ue4guide/editor-extensions/detail-customization/array-builder/
I took a look at FDetailArrayBuilder but I'm tbh pretty out of my depth here
Might have to look more into it later
If you want the insert/duplicate/delete buttons to appear, you should be using the AddChildProperty() API, rather than AddChildContent(). You can then control whether the insert/duplicate/delete buttons appear on a per-entry basis by using IDetailPropertyRow:: ShowPropertyButtons (this gets you the some of ability to prevent entry deletion that ...
I'm defining a background colour but it doesn't seem to cover the entire content as it should
You mean the gap at the very top of the image?
figured it out, just had to add
.BorderImage(FAppStyle::Get().GetBrush("Brushes.Panel"))
is there a file i can look at to find all the inbuilt brush?
damn there are alot
Yes
is there a way in slate to call this details panel (it's the material instance editor) from inside an editor utility widget? (Either C++ way or Python I dont mind). I basically have a custom viewport and would like to call this window up to be parented inside the viewport and would be updated for each material that is selected...
So, to be clear, do you want to:
- Add a details panel to your widget; or,
- Access the details panel in the material instance editor.
?
Add details panel to my own custom widget
And the details panel would reflect the material instance editor properties and accessible options
I'm not sure how the property groups section works, tbh.
You'd have to look at the code.
But all the details panels work by taking a set of objects and display their properties, so it's likely some sort of object somewhere.
You can create details panels using the property editor module.
All you do it feed it an array of objects and it works the rest out. There are some setup parameters too.
This set me down a rabbit hole of requisites so I appreciate it, thanks mate!
Hey does anybody know how to fix Quixel Bridge on mac with unreal because everytime I try to open it it crashes
Quick question: Do I have to absolutely wrap a slate widget with UWidget just to contain it inside a UMG widget? Or can I somehow do that in-place?
Is that a #slate question?
A UMG widget has a slate backing widget, but there's no reason that that backing widget cannot have its own non-umg slate children.
That sounds like much more work and probably some weird bugs
I thought UE would have a quick and easy way to do that
Thanks tho
If i'm being honest I don't know what slate is but I though I would just give it a try to see of anyone knew how to help because I don't know how to use Quixel bridge otherwise and I need to use it
i am trying to create a window with different tabs
but the row where the tabs are displayed is too small for my liking
where would i apply such style so i can add a padding?
They aren't regular tabs. How are you making them?
i have a custom plugin with a window
and a class derived from SCompoundWidget
here i create the tabs
void SMyTestingWidget::Construct(const FArguments& InArgs)
{
TabManager = InArgs._TabManager;
TSharedRef<FWorkspaceItem> AppMenuGroup = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_EderTestingApp", "Eder Testing App"));
TabManager->RegisterTabSpawner(EderTestingTabs::Tab1Name, FOnSpawnTab::CreateRaw(this, &SMyTestingWidget::OnSpawnTab1))
.SetDisplayName(LOCTEXT("Tab1Title", "Tab 1"))
.SetGroup(AppMenuGroup);
TabManager->RegisterTabSpawner(EderTestingTabs::Tab2Name, FOnSpawnTab::CreateRaw(this, &SMyTestingWidget::OnSpawnTab2))
.SetDisplayName(LOCTEXT("Tab2Title", "Tab 2"))
.SetGroup(AppMenuGroup);
TabManager->RegisterTabSpawner(EderTestingTabs::Tab3Name, FOnSpawnTab::CreateRaw(this, &SMyTestingWidget::OnSpawnTab3))
.SetDisplayName(LOCTEXT("Tab3Title", "Tab 3"))
.SetGroup(AppMenuGroup);
const TSharedRef<FTabManager::FLayout> Layout = FTabManager::NewLayout("EderTestingLayout")
->AddArea
(
FTabManager::NewPrimaryArea()
->SetOrientation(Orient_Horizontal)
->Split
(
FTabManager::NewStack()
->AddTab(EderTestingTabs::Tab1Name, ETabState::OpenedTab)
->AddTab(EderTestingTabs::Tab2Name, ETabState::OpenedTab)
->AddTab(EderTestingTabs::Tab3Name, ETabState::OpenedTab)
)
);
ChildSlot
[
TabManager->RestoreFrom(Layout, TSharedPtr<SWindow>()).ToSharedRef()
];
}
while each tab is
TSharedRef<SDockTab> SMyTestingWidget::OnSpawnTab1(const FSpawnTabArgs& SpawnTabArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.CanEverClose(false)
[
SNew(STextBlock)
.Text(LOCTEXT("Tab1Content", "This is the content of Tab 1"))
];
}
and in my plugin module i do:
void FEderTestingModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
FEderTestingStyle::Initialize();
FEderTestingStyle::ReloadTextures();
FEderTestingCommands::Register();
PluginCommands = MakeShareable(new FUICommandList);
PluginCommands->MapAction(
FEderTestingCommands::Get().OpenPluginWindow,
FExecuteAction::CreateRaw(this, &FEderTestingModule::PluginButtonClicked),
FCanExecuteAction());
UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FEderTestingModule::RegisterMenus));
// Register the tab spawner for the main plugin tab
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(EderTestingTabName, FOnSpawnTab::CreateRaw(this, &FEderTestingModule::OnSpawnPluginTab))
.SetDisplayName(LOCTEXT("FEderTestingTabTitle", "Eder Testing"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
}
TSharedRef<SDockTab> FEderTestingModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
TSharedRef<SDockTab> DockTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.ContentPadding(FMargin(5,5));
TSharedRef<SMyTestingWidget> TestingWidget = SNew(SMyTestingWidget)
.TabManager(FGlobalTabmanager::Get()->NewTabManager(DockTab));
DockTab->SetContent(TestingWidget);
/*DockTab->SetPadding(FMargin(20, 20));*/
return DockTab;
}
Hmm. I'm not sure you can change the style of a tab.
they just feel really close to the top somehow
i thought maybe i have something wrong with the registering of the menus in my plugin entry point?
I don't disagree. They do look a little bad.
with
TSharedRef<SDockTab> DockTab = SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
.ContentPadding(FMargin(5,5));
``` i could make it a bit better but still they i have the feeling something is wrong there
slate is really confusing in the beginning
It is
That isn't padding the tab itself, though, just the tab contents.
Or maybe it is?
Idk
no no you are right
it also increases the padding of the "border" around the content
Does anyone have a good tutorial on Slate? General explanation of basics such as slate macros etc
The pinned qt to slate guide is pretty good.
can someone help me why i can't bind my static fuction to the onclicked delegate?
inside
TSharedRef<SDockTab> SMyTestingWidget::OnSpawnTab1(const FSpawnTabArgs& SpawnTabArgs)
{
// Other Stuff
SNew(SButton)
.Text(LOCTEXT("Button1", "This is a BUTTON"))
.OnClicked(FOnClicked::BindStatic(SMyTestingWidget::CreateFolder));
}
.hpp
static FReply CreateFolder();
.cpp
FReply SMyTestingWidget::CreateFolder()
{
UE_LOG(LogTemp, Warning, TEXT("ItWasFired"));
return FReply::Handled();
}
error is:
Error C2352 'TDelegate<FReply (void),FDefaultDelegateUserPolicy>::BindStatic': a call of a non-static member function requires an object
- You're missing a & on your function pointer!
- Have you tried just
.OnClicked(&SMyTestingWidget::CreateFolder);? That might work also.
I rarely bind to statics in slate events! ๐ฆ
I'm trying to make a custom custom graph with nodes.
I'm looking at GenericGraph and trying to re-make a minimalist version for my needs, however I haven't been able to figure out what is actualyl responsible for drawing the pin connections
I'm trying to get something like the behaviour tree nodes / pins where they connect vertically.
This is what i have so far. just trying to see if i can get get pointed in the right direction
graph connections are handled by a FConnectionDrawingPolicy usually. for the GenericGraph plugin it would be FConnectionDrawingPolicy_GenericGraph
Just started with Slate and noticed I deffo prefer raw binding
They can make sense, but only in limited cases. It's usually much better to either 1) just feed the data into the method without a binding or 2) use a sharedptr bind.
I suppose in your example, a static bind might make sense, but they generally don't.
If you're using static methods, that generally means you're using static objects/globals/etc. And that's not good.
For instance, the entire engine is plagued with GWorld used everywhere. That means that 99% of the systems break if you try to use them for something other than the one editor world that's loaded.
Are you saving strong references to those uobjects you're loading?
You mean are they class members?
Are they strong class members.
Slate doesn't support UPROPERTYs, even though you can just add them and the compiler won't care.
If you want to keep uassets loaded, best to store them in a TStrongObjectPtr in the class. Or use TObjectPtrs and inherit from FGCObject.
why is that not good? for example when i want the button to do editor stuff like create directories or sort assets the only thing i could use which is not a static method would be a UObject which i would need to specificly create isn't that a bit much for some editor stuff?
You don't have to use uobjects at all.
Using globals or static objects for command context is just really bad. You can read about the pitfalls of it on google.
so i should rather create non unreal reflection type classes ? or from which class should i derive then?
Yeah. You can do that.
Or you could create a subsystem?
An editor subsystem is basically a global, but it's 1 step up.
just out of curiosity
when i create a non reflection type class
should the object still be created with NewObject? or standard c++ ?
sorry for the stupid question but i had the thought that all classes in unreal should atleast derive from uobject
For non-uobjects, I would use the unreal smart pointers
TSharedPtr TSharedRef TWeakPtr
(and TUniquePtr)
okay so
TSharedPtr<MyNonUObjectClass> Foo = NewObject<MyNonUObjectClass>(this / nullptr);
?
TSharedRef<MyNonUObjectClass> Foo = MakeShared<MyNonUObjectClass>(constructor params)
oh MakeShared
i see so i need to initialize it at declaration
For a ref, yeah.
thank you for the insights! really appreciate it
With a ptr you can do TSharedPtr<MyClass> Foo; and it will just be null.
Or you can do = nullptr
These are ref counted, not proper gc, so you have to be careful with them.
If 2 objects hold storng refs to each other, they will never be destroyed, etc. ๐
yeah i thought so that GC won't help me there much but thats okay in my case i will implement a subsystem anyway since i never did and sounds useful but wanted to know how i would create non UObject types
You can always use std smart pointers too
