[Question] Slate - handling input actions, data binding, communication

So I have setup base shorcut/hot bar logic in my Character class:
Here I assign objects:

void ARPGCharacter::SetCurrentAbility(ARPGAbility* NewAbility)
{
	if(NewAbility)
	{
		//we don't want to override already assigned object. So if it is null we pass
	//it's very bad way of doing this. I think.
		if(!ActionButtonOneObj)
		{
			ActionButtonOneObj = NewAbility;
		}
		else if (!ActionButtonTwoObj)
		{
			ActionButtonTwoObj = NewAbility;
		}
	}
}

And here I execute actions on assigned objects:

void ARPGCharacter::ActionButtonOne()
{
	ARPGPlayerController* PC = Cast(Controller);
	if(PC)
	{
		ActionButtonOneObj->OnCast();
	}
}

void ARPGCharacter::ActionButtonTwo()
{
		ARPGPlayerController* PC = Cast(Controller);
	if(PC)
	{
		ActionButtonTwoObj->OnCast();
	}
}

BIND_ACTION(InputComponent, "ActionButtonOne", IE_Pressed, &ARPGCharacter::ActionButtonOne);
BIND_ACTION(InputComponent, "ActionButtonTwo", IE_Pressed, &ARPGCharacter::ActionButtonTwo);

It’s pretty bad and hard coded, but I was trying to get concept working.

What I really like to do is to:

Create slate UI element.

Bind this element to input action (or rather action to Slate). So functions ActionButtonOne() etc won’t be called directly but rather trough slate.So each slate button, would have assigned exactly one action. And pressing key on keyboard will call slate button, which will call assigned function.

Assign object trough slate. Button doesn’t really know what to do. What it knows, that it should trigger OnCast() event in some ability class. What class exactly is decided during runtime where user can assign particular ability to button.

I’ve got general concept here (I think), that after user drag ability to button (or select it from list), it will be assigned to ActionButtonOneObj, so the corresponding action will know what object exactly should be called.

I will be honest here I completely do not understand Slate. Especially parts about data binding, and how it communicate with other classes (like Pawns). Not looking for ready solution, but some general examples on how to handle data binding, input binding and communication would be very helpful.

Unless I over think issue here, and there is better way to handle this.

Slate is a lower level system than the input bindings that you have set up. When you make a widget you have to insert it somewhere in the live widget tree. For games, that insertion point is usually AddViewportWidgetContent(). Once you have some widget inserted there, it will show up on the screen and begin receiving events. If you look at SWidget.h you will find a list of all the events that can be handed to a Slate widget. Once you have some simple widget inserted on top of your game viewport and you are seeing it, you’ll probably find that the viewport has captured the mouse cursor and keyboard focus. You will probably want to be able to toggle that, which is described in this thread: https://udn.unrealengine.com/questions/189069/ingame-slate-ui-mouse-input.html

Hope this helps.

Hey thanks for help.

But that link is to UDN, and we can’t access it from here (;

Copied:


Ideally, the Viewport would support this with a single switch. However, it does not right now. Here is how you would work around it.

Presumably, you press some button (let’s say that it is [M]) to go from CameraMode to CursorMode. Your SItemManager widget will be where you manage your items. You can add your SItemManager widget into the game with AddViewportWidgetContent().

Going into CursorMode will amount to setting focus on the SItemManager. Your SItemManager widget will be notified when it has been focused, and this event is your opportunity to make appropriate changes to appear in CursorMode. For example, you’ll want to release mouse capture. You’ll also want to show some of the widgets used for managing the items.

When you want to dismiss this screen, you will just set focus back to the viewport. The viewport will aggressively modify the cursor state back to what is needed for camera mode. This is why we cache the WidgetFocusedBeforeMe upon being focused. That widget will be the viewport.

class SItemManager : public
SCompoundWidget { public:
SLATE_BEGIN_ARGS( SItemManager )
{}
SLATE_END_ARGS()

void Construct(const FArguments& InArgs)
{
   this->ChildSlot
   [
     // My Child Widgets
   ];
}

virtual void ToggleCursorMode()
{
   if (bInCursorMode)
   {
     bInCursorMode = false;
     FSlateApplication::Get().SetKeyboardFocus(WidgetFocusedBeforeMe);
     WidgetFocusedBeforeMe.Reset();
   }
   else
   {
     // ORDER of statements MATTERS!
     // Check OnKeyboardFocusReceived and

SupportsKeyboardFocus before moving
these statements.
bInCursorMode = true;
WidgetFocusedBeforeMe = FSlateApplication::Get().GetKeyboardFocusedWidget();
FSlateApplication::Get().SetKeyboardFocus(SharedThis(this),
EKeyboardFocusCause::Keyboard);
}

}

virtual FReply ExitCursorMode()
{
   if (bInCursorMode)
   {
     ToggleCursorMode();
   }

   return FReply::Handled().EndDragDrop();
}   private:

// BEGIN SWidget Interface

virtual bool SupportsKeyboardFocus() const OVERRIDE
{
   return bInCursorMode;
}

virtual FReply OnKeyboardFocusReceived(
   const FGeometry& MyGeometry,
    const FKeyboardFocusEvent& InKeyboardFocusEvent ) OVERRIDE
{
   // HACK: Work-around for held keys.
   GetPlayerController()->FlushPlayerInput();

   const bool bSwitchingToCursorMode =

InKeyboardFocusEvent.GetCause() ==
EKeyboardFocusCause::Keyboard;
if (bSwitchingToCursorMode)
{
// We are switching to CursorMode…
return FReply::Handled()
// … mouse input was captive by the game viewport
// mouse needs to be free to interact with menus
.ReleaseMouseCapture()
// Joystick should not control player while menus are up
.ReleaseJoystickCapture()
// The mouse should still not escape the boundaries of the game.
.LockMouseToWidget( SharedThis(this) );
}
else
{
// Upon focusing we were already in CursorMode, and the mouse
should
// move freely around the desktop until the player clicks on the
game.
return FReply::Handled().ReleaseMouseCapture().ReleaseJoystickCapture();
}
}

virtual FReply OnKeyDown(
   const FGeometry& MyGeometry,
    const FKeyboardEvent& InKeyboardEvent ) OVERRIDE
{
   const EKey PressedKey = InKeyboardEvent.GetKey();

   if(PressedKey == EKeys::Escape)
   {
     return ExitCursorMode();
   }
   else if (PressedKey != EKeys::Tilde)
   {
     // Incercept keyboard control; we do not want

camera/character control
// while in extended HUD.
// Make an exception for system level keys, e.g., Tilde;
return FReply::Handled();
}
else
{
return FReply::Unhandled();
}

}

virtual FReply OnPreviewMouseButtonDown(
   const FGeometry& MyGeometry,
    const FPointerEvent& MouseEvent ) OVERRIDE
{
   // When we are in cursor mode, clicking on the window should lock the

cursor to the window
// but should not alter anything the click would have done
(e.g. press a button).
// This preview event accomplishes that.

   if (bInCursorMode)
   {
     return
      // Notice we have NOT handled the event!
      FReply::Unhandled()
      // Just need to force lock the mouse to the viewport
      // area without affecting any other interaction.
      .LockMouseToWidget(SharedThis(this));
   }
   else
   {
     return FReply::Unhandled();
   }
}

// END SWidget Interface

/** In cursor mode we show an extended, interactive HUD and   */
bool bInCursorMode;
/**
 * We try to be a good citizen, and restore focus to whoever had focus

before we did.
* In this case it is probably the game viewport.
*/
TSharedPtr WidgetFocusedBeforeMe; };

Let me know if you run into trouble with implementing this.