add optional ids to node event listeners + properly clean them up

This commit is contained in:
HJfod 2023-03-29 22:07:33 +03:00
parent 69bd0d99ef
commit 35f7f86e6d
2 changed files with 51 additions and 14 deletions

View file

@ -852,7 +852,10 @@ private:
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer(); GEODE_DLL geode::modifier::FieldContainer* getFieldContainer();
GEODE_DLL std::optional<json::Value> getAttributeInternal(std::string const& attribute); GEODE_DLL std::optional<json::Value> getAttributeInternal(std::string const& attribute);
GEODE_DLL void addEventListenerInternal(geode::EventListenerProtocol* protocol); GEODE_DLL void addEventListenerInternal(
std::string const& id,
geode::EventListenerProtocol* protocol
);
public: public:
/** /**
@ -1003,24 +1006,28 @@ public:
template <class Filter, class... Args> template <class Filter, class... Args>
geode::EventListenerProtocol* addEventListener( geode::EventListenerProtocol* addEventListener(
geode::utils::MiniFunction<typename Filter::Callback> callback, Args&&... args std::string const& id,
geode::utils::MiniFunction<typename Filter::Callback> callback,
Args&&... args
) { ) {
auto listener = new geode::EventListener<Filter>( auto listener = new geode::EventListener<Filter>(
callback, Filter(this, std::forward<Args>(args)...) callback, Filter(this, std::forward<Args>(args)...)
); );
this->addEventListenerInternal(listener); this->addEventListenerInternal(id, listener);
return listener; return listener;
} }
template <class Ev, class... Args> template <class Filter, class... Args>
geode::EventListenerProtocol* addEventListener( geode::EventListenerProtocol* addEventListener(
geode::utils::MiniFunction<geode::ListenerResult(Ev*)> callback, geode::utils::MiniFunction<typename Filter::Callback> callback,
Args&&... args Args&&... args
) { ) {
return this->template addEventListener<typename Ev::Filter>( return this->template addEventListener<Filter, Args...>(
callback, std::forward<Args>(args)... "", callback, std::forward<Args>(args)...
); );
} }
GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener); GEODE_DLL void removeEventListener(geode::EventListenerProtocol* listener);
GEODE_DLL void removeEventListener(std::string const& id);
GEODE_DLL geode::EventListenerProtocol* getEventListener(std::string const& id);
/// @{ /// @{
/// @name Shader Program /// @name Shader Program

View file

@ -22,7 +22,8 @@ private:
Ref<Layout> m_layout = nullptr; Ref<Layout> m_layout = nullptr;
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr; std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
std::unordered_map<std::string, json::Value> m_attributes; std::unordered_map<std::string, json::Value> m_attributes;
std::vector<EventListenerProtocol*> m_eventListeners; std::unordered_set<std::unique_ptr<EventListenerProtocol>> m_eventListeners;
std::unordered_map<std::string, std::unique_ptr<EventListenerProtocol>> m_idEventListeners;
friend class ProxyCCNode; friend class ProxyCCNode;
friend class cocos2d::CCNode; friend class cocos2d::CCNode;
@ -31,9 +32,6 @@ private:
virtual ~GeodeNodeMetadata() { virtual ~GeodeNodeMetadata() {
delete m_fieldContainer; delete m_fieldContainer;
for (auto& listener : m_eventListeners) {
delete listener;
}
} }
public: public:
@ -195,12 +193,44 @@ std::optional<json::Value> CCNode::getAttributeInternal(std::string const& attr)
return std::nullopt; return std::nullopt;
} }
void CCNode::addEventListenerInternal(EventListenerProtocol* listener) { void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) {
GeodeNodeMetadata::set(this)->m_eventListeners.push_back(listener); auto meta = GeodeNodeMetadata::set(this);
if (id.size()) {
if (meta->m_idEventListeners.contains(id)) {
meta->m_idEventListeners.at(id).reset(listener);
}
else {
meta->m_idEventListeners.emplace(id, listener);
}
}
else {
std::erase_if(meta->m_eventListeners, [=](auto& l) {
return l.get() == listener;
});
meta->m_eventListeners.emplace(listener);
}
} }
void CCNode::removeEventListener(EventListenerProtocol* listener) { void CCNode::removeEventListener(EventListenerProtocol* listener) {
ranges::remove(GeodeNodeMetadata::set(this)->m_eventListeners, listener); auto meta = GeodeNodeMetadata::set(this);
std::erase_if(meta->m_eventListeners, [=](auto& l) {
return l.get() == listener;
});
std::erase_if(meta->m_idEventListeners, [=](auto& l) {
return l.second.get() == listener;
});
}
void CCNode::removeEventListener(std::string const& id) {
GeodeNodeMetadata::set(this)->m_idEventListeners.erase(id);
}
EventListenerProtocol* CCNode::getEventListener(std::string const& id) {
auto meta = GeodeNodeMetadata::set(this);
if (meta->m_idEventListeners.contains(id)) {
return meta->m_idEventListeners.at(id).get();
}
return nullptr;
} }
#pragma warning(pop) #pragma warning(pop)