bool UMatineeTrackVectorPropHelper::PreCreateTrack( UInterpGroup* Group, const UInterpTrack *TrackDef, bool bDuplicatingTrack, bool bAllowPrompts ) const { bool bResult = true; if( bAllowPrompts && bDuplicatingTrack == false ) { bResult = false; // For Property tracks - pop up a dialog to choose property name. TrackAddPropName = NAME_None; FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); IMatineeBase* InterpEd = Mode->InterpEd; check(InterpEd != NULL); UInterpGroupInst* GrInst = InterpEd->GetMatineeActor()->FindFirstGroupInst(Group); check(GrInst); AActor* Actor = GrInst->GetGroupActor(); if ( Actor != NULL ) { TArray<FName> PropNames; FMatineeUtils::GetInterpVectorPropertyNames(Actor, PropNames); bResult = ChooseProperty(PropNames); } } return bResult; }
void UFaceFXMatineeControlInst::RestoreActorState(UInterpTrack* Track) { UInterpGroupInst* GrInst = CastChecked<UInterpGroupInst>( GetOuter() ); //called when matinee closes. In that case we stop any running animation/sounds if(const AActor* GroupActor = GrInst->GetGroupActor()) { if(UFaceFXComponent* FaceFXComp = GroupActor->FindComponentByClass<UFaceFXComponent>()) { FaceFXComp->StopAll(); } } }
bool UCameraAnim::CreateFromInterpGroup(class UInterpGroup* SrcGroup, class AMatineeActor* InMatineeActor) { // assert we're controlling a camera actor #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) { UInterpGroupInst* GroupInst = InMatineeActor ? InMatineeActor->FindFirstGroupInst(SrcGroup) : NULL; if (GroupInst) { check( GroupInst->GetGroupActor()->IsA(ACameraActor::StaticClass()) ); } } #endif // copy length information AnimLength = (InMatineeActor && InMatineeActor->MatineeData) ? InMatineeActor->MatineeData->InterpLength : 0.f; UInterpGroup* OldGroup = CameraInterpGroup; if (CameraInterpGroup != SrcGroup) { // copy the source interp group for use in the CameraAnim // @fixme jf: fixed this potentially creating an object of UInterpGroup and raw casting it to InterpGroupCamera. No source data in UE4 to test though. CameraInterpGroup = Cast<UInterpGroupCamera>(StaticDuplicateObject(SrcGroup, this, NAME_None, RF_AllFlags, UInterpGroupCamera::StaticClass())); if (CameraInterpGroup) { // delete the old one, if it exists if (OldGroup) { OldGroup->MarkPendingKill(); } // success! return true; } else { // creation of new one failed somehow, restore the old one CameraInterpGroup = OldGroup; } } else { // no need to perform work above, but still a "success" case return true; } // failed creation return false; }
AActor* UInterpTrackHelper::GetGroupActor(const UInterpTrack* Track) const { FEdModeInterpEdit* mode = (FEdModeInterpEdit*)GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(mode != NULL); IMatineeBase* InterpEd = mode->InterpEd; check(InterpEd != NULL); UInterpGroupInst* GrInst = NULL; // Traverse through the selected tracks in hopes of finding the associated group. for( FSelectedTrackIterator TrackIt(InterpEd->GetSelectedTrackIterator()); TrackIt; ++TrackIt ) { if( (*TrackIt) == Track ) { GrInst = InterpEd->GetMatineeActor()->FindFirstGroupInst(TrackIt.GetGroup()); break; } } return ( GrInst != NULL ) ? GrInst->GetGroupActor() : NULL; }
bool UMatineeTrackColorPropHelper::PreCreateTrack( UInterpGroup* Group, const UInterpTrack *TrackDef, bool bDuplicatingTrack, bool bAllowPrompts ) const { bool bResult = true; if( bAllowPrompts && bDuplicatingTrack == false ) { bResult = false; // For Property tracks - pop up a dialog to choose property name. TrackAddPropName = NAME_None; FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); IMatineeBase* InterpEd = Mode->InterpEd; check(InterpEd != NULL); UInterpGroupInst* GrInst = InterpEd->GetMatineeActor()->FindFirstGroupInst(Group); check(GrInst); AActor* Actor = GrInst->GetGroupActor(); if ( Actor != NULL ) { TArray<FName> PropNames; FMatineeUtils::GetInterpColorPropertyNames(Actor, PropNames); bResult = PropNames.Num() > 0 ? ChooseProperty(PropNames) : false; if( !bResult ) { FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT( "MatineeColorTrackHelper_NoProperties", "No Color track properties are available for this actor" ) ); } } } return bResult; }
bool UMatineeTrackAnimControlHelper::PreCreateTrack( UInterpGroup* Group, const UInterpTrack *TrackDef, bool bDuplicatingTrack, bool bAllowPrompts ) const { // For AnimControl tracks - pop up a dialog to choose slot name. AnimSlotName = NAME_None; FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); IMatineeBase* InterpEd = Mode->InterpEd; check(InterpEd != NULL); UInterpGroupInst* GrInst = InterpEd->GetMatineeActor()->FindFirstGroupInst(Group); check(GrInst); AActor* Actor = GrInst->GetGroupActor(); if ( Actor != NULL ) { IMatineeAnimInterface* MatineeAnimInterface = InterfaceCast<IMatineeAnimInterface>(Actor); if (!MatineeAnimInterface) { UE_LOG(LogSlateMatinee, Log, TEXT("IntepGroup : MatineeAnimInterface is missing for (%s)"), *Actor->GetName()); return false; } // If this is the first AnimControlTrack, then init anim control now. // We need that before calling GetAnimControlSlotDesc if( !Group->HasAnimControlTrack() ) { MatineeAnimInterface->PreviewBeginAnimControl( Group ); } if( bAllowPrompts ) { TArray<FAnimSlotDesc> SlotDescs; MatineeAnimInterface->GetAnimControlSlotDesc(SlotDescs); // If we get no information - just allow it to be created with empty slot. if( SlotDescs.Num() == 0 ) { return true; } // Build combo to let you pick a slot. Don't put any names in that have already used all their channels. */ TArray<FString> SlotStrings; for(int32 i=0; i<SlotDescs.Num(); i++) { int32 ChannelsUsed = GrInst->Group->GetAnimTracksUsingSlot( SlotDescs[i].SlotName ); if(ChannelsUsed < SlotDescs[i].NumChannels) { SlotStrings.Add(*SlotDescs[i].SlotName.ToString()); } } // If no slots free - we fail to create track. if(SlotStrings.Num() == 0) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_NoAnimChannelsLeft", "This Actor Has No AnimControl Channels Left.") ); return false; } TSharedRef<SWindow> NewWindow = SNew(SWindow) .Title(NSLOCTEXT("Matinee.Popups", "ChooseAnimSlotTitle", "Choose Anim Slot...")) .SizingRule( ESizingRule::Autosized ) .SupportsMinimize(false) .SupportsMaximize(false); FString Result; TSharedRef<STextComboPopup> TextEntryPopup = SNew(STextComboPopup) .Label(NSLOCTEXT("Matinee.Popups", "ChooseAnimSlot", "Choose Anim Slot...")) .TextOptions(SlotStrings) .OnTextChosen_UObject(this, &UMatineeTrackAnimControlHelper::OnCreateTrackTextEntry, NewWindow, (FString *)&Result) ; NewWindow->SetContent(TextEntryPopup); GEditor->EditorAddModalWindow(NewWindow); if (!Result.IsEmpty()) { AnimSlotName = FName( *Result ); if ( AnimSlotName != NAME_None ) { return true; } } } else { // Prompts aren't allowed, so just succeed with defaults return true; } } return false; }
bool UMatineeTrackBoolPropHelper::PreCreateTrack( UInterpGroup* Group, const UInterpTrack* TrackDef, bool bDuplicatingTrack, bool bAllowPrompts ) const { if( bAllowPrompts && bDuplicatingTrack == false ) { // For Property tracks - pop up a dialog to choose property name. TrackAddPropName = NAME_None; FEdModeInterpEdit* Mode = (FEdModeInterpEdit*)GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_InterpEdit ); check(Mode != NULL); IMatineeBase* InterpEd = Mode->InterpEd; check(InterpEd != NULL); UInterpGroupInst* GrInst = InterpEd->GetMatineeActor()->FindFirstGroupInst(Group); check(GrInst); AActor* Actor = GrInst->GetGroupActor(); if ( Actor != NULL ) { TArray<FName> PropNames; FMatineeUtils::GetInterpBoolPropertyNames(Actor, PropNames); if( PropNames.Num() > 0 ) { TArray<FString> PropStrings; PropStrings.AddZeroed( PropNames.Num() ); for(int32 i=0; i<PropNames.Num(); i++) { PropStrings[i] = PropNames[i].ToString(); } TSharedRef<SWindow> NewWindow = SNew(SWindow) .Title(NSLOCTEXT("Matinee.Popups", "ChooseProperty", "Choose Property...")) .SizingRule( ESizingRule::Autosized ) .SupportsMinimize(false) .SupportsMaximize(false); FString Result; TSharedRef<STextComboPopup> TextEntryPopup = SNew(STextComboPopup) .Label(NSLOCTEXT("Matinee.Popups", "PropertyName", "Property Name")) .TextOptions(PropStrings) .OnTextChosen_UObject(this, &UMatineeTrackBoolPropHelper::OnCreateTrackTextEntry, TWeakPtr<SWindow>(NewWindow), (FString *)&Result); NewWindow->SetContent(TextEntryPopup); GEditor->EditorAddModalWindow(NewWindow); if (!Result.IsEmpty()) { TrackAddPropName = FName( *Result ); if ( TrackAddPropName != NAME_None ) { // Check we don't already have a track controlling this property. for(int32 i=0; i<Group->InterpTracks.Num(); i++) { UInterpTrackFloatProp* TestFloatTrack = Cast<UInterpTrackFloatProp>( Group->InterpTracks[i] ); if(TestFloatTrack && TestFloatTrack->PropertyName == TrackAddPropName) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_PropertyAlreadyControlled", "Already a FloatProp track controlling this property.") ); return false; } UInterpTrackBoolProp* TestBoolTrack = Cast<UInterpTrackBoolProp>( Group->InterpTracks[i] ); if(TestBoolTrack && TestBoolTrack->PropertyName == TrackAddPropName) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_BoolPropertyAlreadyControlled", "Already a BoolProp track controlling this property.") ); return false; } UInterpTrackVectorProp* TestVectorTrack = Cast<UInterpTrackVectorProp>( Group->InterpTracks[i] ); if(TestVectorTrack && TestVectorTrack->PropertyName == TrackAddPropName) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_VectorPropertyAlreadyControlled", "Already a VectorProp track controlling this property.") ); return false; } UInterpTrackLinearColorProp* TestLinearColorTrack = Cast<UInterpTrackLinearColorProp>( Group->InterpTracks[i] ); if(TestLinearColorTrack && TestLinearColorTrack->PropertyName == TrackAddPropName) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_LinearPropertyAlreadyControlled", "Already a LinearProp track controlling this property.") ); return false; } } return true; } } } else { FMessageDialog::Open( EAppMsgType::Ok, LOCTEXT( "MatineeBoolTrackHelper_NoProperties", "No Bool track properties are available for this actor" ) ); } } return false; } else { return true; } }
void UFaceFXMatineeControl::DrawTrack( FCanvas* Canvas, UInterpGroup* Group, const FInterpTrackDrawParams& Params ) { static const FColor KeySelectedColor(255,128,0); static const FColor KeyLabelColor(225,225,225); static const FColor KeyBackgroundColor(0,150,200); static const FColor KeyColorBlack(0,0,0); static const int32 KeyVertOffset = 3; const bool bHitTesting = Canvas->IsHitTesting(); const bool bAllowBarSelection = bHitTesting && Params.bAllowKeyframeBarSelection; const bool bAllowTextSelection = bHitTesting && Params.bAllowKeyframeTextSelection; AMatineeActor* MatineeActor = CastChecked<AMatineeActor>(Group->GetOuter()->GetOuter()); UInterpGroupInst* GroupInst = MatineeActor->FindFirstGroupInst(Group); const AActor* GroupActor = GroupInst ? GroupInst->GetGroupActor() : nullptr; //cached animation ids TArray<FFaceFXAnimId> AnimIds; AnimIds.AddUninitialized(Keys.Num()); //Draw the tiles for each animation for (int32 i = 0; i < Keys.Num(); i++) { const FFaceFXTrackKey& AnimKey = Keys[i]; FFaceFXAnimId AnimationId; if(AnimKey.AnimationId.IsValid()) { AnimationId = AnimKey.AnimationId; } else if(const UFaceFXAnim* Animation = GetAnimation(AnimKey, this)) { AnimationId = Animation->GetId(); } AnimIds[i] = AnimationId; //determine animation duration const float AnimStartTime = AnimKey.Time; const float AnimEndTime = AnimStartTime + AnimKey.GetAnimationDuration(GroupActor); const int32 StartPixelPos = FMath::TruncToInt((AnimStartTime - Params.StartTime) * Params.PixelsPerSec); const int32 EndPixelPos = FMath::TruncToInt((AnimEndTime - Params.StartTime) * Params.PixelsPerSec); // Find if this sound is one of the selected ones. bool bKeySelected = false; for (const FInterpEdSelKey& SelectedKey : Params.SelectedKeys) { if(SelectedKey.Group == Group && SelectedKey.Track == this && SelectedKey.KeyIndex == i) { bKeySelected = true; break; } } const FColor& BorderColor = bKeySelected ? KeySelectedColor : KeyColorBlack; if(bAllowBarSelection) { Canvas->SetHitProxy(new HInterpTrackKeypointProxy(Group, this, i)); } Canvas->DrawTile(StartPixelPos, KeyVertOffset, EndPixelPos - StartPixelPos + 1, FMath::TruncToFloat(Params.TrackHeight - 2.f*KeyVertOffset), 0.f, 0.f, 1.f, 1.f, BorderColor); Canvas->DrawTile(StartPixelPos+1, KeyVertOffset+1, EndPixelPos - StartPixelPos - 1, FMath::TruncToFloat(Params.TrackHeight - 2.f*KeyVertOffset) - 2, 0.f, 0.f, 1.f, 1.f, KeyBackgroundColor); if(bAllowBarSelection) { Canvas->SetHitProxy(nullptr); } } // Use base-class to draw key triangles Super::DrawTrack( Canvas, Group, Params ); //Draw animation names on top for (int32 i = 0; i < Keys.Num(); i++) { const FFaceFXTrackKey& AnimKey = Keys[i]; //fetch the cached animation id for the key const FFaceFXAnimId& AnimId = AnimIds[i]; FString AnimName(TEXT("Unknown")); if(AnimId.IsValid()) { AnimName = AnimId.Group.IsNone() ? TEXT("") : AnimId.Group.ToString() + TEXT(" / "); AnimName += AnimId.Name.ToString(); } if(AnimKey.bLoop) { AnimName += TEXT(" [Looping]"); } int32 XL, YL; StringSize(GEngine->GetSmallFont(), XL, YL, *AnimName); if (bAllowTextSelection) { Canvas->SetHitProxy(new HInterpTrackKeypointProxy(Group, this, i)); } const int32 PixelPos = FMath::TruncToInt((AnimKey.Time - Params.StartTime) * Params.PixelsPerSec); Canvas->DrawShadowedString((PixelPos + 2), Params.TrackHeight - YL - KeyVertOffset, *AnimName, GEngine->GetSmallFont(), KeyLabelColor); if (bAllowTextSelection) { Canvas->SetHitProxy(nullptr); } } }