mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-23 07:57:51 -05:00
replace attributes with an augmented user object system
This commit is contained in:
parent
e452f482a8
commit
f9d7cfdc68
4 changed files with 55 additions and 65 deletions
62
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
62
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
|
@ -838,19 +838,31 @@ public:
|
||||||
* and the previous UserObject (if existed) will be relese.
|
* and the previous UserObject (if existed) will be relese.
|
||||||
* The UserObject will be released in CCNode's destructure.
|
* The UserObject will be released in CCNode's destructure.
|
||||||
*
|
*
|
||||||
|
* @note In Geode, this actually sets the user object with the ID ""
|
||||||
|
* (empty string)
|
||||||
|
*
|
||||||
* @param A user assigned CCObject
|
* @param A user assigned CCObject
|
||||||
*/
|
*/
|
||||||
virtual void setUserObject(CCObject *pUserObject);
|
virtual void setUserObject(CCObject *pUserObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a user-assigned CCObject with a specific ID. This allows nodes to
|
||||||
|
* have multiple user objects. Objects should be prefixed with the mod ID.
|
||||||
|
* Assigning a null removes the user object with the ID
|
||||||
|
*/
|
||||||
|
GEODE_DLL void setUserObject(std::string const& id, CCObject* object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a user-assigned CCObject with the specific ID
|
||||||
|
*/
|
||||||
|
GEODE_DLL CCObject* getUserObject(std::string const& id);
|
||||||
|
|
||||||
/// @} end of Tag & User Data
|
/// @} end of Tag & User Data
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class geode::modifier::FieldContainer;
|
friend class geode::modifier::FieldContainer;
|
||||||
|
|
||||||
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer();
|
GEODE_DLL geode::modifier::FieldContainer* getFieldContainer();
|
||||||
#ifndef GEODE_IS_MEMBER_TEST
|
|
||||||
GEODE_DLL std::optional<matjson::Value> getAttributeInternal(std::string const& attribute);
|
|
||||||
#endif
|
|
||||||
GEODE_DLL void addEventListenerInternal(
|
GEODE_DLL void addEventListenerInternal(
|
||||||
std::string const& id,
|
std::string const& id,
|
||||||
geode::EventListenerProtocol* protocol
|
geode::EventListenerProtocol* protocol
|
||||||
|
@ -928,38 +940,6 @@ public:
|
||||||
*/
|
*/
|
||||||
GEODE_DLL bool hasAncestor(CCNode* ancestor);
|
GEODE_DLL bool hasAncestor(CCNode* ancestor);
|
||||||
|
|
||||||
#ifndef GEODE_IS_MEMBER_TEST
|
|
||||||
/**
|
|
||||||
* Set an attribute on a node. Attributes are a system added by Geode,
|
|
||||||
* where a node may have any sort of extra data associated with it. Used
|
|
||||||
* for mod intercommunication. For example, a mod that adds scrollbars to
|
|
||||||
* layers might check if the layer has an attribute set for whether the
|
|
||||||
* scrollbar should be disabled. The key of the attribute should be
|
|
||||||
* prefixed with the mod ID, like hjfod.cool-scrollbars/enable.
|
|
||||||
* @param attribute The attribute key. Should be prefixed with the mod ID,
|
|
||||||
* like hjfod.cool-scrollbars/enable
|
|
||||||
* @param value The value of the attribute
|
|
||||||
* @note Geode addition
|
|
||||||
*/
|
|
||||||
GEODE_DLL void setAttribute(std::string const& attribute, matjson::Value const& value);
|
|
||||||
/**
|
|
||||||
* Get an attribute from the node. Attributes may be anything
|
|
||||||
* @param attribute The attribute key
|
|
||||||
* @returns The value, or nullopt if the attribute doesn't exist or if the
|
|
||||||
* type didn't match
|
|
||||||
* @note Geode addition
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
std::optional<T> getAttribute(std::string const& attribute) {
|
|
||||||
if (auto value = this->getAttributeInternal(attribute)) {
|
|
||||||
if (value.value().template is<T>()) {
|
|
||||||
return value.value().template as<T>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Layout for this node. Used to automatically position children,
|
* Set the Layout for this node. Used to automatically position children,
|
||||||
* based on the selected layout. In order to apply the layout after a child
|
* based on the selected layout. In order to apply the layout after a child
|
||||||
|
@ -1834,23 +1814,23 @@ NS_CC_END
|
||||||
|
|
||||||
#ifndef GEODE_IS_MEMBER_TEST
|
#ifndef GEODE_IS_MEMBER_TEST
|
||||||
namespace geode {
|
namespace geode {
|
||||||
struct GEODE_DLL AttributeSetEvent : public Event {
|
struct GEODE_DLL UserObjectSetEvent : public Event {
|
||||||
cocos2d::CCNode* node;
|
cocos2d::CCNode* node;
|
||||||
const std::string id;
|
const std::string id;
|
||||||
matjson::Value& value;
|
cocos2d::CCObject* value;
|
||||||
|
|
||||||
AttributeSetEvent(cocos2d::CCNode* node, std::string const& id, matjson::Value& value);
|
UserObjectSetEvent(cocos2d::CCNode* node, std::string const& id, cocos2d::CCObject* value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GEODE_DLL AttributeSetFilter : public EventFilter<AttributeSetEvent> {
|
class GEODE_DLL AttributeSetFilter : public EventFilter<UserObjectSetEvent> {
|
||||||
public:
|
public:
|
||||||
using Callback = void(AttributeSetEvent*);
|
using Callback = void(UserObjectSetEvent*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string m_targetID;
|
std::string m_targetID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListenerResult handle(utils::MiniFunction<Callback> fn, AttributeSetEvent* event);
|
ListenerResult handle(utils::MiniFunction<Callback> fn, UserObjectSetEvent* event);
|
||||||
|
|
||||||
AttributeSetFilter(std::string const& id);
|
AttributeSetFilter(std::string const& id);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,11 +17,10 @@ struct ProxyCCNode;
|
||||||
class GeodeNodeMetadata final : public cocos2d::CCObject {
|
class GeodeNodeMetadata final : public cocos2d::CCObject {
|
||||||
private:
|
private:
|
||||||
FieldContainer* m_fieldContainer;
|
FieldContainer* m_fieldContainer;
|
||||||
Ref<cocos2d::CCObject> m_userObject;
|
|
||||||
std::string m_id = "";
|
std::string m_id = "";
|
||||||
Ref<Layout> m_layout = nullptr;
|
Ref<Layout> m_layout = nullptr;
|
||||||
Ref<LayoutOptions> m_layoutOptions = nullptr;
|
Ref<LayoutOptions> m_layoutOptions = nullptr;
|
||||||
std::unordered_map<std::string, matjson::Value> m_attributes;
|
std::unordered_map<std::string, Ref<CCObject>> m_userObjects;
|
||||||
std::unordered_set<std::unique_ptr<EventListenerProtocol>> m_eventListeners;
|
std::unordered_set<std::unique_ptr<EventListenerProtocol>> m_eventListeners;
|
||||||
std::unordered_map<std::string, std::unique_ptr<EventListenerProtocol>> m_idEventListeners;
|
std::unordered_map<std::string, std::unique_ptr<EventListenerProtocol>> m_idEventListeners;
|
||||||
|
|
||||||
|
@ -53,8 +52,8 @@ public:
|
||||||
meta->retain();
|
meta->retain();
|
||||||
|
|
||||||
if (old) {
|
if (old) {
|
||||||
meta->m_userObject = old;
|
meta->m_userObjects.insert({ "", old });
|
||||||
// the old user object has been retained by CCNode
|
// the old user object is now managed by Ref
|
||||||
old->release();
|
old->release();
|
||||||
}
|
}
|
||||||
return meta;
|
return meta;
|
||||||
|
@ -69,18 +68,24 @@ public:
|
||||||
#include <Geode/modify/CCNode.hpp>
|
#include <Geode/modify/CCNode.hpp>
|
||||||
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
|
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
|
||||||
virtual CCObject* getUserObject() {
|
virtual CCObject* getUserObject() {
|
||||||
if (typeinfo_cast<CCNode*>(this)) {
|
if (auto asNode = typeinfo_cast<CCNode*>(this)) {
|
||||||
return GeodeNodeMetadata::set(this)->m_userObject;
|
return asNode->getUserObject("");
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// apparently this function is the same as
|
// apparently this function is the same as
|
||||||
// CCDirector::getNextScene so yeah
|
// CCDirector::getNextScene so yeah
|
||||||
return m_pUserObject;
|
return m_pUserObject;
|
||||||
}
|
}
|
||||||
virtual void setUserObject(CCObject* obj) {
|
|
||||||
if (typeinfo_cast<CCNode*>(this)) {
|
|
||||||
GeodeNodeMetadata::set(this)->m_userObject = obj;
|
|
||||||
}
|
}
|
||||||
|
virtual void setUserObject(CCObject* obj) {
|
||||||
|
if (auto asNode = typeinfo_cast<CCNode*>(this)) {
|
||||||
|
asNode->setUserObject("", obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CC_SAFE_RELEASE(m_pUserObject);
|
||||||
m_pUserObject = obj;
|
m_pUserObject = obj;
|
||||||
|
CC_SAFE_RETAIN(m_pUserObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,10 +171,10 @@ void CCNode::updateLayout(bool updateChildOrder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeSetEvent::AttributeSetEvent(CCNode* node, std::string const& id, matjson::Value& value)
|
UserObjectSetEvent::UserObjectSetEvent(CCNode* node, std::string const& id, CCObject* value)
|
||||||
: node(node), id(id), value(value) {}
|
: node(node), id(id), value(value) {}
|
||||||
|
|
||||||
ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, AttributeSetEvent* event) {
|
ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, UserObjectSetEvent* event) {
|
||||||
if (event->id == m_targetID) {
|
if (event->id == m_targetID) {
|
||||||
fn(event);
|
fn(event);
|
||||||
}
|
}
|
||||||
|
@ -178,18 +183,23 @@ ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, AttributeSe
|
||||||
|
|
||||||
AttributeSetFilter::AttributeSetFilter(std::string const& id) : m_targetID(id) {}
|
AttributeSetFilter::AttributeSetFilter(std::string const& id) : m_targetID(id) {}
|
||||||
|
|
||||||
void CCNode::setAttribute(std::string const& attr, matjson::Value const& value) {
|
void CCNode::setUserObject(std::string const& id, CCObject* value) {
|
||||||
auto meta = GeodeNodeMetadata::set(this);
|
auto meta = GeodeNodeMetadata::set(this);
|
||||||
meta->m_attributes[attr] = value;
|
if (value) {
|
||||||
AttributeSetEvent(this, attr, meta->m_attributes.at(attr)).post();
|
meta->m_userObjects[id] = value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
meta->m_userObjects.erase(id);
|
||||||
|
}
|
||||||
|
UserObjectSetEvent(this, id, value).post();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<matjson::Value> CCNode::getAttributeInternal(std::string const& attr) {
|
CCObject* CCNode::getUserObject(std::string const& id) {
|
||||||
auto meta = GeodeNodeMetadata::set(this);
|
auto meta = GeodeNodeMetadata::set(this);
|
||||||
if (meta->m_attributes.count(attr)) {
|
if (meta->m_userObjects.count(id)) {
|
||||||
return meta->m_attributes.at(attr);
|
return meta->m_userObjects.at(id);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) {
|
void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ bool InputNode::init(
|
||||||
m_input->setMaxLabelScale(.85f);
|
m_input->setMaxLabelScale(.85f);
|
||||||
m_input->setMaxLabelLength(maxCharCount);
|
m_input->setMaxLabelLength(maxCharCount);
|
||||||
m_input->setPosition(width / 2, height / 2);
|
m_input->setPosition(width / 2, height / 2);
|
||||||
m_input->setAttribute("fix-text-input", true);
|
m_input->setUserObject("fix-text-input", CCBool::create(true));
|
||||||
if (filter.length()) {
|
if (filter.length()) {
|
||||||
m_input->setAllowedChars(filter);
|
m_input->setAllowedChars(filter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct TextInputNodeFix : Modify<TextInputNodeFix, CCTextInputNode> {
|
||||||
GEODE_FORWARD_COMPAT_DISABLE_HOOKS("TextInputNode fix")
|
GEODE_FORWARD_COMPAT_DISABLE_HOOKS("TextInputNode fix")
|
||||||
|
|
||||||
bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) {
|
bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) {
|
||||||
if (!this->template getAttribute<bool>("fix-text-input").value_or(false)) {
|
if (!this->getUserObject("fix-text-input")) {
|
||||||
return CCTextInputNode::ccTouchBegan(touch, event);
|
return CCTextInputNode::ccTouchBegan(touch, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ bool TextInput::init(float width, std::string const& placeholder, std::string co
|
||||||
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
|
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
|
||||||
m_input->setLabelPlaceholderScale(.6f);
|
m_input->setLabelPlaceholderScale(.6f);
|
||||||
m_input->setMaxLabelScale(.6f);
|
m_input->setMaxLabelScale(.6f);
|
||||||
m_input->setAttribute("fix-text-input", true);
|
m_input->setUserObject("fix-text-input", CCBool::create(true));
|
||||||
this->addChildAtPosition(m_input, cocos2d::Anchor::Center);
|
this->addChildAtPosition(m_input, cocos2d::Anchor::Center);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue