|
You can find a patch attached that enables this feature.
You can use it with natively declared dynamic multicast delegates (declared using the DECLARE_DYNAMIC_MULTICAST_DELEGATE family of macros), or with Blueprint declared Event Dispatchers.
Events.patch (6,615 bytes)
Index: NoesisTypeClass.cpp
===================================================================
--- NoesisTypeClass.cpp (revision 12417)
+++ NoesisTypeClass.cpp (working copy)
@@ -369,6 +369,12 @@
typedef Noesis::FlowDirection NoesisType;
static Noesis::FlowDirection ToNoesis(const ETextFlowDirection& Value)
{
+ if (Value == ETextFlowDirection::Auto)
+ {
+ EFlowDirection FlowDirection = FLayoutLocalization::GetLocalizedLayoutDirection();
+ return (FlowDirection == EFlowDirection::RightToLeft) ? Noesis::FlowDirection_RightToLeft : Noesis::FlowDirection_LeftToRight;
+ }
+
return (Value == ETextFlowDirection::RightToLeft) ? Noesis::FlowDirection_RightToLeft : Noesis::FlowDirection_LeftToRight;
}
static ETextFlowDirection ToUnreal(const Noesis::FlowDirection& Value)
@@ -1673,7 +1679,6 @@
NoesisTypeProperty::NoesisTypeProperty(Noesis::Symbol Name, const Noesis::Type* Type)
: Noesis::TypeProperty(Name, Type)
{
- check(Type != nullptr);
}
void* NoesisTypeProperty::GetContent(void* Ptr) const
@@ -1755,15 +1760,33 @@
mProperties.Insert(It, Property);
}
+ void AddEvent(NoesisTypeProperty* Event)
+ {
+ check(Event);
+
+ PropertyVector::Iterator It = LowerBound(mEvents.Begin(), mEvents.End(), Event,
+ [](Noesis::TypeProperty* elem1, Noesis::TypeProperty* elem2)
+ {
+ return elem1->GetName() < elem2->GetName();
+ });
+
+ check(It == mEvents.End() || (*It)->GetName() != Event->GetName());
+
+ mEvents.Insert(It, Event);
+ }
+
void ChangeName(Noesis::Symbol NewName)
{
PropertyVector Properties = mProperties;
mProperties.Clear();
+ PropertyVector Events = mEvents;
+ mEvents.Clear();
const Noesis::TypeClass* Base = mBase;
NoesisIsShuttingDown = true;
this->~NoesisTypeClass();
NoesisIsShuttingDown = false;
::new(this) NoesisTypeClass(NewName);
+ mEvents = Noesis::MoveArg(Events);
mProperties = Noesis::MoveArg(Properties);
mBase = Base;
}
@@ -1775,6 +1798,12 @@
NoesisTypeProperty* Property = (NoesisTypeProperty*)TypeProperty;
Property->Invalidate();
}
+
+ for (auto TypeProperty : mEvents)
+ {
+ NoesisTypeProperty* Property = (NoesisTypeProperty*)TypeProperty;
+ Property->Invalidate();
+ }
}
union
@@ -2008,6 +2037,7 @@
Noesis::PropertyChangedEventHandler PropertyChangedHandler;
UObject* Object;
TMap<UFunction*, Noesis::Ptr<class NoesisFunctionWrapper>> CommandMap;
+ TMap<FProperty*, Noesis::EventHandler> EventMap;
};
class NoesisFunctionWrapper : public Noesis::BaseCommand
@@ -2389,6 +2419,112 @@
return Property->HasAllPropertyFlags(CPF_BlueprintReadOnly);
}
+class NoesisTypePropertyObjectWrapperEvent : public NoesisTypeProperty
+{
+public:
+ NoesisTypePropertyObjectWrapperEvent(Noesis::Symbol Name, FProperty* InProperty);
+
+ /// From TypeProperty
+ //@{
+ void* GetContent(const void* Ptr) const override;
+ const void* Get(const void* Ptr) const override;
+ //@}
+
+ virtual void Invalidate() override;
+
+protected:
+ /// From TypeProperty
+ //@{
+ bool IsReadOnly() const override;
+ //@}
+
+private:
+ FProperty* Property;
+};
+
+NoesisTypePropertyObjectWrapperEvent::NoesisTypePropertyObjectWrapperEvent(Noesis::Symbol Name, FProperty* InProperty)
+ : NoesisTypeProperty(Name, nullptr), Property(InProperty)
+{
+}
+
+DEFINE_FUNCTION(execNoesisDelegate)
+{
+ P_FINISH;
+ P_NATIVE_BEGIN;
+
+ UFunction* Delegate = Stack.Node;
+ FString EventName = Delegate->GetName().RightChop(15); // Remove the NoesisDelegate_ prefix
+ auto Wrapper = NoesisFindComponentForUObject(Context);
+ if (Wrapper != nullptr)
+ {
+ auto TypeClass = (NoesisTypeClass*)Wrapper->GetClassType();
+ Noesis::TypeClassEvent ClassEvent = Noesis::FindEvent(TypeClass, Noesis::Symbol(TCHAR_TO_UTF8(*EventName)));
+ auto TypeProperty = (NoesisTypePropertyObjectWrapperEvent*)ClassEvent.event;
+ if (TypeProperty != nullptr)
+ {
+ auto EventHandler = (Noesis::EventHandler*)TypeProperty->GetContent(Wrapper);
+ Noesis::EventArgs Args;
+ EventHandler->Invoke(Wrapper, Args);
+ }
+ }
+
+ P_NATIVE_END;
+}
+
+void* NoesisTypePropertyObjectWrapperEvent::GetContent(const void* Ptr) const
+{
+#if WITH_EDITOR
+ if (Property == nullptr)
+ {
+ NS_LOG("A property of a deleted class is still referenced");
+ return nullptr;
+ }
+#endif
+
+ NoesisObjectWrapper* Wrapper = (NoesisObjectWrapper*)Ptr;
+ if (Wrapper->Object == nullptr)
+ {
+ NS_LOG("A wrapper of a deleted object is still referenced");
+ return nullptr;
+ }
+
+ auto Found = Wrapper->EventMap.Find(Property);
+ if (Found == nullptr)
+ {
+ // We add the fuction names to the UObject class so FScriptDelegate can find them later.
+ // We only need to do this once per event name.
+ const auto DelegateName = WriteToString<128>("NoesisDelegate_", *Property->GetName());
+ UClass* ObjectClass = UObject::StaticClass();
+ if (ObjectClass->FindFunctionByName(*DelegateName) == nullptr)
+ {
+ auto NoesisDelegateFunc = NewObject<UFunction>(ObjectClass, *DelegateName);
+ NoesisDelegateFunc->SetNativeFunc(&execNoesisDelegate);
+ NoesisDelegateFunc->FunctionFlags |= FUNC_Native;
+ ObjectClass->AddFunctionToFunctionMap(NoesisDelegateFunc, *DelegateName);
+ }
+
+ FScriptDelegate Delegate;
+ Delegate.BindUFunction(Wrapper->Object, *DelegateName);
+ FMulticastDelegateProperty* DelegateProperty = (FMulticastDelegateProperty*)Property;
+ DelegateProperty->AddDelegate(Delegate, Wrapper->Object);
+ }
+ return &Wrapper->EventMap.FindOrAdd(Property);
+}
+
+const void* NoesisTypePropertyObjectWrapperEvent::Get(const void* Ptr) const
+{
+ return GetContent(Ptr);
+}
+
+void NoesisTypePropertyObjectWrapperEvent::Invalidate()
+{
+}
+
+bool NoesisTypePropertyObjectWrapperEvent::IsReadOnly() const
+{
+ return true;
+}
+
class NoesisTypePropertyObjectWrapperGetterSetter : public NoesisTypeProperty
{
public:
@@ -2680,6 +2816,12 @@
TypeClass->AddProperty(TypeProperty);
}
}
+
+ if (Property->GetClass()->IsChildOf(FMulticastDelegateProperty::StaticClass()))
+ {
+ NoesisTypeProperty* TypeProperty = new NoesisTypePropertyObjectWrapperEvent(PropertyId, Property);
+ TypeClass->AddEvent(TypeProperty);
+ }
}
}
@@ -3450,6 +3592,11 @@
Wrapper = *TextureSource;
}
}
+ else if (Class->IsChildOf(UNoesisXaml::StaticClass()))
+ {
+ auto NoesisXaml = (UNoesisXaml*)Object;
+ Wrapper = NoesisXaml->LoadXaml();
+ }
else
{
Wrapper = *new NoesisObjectWrapper(Object);
|