Unreal Editor Window
- Fabio Pereira
- Aug 5, 2023
- 3 min read
Intro
I challenged myself to make an editor widget because I wanted to learn how to implement Slate UI and an editor tool. I had many difficulties while developing this, but I managed to overcome most of them by deep diving into Unreal's source code and with help from the community - specifically, Slackers Discord server and Epic Developer Community. I used GitHub and Sourcetree as my source control, and Miro with Kanban board as my project management software.

The Standalone Window
This Editor window only works with my custom actor class: MeshActor. The window has a details section for viewing the state of the selected actor(s). It has a text field: "Actor Name"; a Boolean field: "Can Actor Be Damaged"; and a numeric field: "Damage Multiplier". These fields collapse when there's no mesh actor selected. The "Spawn New Actor Details" section is used to spawn a new actor, by pressing a button, and set its mesh and material by using the fields of the same name before clicking the button.
Code
Unreal Version = 5.2
Widget Reflector

Slate Classes
SButton - Spawning An Actor
This was the first feature to cause problems; I was getting syntax errors on its delegate bind function. After a while of research and asking questions, I figured out that implementing it in the module class wasn't a good idea, so I created a custom Slate class which I continued to used for all the other elements. I also implemented the MoveInFrontofActor function that spawning simple actors use to move the new actor in front of the camera.


STextBlock - Actor Name
A Textblock was simple to implement, but I quickly moved on when I tried to change the font as it wasn't a simple, numeric value and I was out of time. Also, I programmed it so it would collapse itself if the user selected multiple actors - you can't display multiple names.
SCheckBox - CanBeDamaged bool
The Checkbox was a little more tricky to implement than the Textblock, as you can set it to undetermined when there's differing values in the selected actors. I implemented this, and added code so when you change the undetermined value, it sets it on all the selected actors.
SNumericEntryBox - DamageMultiplier float
This was another Slate element that could have an undetermined value, so I duplicated the behaviour from the Checkbox. This Slate widget was harder to implement because it was a template class, and the code that I was fishing from the source was using typenames that I couldn't seem to use. After much experimentation - refactoring the instantiation method, function signature and implementation - I figured out that you can simple use float as the type.
SObjectPropertyEntryBox - StaticMesh and Material
This was the hardest Slate class to find and get working. I used the Widget Reflector tool to figure out how the details panel in Unreal was built and what Slate classes it was using, but I couldn't find the classes they were using.

I then tried using the classes that Rider Intellisense found, but I got a linker error saying it couldn't find a header included in the other class.

I ask the Discord server for help and they said that header was private and then directed me to the Slate class I'm using now. I then lost a day to bug fixing my implementation of it as I mistakenly used the wrong function, but I was persistent and managed to spot it.
I used FSoftObjectPath to set the default values for the ObjectPropertyEntryBoxs. A community member said I should use a developer settings class to store the references, but I decided to use SoftObjectPath because I'm referencing Engine Meshes, they will always exist; it's a soft reference, not hard; and I just needed default values, so there's no need for developer settings.
FLevelEditorModule
At first, I was updating the UI using a tick function because I couldn't find a delegate to bind to, but, after I finished the UI, I decided to refactor this and find a more efficient method. After asking the community, I found what I was looking for in the source code: LevelEditorModule.OnActorSelectionChanged(). The implementation after that was simple.
Comments