Cannot compile my own version of SMultiLineEditableText?

Hey,
I made a copy from SMultiLineEditableText.h and SMultiLineEditableText.cpp out of Runtime/Slate/Public (Private) /Widgets, changed some headers and the class name obviously, and tried to compile it, but I get the following result: http://pastebin.com/YCfYeNrP
Unresolved externals point out that there is a target missing in my Build.cs. But which? Slate and SlateCore is included… Can someone help? Thanks :slight_smile:

It looks like some of the internals of FTextLayout need marking with SLATE_API ( FRunModel, FLineModel, and FTextOffsetLocations ).

Might I ask why you’ve needed to copy this class? The multi-line editable text is pretty extensible via custom text marshallers, plus it gives you a low-level access API to directly inject runs into the layout (as used by our WYSIWYG editors). The internals of SMultiLineEditableText have changed considerably between 4.11 and 4.12, so I can’t guarantee that your version will still build in the future (even if you fix those linker errors).

Yep, you’re right with that compatibilty stuff. I already used marshallers to create a fully working in-game script editor with syntax highlighting, but the reason why I need to go deeper into the SMultiLineEditableText is that I need a boolean which controls whether I am allowed to press Backspace or not. I want to build a terminal emulation, so I need to control when I am allowed to use the key and when the KeyEvent is passed to the text. Doing UMG stuff here doesn’t work unfortunatelly…

Edit: What if I create a class and inherit from SMultiLineEditableText? Am I able to override the Key event then and check for backspace?

You might want to consider making your own widget by deriving from SMultiLineEditableText and overriding SMultiLineEditableText::OnKeyChar to intercept the backspace key, TCHAR(8), and only forward on the request if you’re able to press the key. You’d probably need your own version of SMultiLineEditableTextBox too.

It’s still not particularly pretty, but it might be less of a maintenance headache long term.

Theres a SetOnKeyDownHandler( FOnKeyDown ) which I could use I think in order to set a key handler… This Function which serves as the handler returns a FReply so returning Unhandled should let the key through, and returning Handled shouldn’t. But right now, I have a problem assignig a function to it. I have the code

FReply SMyBoxClone::keyDown(args)
{
return FReply::Handled;
}

(I dont have the argument since im on mobile) and I tried to bind it using SetOnKeyDownHandler(FOnKeyDown::CreateRaw(this, &SMyBoxClone::keyDown)); in the constructor, but that crashes with “assert failed (IsValid())”…

That might work.

If it does, you don’t need to copy or derive anything, and you’d just make a composite widget containing the editable text, and then either use the OnKeyDownHandler in its constructor args, or use the SetOnKeyDownHandler function to set it after construction.

For example, assuming:

FReply SYourWidget::HandleKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent)
{
	if (KeyEvent.GetKey() == FKey::BackSpace)
	{
		return FReply::Handled();
	}
	
	return FReply::Unhandled();
}

You’d do either this:

void SYourWidget::Construct(const FArguments& InArgs)
{
	SNew(SMultiLineEditableText)
	// ...
	.OnKeyDownHandler(this, &SYourWidget::HandleKeyDown)
}

Or this:

void SYourWidget::Construct(const FArguments& InArgs)
{
	TSharedRef<SMultiLineEditableText> TextEdit = SNew(SMultiLineEditableText)
	// ...
	
	TextEdit->SetOnKeyDownHandler(FOnKeyDown::CreateSP(this, &SYourWidget::HandleKeyDown));
}

I tried that, but that doesnt block the usage of the backspace…

void STerminalBox::Construct(const FArguments& InArgs)
{
	SMultiLineEditableTextBox::Construct(InArgs);

	SetOnKeyDownHandler(FOnKeyDown::CreateSP(this, &STerminalBox::keydown));
}

FReply STerminalBox::keydown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
	if (InKeyEvent.GetKey() == EKeys::BackSpace)
	{
		UE_LOG(LogWindows, Log, TEXT("Backspace!"));
		return FReply::Handled();
	}
	else
	{
		UE_LOG(LogWindows, Log, TEXT("No Backspace!"));
		return FReply::Unhandled();
	}
}

If I copy the construct function from the SMultiLineEditableTextBox, it does say that some variables are private and cannot be read from my overriding class…

I found out that the SMultiLineEditableText has the function BackspaceChar() which controls the backspace. Overriding that and keeping the function empty makes the backspace not usable anymore. Only problem: I can’t call the function from the parent, since it’s private, and I don’t want to copy the whole thing (since it also relies on other variables of that class which are private)… Any method on how I could do that?

Doesn’t look like it without changing the engine source to make some things protected. In 4.12, everything in protected rather than private, but the bulk of the implementation (including the backspace handling) has been moved into its own class and shared between SEditableText and SMultiLineEditableText.

I can at least make sure you’ll be able to do this in 4.12, however that doesn’t help you in the shorter-term…

Hmm, so either I wait till 4.12, or I need to copy / paste a lot of stuff…

If I get the engine source code, and change the "private: " to "protected: ", I should be able to access it all… Does that bring any problems with it?

Remind me again why you couldn’t derive from SMultiLineEditableText? I’ve checked in 4.11, and the OnKeyChar function that you’d need to override is protected rather than private. You’d just need to intercept backspace there, but otherwise pass it on to the parent implementation.

It sounded like you were trying to copy the body of the SMultiLineEditableText function rather than just call through to the parent version, passing on any construction arguments that are required (I’m pretty sure that SListView gives an example of calling a parent class Construct function).

I tried to override BackspaceChar() because that is the function which is called when backspace is pressed, and that handles the char removing. Using a OnKeyChar function override works too, but returning Handled / Unhandled on a key press does not prevent the SMultiLineEditableText to add that letter. So with the backspace… So BackspaceChar() is in my eyes the function I need to override…

It was OnKeyDown that you tried to override the behaviour of before (using the handler delegate), but OnKeyChar is a different function that is directly responsible for calling through to the code that handles backspaces (backspace comes through to that function as TCHAR(8)).

Overriding OnKeyChar would also be a more future-proof solution, as BackspaceChar no longer exists on SMultiLineEditableText as of 4.12. I’d certainly give it a go before resorting to changing engine code.

No I have a UMG wrapper for STerminalBox which inherits SMultiLineEditableTextBox, and that doesnt spawn a SMultiLineEditableText, but STerminalText, which inherits that. For better understanding:
– UmgTerminal (UWidget)
---- creates STerminalBox (SMultiLineEditableTextBox)
------ creates STerminalText (SMultiLineEditableText)

I can not provide a callstack since it sais “You dont have the debugging symbols required to show a call stack.”

So I tried your approach, but unfortunatelly it crashes when I open the UMG blueprint or show the widget on the viewport. The code I used:
Header:

class STerminalText : public SMultiLineEditableText
{
public:
	bool bAllowBackspace = true;

protected:
	virtual FReply OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent) override;
	
};

Source:

FReply STerminalText::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& InCharacterEvent)
{
	UE_LOG(LogWindows, Log, TEXT("OnKeyChar with"));

	return FReply::Handled();
}

The compilation log (just posting because it contains a warning on 4.11 launcher version): http://pastebin.com/L9ZpDwHA

Crash log:

[2016.04.03-23.22.22:392][615]LogWindows:Error: Windows GetLastError: Der Vorgang wurde erfolgreich beendet. (0)
[2016.04.03-23.22.26:396][615]LogCrashTracker: 


[2016.04.03-23.22.26:535][615]LogCrashTracker: 


[2016.04.03-23.22.26:535][615]LogWindows:Error: === Critical error: ===
Assertion failed: IsValid() [File:D:\BuildFarm\buildmachine_++UE4+Release-4.11\Engine\Source\Runtime\Core\Public\Templates\SharedPointer.h] [Line: 739]

You have a UMG wrapper for STerminalText? Can you provide the callstack for the crash?

After a bit of trying and help on the slack chat I finally made it, but my problem, I need to overwrite the EditableText in my STerminalBox class, where the EditableText variable is a TSharedPtr EditableText. If I override this with TSharedPtr EditableText in my STerminalBox class, the engine crashes when I try to open the blueprint / add it to viewport. Same as before, Assertion failed IsValid(). Also the no debugging symbols thing.

I was able to fix everything up and make it working with OnKeyChar (the crash I had was due a include loop). Also, I could prevent the user from using the delete key for example with overriding OnKeyDown.