void FSequencerObjectChangeListener::OnActorPostEditMove( AActor* Actor ) { // @todo sequencer actors: Currently this only fires on a "final" move. For our purposes we probably // want to get an update every single movement, even while dragging an object. FPropertyChangedEvent PropertyChangedEvent(nullptr); OnObjectPostEditChange( Actor, PropertyChangedEvent ); }
void FStreamingLevelModel::SetLevelColor(FLinearColor InColor) { if (LevelStreaming.IsValid()) { UProperty* DrawColorProperty = FindField<UProperty>(LevelStreaming->GetClass(), "LevelColor"); LevelStreaming->PreEditChange(DrawColorProperty); LevelStreaming.Get()->LevelColor = InColor; FPropertyChangedEvent PropertyChangedEvent(DrawColorProperty, EPropertyChangeType::ValueSet); LevelStreaming->PostEditChangeProperty(PropertyChangedEvent); } }
/** * Sets an object property value by name * @param TargetObject - The object to modify * @param InVariableName - The name of the property */ void SetPropertyByName(UObject* TargetObject, const FString& InVariableName, const FString& NewValueString) { UProperty* FoundProperty = FindField<UProperty>(TargetObject->GetClass(), *InVariableName); if (FoundProperty) { const FScopedTransaction PropertyChanged(LOCTEXT("PropertyChanged", "Object Property Change")); TargetObject->Modify(); TargetObject->PreEditChange(FoundProperty); FoundProperty->ImportText(*NewValueString, FoundProperty->ContainerPtrToValuePtr<uint8>(TargetObject), 0, TargetObject); FPropertyChangedEvent PropertyChangedEvent(FoundProperty, EPropertyChangeType::ValueSet); TargetObject->PostEditChangeProperty(PropertyChangedEvent); } }
void FSplineComponentVisualizer::NotifyComponentModified() { USplineComponent* SplineComp = GetEditedSplineComponent(); SplineComp->bSplineHasBeenEdited = true; SplineComp->UpdateSpline(); // Notify that the spline info has been modified UProperty* SplineInfoProperty = FindField<UProperty>(USplineComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(USplineComponent, SplineInfo)); FPropertyChangedEvent PropertyChangedEvent(SplineInfoProperty); SplineComp->PostEditChangeProperty(PropertyChangedEvent); // Notify of change so any CS is re-run if (SplineOwningActor.IsValid()) { SplineOwningActor.Get()->PostEditMove(false); } GEditor->RedrawLevelEditingViewports(true); }
void UUnrealEdEngine::ConvertMatinees() { FVector StartLocation= FVector::ZeroVector; UWorld* World = GWorld; if( World ) { ULevel* Level = World->GetCurrentLevel(); if( !Level ) { Level = World->PersistentLevel; } check(Level); for( TObjectIterator<UInterpData> It; It; ++It ) { UInterpData* InterpData = *It; if( InterpData->IsIn( Level ) ) { // We dont care about renaming references or adding redirectors. References to this will be old seqact_interps GEditor->RenameObject( InterpData, Level->GetOutermost(), *InterpData->GetName() ); AMatineeActor* MatineeActor = Level->OwningWorld->SpawnActor<AMatineeActor>(StartLocation, FRotator::ZeroRotator); StartLocation.Y += 50; MatineeActor->MatineeData = InterpData; UProperty* MatineeDataProp = NULL; for( UProperty* Property = MatineeActor->GetClass()->PropertyLink; Property != NULL; Property = Property->PropertyLinkNext ) { if( Property->GetName() == TEXT("MatineeData") ) { MatineeDataProp = Property; break; } } FPropertyChangedEvent PropertyChangedEvent( MatineeDataProp ); MatineeActor->PostEditChangeProperty( PropertyChangedEvent ); } } } }
/** * Attempts to apply the material to the specified actor. * * @param TargetActor the actor to apply the material to * @param MaterialToApply the material to apply to the actor * @param OptionalMaterialSlot the material slot to apply to. * * @return true if the material was successfully applied to the actor */ bool FActorFactoryAssetProxy::ApplyMaterialToActor( AActor* TargetActor, UMaterialInterface* MaterialToApply, int32 OptionalMaterialSlot ) { bool bResult = false; if ( TargetActor != NULL && MaterialToApply != NULL ) { ALandscapeProxy* Landscape = Cast<ALandscapeProxy>(TargetActor); if (Landscape != NULL) { UProperty* MaterialProperty = FindField<UProperty>(ALandscapeProxy::StaticClass(), "LandscapeMaterial"); Landscape->PreEditChange(MaterialProperty); Landscape->LandscapeMaterial = MaterialToApply; FPropertyChangedEvent PropertyChangedEvent(MaterialProperty); Landscape->PostEditChangeProperty(PropertyChangedEvent); bResult = true; } else { TArray<UActorComponent*> EditableComponents; FActorEditorUtils::GetEditableComponents( TargetActor, EditableComponents ); // Some actors could potentially have multiple mesh components, so we need to store all of the potentially valid ones // (or else perform special cases with IsA checks on the target actor) TArray<USceneComponent*> FoundMeshComponents; // Find which mesh the user clicked on first. TInlineComponentArray<USceneComponent*> SceneComponents; TargetActor->GetComponents(SceneComponents); for ( int32 ComponentIdx=0; ComponentIdx < SceneComponents.Num(); ComponentIdx++ ) { USceneComponent* SceneComp = SceneComponents[ComponentIdx]; // Only apply the material to editable components. Components which are not exposed are not intended to be changed. if( EditableComponents.Contains( SceneComp ) ) { UMeshComponent* MeshComponent = Cast<UMeshComponent>(SceneComp); if((MeshComponent && MeshComponent->IsRegistered()) || SceneComp->IsA<UDecalComponent>()) { // Intentionally do not break the loop here, as there could be potentially multiple mesh components FoundMeshComponents.AddUnique( SceneComp ); } } } if ( FoundMeshComponents.Num() > 0 ) { // Check each component that was found for ( TArray<USceneComponent*>::TConstIterator MeshCompIter( FoundMeshComponents ); MeshCompIter; ++MeshCompIter ) { USceneComponent* SceneComp = *MeshCompIter; bResult = FComponentEditorUtils::AttemptApplyMaterialToComponent(SceneComp, MaterialToApply, OptionalMaterialSlot); } } } } return bResult; }
void FComponentMaterialCategory::OnMaterialChanged( UMaterialInterface* NewMaterial, UMaterialInterface* PrevMaterial, int32 SlotIndex, bool bReplaceAll ) { // Whether or not we should begin a transaction on swap // Note we only begin a transaction on the first swap bool bShouldMakeTransaction = true; // Whether or not we made a transaction and need to end it bool bMadeTransaction = false; // Lambda to swap materials on a given component at the given slot index auto SwapMaterialLambda = []( UActorComponent* InComponent, int32 InElementIndex, UMaterialInterface* InNewMaterial ) { UPrimitiveComponent* PrimitiveComp = Cast<UPrimitiveComponent>( InComponent ); UDecalComponent* DecalComponent = Cast<UDecalComponent>( InComponent ); if( PrimitiveComp ) { PrimitiveComp->SetMaterial( InElementIndex, InNewMaterial ); } else if( DecalComponent ) { DecalComponent->SetMaterial( InElementIndex, InNewMaterial ); } }; // Scan the selected actors mesh components for the old material and swap it with the new material for( FMaterialIterator It( SelectedComponents ); It; ++It ) { int32 MaterialIndex = It.GetMaterialIndex(); UActorComponent* CurrentComponent = It.GetComponent(); if( CurrentComponent ) { // Component materials can be replaced if they are not created from a blueprint (not exposed to the user) and have material overrides on the component bool bCanBeReplaced = ( CurrentComponent->IsA( UMeshComponent::StaticClass() ) || CurrentComponent->IsA( UDecalComponent::StaticClass() ) || CurrentComponent->IsA( UTextRenderComponent::StaticClass() ) || CurrentComponent->IsA( ULandscapeComponent::StaticClass() ) ); UMaterialInterface* Material = It.GetMaterial(); // Check if the material is the same as the previous material or we are replaceing all in the same slot. If so we will swap it with the new material if( bCanBeReplaced && ( Material == PrevMaterial || bReplaceAll ) && It.GetMaterialIndex() == SlotIndex ) { // Begin a transaction for undo/redo the first time we encounter a material to replace. // There is only one transaction for all replacement if( bShouldMakeTransaction && !bMadeTransaction ) { GEditor->BeginTransaction( NSLOCTEXT("UnrealEd", "ReplaceComponentUsedMaterial", "Replace component used material") ); bMadeTransaction = true; } UProperty* MaterialProperty = NULL; UObject* EditChangeObject = CurrentComponent; if( CurrentComponent->IsA( UMeshComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UMeshComponent::StaticClass(), "OverrideMaterials" ); } else if( CurrentComponent->IsA( UDecalComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UDecalComponent::StaticClass(), "DecalMaterial" ); } else if( CurrentComponent->IsA( UTextRenderComponent::StaticClass() ) ) { MaterialProperty = FindField<UProperty>( UTextRenderComponent::StaticClass(), "TextMaterial" ); } else if (CurrentComponent->IsA<ULandscapeComponent>() ) { MaterialProperty = FindField<UProperty>( ALandscapeProxy::StaticClass(), "LandscapeMaterial" ); EditChangeObject = CastChecked<ULandscapeComponent>(CurrentComponent)->GetLandscapeProxy(); } // Add a navigation update lock only if the component world is valid TSharedPtr<FNavigationLockContext> NavUpdateLock; UWorld* World = CurrentComponent->GetWorld(); if( World ) { NavUpdateLock = MakeShareable( new FNavigationLockContext(World, ENavigationLockReason::MaterialUpdate) ); } EditChangeObject->PreEditChange( MaterialProperty ); if( NotifyHook && MaterialProperty ) { NotifyHook->NotifyPreChange( MaterialProperty ); } SwapMaterialLambda( CurrentComponent, It.GetMaterialIndex(), NewMaterial ); FPropertyChangedEvent PropertyChangedEvent( MaterialProperty ); EditChangeObject->PostEditChangeProperty( PropertyChangedEvent ); if( NotifyHook && MaterialProperty ) { NotifyHook->NotifyPostChange( PropertyChangedEvent, MaterialProperty ); } // Propagate material change to instances of the edited component template if( !FApp::IsGame() ) { TArray<UObject*> ComponentArchetypeInstances; if( CurrentComponent->HasAnyFlags(RF_ArchetypeObject) ) { CurrentComponent->GetArchetypeInstances(ComponentArchetypeInstances); } else if( UObject* Outer = CurrentComponent->GetOuter() ) { TArray<UObject*> OuterArchetypeInstances; Outer->GetArchetypeInstances(OuterArchetypeInstances); for( auto OuterArchetypeInstance : OuterArchetypeInstances ) { if( UObject* ArchetypeInstance = static_cast<UObject*>(FindObjectWithOuter(OuterArchetypeInstance, CurrentComponent->GetClass(), CurrentComponent->GetFName())) ) { ComponentArchetypeInstances.Add(ArchetypeInstance); } } } for( auto ComponentArchetypeInstance : ComponentArchetypeInstances ) { CurrentComponent = CastChecked<UActorComponent>( ComponentArchetypeInstance ); if( CurrentComponent->IsA<ULandscapeComponent>() ) { ComponentArchetypeInstance = CastChecked<ULandscapeComponent>(CurrentComponent)->GetLandscapeProxy(); } // Reset the navigation update lock if necessary UWorld* PreviousWorld = World; World = CurrentComponent->GetWorld(); if( PreviousWorld != World ) { NavUpdateLock = MakeShareable( new FNavigationLockContext(World, ENavigationLockReason::MaterialUpdate) ); } ComponentArchetypeInstance->PreEditChange( MaterialProperty ); SwapMaterialLambda( CurrentComponent, It.GetMaterialIndex(), NewMaterial ); ComponentArchetypeInstance->PostEditChangeProperty( PropertyChangedEvent ); } } } } } if( bMadeTransaction ) { // End the transation if we created one GEditor->EndTransaction(); // Redraw viewports to reflect the material changes GUnrealEd->RedrawLevelEditingViewports(); } }
bool FStaticMeshEditorViewportClient::InputWidgetDelta( FViewport* Viewport, EAxisList::Type CurrentAxis, FVector& Drag, FRotator& Rot, FVector& Scale ) { bool bHandled = false; if (bManipulating) { if (CurrentAxis != EAxisList::None) { UStaticMeshSocket* SelectedSocket = StaticMeshEditorPtr.Pin()->GetSelectedSocket(); if(SelectedSocket) { UProperty* ChangedProperty = NULL; const FWidget::EWidgetMode MoveMode = GetWidgetMode(); if(MoveMode == FWidget::WM_Rotate) { ChangedProperty = FindField<UProperty>( UStaticMeshSocket::StaticClass(), "RelativeRotation" ); SelectedSocket->PreEditChange(ChangedProperty); FRotator CurrentRot = SelectedSocket->RelativeRotation; FRotator SocketWinding, SocketRotRemainder; CurrentRot.GetWindingAndRemainder(SocketWinding, SocketRotRemainder); const FQuat ActorQ = SocketRotRemainder.Quaternion(); const FQuat DeltaQ = Rot.Quaternion(); const FQuat ResultQ = DeltaQ * ActorQ; const FRotator NewSocketRotRem = FRotator( ResultQ ); FRotator DeltaRot = NewSocketRotRem - SocketRotRemainder; DeltaRot.Normalize(); SelectedSocket->RelativeRotation += DeltaRot; SelectedSocket->RelativeRotation = SelectedSocket->RelativeRotation.Clamp(); } else if(MoveMode == FWidget::WM_Translate) { ChangedProperty = FindField<UProperty>( UStaticMeshSocket::StaticClass(), "RelativeLocation" ); SelectedSocket->PreEditChange(ChangedProperty); //FRotationMatrix SocketRotTM( SelectedSocket->RelativeRotation ); //FVector SocketMove = SocketRotTM.TransformVector( Drag ); SelectedSocket->RelativeLocation += Drag; } if ( ChangedProperty ) { FPropertyChangedEvent PropertyChangedEvent( ChangedProperty ); SelectedSocket->PostEditChangeProperty(PropertyChangedEvent); } StaticMeshEditorPtr.Pin()->GetStaticMesh()->MarkPackageDirty(); } else { const bool bSelectedPrim = StaticMeshEditorPtr.Pin()->HasSelectedPrims(); if (bSelectedPrim && CurrentAxis != EAxisList::None) { const FWidget::EWidgetMode MoveMode = GetWidgetMode(); if (MoveMode == FWidget::WM_Rotate) { StaticMeshEditorPtr.Pin()->RotateSelectedPrims(Rot); } else if (MoveMode == FWidget::WM_Scale) { StaticMeshEditorPtr.Pin()->ScaleSelectedPrims(Scale); } else if (MoveMode == FWidget::WM_Translate) { StaticMeshEditorPtr.Pin()->TranslateSelectedPrims(Drag); } StaticMeshEditorPtr.Pin()->GetStaticMesh()->MarkPackageDirty(); } } } Invalidate(); bHandled = true; } return bHandled; }