From 41509dfe9640a67f924c5f843fe6bceb0cdb8f78 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Wed, 27 Mar 2024 21:10:03 -0400 Subject: [PATCH] Addressing issues with PyColor by splitting behavior off into PyLinkedColor --- src/PyLinkedColor.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++ src/PyLinkedColor.h | 58 +++++++++++++++++ src/UI.h | 34 ++++++---- 3 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 src/PyLinkedColor.cpp create mode 100644 src/PyLinkedColor.h diff --git a/src/PyLinkedColor.cpp b/src/PyLinkedColor.cpp new file mode 100644 index 0000000..f349816 --- /dev/null +++ b/src/PyLinkedColor.cpp @@ -0,0 +1,144 @@ +#include "PyLinkedColor.h" + +PyGetSetDef PyLinkedColor::getsetters[] = { + {"r", (getter)PyLinkedColor::get_member, (setter)PyLinkedColor::set_member, "Red component", (void*)0}, + {"g", (getter)PyLinkedColor::get_member, (setter)PyLinkedColor::set_member, "Green component", (void*)1}, + {"b", (getter)PyLinkedColor::get_member, (setter)PyLinkedColor::set_member, "Blue component", (void*)2}, + {"a", (getter)PyLinkedColor::get_member, (setter)PyLinkedColor::set_member, "Alpha component", (void*)3}, + {NULL} +}; + +PyLinkedColor::PyLinkedColor(_PyLinkedColorData d) +{ + data = d; +} + +PyLinkedColor::PyLinkedColor(sf::Color (*getter)(), void (*setter)(sf::Color), std::weak_ptr parent, int index) +{ + data.index = index; + data.parent = parent; + data.setter = setter; + data.getter = getter; +} + +PyObject* PyLinkedColor::pyObject() +{ + PyObject* obj = PyType_GenericAlloc(&mcrfpydef::PyLinkedColorType, 0); + PyLinkedColorObject* self = (PyLinkedColorObject*)obj; + self->data = data; + return obj; +} + +PyLinkedColor PyLinkedColor::fromPy(PyObject* obj) +{ + PyLinkedColorObject* self = (PyLinkedColorObject*)obj; + return PyLinkedColor(self->data); +} + +PyLinkedColor PyLinkedColor::fromPy(PyLinkedColorObject* self) +{ + return PyLinkedColor(self->data); +} + +void PyLinkedColor::set(sf::Color color) +{ + auto ptr = data.parent.lock(); + if (ptr) + { + if (data.setter) + data.setter(color); + } +} + +sf::Color PyLinkedColor::get() +{ + auto ptr = data.parent.lock(); + if (ptr) + { + if (data.getter) + return data.getter(); + } + return sf::Color(0, 0, 0, 0); +} + +bool PyLinkedColor::alive() +{ + return !data.parent.lock(); +} + +std::string PyLinkedColor::field() +{ + switch (data.index) + { + case 0: + return "fill"; + break; + case 1: + return "outline"; + break; + case 2: + return "background"; + break; + default: + return "unknown"; + break; + } +} + +Py_hash_t PyLinkedColor::hash(PyObject* obj) +{ + auto self = (PyLinkedColorObject*)obj; + Py_hash_t value = 0; + auto ptr = self->data.parent.lock(); + if (ptr) + { + auto color = PyLinkedColor(self->data); + auto c = linkedcolor.get(); + value += c.r; + value << 8; value += c.g; + value << 8; value += c.b; + value << 8; value += c.a; + } + if (ptr) + { + //value << (sizeof(*UIDrawable) * 8); + value += reinterpret_cast(&ptr); + } + + return value; +} + +PyObject* PyLinkedColor::repr(PyObject* obj) +{ + PyLinkedColorObject* self = (PyLinkedColorObject*)obj; + std::ostringstream ss; + PyLinkedColor color = PyLinkedColor(self->data); + sf::Color c = color.get(); + ss << ""; + + std::string repr_str = ss.str(); + return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); +} + + +int PyLinkedColor::init(PyLinkedColorObject* self, PyObject* args, PyObject* kwds) +{ + // TODO + static const char* keywords[] = { "r", "g", "b", "a", nullptr }; + return 0; +} + +PyObject* PyLinkedColor::pynew(PyTypeObject* type, PyObject* args, PyObject* kwds) +{ + return (PyObject*)type->tp_alloc(type, 0); +} + +PyObject* PyLinkedColor::get_member(PyObject* obj, void* closure) +{ + return Py_None; // TODO +} + +int PyLinkedColor::set_member(PyObject* obj, PyObject* value, void* closure) +{ + return 0; // TODO +} diff --git a/src/PyLinkedColor.h b/src/PyLinkedColor.h new file mode 100644 index 0000000..8b0d498 --- /dev/null +++ b/src/PyLinkedColor.h @@ -0,0 +1,58 @@ +#pragma once +#include "Common.h" +#include "Python.h" + +class PyLinkedColor; +class UIDrawable; // forward declare for pointer + +typedef struct { + std::weak_ptr parent; // lifetime management: parent must still exist + int index; // specific to the parent class, which color is it? + sf::Color(*getter)(); + void(*setter)(sf::Color); +} _PyLinkedColorData; + +typedef struct { + PyObject_HEAD + _PyLinkedColorData data; +} PyLinkedColorObject; + +class PyLinkedColor +{ +private: + _PyLinkedColorData data; + PyColor(_PyColorData); // private constructor / for operations transferring between C++ and Python + +public: + PyLinkedColor(sf::Color (*)(), void (*)(sf::Color), std::weak_ptr, int); + void set(sf::Color); // change target value, behavior determined by the mode + sf::Color get(); // retrieve target value, behavior determined by the mode + PyObject* pyParent(); // UIDrawable derived parent object or None + std::string field(); // interpret the index as a field's name on UIDrawable + bool alive(); // true if SELF_OWNED or parent still exists + PyObject* pyObject(); + static PyLinkedColor fromPy(PyObject*); + static PyLinkedColor fromPy(PyLinkedColorObject*); + static PyObject* repr(PyObject*); + static Py_hash_t hash(PyObject*); + static int init(PyLinkedColorObject*, PyObject*, PyObject*); + static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL); + static PyObject* get_member(PyObject*, void*); + static int set_member(PyObject*, PyObject*, void*); + static PyGetSetDef getsetters[]; +}; + +namespace mcrfpydef { + static PyTypeObject PyLinkedColorType = { + .tp_name = "mcrfpy.LinkedColor", + .tp_basicsize = sizeof(PyLinkedColorObject), + .tp_itemsize = 0, + .tp_repr = PyLinkedColor::repr, + .tp_hash = PyLinkedColor::hash, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = PyDoc_STR("SFML Color Object - Linked to UIDrawable Field"), + .tp_getset = PyLinkedColor::getsetters, + .tp_init = (initproc)PyLinkedColor::init, + .tp_new = PyLinkedColor::pynew, + }; +} diff --git a/src/UI.h b/src/UI.h index 39d3e8b..aa0b335 100644 --- a/src/UI.h +++ b/src/UI.h @@ -8,6 +8,7 @@ #include "PyCallable.h" #include "PyTexture.h" #include "PyColor.h" +#include "PyLinkedColor.h" enum PyObjectsEnum : int { @@ -594,33 +595,44 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c } // TODO: manually calling tp_alloc to create a PyColorObject seems like an antipattern - PyTypeObject* colorType = &PyColorType; - PyObject* pyColor = colorType->tp_alloc(colorType, 0); + /* + PyTypeObject* colorType = &PyLinkedColorType; + PyObject* pyColor = colorType->tp_alloc(colorLinkedType, 0); if (pyColor == NULL) { - std::cout << "failure to allocate mcrfpy.Color / PyColorType" << std::endl; + std::cout << "failure to allocate mcrfpy.LinkedColor / PyLinkedColorType" << std::endl; return NULL; } - PyColorObject* pyColorObj = reinterpret_cast(pyColor); + PyColorObject* pyColorObj = reinterpret_cast(pyColor); + */ // fetch correct member data - sf::Color color; + //sf::Color color; + sf::Color (*cgetter)(); + void (*csetter)(sf::Color); if (member_ptr == 0) { - color = self->data->text.getFillColor(); + //color = self->data->text.getFillColor(); //return Py_BuildValue("(iii)", color.r, color.g, color.b); + csetter = &self->data->text.setFillColor; + cgetter = &self->data->text.getFillColor; } else if (member_ptr == 1) { - color = self->data->text.getOutlineColor(); + //color = self->data->text.getOutlineColor(); //return Py_BuildValue("(iii)", color.r, color.g, color.b); + csetter = &self->data->text.setOutlineColor; + cgetter = &self->data->text.getOutlineColor; } // initialize new mcrfpy.Color instance //pyColorObj->data = std::make_shared(color); - PyColor::fromPy(pyColorObj).set(color); + //PyLinkedColor::fromPy(pyColorObj).set(color); + auto linkedcolor = PyLinkedColor(getter, setter, self->data, member_ptr); + //linkedcolor.set(color); // don't need to set a linked color! - return pyColor; + //return pyColor; + return linkedcolor.pyObject(); } static int PyUICaption_set_color_member(PyUICaptionObject* self, PyObject* value, void* closure) @@ -628,7 +640,7 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c auto member_ptr = reinterpret_cast(closure); //TODO: this logic of (PyColor instance OR tuple -> sf::color) should be encapsulated for reuse int r, g, b, a; - if (PyObject_IsInstance(value, (PyObject*)&PyColorType)) + if (PyObject_IsInstance(value, (PyObject*)&PyLinkedColorType)) { // get value from mcrfpy.Color instance /* @@ -638,7 +650,7 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c b = color->data->b; a = color->data->a; */ - sf::Color c = PyColor::fromPy(value).get(); + sf::Color c = PyLinkedColor::fromPy(value).get(); r = c.r; g = c.g; b = c.b; a = c.a; } else if (!PyTuple_Check(value) || PyTuple_Size(value) < 3 || PyTuple_Size(value) > 4)