You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Added the FScriptTypedElementHandle. These handles are disarmed when the element they pointing to is destroyed instead of crashing the engine. They do have a performance overhead so using these should be restricted to exposing stuff to blueprint/python. Reworked the TypedElementList to be a template so that we have both a FTypedElementList and a FScriptTypedElementList from the same source code. Changed the api of the interfaces so that can now accept and use the scripted version of the handle and list instead of the native ones. #jira UE-133667 #rb Brooke.Hubert #preflight 61f89bfaf657e25a5908db48 #ROBOMERGE-AUTHOR: julien.stjean #ROBOMERGE-SOURCE: CL 18816318 in //UE5/Release-5.0/... via CL 18816336 via CL 18822818 #ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v910-18824042) [CL 18824371 by julien stjean in ue5-main branch]
355 lines
10 KiB
C++
355 lines
10 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Selection.h"
|
|
#include "UObject/Package.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "Elements/Framework/EngineElementsLibrary.h"
|
|
#include "Elements/Interfaces/TypedElementObjectInterface.h"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogSelection, Log, All);
|
|
|
|
class ISelectionElementBridge
|
|
{
|
|
public:
|
|
virtual ~ISelectionElementBridge() = default;
|
|
virtual bool IsValidObjectType(const UObject* InObject) const = 0;
|
|
virtual FTypedElementHandle GetElementHandleForObject(const UObject* InObject, const bool bAllowCreate = true) const = 0;
|
|
};
|
|
|
|
class FObjectSelectionElementBridge : public ISelectionElementBridge
|
|
{
|
|
public:
|
|
virtual bool IsValidObjectType(const UObject* InObject) const override
|
|
{
|
|
check(InObject);
|
|
return true;
|
|
}
|
|
|
|
virtual FTypedElementHandle GetElementHandleForObject(const UObject* InObject, const bool bAllowCreate = true) const override
|
|
{
|
|
check(InObject);
|
|
return UEngineElementsLibrary::AcquireEditorObjectElementHandle(InObject, bAllowCreate);
|
|
}
|
|
};
|
|
|
|
class FActorSelectionElementBridge : public ISelectionElementBridge
|
|
{
|
|
public:
|
|
virtual bool IsValidObjectType(const UObject* InObject) const override
|
|
{
|
|
check(InObject);
|
|
return InObject->IsA<AActor>();
|
|
}
|
|
|
|
virtual FTypedElementHandle GetElementHandleForObject(const UObject* InObject, const bool bAllowCreate = true) const override
|
|
{
|
|
check(InObject);
|
|
return UEngineElementsLibrary::AcquireEditorActorElementHandle(CastChecked<AActor>(InObject), bAllowCreate);
|
|
}
|
|
};
|
|
|
|
class FComponentSelectionElementBridge : public ISelectionElementBridge
|
|
{
|
|
public:
|
|
virtual bool IsValidObjectType(const UObject* InObject) const override
|
|
{
|
|
check(InObject);
|
|
return InObject->IsA<UActorComponent>();
|
|
}
|
|
|
|
virtual FTypedElementHandle GetElementHandleForObject(const UObject* InObject, const bool bAllowCreate = true) const override
|
|
{
|
|
check(InObject);
|
|
return UEngineElementsLibrary::AcquireEditorComponentElementHandle(CastChecked<UActorComponent>(InObject), bAllowCreate);
|
|
}
|
|
};
|
|
|
|
USelection::FOnSelectionChanged USelection::SelectionChangedEvent;
|
|
USelection::FOnSelectionChanged USelection::SelectObjectEvent;
|
|
FSimpleMulticastDelegate USelection::SelectNoneEvent;
|
|
USelection::FOnSelectionElementSelectionPtrChanged USelection::SelectionElementSelectionPtrChanged;
|
|
|
|
USelection* USelection::CreateObjectSelection(UObject* InOuter, FName InName, EObjectFlags InFlags)
|
|
{
|
|
USelection* Selection = NewObject<USelection>(InOuter, InName, InFlags);
|
|
Selection->Initialize(MakeShared<FObjectSelectionElementBridge>());
|
|
return Selection;
|
|
}
|
|
|
|
USelection* USelection::CreateActorSelection(UObject* InOuter, FName InName, EObjectFlags InFlags)
|
|
{
|
|
USelection* Selection = NewObject<USelection>(InOuter, InName, InFlags);
|
|
Selection->Initialize(MakeShared<FActorSelectionElementBridge>());
|
|
return Selection;
|
|
}
|
|
|
|
USelection* USelection::CreateComponentSelection(UObject* InOuter, FName InName, EObjectFlags InFlags)
|
|
{
|
|
USelection* Selection = NewObject<USelection>(InOuter, InName, InFlags);
|
|
Selection->Initialize(MakeShared<FComponentSelectionElementBridge>());
|
|
return Selection;
|
|
}
|
|
|
|
void USelection::Initialize(TSharedRef<ISelectionElementBridge>&& InSelectionElementBridge)
|
|
{
|
|
SelectionElementBridge = MoveTemp(InSelectionElementBridge);
|
|
}
|
|
|
|
void USelection::SetElementSelectionSet(UTypedElementSelectionSet* InElementSelectionSet)
|
|
{
|
|
if (ElementSelectionSet)
|
|
{
|
|
ElementSelectionSet->Legacy_GetElementListSync().OnSyncEvent().RemoveAll(this);
|
|
}
|
|
|
|
UTypedElementSelectionSet* OldElementSelectionSet = ElementSelectionSet;
|
|
ElementSelectionSet = InElementSelectionSet;
|
|
|
|
if (ElementSelectionSet)
|
|
{
|
|
ElementSelectionSet->Legacy_GetElementListSync().OnSyncEvent().AddUObject(this, &USelection::OnElementListSyncEvent);
|
|
}
|
|
|
|
USelection::SelectionElementSelectionPtrChanged.Broadcast(this, OldElementSelectionSet, ElementSelectionSet);
|
|
}
|
|
|
|
UTypedElementSelectionSet* USelection::GetElementSelectionSet() const
|
|
{
|
|
return ElementSelectionSet;
|
|
}
|
|
|
|
int32 USelection::Num() const
|
|
{
|
|
return ElementSelectionSet
|
|
? ElementSelectionSet->GetElementList()->Num()
|
|
: 0;
|
|
}
|
|
|
|
UObject* USelection::GetSelectedObject(const int32 InIndex) const
|
|
{
|
|
if (ElementSelectionSet)
|
|
{
|
|
FTypedElementListConstRef ElementList = ElementSelectionSet->GetElementList();
|
|
if (ElementList->IsValidIndex(InIndex))
|
|
{
|
|
const FTypedElementHandle ElementHandle = ElementList->GetElementHandleAt(InIndex);
|
|
return GetObjectForElementHandle(ElementHandle);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void USelection::BeginBatchSelectOperation()
|
|
{
|
|
if (ElementSelectionSet)
|
|
{
|
|
ElementSelectionSet->Legacy_GetElementListSync().BeginBatchOperation();
|
|
}
|
|
}
|
|
|
|
void USelection::EndBatchSelectOperation(bool bNotify)
|
|
{
|
|
if (ElementSelectionSet)
|
|
{
|
|
ElementSelectionSet->Legacy_GetElementListSync().EndBatchOperation(bNotify);
|
|
}
|
|
}
|
|
|
|
bool USelection::IsBatchSelecting() const
|
|
{
|
|
return ElementSelectionSet && ElementSelectionSet->Legacy_GetElementListSync().IsRunningBatchOperation();
|
|
}
|
|
|
|
bool USelection::IsValidObjectToSelect(const UObject* InObject) const
|
|
{
|
|
bool bIsValid = SelectionElementBridge->IsValidObjectType(InObject);
|
|
|
|
if (bIsValid && ElementSelectionSet)
|
|
{
|
|
TTypedElement<ITypedElementObjectInterface> ObjectElement = ElementSelectionSet->GetElementList()->GetElement<ITypedElementObjectInterface>(SelectionElementBridge->GetElementHandleForObject(InObject));
|
|
if (ObjectElement)
|
|
{
|
|
bIsValid &= ObjectElement.GetObject() == InObject;
|
|
}
|
|
else
|
|
{
|
|
// Elements must implement the object interface in order to be selected!
|
|
bIsValid = false;
|
|
}
|
|
}
|
|
|
|
return bIsValid;
|
|
}
|
|
|
|
UObject* USelection::GetObjectForElementHandle(const FTypedElementHandle& InElementHandle) const
|
|
{
|
|
check(InElementHandle && ElementSelectionSet);
|
|
|
|
if (TTypedElement<ITypedElementObjectInterface> ObjectElement = ElementSelectionSet->GetElementList()->GetElement<ITypedElementObjectInterface>(InElementHandle))
|
|
{
|
|
UObject* Object = ObjectElement.GetObject();
|
|
if (Object && SelectionElementBridge->IsValidObjectType(Object))
|
|
{
|
|
return Object;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void USelection::OnElementListSyncEvent(const FTypedElementList& InElementList, FTypedElementList::FLegacySync::ESyncType InSyncType, const FTypedElementHandle& InElementHandle, bool bIsWithinBatchOperation)
|
|
{
|
|
check(&InElementList == &ElementSelectionSet->GetElementList().Get());
|
|
|
|
const bool bNotify = !bIsWithinBatchOperation;
|
|
if (bNotify)
|
|
{
|
|
switch (InSyncType)
|
|
{
|
|
// Emit a general object selection changed notification for the following events
|
|
case FTypedElementList::FLegacySync::ESyncType::Added:
|
|
case FTypedElementList::FLegacySync::ESyncType::Removed:
|
|
if (UObject* Object = GetObjectForElementHandle(InElementHandle))
|
|
{
|
|
USelection::SelectObjectEvent.Broadcast(Object);
|
|
}
|
|
break;
|
|
|
|
// Emit a general selection changed notification for the following events
|
|
case FTypedElementList::FLegacySync::ESyncType::Modified:
|
|
case FTypedElementList::FLegacySync::ESyncType::Cleared:
|
|
case FTypedElementList::FLegacySync::ESyncType::BatchComplete:
|
|
USelection::SelectionChangedEvent.Broadcast(this);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void USelection::Select(UObject* InObject)
|
|
{
|
|
check(InObject && IsValidObjectToSelect(InObject));
|
|
if (ElementSelectionSet)
|
|
{
|
|
FTypedElementHandle ElementHandle = SelectionElementBridge->GetElementHandleForObject(InObject);
|
|
check(ElementHandle);
|
|
ElementSelectionSet->SelectElement(ElementHandle, FTypedElementSelectionOptions().SetAllowHidden(true).SetAllowGroups(false).SetWarnIfLocked(false));
|
|
}
|
|
}
|
|
|
|
void USelection::Deselect(UObject* InObject)
|
|
{
|
|
check(InObject);
|
|
if (ElementSelectionSet)
|
|
{
|
|
if (const FTypedElementHandle ElementHandle = SelectionElementBridge->GetElementHandleForObject(InObject, /*bAllowCreate*/false))
|
|
{
|
|
ElementSelectionSet->DeselectElement(ElementHandle, FTypedElementSelectionOptions().SetAllowHidden(true).SetAllowGroups(false).SetWarnIfLocked(false));
|
|
}
|
|
}
|
|
}
|
|
|
|
void USelection::Select(UObject* InObject, bool bSelect)
|
|
{
|
|
if (bSelect)
|
|
{
|
|
Select(InObject);
|
|
}
|
|
else
|
|
{
|
|
Deselect(InObject);
|
|
}
|
|
}
|
|
|
|
void USelection::ToggleSelect(UObject* InObject)
|
|
{
|
|
Select(InObject, InObject && !InObject->IsSelected());
|
|
}
|
|
|
|
void USelection::DeselectAll(UClass* InClass)
|
|
{
|
|
if (!ElementSelectionSet)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UClass* ClassToDeselect = InClass;
|
|
if (!ClassToDeselect)
|
|
{
|
|
ClassToDeselect = UObject::StaticClass();
|
|
}
|
|
|
|
TArray<UObject*> ObjectsToDeselect;
|
|
GetSelectedObjects(ClassToDeselect, ObjectsToDeselect);
|
|
|
|
TArray<FTypedElementHandle, TInlineAllocator<256>> ElementsToDeselect;
|
|
ElementsToDeselect.Reserve(ObjectsToDeselect.Num());
|
|
for (UObject* ObjectToDeselect : ObjectsToDeselect)
|
|
{
|
|
if (FTypedElementHandle ElementHandle = SelectionElementBridge->GetElementHandleForObject(ObjectToDeselect, /*bAllowCreate*/false))
|
|
{
|
|
ElementsToDeselect.Add(MoveTemp(ElementHandle));
|
|
}
|
|
}
|
|
|
|
if (ElementsToDeselect.Num() > 0)
|
|
{
|
|
ElementSelectionSet->DeselectElements(ElementsToDeselect, FTypedElementSelectionOptions().SetAllowHidden(true).SetAllowGroups(false).SetWarnIfLocked(false));
|
|
}
|
|
}
|
|
|
|
void USelection::ForceBatchDirty()
|
|
{
|
|
if (IsBatchSelecting())
|
|
{
|
|
check(ElementSelectionSet);
|
|
ElementSelectionSet->Legacy_GetElementListSync().ForceBatchOperationDirty();
|
|
}
|
|
}
|
|
|
|
void USelection::NoteSelectionChanged()
|
|
{
|
|
USelection::SelectionChangedEvent.Broadcast(this);
|
|
}
|
|
|
|
void USelection::NoteUnknownSelectionChanged()
|
|
{
|
|
USelection::SelectionChangedEvent.Broadcast(nullptr);
|
|
}
|
|
|
|
bool USelection::IsSelected(const UObject* InObject) const
|
|
{
|
|
if (InObject && ElementSelectionSet)
|
|
{
|
|
if (const FTypedElementHandle ElementHandle = SelectionElementBridge->GetElementHandleForObject(InObject, /*bAllowCreate*/false))
|
|
{
|
|
return ElementSelectionSet->IsElementSelected(ElementHandle, FTypedElementIsSelectedOptions());
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool USelection::IsClassSelected(UClass* Class) const
|
|
{
|
|
return ElementSelectionSet
|
|
&& TypedElementListObjectUtil::HasObjectsOfExactClass(ElementSelectionSet->GetElementList(), Class);
|
|
}
|
|
|
|
void USelection::Serialize(FArchive& Ar)
|
|
{
|
|
if (ElementSelectionSet)
|
|
{
|
|
ElementSelectionSet->Serialize(Ar);
|
|
}
|
|
}
|
|
|
|
bool USelection::Modify(bool bAlwaysMarkDirty)
|
|
{
|
|
return ElementSelectionSet
|
|
&& ElementSelectionSet->Modify(bAlwaysMarkDirty);
|
|
}
|