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.
}

```
This commit is contained in:
LuisAntonRebollo 2014-04-23 21:09:50 +02:00
parent aca58356ee
commit 0137c86765

View file

@ -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;