Browse Source

Add SlotSignal for handle automatic disconnect on Signal or SignalSlot destruction.

Example:

```
Win32WindowManager::Win32WindowManager()
{
   // Register in the process list.
   mOnProcessSignalSlot.setDelegate( this, &Win32WindowManager::_process );
   Process::notify( mOnProcessSignalSlot, PROCESS_INPUT_ORDER );

   // When Signal it's destroyed, all slots are disconected.
   // When a SignalSlot it's destroyed, it's disconected from Signal.
}

```
LuisAntonRebollo 11 years ago
parent
commit
0137c86765
1 changed files with 103 additions and 0 deletions
  1. 103 0
      Engine/source/core/util/tSignal.h

+ 103 - 0
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<DelegateLink*> mTriggerNext;
 };
 
+template<typename Signature> 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<typename X>
+   void setDelegate( const X &fn ) { setDelegate( DelegateSig( fn ) ); }
+
+   template<typename X, typename Y>
+   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<typename Signature> class SignalBaseT : public SignalBase
 {
 public:
@@ -163,6 +237,18 @@ public:
       notify(dlg, order);
    }
 
+   void notify( SignalSlot<Signature> &slot, F32 order = 0.5f)
+   {
+      if( !slot.getDelegate() )
+         return;
+
+      if( slot.isConnected() )
+         slot.disconnect();
+
+      slot._setSignal( this );
+      mList.insert( new SlotLinkImpl(slot), order );
+   }
+
    template <class T,class U>
    void remove(T obj,U func)
    {
@@ -198,6 +284,23 @@ protected:
       DelegateLinkImpl(DelegateSig dlg) : mDelegate(dlg) {}
    };
 
+   struct SlotLinkImpl : public DelegateLinkImpl
+   {      
+      SlotLinkImpl(SignalSlot<Signature>& slot) : mSlot( &slot ), DelegateLinkImpl( slot.getDelegate() )
+      {
+
+      }
+
+      ~SlotLinkImpl()
+      {
+         if( mSlot )
+            mSlot->_setSignal( NULL ); 
+      }
+
+   protected:
+      SignalSlot<Signature> *mSlot;
+   };
+
    DelegateSig & getDelegate(SignalBase::DelegateLink * link)
    {
       return ((DelegateLinkImpl*)link)->mDelegate;