Options to spawn several SDockTabs instances?

Hello.
I am in the process of extending the editor as a module and I have added buttons through ToolbarExtender.

From the button actions, I spawn SDockTabs and populate them with content (dummy data so far). Although the tab spawning works correctly, I would like to get more details on the usage of the tab spawners and possible drawbacks for the method I use.

While implementing it, I also found some pieces of undocumented code that I hope someone can help me clarify.

About InsertNewDocumentTab

Create a new TabManager from a simple SDockTab. Here I followed the SlateViewer project, I only care about the SpawnTestSuite1 and the DocumentsTestTab (inside STestSuite). I want to follow the same parent-child between SpawnTestSuite1 and DocumentsTestTab: TestSuite1Tab is created as a new tab manager and later registers a tab spawner for the DocumentsTestTab . A new tab is spawned with the method InsertNewDocumentTab

Why is the function called InsertNewDocumentTab instead of InsertNewTab? What’s the context of the Document word in this function? I am concerned because I am planning to later include a nested viewport tab, details tab and more.

InsertNewDocumentTab also requires an ESearchPreference enum, can someone explain me what’s the difference in using FTabManager::ESearchPreference::RequireClosedTab & PreferLiveTab?

About dynamically generating Id on tabs

When spawning a NewTab I want to be able to change the label of “MyTabTile” in runtime.

.Label(NSLOCTEXT("MyTabTitle", "TabTitle", "My Tab Title"));

I tried the simplest method looking at STimelineTrack code

TAttribute NameAttribute; 

TSharedRef NewSpawnedTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)
	.Label(NameAttribute);

But I don’t understand how to initialize without callbacks the TAttribute, is it possible? Could you point me an example in the engine that uses a simple initialization? I used this piece of code as a reference

TAttribute CurrentAssetTitle = TAttribute::Create(TAttribute::FGetter::CreateSP(this, &SFlipbookKeyframeWidget::GetKeyframeAssetName));

Please elaborate what does the CreateSP work? With that clear, I would probably be able to assign a variable without introducing a function.
My major problem using the callback approach, is that the function should be contained within a class based on SCompoundWidget. Any change I can assign the function to CreateSP without being an SCompountWidget?

Should I also UnregisterTabSpawner

When creating my own Tab Manager and spawning tabs through it, should I also make sure to unregister the TabSpawners?

Restoring a layout from my own TabManager

I noticed that when using the FGlobalTabmanager::Get()->RegisterTabSpawner, the layout of the tabs is saved when re-opening the editor, but it doesn’t work the same way when using my own tab manager.
Can you point out the missing pieces to have my own TabManager layout being restored after re-opening the editor?

I hope I made my self clear, looking forward some help.

Regards

Why is the function called InsertNewDocumentTab instead of InsertNewTab?

This is somewhat of a misnomer. What Document really refers to is that you are responsible for managing the restoration of this tab. It will not be automatically saved into a layout.

InsertNewDocumentTab also requires an ESearchPreference enum, can someone explain me what’s the difference in using FTabManager::ESearchPreference::RequireClosedTab & PreferLiveTab?

Because Document tabs are not saved into layouts, you are responsible for restoring them. As such, you need to tell the FTabManager where to spawn the tab. You do this by providing the name of another tab that IS saved in the layout. The search preference determines whether we prefer an open tab, or whether the tab next to which we spawn should be a closed tab whose location is saved in the layout.

Any change I can assign the function to CreateSP without being an SCompountWidget?

CreateSP is a mechanism for creating a delegate to a shared pointer object. SCompoundWidget is a SharedPtr. There are others. in all, you can use:

  • CreateSP : create delegate to a member function on an object pointed to by a Shared Pointer
  • CreateUObject : create delegate to a member function on a UObject
  • CreateRaw : create delegate to a member function on a vanilla C++ pointer
  • CreateLambda : create a delegate from a lambda
  • CreateStatic : create a delegate to a free C++ function.

However, in the case of your label, it is sufficient to do something like this:

TSharedRef NewSpawnedTab = SNew(SDockTab)
.TabRole(ETabRole::DocumentTab)
.Label(this, &SMyWidget::GetSpawnedTabName);

If you are not spawning from a widget, you can use .Label_UObject(), .Label_Raw, .Label_Lambda() or .Label_Static() in a similar manner.

When creating my own Tab Manager and spawning tabs through it, should I also make sure to unregister the TabSpawners?

Yes. You should.

Can you point out the missing pieces to have my own TabManager layout being restored after re-opening the editor?

Look for uses of SetOnPersistLayout in the codebase. There are several examples. That’s a delegate that will be invoked when your tab manager should save its layout. We have utility methods for saving the persistent layout structure into a .ini file, which is what you find most of the examples are doing.

Hope this helps.

Hi,

We think this post contains useful information which we would like to share with our public UE4 community. With your approval, we would like to make a copy of this post on the public AnswerHub which includes the discussion but strips out your username and company name. Please let us know if you are okay with this.

Thanks!

Thank you for sharing your information Nick it definitely help us.
We will make sure to use all what you described and follow up the thread once we are done testing it.
Regards.

Hi,

Please share to the community. I also found all the answers very useful, specially for the Labeling options which are very deep in the macros and only few of them can be found in practice in 4.8.

Again, thank you for your support.