diff --git a/Engine/source/core/util/tSignal.h b/Engine/source/core/util/tSignal.h index ea2e67954..a275d8da4 100644 --- a/Engine/source/core/util/tSignal.h +++ b/Engine/source/core/util/tSignal.h @@ -77,6 +77,8 @@ protected: void insert(DelegateLink* node, F32 order); void unlink(); + + virtual ~DelegateLink() {} }; DelegateLink mList; @@ -92,6 +94,78 @@ protected: Vector mTriggerNext; }; +template class SignalBaseT; + +/// Class for handle automatic diconnect form Signal when destroyed +template< typename Signature > +class SignalSlot +{ +public: + typedef Delegate< Signature > DelegateSig; + typedef SignalBaseT< Signature > SignalSig; + + SignalSlot() : mSignal(NULL) + { + + } + + ~SignalSlot() + { + disconnect(); + } + + const DelegateSig& getDelegate() { return mDlg; } + + /// setDelegate disconect form Signal old delegate and connect new delegate + template + void setDelegate( const X &fn ) { setDelegate( DelegateSig( fn ) ); } + + template + void setDelegate( const X &ptr, const Y &fn ) { setDelegate( DelegateSig( ptr, fn ) ); } + + void setDelegate( const DelegateSig &dlg) + { + SignalSig* signal = mSignal; + if( isConnected() ) + disconnect(); + + mDlg = dlg; + if( signal && mDlg ) + signal->notify( mDlg ); + } + + /// is connected to Signal + bool isConnected() const { return mSignal; } + + /// disconnect from Signal + void disconnect() + { + if( mSignal ) + { + SignalSig *oldSignal = mSignal; + mSignal = NULL; + oldSignal->remove( mDlg ); + } + } + +protected: + friend class SignalSig; + + void _setSignal(SignalSig *sig) + { + mSignal = sig; + } + + SignalSig* _getSignal() const { return mSignal; } + + DelegateSig mDlg; + SignalSig *mSignal; + +private: + SignalSlot( const SignalSlot&) {} + SignalSlot& operator=( const SignalSlot&) {} +}; + template class SignalBaseT : public SignalBase { public: @@ -163,6 +237,18 @@ public: notify(dlg, order); } + void notify( SignalSlot &slot, F32 order = 0.5f) + { + if( !slot.getDelegate() ) + return; + + if( slot.isConnected() ) + slot.disconnect(); + + slot._setSignal( this ); + mList.insert( new SlotLinkImpl(slot), order ); + } + template void remove(T obj,U func) { @@ -198,6 +284,23 @@ protected: DelegateLinkImpl(DelegateSig dlg) : mDelegate(dlg) {} }; + struct SlotLinkImpl : public DelegateLinkImpl + { + SlotLinkImpl(SignalSlot& slot) : mSlot( &slot ), DelegateLinkImpl( slot.getDelegate() ) + { + + } + + ~SlotLinkImpl() + { + if( mSlot ) + mSlot->_setSignal( NULL ); + } + + protected: + SignalSlot *mSlot; + }; + DelegateSig & getDelegate(SignalBase::DelegateLink * link) { return ((DelegateLinkImpl*)link)->mDelegate;