How does the Editor Mode plugin delete toolbars?

  1. I want to remove the toolbar and the parent controls below to make this window a truly empty window


2. I want to add a custom widget, for example, I write an SCompoundWidget to fill this window (after removing the parent widgets of the toolbar and detail widgets)

  1. I want to have two tabs on the right side, like in the animation mode?

Regarding the third point, I imitated FControlRigEditModeToolkit and wrote:

.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

/**
 * This is the module definition for the editor mode. You can implement custom functionality
 * as your plugin module starts up and shuts down. See IModuleInterface for more extensibility options.
 */
class FDigitalHumanEditorModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

.cpp:

// Copyright Epic Games, Inc. All Rights Reserved.

#include "DigitalHumanEditorEditorModeToolkit.h"
#include "DigitalHumanEditorEditorMode.h"
#include "Engine/Selection.h"

#include "Modules/ModuleManager.h"
#include "PropertyEditorModule.h"
#include "IDetailsView.h"
#include "EditorModeManager.h"
#include "Toolkits/AssetEditorModeUILayer.h"

#define LOCTEXT_NAMESPACE "DigitalHumanEditorEditorModeToolkit"

FDigitalHumanEditorEditorModeToolkit::FDigitalHumanEditorEditorModeToolkit()
{
}

void FDigitalHumanEditorEditorModeToolkit::Init(const TSharedPtr<IToolkitHost>& InitToolkitHost, TWeakObjectPtr<UEdMode> InOwningMode)
{
	FModeToolkit::Init(InitToolkitHost, InOwningMode);
   RequestModeUITabs();
   TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();
   if (ModeUILayerPtr.IsValid())
   {
       ModeUILayerPtr->GetTabManager()->TryInvokeTab(FName(TEXT("DigitalHumanOutlinerTab")));
   }

}

void FDigitalHumanEditorEditorModeToolkit::GetToolPaletteNames(TArray<FName>& PaletteNames) const
{
	PaletteNames.Add(NAME_Default);
}


FName FDigitalHumanEditorEditorModeToolkit::GetToolkitFName() const
{
	return FName("DigitalHumanEditorEditorMode");
}

FText FDigitalHumanEditorEditorModeToolkit::GetBaseToolkitName() const
{
	return LOCTEXT("DisplayName", "DigitalHumanEditorEditorMode Toolkit");
}


void FDigitalHumanEditorEditorModeToolkit::RequestModeUITabs()
{
    if (ModeUILayer.IsValid())
    {
        TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();
        TSharedRef<FWorkspaceItem> MenuGroup = ModeUILayerPtr->GetModeMenuCategory().ToSharedRef();

        ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(FName(TEXT("DigitalHumanOutlinerTab")));

        ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(FName(TEXT("DigitalHumanOutlinerTab")), FOnSpawnTab::CreateStatic(&FDigitalHumanEditorEditorModeToolkit::SpawnOutlinerTab))
            .SetDisplayName(LOCTEXT("DigitalHumanOutlinerTab", "Digital Human Outliner"))
            .SetTooltipText(LOCTEXT("DigitalHumanOutlinerTabTooltip", "Show Digital Human Outliner."))
            .SetGroup(MenuGroup)
            .SetIcon(FSlateIcon(TEXT("DigitalHumanEditorStyle"), TEXT("DigitalHuman.Outliner")));

        ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(FName(TEXT("DigitalHumanSpacePickerTab")));
        ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(FName(TEXT("DigitalHumanSpacePickerTab")), FOnSpawnTab::CreateStatic(&FDigitalHumanEditorEditorModeToolkit::SpawnSpacePickerTab))
            .SetDisplayName(LOCTEXT("DigitalHumanSpacePickerTab", "Digital Human Space Picker"))
            .SetTooltipText(LOCTEXT("DigitalHumanSpacePickerTabTooltip", "Show Digital Human Space Picker."))
            .SetGroup(MenuGroup)
            .SetIcon(FSlateIcon(TEXT("DigitalHumanEditorStyle"), TEXT("DigitalHuman.SpacePicker")));

        ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(FName(TEXT("DigitalHumanDetailsTab")));
        ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(FName(TEXT("DigitalHumanDetailsTab")), FOnSpawnTab::CreateStatic(&FDigitalHumanEditorEditorModeToolkit::SpawnDetailsTab))
            .SetDisplayName(LOCTEXT("DigitalHumanDetailsTab", "Digital Human Details"))
            .SetTooltipText(LOCTEXT("DigitalHumanDetailsTabTooltip", "Show Digital Human Details."))
            .SetGroup(MenuGroup)
            .SetIcon(FSlateIcon(TEXT("DigitalHumanEditorStyle"), TEXT("DigitalHuman.Details")));
    }
}

TSharedRef<SDockTab> FDigitalHumanEditorEditorModeToolkit::SpawnOutlinerTab(const FSpawnTabArgs& Args)
{
    UE_LOG(LogTemp, Warning, TEXT("SpawnOutlinerTab called"));
    return SNew(SDockTab)
        [
            SNew(STextBlock).Text(LOCTEXT("DigitalHumanOutlinerTabContent", "Digital Human Outliner Content"))
        ];
}

TSharedRef<SDockTab> FDigitalHumanEditorEditorModeToolkit::SpawnSpacePickerTab(const FSpawnTabArgs& Args)
{
    UE_LOG(LogTemp, Warning, TEXT("SpawnOutlinerTab called"));
    return SNew(SDockTab)
        [
            SNew(STextBlock).Text(LOCTEXT("DigitalHumanSpacePickerTabContent", "Digital Human Space Picker Content"))
        ];
}

TSharedRef<SDockTab> FDigitalHumanEditorEditorModeToolkit::SpawnDetailsTab(const FSpawnTabArgs& Args)
{
    UE_LOG(LogTemp, Warning, TEXT("SpawnOutlinerTab called"));
    return SNew(SDockTab)
        [
            SNew(STextBlock).Text(LOCTEXT("DigitalHumanDetailsTabContent", "Digital Human Details Content"))
        ];
}
#undef LOCTEXT_NAMESPACE

But now there is a problem, as long as the RequestMode Tabs function is there, no matter whether there is code in this function, switching modes will not have any effect.

References:

ControlRigEditModeToolkit.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SWidget.h"
#include "EditorModes.h"
#include "Toolkits/BaseToolkit.h"
#include "EditorModeManager.h"
#include "EditMode/SControlRigEditModeTools.h"
#include "EditMode/ControlRigEditMode.h"

class SControlRigTweenWidget;

class FControlRigEditModeToolkit : public FModeToolkit
{
public:
	friend class SControlRigTweenWidget;

	FControlRigEditModeToolkit(FControlRigEditMode& InEditMode)
		: EditMode(InEditMode)
	{
		
	}

	/** IToolkit interface */
	virtual FName GetToolkitFName() const override { return FName("AnimationMode"); }
	virtual FText GetBaseToolkitName() const override { return NSLOCTEXT("AnimationModeToolkit", "DisplayName", "Animation"); }
	virtual class FEdMode* GetEditorMode() const override { return &EditMode; }
	virtual TSharedPtr<class SWidget> GetInlineContent() const override { return ModeTools; }
	virtual bool ProcessCommandBindings(const FKeyEvent& InKeyEvent) const override
	{
		if (EditMode.GetCommandBindings() && EditMode.GetCommandBindings()->ProcessCommandBindings(InKeyEvent))
		{
			return true;
		}
		return false;
	}
	virtual void Init(const TSharedPtr<IToolkitHost>& InitToolkitHost) override;

	/** Mode Toolbar Palettes **/
	virtual void GetToolPaletteNames(TArray<FName>& InPaletteName) const override;
	virtual FText GetToolPaletteDisplayName(FName PaletteName) const override;
	virtual void BuildToolPalette(FName PaletteName, class FToolBarBuilder& ToolbarBuilder) override;

	/** Modes Panel Header Information **/
	virtual FText GetActiveToolDisplayName() const override;
	virtual FText GetActiveToolMessage() const override;
	virtual void OnToolPaletteChanged(FName PaletteName) override;

	void TryInvokeToolkitUI(const FName InName);
	bool IsToolkitUIActive(const FName InName) const;

	/** For updating tween values via hot keys*/
	void GetToNextActiveSlider();
	bool CanChangeAnimSliderTool() const;
	void DragAnimSliderTool(double Val);
	void ResetAnimSlider();
	void StartAnimSliderTool();
public:
	static const FName PoseTabName;
	static const FName MotionTrailTabName;
	static const FName TweenOverlayName;
	static const FName SnapperTabName;
	static const FName DetailsTabName;
	static const FName OutlinerTabName;
	static const FName SpacePickerTabName;

protected:

	void CreateAndShowTweenOverlay();
	void TryShowTweenOverlay();
	void RemoveAndDestroyTweenOverlay();
	void TryRemoveTweenOverlay();

	void UpdateTweenWidgetLocation(const FVector2D InLocation);

	FMargin GetTweenWidgetPadding() const;

	/* FModeToolkit Interface */
	virtual void RequestModeUITabs() override;
	virtual void InvokeUI() override;

	void UnregisterAndRemoveFloatingTabs();

private:


private:
	/** The edit mode we are bound to */
	FControlRigEditMode& EditMode;
	TSharedPtr<SWidget> TweenWidgetParent;
	TSharedPtr<SControlRigTweenWidget> TweenWidget;


	FVector2D InViewportTweenWidgetLocation;
	/** The tools widget */
	TSharedPtr<SControlRigEditModeTools> ModeTools;

};

ControlRigEditModeToolkit.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

/**
* Control Rig Edit Mode Toolkit
*/
#include "EditMode/ControlRigEditModeToolkit.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SWidget.h"
#include "EditorModes.h"
#include "Toolkits/BaseToolkit.h"
#include "EditorModeManager.h"
#include "EditMode/SControlRigEditModeTools.h"
#include "EditMode/ControlRigEditMode.h"
#include "Modules/ModuleManager.h"
#include "EditMode/SControlRigBaseListWidget.h"
#include "EditMode/SControlRigTweenWidget.h"
#include "EditMode/SControlRigSnapper.h"
#include "Tools/SMotionTrailOptions.h"
#include "Toolkits/AssetEditorModeUILayer.h"
#include "Widgets/Docking/SDockTab.h"
#include "EditMode/ControlRigEditModeSettings.h"
#include "EditMode/SControlRigDetails.h"
#include "EditMode/SControlRigOutliner.h"
#include "EditMode/SControlRigSpacePicker.h"
#include "LevelEditor.h"
#include "SLevelViewport.h"

#define LOCTEXT_NAMESPACE "FControlRigEditModeToolkit"

namespace 
{
	static const FName AnimationName(TEXT("Animation")); 
	const TArray<FName> AnimationPaletteNames = { AnimationName };
}

const FName FControlRigEditModeToolkit::PoseTabName = FName(TEXT("PoseTab"));
const FName FControlRigEditModeToolkit::MotionTrailTabName = FName(TEXT("MotionTrailTab"));
const FName FControlRigEditModeToolkit::SnapperTabName = FName(TEXT("SnapperTab"));
const FName FControlRigEditModeToolkit::TweenOverlayName = FName(TEXT("TweenOverlay"));
const FName FControlRigEditModeToolkit::OutlinerTabName = FName(TEXT("ControlRigOutlinerTab"));
const FName FControlRigEditModeToolkit::DetailsTabName = FName(TEXT("ControlRigDetailsTab"));
const FName FControlRigEditModeToolkit::SpacePickerTabName = FName(TEXT("ControlRigSpacePicker"));

void FControlRigEditModeToolkit::Init(const TSharedPtr<IToolkitHost>& InitToolkitHost)
{
	SAssignNew(ModeTools, SControlRigEditModeTools, SharedThis(this), EditMode, EditMode.GetWorld());

	FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");

	FDetailsViewArgs DetailsViewArgs;

	DetailsViewArgs.bUpdatesFromSelection = false;
	DetailsViewArgs.bLockable = false;
	DetailsViewArgs.bAllowSearch = false;
	DetailsViewArgs.NameAreaSettings = FDetailsViewArgs::HideNameArea;
	DetailsViewArgs.bHideSelectionTip = true;
	DetailsViewArgs.bSearchInitialKeyFocus = false;
	DetailsViewArgs.DefaultsOnlyVisibility = EEditDefaultsOnlyNodeVisibility::Automatic;
	DetailsViewArgs.bShowOptions = false;
	DetailsViewArgs.bAllowMultipleTopLevelObjects = true;

	DetailsView = PropertyEditorModule.CreateDetailView(DetailsViewArgs);
	FModeToolkit::Init(InitToolkitHost);
}

void FControlRigEditModeToolkit::GetToolPaletteNames(TArray<FName>& InPaletteName) const
{
	InPaletteName = AnimationPaletteNames;
}

FText FControlRigEditModeToolkit::GetToolPaletteDisplayName(FName PaletteName) const
{
	if (PaletteName == AnimationName)
	{
		FText::FromName(AnimationName);
	}
	return FText();
}

void FControlRigEditModeToolkit::BuildToolPalette(FName PaletteName, class FToolBarBuilder& ToolBarBuilder)
{
	if (PaletteName == AnimationName)
	{
		ModeTools->CustomizeToolBarPalette(ToolBarBuilder);
	}
}

void FControlRigEditModeToolkit::OnToolPaletteChanged(FName PaletteName)
{

}

void FControlRigEditModeToolkit::TryInvokeToolkitUI(const FName InName)
{
	TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();

	if (InName == MotionTrailTabName)
	{
		FTabId TabID(MotionTrailTabName);
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(TabID);
	}
	else if (InName == PoseTabName)
	{
		FTabId TabID(PoseTabName);
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(TabID);
	}
	else if (InName == SnapperTabName)
	{
		FTabId TabID(SnapperTabName);
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(TabID);
	}
	else if (InName == OutlinerTabName)
	{
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::TopRightTabID);
	}
	else if (InName == SpacePickerTabName)
	{
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::BottomLeftTabID);
	}
	else if (InName == DetailsTabName)
	{
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::BottomRightTabID);
	}
	else if (InName == TweenOverlayName)
	{
		if(TweenWidgetParent)
		{ 
			RemoveAndDestroyTweenOverlay();
		}
		else
		{
			CreateAndShowTweenOverlay();
		}
	}
}

bool FControlRigEditModeToolkit::IsToolkitUIActive(const FName InName) const
{
	if (InName == TweenOverlayName)
	{
		return TweenWidgetParent.IsValid();
	}

	TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();
	return ModeUILayerPtr->GetTabManager()->FindExistingLiveTab(FTabId(InName)).IsValid();
}

FText FControlRigEditModeToolkit::GetActiveToolDisplayName() const
{
	return ModeTools->GetActiveToolName();
}

FText FControlRigEditModeToolkit::GetActiveToolMessage() const
{

	return ModeTools->GetActiveToolMessage();
}

TSharedRef<SDockTab> SpawnPoseTab(const FSpawnTabArgs& Args)
{
	return SNew(SDockTab)
		[
			SNew(SControlRigBaseListWidget)
		];
}

TSharedRef<SDockTab> SpawnSnapperTab(const FSpawnTabArgs& Args)
{
	return SNew(SDockTab)
		[
			SNew(SControlRigSnapper)
		];
}

TSharedRef<SDockTab> SpawnMotionTrailTab(const FSpawnTabArgs& Args)
{
	return SNew(SDockTab)
		[
			SNew(SMotionTrailOptions)
		];
}

TSharedRef<SDockTab> SpawnOutlinerTab(const FSpawnTabArgs& Args, FControlRigEditMode* InEditorMode)
{
	return SNew(SDockTab)
		[
			SNew(SControlRigOutliner, *InEditorMode)
		];
}

TSharedRef<SDockTab> SpawnSpacePickerTab(const FSpawnTabArgs& Args, FControlRigEditMode* InEditorMode)
{
	return SNew(SDockTab)
		[
			SNew(SControlRigSpacePicker, *InEditorMode)
		];
}

TSharedRef<SDockTab> SpawnDetailsTab(const FSpawnTabArgs& Args, FControlRigEditMode* InEditorMode)
{
	return SNew(SDockTab)
		[
			SNew(SControlRigDetails, *InEditorMode)
		];
}


void FControlRigEditModeToolkit::CreateAndShowTweenOverlay()
{
	FVector2D NewTweenWidgetLocation = GetDefault<UControlRigEditModeSettings>()->LastInViewportTweenWidgetLocation;

	if (NewTweenWidgetLocation.IsZero())
	{
		const FVector2D ActiveViewportSize = GetToolkitHost()->GetActiveViewportSize();
		NewTweenWidgetLocation.X = ActiveViewportSize.X / 2.0f;
		NewTweenWidgetLocation.Y = ActiveViewportSize.Y - 100.0f;
		
	}
	UpdateTweenWidgetLocation(NewTweenWidgetLocation);

	SAssignNew(TweenWidgetParent, SHorizontalBox)

		+ SHorizontalBox::Slot()
		.FillWidth(1.0f)
		.VAlign(VAlign_Top)
		.HAlign(HAlign_Left)
		.Padding(TAttribute<FMargin>(this, &FControlRigEditModeToolkit::GetTweenWidgetPadding))
		[
			SAssignNew(TweenWidget, SControlRigTweenWidget)
			.InOwningToolkit(SharedThis(this))
		];

	TryShowTweenOverlay();
}

void FControlRigEditModeToolkit::GetToNextActiveSlider()
{
	if (TweenWidgetParent && TweenWidget)
	{
		TweenWidget->GetToNextActiveSlider();
	}
}
bool FControlRigEditModeToolkit::CanChangeAnimSliderTool() const
{
	return (TweenWidgetParent && TweenWidget);
}

void FControlRigEditModeToolkit::DragAnimSliderTool(double Val)
{
	if (TweenWidgetParent && TweenWidget)
	{
		TweenWidget->DragAnimSliderTool(Val);
	}
}
void FControlRigEditModeToolkit::ResetAnimSlider()
{
	if (TweenWidgetParent && TweenWidget)
	{
		TweenWidget->ResetAnimSlider();
	}
}

void FControlRigEditModeToolkit::StartAnimSliderTool()
{
	if (TweenWidgetParent && TweenWidget)
	{
		TweenWidget->StartAnimSliderTool();
	}
}
void FControlRigEditModeToolkit::TryShowTweenOverlay()
{
	if (TweenWidgetParent)
	{
		GetToolkitHost()->AddViewportOverlayWidget(TweenWidgetParent.ToSharedRef());
	}
}

void FControlRigEditModeToolkit::RemoveAndDestroyTweenOverlay()
{
	TryRemoveTweenOverlay();
	if (TweenWidgetParent)
	{
		TweenWidgetParent.Reset();
		TweenWidget.Reset();
	}
}

void FControlRigEditModeToolkit::TryRemoveTweenOverlay()
{
	if (IsHosted() && TweenWidgetParent)
	{
		if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr<FLevelEditorModule>(TEXT("LevelEditor")))
		{
			if (TSharedPtr<ILevelEditor> LevelEditor = LevelEditorModule->GetFirstLevelEditor())
			{
				for (TSharedPtr<SLevelViewport> LevelViewport : LevelEditor->GetViewports())
				{
					if (LevelViewport.IsValid())
					{
						if (TweenWidgetParent)
						{
							LevelViewport->RemoveOverlayWidget(TweenWidgetParent.ToSharedRef());
						}
					}
				}
			}
		}
	}
}

void FControlRigEditModeToolkit::UpdateTweenWidgetLocation(const FVector2D InLocation)
{
	const FVector2D ActiveViewportSize = GetToolkitHost()->GetActiveViewportSize();
	FVector2D ScreenPos = InLocation;

	const float EdgeFactor = 0.97f;
	const float MinX = ActiveViewportSize.X * (1 - EdgeFactor);
	const float MinY = ActiveViewportSize.Y * (1 - EdgeFactor);
	const float MaxX = ActiveViewportSize.X * EdgeFactor;
	const float MaxY = ActiveViewportSize.Y * EdgeFactor;
	const bool bOutside = ScreenPos.X < MinX || ScreenPos.X > MaxX || ScreenPos.Y < MinY || ScreenPos.Y > MaxY;
	if (bOutside)
	{
		// reset the location if it was placed out of bounds
		ScreenPos.X = ActiveViewportSize.X / 2.0f;
		ScreenPos.Y = ActiveViewportSize.Y - 100.0f;
	}
	InViewportTweenWidgetLocation = ScreenPos;
	UControlRigEditModeSettings* ControlRigEditModeSettings = GetMutableDefault<UControlRigEditModeSettings>();
	ControlRigEditModeSettings->LastInViewportTweenWidgetLocation = ScreenPos;
	ControlRigEditModeSettings->SaveConfig();
}

FMargin FControlRigEditModeToolkit::GetTweenWidgetPadding() const
{
	return FMargin(InViewportTweenWidgetLocation.X, InViewportTweenWidgetLocation.Y, 0, 0);
}

void FControlRigEditModeToolkit::RequestModeUITabs()
{
	FModeToolkit::RequestModeUITabs();
	if (ModeUILayer.IsValid())
	{
		TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();
		TSharedRef<FWorkspaceItem> MenuGroup = ModeUILayerPtr->GetModeMenuCategory().ToSharedRef();

		FMinorTabConfig DetailTabInfo;
		DetailTabInfo.OnSpawnTab = FOnSpawnTab::CreateStatic(&SpawnDetailsTab, &EditMode);
		DetailTabInfo.TabLabel = LOCTEXT("ControlRigDetailTab", "Anim Details");
		DetailTabInfo.TabTooltip = LOCTEXT("ControlRigDetailTabTooltip", "Show Details For Selected Controls.");
		ModeUILayerPtr->SetModePanelInfo(UAssetEditorUISubsystem::BottomRightTabID, DetailTabInfo);

		FMinorTabConfig OutlinerTabInfo;
		OutlinerTabInfo.OnSpawnTab = FOnSpawnTab::CreateStatic(&SpawnOutlinerTab, &EditMode);
		OutlinerTabInfo.TabLabel = LOCTEXT("AnimationOutlinerTab", "Anim Outliner");
		OutlinerTabInfo.TabTooltip = LOCTEXT("AnimationOutlinerTabTooltip", "Control Rig Controls");
		ModeUILayerPtr->SetModePanelInfo(UAssetEditorUISubsystem::TopRightTabID, OutlinerTabInfo);
		/* doesn't work as expected
		FMinorTabConfig SpawnSpacePickerTabInfo;
		SpawnSpacePickerTabInfo.OnSpawnTab = FOnSpawnTab::CreateStatic(&SpawnSpacePickerTab, &EditMode);
		SpawnSpacePickerTabInfo.TabLabel = LOCTEXT("ControlRigSpacePickerTab", "Control Rig Space Picker");
		SpawnSpacePickerTabInfo.TabTooltip = LOCTEXT("ControlRigSpacePickerTabTooltip", "Control Rig Space Picker");
		ModeUILayerPtr->SetModePanelInfo(UAssetEditorUISubsystem::TopLeftTabID, SpawnSpacePickerTabInfo);
		*/

		ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(SnapperTabName);
		ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(SnapperTabName, FOnSpawnTab::CreateStatic(&SpawnSnapperTab))
			.SetDisplayName(LOCTEXT("ControlRigSnapperTab", "Control Rig Snapper"))
			.SetTooltipText(LOCTEXT("ControlRigSnapperTabTooltip", "Snap child objects to a parent object over a set of frames."))
			.SetGroup(MenuGroup)
			.SetIcon(FSlateIcon(TEXT("ControlRigEditorStyle"), TEXT("ControlRig.SnapperTool")));
		ModeUILayerPtr->GetTabManager()->RegisterDefaultTabWindowSize(SnapperTabName, FVector2D(300, 325));

		ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(PoseTabName);
		ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(PoseTabName, FOnSpawnTab::CreateStatic(&SpawnPoseTab))
			.SetDisplayName(LOCTEXT("ControlRigPoseTab", "Control Rig Pose"))
			.SetTooltipText(LOCTEXT("ControlRigPoseTabTooltip", "Show Poses."))
			.SetGroup(MenuGroup)
			.SetIcon(FSlateIcon(TEXT("ControlRigEditorStyle"), TEXT("ControlRig.PoseTool")));
		ModeUILayerPtr->GetTabManager()->RegisterDefaultTabWindowSize(PoseTabName, FVector2D(675, 625));

		ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(MotionTrailTabName);
		ModeUILayerPtr->GetTabManager()->RegisterTabSpawner(MotionTrailTabName, FOnSpawnTab::CreateStatic(&SpawnMotionTrailTab))
			.SetDisplayName(LOCTEXT("MotionTrailTab", "Motion Trail"))
			.SetTooltipText(LOCTEXT("MotionTrailTabTooltip", "Display motion trails for animated objects."))
			.SetGroup(MenuGroup)
			.SetIcon(FSlateIcon(TEXT("ControlRigEditorStyle"), TEXT("ControlRig.EditableMotionTrails")));
		ModeUILayerPtr->GetTabManager()->RegisterDefaultTabWindowSize(MotionTrailTabName, FVector2D(425, 575));

		ModeUILayer.Pin()->ToolkitHostShutdownUI().BindSP(this, &FControlRigEditModeToolkit::UnregisterAndRemoveFloatingTabs);


	}
};

void FControlRigEditModeToolkit::InvokeUI()
{
	FModeToolkit::InvokeUI();

	if (ModeUILayer.IsValid())
	{
		TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::TopRightTabID);
		// doesn't work as expected todo ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::TopLeftTabID);
		ModeUILayerPtr->GetTabManager()->TryInvokeTab(UAssetEditorUISubsystem::BottomRightTabID);
	}	
}

void FControlRigEditModeToolkit::UnregisterAndRemoveFloatingTabs()
{
	if (FSlateApplication::IsInitialized())
	{
		RemoveAndDestroyTweenOverlay();
		if (ModeUILayer.IsValid())
		{
			TSharedPtr<FAssetEditorModeUILayer> ModeUILayerPtr = ModeUILayer.Pin();

			TSharedPtr<SDockTab> MotionTrailTab = ModeUILayerPtr->GetTabManager()->FindExistingLiveTab(FTabId(MotionTrailTabName));
			if (MotionTrailTab)
			{
				MotionTrailTab->RequestCloseTab();
			}
			ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(MotionTrailTabName);

			TSharedPtr<SDockTab> SnapperTab = ModeUILayerPtr->GetTabManager()->FindExistingLiveTab(FTabId(SnapperTabName));
			if (SnapperTab)
			{
				SnapperTab->RequestCloseTab();
			}
			ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(SnapperTabName);
		
			TSharedPtr<SDockTab> PoseTab = ModeUILayerPtr->GetTabManager()->FindExistingLiveTab(FTabId(PoseTabName));
			if (PoseTab)
			{
				PoseTab->RequestCloseTab();
			}
			ModeUILayerPtr->GetTabManager()->UnregisterTabSpawner(PoseTabName);
		}
	}
}

#undef LOCTEXT_NAMESPACE

Two Chinese posts:

https://zhuanlan.zhihu.com/p/641521580

https://zhuanlan.zhihu.com/p/662689335