Sequencer改造 2 #UE4Study

# Sequencer改造 2
## 前回
Sequencer改造
http://qiita.com/gansaibow/items/d47874de4628ca8fa93d

## 続き

LOCTEXTの第一引数もPokopenにすることで、Deleteが表示された
どこかにKeyを設定する必要はなさそうなので、重複しなさそうなKey名を設定すれば良さそう。
![image](https://qiita-image-store.s3.amazonaws.com/0/111261/f9ad231b-3acc-82d5-98ce-cd57bd3e8ba9.png)

![image](https://qiita-image-store.s3.amazonaws.com/0/111261/f0530014-f0a0-52d9-d1a5-903e940ad0aa.png)


## 1フレームごとにキーを打つ

ToolTipのコメントを検索ワードとして取得する
[Add a new key at the current time]
![image](https://qiita-image-store.s3.amazonaws.com/0/111261/119b24b3-bfa4-5edb-d695-47df8ad64fec.png)

検索範囲をソリューション全体に設定して、検索ワードを入れて検索すると該当箇所が見つかる
![image](https://qiita-image-store.s3.amazonaws.com/0/111261/f4b686e4-62a9-ec43-8d56-952abbb17c82.png)

該当のボタンを追加するソースコード

OnAddKeyClickedというイベントでキーを追加している
OnClicked(this, &SKeyNavigationButtons::OnAddKeyClicked)


```C++:SKeyNavigationButtons.h
			// Add key slot
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.AutoWidth()
			[
				SNew(SBorder)
				.Padding(0)
				.BorderImage(NoBorder)
				.ColorAndOpacity(HoverTint)
				.IsEnabled(!InDisplayNode->GetSequencer().IsReadOnly())
				[
					SNew(SButton)
					.ButtonStyle(FEditorStyle::Get(), "FlatButton")
					.ToolTipText(LOCTEXT("AddKeyButton", "Add a new key at the current time"))
					.OnClicked(this, &SKeyNavigationButtons::OnAddKeyClicked)
					.ForegroundColor( FSlateColor::UseForeground() )
					.ContentPadding(0)
					.IsFocusable(false)
					[
						SNew(STextBlock)
						.Font(FEditorStyle::Get().GetFontStyle("FontAwesome.7"))
						.Text(FText::FromString(FString(TEXT("\xf055"))) /*fa-plus-circle*/)
					]
				]
			]
```
OnAddKeyClickedを右クリックして定義に移動
![image](https://qiita-image-store.s3.amazonaws.com/0/111261/b62a920d-39a7-db4f-a908-f56cae8c4fca.png)


```C++:SKeyNavigationButtons.h
	FReply OnAddKeyClicked()
	{
		FSequencer& Sequencer = DisplayNode->GetSequencer();
		float CurrentTime = Sequencer.GetLocalTime();

		TSet<TSharedPtr<IKeyArea>> KeyAreas;
		SequencerHelpers::GetAllKeyAreas(DisplayNode, KeyAreas);

		TArray<UMovieSceneSection*> KeyAreaSections;
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			KeyAreaSections.Add(OwningSection);
		}

		UMovieSceneSection* NearestSection = MovieSceneHelpers::FindNearestSectionAtTime(KeyAreaSections, CurrentTime);
		if (!NearestSection)
		{
			return FReply::Unhandled();
		}

		FScopedTransaction Transaction(LOCTEXT("AddKeys", "Add Keys at Current Time"));
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			if (OwningSection == NearestSection)
			{
				OwningSection->SetFlags(RF_Transactional);
				if (OwningSection->TryModify())
				{
					KeyArea->AddKeyUnique(CurrentTime, Sequencer.GetKeyInterpolation());
				}
			}
		}

		Sequencer.UpdatePlaybackRange();

		return FReply::Handled();
	}
```


テスト用のボタンを追加して
OnAddKeyClickedをコピーして、新しい関数OnAddKeyAllFrameClickedを作成する

```C++:SKeyNavigationButtons.h
			// Add key slot
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.AutoWidth()
			[
				SNew(SBorder)
				.Padding(0)
				.BorderImage(NoBorder)
				.ColorAndOpacity(HoverTint)
				.IsEnabled(!InDisplayNode->GetSequencer().IsReadOnly())
				[
					SNew(SButton)
					.ButtonStyle(FEditorStyle::Get(), "FlatButton")
					.ToolTipText(LOCTEXT("AddKeyButton", "Add a new key at the current time"))
					.OnClicked(this, &SKeyNavigationButtons::OnAddKeyClicked)
					.ForegroundColor( FSlateColor::UseForeground() )
					.ContentPadding(0)
					.IsFocusable(false)
					[
						SNew(STextBlock)
						.Font(FEditorStyle::Get().GetFontStyle("FontAwesome.7"))
						.Text(FText::FromString(FString(TEXT("\xf055"))) /*fa-plus-circle*/)
					]
				]
			]
			// Add key slot 2
			+ SHorizontalBox::Slot()
			.VAlign(VAlign_Center)
			.AutoWidth()
			[
				SNew(SBorder)
				.Padding(0)
				.BorderImage(NoBorder)
				.ColorAndOpacity(HoverTint)
				.IsEnabled(!InDisplayNode->GetSequencer().IsReadOnly())
				[
					SNew(SButton)
					.ButtonStyle(FEditorStyle::Get(), "FlatButton")
					.ToolTipText(LOCTEXT("AddKeyAllButton", "Add a new key All frame"))
					.OnClicked(this, &SKeyNavigationButtons::OnAddKeyAllFrameClicked)
					.ForegroundColor( FSlateColor::UseForeground() )
					.ContentPadding(0)
					.IsFocusable(false)
					[
						SNew(STextBlock)
						.Font(FEditorStyle::Get().GetFontStyle("FontAwesome.7"))
						.Text(FText::FromString(FString(TEXT("\xf055"))) /*fa-plus-circle*/)
					]
				]
			]

```

CurrentFrameに1を足して、次のフレームにキーを打ってみるように処理を変えてみる

```C++:SKeyNavigationButtons.h
	FReply OnAddKeyAllFrameClicked()
	{
		FSequencer& Sequencer = DisplayNode->GetSequencer();

		float CurrentTime = Sequencer.GetGlobalTime();
		CurrentTime = CurrentTime + 1;
		Sequencer.SetGlobalTime(CurrentTime);
		
		TSet<TSharedPtr<IKeyArea>> KeyAreas;
		SequencerHelpers::GetAllKeyAreas(DisplayNode, KeyAreas);

		TArray<UMovieSceneSection*> KeyAreaSections;
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			KeyAreaSections.Add(OwningSection);
		}

		UMovieSceneSection* NearestSection = MovieSceneHelpers::FindNearestSectionAtTime(KeyAreaSections, CurrentTime);
		if (!NearestSection)
		{
			return FReply::Unhandled();
		}

		FScopedTransaction Transaction(LOCTEXT("AddKeys", "Add Keys at Current Time"));
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			if (OwningSection == NearestSection)
			{
				OwningSection->SetFlags(RF_Transactional);
				if (OwningSection->TryModify())
				{
					KeyArea->AddKeyUnique(CurrentTime, Sequencer.GetKeyInterpolation());
				}
			}
		}

		Sequencer.UpdatePlaybackRange();

		return FReply::Handled();
	}
```

ボタンが追加されたが、３０フレームごとにキーが打たれてしまう
CurrentTime = CurrentTime + 1;
とすると、設定しているFPS x 1が進んでしまう
1フレーム分を取得しないといけない

![image](https://qiita-image-store.s3.amazonaws.com/0/111261/291890d4-9c41-62b9-a516-5f169d0336ef.png)

1フレーム分の時間はSequencer.cppでSettings->GetTimeSnapInterval()で取得することが出来るようだ。

Sequencer.hとSequencer.cppにGetOneFrameTimeを追加する

```C++:Sequencer.h
public:

	FMovieSceneRootEvaluationTemplateInstance& GetSequenceInstance() { return RootTemplateInstance; }
	float GetOneFrameTime();
```

```C++:Sequencer.cpp
float FSequencer::GetOneFrameTime()
{
	return Settings->GetTimeSnapInterval();
}
```

OnAddKeyAllFrameClickedを1フレーム次のフレームにキーを打つように変更してみる

```C++:SKeyNavigationButtons.h
	FReply OnAddKeyAllFrameClicked()
	{
		FSequencer& Sequencer = DisplayNode->GetSequencer();

		float oneFrameTime = Sequencer.GetOneFrameTime();
		float CurrentTime = Sequencer.GetGlobalTime();
		CurrentTime = CurrentTime + oneFrameTime;
		Sequencer.SetGlobalTime(CurrentTime);
	
		TSet<TSharedPtr<IKeyArea>> KeyAreas;
		SequencerHelpers::GetAllKeyAreas(DisplayNode, KeyAreas);

		TArray<UMovieSceneSection*> KeyAreaSections;
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			KeyAreaSections.Add(OwningSection);
		}

		UMovieSceneSection* NearestSection = MovieSceneHelpers::FindNearestSectionAtTime(KeyAreaSections, CurrentTime);
		if (!NearestSection)
		{
			return FReply::Unhandled();
		}

		FScopedTransaction Transaction(LOCTEXT("AddKeys", "Add Keys at Current Time"));
		for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
		{
			UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
			if (OwningSection == NearestSection)
			{
				OwningSection->SetFlags(RF_Transactional);
				if (OwningSection->TryModify())
				{
					KeyArea->AddKeyUnique(CurrentTime, Sequencer.GetKeyInterpolation());
				}
			}
		}

		Sequencer.UpdatePlaybackRange();

		return FReply::Handled();
	}
```

1フレームごとキーが設定される
![image](https://qiita-image-store.s3.amazonaws.com/0/111261/605dd896-8c47-323e-b607-4e6d3381cb93.png)

## 全フレームにキーを打つ

あとは開始フレームと終了フレームが取得できれば、全フレームにキーが打てそうだ

開始フレームと終了フレームはGetPlaybackRange()で取得できる

終了フレームのフレームトータル時間は
PlaybackRangeの終了フレーム * (フレームレート * 1フレームの時間)で出せる。
開始トータル時間と終了トータル時間の1フレームごとの時間を配列に入れて戻り値として返す

GetAllFrameTimesをSequencer.h(Public)とSequencer.cppに追加

```C++:Sequencer.h
	TArray<float> GetAllFrameTimes();
```

OnAddKeyAllFrameClickedからGetAllFrameTimesで全フレームのキーフレーム時間配列を取得して、全フレームキーを打つように修正する

```C++:Sequencer.cpp
TArray<float> FSequencer::GetAllFrameTimes()
{
	TArray<float> allFrameTimes;
	float frameRate = 1.0f / Settings->GetTimeSnapInterval();
	float oneFrameTime = Settings->GetTimeSnapInterval();

	TRange<float> range = GetPlaybackRange();
	float StartTime = range.GetLowerBoundValue();
	float EndTime = range.GetUpperBoundValue();

	float startFrame = StartTime * (frameRate * oneFrameTime);
	float endFrame = EndTime * (frameRate * oneFrameTime);

	for (float i = startFrame; i < endFrame; i = i + oneFrameTime)
	{
		allFrameTimes.Add(i);
	}

	return allFrameTimes;
}
```

OnAddKeyAllFrameClickedにGetAllFrameTimesで全フレームの時間を取得して、キーを打つように変更する

```C++:SKeyNavigationButtons.h
	FReply OnAddKeyAllFrameClicked()
	{
		FSequencer& Sequencer = DisplayNode->GetSequencer();

		TArray<float> allFrameTimes = Sequencer.GetAllFrameTimes();

		for (float CurrentTime : allFrameTimes)
		{
			Sequencer.SetGlobalTime(CurrentTime);

			TSet<TSharedPtr<IKeyArea>> KeyAreas;
			SequencerHelpers::GetAllKeyAreas(DisplayNode, KeyAreas);

			TArray<UMovieSceneSection*> KeyAreaSections;
			for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
			{
				UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
				KeyAreaSections.Add(OwningSection);
			}

			UMovieSceneSection* NearestSection = MovieSceneHelpers::FindNearestSectionAtTime(KeyAreaSections, CurrentTime);
			if (!NearestSection)
			{
				return FReply::Unhandled();
			}

			FScopedTransaction Transaction(LOCTEXT("AddKeys", "Add Keys at Current Time"));
			for (TSharedPtr<IKeyArea> KeyArea : KeyAreas)
			{
				UMovieSceneSection* OwningSection = KeyArea->GetOwningSection();
				if (OwningSection == NearestSection)
				{
					OwningSection->SetFlags(RF_Transactional);
					if (OwningSection->TryModify())
					{
						KeyArea->AddKeyUnique(CurrentTime, Sequencer.GetKeyInterpolation());
					}
				}
			}

		}

		Sequencer.UpdatePlaybackRange();

		return FReply::Handled();
	}
```

![image](https://qiita-image-store.s3.amazonaws.com/0/111261/d0cf524b-28ed-3fd0-2dcb-5c29eeb0a1d5.png)