mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -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.
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
|
||||
private:
|
||||
friend class geode::modifier::FieldContainer;
|
||||
|
||||
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(
|
||||
std::string const& id,
|
||||
geode::EventListenerProtocol* protocol
|
||||
|
@ -928,38 +940,6 @@ public:
|
|||
*/
|
||||
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,
|
||||
* 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
|
||||
namespace geode {
|
||||
struct GEODE_DLL AttributeSetEvent : public Event {
|
||||
struct GEODE_DLL UserObjectSetEvent : public Event {
|
||||
cocos2d::CCNode* node;
|
||||
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:
|
||||
using Callback = void(AttributeSetEvent*);
|
||||
using Callback = void(UserObjectSetEvent*);
|
||||
|
||||
protected:
|
||||
std::string m_targetID;
|
||||
|
||||
public:
|
||||
ListenerResult handle(utils::MiniFunction<Callback> fn, AttributeSetEvent* event);
|
||||
ListenerResult handle(utils::MiniFunction<Callback> fn, UserObjectSetEvent* event);
|
||||
|
||||
AttributeSetFilter(std::string const& id);
|
||||
};
|
||||
|
|
|
@ -17,11 +17,10 @@ struct ProxyCCNode;
|
|||
class GeodeNodeMetadata final : public cocos2d::CCObject {
|
||||
private:
|
||||
FieldContainer* m_fieldContainer;
|
||||
Ref<cocos2d::CCObject> m_userObject;
|
||||
std::string m_id = "";
|
||||
Ref<Layout> m_layout = 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_map<std::string, std::unique_ptr<EventListenerProtocol>> m_idEventListeners;
|
||||
|
||||
|
@ -53,8 +52,8 @@ public:
|
|||
meta->retain();
|
||||
|
||||
if (old) {
|
||||
meta->m_userObject = old;
|
||||
// the old user object has been retained by CCNode
|
||||
meta->m_userObjects.insert({ "", old });
|
||||
// the old user object is now managed by Ref
|
||||
old->release();
|
||||
}
|
||||
return meta;
|
||||
|
@ -69,18 +68,24 @@ public:
|
|||
#include <Geode/modify/CCNode.hpp>
|
||||
struct ProxyCCNode : Modify<ProxyCCNode, CCNode> {
|
||||
virtual CCObject* getUserObject() {
|
||||
if (typeinfo_cast<CCNode*>(this)) {
|
||||
return GeodeNodeMetadata::set(this)->m_userObject;
|
||||
if (auto asNode = typeinfo_cast<CCNode*>(this)) {
|
||||
return asNode->getUserObject("");
|
||||
}
|
||||
else {
|
||||
// apparently this function is the same as
|
||||
// CCDirector::getNextScene so yeah
|
||||
return m_pUserObject;
|
||||
}
|
||||
// apparently this function is the same as
|
||||
// CCDirector::getNextScene so yeah
|
||||
return m_pUserObject;
|
||||
}
|
||||
virtual void setUserObject(CCObject* obj) {
|
||||
if (typeinfo_cast<CCNode*>(this)) {
|
||||
GeodeNodeMetadata::set(this)->m_userObject = obj;
|
||||
if (auto asNode = typeinfo_cast<CCNode*>(this)) {
|
||||
asNode->setUserObject("", obj);
|
||||
}
|
||||
else {
|
||||
CC_SAFE_RELEASE(m_pUserObject);
|
||||
m_pUserObject = obj;
|
||||
CC_SAFE_RETAIN(m_pUserObject);
|
||||
}
|
||||
m_pUserObject = obj;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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) {}
|
||||
|
||||
ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, AttributeSetEvent* event) {
|
||||
ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, UserObjectSetEvent* event) {
|
||||
if (event->id == m_targetID) {
|
||||
fn(event);
|
||||
}
|
||||
|
@ -178,18 +183,23 @@ ListenerResult AttributeSetFilter::handle(MiniFunction<Callback> fn, AttributeSe
|
|||
|
||||
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);
|
||||
meta->m_attributes[attr] = value;
|
||||
AttributeSetEvent(this, attr, meta->m_attributes.at(attr)).post();
|
||||
if (value) {
|
||||
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);
|
||||
if (meta->m_attributes.count(attr)) {
|
||||
return meta->m_attributes.at(attr);
|
||||
if (meta->m_userObjects.count(id)) {
|
||||
return meta->m_userObjects.at(id);
|
||||
}
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CCNode::addEventListenerInternal(std::string const& id, EventListenerProtocol* listener) {
|
||||
|
|
|
@ -56,7 +56,7 @@ bool InputNode::init(
|
|||
m_input->setMaxLabelScale(.85f);
|
||||
m_input->setMaxLabelLength(maxCharCount);
|
||||
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()) {
|
||||
m_input->setAllowedChars(filter);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ struct TextInputNodeFix : Modify<TextInputNodeFix, CCTextInputNode> {
|
|||
GEODE_FORWARD_COMPAT_DISABLE_HOOKS("TextInputNode fix")
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool TextInput::init(float width, std::string const& placeholder, std::string co
|
|||
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
|
||||
m_input->setLabelPlaceholderScale(.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);
|
||||
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue