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 ); } } }