void SAnimationOutlinerView::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const float Padding = SequencerLayoutConstants::NodePadding; const float IndentAmount = SequencerLayoutConstants::IndentAmount; const float Scale = 1.0f; float CurrentHeight = 0; for (int32 WidgetIndex = 0; WidgetIndex < Children.Num(); ++WidgetIndex) { const TSharedRef<SAnimationOutlinerTreeNode>& Widget = Children[WidgetIndex]; EVisibility Visibility = Widget->GetVisibility(); if( ArrangedChildren.Accepts( Visibility ) ) { const TSharedPtr<const FSequencerDisplayNode>& DisplayNode = Widget->GetDisplayNode(); // How large to make this node float HeightIncrement = DisplayNode->GetNodeHeight(); // How far to indent the widget float WidgetIndentOffset = IndentAmount*DisplayNode->GetTreeLevel(); // Place the widget at the current height, at the nodes desired size ArrangedChildren.AddWidget( Visibility, AllottedGeometry.MakeChild( Widget, FVector2D( WidgetIndentOffset, CurrentHeight ), FVector2D( AllottedGeometry.GetDrawSize().X-WidgetIndentOffset, HeightIncrement ), Scale ) ); // Compute the start height for the next widget CurrentHeight += HeightIncrement+Padding; } } }
void SScaleBox::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const EVisibility ChildVisibility = ChildSlot.GetWidget()->GetVisibility(); if ( ArrangedChildren.Accepts(ChildVisibility) ) { FVector2D DesiredSize = ChildSlot.GetWidget()->GetDesiredSize(); float FinalScale = 1; EStretch::Type CurrentStretch = Stretch.Get(); EStretchDirection::Type CurrentStretchDirection = StretchDirection.Get(); if ( DesiredSize.X != 0 && DesiredSize.Y != 0 ) { switch ( CurrentStretch ) { case EStretch::None: break; case EStretch::Fill: DesiredSize = AllottedGeometry.Size; break; case EStretch::ScaleToFit: FinalScale = FMath::Min(AllottedGeometry.Size.X / DesiredSize.X, AllottedGeometry.Size.Y / DesiredSize.Y); break; case EStretch::ScaleToFill: FinalScale = FMath::Max(AllottedGeometry.Size.X / DesiredSize.X, AllottedGeometry.Size.Y / DesiredSize.Y); break; } switch ( CurrentStretchDirection ) { case EStretchDirection::DownOnly: FinalScale = FMath::Min(FinalScale, 1.0f); break; case EStretchDirection::UpOnly: FinalScale = FMath::Max(FinalScale, 1.0f); break; } } FVector2D FinalOffset(0, 0); if ( CurrentStretch != EStretch::Fill ) { const FMargin SlotPadding(ChildSlot.SlotPadding.Get()); AlignmentArrangeResult XResult = AlignChild<Orient_Horizontal>(AllottedGeometry.Size.X, ChildSlot, SlotPadding, FinalScale, false); AlignmentArrangeResult YResult = AlignChild<Orient_Vertical>(AllottedGeometry.Size.Y, ChildSlot, SlotPadding, FinalScale, false); FinalOffset = FVector2D(XResult.Offset, YResult.Offset) * ( 1.0f / FinalScale ); } ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild( ChildSlot.GetWidget(), FinalOffset, DesiredSize, FinalScale ) ); } }
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()))) ); }
void SDockingTabWell::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // The specialized TabWell is dedicated to arranging tabs. // Tabs have uniform sizing (all tabs the same size). // TabWell also ignores widget visibilit, as it is not really // relevant. // The tab that is being dragged by the user, if any. TSharedPtr<SDockTab> TabBeingDragged = TabBeingDraggedPtr; const int32 NumChildren = Tabs.Num(); // Tabs have a uniform size. const FVector2D ChildSize = ComputeChildSize(AllottedGeometry); const float DraggedChildCenter = ChildBeingDraggedOffset + ChildSize.X / 2; // Arrange all the tabs left to right. float XOffset = 0; for( int32 TabIndex=0; TabIndex < NumChildren; ++TabIndex ) { const TSharedRef<SDockTab> CurTab = Tabs[TabIndex]; const float ChildWidthWithOverlap = ChildSize.X - CurTab->GetOverlapWidth(); // Is this spot reserved from the tab that is being dragged? if ( TabBeingDragged.IsValid() && XOffset <= DraggedChildCenter && DraggedChildCenter < (XOffset + ChildWidthWithOverlap) ) { // if so, leave some room to signify that this is where the dragged tab would end up XOffset += ChildWidthWithOverlap; } ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(CurTab, FVector2D(XOffset, 0), ChildSize) ); XOffset += ChildWidthWithOverlap; } // Arrange the tab currently being dragged by the user, if any if ( TabBeingDragged.IsValid() ) { ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( TabBeingDragged.ToSharedRef(), FVector2D(ChildBeingDraggedOffset,0), ChildSize) ); } }
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))); } }
/** * Panels arrange their children in a space described by the AllottedGeometry parameter. The results of the arrangement * should be returned by appending a FArrangedWidget pair for every child widget. See StackPanel for an example */ void SSplitter::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { TArray<FLayoutGeometry> LayoutChildren = ArrangeChildrenForLayout(AllottedGeometry); // Arrange the children horizontally or vertically. for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex) { ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( Children[ChildIndex].GetWidget(), LayoutChildren[ChildIndex] ) ); } }
void SMenuAnchor::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { ArrangeSingleChild( AllottedGeometry, ArrangedChildren, Children[0], FVector2D::UnitVector); if ( IsOpen() ) { // @todo umg na AllottedGeometry here is in Window-Space when computed via OnPaint. // The incorrect geometry causes the popup to fail workspace-edge tests. const FGeometry PopupGeometry = ComputeMenuPlacement( AllottedGeometry, Children[1].GetWidget()->GetDesiredSize(), Placement.Get() ); ArrangedChildren.AddWidget( FArrangedWidget( Children[1].GetWidget(), PopupGeometry ) ); } }
void SSplitter2x2::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { TArray<FLayoutGeometry> LayoutChildren = ArrangeChildrenForLayout(AllottedGeometry); for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex) { const FSlot& CurSlot = Children[ChildIndex]; // put them in their spot ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( Children[ChildIndex].GetWidget(), LayoutChildren[ChildIndex] ) ); } }
void SFxWidget::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const EVisibility MyVisibility = this->GetVisibility(); if ( ArrangedChildren.Accepts( MyVisibility ) ) { // Only layout scale affects the arranged geometry. const FSlateLayoutTransform LayoutTransform(LayoutScale.Get()); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( this->ChildSlot.GetWidget(), TransformVector(Inverse(LayoutTransform), AllottedGeometry.Size), LayoutTransform)); } }
void SGraphPanel::ArrangeChildrenForContextMenuSummon(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { // First pass nodes for (int32 ChildIndex = 0; ChildIndex < VisibleChildren.Num(); ++ChildIndex) { const TSharedRef<SNode>& SomeChild = VisibleChildren[ChildIndex]; if (!SomeChild->RequiresSecondPassLayout()) { ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( SomeChild, SomeChild->GetPosition() - ViewOffset, SomeChild->GetDesiredSizeForMarquee(), GetZoomAmount() ) ); } } // Second pass nodes for (int32 ChildIndex = 0; ChildIndex < VisibleChildren.Num(); ++ChildIndex) { const TSharedRef<SNode>& SomeChild = VisibleChildren[ChildIndex]; if (SomeChild->RequiresSecondPassLayout()) { SomeChild->PerformSecondPassLayout(NodeToWidgetLookup); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( SomeChild, SomeChild->GetPosition() - ViewOffset, SomeChild->GetDesiredSizeForMarquee(), GetZoomAmount() ) ); } } }
void SWeakWidget::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // We just want to show the child that we are presenting. Always stretch it to occupy all of the space. TSharedRef<SWidget> MyContent = WeakChild.GetWidget(); if( MyContent!=SNullWidget::NullWidget && ArrangedChildren.Accepts(MyContent->GetVisibility()) ) { ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( MyContent, FVector2D(0,0), AllottedGeometry.Size ) ); } }
void SAutoFolding::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { //这里处理添加到content里面的逻辑,对齐方式,显示方式 areaSize = AllottedGeometry.GetLocalSize(); float startX = contentMargin.Left; float startY = contentMargin.Top; for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex) { const SBoxPanel::FSlot& CurChild = Children[ChildIndex]; const EVisibility ChildVisibility = CurChild.GetWidget()->GetVisibility(); FVector2D size = CurChild.GetWidget()->GetDesiredSize(); ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild(CurChild.GetWidget(), FVector2D(startX, startY), FVector2D(size.X, size.Y))); } }
void SDPIScaler::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const EVisibility MyVisibility = this->GetVisibility(); if ( ArrangedChildren.Accepts( MyVisibility ) ) { const float MyDPIScale = DPIScale.Get(); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( this->ChildSlot.GetWidget(), FVector2D::ZeroVector, AllottedGeometry.Size / MyDPIScale, MyDPIScale )); } }
virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override { CachedSize = AllottedGeometry.GetLocalSize(); const TSharedRef<SWidget>& ChildWidget = ChildSlot.GetWidget(); if (ChildWidget->GetVisibility() != EVisibility::Collapsed) { const FVector2D& WidgetDesiredSize = ChildWidget->GetDesiredSize(); // Clamp the pan offset based on our current geometry SScrollableSnapshotImage* const NonConstThis = const_cast<SScrollableSnapshotImage*>(this); NonConstThis->ClampViewOffset(WidgetDesiredSize, CachedSize); ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(ChildWidget, PhysicalOffset, WidgetDesiredSize)); } }
void SZoomPan::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { const EVisibility ChildVisibility = ChildSlot.GetWidget()->GetVisibility(); if ( ArrangedChildren.Accepts(ChildVisibility) ) { const FMargin SlotPadding(ChildSlot.SlotPadding.Get()); AlignmentArrangeResult XResult = AlignChild<Orient_Horizontal>(AllottedGeometry.Size.X, ChildSlot, SlotPadding, 1); AlignmentArrangeResult YResult = AlignChild<Orient_Vertical>(AllottedGeometry.Size.Y, ChildSlot, SlotPadding, 1); ArrangedChildren.AddWidget( ChildVisibility, AllottedGeometry.MakeChild( ChildSlot.GetWidget(), FVector2D(XResult.Offset, YResult.Offset) - ViewOffset.Get(), ChildSlot.GetWidget()->GetDesiredSize(), ZoomAmount.Get() ) ); } }
void SWrapBox::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { const float WidthToWrapAt = PreferredWidth.Get(); FChildArranger::Arrange(*this, [&](const FSlot& Slot, const FChildArranger::FArrangementData& ArrangementData) { // Calculate offset and size in slot using alignment. const AlignmentArrangeResult XResult = AlignChild<Orient_Horizontal>(ArrangementData.SlotSize.X, Slot, Slot.SlotPadding.Get()); const AlignmentArrangeResult YResult = AlignChild<Orient_Vertical>(ArrangementData.SlotSize.Y, Slot, Slot.SlotPadding.Get()); // Note: Alignment offset is relative to slot offset. const FVector2D PostAlignmentOffset = ArrangementData.SlotOffset + FVector2D(XResult.Offset, YResult.Offset); const FVector2D PostAlignmentSize = FVector2D(XResult.Size, YResult.Size); ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(Slot.GetWidget(), PostAlignmentOffset, PostAlignmentSize)); }); }
void SBox::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const EVisibility& MyCurrentVisibility = this->GetVisibility(); if ( ArrangedChildren.Accepts( MyCurrentVisibility ) ) { const FMargin SlotPadding(ChildSlot.SlotPadding.Get()); AlignmentArrangeResult XAlignmentResult = AlignChild<Orient_Horizontal>( AllottedGeometry.Size.X, ChildSlot, SlotPadding ); AlignmentArrangeResult YAlignmentResult = AlignChild<Orient_Vertical>( AllottedGeometry.Size.Y, ChildSlot, SlotPadding ); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( ChildSlot.GetWidget(), FVector2D(XAlignmentResult.Offset, YAlignmentResult.Offset), FVector2D(XAlignmentResult.Size, YAlignmentResult.Size) ) ); } }
/** SWidget interface */ virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const override { for (int32 ChildIndex=0; ChildIndex < VisibleChildren.Num(); ++ChildIndex) { const auto Child = StaticCastSharedRef<SWorldTileItem>(VisibleChildren[ChildIndex]); const EVisibility ChildVisibility = Child->GetVisibility(); if (ArrangedChildren.Accepts(ChildVisibility)) { FVector2D ChildPos = Child->GetPosition(); ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild(Child, ChildPos - GetViewOffset(), Child->GetDesiredSize(), GetZoomAmount() )); } } }
void STrack::ArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { for ( auto TrackIter = TrackNodes.CreateConstIterator() ; TrackIter ; ++TrackIter ) { TSharedRef<STrackNode> TrackNode = (*TrackIter); if (TrackNode->bBeingDragged) { continue; } // our desired size is sum of all children // this isn't precisely correct size, but it is minimal required size TrackNode->CacheTrackGeometry(AllottedGeometry); FVector2D Offset = TrackNode->GetOffsetRelativeToParent(AllottedGeometry); FVector2D Size = TrackNode->GetSizeRelativeToParent(AllottedGeometry); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(TrackNode, Offset, Size) ); } }
void SSequencerSectionAreaView::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { int32 MaxRowIndex = 0; for( int32 WidgetIndex = 0; WidgetIndex < Children.Num(); ++WidgetIndex ) { const TSharedRef<SSection>& Widget = Children[WidgetIndex]; TSharedPtr<ISequencerSection> SectionInterface = Widget->GetSectionInterface(); MaxRowIndex = FMath::Max(MaxRowIndex, SectionInterface->GetSectionObject()->GetRowIndex()); } int32 MaxTracks = MaxRowIndex + 1; float SectionHeight = GetSectionAreaHeight(); FTimeToPixel TimeToPixelConverter = GetTimeToPixel( AllottedGeometry ); for( int32 WidgetIndex = 0; WidgetIndex < Children.Num(); ++WidgetIndex ) { const TSharedRef<SSection>& Widget = Children[WidgetIndex]; TSharedPtr<ISequencerSection> SectionInterface = Widget->GetSectionInterface(); int32 RowIndex = SectionInterface->GetSectionObject()->GetRowIndex(); FGeometry SectionGeometry = SequencerSectionUtils::GetSectionGeometry( AllottedGeometry, RowIndex, MaxTracks, SectionHeight, SectionInterface, TimeToPixelConverter ); EVisibility Visibility = Widget->GetVisibility(); if( ArrangedChildren.Accepts( Visibility ) ) { Widget->CacheParentGeometry(AllottedGeometry); ArrangedChildren.AddWidget( Visibility, AllottedGeometry.MakeChild( Widget, SectionGeometry.Position, SectionGeometry.GetDrawSize() ) ); } } }
void SGridPanel::ArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // PREPARE PHASE // Prepare some data for arranging children. // FinalColumns will be populated with column sizes that include the stretched column sizes. // Then we will build partial sums so that we can easily handle column spans. // Repeat the same for rows. float ColumnCoeffTotal = 0.0f; TArray<float> FinalColumns; if ( Columns.Num() > 0 ) { FinalColumns.AddUninitialized(Columns.Num()); FinalColumns[FinalColumns.Num()-1] = 0.0f; } float RowCoeffTotal = 0.0f; TArray<float> FinalRows; if ( Rows.Num() > 0 ) { FinalRows.AddUninitialized(Rows.Num()); FinalRows[FinalRows.Num()-1] = 0.0f; } FVector2D FlexSpace = AllottedGeometry.Size; const int32 ColFillCoeffsLength = ColFillCoefficients.Num(); for(int32 ColIndex=0; ColIndex < Columns.Num(); ++ColIndex) { // Compute the total space available for stretchy columns. if (ColIndex >= ColFillCoeffsLength || ColFillCoefficients[ColIndex] == 0) { FlexSpace.X -= Columns[ColIndex]; } else //(ColIndex < ColFillCoeffsLength) { // Compute the denominator for dividing up the stretchy column space ColumnCoeffTotal += ColFillCoefficients[ColIndex]; } } for(int32 ColIndex=0; ColIndex < Columns.Num(); ++ColIndex) { // Figure out how big each column needs to be FinalColumns[ColIndex] = (ColIndex < ColFillCoeffsLength && ColFillCoefficients[ColIndex] != 0) ? (ColFillCoefficients[ColIndex] / ColumnCoeffTotal * FlexSpace.X) : Columns[ColIndex]; } const int32 RowFillCoeffsLength = RowFillCoefficients.Num(); for(int32 RowIndex=0; RowIndex < Rows.Num(); ++RowIndex) { // Compute the total space available for stretchy rows. if (RowIndex >= RowFillCoeffsLength || RowFillCoefficients[RowIndex] == 0) { FlexSpace.Y -= Rows[RowIndex]; } else //(RowIndex < RowFillCoeffsLength) { // Compute the denominator for dividing up the stretchy row space RowCoeffTotal += RowFillCoefficients[RowIndex]; } } for(int32 RowIndex=0; RowIndex < Rows.Num(); ++RowIndex) { // Compute how big each row needs to be FinalRows[RowIndex] = (RowIndex < RowFillCoeffsLength && RowFillCoefficients[RowIndex] != 0) ? (RowFillCoefficients[RowIndex] / RowCoeffTotal * FlexSpace.Y) : Rows[RowIndex]; } // Build up partial sums for row and column sizes so that we can handle column and row spans conveniently. ComputePartialSums(FinalColumns); ComputePartialSums(FinalRows); // ARRANGE PHASE for( int32 SlotIndex=0; SlotIndex < Slots.Num(); ++SlotIndex ) { const FSlot& CurSlot = Slots[SlotIndex]; const EVisibility ChildVisibility = CurSlot.Widget->GetVisibility(); if ( ArrangedChildren.Accepts(ChildVisibility) ) { // Figure out the position of this cell. const FVector2D ThisCellOffset( FinalColumns[CurSlot.ColumnParam], FinalRows[CurSlot.RowParam] ); // Figure out the size of this slot; takes row span into account. // We use the properties of partial sums arrays to achieve this. const FVector2D CellSize( FinalColumns[CurSlot.ColumnParam+CurSlot.ColumnSpanParam] - ThisCellOffset.X , FinalRows[CurSlot.RowParam+CurSlot.RowSpanParam] - ThisCellOffset.Y ); // Do the standard arrangement of elements within a slot // Takes care of alignment and padding. const FMargin SlotPadding(CurSlot.SlotPadding.Get()); AlignmentArrangeResult XAxisResult = AlignChild<Orient_Horizontal>( CellSize.X, CurSlot, SlotPadding ); AlignmentArrangeResult YAxisResult = AlignChild<Orient_Vertical>( CellSize.Y, CurSlot, SlotPadding ); // Output the result ArrangedChildren.AddWidget( ChildVisibility, AllottedGeometry.MakeChild( CurSlot.Widget, ThisCellOffset + FVector2D( XAxisResult.Offset, YAxisResult.Offset ) + CurSlot.NudgeParam, FVector2D(XAxisResult.Size, YAxisResult.Size) )); } } }
void SResponsiveGridPanel::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // Don't attempt to array anything if we don't have any slots allocated. if ( Slots.Num() == 0 ) { return; } // PREPARE PHASE // Prepare some data for arranging children. // FinalColumns will be populated with column sizes that include the stretched column sizes. // Then we will build partial sums so that we can easily handle column spans. const FVector2D LocalSize = AllottedGeometry.GetLocalSize(); FVector2D FlexSpace = LocalSize; PreviousWidth = LocalSize.X; const float FullColumnGutter = (ColumnGutter * 2); const float FullRowGutter = (RowGutter * 2); TArray<float> Rows; TArray<float> RowToSlot; TArray<float> Columns; ComputeDesiredCellSizes(LocalSize.X, Columns, Rows, RowToSlot); check(Rows.Num() == RowToSlot.Num()); TArray<float> FinalColumns; if (Columns.Num() > 0) { FinalColumns.AddUninitialized(Columns.Num()); FinalColumns[FinalColumns.Num() - 1] = 0.0f; // We need an extra cell at the end for easily figuring out the size across any number of cells FinalColumns.AddZeroed((TotalColumns + 1) - Columns.Num()); } // You can't remove the gutter space from the flexspace for the columns because you don't know how // many columns there actually are in a single row at this point float ColumnCoeffTotal = TotalColumns; for (int32 ColIndex = 0; ColIndex < Columns.Num(); ++ColIndex) { // Figure out how big each column needs to be FinalColumns[ColIndex] = (1.0f / ColumnCoeffTotal * FlexSpace.X); } // FinalColumns will be populated with column sizes that include the stretched column sizes. // Then we will build partial sums so that we can easily handle column spans. float RowCoeffTotal = 0.0f; TArray<float> FinalRows; if (Rows.Num() > 0) { FinalRows.AddUninitialized(Rows.Num()); FinalRows[FinalRows.Num() - 1] = 0.0f; // We need an extra cell at the end for easily figuring out the size across any number of cells FinalRows.AddZeroed(1); } FlexSpace.Y -= (RowGutter * 2) * (Slots[Slots.Num() - 1].RowParam); const int32 RowFillCoeffsLength = RowFillCoefficients.Num(); for (int32 RowIndex = 0; RowIndex < Rows.Num(); ++RowIndex) { // Compute the total space available for stretchy rows. if (RowToSlot[RowIndex] >= RowFillCoeffsLength || RowFillCoefficients[RowToSlot[RowIndex]] == 0) { FlexSpace.Y -= Rows[RowIndex]; } else //(RowIndex < RowFillCoeffsLength) { // Compute the denominator for dividing up the stretchy row space RowCoeffTotal += RowFillCoefficients[RowToSlot[RowIndex]]; } } for (int32 RowIndex = 0; RowIndex < Rows.Num(); ++RowIndex) { // Compute how big each row needs to be FinalRows[RowIndex] = (RowToSlot[RowIndex] < RowFillCoeffsLength && RowFillCoefficients[RowToSlot[RowIndex]] != 0) ? (RowFillCoefficients[RowToSlot[RowIndex]] / RowCoeffTotal * FlexSpace.Y) : Rows[RowIndex]; } // Build up partial sums for row and column sizes so that we can handle column and row spans conveniently. ComputePartialSums(FinalColumns); ComputePartialSums(FinalRows); // ARRANGE PHASE int32 ColumnsSoFar = 0; int32 CurrentRow = INDEX_NONE; int32 LastRowParam = INDEX_NONE; float RowGuttersSoFar = 0; for (int32 SlotIndex = 0; SlotIndex < Slots.Num(); ++SlotIndex) { const FSlot& CurSlot = Slots[SlotIndex]; const EVisibility ChildVisibility = CurSlot.GetWidget()->GetVisibility(); if (ChildVisibility != EVisibility::Collapsed) { // Find the appropriate column layout for the slot FSlot::FColumnLayout ColumnLayout; ColumnLayout.Span = TotalColumns; ColumnLayout.Offset = 0; for (int32 Index = CurSlot.ColumnLayouts.Num() - 1; Index >= 0; Index--) { if (CurSlot.ColumnLayouts[Index].LayoutSize < LocalSize.X) { ColumnLayout = CurSlot.ColumnLayouts[Index]; break; } } if (ColumnLayout.Span == 0) { continue; } if (CurSlot.RowParam != LastRowParam) { ColumnsSoFar = 0; LastRowParam = CurSlot.RowParam; ++CurrentRow; if (LastRowParam > 0) { RowGuttersSoFar += FullRowGutter; } } // Figure out the position of this cell. int32 StartColumn = ColumnsSoFar + ColumnLayout.Offset; int32 EndColumn = StartColumn + ColumnLayout.Span; ColumnsSoFar = FMath::Max(EndColumn, ColumnsSoFar); if (ColumnsSoFar > TotalColumns) { StartColumn = 0; EndColumn = StartColumn + ColumnLayout.Span; ColumnsSoFar = EndColumn - StartColumn; ++CurrentRow; } FVector2D ThisCellOffset(FinalColumns[StartColumn], FinalRows[CurrentRow]); // Account for the gutters applied to columns before the starting column of this cell if (StartColumn > 0) { ThisCellOffset.X += FullColumnGutter; } // Figure out the size of this slot; takes row span into account. // We use the properties of partial sums arrays to achieve this. FVector2D CellSize( FinalColumns[EndColumn] - ThisCellOffset.X, FinalRows[CurrentRow + 1] - ThisCellOffset.Y); // Do the standard arrangement of elements within a slot // Takes care of alignment and padding. FMargin SlotPadding(CurSlot.SlotPadding.Get()); AlignmentArrangeResult XAxisResult = AlignChild<Orient_Horizontal>(CellSize.X, CurSlot, SlotPadding); AlignmentArrangeResult YAxisResult = AlignChild<Orient_Vertical>(CellSize.Y, CurSlot, SlotPadding); // The row gutters have already been accounted for in the cell size by removing them from the flexspace, // so we just need to offset the cells appropriately ThisCellOffset.Y += RowGuttersSoFar; // Output the result ArrangedChildren.AddWidget(ChildVisibility, AllottedGeometry.MakeChild( CurSlot.GetWidget(), ThisCellOffset + FVector2D(XAxisResult.Offset, YAxisResult.Offset), FVector2D(XAxisResult.Size, YAxisResult.Size) )); } } }
void SConstraintCanvas::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { CachedGeometry = AllottedGeometry; if (Children.Num() > 0) { // Sort the children based on zorder. TArray< FChildZOrder > SlotOrder; for ( int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex ) { const SConstraintCanvas::FSlot& CurChild = Children[ChildIndex]; FChildZOrder Order; Order.ChildIndex = ChildIndex; Order.ZOrder = CurChild.ZOrderAttr.Get(); SlotOrder.Add( Order ); } SlotOrder.Sort(FSortSlotsByZOrder()); // Arrange the children now in their proper z-order. for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex) { const FChildZOrder& CurSlot = SlotOrder[ChildIndex]; const SConstraintCanvas::FSlot& CurChild = Children[CurSlot.ChildIndex]; const FMargin Offset = CurChild.OffsetAttr.Get(); const FVector2D Alignment = CurChild.AlignmentAttr.Get(); const FAnchors Anchors = CurChild.AnchorsAttr.Get(); const bool AutoSize = CurChild.AutoSizeAttr.Get(); const FMargin AnchorPixels = FMargin(Anchors.Minimum.X * AllottedGeometry.Size.X, Anchors.Minimum.Y * AllottedGeometry.Size.Y, Anchors.Maximum.X * AllottedGeometry.Size.X, Anchors.Maximum.Y * AllottedGeometry.Size.Y); const bool bIsHorizontalStretch = Anchors.Minimum.X != Anchors.Maximum.X; const bool bIsVerticalStretch = Anchors.Minimum.Y != Anchors.Maximum.Y; const FVector2D SlotSize = FVector2D(Offset.Right, Offset.Bottom); const FVector2D WidgetDesiredSize = CurChild.GetWidget()->GetDesiredSize(); const FVector2D Size = AutoSize ? WidgetDesiredSize : SlotSize; // Calculate the offset based on the pivot position. FVector2D AlignmentOffset = Size * Alignment; // Calculate the local position based on the anchor and position offset. FVector2D LocalPosition, LocalSize; // Calculate the position and size based on the horizontal stretch or non-stretch if ( bIsHorizontalStretch ) { LocalPosition.X = AnchorPixels.Left + Offset.Left; LocalSize.X = AnchorPixels.Right - LocalPosition.X - Offset.Right; } else { LocalPosition.X = AnchorPixels.Left + Offset.Left - AlignmentOffset.X; LocalSize.X = Size.X; } // Calculate the position and size based on the vertical stretch or non-stretch if ( bIsVerticalStretch ) { LocalPosition.Y = AnchorPixels.Top + Offset.Top; LocalSize.Y = AnchorPixels.Bottom - LocalPosition.Y - Offset.Bottom; } else { LocalPosition.Y = AnchorPixels.Top + Offset.Top - AlignmentOffset.Y; LocalSize.Y = Size.Y; } // Add the information about this child to the output list (ArrangedChildren) ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( // The child widget being arranged CurChild.GetWidget(), // Child's local position (i.e. position within parent) LocalPosition, // Child's size LocalSize )); } } }
void SWrapBox::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { const float MyPreferredWidth = PreferredWidth.Get(); // PREPASS // Figure out when we start wrapping and how tall each line (aka. row) needs to be TArray<int32, TInlineAllocator<3> > WidgetIndexStartsNewLine; TArray<float, TInlineAllocator<3> > LineHeights; { float WidthSoFar = 0; float LineHeightSoFar = 0; for ( int32 ChildIndex=0; ChildIndex < Slots.Num(); ++ChildIndex ) { const TSharedRef<SWidget>& ThisChild = Slots[ChildIndex].GetWidget(); // If slot isn't the first one on the line, we need to add the inner slot padding. const float ConditionPaddingX = ( WidthSoFar == 0 ) ? 0 : InnerSlotPadding.X; FVector2D ThisSlotSize = ThisChild->GetDesiredSize() + Slots[ChildIndex].SlotPadding.Get().GetDesiredSize(); // If the width is smaller than this slots fill limit, we need to account for it filling the line // and forcing all controls that follow it to wrap. if ( Slots[ChildIndex].SlotFillLineWhenWidthLessThan.IsSet() ) { if ( MyPreferredWidth < Slots[ChildIndex].SlotFillLineWhenWidthLessThan.GetValue() ) { ThisSlotSize.X = MyPreferredWidth; } } if ( ( WidthSoFar + ThisSlotSize.X + ConditionPaddingX ) > MyPreferredWidth ) { WidgetIndexStartsNewLine.Add( ChildIndex ); LineHeights.Add( LineHeightSoFar ); WidthSoFar = ThisSlotSize.X + ConditionPaddingX; LineHeightSoFar = ThisSlotSize.Y; } else { WidthSoFar += ThisSlotSize.X; LineHeightSoFar = FMath::Max( ThisSlotSize.Y + InnerSlotPadding.Y, LineHeightSoFar ); } } // Add trailing values so that we won't out of bound (easier than adding extra conditionals) LineHeights.Add(LineHeightSoFar); WidgetIndexStartsNewLine.Add(INDEX_NONE); } // ACTUALLY ARRANGE float XOffsetSoFar = 0; float YOffsetSoFar = 0; for ( int32 CurrentLineIndex=0, ChildIndex=0; ChildIndex < Slots.Num(); ++ChildIndex ) { // If slot isn't on the first line, we need to add the inner slot padding. const float ConditionPaddingY = ( YOffsetSoFar == 0 ) ? 0 : InnerSlotPadding.Y; // Do we need to start a new line? const bool bStartNewLine = ( WidgetIndexStartsNewLine[CurrentLineIndex] == ChildIndex ); if (bStartNewLine) { // New line starts at the very left XOffsetSoFar = 0; // YOffsetSoFar += LineHeights[CurrentLineIndex] + InnerSlotPadding.Y; // Move on to the next line. CurrentLineIndex++; } // If slot isn't the first one on the line, we need to add the inner slot padding. const float ConditionPaddingX = ( XOffsetSoFar == 0 ) ? 0 : InnerSlotPadding.X; // Is this the last widget on the line? bool bLastWidgetOnLine = ((ChildIndex + 1) >= Slots.Num()) || WidgetIndexStartsNewLine[CurrentLineIndex] == ( ChildIndex + 1 ); const float CurrentLineHeight = LineHeights[ CurrentLineIndex ]; const FMargin& SlotPadding( Slots[ChildIndex].SlotPadding.Get() ); const TSharedRef<SWidget>& ThisChild = Slots[ChildIndex].GetWidget(); float ThisSlotSizeX = ThisChild->GetDesiredSize().X + SlotPadding.GetTotalSpaceAlong<Orient_Horizontal>(); // If the width is smaller than this slots fill limit, we need to account for it filling the line // and forcing all controls that follow it to wrap. if ( Slots[ChildIndex].SlotFillLineWhenWidthLessThan.IsSet() ) { if ( MyPreferredWidth < Slots[ChildIndex].SlotFillLineWhenWidthLessThan.GetValue() ) { ThisSlotSizeX = MyPreferredWidth; } } // If this slot fills empty space, we need to have it fill the remaining space on the line. if ( bLastWidgetOnLine && Slots[ChildIndex].bSlotFillEmptySpace ) { ThisSlotSizeX = MyPreferredWidth - (XOffsetSoFar - ConditionPaddingX); } // Horizontal alignment will always be equivalent to HAlign_Fill due to the nature of the widget. // But we still need to account for padding. AlignmentArrangeResult XAlignmentResult = AlignChild<Orient_Horizontal>( ThisSlotSizeX, Slots[ChildIndex], SlotPadding + ConditionPaddingX ); AlignmentArrangeResult YAlignmentResult = AlignChild<Orient_Vertical>( CurrentLineHeight, Slots[ChildIndex], SlotPadding + ConditionPaddingY ); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( ThisChild, FVector2D( XOffsetSoFar + XAlignmentResult.Offset, YOffsetSoFar + YAlignmentResult.Offset), FVector2D( XAlignmentResult.Size, YAlignmentResult.Size ) ) ); XOffsetSoFar += ThisSlotSizeX; } }
/** * Arrange the children top-to-bottom with not additional layout info. */ void SListPanel::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { if ( ShouldArrangeHorizontally() ) { const EListItemAlignment ListItemAlignment = ItemAlignment.Get(); // This is a tile view list, arrange items horizontally until there is no more room then create a new row. const float AllottedWidth = AllottedGeometry.Size.X; const float ItemPadding = GetItemPadding(AllottedGeometry, ListItemAlignment); const float HalfItemPadding = ItemPadding * 0.5; const float LocalItemWidth = GetItemWidth(AllottedGeometry, ListItemAlignment); const float LocalItemHeight = GetItemHeight(); float WidthSoFar = 0; float HeightSoFar = -FMath::FloorToInt(SmoothScrollOffsetInItems * LocalItemHeight) - OverscrollAmount; bool bIsNewLine = true; for( int32 ItemIndex = 0; ItemIndex < Children.Num(); ++ItemIndex ) { if ( bIsNewLine ) { if ( ListItemAlignment == EListItemAlignment::RightAligned || ListItemAlignment == EListItemAlignment::CenterAligned ) { const float LinePadding = GetLinePadding(AllottedGeometry, ItemIndex); if ( ListItemAlignment == EListItemAlignment::RightAligned ) { WidthSoFar += LinePadding; } else { const float HalfLinePadding = LinePadding * 0.5; WidthSoFar += HalfLinePadding; } } } ArrangedChildren.AddWidget( AllottedGeometry.MakeChild(Children[ItemIndex].GetWidget(), FVector2D(WidthSoFar + HalfItemPadding, HeightSoFar), FVector2D(LocalItemWidth, LocalItemHeight)) ); WidthSoFar += LocalItemWidth + ItemPadding; if ( WidthSoFar + LocalItemWidth + ItemPadding > AllottedWidth ) { WidthSoFar = 0; HeightSoFar += LocalItemHeight; bIsNewLine = true; } } } else { if (Children.Num() > 0) { // This is a normal list, arrange items vertically float HeightSoFar = -FMath::FloorToInt(SmoothScrollOffsetInItems * Children[0].GetWidget()->GetDesiredSize().Y)-OverscrollAmount; for( int32 ItemIndex = 0; ItemIndex < Children.Num(); ++ItemIndex ) { const FVector2D ItemDesiredSize = Children[ItemIndex].GetWidget()->GetDesiredSize(); const float LocalItemHeight = ItemDesiredSize.Y; // Note that ListPanel does not respect child Visibility. // It is simply not useful for ListPanels. ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( Children[ItemIndex].GetWidget(), FVector2D(0, HeightSoFar), FVector2D(AllottedGeometry.Size.X, LocalItemHeight) ) ); HeightSoFar += LocalItemHeight; } } } }
void STimingTrack::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { // To make this track look nice and have no overlapping nodes we're going to // treat this as a 1D collision problem and build/resolve islands until everything // is nicely resolved (or until we hit an upper limit as it can't be solved) // Helper holding info about a single node struct NodeData { NodeData(TSharedRef<STrackNode>& NodeRef, const FGeometry& Geometry) : Node(NodeRef) { // Separation of the nodes on the track const float NodeSeparation = 3.0f; Node->CacheTrackGeometry(Geometry); FVector2D Offset = Node->GetOffsetRelativeToParent(Geometry); FVector2D Size = Node->GetSizeRelativeToParent(Geometry); Offset.Y += (Geometry.GetLocalSize().Y - Size.Y) * 0.5f; ActualRect = FBox2D(Offset, Offset + Size); QueryRect = FBox2D(Offset - FVector2D(NodeSeparation, 0.0f), Offset + Size + FVector2D(NodeSeparation, 0.0f)); } TSharedRef<STrackNode> Node; // The node widget FBox2D ActualRect; // The actual render rect of the widget FBox2D QueryRect; // An expanded rect used to detect collisions }; // Helper holding list of overlapping nodes struct NodeIsland { TArray<NodeData*> Nodes; }; int32 NumNodes = TrackNodes.Num(); TArray<NodeData> SortedNodeData; SortedNodeData.Reserve(NumNodes); // List of collision islands TArray<NodeIsland> Islands; // Scaling info to translate between local positions and data values FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, AllottedGeometry.Size); for(int32 TrackIndex = 0; TrackIndex < NumNodes; ++TrackIndex) { TSharedRef<STrackNode> TrackNode = (TrackNodes[TrackIndex]); SortedNodeData.Add(NodeData(TrackNode, AllottedGeometry)); } const static int32 MaxRetries = 5; int32 Retries = 0; bool bResolved = true; while(bResolved && Retries < MaxRetries) { ++Retries; bResolved = false; for(int32 NodeIdx = 0; NodeIdx < NumNodes; ++NodeIdx) { NodeData& CurrentNode = SortedNodeData[NodeIdx]; // Island generation NodeIsland* CurrentIsland = nullptr; CurrentIsland = &Islands[Islands.AddZeroed()]; int32 Direction = -1; int32 Next = NodeIdx + 1; int32 HighestNode = NodeIdx; FBox2D& CurrentRect = CurrentNode.ActualRect; FBox2D CurrentQueryRect = CurrentNode.QueryRect; CurrentIsland->Nodes.Add(&CurrentNode); // Walk Nodes while(Next >= 0 && Next < NumNodes) { NodeData& NextNode = SortedNodeData[Next]; FBox2D& NextRect = NextNode.ActualRect; FBox2D& NextQueryRect = NextNode.QueryRect; if(NextQueryRect.Intersect(CurrentQueryRect)) { // Add to island CurrentIsland->Nodes.Add(&NextNode); HighestNode = Next; // Expand the current query CurrentQueryRect.Max = NextQueryRect.Max; } else { // No island, next node break; } ++Next; } // Skip processed nodes (those already in islands) NodeIdx = HighestNode; } // Separation of the nodes on the track const float NodeSeparation = 3.0f; for(NodeIsland& Island : Islands) { if(Island.Nodes.Num() == 1) { // Keep single nodes on the data track range but skip everything else FBox2D& NodeBox = Island.Nodes[0]->ActualRect; FBox2D& NodeQueryRect = Island.Nodes[0]->QueryRect; float Offset = 0.0f; float Begin = ScaleInfo.LocalXToInput(NodeBox.Min.X); float End = ScaleInfo.LocalXToInput(NodeBox.Max.X); if(Begin < 0) { Offset = ScaleInfo.InputToLocalX(-Begin); } else if(End > TrackMaxValue.Get()) { Offset = ScaleInfo.InputToLocalX(TrackMaxValue.Get() - End); } if(Offset != 0.0f) { NodeBox.Min.X += Offset; NodeBox.Max.X += Offset; NodeQueryRect.Min.X = NodeBox.Min.X - NodeSeparation; NodeQueryRect.Max.X = NodeBox.Max.X + NodeSeparation; } continue; } bResolved = true; // Island resolution int32 NumIslandNodes = Island.Nodes.Num(); float Width = FMath::Max<float>((NumIslandNodes - 1), 0.0f) * NodeSeparation; float Centre = 0.0f; for(NodeData* Node : Island.Nodes) { Width += Node->ActualRect.GetSize().X; Centre += Node->ActualRect.GetCenter().X; } Centre /= NumIslandNodes; // Make sure the group stays on the track float Begin = Centre - Width / 2.0f; float WidthAsInput = Width / ScaleInfo.PixelsPerInput; float BeginAsInput = FMath::Clamp(ScaleInfo.LocalXToInput(Begin), 0.0f, TrackMaxValue.Get() - WidthAsInput); Begin = ScaleInfo.InputToLocalX(BeginAsInput); for(int32 NodeIdx = 0 ; NodeIdx < NumIslandNodes ; ++NodeIdx) { FBox2D& NodeBox = Island.Nodes[NodeIdx]->ActualRect; float NodeWidth = NodeBox.GetSize().X; float SeparationOffset = NodeIdx * NodeSeparation; float PositionOffset = 0.0f; for(int32 PositionNodeIdx = 0 ; PositionNodeIdx < NodeIdx ; ++PositionNodeIdx) { PositionOffset += Island.Nodes[PositionNodeIdx]->ActualRect.GetSize().X; } FBox2D& OriginalRect = Island.Nodes[NodeIdx]->ActualRect; OriginalRect.Min.X = Begin + PositionOffset + SeparationOffset; OriginalRect.Max.X = OriginalRect.Min.X + NodeWidth; // Alter Query rect for next pass FBox2D& NodeQueryRect = Island.Nodes[NodeIdx]->QueryRect; NodeQueryRect.Min = OriginalRect.Min - FVector2D(NodeSeparation, 0.0f); NodeQueryRect.Max = OriginalRect.Max + FVector2D(NodeSeparation, 0.0f); } } } for(int32 TrackIndex = 0; TrackIndex < NumNodes; ++TrackIndex) { TSharedRef<STrackNode> TrackNode = (SortedNodeData[TrackIndex].Node); if(TrackNode->IsBeingDragged()) { continue; } FBox2D& Rect = SortedNodeData[TrackIndex].ActualRect; ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(TrackNode, Rect.Min, Rect.GetSize())); } }
void SGridPanel::OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { // PREPARE PHASE // Prepare some data for arranging children. // FinalColumns will be populated with column sizes that include the stretched column sizes. // Then we will build partial sums so that we can easily handle column spans. // Repeat the same for rows. float ColumnCoeffTotal = 0.0f; TArray<float> FinalColumns; if ( Columns.Num() > 0 ) { FinalColumns.AddUninitialized(Columns.Num()); FinalColumns[FinalColumns.Num()-1] = 0.0f; } float RowCoeffTotal = 0.0f; TArray<float> FinalRows; if ( Rows.Num() > 0 ) { FinalRows.AddUninitialized(Rows.Num()); FinalRows[FinalRows.Num()-1] = 0.0f; } CalculateStretchedCellSizes(FinalColumns, AllottedGeometry.Size.X, Columns, ColFillCoefficients); CalculateStretchedCellSizes(FinalRows, AllottedGeometry.Size.Y, Rows, RowFillCoefficients); // Build up partial sums for row and column sizes so that we can handle column and row spans conveniently. ComputePartialSums(FinalColumns); ComputePartialSums(FinalRows); // ARRANGE PHASE for( int32 SlotIndex=0; SlotIndex < Slots.Num(); ++SlotIndex ) { const FSlot& CurSlot = Slots[SlotIndex]; const EVisibility ChildVisibility = CurSlot.GetWidget()->GetVisibility(); if ( ArrangedChildren.Accepts(ChildVisibility) ) { // Figure out the position of this cell. const FVector2D ThisCellOffset( FinalColumns[CurSlot.ColumnParam], FinalRows[CurSlot.RowParam] ); // Figure out the size of this slot; takes row span into account. // We use the properties of partial sums arrays to achieve this. const FVector2D CellSize( FinalColumns[CurSlot.ColumnParam+CurSlot.ColumnSpanParam] - ThisCellOffset.X , FinalRows[CurSlot.RowParam+CurSlot.RowSpanParam] - ThisCellOffset.Y ); // Do the standard arrangement of elements within a slot // Takes care of alignment and padding. const FMargin SlotPadding(CurSlot.SlotPadding.Get()); AlignmentArrangeResult XAxisResult = AlignChild<Orient_Horizontal>( CellSize.X, CurSlot, SlotPadding ); AlignmentArrangeResult YAxisResult = AlignChild<Orient_Vertical>( CellSize.Y, CurSlot, SlotPadding ); // Output the result ArrangedChildren.AddWidget( ChildVisibility, AllottedGeometry.MakeChild( CurSlot.GetWidget(), ThisCellOffset + FVector2D( XAxisResult.Offset, YAxisResult.Offset ) + CurSlot.NudgeParam, FVector2D(XAxisResult.Size, YAxisResult.Size) )); } } }
void FSlateWidgetRun::ArrangeChildren( const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren ) const { ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( Info.Widget, Block->GetLocationOffset() * ( 1 / AllottedGeometry.Scale ), Block->GetSize() * ( 1 / AllottedGeometry.Scale ), 1.0f ) ); }