Ejemplo n.º 1
0
void SInvalidationPanel::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
{
	if ( GetCanCache() )
	{
		const bool bWasCachingNeeded = bNeedsCaching;

		if ( bNeedsCaching == false )
		{
			if ( bCacheRelativeTransforms )
			{
				// If the container we're in has changed in either scale or the rotation matrix has changed, 
				if ( AllottedGeometry.GetAccumulatedLayoutTransform().GetScale() != LastAllottedGeometry.GetAccumulatedLayoutTransform().GetScale() ||
					 AllottedGeometry.GetAccumulatedRenderTransform().GetMatrix() != LastAllottedGeometry.GetAccumulatedRenderTransform().GetMatrix() )
				{
					InvalidateCache();
				}
			}
			else
			{
				// If the container we're in has changed in any way we need to invalidate for sure.
				if ( AllottedGeometry.GetAccumulatedLayoutTransform() != LastAllottedGeometry.GetAccumulatedLayoutTransform() ||
					AllottedGeometry.GetAccumulatedRenderTransform() != LastAllottedGeometry.GetAccumulatedRenderTransform() )
				{
					InvalidateCache();
				}
			}

			if ( AllottedGeometry.GetLocalSize() != LastAllottedGeometry.GetLocalSize() )
			{
				InvalidateCache();
			}
		}

		LastAllottedGeometry = AllottedGeometry;

		// TODO We may be double pre-passing here, if the invalidation happened at the end of last frame,
		// we'll have already done one pre-pass before getting here.
		if ( bNeedsCaching )
		{
			SlatePrepass(AllottedGeometry.Scale);
			CachePrepass(SharedThis(this));
		}
	}
}
	void Add(const TSharedRef<SWidget>& InWidget)
	{
		TSharedPtr<SWidgetStackItem> NewItem;

		InsertSlot(0)
		.AutoHeight()
		[
			SAssignNew(NewItem, SWidgetStackItem)
			[
				InWidget
			]
		];
		
		{
			auto Widget = Children[0].GetWidget();
			Widget->SlatePrepass();

			const float WidgetHeight = Widget->GetDesiredSize().Y;
			StartSlideOffset += WidgetHeight;
			// Fade in time is 1 second x the proportion of the slide amount that this widget takes up
			NewItem->FadeIn(WidgetHeight / StartSlideOffset);

			if (!SlideCurve.IsPlaying())
			{
				SlideCurve.Play(AsShared());
			}
		}

		const FVector2D NewSize = ComputeTotalSize();
		if (NewSize != StartSizeOffset)
		{
			StartSizeOffset = NewSize;

			if (!SizeCurve.IsPlaying())
			{
				SizeCurve.Play(AsShared());
			}
		}
	}
Ejemplo n.º 3
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);
			}
		}
	}
}
Ejemplo n.º 4
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();
			}
		}
	}
}
Ejemplo n.º 5
0
void SWidget::SlatePrepass()
{
	SlatePrepass( FSlateApplicationBase::Get().GetApplicationScale() );
}