void UUnrealEdEngine::NoteSelectionChange() { // The selection changed, so make sure the pivot (widget) is located in the right place UpdatePivotLocationForSelection( true ); // Clear active editing visualizer on selection change GUnrealEd->ComponentVisManager.ClearActiveComponentVis(); TArray<FEdMode*> ActiveModes; GLevelEditorModeTools().GetActiveModes( ActiveModes ); for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex ) { ActiveModes[ModeIndex]->ActorSelectionChangeNotify(); } const bool bComponentSelectionChanged = GetSelectedComponentCount() > 0; USelection* Selection = bComponentSelectionChanged ? GetSelectedComponents() : GetSelectedActors(); USelection::SelectionChangedEvent.Broadcast(Selection); if (!bComponentSelectionChanged) { //whenever selection changes, recompute whether the selection contains a locked actor bCheckForLockActors = true; //whenever selection changes, recompute whether the selection contains a world info actor bCheckForWorldSettingsActors = true; UpdateFloatingPropertyWindows(); } RedrawLevelEditingViewports(); }
bool UUnrealEdEngine::IsComponentSelected(const UPrimitiveComponent* PrimComponent) { bool bIsSelected = false; if (GetSelectedComponentCount() > 0) { bIsSelected = GetSelectedComponents()->IsSelected(PrimComponent->IsEditorOnly() ? PrimComponent->AttachParent : PrimComponent); } return bIsSelected; }
void UUnrealEdEngine::SelectComponent(UActorComponent* Component, bool bInSelected, bool bNotify, bool bSelectEvenIfHidden) { // Don't do any work if the component's selection state matches the target selection state const bool bComponentSelected = GetSelectedComponents()->IsSelected(Component); if (( bComponentSelected && !bInSelected ) || ( !bComponentSelected && bInSelected )) { if (bInSelected) { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Selected Component: %s"), *Component->GetClass()->GetName()); } else { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Deselected Component: %s"), *Component->GetClass()->GetName()); } GetSelectedComponents()->Select(Component, bInSelected); // Make sure the override delegate is bound properly auto SceneComponent = Cast<USceneComponent>(Component); if (SceneComponent) { FComponentEditorUtils::BindComponentSelectionOverride(SceneComponent, true); } // Update the selection visualization AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { TInlineComponentArray<UPrimitiveComponent*> PrimitiveComponents; ComponentOwner->GetComponents(PrimitiveComponents); for (int32 Idx = 0; Idx < PrimitiveComponents.Num(); ++Idx) { PrimitiveComponents[Idx]->PushSelectionToProxy(); } } if (bNotify) { NoteSelectionChange(); } } }
void EditorSelection::OnHierarchyListSelectionChange(const PODVector<UIElement*>& items, const PODVector<unsigned>& indices) { ClearSelection(); for (unsigned int i = 0; i < indices.Size(); ++i) { unsigned int index = indices[i]; UIElement* item = items[index]; int type = item->GetVar(TYPE_VAR).GetInt(); if (type == ITEM_COMPONENT) { Component* comp = editor_->GetListComponent(item); AddSelectedComponent(comp); } else if (type == ITEM_NODE) { Node* node = editor_->GetListNode(item); AddSelectedNode(node); } else if (type == ITEM_UI_ELEMENT) { UIElement* element = editor_->GetListUIElement(item); AddSelectedUIElement(element); } } // If only one node/UIElement selected, use it for editing if (GetNumSelectedNodes() == 1) editNode_ = selectedNodes_[0]; if (GetNumSelectedUIElements() == 1) editUIElement_ = selectedUIElements_[0]; // If selection contains only components, and they have a common node, use it for editing if (selectedNodes_.Empty() && !selectedComponents_.Empty()) { Node* commonNode = NULL; for (unsigned int i = 0; i < GetNumSelectedComponents(); ++i) { if (i == 0) commonNode = GetSelectedComponents()[i]->GetNode(); else { if (selectedComponents_[i]->GetNode() != commonNode) commonNode = NULL; } } editNode_ = commonNode; } // Now check if the component(s) can be edited. If many selected, must have same type or have same edit node if (!selectedComponents_.Empty()) { if (editNode_ == NULL) { StringHash compType = selectedComponents_[0]->GetType(); bool sameType = true; for (unsigned int i = 1; i < GetNumSelectedComponents(); ++i) { if (selectedComponents_[i]->GetType() != compType) { sameType = false; break; } } if (sameType) editComponents_ = selectedComponents_; } else { editComponents_ = selectedComponents_; numEditableComponentsPerNode_ = GetNumSelectedComponents(); } } // If just nodes selected, and no components, show as many matching components for editing as possible if (!selectedNodes_.Empty() && selectedComponents_.Empty() && selectedNodes_[0]->GetNumComponents() > 0) { unsigned int count = 0; for (unsigned int j = 0; j < selectedNodes_[0]->GetNumComponents(); ++j) { StringHash compType = selectedNodes_[0]->GetComponents()[j]->GetType(); bool sameType = true; for (unsigned int i = 1; i < GetNumSelectedNodes(); ++i) { if (selectedNodes_[i]->GetNumComponents() <= j || selectedNodes_[i]->GetComponents()[j]->GetType() != compType) { sameType = false; break; } } if (sameType) { ++count; for (unsigned int i = 0; i < GetNumSelectedNodes(); ++i) AddEditComponent(selectedNodes_[i]->GetComponents()[j]); } } if (count > 1) numEditableComponentsPerNode_ = count; } if (selectedNodes_.Empty() && editNode_ != NULL) AddEditNode(editNode_); else { editNodes_ = selectedNodes_; // Cannot multi-edit on scene and node(s) together as scene and node do not share identical attributes, // editing via gizmo does not make too much sense either if (editNodes_.Size() > 1 && editNodes_[0] == editor_->GetScene()) editNodes_.Erase(0); } if (selectedUIElements_.Empty() && editUIElement_ != NULL) AddEditUIElement(editUIElement_); else editUIElements_ = selectedUIElements_; }
void UUnrealEdEngine::SelectActor(AActor* Actor, bool bInSelected, bool bNotify, bool bSelectEvenIfHidden, bool bForceRefresh) { const bool bWarnIfLevelLocked = true; if( !CanSelectActor( Actor, bInSelected, bSelectEvenIfHidden, bWarnIfLevelLocked ) ) { return; } bool bSelectionHandled = false; TArray<FEdMode*> ActiveModes; GLevelEditorModeTools().GetActiveModes( ActiveModes ); for( int32 ModeIndex = 0; ModeIndex < ActiveModes.Num(); ++ModeIndex ) { bSelectionHandled |= ActiveModes[ModeIndex]->Select( Actor, bInSelected ); } // Select the actor and update its internals. if( !bSelectionHandled ) { if(bInSelected) { // If trying to select an Actor spawned by a ChildACtorComponent, instead select Actor that spawned us if(Actor->ParentComponentActor.IsValid()) { Actor = Actor->ParentComponentActor.Get(); } } if (GEditor->bGroupingActive) { // if this actor is a group, do a group select/deselect AGroupActor* SelectedGroupActor = Cast<AGroupActor>(Actor); if (SelectedGroupActor) { SelectGroup(SelectedGroupActor, true, bInSelected, bNotify); } else { // Select/Deselect this actor's entire group, starting from the top locked group. // If none is found, just use the actor. AGroupActor* ActorLockedRootGroup = AGroupActor::GetRootForActor(Actor, true); if (ActorLockedRootGroup) { SelectGroup(ActorLockedRootGroup, false, bInSelected, bNotify); } } } // Don't do any work if the actor's selection state is already the selected state. const bool bActorSelected = Actor->IsSelected(); if ( (bActorSelected && !bInSelected) || (!bActorSelected && bInSelected) ) { if(bInSelected) { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Selected Actor: %s"), *Actor->GetClass()->GetName()); } else { UE_LOG(LogEditorSelectUtils, Verbose, TEXT("Deselected Actor: %s"), *Actor->GetClass()->GetName() ); } GetSelectedActors()->Select( Actor, bInSelected ); if (!bInSelected) { if (GetSelectedComponentCount() > 0) { GetSelectedComponents()->Modify(); } for (UActorComponent* Component : Actor->GetComponents()) { GetSelectedComponents()->Deselect( Component ); // Remove the selection override delegates from the deselected components auto SceneComponent = Cast<USceneComponent>(Component); FComponentEditorUtils::BindComponentSelectionOverride(SceneComponent, false); } } else { // Bind the override delegates for the components in the selected actor for (UActorComponent* Component : Actor->GetComponents()) { auto SceneComponent = Cast<USceneComponent>(Component); FComponentEditorUtils::BindComponentSelectionOverride(SceneComponent, true); } } //A fast path to mark selection rather than reconnecting ALL components for ALL actors that have changed state SetActorSelectionFlags (Actor); if( bNotify ) { NoteSelectionChange(); } //whenever selection changes, recompute whether the selection contains a locked actor bCheckForLockActors = true; //whenever selection changes, recompute whether the selection contains a world info actor bCheckForWorldSettingsActors = true; } else { if (bNotify || bForceRefresh) { //reset the property windows. In case something has changed since previous selection UpdateFloatingPropertyWindows(bForceRefresh); } } } }
void UUnrealEdEngine::UpdatePivotLocationForSelection( bool bOnChange ) { // Pick a new common pivot, or not. AActor* SingleActor = nullptr; USceneComponent* SingleComponent = nullptr; if (GetSelectedComponentCount() > 0) { for (FSelectedEditableComponentIterator It(*GetSelectedComponents()); It; ++It) { UActorComponent* Component = CastChecked<UActorComponent>(*It); AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { auto SelectedActors = GetSelectedActors(); const bool bIsOwnerSelected = SelectedActors->IsSelected(ComponentOwner); check(bIsOwnerSelected); if (ComponentOwner->GetWorld() == GWorld) { SingleActor = ComponentOwner; if (Component->IsA<USceneComponent>()) { SingleComponent = CastChecked<USceneComponent>(Component); } const bool IsTemplate = ComponentOwner->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(ComponentOwner->GetLevel()); check(IsTemplate || LevelLocked); } } } } else { for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = static_cast<AActor*>(*It); checkSlow(Actor->IsA(AActor::StaticClass())); if (Actor->GetWorld() == GWorld) { const bool IsTemplate = Actor->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(Actor->GetLevel()); check(IsTemplate || LevelLocked); SingleActor = Actor; } } } if (SingleComponent != NULL) { SetPivot(SingleComponent->GetComponentLocation(), false, true); } else if( SingleActor != NULL ) { // For geometry mode use current pivot location as it's set to selected face, not actor FEditorModeTools& Tools = GLevelEditorModeTools(); if( Tools.IsModeActive(FBuiltinEditorModes::EM_Geometry) == false || bOnChange == true ) { // Set pivot point to the actor's location FVector PivotPoint = SingleActor->GetActorLocation(); // If grouping is active, see if this actor is part of a locked group and use that pivot instead if(GEditor->bGroupingActive) { AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(SingleActor, true, true); if(ActorGroupRoot) { PivotPoint = ActorGroupRoot->GetActorLocation(); } } SetPivot( PivotPoint, false, true ); } } else { ResetPivot(); } }