void SDockingTabWell::BringTabToFront( int32 TabIndexToActivate )
{
	const bool bActiveIndexChanging = TabIndexToActivate != ForegroundTabIndex;
	if ( bActiveIndexChanging )
	{
		const int32 LastForegroundTabIndex = FMath::Min(ForegroundTabIndex, Tabs.Num()-1);

		// For positive indexes, don't go out of bounds on the array.
		ForegroundTabIndex = FMath::Min(TabIndexToActivate, Tabs.Num()-1);

		TSharedPtr<SDockingArea> MyDockArea = GetDockArea();
		if ( Tabs.Num() > 0 && MyDockArea.IsValid() )
		{
			const TSharedPtr<SDockTab> PreviousForegroundTab = (LastForegroundTabIndex == INDEX_NONE)
				? TSharedPtr<SDockTab>()
				: Tabs[LastForegroundTabIndex];

			const TSharedPtr<SDockTab> NewForegroundTab = (ForegroundTabIndex == INDEX_NONE)
				? TSharedPtr<SDockTab>()
				: Tabs[ForegroundTabIndex];
			
			MyDockArea->GetTabManager()->GetPrivateApi().OnTabForegrounded(NewForegroundTab, PreviousForegroundTab);
		}
	}

	// Always force a refresh, even if we don't think the active index changed.
	RefreshParentContent();
}
FReply SDockingTabWell::StartDraggingTab( TSharedRef<SDockTab> TabToStartDragging, FVector2D InTabGrabOffsetFraction, const FPointerEvent& MouseEvent )
{
	Tabs.Remove(TabToStartDragging);
	// We just removed the foreground tab.
	ForegroundTabIndex = INDEX_NONE;
	ParentTabStackPtr.Pin()->OnTabRemoved(TabToStartDragging->GetLayoutIdentifier());

	// Tha tab well keeps track of which tab we are dragging; we treat is specially during rendering and layout.
	TabBeingDraggedPtr = TabToStartDragging;
		
	TabGrabOffsetFraction = InTabGrabOffsetFraction;

	// We are about to start dragging a tab, so make sure its offset is correct
	this->ChildBeingDraggedOffset = ComputeDraggedTabOffset( MouseEvent.FindGeometry(SharedThis(this)), MouseEvent, InTabGrabOffsetFraction );

	// Start dragging.
	TSharedRef<FDockingDragOperation> DragDropOperation =
		FDockingDragOperation::New(
			TabToStartDragging,
			InTabGrabOffsetFraction,
			GetDockArea().ToSharedRef(),
			ParentTabStackPtr.Pin()->GetTabStackGeometry().Size
		);

	return FReply::Handled().BeginDragDrop( DragDropOperation );
}
void SDockingTabWell::RemoveAndDestroyTab(const TSharedRef<SDockTab>& TabToRemove, SDockingNode::ELayoutModification RemovalMethod)
{
	int32 TabIndex = Tabs.Find(TabToRemove);

	if (TabIndex != INDEX_NONE)
	{
		const TSharedPtr<SDockingTabStack> ParentTabStack = ParentTabStackPtr.Pin();

		// Remove the old tab from the list of tabs and activate the new tab.
		{
			BringTabToFront(TabIndex);
			Tabs.RemoveAt(TabIndex);
			// We no longer have a tab in the foreground.
			// This is important because BringTabToFront triggers notifications based on the difference in active tab indexes.
			ForegroundTabIndex = INDEX_NONE;

			// Now bring the last tab that we were on to the foreground
			BringTabToFront(FMath::Max(TabIndex-1, 0));
		}
		
		if ( ensure(ParentTabStack.IsValid()) )
		{
			ParentTabStack->OnTabClosed( TabToRemove );
			
			// We might be closing down an entire dock area, if this is a major tab.
			// Use this opportunity to save its layout
			if (RemovalMethod == SDockingNode::TabRemoval_Closed)
			{
				ParentTabStack->GetDockArea()->GetTabManager()->GetPrivateApi().OnTabClosing( TabToRemove );
			}

			if (Tabs.Num() == 0)
			{
				ParentTabStack->OnLastTabRemoved();
			}
			else
			{
				RefreshParentContent();
			}
		}


		GetDockArea()->CleanUp( RemovalMethod );
	}
}
void SDockingTabWell::BringTabToFront( int32 TabIndexToActivate )
{
	const bool bActiveIndexChanging = TabIndexToActivate != ForegroundTabIndex;
	if ( bActiveIndexChanging )
	{
		const int32 LastForegroundTabIndex = FMath::Min(ForegroundTabIndex, Tabs.Num()-1);

		// For positive indexes, don't go out of bounds on the array.
		ForegroundTabIndex = FMath::Min(TabIndexToActivate, Tabs.Num()-1);

		TSharedPtr<SDockingArea> MyDockArea = GetDockArea();
		if ( Tabs.Num() > 0 && MyDockArea.IsValid() )
		{
			const TSharedPtr<SDockTab> PreviousForegroundTab = (LastForegroundTabIndex == INDEX_NONE)
				? TSharedPtr<SDockTab>()
				: Tabs[LastForegroundTabIndex];

			const TSharedPtr<SDockTab> NewForegroundTab = (ForegroundTabIndex == INDEX_NONE)
				? TSharedPtr<SDockTab>()
				: Tabs[ForegroundTabIndex];
			
			MyDockArea->GetTabManager()->GetPrivateApi().OnTabForegrounded(NewForegroundTab, PreviousForegroundTab);

			FGlobalTabmanager::Get()->GetPrivateApi().OnTabForegrounded(NewForegroundTab, PreviousForegroundTab);
		}
	}

	// Always force a refresh, even if we don't think the active index changed.
	RefreshParentContent();

	// Update the native, global menu bar if a tab is in the foreground.
	if( ForegroundTabIndex != INDEX_NONE )
	{
		TSharedPtr<FTabManager> TabManager = Tabs[ForegroundTabIndex]->GetTabManager();
		if(TabManager == FGlobalTabmanager::Get())
		{
			FGlobalTabmanager::Get()->UpdateMainMenu(Tabs[ForegroundTabIndex], false);
		}
		else
		{
			TabManager->UpdateMainMenu(false);
		}
	}
}
FReply SDockingTabWell::StartDraggingTab( TSharedRef<SDockTab> TabToStartDragging, FVector2D InTabGrabOffsetFraction, const FPointerEvent& MouseEvent )
{
	const bool bCanLeaveTabWell = TabToStartDragging->GetTabManager()->GetPrivateApi().CanTabLeaveTabWell( TabToStartDragging );

	// We are about to start dragging a tab, so make sure its offset is correct
	this->ChildBeingDraggedOffset = ComputeDraggedTabOffset( MouseEvent.FindGeometry(SharedThis(this)), MouseEvent, InTabGrabOffsetFraction );

	// Tha tab well keeps track of which tab we are dragging; we treat is specially during rendering and layout.
	TabBeingDraggedPtr = TabToStartDragging;	
	TabGrabOffsetFraction = InTabGrabOffsetFraction;
	Tabs.Remove(TabToStartDragging);
	

	if (bCanLeaveTabWell)
	{
		// We just removed the foreground tab.
		ForegroundTabIndex = INDEX_NONE;
		ParentTabStackPtr.Pin()->OnTabRemoved(TabToStartDragging->GetLayoutIdentifier());

#if PLATFORM_MAC
		// On Mac we need to activate the app as we may be dragging a window that is set to be invisible if the app is inactive
		FPlatformMisc::ActivateApplication();
#endif

		// Start dragging.
		TSharedRef<FDockingDragOperation> DragDropOperation =
			FDockingDragOperation::New(
				TabToStartDragging,
				InTabGrabOffsetFraction,
				GetDockArea().ToSharedRef(),
				ParentTabStackPtr.Pin()->GetTabStackGeometry().Size
			);

		return FReply::Handled().BeginDragDrop( DragDropOperation );
	}
	else
	{
		return FReply::Handled().CaptureMouse(SharedThis(this));
	}
}
void SDockingTabWell::OnDragLeave( const FDragDropEvent& DragDropEvent )
{
	TSharedPtr<FDockingDragOperation> DragDropOperation = DragDropEvent.GetOperationAs<FDockingDragOperation>();
	if ( DragDropOperation.IsValid() )
	{
		TSharedRef<SDockingTabStack> ParentTabStack = ParentTabStackPtr.Pin().ToSharedRef();
		TSharedPtr<SDockTab> TabBeingDragged = this->TabBeingDraggedPtr;
		// Check for TabBeingDraggedPtr validity as it may no longer be valid when dragging tabs in game
		if ( TabBeingDragged.IsValid() && DragDropOperation->CanDockInNode(ParentTabStack, FDockingDragOperation::DockingViaTabWell) )
		{
			// Update the DragAndDrop operation based on this change.
			const int32 LastForegroundTabIndex = Tabs.Find(TabBeingDragged.ToSharedRef());

			// The user is pulling a tab out of this TabWell.
			TabBeingDragged->SetParent();

			// We are no longer dragging a tab in this tab well, so stop
			// showing it in the TabWell.
			this->TabBeingDraggedPtr.Reset();

			// Also stop showing its content; switch to the last tab that was active.
			BringTabToFront( FMath::Max(LastForegroundTabIndex-1, 0) );

			// We may have removed the last tab that this DockNode had.
			if ( Tabs.Num() == 0 )
			{
				// Let the DockNode know that it is no longer needed.
				ParentTabStack->OnLastTabRemoved();
			}

			GetDockArea()->CleanUp( SDockingNode::TabRemoval_DraggedOut );

			const FGeometry& DockNodeGeometry = ParentTabStack->GetTabStackGeometry();
			DragDropOperation->OnTabWellLeft( SharedThis(this), DockNodeGeometry );
		}
	}
}