FVector2D FParticleSection::GetKeyBrushOrigin( FKeyHandle KeyHandle ) const
{
	UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section );
	if ( ParticleSection != nullptr )
	{
		FIntegralKey ParticleKey = ParticleSection->GetParticleCurve().GetKey(KeyHandle);
		if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Activate )
		{
			return FVector2D(-1.0f, 1.0f);
		}
		else if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Deactivate )
		{
			return FVector2D(1.0f, 1.0f);
		}
	}
	return FVector2D(0.0f, 0.0f);
}
const FSlateBrush* FParticleSection::GetKeyBrush( FKeyHandle KeyHandle ) const
{
	UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section );
	if ( ParticleSection != nullptr )
	{
		FIntegralKey ParticleKey = ParticleSection->GetParticleCurve().GetKey(KeyHandle);
		if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Activate )
		{
			return LeftKeyBrush;
		}
		else if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Deactivate )
		{
			return RightKeyBrush;
		}
	}
	return nullptr;
}
void FMatineeImportTools::CopyInterpParticleTrack( TSharedRef<ISequencer> Sequencer, UInterpTrackToggle* MatineeToggleTrack, UMovieSceneParticleTrack* ParticleTrack )
{
	const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeParticleTrack", "Paste Matinee particle track" ) );
	bool bSectionCreated = false;

	ParticleTrack->Modify();

	float KeyTime = MatineeToggleTrack->GetKeyframeTime( 0 );
	UMovieSceneParticleSection* Section = Cast<UMovieSceneParticleSection>( MovieSceneHelpers::FindSectionAtTime( ParticleTrack->GetAllSections(), KeyTime ) );
	if ( Section == nullptr )
	{
		Section = Cast<UMovieSceneParticleSection>( ParticleTrack->CreateNewSection() );
		ParticleTrack->AddSection( *Section );
		bSectionCreated = true;
	}

	if (Section->TryModify())
	{
		float SectionMin = Section->GetStartTime();
		float SectionMax = Section->GetEndTime();

		FIntegralCurve& ParticleCurve = Section->GetParticleCurve();
		for ( const auto& Key : MatineeToggleTrack->ToggleTrack )
		{
			EParticleKey::Type ParticleKey;
			if ( TryConvertMatineeToggleToOutParticleKey( Key.ToggleAction, ParticleKey ) )
			{
				ParticleCurve.AddKey( Key.Time, (int32)ParticleKey, ParticleCurve.FindKey( Key.Time ) );
			}
			SectionMin = FMath::Min( SectionMin, Key.Time );
			SectionMax = FMath::Max( SectionMax, Key.Time );
		}

		Section->SetStartTime( SectionMin );
		Section->SetEndTime( SectionMax );

		if ( bSectionCreated )
		{
			Sequencer->NotifyMovieSceneDataChanged();
		}
	}
}
int32 FParticleSection::OnPaintSection( FSequencerSectionPainter& InPainter ) const
{
	TSharedPtr<ISequencer> OwningSequencer = OwningSequencerPtr.Pin();

	if (!OwningSequencer.IsValid())
	{
		return InPainter.LayerId + 1;
	}

	const ESlateDrawEffect::Type DrawEffects = InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
	UMovieSceneParticleSection* AnimSection = Cast<UMovieSceneParticleSection>( &Section );
	const FTimeToPixel& TimeToPixelConverter = InPainter.GetTimeConverter();

	FLinearColor TrackColor;

	// @todo Sequencer - These values should be cached and then refreshed only when the particle system changes.
	bool bIsLooping = false;
	float LastEmitterEndTime = 0;
	UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section );
	if ( ParticleSection != nullptr )
	{
		UMovieSceneParticleTrack* ParentTrack = Cast<UMovieSceneParticleTrack>( ParticleSection->GetOuter() );
		if ( ParentTrack != nullptr )
		{
			TrackColor = ParentTrack->GetColorTint();

			FGuid ObjectHandle;
			for ( const FMovieSceneBinding& Binding : OwningSequencer->GetFocusedMovieSceneSequence()->GetMovieScene()->GetBindings() )
			{
				if ( Binding.GetTracks().Contains( ParentTrack ) )
				{
					ObjectHandle = Binding.GetObjectGuid();
					break;
				}
			}

			if ( ObjectHandle.IsValid() )
			{
				UObject* BoundObject = OwningSequencer->GetFocusedMovieSceneSequenceInstance()->FindObject( ObjectHandle, *OwningSequencer );
				UParticleSystemComponent* ParticleSystemComponent = Cast<UParticleSystemComponent>(BoundObject);
				if(AEmitter* ParticleSystemActor = Cast<AEmitter>(BoundObject))
				{
					ParticleSystemComponent = ParticleSystemActor->GetParticleSystemComponent();
				}

				if ( ParticleSystemComponent != nullptr && ParticleSystemComponent->Template != nullptr )
				{
					for ( UParticleEmitter* Emitter : ParticleSystemComponent->Template->Emitters )
					{
						UParticleModuleRequired* RequiredModule = Emitter->GetLODLevel( 0 )->RequiredModule;
						bIsLooping |= RequiredModule->EmitterLoops == 0;
						LastEmitterEndTime = FMath::Max( LastEmitterEndTime, RequiredModule->EmitterDelay + RequiredModule->EmitterDuration );
					}
				}
			}
		}
	}

	// @todo Sequencer - This should only draw the visible ranges.
	TArray<TRange<float>> DrawRanges;
	TOptional<float> CurrentRangeStart;
	for ( auto KeyIterator = ParticleSection->GetParticleCurve().GetKeyIterator(); KeyIterator; ++KeyIterator )
	{
		FIntegralKey Key = *KeyIterator;
		if ( (EParticleKey::Type)Key.Value == EParticleKey::Activate )
		{
			if ( CurrentRangeStart.IsSet() == false )
			{
				CurrentRangeStart = Key.Time;
			}
			else
			{
				if ( bIsLooping == false )
				{
					if ( Key.Time > CurrentRangeStart.GetValue() + LastEmitterEndTime )
					{
						DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) );
					}
					else
					{
						DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) );
					}
					CurrentRangeStart = Key.Time;
				}
			}
		}
		if ( (EParticleKey::Type)Key.Value == EParticleKey::Deactivate )
		{
			if ( CurrentRangeStart.IsSet() )
			{
				if (bIsLooping)
				{
					DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) );
				}
				else
				{
					if ( Key.Time > CurrentRangeStart.GetValue() + LastEmitterEndTime )
					{
						DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) );
					}
					else
					{
						DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) );
					}
				}
				CurrentRangeStart.Reset();
			}
		}
	}
	if ( CurrentRangeStart.IsSet() )
	{
		if ( bIsLooping )
		{
			DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), OwningSequencer->GetViewRange().GetUpperBoundValue() ) );
		}
		else
		{
			DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) );
		}
	}

	for ( const TRange<float>& DrawRange : DrawRanges )
	{
		float XOffset = TimeToPixelConverter.TimeToPixel(DrawRange.GetLowerBoundValue());
		float XSize = TimeToPixelConverter.TimeToPixel(DrawRange.GetUpperBoundValue()) - XOffset;
		FSlateDrawElement::MakeBox(
			InPainter.DrawElements,
			InPainter.LayerId,
			InPainter.SectionGeometry.ToPaintGeometry( FVector2D( XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2 ), FVector2D( XSize, SequencerSectionConstants::KeySize.Y ) ),
			FEditorStyle::GetBrush( "Sequencer.Section.Background" ),
			InPainter.SectionClippingRect,
			DrawEffects
			);
		FSlateDrawElement::MakeBox(
			InPainter.DrawElements,
			InPainter.LayerId,
			InPainter.SectionGeometry.ToPaintGeometry( FVector2D( XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2 ), FVector2D( XSize, SequencerSectionConstants::KeySize.Y ) ),
			FEditorStyle::GetBrush( "Sequencer.Section.BackgroundTint" ),
			InPainter.SectionClippingRect,
			DrawEffects,
			TrackColor
			);
	}

	return InPainter.LayerId+1;
}
void FParticleSection::GenerateSectionLayout( class ISectionLayoutBuilder& LayoutBuilder ) const
{
	UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section );
	LayoutBuilder.SetSectionAsKeyArea( MakeShareable( new FEnumKeyArea( ParticleSection->GetParticleCurve(), ParticleSection, ParticleKeyEnum ) ) );
}