FVector2D SWeakWidget::ComputeDesiredSize() const { TSharedRef<SWidget> ReferencedWidget = WeakChild.GetWidget(); if ( ReferencedWidget != SNullWidget::NullWidget && ReferencedWidget->GetVisibility() != EVisibility::Collapsed ) { return ReferencedWidget->GetDesiredSize(); } return FVector2D::ZeroVector; }
void FGridSlotExtension::ExtendSelection(const TArray< FWidgetReference >& Selection, TArray< TSharedRef<FDesignerSurfaceElement> >& SurfaceElements) { SelectionCache = Selection; TSharedRef<SButton> UpArrow = SNew(SButton) .Text(LOCTEXT("UpArrow", "↑")) .ContentPadding(FMargin(6, 2)) .OnClicked(this, &FGridSlotExtension::HandleShiftRow, -1); TSharedRef<SButton> DownArrow = SNew(SButton) .Text(LOCTEXT("DownArrow", "↓")) .ContentPadding(FMargin(6, 2)) .OnClicked(this, &FGridSlotExtension::HandleShiftRow, 1); TSharedRef<SButton> LeftArrow = SNew(SButton) .Text(LOCTEXT("LeftArrow", "←")) .ContentPadding(FMargin(2, 6)) .OnClicked(this, &FGridSlotExtension::HandleShiftColumn, -1); TSharedRef<SButton> RightArrow = SNew(SButton) .Text(LOCTEXT("RightArrow", "→")) .ContentPadding(FMargin(2, 6)) .OnClicked(this, &FGridSlotExtension::HandleShiftColumn, 1); UpArrow->SlatePrepass(); DownArrow->SlatePrepass(); LeftArrow->SlatePrepass(); RightArrow->SlatePrepass(); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(LeftArrow, EExtensionLayoutLocation::CenterLeft, FVector2D(-LeftArrow->GetDesiredSize().X, LeftArrow->GetDesiredSize().Y * -0.5f)))); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(RightArrow, EExtensionLayoutLocation::CenterRight, FVector2D(0, RightArrow->GetDesiredSize().Y * -0.5f)))); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(UpArrow, EExtensionLayoutLocation::TopCenter, FVector2D(UpArrow->GetDesiredSize().X * -0.5f, -UpArrow->GetDesiredSize().Y)))); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(DownArrow, EExtensionLayoutLocation::BottomCenter, FVector2D(DownArrow->GetDesiredSize().X * -0.5f, 0)))); }
/** * Open or close the popup * * @param InIsOpen If true, open the popup. Otherwise close it. */ void SMenuAnchor::SetIsOpen( bool InIsOpen, const bool bFocusMenu ) { // Prevent redundant opens/closes if ( IsOpen() != InIsOpen ) { if ( InIsOpen ) { TSharedPtr< SWidget > MenuContentPtr = OnGetMenuContent.IsBound() ? OnGetMenuContent.Execute() : MenuContent; if ( MenuContentPtr.IsValid() ) { // OPEN POPUP if ( OnMenuOpenChanged.IsBound() ) { OnMenuOpenChanged.Execute(true); } // This can be called at any time so we use the push menu override that explicitly allows us to specify our parent // Figure out where the menu anchor is on the screen, so we can set the initial position of our pop-up window SlatePrepass(); // NOTE: Careful, GeneratePathToWidget can be reentrant in that it can call visibility delegates and such FWidgetPath MyWidgetPath; FSlateApplication::Get().GeneratePathToWidgetChecked(AsShared(), MyWidgetPath); const FGeometry& MyGeometry = MyWidgetPath.Widgets.Last().Geometry; // @todo Slate: This code does not properly propagate the layout scale of the widget we are creating the popup for. // The popup instead has a scale of one, but a computed size as if the contents were scaled. This code should ideally // wrap the contents with an SFxWidget that applies the necessary layout scale. This is a very rare case right now. // Figure out how big the content widget is so we can set the window's initial size properly TSharedRef< SWidget > MenuContentRef = MenuContentPtr.ToSharedRef(); MenuContentRef->SlatePrepass(); // Combo-boxes never size down smaller than the widget that spawned them, but all // other pop-up menus are currently auto-sized const FVector2D DesiredContentSize = MenuContentRef->GetDesiredSize(); // @todo: This is ignoring any window border size! const EMenuPlacement PlacementMode = Placement.Get(); const FVector2D NewPosition = MyGeometry.AbsolutePosition; FVector2D NewWindowSize = DesiredContentSize; const FVector2D SummonLocationSize = MyGeometry.Size; FPopupTransitionEffect TransitionEffect(FPopupTransitionEffect::None); if ( PlacementMode == MenuPlacement_ComboBox || PlacementMode == MenuPlacement_ComboBoxRight ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::ComboButton); NewWindowSize = FVector2D(FMath::Max(MyGeometry.Size.X, DesiredContentSize.X), DesiredContentSize.Y); } else if ( PlacementMode == MenuPlacement_BelowAnchor ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::TopMenu); } else if ( PlacementMode == MenuPlacement_MenuRight ) { TransitionEffect = FPopupTransitionEffect(FPopupTransitionEffect::SubMenu); } if ( Method == CreateNewWindow ) { // Open the pop-up TSharedRef<SWindow> PopupWindow = FSlateApplication::Get().PushMenu(AsShared(), MenuContentRef, NewPosition, TransitionEffect, bFocusMenu, false, NewWindowSize, SummonLocationSize); PopupWindow->SetRequestDestroyWindowOverride(FRequestDestroyWindowOverride::CreateSP(this, &SMenuAnchor::RequestClosePopupWindow)); PopupWindowPtr = PopupWindow; } else { // We are re-using the current window instead of creating a new one. // The popup will be presented via an overlay service. ensure(Method == UseCurrentWindow); Children[1] [ MenuContentRef ]; // We want to support dismissing the popup widget when the user clicks outside it. FSlateApplication::Get().GetPopupSupport().RegisterClickNotification(MenuContentRef, FOnClickedOutside::CreateSP(this, &SMenuAnchor::OnClickedOutsidePopup)); } if ( bFocusMenu ) { FSlateApplication::Get().SetKeyboardFocus(MenuContentRef, EKeyboardFocusCause::SetDirectly); } } } else { // CLOSE POPUP if (Method == CreateNewWindow) { // Close the Popup window. TSharedPtr<SWindow> PopupWindow = PopupWindowPtr.Pin(); if ( PopupWindow.IsValid() ) { // Request that the popup be closed. PopupWindow->RequestDestroyWindow(); } } else { // Close the popup overlay ensure(Method==UseCurrentWindow); Children[1].DetachWidget(); } if (OnMenuOpenChanged.IsBound()) { OnMenuOpenChanged.Execute(false); } } } }
void FVerticalSlotExtension::ExtendSelection(const TArray< FWidgetReference >& Selection, TArray< TSharedRef<FDesignerSurfaceElement> >& SurfaceElements) { SelectionCache = Selection; TSharedRef<SButton> UpArrow = SNew(SButton) .Text(LOCTEXT("UpArrow", "↑")) .ContentPadding(FMargin(6, 2)) .IsEnabled(this, &FVerticalSlotExtension::CanShift, -1) .OnClicked(this, &FVerticalSlotExtension::HandleShiftVertical, -1); TSharedRef<SButton> DownArrow = SNew(SButton) .Text(LOCTEXT("DownArrow", "↓")) .ContentPadding(FMargin(6, 2)) .IsEnabled(this, &FVerticalSlotExtension::CanShift, 1) .OnClicked(this, &FVerticalSlotExtension::HandleShiftVertical, 1); UpArrow->SlatePrepass(); DownArrow->SlatePrepass(); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(UpArrow, EExtensionLayoutLocation::TopCenter, FVector2D(UpArrow->GetDesiredSize().X * -0.5f, -UpArrow->GetDesiredSize().Y)))); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(DownArrow, EExtensionLayoutLocation::BottomCenter, FVector2D(DownArrow->GetDesiredSize().X * -0.5f, 0)))); }
/** * Open or close the popup * * @param InIsOpen If true, open the popup. Otherwise close it. */ void SMenuAnchor::SetIsOpen( bool InIsOpen, const bool bFocusMenu ) { // Prevent redundant opens/closes if ( IsOpen() != InIsOpen ) { if ( InIsOpen ) { if ( OnGetMenuContent.IsBound() ) { SetMenuContent(OnGetMenuContent.Execute()); } if ( MenuContent.IsValid() ) { // OPEN POPUP if ( OnMenuOpenChanged.IsBound() ) { OnMenuOpenChanged.Execute(true); } // Figure out where the menu anchor is on the screen, so we can set the initial position of our pop-up window // This can be called at any time so we use the push menu override that explicitly allows us to specify our parent // NOTE: Careful, GeneratePathToWidget can be reentrant in that it can call visibility delegates and such FWidgetPath MyWidgetPath; FSlateApplication::Get().GeneratePathToWidgetUnchecked(AsShared(), MyWidgetPath); if (MyWidgetPath.IsValid()) { const FGeometry& MyGeometry = MyWidgetPath.Widgets.Last().Geometry; const float LayoutScaleMultiplier = MyGeometry.GetAccumulatedLayoutTransform().GetScale(); SlatePrepass(LayoutScaleMultiplier); // Figure out how big the content widget is so we can set the window's initial size properly TSharedRef< SWidget > MenuContentRef = MenuContent.ToSharedRef(); MenuContentRef->SlatePrepass(LayoutScaleMultiplier); // Combo-boxes never size down smaller than the widget that spawned them, but all // other pop-up menus are currently auto-sized const FVector2D DesiredContentSize = MenuContentRef->GetDesiredSize(); // @todo slate: This is ignoring any window border size! const EMenuPlacement PlacementMode = Placement.Get(); const FVector2D NewPosition = MyGeometry.AbsolutePosition; FVector2D NewWindowSize = DesiredContentSize; const FVector2D SummonLocationSize = MyGeometry.Size; FPopupTransitionEffect TransitionEffect( FPopupTransitionEffect::None ); if ( PlacementMode == MenuPlacement_ComboBox || PlacementMode == MenuPlacement_ComboBoxRight ) { TransitionEffect = FPopupTransitionEffect( FPopupTransitionEffect::ComboButton ); NewWindowSize = FVector2D( FMath::Max( MyGeometry.Size.X, DesiredContentSize.X ), DesiredContentSize.Y ); } else if ( PlacementMode == MenuPlacement_BelowAnchor ) { TransitionEffect = FPopupTransitionEffect( FPopupTransitionEffect::TopMenu ); } else if ( PlacementMode == MenuPlacement_MenuRight ) { TransitionEffect = FPopupTransitionEffect( FPopupTransitionEffect::SubMenu ); } MethodInUse = Method.IsSet() ? Method.GetValue() : QueryPopupMethod(MyWidgetPath); if (MethodInUse == EPopupMethod::CreateNewWindow) { // Open the pop-up const bool bIsCollapsedByParent = false; // don't auto-close child menus when the parent gets focus TSharedPtr<IMenu> NewMenu = FSlateApplication::Get().PushMenu(AsShared(), MyWidgetPath, MenuContentRef, NewPosition, TransitionEffect, bFocusMenu, SummonLocationSize, MethodInUse, bIsCollapsedByParent); PopupMenuPtr = NewMenu; check(NewMenu.IsValid() && NewMenu->GetOwnedWindow().IsValid()); NewMenu->GetOnMenuDismissed().AddSP(this, &SMenuAnchor::OnMenuClosed); PopupWindowPtr = NewMenu->GetOwnedWindow(); } else { // We are re-using the current window instead of creating a new one. // The popup will be presented via an overlay service. ensure(MethodInUse == EPopupMethod::UseCurrentWindow); TSharedRef<SWindow> PopupWindow = MyWidgetPath.GetWindow(); PopupWindowPtr = PopupWindow; if (bFocusMenu) { FSlateApplication::Get().ReleaseMouseCapture(); } TSharedRef<SMenuAnchor> SharedThis = StaticCastSharedRef<SMenuAnchor>(AsShared()); const bool bIsCollapsedByParent = false; // don't auto-close child menus when the parent gets focus TSharedPtr<IMenu> NewMenu = FSlateApplication::Get().PushHostedMenu( SharedThis, MyWidgetPath, SharedThis, MenuContentRef, WrappedContent, TransitionEffect, bIsCollapsedByParent); PopupMenuPtr = NewMenu; check(NewMenu.IsValid()); check(NewMenu->GetParentWindow().ToSharedRef() == PopupWindow); check(WrappedContent.IsValid()); Children[1] [ WrappedContent.ToSharedRef() ]; if (bFocusMenu) { FSlateApplication::Get().SetKeyboardFocus(MenuContentRef, EFocusCause::SetDirectly); } } } } } else { // CLOSE POPUP if (PopupMenuPtr.IsValid()) { PopupMenuPtr.Pin()->Dismiss(); } else { PopupWindowPtr.Reset(); MethodInUse.Reset(); } } } }
void FHorizontalSlotExtension::ExtendSelection(const TArray< FWidgetReference >& Selection, TArray< TSharedRef<FDesignerSurfaceElement> >& SurfaceElements) { SelectionCache = Selection; TSharedRef<SButton> LeftArrow = SNew(SButton) .Text(LOCTEXT("LeftArrow", "←")) .ContentPadding(FMargin(2, 6)) .IsEnabled(this, &FHorizontalSlotExtension::CanShift, -1) .OnClicked(this, &FHorizontalSlotExtension::HandleShift, -1); TSharedRef<SButton> RightArrow = SNew(SButton) .Text(LOCTEXT("RightArrow", "→")) .ContentPadding(FMargin(2, 6)) .IsEnabled(this, &FHorizontalSlotExtension::CanShift, 1) .OnClicked(this, &FHorizontalSlotExtension::HandleShift, 1); LeftArrow->SlatePrepass(); RightArrow->SlatePrepass(); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(LeftArrow, EExtensionLayoutLocation::CenterLeft, FVector2D(-LeftArrow->GetDesiredSize().X, LeftArrow->GetDesiredSize().Y * -0.5f)))); SurfaceElements.Add(MakeShareable(new FDesignerSurfaceElement(RightArrow, EExtensionLayoutLocation::CenterRight, FVector2D(0, RightArrow->GetDesiredSize().Y * -0.5f)))); }