Download

Initializing Slate style

This is basically a re-post of a question I had asked on the AnswerHub and never got an answer to, with a bit more details hopefully so someone could help me figure out what I’ve done wrong. So a few weeks ago I started playing around with the idea of creating a new Slate widget that I could later implement into UMG. Unlike all the tutorials around, though, what I wanted to do was extend one of the basic Slate widgets, SBorder, and make my own text box in the style of the SMultiLineEditableTextBox, but using STextBlock instead of SEditableText, since all I wanted was a background image upon which I could display read-only text. Everything goes well, I write the code necessary to create the widget, then I create a style asset using this tutorial: https://wiki.unrealengine.com/Slate_Style_Sets_Part_2 and everything compiles perfectly, so I go and create the wrapper for UMG following the many examples from the engine’s UMG widgets. Then the engine crashes after I compile. Being used to this, I open Visual Studio and run a debug, and the compiler finds this error:

Assertion failed: IsValid() [File:C:\Program Files\Epic Games\4.13\Engine\Source\Runtime\Core\Public\Templates\SharedPointer.h] [Line: 769]

On line 34 of the code for the style set, which just so happens to be the Get() function:


// Copyright © 2016 TimeStop Software All Rights Reserved

#include "Libera_Me.h"
#include "FTextBoxStyleSet.h"
#include "SlateGameResources.h"

TSharedPtr<FSlateStyleSet> FTextBoxStyleSet::StyleSetInstance = NULL;

void FTextBoxStyleSet::Initialize()
{
	//We check whether the StyleSetInstance hasn't been set yet.
	if (!StyleSetInstance.IsValid())
	{
		StyleSetInstance = Create();
		FSlateStyleRegistry::RegisterSlateStyle(*StyleSetInstance);
	}
}

void FTextBoxStyleSet::Shutdown()
{
	FSlateStyleRegistry::UnRegisterSlateStyle(*StyleSetInstance);
	//Make sure that there is no more references to this container.
	ensure(StyleSetInstance.IsUnique());
	StyleSetInstance.Reset();
}

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

const ISlateStyle & FTextBoxStyleSet::Get()
{
	return *StyleSetInstance;
}

FName FTextBoxStyleSet::GetStyleSetName()
{
	static FName StyleSetName = TEXT("TextBoxStyles");
	return StyleSetName;
}

TSharedRef<FSlateStyleSet> FTextBoxStyleSet::Create()
{
	TSharedRef<FSlateStyleSet> StyleRef = FSlateGameResources::New(FTextBoxStyleSet::GetStyleSetName(), "/Game/UI/Styles", "/Game/UI/Styles");
	return StyleRef;
}

So I’m guessing the pointer is simply invalid at the time, but I have initialized it in the module:


// Copyright © 2016 TimeStop Software All Rights Reserved

#include "Libera_Me.h"

//Custom implementation of the Default Game Module
class FLiberaMeGameModule : public FDefaultGameModuleImpl
{
	/**
	* Called whenever the module is starting up. Unregister any Style Set that share
	* our Style Set's name, then initialize the Style Set.
	*/
	virtual void StartupModule() override
	{
		FSlateStyleRegistry::UnRegisterSlateStyle(FTextBoxStyleSet::GetStyleSetName());
		FTextBoxStyleSet::Initialize();
	}

	//Called whenever the module is shutting down. Tells the Style Set to shut down.
	virtual void ShutdownModule() override
	{
		FTextBoxStyleSet::Shutdown();
	}
};

IMPLEMENT_PRIMARY_GAME_MODULE(FLiberaMeGameModule, Libera_Me, "Libera_Me");

And now I’m completely out of ideas of why exactly this pointer is returning as invalid when even the StrategyGame code tells you to do it this way. I’ve included the header for the widget itself below, which is the only instance of the Get() function being used, if it’s of any use.


class LIBERA_ME_API STextBox : public SBorder
{

public:
	SLATE_BEGIN_ARGS(STextBox)
		: _Style(&FTextBoxStyleSet::Get().GetWidgetStyle<FDefaultTextBoxStyle>("DefaultTextBoxStyle"))
		, _TextStyle(&FCoreStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText"))
		, _ForegroundColor()
		, _BackgroundColor()
		, _Text()
		, _Font()
		, _ShadowOffset()
		, _ShadowColorAndOpacity()
		, _WrapTextAt(0.0f)
		, _AutoWrapText(false)
		, _WrappingPolicy(ETextWrappingPolicy::DefaultWrapping)
		, _Margin()
		, _LineHeightPercentage(1.0f)
		, _Justification(ETextJustify::Left)
		, _TextShapingMethod()
		, _TextFlowDirection()
		{}

		//The style used by the text box itself.
		SLATE_STYLE_ARGUMENT(FDefaultTextBoxStyle, Style)

		//The style used by the text, controls the font, color and shadow options.
		SLATE_STYLE_ARGUMENT(FTextBlockStyle, TextStyle)

		//Color applied to the text box's content. Overrides Style. Affects the font's color.
		SLATE_ATTRIBUTE(FSlateColor, ForegroundColor)

		//Color applied to the text box's background. Overrides Style. Affects the brush's color.
		SLATE_ATTRIBUTE(FSlateColor, BackgroundColor)

		//The text to be displayed in the text box.
		SLATE_ATTRIBUTE(FText, Text)

		//The font to use for the text. Overrides Style.
		SLATE_ATTRIBUTE(FSlateFontInfo, Font)

		//The drop shadow offset in pixels. Overrides Style.
		SLATE_ATTRIBUTE(FVector2D, ShadowOffset)

		//The color and opacity of the text's drop shadow. Overrides Style.
		SLATE_ATTRIBUTE(FLinearColor, ShadowColorAndOpacity)

		//The maximum length the text string can reach before it wraps to a new line. Zero or negative values prevents wrapping entirely.
		SLATE_ATTRIBUTE(float, WrapTextAt)

		//Whether or not to wrap the text based on the widget's computed horizontal space. Automatic wrapping can cause some visual artifacts.
		SLATE_ATTRIBUTE(bool, AutoWrapText)

		//The wrapping policy to use.
		SLATE_ATTRIBUTE(ETextWrappingPolicy, WrappingPolicy)

		//The amount of blank space to leave between the text and the text box's edges.
		SLATE_ATTRIBUTE(FMargin, Margin)

		//The amount to scale each line's height by.
		SLATE_ATTRIBUTE(float, LineHeightPercentage)

		//How the text should be aligned with the margin.
		SLATE_ATTRIBUTE(ETextJustify::Type, Justification)

		//How the glyphs should be drawn. Unset to use the default.
		SLATE_ARGUMENT(TOptional<ETextShapingMethod>, TextShapingMethod)

		//How the text should flow. (Left-to-Right or Right-to-Left)
		SLATE_ARGUMENT(TOptional<ETextFlowDirection>, TextFlowDirection)

	SLATE_END_ARGS()
	
	//Constructor
	STextBox();

	//Destructor
	~STextBox();

	//Construct this widget. Parameter: InArgs, the declaration data for this widget.
	void Construct(const FArguments& InArgs);

	//Returns the text currently displayed.
	FText GetText() const
	{
		return TextBlock->GetText();
	}

	//Sets the text to be displayed.
	void SetText(const TAttribute<FText>& InText);
	
	//Sets the style to be used for the text box. WARNING: This function will erase any overrides unless specified.
	void SetStyle(const FDefaultTextBoxStyle* InStyle, bool bEraseOverrides = true);

	//Sets the color for the text.
	void SetTextBoxForegroundColor(const TAttribute<FSlateColor>& InColorAndOpacity);

	//Sets the color for the background.
	void SetTextBoxBackgroundColor(const TAttribute<FSlateColor>& InColorAndOpacity);

	//Sets the font to assign to the text.
	void SetFont(const TAttribute<FSlateFontInfo>& InFont);

	//Sets the size of the text's drop shadow.
	void SetShadowOffset(const TAttribute<FVector2D>& InShadowOffset);

	//Sets the color for the drop shadow.
	void SetShadowColor(const TAttribute<FLinearColor>& InShadowColor);

	//Sets the value for WrapTextAt.
	void SetWrapTextAt(const TAttribute<float>& InWrapTextAt);

	//Sets the value for AutoWrapText.
	void SetAutoWrapText(const TAttribute<bool>& InAutoWrapText);

	//Sets the wrapping policy to use.
	void SetWrappingPolicy(const TAttribute<ETextWrappingPolicy>& InWrappingPolicy);

	//Sets the margin around the text area.
	void SetMargin(const TAttribute<FMargin>& InMargin);

	//Sets the line height percentage.
	void SetLineHeightPercentage(const TAttribute<float> InLineHeightPercent);

	//Sets the alignment for the text.
	void SetJustification(const TAttribute<ETextJustify::Type> InJustification);

	//Sets the text shaping method.
	void SetTextShapingMethod(const TOptional<ETextShapingMethod>& InTextShapingMethod);

	//Sets the text flow direction.
	void SetTextFlowDirection(const TOptional<ETextFlowDirection>& InTextFlowDirection);

protected:

	//The text widget used to display text.
	TSharedPtr<STextBlock> TextBlock;

	//The default style used by the text box.
	const FDefaultTextBoxStyle* Style;

	//The color to assign to the text when overriding the style.
	TAttribute<FSlateColor> ForegroundColorOverride;

	//The color to assign to the background when overriding the style.
	TAttribute<FSlateColor> BackgroundColorOverride;

	//The font to assign to the text when overriding the style.
	TAttribute<FSlateFontInfo> FontOverride;

	//The offset to assign to the drop shadow when overriding the style.
	TAttribute<FVector2D> ShadowOffsetOverride;

	//The color to assign to the drop shadow when overriding the style.
	TAttribute<FLinearColor> ShadowColorOverride;

	//Gets the current brush assigned to the text box.
	const FSlateBrush* GetBackgroundImage() const;

	//Gets the current foreground color.
	FSlateColor GetForegroundColor() const;

	//Gets the current background color.
	FSlateColor GetBackgroundColor() const;

	//Gets the current font assigned to the text.
	FSlateFontInfo GetFont() const;

	//Gets the current offset of the drop shadow.
	FVector2D GetShadowOffset() const;

	//Gets the current color and opacity of the drop shadow.
	FLinearColor GetShadowColorAndOpacity() const;


};

I found the problem. It was in the UMG wrapper, in the constructor for the widget:


UTextBoxWidget::UTextBoxWidget(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	STextBox::FArguments Defaults;
	WidgetStyle = *Defaults._Style;
}

I’m guessing that for some reason the UMG widget was initialized before the Style asset could be assigned to the pointer, so it failed to get it in the Slate widget’s argument list. Taking out those lines made everything work with no consequences as far as I can tell, even if they’re present in the code for the engine’s widgets.