Drag and Drop Slate SWindow

I’m working on making an inventory for my game, I want to make a SWindow that can be moved around. That SWindow would contain an SOverlay that contains a background image and a SUniformGrid.

I tried my best but I cant get the window to drag or move :frowning:

I think I’m going about this the right way but I am open to suggestions. I’m not crazy about UMG and I would rather stick with slate. Bellow is the full cpp code to my Inventory and my custom window class. I use my custom window class (EtherWindow) in my Inventory.

Inventory.cpp



#include "TheEther.h"
#include "Items/BaseItem.h"
#include "UI/EtherOverlay.h"
#include "UI/EtherWindow.h"
#include "UI/InventorySlot.h"
#include "UI/Inventory.h"

TSharedRef<SEtherWindow> myInventoryWindow = SNew(SEtherWindow);
TSharedRef<SEtherOverlay> myInventoryOverlay = SNew(SEtherOverlay);
TSharedRef<SUniformGridPanel> myInventoryGridPanel = SNew(SUniformGridPanel);

SInventory::SInventory()
{
	//Default values for inventory.
	myIsVisible = false;
	myIsConstructed = false;
	myNumRows = 3;
	myNumColumns = 3;
	myWidth = 700;
	myHeight = 700;
}

SInventory::~SInventory()
{

}

void SInventory::AddItem(ABaseItem* itemToAdd)
{
	bool itemWasAdded = false;

	//Find the next free slot in the inventory to add the item.
	for (int32 i = 0; i < mySlots.Num() && itemWasAdded == false; i++)
	{
		//Check to see if the slot is free.
		if (mySlots*->GetInventoryItem() == NULL)
		{
			mySlots*->SetInventoryItem(itemToAdd);
			itemWasAdded = true;
		}
	}

	//Check to see if the item was added successfully.
	if (itemWasAdded == true)
	{
		//Remove the item from the world since it was successfully picked up.
		itemToAdd->Destroy();
	}
}

void SInventory::InitializeSlots(UWorld* playersWorld)
{
	TSharedPtr<SInventorySlot> inventorySlotWidget;

	//Create the visual representation of the inventory.
	for (int32 currRowIndex = 0; currRowIndex < myNumRows; currRowIndex++)
	{
		for (int32 currColIndex = 0; currColIndex < myNumColumns; currColIndex++)
		{
			myInventoryGridPanel->AddSlot(currColIndex, currRowIndex)
			
				//Dynamically create the inventory slots and add them to the list.
				SAssignNew(inventorySlotWidget, SInventorySlot)
			];

			mySlots.Add(inventorySlotWidget.Get());
		}
	}
	
}

void SInventory::Construct(const FArguments& InArgs)
{
	FSlateBrush* imageSlateBrush = new FSlateBrush();
	
	this->OwnerHUD = InArgs._OwnerHUD;
	this->InventoryBackgroundTexture = InArgs._InventoryBackgroundTexture;

	//Convert our UTexture2D to an FSlateBrush.
	imageSlateBrush->SetResourceObject(InventoryBackgroundTexture.Get());

	//Prevent construction more than once.
	if (myIsConstructed == false)
	{
		FSlateApplication::Get().AddWindow(myInventoryWindow, false);

		myInventoryWindow->SetContent(SNew(SBox)
			.WidthOverride(myWidth)
			.HeightOverride(myHeight)
			
				SNew(SImage)
				.Image(imageSlateBrush)
			]);

		ChildSlot
			.VAlign(VAlign_Center)
			.HAlign(HAlign_Center)
			
				myInventoryWindow
			];

		myIsConstructed = true;
	}
}

void SInventory::ToggleVisibility()
{
	if (myIsVisible == true)
	{
		this->SetVisibility(EVisibility::Collapsed);
		myIsVisible = false;
	}
	else
	{
		this->SetVisibility(EVisibility::Visible);
		myIsVisible = true;
	}

	this->ToggleSlotsVisibility();
	myInventoryOverlay->ToggleVisibility();
}

void SInventory::ToggleSlotsVisibility()
{
	//Only show the slots if the inventory is visible.
	for (int i = 0; i < mySlots.Num(); i++)
	{
		if (myIsVisible == true)
		{
			mySlots*->SetVisibility(EVisibility::Visible);
		}
		else
		{
			mySlots*->SetVisibility(EVisibility::Collapsed);
		}
	}
}

///Getters
int SInventory::GetNumRows()
{
	return myNumRows;
}

int SInventory::GetNumColumns()
{
	return myNumColumns;
}

bool SInventory::GetIsVisible()
{
	return myIsVisible;
}


EtherWindow.cpp



#include "TheEther.h"
#include "UI/EtherWindow.h"

SEtherWindow::SEtherWindow()
{
	myIsVisible = false;
	this->bIsCursorDecoratorWindow = true;
	this->bDragAnywhere = true;
	this->bHasOSWindowBorder = true;
	this->bHasSizingFrame = true;
}

void SEtherWindow::Construct(const FArguments& InArgs)
{

}

FReply SEtherWindow::OnMouseMove(const FGeometry& geometry, const FPointerEvent& mouseEvent)
{
	this->MoveWindowTo(mouseEvent.GetScreenSpacePosition() + FSlateApplication::Get().GetCursorSize());
	
	return FReply::Handled();
}

void SEtherWindow::ToggleVisibility()
{
	myIsVisible = !myIsVisible;

	this->EnableWindow(myIsVisible);

	if (myIsVisible == true)
	{
		this->ShowWindow();
	}
	else
	{
		this->HideWindow();
	}
}

///Getters
bool SEtherWindow::GetIsVisible()
{
	return myIsVisible;
}


Hi,

You really shouldnt use SWindow for draggable window in games. Why? Check out other threads on this subject:
https://answers.unrealengine.com/questions/58283/moveable-window-inside-game-viewport.html
https://answers.unrealengine.com/questions/22903/using-window-for-game-ui.html

And here you can find overview of how it should be done:

I think there was also an UMG solution for inventory and draggable windows.

Cheers

Thanks for getting back to me, As I said previously I would prefer to stay away from UMG since it does not expose events and forces me to use kismet code. The Inventory tutorial provides is strictly just kismet code.

What is the point of SWindow and why does it seem to have support for dragging considering its member variables?

SWindow is a Slate representation of native OS window. It was designed to create windows for Editor tools and not to be used in games.

Ahh ok that explains a lot, I found this which is leading me in a better direction: