FReply FCurveColorCustomization::OnCurvePreviewDoubleClick(const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent) { if (InMouseEvent.GetEffectingButton() == EKeys::LeftMouseButton) { if (RuntimeCurve->ExternalCurve) { FAssetEditorManager::Get().OpenEditorForAsset(RuntimeCurve->ExternalCurve); } else { DestroyPopOutWindow(); // Determine the position of the window so that it will spawn near the mouse, but not go off the screen. const FVector2D CursorPos = FSlateApplication::Get().GetCursorPos(); FSlateRect Anchor(CursorPos.X, CursorPos.Y, CursorPos.X, CursorPos.Y); FVector2D AdjustedSummonLocation = FSlateApplication::Get().CalculatePopupWindowPosition( Anchor, FCurveColorCustomization::DEFAULT_WINDOW_SIZE, Orient_Horizontal ); TSharedPtr<SWindow> Window = SNew(SWindow) .Title( FText::Format( LOCTEXT("WindowHeader", "{0} - Internal Color Curve Editor"), StructPropertyHandle->GetPropertyDisplayName()) ) .ClientSize( FCurveColorCustomization::DEFAULT_WINDOW_SIZE ) .ScreenPosition(AdjustedSummonLocation) .AutoCenter(EAutoCenter::None) .SupportsMaximize(false) .SupportsMinimize(false) .SizingRule( ESizingRule::FixedSize ); // init the mini curve editor widget TSharedRef<SMiniCurveEditor> MiniCurveEditor = SNew(SMiniCurveEditor) .CurveOwner(this) .OwnerObject(Owner) .ParentWindow(Window); Window->SetContent( MiniCurveEditor ); // Find the window of the parent widget FWidgetPath WidgetPath; FSlateApplication::Get().GeneratePathToWidgetChecked( CurveWidget.ToSharedRef(), WidgetPath ); Window = FSlateApplication::Get().AddWindowAsNativeChild( Window.ToSharedRef(), WidgetPath.GetWindow() ); //hold on to the window created for external use... CurveEditorWindow = Window; } } return FReply::Handled(); }
/** * 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(); } } } }