コード例 #1
0
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;
		}
	}
}
コード例 #2
0
ファイル: SScaleBox.cpp プロジェクト: 1vanK/AHRUnrealEngine
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
		) );
	}
}
コード例 #3
0
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())))
		);
}
コード例 #4
0
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) );
	}
}
コード例 #5
0
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)));
	}
}
コード例 #6
0
ファイル: SSplitter.cpp プロジェクト: amyvmiwei/UnrealEngine4
/**
* 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] ) );
	}
}
コード例 #7
0
ファイル: SMenuAnchor.cpp プロジェクト: 1vanK/AHRUnrealEngine
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 ) );
	}
}
コード例 #8
0
ファイル: SSplitter.cpp プロジェクト: amyvmiwei/UnrealEngine4
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] ) );
	}
}
コード例 #9
0
ファイル: SFxWidget.cpp プロジェクト: 1vanK/AHRUnrealEngine
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));
	}
}
コード例 #10
0
ファイル: SGraphPanel.cpp プロジェクト: kidaa/UnrealEngineVR
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() ) );
		}
	}
}
コード例 #11
0
ファイル: SWeakWidget.cpp プロジェクト: kidaa/UnrealEngineVR
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
			) );
	}
}
コード例 #12
0
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)));
	}
}
コード例 #13
0
ファイル: SDPIScaler.cpp プロジェクト: kidaa/UnrealEngineVR
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));
		}
	}
コード例 #15
0
ファイル: SZoomPan.cpp プロジェクト: kidaa/UnrealEngineVR
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()
		) );
	}
}
コード例 #16
0
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));
	});
}
コード例 #17
0
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)
			)
		);
	}
}
コード例 #18
0
	/**  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()
					));
			}
		}
	}
コード例 #19
0
ファイル: STrack.cpp プロジェクト: Tigrouzen/UnrealEngine-4
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) );
	}
}
コード例 #20
0
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() )
				);
		}
	}
}
コード例 #21
0
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)
			));
		}
	}
}
コード例 #22
0
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)
				));
		}
	}
}
コード例 #23
0
ファイル: SConstraintCanvas.cpp プロジェクト: johndpope/UE4
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
			));
		}
	}
}
コード例 #24
0
ファイル: SWrapBox.cpp プロジェクト: xiangyuan/Unreal4
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;		
	}
}
コード例 #25
0
ファイル: SListPanel.cpp プロジェクト: xiangyuan/Unreal4
/**
 * 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;
			}
		}
	}
}
コード例 #26
0
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()));
	}
}
コード例 #27
0
ファイル: SGridPanel.cpp プロジェクト: colwalder/unrealengine
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)
                                        ));
        }
    }
}
コード例 #28
0
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 ) );
}