diff --git a/src/PyColor.cpp b/src/PyColor.cpp index 651fbd6..9d001df 100644 --- a/src/PyColor.cpp +++ b/src/PyColor.cpp @@ -8,11 +8,19 @@ PyGetSetDef PyColor::getsetters[] = { {NULL} }; +PyColor::PyColor(_PyColorData d) +{ + data = d; + if (data.index == PyColor::SELF_OWNED) data.index = PyColor::BORROWED; // I think this is a bad idea, but the alternatives come with their own mess +} + PyColor::PyColor(sf::Color* target, std::weak_ptr parent, int index) { data.index = index; data.parent = parent; data.target = target; + data.setter = NULL; + data.getter = NULL; } PyColor::PyColor(sf::Color target) @@ -20,6 +28,18 @@ PyColor::PyColor(sf::Color target) data.index = PyColor::SELF_OWNED; data.parent = std::weak_ptr(); data.target = new sf::Color; + data.setter = NULL; + data.getter = NULL; +} + +PyColor::PyColor(sf::Color (*getter)(), void (*setter)(sf::Color), std::weak_ptr parent, int index) +{ + data.index = index; + data.parent = parent; + data.target = NULL; + data.setter = setter; + data.getter = getter; + } PyColor::~PyColor() @@ -31,32 +51,123 @@ PyColor::~PyColor() PyObject* PyColor::pyObject() { PyObject* obj = PyType_GenericAlloc(&mcrfpydef::PyColorType, 0); - ((PyColorObject*)obj->data = data; + PyColorObject* self = (PyColorObject*)obj; + self->data = data; + if (data.index == PyColor::SELF_OWNED) self->data.index = PyColor::BORROWED; return obj; } +PyColor PyColor::fromPy(PyObject* obj) +{ + PyColorObject* self = (PyColorObject*)obj; + return PyColor(self->data); +} + +PyColor PyColor::fromPy(PyColorObject* self) +{ + return PyColor(self->data); +} + +void PyColor::set(sf::Color color) +{ + auto ptr = data.parent.lock(); + if (ptr || data.index == PyColor::SELF_OWNED) + { + if (data.setter) + data.setter(color); + else + *data.target = color; + } +} + +sf::Color PyColor::get() +{ + auto ptr = data.parent.lock(); + if (ptr || data.index == PyColor::SELF_OWNED) + { + if (data.getter) + return data.getter(); + else + return *(data.target); + } + return sf::Color(0, 0, 0, 0); +} + +bool PyColor::alive() +{ + if (data.index == PyColor::SELF_OWNED) return true; + return !data.parent.lock(); +} + +std::string PyColor::field() +{ + switch (data.index) + { + case PyColor::SELF_OWNED: + return "None"; + break; + case 0: + return "fill"; + break; + case 1: + return "outline"; + break; + case 2: + return "background"; + break; + default: + return "unknown"; + break; + } +} + +std::string PyColor::mode() +{ + if (data.index == PyColor::SELF_OWNED) return "self-owned value"; + else if (data.index == PyColor::BORROWED) return "self-owned value (borrowed)"; + else if (data.getter || data.setter) + { + if (alive()) return "callback passthrough"; + else return "callback passthrough (dangling; parent dead)"; + } + else if (alive()) return "linked pointer"; + else return "linked pointer (dangling; parent dead)"; +} + Py_hash_t PyColor::hash(PyObject* obj) { auto self = (PyColorObject*)obj; Py_hash_t value = 0; - auto ptr = self.data.parent.lock(); + auto ptr = self->data.parent.lock(); if (ptr || self->data.index == PyColor::SELF_OWNED) { - value += self->data.target.r; - value << 8; value += self->data.target.g; - value << 8; value += self->data.target.b; - value << 8; value += self->data.target.a; + value += self->data.target->r; + value << 8; value += self->data.target->g; + value << 8; value += self->data.target->b; + value << 8; value += self->data.target->a; } if (ptr) { - - value << (sizeof(*UIDrawable) * 8); - value += reinterpret_cast(ptr); + //value << (sizeof(*UIDrawable) * 8); + value += reinterpret_cast(&ptr); } return value; } +PyObject* PyColor::repr(PyObject* obj) +{ + PyColorObject* self = (PyColorObject*)obj; + std::ostringstream ss; + PyColor color = PyColor(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 PyColor::init(PyColorObject* self, PyObject* args, PyObject* kwds) { static const char* keywords[] = { "r", "g", "b", "a", nullptr }; @@ -67,3 +178,13 @@ PyObject* PyColor::pynew(PyTypeObject* type, PyObject* args, PyObject* kwds) { return (PyObject*)type->tp_alloc(type, 0); } + +PyObject* PyColor::get_member(PyObject* obj, void* closure) +{ + return Py_None; +} + +int PyColor::set_member(PyObject* obj, PyObject* value, void* closure) +{ + return 0; +} diff --git a/src/PyColor.h b/src/PyColor.h index 28a40f3..6d0d35a 100644 --- a/src/PyColor.h +++ b/src/PyColor.h @@ -9,6 +9,8 @@ typedef struct { sf::Color* target; // color target to set/get 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); } _PyColorData; typedef struct { @@ -21,16 +23,27 @@ class PyColor private: _PyColorData data; static const int SELF_OWNED = -1; + static const int BORROWED = -2; + PyColor(_PyColorData); // private constructor / for operations transferring between C++ and Python + public: PyColor(sf::Color* target, std::weak_ptr parent, int index); // linked constructor PyColor(sf::Color target); // simple color container - void set(sf::Color); - sf::Color get(); + PyColor(sf::Color (*)(), void (*)(sf::Color), std::weak_ptr, int); + ~PyColor(); + 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 + std::string mode(); // "value" for SELF_OWNED, "linked" for pointer, and "passthrough" for callbacks + bool alive(); // true if SELF_OWNED or parent still exists PyObject* pyObject(); + static PyColor fromPy(PyObject*); + static PyColor fromPy(PyColorObject*); + static PyObject* repr(PyObject*); static Py_hash_t hash(PyObject*); static int init(PyColorObject*, 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*); @@ -81,6 +94,7 @@ namespace mcrfpydef { .tp_name = "mcrfpy.Color", .tp_basicsize = sizeof(PyColorObject), .tp_itemsize = 0, + .tp_repr = PyColor::repr, .tp_hash = PyColor::hash, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = PyDoc_STR("SFML Color Object"), diff --git a/src/UI.h b/src/UI.h index 70a28f0..39d3e8b 100644 --- a/src/UI.h +++ b/src/UI.h @@ -617,7 +617,8 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c } // initialize new mcrfpy.Color instance - pyColorObj->data = std::make_shared(color); + //pyColorObj->data = std::make_shared(color); + PyColor::fromPy(pyColorObj).set(color); return pyColor; } @@ -630,11 +631,15 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c if (PyObject_IsInstance(value, (PyObject*)&PyColorType)) { // get value from mcrfpy.Color instance + /* PyColorObject* color = reinterpret_cast(value); r = color->data->r; g = color->data->g; b = color->data->b; a = color->data->a; + */ + sf::Color c = PyColor::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) { @@ -901,7 +906,8 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c } // initialize new mcrfpy.Color instance - pyColorObj->data = std::make_shared(color); + //pyColorObj->data = std::make_shared(color); + PyColor::fromPy(pyColorObj).set(color); return pyColor; } @@ -914,12 +920,16 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c if (PyObject_IsInstance(value, (PyObject*)&PyColorType)) { // get value from mcrfpy.Color instance + /* PyColorObject* color = reinterpret_cast(value); r = color->data->r; g = color->data->g; b = color->data->b; a = color->data->a; std::cout << "using color: " << r << " " << g << " " << b << " " << a << std::endl; + */ + sf::Color c = PyColor::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) {