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 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:
/**
@ -1003,24 +1006,28 @@ public:
template <class Filter, class... Args>
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>(
callback, Filter(this, std::forward<Args>(args)...)
);
this->addEventListenerInternal(listener);
this->addEventListenerInternal(id, listener);
return listener;
}
template <class Ev, class... Args>
template <class Filter, class... Args>
geode::EventListenerProtocol* addEventListener(
geode::utils::MiniFunction<geode::ListenerResult(Ev*)> callback,
geode::utils::MiniFunction<typename Filter::Callback> callback,
Args&&... args
) {
return this->template addEventListener<typename Ev::Filter>(
callback, std::forward<Args>(args)...
return this->template addEventListener<Filter, Args...>(
"", callback, std::forward<Args>(args)...
);
}
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

View file

@ -22,7 +22,8 @@ private:
Ref<Layout> m_layout = nullptr;
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
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 cocos2d::CCNode;
@ -31,9 +32,6 @@ private:
virtual ~GeodeNodeMetadata() {
delete m_fieldContainer;
for (auto& listener : m_eventListeners) {
delete listener;
}
}
public:
@ -195,12 +193,44 @@ std::optional<json::Value> CCNode::getAttributeInternal(std::string const& attr)
return std::nullopt;
}
void CCNode::addEventListenerInternal(EventListenerProtocol* listener) {
GeodeNodeMetadata::set(this)->m_eventListeners.push_back(listener);
void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* 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) {
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)