#pragma once // DelegateEvent is used to implement a Qt-style signal/slot mechanism. #include #include #include #include namespace sead { /// Manages signal and slots for an event. template class DelegateEvent { public: class Slot; using SlotList = TList; using SlotListNode = TListNode; /// A Slot is a wrapper around a Delegate that is invoked when a signal is emitted. class Slot : public IDisposer { public: template Slot(TDelegate delegate) // NOLINT(google-explicit-constructor) { mDelegate.construct(std::move(delegate)); // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) mDelegatePtr = mDelegate->getDelegate(); } template Slot(C* instance, void (C::*func)(T)) : Slot(Delegate1(instance, func)) { } ~Slot() override { release(); } void release() { if (mConnectedToDelegateEvent) { mNode.erase(); mConnectedToDelegateEvent = false; } } private: friend class DelegateEvent; void invoke_(T arg) { if (mDelegatePtr) (*mDelegatePtr)(arg); } SlotListNode mNode{this}; IDelegate1* mDelegatePtr = nullptr; StorageFor, true> mDelegate; bool mConnectedToDelegateEvent = false; }; virtual ~DelegateEvent() { auto it = mList.begin(); while (it != mList.end()) { Slot* ptr = *it; ++it; ptr->release(); } } void connect(Slot& slot) { slot.release(); mList.pushBack(&slot.mNode); slot.mConnectedToDelegateEvent = true; } void disconnect(Slot& slot) { slot.release(); } void emit(T arg) { for (Slot* slot : mList.robustRange()) slot->invoke_(arg); } int getNumSlots() const { return mList.size(); } protected: SlotList mList; }; } // namespace sead