Slate Tabs

From Epic Wiki

Overview

Author Syntopia

In this tutorial I show you how to make tabs. There are many ways to do this. With a checkbox or button style change, but for me it was the easiest way.

Tabs.png

Code:

MyStyle.h

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#pragma once

class FMyStyle 
{
public:
	static void Initialize();
	static void Shutdown();

	static const ISlateStyle& Get();

	static TSharedPtr<class ISlateStyle> StylePtr;

};

MyStyle.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "TabbedView.h"
#include "MyStyle.h"
#include "Engine.h"
#include "SlateBasics.h"
#include "SlateStyle.h"

#define IMAGE_BRUSH(RelativePath, ...)	FSlateImageBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__)

TSharedPtr<ISlateStyle> CreateStyle()
{
	TSharedPtr<FSlateStyleSet> Style = MakeShareable(new FSlateStyleSet("PreloadStyle"));
	Style->SetContentRoot(FPaths::GameContentDir() / "Slate");

	Style->Set("tab_normal", new IMAGE_BRUSH("tab_normal", FVector2D(256, 64)));
	Style->Set("tab_active", new IMAGE_BRUSH("tab_active", FVector2D(256, 64)));

	return Style;
}

#undef IMAGE_BRUSH


TSharedPtr<ISlateStyle> FMyStyle::StylePtr = NULL;

void FMyStyle::Initialize()
{
	if (!StylePtr.IsValid())
	{
		StylePtr = CreateStyle();
		FSlateStyleRegistry::RegisterSlateStyle(*StylePtr);
	}
}

void FMyStyle::Shutdown()
{
	FSlateStyleRegistry::UnRegisterSlateStyle(*StylePtr);
	ensure(StylePtr.IsUnique());
	StylePtr.Reset();
}

const ISlateStyle& FMyStyle::Get()
{
	return *StylePtr;	
}

TabbedView.h

#pragma once

#include "Engine.h"

TabbedView.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "TabbedView.h"
#include "MyStyle.h"

class MyModule : public FDefaultGameModuleImpl
{
public:
	virtual void StartupModule() override
	{
		FSlateStyleRegistry::UnRegisterSlateStyle("PreloadStyle");
		FMyStyle::Initialize();
	}

	virtual void ShutdownModule() override
	{
		FMyStyle::Shutdown();
	}
};

IMPLEMENT_PRIMARY_GAME_MODULE(MyModule, TabbedView, "TabbedView");

MyGameMode.h

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once

#include "MyGameMode.generated.h"

UCLASS(minimalapi)
class AMyGameMode : public AGameMode
{
	GENERATED_UCLASS_BODY()

};

MyGameMode.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "TabbedView.h"
#include "MyGameMode.h"
#include "MyHUD.h"


AMyGameMode::AMyGameMode(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// use our custom HUD class
	HUDClass = AMyHUD::StaticClass();
}

MyHUD.h

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once 

#include "MyHUD.generated.h"

class SMyUIWidget : public SCompoundWidget
{
	SLATE_BEGIN_ARGS(SMyUIWidget)
	{}
    /*See private declaration of OwnerHUD below.*/
	SLATE_ARGUMENT(TWeakObjectPtr<class AMyHUD>, OwnerHUD)
	/** The visual style of the button */
	SLATE_END_ARGS()
 
public:
	void Construct(const FArguments& InArgs);

	FReply FirstTabClicked();
	FReply SecondTabClicked();

	const FSlateBrush* GetFirstImageBrush() const;
	const FSlateBrush* GetSecondImageBrush() const;

private:
	TWeakObjectPtr<class AMyHUD> OwnerHUD;

	int32 TabIndex;

	int32 GetCurrentTabIndex() const
	{
		return TabIndex;
	}
	
};

UCLASS()
class AMyHUD : public AHUD
{
	GENERATED_UCLASS_BODY()

public:
	void BeginPlay();

	virtual void DrawHUD() override;

private:
	TSharedPtr<SMyUIWidget> MyUIWidget;

};

MyHUD.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "TabbedView.h"
#include "MyHUD.h"
#include "SWidgetSwitcher.h"
#include "MyStyle.h"

int FirstTabActive  = 1;
int SecondTabActive = 0;

int ftClick = 1;
int stClick = 0;

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

	TabIndex = 0;

	ChildSlot
		[
			SNew(SVerticalBox) 
			+ SVerticalBox::Slot()
			.FillHeight(0.1)

			+ SVerticalBox::Slot()
			.FillHeight(0.8)
			[
				SNew(SHorizontalBox)

				+ SHorizontalBox::Slot()
				.FillWidth(0.3)

				+ SHorizontalBox::Slot()
				.FillWidth(0.4)
				[
					SNew(SVerticalBox)
					+ SVerticalBox::Slot()
					.FillHeight(0.2)
					[
						SNew(SHorizontalBox)
						+ SHorizontalBox::Slot()
						[
							SNew(SButton)
							.ContentPadding(-3)
							.OnClicked(this, &SMyUIWidget::FirstTabClicked)
							[
								SNew(SVerticalBox)
								+ SVerticalBox::Slot()
								.HAlign(HAlign_Fill)
								.VAlign(VAlign_Fill)
								[
									SNew(SBorder)
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									.BorderImage(this, &SMyUIWidget::GetFirstImageBrush)
									[
										SNew(STextBlock)
										.Font(FSlateFontInfo("Veranda", 54))
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Text(FText::FromString("Page One"))
									]
								]
							]
						]

						+ SHorizontalBox::Slot()
						.FillWidth(0.1)

						+ SHorizontalBox::Slot()
						[
							SNew(SButton)
							.ContentPadding(-3)
							.OnClicked(this, &SMyUIWidget::SecondTabClicked)
							[
								SNew(SVerticalBox)
								+ SVerticalBox::Slot()
								.HAlign(HAlign_Fill)
								.VAlign(VAlign_Fill)
								[
									SNew(SBorder)
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									.BorderImage(this, &SMyUIWidget::GetSecondImageBrush)
									[
										SNew(STextBlock)
										.Font(FSlateFontInfo("Veranda", 54))
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Text(FText::FromString("Page Two"))
									]
								]
							]
						]
					]

					+ SVerticalBox::Slot()
					.FillHeight(0.8)
					[
						SNew(SWidgetSwitcher)
						.WidgetIndex(this, &SMyUIWidget::GetCurrentTabIndex)
						+ SWidgetSwitcher::Slot() 
						[
							SNew(SBorder)
							.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
							[
								SNew(SVerticalBox)
								+ SVerticalBox::Slot()
								.HAlign(HAlign_Center)
								.VAlign(VAlign_Center)
								[
									SNew(STextBlock)
									.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
									.Font(FSlateFontInfo("Veranda", 72))
									.Text(FText::FromString("Page One"))
								]
								+ SVerticalBox::Slot()
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									[
										SNew(STextBlock)
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Font(FSlateFontInfo("Veranda", 52))
										.Text(FText::FromString("Page One"))
									]
								+ SVerticalBox::Slot()
								.HAlign(HAlign_Center)
								.VAlign(VAlign_Center)
								[
									SNew(STextBlock)
									.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
									.Font(FSlateFontInfo("Veranda", 32))
									.Text(FText::FromString("Page One"))
								]
							]
						]
						+ SWidgetSwitcher::Slot() // Weapons
							[
								SNew(SBorder)
								.BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
								[
									SNew(SVerticalBox)
									+ SVerticalBox::Slot()
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									[
										SNew(STextBlock)
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Font(FSlateFontInfo("Veranda", 72))
										.Text(FText::FromString("Page Two"))
									]
									+ SVerticalBox::Slot()
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									[
										SNew(STextBlock)
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Font(FSlateFontInfo("Veranda", 52))
										.Text(FText::FromString("Page Two"))
									]
									+ SVerticalBox::Slot()
									.HAlign(HAlign_Center)
									.VAlign(VAlign_Center)
									[
										SNew(STextBlock)
										.ColorAndOpacity(FLinearColor(1, 1, 1, 1))
										.Font(FSlateFontInfo("Veranda", 32))
										.Text(FText::FromString("Page Two"))
									]
								]
							]
					]
				]

				+ SHorizontalBox::Slot()
				.FillWidth(0.3)
			]

			+ SVerticalBox::Slot()
			.FillHeight(0.1)
		];
}

const FSlateBrush* SMyUIWidget::GetFirstImageBrush() const
{
	FName BrushName;
	(FirstTabActive == 0) ? BrushName = TEXT("tab_normal") : BrushName = TEXT("tab_active");

	return FMyStyle::Get().GetBrush(BrushName);
}

const FSlateBrush* SMyUIWidget::GetSecondImageBrush() const
{
	FName BrushName;
	(SecondTabActive == 0) ? BrushName = TEXT("tab_normal") : BrushName = TEXT("tab_active");

	return FMyStyle::Get().GetBrush(BrushName);
}

AMyHUD::AMyHUD(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{

}

void AMyHUD::BeginPlay()
{
	SAssignNew(MyUIWidget, SMyUIWidget).OwnerHUD(this);

	if (GEngine->IsValidLowLevel())
	{
		GEngine->GameViewport->AddViewportWidgetContent(SNew(SWeakWidget).PossiblyNullContent(MyUIWidget.ToSharedRef()));
	}
 
	if (MyUIWidget.IsValid())
	{
		MyUIWidget->SetVisibility(EVisibility::Visible);
	}
}

void AMyHUD::DrawHUD()
{
	Super::DrawHUD();
}

FReply SMyUIWidget::FirstTabClicked()
{
	TabIndex = 0;

	stClick = 0;
	ftClick++;

	if (ftClick == 1)
	{
		if (FirstTabActive == 0)
		{
			FirstTabActive = 1;
			SecondTabActive = 0;
		}

	}

	return FReply::Handled();
}

FReply SMyUIWidget::SecondTabClicked()
{
	TabIndex = 1;

	ftClick = 0;
	stClick++;

	if (stClick == 1)
	{
		if (SecondTabActive == 0)
		{
			FirstTabActive = 0;
			SecondTabActive = 1;
		}

	}

	return FReply::Handled();
}

Summary

Set your level to use your new game mode, and run!

Source code: (~67KB)