int32 FCinematicShotSection::OnPaintSection(FSequencerSectionPainter& InPainter) const { static const FSlateBrush* FilmBorder = FEditorStyle::GetBrush("Sequencer.Section.FilmBorder"); InPainter.LayerId = InPainter.PaintSectionBackground(); FVector2D SectionSize = InPainter.SectionGeometry.GetLocalSize(); FSlateDrawElement::MakeBox( InPainter.DrawElements, InPainter.LayerId++, InPainter.SectionGeometry.ToPaintGeometry(FVector2D(SectionSize.X-2.f, 7.f), FSlateLayoutTransform(FVector2D(1.f, 4.f))), FilmBorder, InPainter.SectionClippingRect.InsetBy(FMargin(1.f)), InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect ); FSlateDrawElement::MakeBox( InPainter.DrawElements, InPainter.LayerId++, InPainter.SectionGeometry.ToPaintGeometry(FVector2D(SectionSize.X-2.f, 7.f), FSlateLayoutTransform(FVector2D(1.f, SectionSize.Y - 11.f))), FilmBorder, InPainter.SectionClippingRect.InsetBy(FMargin(1.f)), InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect ); if (SequenceInstance.IsValid()) { return FThumbnailSection::OnPaintSection(InPainter); } return InPainter.LayerId; }
FPaintGeometry FGeometry::ToInflatedPaintGeometry( const FVector2D& InflateAmount ) const { // This essentially adds (or subtracts) a border around the widget. We scale the size then offset by the border amount. // Note this is not scaling child widgets, so the scale is not changing. FVector2D NewSize = Size + InflateAmount * 2; return ToPaintGeometry(NewSize, FSlateLayoutTransform(-InflateAmount)); }
void FDesignTimeUtils::GetArrangedWidgetRelativeToParent(FWidgetPath& WidgetPath, TSharedRef<const SWidget> Widget, TSharedRef<const SWidget> Parent, FArrangedWidget& ArrangedWidget) { FArrangedWidget ArrangedDesigner = WidgetPath.FindArrangedWidget(Parent).Get(FArrangedWidget::NullWidget); ArrangedWidget = WidgetPath.FindArrangedWidget(Widget).Get(FArrangedWidget::NullWidget); // !!! WRH 2014/08/26 - This code tries to mutate an FGeometry in an unsupported way. This code should be refactored. ArrangedWidget.Geometry.AppendTransform(FSlateLayoutTransform(Inverse(ArrangedDesigner.Geometry.AbsolutePosition))); }
int32 FHittestGrid::InsertWidget( const int32 ParentHittestIndex, const EVisibility& Visibility, const FArrangedWidget& Widget, const FVector2D InWindowOffset, const FSlateRect& InClippingRect ) { check( ParentHittestIndex < WidgetsCachedThisFrame->Num() ); // Update the FGeometry to transform into desktop space. FArrangedWidget WindowAdjustedWidget(Widget); WindowAdjustedWidget.Geometry.AppendTransform(FSlateLayoutTransform(InWindowOffset)); const FSlateRect WindowAdjustedRect = InClippingRect.OffsetBy(InWindowOffset); // Remember this widget, its geometry, and its place in the logical hierarchy. const int32 WidgetIndex = WidgetsCachedThisFrame->Add( FCachedWidget( ParentHittestIndex, WindowAdjustedWidget, WindowAdjustedRect ) ); check( WidgetIndex < WidgetsCachedThisFrame->Num() ); if (ParentHittestIndex != INDEX_NONE) { (*WidgetsCachedThisFrame)[ParentHittestIndex].AddChild( WidgetIndex ); } if (Visibility.IsHitTestVisible()) { // Mark any cell that is overlapped by this widget. // Compute the render space clipping rect, and compute it's aligned bounds so we can insert conservatively into the hit test grid. FSlateRect GridRelativeBoundingClipRect = TransformRect( Concatenate( Inverse(WindowAdjustedWidget.Geometry.GetAccumulatedLayoutTransform()), WindowAdjustedWidget.Geometry.GetAccumulatedRenderTransform() ), FSlateRotatedRect(WindowAdjustedWidget.Geometry.GetClippingRect().IntersectionWith(WindowAdjustedRect)) ) .ToBoundingRect() .OffsetBy(-GridOrigin); // Starting and ending cells covered by this widget. const FIntPoint UpperLeftCell = FIntPoint( FMath::Max(0, FMath::FloorToInt(GridRelativeBoundingClipRect.Left / CellSize.X)), FMath::Max(0, FMath::FloorToInt(GridRelativeBoundingClipRect.Top / CellSize.Y))); const FIntPoint LowerRightCell = FIntPoint( FMath::Min( NumCells.X-1, FMath::FloorToInt(GridRelativeBoundingClipRect.Right / CellSize.X)), FMath::Min( NumCells.Y-1, FMath::FloorToInt(GridRelativeBoundingClipRect.Bottom / CellSize.Y))); for (int32 XIndex=UpperLeftCell.X; XIndex <= LowerRightCell.X; ++ XIndex ) { for(int32 YIndex=UpperLeftCell.Y; YIndex <= LowerRightCell.Y; ++YIndex) { CellAt(XIndex, YIndex).CachedWidgetIndexes.Add( WidgetIndex ); } } } return WidgetIndex; }
FGeometry ComputeMenuPlacement(const FGeometry& AllottedGeometry, const FVector2D& PopupDesiredSize, EMenuPlacement PlacementMode) { // Compute the popup size, offset, and anchor rect in local space const FPopupPlacement Placement(AllottedGeometry, PopupDesiredSize, PlacementMode); // ask the application to compute the proper desktop offset for the anchor. This requires the offsets to be in desktop space. const FVector2D NewPositionDesktopSpace = FSlateApplication::Get().CalculatePopupWindowPosition( TransformRect(AllottedGeometry.GetAccumulatedLayoutTransform(), Placement.AnchorLocalSpace), TransformVector(AllottedGeometry.GetAccumulatedLayoutTransform(), Placement.LocalPopupSize), Placement.Orientation); // transform the desktop offset into local space and use that as the layout transform for the child content. return AllottedGeometry.MakeChild( Placement.LocalPopupSize, FSlateLayoutTransform(TransformPoint(Inverse(AllottedGeometry.GetAccumulatedLayoutTransform()), NewPositionDesktopSpace))); }
void SClippingHorizontalBox::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // If WrapButton hasn't been initialized, that means AddWrapButton() hasn't // been called and this method isn't going to behave properly check(WrapButton.IsValid()); SHorizontalBox::OnArrangeChildren(AllottedGeometry, ArrangedChildren); // Remove children that are clipped by the allotted geometry const int32 NumChildren = ArrangedChildren.Num(); int32 IndexClippedAt = NumChildren; for (int32 ChildIdx = NumChildren - 2; ChildIdx >= 0; --ChildIdx) { const FArrangedWidget& CurWidget = ArrangedChildren[ChildIdx]; if (FMath::TruncToInt(CurWidget.Geometry.AbsolutePosition.X + CurWidget.Geometry.Size.X * CurWidget.Geometry.Scale) > FMath::TruncToInt(AllottedGeometry.AbsolutePosition.X + AllottedGeometry.Size.X * CurWidget.Geometry.Scale)) { ArrangedChildren.Remove(ChildIdx); IndexClippedAt = ChildIdx; } } if (IndexClippedAt == NumChildren) { // None of the children are being clipped, so remove the wrap button ArrangedChildren.Remove(ArrangedChildren.Num() - 1); } else { // Right align the wrap button FArrangedWidget& ArrangedButton = ArrangedChildren[ArrangedChildren.Num() - 1]; ArrangedButton.Geometry = AllottedGeometry.MakeChild(ArrangedButton.Geometry.Size, FSlateLayoutTransform(AllottedGeometry.Size - ArrangedButton.Geometry.Size)); const int32 WrapButtonXPosition = FMath::TruncToInt(ArrangedButton.Geometry.AbsolutePosition.X); // Further remove any children that the wrap button overlaps with for (int32 ChildIdx = IndexClippedAt - 1; ChildIdx >= 0; --ChildIdx) { const FArrangedWidget& CurWidget = ArrangedChildren[ChildIdx]; if (FMath::TruncToInt(CurWidget.Geometry.AbsolutePosition.X + CurWidget.Geometry.Size.X * CurWidget.Geometry.Scale) > WrapButtonXPosition) { ArrangedChildren.Remove(ChildIdx); } } } }
void FWidgetRenderer::DrawWindow( UTextureRenderTarget2D* RenderTarget, TSharedRef<FHittestGrid> HitTestGrid, TSharedRef<SWindow> Window, float Scale, FVector2D DrawSize, float DeltaTime) { FGeometry WindowGeometry = FGeometry::MakeRoot(DrawSize * ( 1 / Scale ), FSlateLayoutTransform(Scale)); DrawWindow( RenderTarget, HitTestGrid, Window, WindowGeometry, WindowGeometry.GetClippingRect(), DeltaTime ); }
bool FDesignTimeUtils::GetArrangedWidgetRelativeToWindow(TSharedRef<SWidget> Widget, FArrangedWidget& ArrangedWidget) { TSharedPtr<SWindow> WidgetWindow = FSlateApplication::Get().FindWidgetWindow(Widget); if ( !WidgetWindow.IsValid() ) { return false; } TSharedRef<SWindow> CurrentWindowRef = WidgetWindow.ToSharedRef(); FWidgetPath WidgetPath; if ( FSlateApplication::Get().GeneratePathToWidgetUnchecked(Widget, WidgetPath) ) { ArrangedWidget = WidgetPath.FindArrangedWidget(Widget).Get(FArrangedWidget::NullWidget); ArrangedWidget.Geometry.AppendTransform(FSlateLayoutTransform(Inverse(CurrentWindowRef->GetPositionInScreen()))); return true; } return false; }
TArray<FLayoutGeometry> SSplitter2x2::ArrangeChildrenForLayout( const FGeometry& AllottedGeometry ) const { check( Children.Num() == 4 ); TArray<FLayoutGeometry> Result; Result.Empty(Children.Num()); int32 NumNonCollapsedChildren = 0; FVector2D CoefficientTotal(0,0); // The allotted space for our children is our geometry minus a little space to show splitter handles const FVector2D SpaceAllottedForChildren = AllottedGeometry.Size - FVector2D(SplitterHandleSize,SplitterHandleSize); // The current offset that the next child should be positioned at. FVector2D Offset(0,0); for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex) { const FSlot& CurSlot = Children[ChildIndex]; // Calculate the amount of space that this child should take up. // It is based on the current percentage of space it should take up which is defined by a user moving the splitters const FVector2D ChildSpace = SpaceAllottedForChildren * CurSlot.PercentageAttribute.Get(); // put them in their spot Result.Emplace(FSlateLayoutTransform(Offset), ChildSpace); // Advance to the next slot. If the child is collapsed, it takes up no room and does not need a splitter if( ChildIndex == 1 ) { // ChildIndex of 1 means we are starting the next column so reset the Y offset. Offset.Y = 0.0f; Offset += FVector2D( ChildSpace.X + SplitterHandleSize, 0); } else { Offset += FVector2D( 0, ChildSpace.Y + SplitterHandleSize ); } } return Result; }
FGeometry SMenuAnchor::ComputeMenuPlacement( const FGeometry& AllottedGeometry, const FVector2D& PopupDesiredSize, EMenuPlacement PlacementMode ) { // Compute the popup size, offset, and anchor rect in local space const FVector2D PopupSizeLocalSpace = (PlacementMode == MenuPlacement_ComboBox || PlacementMode == MenuPlacement_ComboBoxRight) ? FVector2D( FMath::Max( AllottedGeometry.Size.X, PopupDesiredSize.X ), PopupDesiredSize.Y ) : PopupDesiredSize; const FVector2D OffsetLocalSpace = GetMenuOffsetForPlacement(AllottedGeometry, PlacementMode, PopupSizeLocalSpace); const FSlateRect AnchorLocalSpace = FSlateRect::FromPointAndExtent(OffsetLocalSpace, AllottedGeometry.Size); const EOrientation Orientation = (PlacementMode == MenuPlacement_MenuRight || PlacementMode == MenuPlacement_MenuLeft) ? Orient_Horizontal : Orient_Vertical; // ask the application to compute the proper desktop offset for the anchor. This requires the offsets to be in desktop space. const FVector2D NewPositionDesktopSpace = FSlateApplication::Get().CalculatePopupWindowPosition( TransformRect(AllottedGeometry.GetAccumulatedLayoutTransform(), AnchorLocalSpace), TransformVector(AllottedGeometry.GetAccumulatedLayoutTransform(), PopupSizeLocalSpace), Orientation ); // transform the desktop offset into local space and use that as the layout transform for the child content. return AllottedGeometry.MakeChild( PopupSizeLocalSpace, FSlateLayoutTransform(TransformPoint(Inverse(AllottedGeometry.GetAccumulatedLayoutTransform()), NewPositionDesktopSpace))); }
int32 FSlateImageRun::OnPaint( const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); if ( Image->DrawAs != ESlateBrushDrawType::NoDrawType ) { const FColor FinalColorAndOpacity( InWidgetStyle.GetColorAndOpacityTint() * Image->GetTint( InWidgetStyle ) ); const uint32 DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))), Image, MyClippingRect, DrawEffects, FinalColorAndOpacity ); } return LayerId; }
TArray<FLayoutGeometry> SSplitter::ArrangeChildrenForLayout(const FGeometry& AllottedGeometry) const { TArray<FLayoutGeometry> Result; Result.Empty(Children.Num()); const int32 AxisIndex = (Orientation == Orient_Horizontal) ? 0 : 1; // Splitters divide the space between their children proportionately based on size coefficients. // The size coefficients are usually determined by a user, who grabs the handled between the child elements // and moves them to resize the space available to the children. // Some children are sized automatically based on their content; those children cannot be resized. // // e.g. _____________________________________ Children // / / / // v v v // + - - - - - + + - - - + + - - - - - - - - - - - - - - + // | | | | | | // | Child 0 | |Child1 | | Child2 | // + - - - - - + + - - - + + - - - - - - - - - - - - - - + // ^ ^ // \_________\___________ Resize handles. int32 NumNonCollapsedChildren = 0; int32 NumResizeableChildren = 0; float CoefficientTotal = 0; // Some space is claimed by non-resizeable elements (auto-sized elements) float NonResizeableSpace = 0; { for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex) { if (Children[ChildIndex].GetWidget()->GetVisibility() != EVisibility::Collapsed) { ++NumNonCollapsedChildren; if ( Children[ChildIndex].SizingRule == SSplitter::SizeToContent ) { NonResizeableSpace += Children[ChildIndex].GetWidget()->GetDesiredSize()[AxisIndex]; } else // SizingRule == SSplitter::FractionOfParent { CoefficientTotal += Children[ChildIndex].SizeValue.Get(); } } } } // The user-sizeable children must make room for the resize handles and for auto-sized children. const float SpaceNeededForHandles = FMath::Max(0, NumNonCollapsedChildren-1) * PhysicalSplitterHandleSize; const float ResizeableSpace = AllottedGeometry.Size.Component(AxisIndex) - SpaceNeededForHandles - NonResizeableSpace; // Arrange the children horizontally or vertically. float XOffset = 0; for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex) { const FSlot& CurSlot = Children[ChildIndex]; const float ChildSpace = ( CurSlot.SizingRule == SSplitter::SizeToContent ) ? CurSlot.GetWidget()->GetDesiredSize()[AxisIndex] : ResizeableSpace * CurSlot.SizeValue.Get() / CoefficientTotal; const EVisibility ChildVisibility = CurSlot.GetWidget()->GetVisibility(); FVector2D ChildOffset = Orientation == Orient_Horizontal ? FVector2D(XOffset, 0) : FVector2D(0, XOffset); FVector2D ChildSize = Orientation == Orient_Horizontal ? FVector2D(ChildSpace, AllottedGeometry.Size.Y) : FVector2D(AllottedGeometry.Size.X, ChildSpace); Result.Emplace(FSlateLayoutTransform(ChildOffset), ChildSize); // Advance to the next slot. If the child is collapsed, it takes up no room and does not need a splitter if ( ChildVisibility != EVisibility::Collapsed) { XOffset += ChildSpace + PhysicalSplitterHandleSize; } } return Result; }
FGeometry FGeometry::MakeRoot(const FVector2D& LocalSize, const FSlateLayoutTransform& LayoutTransform) { return FGeometry(LocalSize, LayoutTransform, FSlateLayoutTransform(), FSlateRenderTransform()); }
int32 SSlider::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // we draw the slider like a horizontal slider regardless of the orientation, and apply a render transform to make it display correctly. // However, the AllottedGeometry is computed as it will be rendered, so we have to use the "horizontal orientation" when doing drawing computations. const float AllottedWidth = Orientation == Orient_Horizontal ? AllottedGeometry.GetLocalSize().X : AllottedGeometry.GetLocalSize().Y; const float AllottedHeight = Orientation == Orient_Horizontal ? AllottedGeometry.GetLocalSize().Y : AllottedGeometry.GetLocalSize().X; float HandleRotation; FVector2D HandleTopLeftPoint; FVector2D SliderStartPoint; FVector2D SliderEndPoint; // calculate slider geometry as if it's a horizontal slider (we'll rotate it later if it's vertical) const FVector2D HandleSize = Style->NormalThumbImage.ImageSize; const FVector2D HalfHandleSize = 0.5f * HandleSize; const float Indentation = IndentHandle.Get() ? HandleSize.X : 0.0f; const float SliderLength = AllottedWidth - Indentation; const float SliderPercent = ValueAttribute.Get(); const float SliderHandleOffset = SliderPercent * SliderLength; const float SliderY = 0.5f * AllottedHeight; HandleRotation = 0.0f; HandleTopLeftPoint = FVector2D(SliderHandleOffset - ( HandleSize.X * SliderPercent ) + 0.5f * Indentation, SliderY - HalfHandleSize.Y); SliderStartPoint = FVector2D(HalfHandleSize.X, SliderY); SliderEndPoint = FVector2D(AllottedWidth - HalfHandleSize.X, SliderY); FSlateRect RotatedClippingRect = MyClippingRect; FGeometry SliderGeometry = AllottedGeometry; // rotate the slider 90deg if it's vertical. The 0 side goes on the bottom, the 1 side on the top. if (Orientation == Orient_Vertical) { // Do this by translating along -X by the width of the geometry, then rotating 90 degreess CCW (left-hand coords) FSlateRenderTransform SlateRenderTransform = TransformCast<FSlateRenderTransform>(Concatenate(Inverse(FVector2D(AllottedWidth, 0)), FQuat2D(FMath::DegreesToRadians(-90.0f)))); // create a child geometry matching this one, but with the render transform. SliderGeometry = AllottedGeometry.MakeChild( FVector2D(AllottedWidth, AllottedHeight), FSlateLayoutTransform(), SlateRenderTransform, FVector2D::ZeroVector); // The clipping rect is already given properly in window space. But we do not support layout rotations, so our local space rendering cannot // get the clipping rect into local space properly for the local space clipping we do in the shader. // Thus, we transform the clip coords into local space manually, UNDO the render transform so it will clip properly, // and then bring the clip coords back into window space where DrawElements expect them. RotatedClippingRect = TransformRect( Concatenate( Inverse(SliderGeometry.GetAccumulatedLayoutTransform()), Inverse(SlateRenderTransform), SliderGeometry.GetAccumulatedLayoutTransform()), MyClippingRect); } const bool bEnabled = ShouldBeEnabled(bParentEnabled); const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; // draw slider bar auto BarTopLeft = FVector2D(SliderStartPoint.X, SliderStartPoint.Y - Style->BarThickness * 0.5f); auto BarSize = FVector2D(SliderEndPoint.X - SliderStartPoint.X, Style->BarThickness); FSlateDrawElement::MakeBox( OutDrawElements, LayerId, SliderGeometry.ToPaintGeometry(BarTopLeft, BarSize), LockedAttribute.Get() ? &Style->DisabledBarImage : &Style->NormalBarImage, RotatedClippingRect, DrawEffects, SliderBarColor.Get().GetColor(InWidgetStyle) * InWidgetStyle.GetColorAndOpacityTint() ); ++LayerId; // draw slider thumb FSlateDrawElement::MakeBox( OutDrawElements, LayerId, SliderGeometry.ToPaintGeometry(HandleTopLeftPoint, Style->NormalThumbImage.ImageSize), LockedAttribute.Get() ? &Style->DisabledThumbImage : &Style->NormalThumbImage, RotatedClippingRect, DrawEffects, SliderHandleColor.Get().GetColor(InWidgetStyle) * InWidgetStyle.GetColorAndOpacityTint() ); return LayerId; }
FPaintGeometry FGeometry::ToOffsetPaintGeometry(const FVector2D& LocalOffset) const { return ToPaintGeometry(FSlateLayoutTransform(LocalOffset)); }
FPaintGeometry FGeometry::ToPaintGeometry(const FVector2D& LocalOffset, const FVector2D& LocalSize, float LocalScale) const { // Since ChildOffset is given as a LocalSpaceOffset, we MUST convert this offset into the space of the parent to construct a valid layout transform. // The extra TransformPoint below does this by converting the local offset to an offset in parent space. return ToPaintGeometry(LocalSize, FSlateLayoutTransform(LocalScale, TransformPoint(LocalScale, LocalOffset))); }
FArrangedWidget FGeometry::MakeChild( const TSharedRef<SWidget>& ChildWidget, const FVector2D& ChildOffset, const FVector2D& LocalSize, float ChildScale) const { // Since ChildOffset is given as a LocalSpaceOffset, we MUST convert this offset into the space of the parent to construct a valid layout transform. // The extra TransformPoint below does this by converting the local offset to an offset in parent space. return MakeChild(ChildWidget, LocalSize, FSlateLayoutTransform(ChildScale, TransformPoint(ChildScale, ChildOffset))); }
int32 FSlateTextHighlightRunRenderer::OnPaint( const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ISlateRun >& Run, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { FVector2D Location( Block->GetLocationOffset() ); Location.Y = Line.Offset.Y; // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); // Draw the actual highlight rectangle FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, FVector2D( Block->GetSize().X, Line.Size.Y )), FSlateLayoutTransform(TransformPoint(InverseScale, Location))), &DefaultStyle.HighlightShape, MyClippingRect, bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, InWidgetStyle.GetColorAndOpacityTint() * DefaultStyle.HighlightColor ); FLinearColor InvertedHighlightColor = FLinearColor::White - DefaultStyle.HighlightColor; InvertedHighlightColor.A = InWidgetStyle.GetForegroundColor().A; FWidgetStyle WidgetStyle( InWidgetStyle ); WidgetStyle.SetForegroundColor( InvertedHighlightColor ); return Run->OnPaint( Args, Line, Block, DefaultStyle, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, WidgetStyle, bParentEnabled ); }
int32 SWidget::Paint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { INC_DWORD_STAT(STAT_SlateNumPaintedWidgets); SLATE_CYCLE_COUNTER_SCOPE_CUSTOM_DETAILED(SLATE_STATS_DETAIL_LEVEL_MED, GSlateOnPaint, GetType()); // Save the current layout cache we're associated with (if any) LayoutCache = Args.GetLayoutCache(); // Record if we're part of a volatility pass, this is critical for ensuring we don't report a child // of a volatile widget as non-volatile, causing the invalidation panel to do work that's not required. bInheritedVolatility = Args.IsVolatilityPass(); // If this paint pass is to cache off our geometry, but we're a volatile widget, // record this widget as volatile in the draw elements so that we get our own tick/paint // pass later when the layout cache draws. if ( Args.IsCaching() && IsVolatile() ) { const int32 VolatileLayerId = LayerId + 1; OutDrawElements.QueueVolatilePainting( FSlateWindowElementList::FVolatilePaint(SharedThis(this), Args, AllottedGeometry, MyClippingRect, VolatileLayerId, InWidgetStyle, bParentEnabled)); return VolatileLayerId; } if ( bFoldTick && bCanTick ) { FGeometry TickGeometry = AllottedGeometry; TickGeometry.AppendTransform( FSlateLayoutTransform(Args.GetWindowToDesktopTransform()) ); SWidget* MutableThis = const_cast<SWidget*>(this); MutableThis->ExecuteActiveTimers( Args.GetCurrentTime(), Args.GetDeltaTime() ); MutableThis->Tick( TickGeometry, Args.GetCurrentTime(), Args.GetDeltaTime() ); } // Record hit test geometry, but only if we're not caching. const FPaintArgs UpdatedArgs = Args.RecordHittestGeometry(this, AllottedGeometry, MyClippingRect); // Paint the geometry of this widget. int32 NewLayerID = OnPaint(UpdatedArgs, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); // Check if we need to show the keyboard focus ring, this is only necessary if the widget could be focused. if ( bCanSupportFocus && SupportsKeyboardFocus() ) { bool bShowUserFocus = FSlateApplicationBase::Get().ShowUserFocus(SharedThis(this)); if (bShowUserFocus) { const FSlateBrush* BrushResource = GetFocusBrush(); if (BrushResource != nullptr) { FSlateDrawElement::MakeBox( OutDrawElements, NewLayerID, AllottedGeometry.ToPaintGeometry(), BrushResource, MyClippingRect, ESlateDrawEffect::None, BrushResource->GetTint(InWidgetStyle) ); } } } return NewLayerID; }
int32 SClippingHorizontalBox::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // Get the clipped children info FArrangedChildren ClippedArrangedChildren(EVisibility::Visible); ArrangeChildren(AllottedGeometry, ClippedArrangedChildren); // Get the non-clipped children info // @todo umg: One should not call the virtual OnArrangeChildren, one should only call ArrangeChildren. FArrangedChildren ArrangedChildren(EVisibility::Visible); SBoxPanel::OnArrangeChildren(AllottedGeometry, ArrangedChildren); if ((ClippedArrangedChildren.Num() != 0) && (ArrangedChildren.Num() != 0)) { int32 IndexClippedAt = ClippedArrangedChildren.Num() - 1; const FArrangedWidget& LastCippedChild = ClippedArrangedChildren[IndexClippedAt]; const FArrangedWidget& FirstChild = ArrangedChildren[0]; const FArrangedWidget& LastChild = ArrangedChildren[ArrangedChildren.Num() - 1]; float BorderLocalWidth = AllottedGeometry.Size.X; // If only the last child/block, which is the wrap button, is being clipped if (IndexClippedAt == ArrangedChildren.Num() - 2) { // Only recalculate the alloted geometry size if said size is fitted to the toolbar/menubar if (FMath::TruncToInt(AllottedGeometry.AbsolutePosition.X + AllottedGeometry.Size.X * AllottedGeometry.Scale) <= FMath::TruncToInt(LastChild.Geometry.AbsolutePosition.X + LastChild.Geometry.Size.X * LastChild.Geometry.Scale)) { // Calculate the size of the custom border BorderLocalWidth = (LastCippedChild.Geometry.AbsolutePosition.X + LastCippedChild.Geometry.Size.X * LastCippedChild.Geometry.Scale - FirstChild.Geometry.AbsolutePosition.X) / AllottedGeometry.Scale; } } else { // Children/blocks are being clipped, calculate the size of the custom border const FArrangedWidget& NextChild = (IndexClippedAt + 1 < ClippedArrangedChildren.Num())? ClippedArrangedChildren[IndexClippedAt + 1]: LastCippedChild; BorderLocalWidth = (NextChild.Geometry.AbsolutePosition.X + NextChild.Geometry.Size.X * NextChild.Geometry.Scale - FirstChild.Geometry.AbsolutePosition.X) / AllottedGeometry.Scale; } bool bEnabled = ShouldBeEnabled( bParentEnabled ); ESlateDrawEffect::Type DrawEffects = !bEnabled ? ESlateDrawEffect::DisabledEffect : ESlateDrawEffect::None; FSlateColor BorderBackgroundColor = FLinearColor::White; // Draw the custom border FSlateDrawElement::MakeBox( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(FVector2D(BorderLocalWidth, AllottedGeometry.Size.Y), FSlateLayoutTransform()), BackgroundBrush, MyClippingRect, DrawEffects, BackgroundBrush->GetTint( InWidgetStyle ) * InWidgetStyle.GetColorAndOpacityTint() * BorderBackgroundColor.GetColor(InWidgetStyle) ); } return SHorizontalBox::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); }
int32 FSlateHyperlinkRun::OnPaint( const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { const TSharedRef< FWidgetLayoutBlock > WidgetBlock = StaticCastSharedRef< FWidgetLayoutBlock >( Block ); // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); const FGeometry WidgetGeometry = AllottedGeometry.MakeChild(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))); return WidgetBlock->GetWidget()->Paint( Args, WidgetGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled ); }
void SMenuAnchor::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { ArrangeSingleChild( AllottedGeometry, ArrangedChildren, Children[0], FVector2D::UnitVector ); const TSharedPtr<SWindow> PresentingWindow = PopupWindowPtr.Pin(); if (IsOpenAndReusingWindow() && PresentingWindow.IsValid()) { const FPopupPlacement LocalPlacement(AllottedGeometry, Children[1].GetWidget()->GetDesiredSize(), Placement.Get()); ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(Children[1].GetWidget(), LocalPlacement.LocalPopupSize, FSlateLayoutTransform(LocalPopupPosition))); } }
void FSlateWidgetRun::ArrangeChildren( const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(Info.Widget, TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))) ); }
int32 FSlateWidgetRun::OnPaint( const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); const FVector2D DesiredWidgetSize = Info.Widget->GetDesiredSize(); if (DesiredWidgetSize != WidgetSize) { WidgetSize = DesiredWidgetSize; const TSharedPtr<FTextLayout> TextLayoutPtr = TextLayout.Pin(); if (TextLayoutPtr.IsValid()) { TextLayoutPtr->DirtyRunLayout(SharedThis(this)); } } const FGeometry WidgetGeometry = AllottedGeometry.MakeChild(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))); return Info.Widget->Paint( Args, WidgetGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled ); }
int32 SColorGradientEditor::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); if( CurveOwner ) { // Split the geometry into areas for stops and the gradient FGeometry ColorMarkAreaGeometry = GetColorMarkAreaGeometry( AllottedGeometry ); FGeometry AlphaMarkAreaGeometry = GetAlphaMarkAreaGeometry( AllottedGeometry ); FGeometry GradientAreaGeometry = AllottedGeometry.MakeChild( FVector2D(0.0f, 16.0f), FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y - 30.0f ) ); bool bEnabled = ShouldBeEnabled( bParentEnabled ); ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; // Pixel to value input converter FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.0f, 1.0f, GradientAreaGeometry.Size); // The start and end location in slate units of the area to draw int32 Start = 0; int32 Finish = FMath::TruncToInt( AllottedGeometry.Size.X ); TArray<FSlateGradientStop> Stops; // If no alpha keys are available, treat the curve as being completely opaque for drawing purposes bool bHasAnyAlphaKeys = CurveOwner->HasAnyAlphaKeys(); // If any transpareny (A < 1) is found, we'll draw a checkerboard to visualize the color with alpha bool bHasTransparency = false; // Sample the curve every 2 units. THe curve could be non-linear so sampling at each stop would display an incorrect gradient for( int32 CurrentStep = Start; CurrentStep < Finish; CurrentStep+=2 ) { // Figure out the time from the current screen unit float Time = ScaleInfo.LocalXToInput(CurrentStep); // Sample the curve FLinearColor Color = CurveOwner->GetLinearColorValue( Time ); if( !bHasAnyAlphaKeys ) { // Only show alpha if there is at least one key. For some curves, alpha may not be important Color.A = 1.0f; bHasTransparency = false; } else { bHasTransparency |= (Color.A < 1.0f); } Stops.Add( FSlateGradientStop( FVector2D( CurrentStep, 0.0f ), Color ) ); } if( Stops.Num() > 0 ) { if( bHasTransparency ) { // Draw a checkerboard behind there is any transparency visible FSlateDrawElement::MakeBox ( OutDrawElements, LayerId, GradientAreaGeometry.ToPaintGeometry(), FEditorStyle::GetBrush("Checkerboard"), MyClippingRect, DrawEffects ); } // Draw the color gradient FSlateDrawElement::MakeGradient ( OutDrawElements, LayerId, GradientAreaGeometry.ToPaintGeometry(), Stops, Orient_Vertical, MyClippingRect, DrawEffects, false ); } // Get actual editable stop marks TArray<FGradientStopMark> ColorMarks; TArray<FGradientStopMark> AlphaMarks; GetGradientStopMarks( ColorMarks, AlphaMarks ); // Draw each color stop for( int32 ColorIndex = 0; ColorIndex < ColorMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = ColorMarks[ColorIndex]; float XVal = ScaleInfo.InputToLocalX( Mark.Time ); // Dont draw stops which are not visible if( XVal >= 0 && XVal <= ColorMarkAreaGeometry.Size.X ) { FLinearColor Color = CurveOwner->GetLinearColorValue( Mark.Time ); Color.A = 1.0f; DrawGradientStopMark( Mark, ColorMarkAreaGeometry, XVal, Color, OutDrawElements, LayerId, MyClippingRect, DrawEffects, true, InWidgetStyle ); } } // Draw each alpha stop for( int32 ColorIndex = 0; ColorIndex < AlphaMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = AlphaMarks[ColorIndex]; float XVal = ScaleInfo.InputToLocalX( Mark.Time ); // Dont draw stops which are not visible if( XVal >= 0 && XVal <= AlphaMarkAreaGeometry.Size.X ) { float Alpha = CurveOwner->GetLinearColorValue( Mark.Time ).A; DrawGradientStopMark( Mark, AlphaMarkAreaGeometry, XVal, FLinearColor( Alpha, Alpha, Alpha, 1.0f ), OutDrawElements, LayerId, MyClippingRect, DrawEffects, false, InWidgetStyle ); } } // Draw some hint messages about how to add stops if no stops exist if( ColorMarks.Num() == 0 && AlphaMarks.Num() == 0 && IsEditingEnabled.Get() == true ) { static FString GradientColorMessage( LOCTEXT("ClickToAddColorStop", "Click in this area add color stops").ToString() ); static FString GradientAlphaMessage( LOCTEXT("ClickToAddAlphaStop", "Click in this area add opacity stops").ToString() ); // Draw the text centered in the color region { FVector2D StringSize = FontMeasureService->Measure( GradientColorMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ) ); FPaintGeometry PaintGeom = ColorMarkAreaGeometry.ToPaintGeometry(FSlateLayoutTransform(FVector2D((ColorMarkAreaGeometry.Size.X - StringSize.X) * 0.5f, 1.0f))); FSlateDrawElement::MakeText ( OutDrawElements, LayerId, PaintGeom, GradientColorMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ), MyClippingRect, DrawEffects, FLinearColor( .5f, .5f, .5f, .85f ) ); } // Draw the text centered in the alpha region { FVector2D StringSize = FontMeasureService->Measure( GradientAlphaMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ) ); FPaintGeometry PaintGeom = AlphaMarkAreaGeometry.ToPaintGeometry(FSlateLayoutTransform(FVector2D((AlphaMarkAreaGeometry.Size.X - StringSize.X) * 0.5f, 1.0f))); FSlateDrawElement::MakeText ( OutDrawElements, LayerId, PaintGeom, GradientAlphaMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ), MyClippingRect, DrawEffects, FLinearColor( .5f, .5f, .5f, .85f ) ); } } } return LayerId; }
int32 FSlateTextLayout::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { const FSlateRect ClippingRect = AllottedGeometry.GetClippingRect().IntersectionWith(MyClippingRect); const ESlateDrawEffect::Type DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; static bool ShowDebug = false; FLinearColor BlockHue( 0, 1.0f, 1.0f, 0.5 ); int32 HighestLayerId = LayerId; for (const FTextLayout::FLineView& LineView : LineViews) { // Is this line visible? const FSlateRect LineViewRect(AllottedGeometry.AbsolutePosition + LineView.Offset, AllottedGeometry.AbsolutePosition + LineView.Offset + LineView.Size); const FSlateRect VisibleLineView = ClippingRect.IntersectionWith(LineViewRect); if (VisibleLineView.IsEmpty()) { continue; } // Render any underlays for this line const int32 HighestUnderlayLayerId = OnPaintHighlights( Args, LineView, LineView.UnderlayHighlights, DefaultTextStyle, AllottedGeometry, ClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled ); const int32 BlockDebugLayer = HighestUnderlayLayerId; const int32 TextLayer = BlockDebugLayer + 1; int32 HighestBlockLayerId = TextLayer; // Render every block for this line for (const TSharedRef< ILayoutBlock >& Block : LineView.Blocks) { if ( ShowDebug ) { BlockHue.R += 50.0f; // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); FSlateDrawElement::MakeBox( OutDrawElements, BlockDebugLayer, AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()))), &DefaultTextStyle.HighlightShape, ClippingRect, DrawEffects, InWidgetStyle.GetColorAndOpacityTint() * BlockHue.HSVToLinearRGB() ); } const TSharedRef< ISlateRun > Run = StaticCastSharedRef< ISlateRun >( Block->GetRun() ); int32 HighestRunLayerId = TextLayer; const TSharedPtr< ISlateRunRenderer > RunRenderer = StaticCastSharedPtr< ISlateRunRenderer >( Block->GetRenderer() ); if ( RunRenderer.IsValid() ) { HighestRunLayerId = RunRenderer->OnPaint( Args, LineView, Run, Block, DefaultTextStyle, AllottedGeometry, ClippingRect, OutDrawElements, TextLayer, InWidgetStyle, bParentEnabled ); } else { HighestRunLayerId = Run->OnPaint( Args, LineView, Block, DefaultTextStyle, AllottedGeometry, ClippingRect, OutDrawElements, TextLayer, InWidgetStyle, bParentEnabled ); } HighestBlockLayerId = FMath::Max( HighestBlockLayerId, HighestRunLayerId ); } // Render any overlays for this line const int32 HighestOverlayLayerId = OnPaintHighlights( Args, LineView, LineView.OverlayHighlights, DefaultTextStyle, AllottedGeometry, ClippingRect, OutDrawElements, HighestBlockLayerId, InWidgetStyle, bParentEnabled ); HighestLayerId = FMath::Max( HighestLayerId, HighestOverlayLayerId ); } return HighestLayerId; }
int32 SInvalidationPanel::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { if ( GetCanCache() ) { const bool bWasCachingNeeded = bNeedsCaching; if ( bNeedsCaching ) { SInvalidationPanel* MutableThis = const_cast<SInvalidationPanel*>( this ); // Always set the caching flag to false first, during the paint / tick pass we may change something // to volatile and need to re-cache. bNeedsCaching = false; bIsInvalidating = true; if ( !CachedWindowElements.IsValid() || CachedWindowElements->GetWindow() != OutDrawElements.GetWindow() ) { CachedWindowElements = MakeShareable(new FSlateWindowElementList(OutDrawElements.GetWindow())); } else { CachedWindowElements->Reset(); } // Reset the cached node pool index so that we effectively reset the pool. LastUsedCachedNodeIndex = 0; RootCacheNode = CreateCacheNode(); RootCacheNode->Initialize(Args, SharedThis(MutableThis), AllottedGeometry, MyClippingRect); //TODO: When SWidget::Paint is called don't drag self if volatile, and we're doing a cache pass. CachedMaxChildLayer = SCompoundWidget::OnPaint( Args.EnableCaching(SharedThis(MutableThis), RootCacheNode, true, false), AllottedGeometry, MyClippingRect, *CachedWindowElements.Get(), LayerId, InWidgetStyle, bParentEnabled); if ( bCacheRelativeTransforms ) { CachedAbsolutePosition = AllottedGeometry.Position; } LastLayerId = LayerId; LastHitTestIndex = Args.GetLastHitTestIndex(); bIsInvalidating = false; } // The hit test grid is actually populated during the initial cache phase, so don't bother // recording the hit test geometry on the same frame that we regenerate the cache. if ( bWasCachingNeeded == false ) { RootCacheNode->RecordHittestGeometry(Args.GetGrid(), Args.GetLastHitTestIndex()); } if ( bCacheRelativeTransforms ) { FVector2D DeltaPosition = AllottedGeometry.Position - CachedAbsolutePosition; const TArray<FSlateDrawElement>& CachedElements = CachedWindowElements->GetDrawElements(); const int32 CachedElementCount = CachedElements.Num(); for ( int32 Index = 0; Index < CachedElementCount; Index++ ) { const FSlateDrawElement& LocalElement = CachedElements[Index]; FSlateDrawElement AbsElement = LocalElement; AbsElement.SetPosition(LocalElement.GetPosition() + DeltaPosition); AbsElement.SetClippingRect(LocalElement.GetClippingRect().OffsetBy(DeltaPosition)); OutDrawElements.AddItem(AbsElement); } } else { OutDrawElements.AppendDrawElements(CachedWindowElements->GetDrawElements()); } int32 OutMaxChildLayer = CachedMaxChildLayer; // Paint the volatile elements if ( CachedWindowElements.IsValid() ) { OutMaxChildLayer = FMath::Max(CachedMaxChildLayer, CachedWindowElements->PaintVolatile(OutDrawElements)); } #if !UE_BUILD_SHIPPING if ( IsInvalidationDebuggingEnabled() ) { // Draw a green or red border depending on if we were invalidated this frame. { check(Args.IsCaching() == false); //const bool bShowOutlineAsCached = Args.IsCaching() || bWasCachingNeeded == false; const FLinearColor DebugTint = bWasCachingNeeded ? FLinearColor::Red : FLinearColor::Green; FGeometry ScaledOutline = AllottedGeometry.MakeChild(FVector2D(0, 0), AllottedGeometry.GetLocalSize() * AllottedGeometry.Scale, Inverse(AllottedGeometry.Scale)); FSlateDrawElement::MakeBox( OutDrawElements, ++OutMaxChildLayer, ScaledOutline.ToPaintGeometry(), FCoreStyle::Get().GetBrush(TEXT("Debug.Border")), MyClippingRect, ESlateDrawEffect::None, DebugTint ); } // Draw a yellow outline around any volatile elements. const TArray< TSharedRef<FSlateWindowElementList::FVolatilePaint> >& VolatileElements = CachedWindowElements->GetVolatileElements(); for ( const TSharedRef<FSlateWindowElementList::FVolatilePaint>& VolatileElement : VolatileElements ) { FSlateDrawElement::MakeBox( OutDrawElements, ++OutMaxChildLayer, VolatileElement->GetGeometry().ToPaintGeometry(), FCoreStyle::Get().GetBrush(TEXT("FocusRectangle")), MyClippingRect, ESlateDrawEffect::None, FLinearColor::Yellow ); } // Draw a white flash for any widget that invalidated us this frame. for ( TWeakPtr<SWidget> Invalidator : InvalidatorWidgets ) { TSharedPtr<SWidget> SafeInvalidator = Invalidator.Pin(); if ( SafeInvalidator.IsValid() ) { FWidgetPath WidgetPath; if ( FSlateApplication::Get().GeneratePathToWidgetUnchecked(SafeInvalidator.ToSharedRef(), WidgetPath, EVisibility::All) ) { FArrangedWidget ArrangedWidget = WidgetPath.FindArrangedWidget(SafeInvalidator.ToSharedRef()).Get(FArrangedWidget::NullWidget); ArrangedWidget.Geometry.AppendTransform( FSlateLayoutTransform(Inverse(Args.GetWindowToDesktopTransform())) ); FSlateDrawElement::MakeBox( OutDrawElements, ++OutMaxChildLayer, ArrangedWidget.Geometry.ToPaintGeometry(), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), MyClippingRect, ESlateDrawEffect::None, FLinearColor::White.CopyWithNewOpacity(0.6f) ); } } } InvalidatorWidgets.Reset(); } #endif return OutMaxChildLayer; } else { return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); } }
int32 FThumbnailSection::OnPaintSection( FSequencerSectionPainter& InPainter ) const { if (!GetDefault<UMovieSceneUserThumbnailSettings>()->bDrawThumbnails) { return InPainter.LayerId; } static const float SectionThumbnailPadding = 4.f; const ESlateDrawEffect::Type DrawEffects = InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; int32 LayerId = InPainter.LayerId; const FGeometry& SectionGeometry = InPainter.SectionGeometry; // @todo Sequencer: Need a way to visualize the key here const TRange<float> VisibleRange = SequencerPtr.Pin()->GetViewRange(); const TRange<float> SectionRange = Section->IsInfinite() ? VisibleRange : Section->GetRange(); const float TimePerPx = SectionRange.Size<float>() / InPainter.SectionGeometry.GetLocalSize().X; FSlateRect ThumbnailClipRect = SectionGeometry.GetClippingRect().InsetBy(FMargin(SectionThumbnailPadding, 0.f)).IntersectionWith(InPainter.SectionClippingRect); for (const TSharedPtr<FTrackEditorThumbnail>& Thumbnail : ThumbnailCache.GetThumbnails()) { const float Fade = Thumbnail->bHasFinishedDrawing ? Thumbnail->GetFadeInCurve() : 1.f; FIntPoint ThumbnailSize = Thumbnail->GetSize(); // Calculate the paint geometry for this thumbnail TOptional<float> SingleReferenceFrame = ThumbnailCache.GetSingleReferenceFrame(); // Single thumbnails are always draw at the start of the section, clamped to the visible range // Thumbnail sequences draw relative to their actual position in the sequence const int32 Offset = SingleReferenceFrame.IsSet() ? FMath::Max((VisibleRange.GetLowerBoundValue() - SectionRange.GetLowerBoundValue()) / TimePerPx, 0.f) + SectionThumbnailPadding : (Thumbnail->GetTimeRange().GetLowerBoundValue() - SectionRange.GetLowerBoundValue()) / TimePerPx; FPaintGeometry PaintGeometry = SectionGeometry.ToPaintGeometry( ThumbnailSize, FSlateLayoutTransform( SectionGeometry.Scale, FVector2D( Offset, (SectionGeometry.GetLocalSize().Y - ThumbnailSize.Y)*.5f) ) ); if (Fade <= 1.f) { FSlateDrawElement::MakeViewport( InPainter.DrawElements, LayerId, PaintGeometry, Thumbnail, ThumbnailClipRect, DrawEffects | ESlateDrawEffect::NoGamma, FLinearColor(1.f, 1.f, 1.f, 1.f - Fade) ); } } return LayerId + 2; }
int32 FSlateTextUnderlineLineHighlighter::OnPaint(const FPaintArgs& Args, const FTextLayout::FLineView& Line, const float OffsetX, const float Width, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { TSharedRef<FSlateFontCache> FontCache = FSlateApplication::Get().GetRenderer()->GetFontCache(); const uint16 MaxHeight = FontCache->GetMaxCharacterHeight(FontInfo, AllottedGeometry.Scale); const int16 Baseline = FontCache->GetBaseline(FontInfo, AllottedGeometry.Scale); int16 UnderlinePos, UnderlineThickness; FontCache->GetUnderlineMetrics(FontInfo, AllottedGeometry.Scale, UnderlinePos, UnderlineThickness); const FVector2D Location(Line.Offset.X + OffsetX, Line.Offset.Y + MaxHeight + Baseline - (UnderlinePos * 0.5f)); const FVector2D Size(Width, FMath::Max<int16>(1, UnderlineThickness)); // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry const float InverseScale = Inverse(AllottedGeometry.Scale); if (Size.X) { const FLinearColor LineColorAndOpacity = ColorAndOpacity.GetColor(InWidgetStyle); const bool ShouldDropShadow = ShadowColorAndOpacity.A > 0.f && ShadowOffset.SizeSquared() > 0.f; // A negative shadow offset should be applied as a positive offset to the underline to avoid clipping issues const FVector2D DrawShadowOffset( (ShadowOffset.X > 0.0f) ? ShadowOffset.X * AllottedGeometry.Scale : 0.0f, (ShadowOffset.Y > 0.0f) ? ShadowOffset.Y * AllottedGeometry.Scale : 0.0f ); const FVector2D DrawUnderlineOffset( (ShadowOffset.X < 0.0f) ? -ShadowOffset.X * AllottedGeometry.Scale : 0.0f, (ShadowOffset.Y < 0.0f) ? -ShadowOffset.Y * AllottedGeometry.Scale : 0.0f ); // Draw the optional shadow if (ShouldDropShadow) { FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, Size), FSlateLayoutTransform(TransformPoint(InverseScale, Location + DrawShadowOffset))), &UnderlineBrush, MyClippingRect, bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, ShadowColorAndOpacity * InWidgetStyle.GetColorAndOpacityTint() ); } // Draw underline FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(TransformVector(InverseScale, Size), FSlateLayoutTransform(TransformPoint(InverseScale, Location + DrawUnderlineOffset))), &UnderlineBrush, MyClippingRect, bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect, LineColorAndOpacity * InWidgetStyle.GetColorAndOpacityTint() ); } return LayerId; }