void SAnimationSegmentViewport::InitSkeleton()
{
	UObject *Object = NULL;
	AnimRefPropertyHandle->GetValue(Object);
	UAnimSequenceBase *AnimSequence = Cast<UAnimSequenceBase>(Object);
	USkeleton *Skeleton = NULL;
	if(AnimSequence != NULL)
	{
		Skeleton = AnimSequence->GetSkeleton();
	}

	if( PreviewComponent != NULL && Skeleton != NULL )
	{
		USkeletalMesh* PreviewMesh = Skeleton->GetAssetPreviewMesh(AnimSequence);
		if (PreviewMesh)
		{
			UAnimSingleNodeInstance * Preview = PreviewComponent->PreviewInstance;
			if((Preview == NULL || Preview->GetCurrentAsset() != AnimSequence) ||
				(PreviewComponent->SkeletalMesh != PreviewMesh))
			{
				PreviewComponent->SetSkeletalMesh(PreviewMesh);
				PreviewComponent->EnablePreview(true, AnimSequence, NULL);
				PreviewComponent->PreviewInstance->SetLooping(true);

				//Place the camera at a good viewer position
				FVector NewPosition = LevelViewportClient->GetViewLocation();
				NewPosition.Normalize();
				LevelViewportClient->SetViewLocation(NewPosition * (PreviewMesh->GetImportedBounds().SphereRadius*1.5f));
			}
		}
	}

	TargetSkeleton = Skeleton;
}
void FAnimMontageSegmentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	IDetailCategoryBuilder& SegmentCategory = DetailBuilder.EditCategory("Animation Segment", LOCTEXT("AnimationSegmentCategoryTitle", "Animation Segment") );

	SegmentCategory.AddProperty("AnimSegment.AnimReference").DisplayName( LOCTEXT("AnimationReferenceLabel", "Animation Reference") );

	SegmentCategory.AddProperty("AnimSegment.AnimStartTime").DisplayName( LOCTEXT("StartTimeLabel", "Start Time") );
	SegmentCategory.AddProperty("AnimSegment.AnimEndTime").DisplayName( LOCTEXT("EndTimeLabel", "End Time") );

	SegmentCategory.AddProperty("AnimSegment.AnimPlayRate").DisplayName( LOCTEXT("PlayRateLabel", "Play Rate") );
	SegmentCategory.AddProperty("AnimSegment.LoopingCount").DisplayName( LOCTEXT("LoopCountLabel", "Loop Count") );

	TSharedPtr<IPropertyHandle> InPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference");
	UObject *Object = NULL;
	InPropertyHandle->GetValue(Object);

	UAnimSequenceBase *AnimRef = Cast<UAnimSequenceBase>(Object);
	USkeleton *Skeleton = NULL;
	if(AnimRef != NULL)
	{
		Skeleton = AnimRef->GetSkeleton();
	}

	SegmentCategory.AddCustomRow(FText::GetEmpty(), false)
	[
		SNew(SAnimationSegmentViewport)
		.Skeleton(Skeleton)
		.AnimRef(AnimRef)
		.AnimRefPropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimReference"))
		.StartTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimStartTime"))
		.EndTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimEndTime"))
	];	
}
void UAnimSingleNodeInstance::SetPosition(float InPosition, bool bFireNotifies)
{
	float PreviousTime = CurrentTime;
	CurrentTime = FMath::Clamp<float>(InPosition, 0.f, GetLength());

	if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
	{
		CurMontageInstance->SetPosition(CurrentTime);
	}

	// Handle notifies
	// the way AnimInstance handles notifies doesn't work for single node because this does not tick or anything
	// this will need to handle manually, emptying, it and collect it, and trigger them at once. 
	if (bFireNotifies)
	{
		UAnimSequenceBase * SequenceBase = Cast<UAnimSequenceBase> (CurrentAsset);
		if (SequenceBase)
		{
			AnimNotifies.Empty();

			TArray<const FAnimNotifyEvent*> Notifies;
			SequenceBase->GetAnimNotifiesFromDeltaPositions(PreviousTime, CurrentTime, Notifies);
			if ( Notifies.Num() > 0 )
			{
				// single node instance only has 1 asset at a time
				AddAnimNotifies(Notifies, 1.0f);
			}

			TriggerAnimNotifies(0.f);

		}
	}
}
FString	SAnimSegmentsPanel::GetAnimSegmentName(int32 AnimSegmentIndex) const
{
	if (ValidIndex(AnimSegmentIndex))
	{
		UAnimSequenceBase* AnimReference = AnimTrack->AnimSegments[AnimSegmentIndex].AnimReference;
		if(AnimReference)
		{
			return AnimReference->GetName();
		}
	}
	return FString();
}
FString	SAnimSegmentsPanel::GetAnimSegmentDetailedInfo(int32 AnimSegmentIndex) const
{
	if (ValidIndex(AnimSegmentIndex))
	{
		FAnimSegment& AnimSegment = AnimTrack->AnimSegments[AnimSegmentIndex];
		UAnimSequenceBase * Anim = AnimSegment.AnimReference;
		if ( Anim != NULL )
		{
			return FString::Printf(TEXT("%s %.2f"), *Anim->GetName(), AnimSegment.GetLength() );
		}
	}
	return FString();
}
void UAnimSingleNodeInstance::SetPosition(float InPosition, bool bFireNotifies)
{
	float PreviousTime = CurrentTime;
	CurrentTime = FMath::Clamp<float>(InPosition, 0.f, GetLength());

	if (FAnimMontageInstance* CurMontageInstance = GetActiveMontageInstance())
	{
		CurMontageInstance->SetPosition(CurrentTime);
	}

	// Handle notifies
	// the way AnimInstance handles notifies doesn't work for single node because this does not tick or anything
	// this will need to handle manually, emptying, it and collect it, and trigger them at once. 
	if (bFireNotifies)
	{
		UAnimSequenceBase * SequenceBase = Cast<UAnimSequenceBase> (CurrentAsset);
		if (SequenceBase)
		{
			AnimNotifies.Empty();

			TArray<const FAnimNotifyEvent*> Notifies;
			SequenceBase->GetAnimNotifiesFromDeltaPositions(PreviousTime, CurrentTime, Notifies);
			if ( Notifies.Num() > 0 )
			{
				// single node instance only has 1 asset at a time
				AddAnimNotifies(Notifies, 1.0f);
			}

			TriggerAnimNotifies(0.f);

			// since this is singlenode instance, if position changes, we can't keep old morphtarget curves
			// we clear it and evaluate curve here with new asset. 
			MorphTargetCurves.Empty();
			MaterialParameterCurves.Empty();
			// Evaluate Curve data now - even if time did not move, we still need to return curve if it exists
			SequenceBase->EvaluateCurveData(this, CurrentTime, 1.0);
		}
	}
}
void FAnimMontageSegmentDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder )
{
	IDetailCategoryBuilder& SegmentCategory = DetailBuilder.EditCategory("Animation Segment", LOCTEXT("AnimationSegmentCategoryTitle", "Animation Segment") );

	TSharedRef<IPropertyHandle> TargetPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference");
	UProperty* TargetProperty = TargetPropertyHandle->GetProperty();

	const UObjectPropertyBase* ObjectProperty = CastChecked<const UObjectPropertyBase>(TargetProperty);

	IDetailPropertyRow& PropertyRow = SegmentCategory.AddProperty(TargetPropertyHandle);
	PropertyRow.DisplayName(LOCTEXT("AnimationReferenceLabel", "Animation Reference"));

	TSharedPtr<SWidget> NameWidget;
	TSharedPtr<SWidget> ValueWidget;
	FDetailWidgetRow Row;
	PropertyRow.GetDefaultWidgets(NameWidget, ValueWidget, Row);

	bool bAllowClear = !(ObjectProperty->PropertyFlags & CPF_NoClear);

	SAssignNew(ValueWidget, SObjectPropertyEntryBox)
		.PropertyHandle(TargetPropertyHandle)
		.AllowedClass(ObjectProperty->PropertyClass)
		.AllowClear(bAllowClear)
		.OnShouldFilterAsset(FOnShouldFilterAsset::CreateSP(this, &FAnimMontageSegmentDetails::OnShouldFilterAnimAsset));

	PropertyRow.CustomWidget()
		.NameContent()
		.MinDesiredWidth(Row.NameWidget.MinWidth)
		.MaxDesiredWidth(Row.NameWidget.MaxWidth)
		[
			NameWidget.ToSharedRef()
		]
		.ValueContent()
		.MinDesiredWidth(Row.ValueWidget.MinWidth)
		.MaxDesiredWidth(Row.ValueWidget.MaxWidth)
		[
			ValueWidget.ToSharedRef()
		];

	SegmentCategory.AddProperty("AnimSegment.AnimStartTime").DisplayName( LOCTEXT("StartTimeLabel", "Start Time") );
	SegmentCategory.AddProperty("AnimSegment.AnimEndTime").DisplayName( LOCTEXT("EndTimeLabel", "End Time") );

	SegmentCategory.AddProperty("AnimSegment.AnimPlayRate").DisplayName( LOCTEXT("PlayRateLabel", "Play Rate") );
	SegmentCategory.AddProperty("AnimSegment.LoopingCount").DisplayName( LOCTEXT("LoopCountLabel", "Loop Count") );

	TSharedPtr<IPropertyHandle> InPropertyHandle = DetailBuilder.GetProperty("AnimSegment.AnimReference");
	UObject *Object = NULL;
	InPropertyHandle->GetValue(Object);

	UAnimSequenceBase *AnimRef = Cast<UAnimSequenceBase>(Object);
	USkeleton *Skeleton = NULL;
	if(AnimRef != NULL)
	{
		Skeleton = AnimRef->GetSkeleton();
	}

	SegmentCategory.AddCustomRow(FText::GetEmpty(), false)
	[
		SNew(SAnimationSegmentViewport)
		.Skeleton(Skeleton)
		.AnimRef(AnimRef)
		.AnimRefPropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimReference"))
		.StartTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimStartTime"))
		.EndTimePropertyHandle(DetailBuilder.GetProperty("AnimSegment.AnimEndTime"))
	];	
}