slate tutorials from Wraiyth

Not mine, but they helped me a ton and I would hate to have them go to waste. All credit goes to Wraiyth for these.
Start off by creating two files in your Private directory. Slate widgets are generally prefixed with S, so we’ll call is SMyGameSlateHUDWidget. Create a header and cpp file with that name (SMyGameSlateHUDWidget.cpp and SMyGameSlateHUDWidget.h)

Header code:



#pragma once

#include "Slate.h"

class SMyGameSlateHUDWidget : public SCompoundWidget
{
    SLATE_BEGIN_ARGS(SMyGameSlateHUDWidget)
        : _OwnerHUD()
    {}

    SLATE_ARGUMENT(TWeakObjectPtr<AShooterHUD>, OwnerHUD)

    SLATE_END_ARGS()

    /** Needed for every widget */
    void Construct(const FArguments& InArgs);

    /** returns a string of information to display */
    FString    GetSomeString() const;

private:
    /** Pointer to our parent HUD */
    TWeakObjectPtr<class AShooterHUD> OwnerHUD;
};
\CODE]
There's a few important parts here:

Inheriting from SCompoundWidget allows us to create our own Widget that contains other multiple widgets.
All Slate widgets need to include arguments sections. This is where you can initialize properties for this widget through Slate's syntax.
Every Slate widget contains a Construction function called Construct.

CPP file:


#include “ShooterGame.h”
#include “SMyGameSlateHUDWidget.h”

void SMyGameSlateHUDWidget::Construct(const FArguments& InArgs)
{
OwnerHUD = InArgs._OwnerHUD;

ChildSlot
    .VAlign(VAlign_Fill)
    .HAlign(HAlign_Fill)
    
        SNew(SOverlay)
        +SOverlay::Slot()
        .VAlign(VAlign_Top)
        .HAlign(HAlign_Center)
        
            SNew(STextBlock)
            .ShadowColorAndOpacity(FLinearColor::Black)
            .ColorAndOpacity(FLinearColor::White)
            .ShadowOffset(FIntPoint(-1,1))
            .Font(FSlateStyle::GetFontStyle("NormalFont"))
            .Text(this, &SMyGameSlateHUDWidget::GetSomeString)
        ]
    ];

}

FString SMyGameSlateHUDWidget::GetSomeString() const
{
return FString(TEXT(“Hello!”));
}\Code]
This part is pretty straightforward! We add a new SOverlay to this widget and inside that overlay we create an STextBlock with a variety of properties. Note the bind to GetSomeString for the text for the Widget. If we wanted that text to be conditional or changing (say a Round Timer) then we can perform functionality inside the GetSomeString function to return the text.
SNew will create a new Widget, and then all prpoerties of that widget are accessed and set afterwards.

Thats the entire widget itself! The next step is to actually add it in-game.
We do this inside the HUD.

Inside your HUD’s header file, add a TSharedPtr of your Widget class:



    /** HUD menu widget */
    TSharedPtr<class SMyGameSlateHUDWidget> MyHUDMenuWidget;
Finally, in DrawHUD(), we need to conditionally construct the Widget and add it to the Viewport
Code:
    if ( !MyHUDMenuWidget.IsValid() )
    {
        SAssignNew(MyHUDMenuWidget,SMyGameSlateHUDWidget)
            .OwnerHUD(this);

        if ( MyHUDMenuWidget.IsValid() )
        {
            GEngine->GameViewport->AddViewportWidgetContent(
                SNew(SWeakWidget)
                .PossiblyNullContent(MyHUDMenuWidget.ToSharedRef())
                );
        }
    }


The important part here is SAssignNew. As opposed to SNew which creates a widget, SAssignNew creates a widget and lets you assign it to a variable for later use. In this case the later use is adding it in AddViewportWidgetContent.

Fire up your game and you should have the word “Hello” printed in the top middle of the screen! Note that Slate doesn’t work in Play-In-Editor - you need to launch the game in a separate window to see the results.

Next tutorial I’ll probably cover Slate Styles and adding some additional controls to a basic HUD widget. Menus will come later

Slate Styles:

Start off by creating two files in your Private directory - MyGameStyle.cpp and MyGameStyle.h

MyGameStyle.h:



#pragma once

#include "Slate.h"

class MyGameStyle
{
public:
    /** overrides current slate style */
    static void ApplyStyle();

    /** reloads textures used by slate renderer */
    static void ReloadTextures();
};

MyGameStyle.cpp:


#include "ShooterGame.h"
#include "MyGameStyle.h"

void MyGameStyle::ApplyStyle()
{
    FSlateStyle& Style = FSlateStyle::GetInstance();

    //Fonts
    Style.Set("MyGame.HUDFont", FSlateFontInfo(TEXT("Roboto-Black"), 36));


}

void MyGameStyle::ReloadTextures()
{
    FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
}

The important part is the ApplyStyle function. This is where you set your styles for the various Slate controls. In this case we’re setting a Style called MyGame.HUDFont and setting it to use Roboto-Black font with a font size of 36. This function is where you’d add other styles. For instance, you could set a color as such:
Style.Set(“MyGame.SomeFontColor”, FLinearColor(0.6f,1.0f,0.6f));

Or an image like such:
Style.Set(“ShooterGame.MainMenu.BackgroundImage”, new FSlateImageBrush(TEXT(“texture://Game/UI/MainMenu/Background.Background”), ScreenSize));

To use this style, you first need to call ApplyStyle in the context that you are going to use it. In this case, its in the Construct function of our widget.
MyGameStyle::ApplyStyle();

You can then replace the Font in the STextBlock widget to reference your style:
.Font(FSlateStyle::GetFontStyle(“MyGame.HUDFont”))

Done! Fire up the game and your text up the top will be larger.

Sorry for the dumb question, but where can I download/find info about Slate ?

The documentation will likely be updated in due time, but it appears to have been left off as of now.

Looks like you have to open the plugin manager and enable Slate before to start to use it.

Thanks for bringing this post over. Sometime in the next few days, I’ll move this to the Tutorials section of the Wiki :slight_smile:

I’m asking myself the same question! Anyone?

[EDIT] Nevermind. I found it: https://docs.unrealengine.com/latest/INT/Programming/Slate/Architecture/index.html

The best way to learn Slate right now is by example. To find examples, you can use the widget reflector. In the editor, go to Window -> Developer Tools -> Widget Reflector. From a running game, hit ~ to bring up the console and type WidgetReflector. Now you can press the “Pick Widget” button and point at any piece of UI to inspect it. Press ESC to stop picking. Notice that there is a file name and line number listed for every Widget. You can now look at the code that created most widgets.

For the simplest example of writing UI, take a look at the SlateViewer program. It has a TestSuite with many examples of straight-forward Slate code that is generally unobstructed by the complexities of various use cases.

I haven’t started with Slate yet, but I just wanted to say, if this tutorial is worthy, add it to the wiki A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums

I had to change a few parameters, I got everything to build, but I’m getting linker errors. Hmm, guess I’ll have to take a look at the pre-built strategy game.



//MyUIWidget.h

#pragma once
#include "MyHUD.h"
#include "Slate.h"




class SMyUIWidget : public SCompoundWidget
{

SLATE_BEGIN_ARGS(SMyUIWidget)
: _OwnerHUD()
{}

SLATE_ARGUMENT(TWeakObjectPtr<AMyHUD>, OwnerHUD)

SLATE_END_ARGS()

/** Needed for every widget */
void Construct(const FArguments& InArgs);

/** returns a string of information to display */
FString GetSomeString() const;

private:
/** Pointer to our parent HUD */
TWeakObjectPtr<class AMyHUD> OwnerHUD;
};




//MyUIWidget.cpp

#include "MyProject.h"
#include "MyUIWidget.h"

void SMyUIWidget::Construct(const FArguments& InArgs)
{
OwnerHUD = InArgs._OwnerHUD;

ChildSlot
.VAlign(VAlign_Fill)
.HAlign(HAlign_Fill)

SNew(SOverlay)
+SOverlay::Slot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Center)

SNew(STextBlock)
.ShadowColorAndOpacity(FLinearColor::Black)
.ColorAndOpacity(FLinearColor::White)
.ShadowOffset(FIntPoint(-1,1))
.Font(FSlateFontInfo("Veranda", 16))
.Text(FText::FromString("asdf"))
]
];
}

FString SMyUIWidget::GetSomeString() const
{
return FString(TEXT("Hello!"));
}


I’ve gotten a little further, but still getting errors and now I have no idea how to fix them. The documentation is no help, it needs to provide complete examples of working code (aka idioms) in a start-to-finish manner, not random broken function calls with ambiguous explanations. As it is, the only way to understand the documentation would be to learn Slate, at which point you would want a reference manual not a “getting started” guide. Anyway, here’s my code, I modified the tutorial above to get it down to a single linker error. Once I get it to build/work I’ll spend the time going through it line by line itt.



1>  MyActor.cpp
1>C:\Users\\Unreal Projects\MyProject\Source\MyProject\MyUIWidget.cpp(8): error C2220: warning treated as error - no 'object' file generated
1>C:\Users\\Unreal Projects\MyProject\Source\MyProject\MyUIWidget.cpp(8): warning C4273: 'SMyUIWidget::Construct' : inconsistent dll linkage
1>          c:\users	rae\documents\unreal projects\myproject\source\myproject\MyUIWidget.h(21) : see previous definition of 'Construct'
1>  -------- End Detailed Actions Stats -----------------------------------------------------------




//MyUIWidget.h



#include "MyHUD.h"
#include "Core.h"
#include "PrimitiveTypes.h"
#include "DrawElements.h"
#include "Events.h"


class SLATE_API SMyUIWidget :
	public SCompoundWidget
{
public:
	// Needed for every widget
	void Construct(
		const TAttribute<FString> & InToolTipText,
		const TSharedPtr<SToolTip> & InToolTip,
		const TAttribute< TOptional<EMouseCursor::Type> > & InCursor,
		const TAttribute<bool> & InEnabledState,
		const TAttribute<EVisibility> & InVisibility,
		const FName& InTag);

	SLATE_BEGIN_ARGS(SMyUIWidget)
		: _OwnerHUD()
		{}

	SLATE_ARGUMENT(TWeakObjectPtr<AMyHUD>, OwnerHUD)

	SLATE_END_ARGS()

private:
	// Pointer to our parent HUD
	TWeakObjectPtr<class AMyHUD> OwnerHUD;
};



//MyUIWidget.cpp

#include "MyProject.h"
#include "MyUIWidget.h"


void SMyUIWidget::Construct(
	const TAttribute<FString> & InToolTipText,
	const TSharedPtr<SToolTip> & InToolTip,
	const TAttribute< TOptional<EMouseCursor::Type> > & InCursor,
	const TAttribute<bool> & InEnabledState,
	const TAttribute<EVisibility> & InVisibility,
	const FName& InTag)
{

	/*
OwnerHUD = InArgs._OwnerHUD;

ChildSlot
.VAlign(VAlign_Fill)
.HAlign(HAlign_Fill)

SNew(SOverlay)
+SOverlay::Slot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Center)

SNew(STextBlock)
.ShadowColorAndOpacity(FLinearColor::Black)
.ColorAndOpacity(FLinearColor::White)
.ShadowOffset(FIntPoint(-1,1))
.Font(FSlateFontInfo("Veranda", 16))
.Text(FText::FromString("asdf"))
]
];
*/
}



Here is the code for the previous definition.



	void Construct(
		const TAttribute<FString> & InToolTipText ,
		const TSharedPtr<SToolTip> & InToolTip ,
		const TAttribute< TOptional<EMouseCursor::Type> > & InCursor ,
		const TAttribute<bool> & InEnabledState ,
		const TAttribute<EVisibility> & InVisibility,
		const FName& InTag );


PROGRESS

I’ve gotten a basic “skeleton widget” to compile. I don’t think it will do anything, but here it is. Maybe from here the documentation will be more useful.



//MyUIWidget.h

#pragma once

#include "MyHUD.h"
#include "Slate.h"

//class declare
class SMyUIWidget : public SCompoundWidget
{
public:
	SLATE_BEGIN_ARGS(SMyUIWidget)
	{}

	SLATE_ARGUMENT(TWeakObjectPtr<AMyHUD>, OwnerHUD)

	SLATE_END_ARGS()

	/** needed for every widget */
	void Construct(const FArguments& InArgs);

private:
	/** Pointer to our parent HUD */
	TWeakObjectPtr<class AMyHUD> OwnerHUD;
};




//MyUIWidget.cpp

#include "MyProject.h"
#include "MyUIWidget.h"


void SMyUIWidget::Construct(const FArguments& InArgs)
{
	OwnerHUD = InArgs._OwnerHUD;
}



This is some of the nastiest design I’ve ever worked with, it even makes oldschool Win32 programming seem easy/fun.

Just to fill in the color of an SNew argument, I’ve gone through about 6 classes/struts that do nothing but wrap functoin call and do half a dozen implicit conversions just to get a data structure Slate can work with. It’s simply disgusting.

The only conclusion I can come to is that we’re supposed to be designing 4-6 classes for each widget, because half a dozen half a dozen line function-arguments (a function that takes two arguments, which are two function calls, that take 2-3 arguments each, that take 2-3 function calls each and so forth…) aren’t how good C++ is written.

For example,


.ColorAndOpacity(this, FLinearColor(FColor(255, 213, 160, GetCurrentOpacity() * 255))

is bad

what exactly would you like to do? Do you want to have a color parameter in your widget? What kind of widget would you like to make? Specify your question to make it easier to help you.

I was just trying to get some widget class to build so I could start tinkering with it. I the way I do these things is just start off with the most basic build I can and then start adding things to it / changing things around until I get a feel for the library then I start actually putting in work towards a goal.

I’ve made some more progress, but I’m having trouble with PDB files at the moment, my entire build environment just died on me and I’m not sure why. I think it has something to do with the way I built the engine, it’s weird but instead of having the build platforms I had about 12 different build options, 4 debug, 4 debug engine, 4 debug editor, 4 developer, 4 developer engine, 4 developer game, and then 4 debug-development options etc etc…

Anyway, I had a working build of “Hello, Slate World!” right before things went nuts. I’m planning on making a tutorial on the wiki when I return my environment to some level of sanity, it will cover how to get “Hello, Slate World!” to build from a freshly made project and cover all the required classes, buildfile modifications, a widget class, a custom HUD class, and how to use that custom HUD in your game.

Trying to get a grip on Slate as well, but I’ve run into a weird compiler error that says it can’t find the <WidgetClassName>.generated.h file … The examples above doesn’t contain that include so at first I assumed it doesn’t need it - but if I don’t have that include, the compiler complains about it not being there…

Not sure where to go from here - I was wondering if you guys could confirm or deny that it indeed belongs in the header and maybe why I’d get this compiler error?

Thanks in advance!

My tutorial is up. All code is current with 4.0.1 and it takes you all the way through “Hello Slate!” from a clean-install all the way through to a working build. I haven’t commented up the code yet, but I’ll be massaging this thing for the next few days, it will only get bigger better and more descriptive as I continue to flesh it out.

Where can we find this SlateViewerProgram ?

It’s in the editor.

Window => Developer Tools => Widget Reflector

Unless Slate Viewer is something else.

yeah thanks, but I was wondering if it was something else because of the "It has a TestSuite with many examples of straight-forward Slate code ". What/Where is the Test Suite ?

Edit: I looked at the engine code, SlateViewer seems to be a standalone version of the Widget Reflector tool. And it calls a function about restoring a test suite…

If you get the Unreal source, its under Engine\Source\Programs\SlateViewer. It calls a test suite (RestoreSlateTestSuite()) which is in Engine/Source/Runtime/Slate/Private/Testing/STestSuite.cpp.

If you compile the code, you can run the SlateViewer app. It is a standalone slate app. It gives an overview of all widget possibilities. However it asserts on some operations.

Personally, I am having trouble wrapping my head around how Slate works, especially creating in-game UIs with it. How to create menus, delegates, how to invoke it (from HUD class? from elsewhere?). Docs say “examples abound”, and they do, but are really hard to figure out. Well, for me anyway :slight_smile:

We need code samples for menus, buttons, delegates. Bleakwise’s tut is a start, but much more needed.

A visual editor would be a godsend, so I can actually code a game instead of learning Slate’s dirty tricks :stuck_out_tongue: