From c186d8c7f301f216f46ea52c92d60d15615c45ff Mon Sep 17 00:00:00 2001 From: John McCardle Date: Wed, 10 Apr 2024 23:10:15 -0400 Subject: [PATCH] We are compiling again! Started refactoring UICaption to be more idiomatic --- src/UI.h | 2457 -------------------------------------------- src/UICaption.cpp | 235 +++++ src/UICaption.h | 48 +- src/UIDrawable.cpp | 5 +- src/UIEntity.cpp | 7 +- src/UIEntity.h | 2 + src/UIFrame.cpp | 5 +- src/UIGrid.cpp | 10 + src/UIGridPoint.h | 1 + src/UISprite.cpp | 1 + src/UISprite.h | 1 + 11 files changed, 298 insertions(+), 2474 deletions(-) diff --git a/src/UI.h b/src/UI.h index 73dd5bc..61e4576 100644 --- a/src/UI.h +++ b/src/UI.h @@ -6,12 +6,9 @@ #include "Resources.h" #include -#define ui_h - #include "PyCallable.h" #include "PyTexture.h" #include "PyColor.h" -//#include "PyLinkedColor.h" #include "PyVector.h" #include "PyFont.h" @@ -24,2457 +21,3 @@ #include "UIEntity.h" #include "UIGrid.h" #include "UICollection.h" - -// -//class UIFrame: public UIDrawable -//{ -//public: -// UIFrame(float, float, float, float); -// UIFrame(); -// ~UIFrame(); -// sf::RectangleShape box; -// // todone: why does UIFrame have x,y,w,h AND a box? Which one should be used for bounds checks? (floats removed) -// -// //Simulate RectangleShape -// //float x, y, w, h, -// float outline; -// std::shared_ptr>> children; -// void render(sf::Vector2f) override final; -// void move(sf::Vector2f); -// -// PyObjectsEnum derived_type() override final; // { return PyObjectsEnum::UIFrame; }; -// virtual UIDrawable* click_at(sf::Vector2f point) override final; -// /* -// sf::Color fillColor(); // getter -// void fillColor(sf::Color c); // C++ setter -// void fillColor(PyColorObject* pyColor); // Python setter -// -// sf::Color outlineColor(); // getter -// void outlineColor(sf::Color c); // C++ setter -// void outlineColor(PyColorObject* pyColor); // Python setter -// */ -// -//private: -// //std::shared_ptr fillColor, outlineColor; -// /* -// sf::Color *_fillColor, *_outlineColor; -// PyColorObject *pyFillColor, *pyOutlineColor; -// */ -//}; -// -//class UICaption: public UIDrawable -//{ -//public: -// sf::Text text; -// void render(sf::Vector2f) override final; -// PyObjectsEnum derived_type() override final; // { return PyObjectsEnum::UICaption; }; -// virtual UIDrawable* click_at(sf::Vector2f point) override final; -//}; -// -//class UISprite: public UIDrawable -//{ -//private: -// int sprite_index; -// sf::Sprite sprite; -//protected: -// std::shared_ptr ptex; -//public: -// UISprite(); -// //UISprite(IndexTexture*, int, float, float, float); -// //UISprite(IndexTexture*, int, sf::Vector2f, float); -// UISprite(std::shared_ptr, int, sf::Vector2f, float); -// void update(); -// void render(sf::Vector2f) override final; -// virtual UIDrawable* click_at(sf::Vector2f point) override final; -// -// // 7DRL hack - TODO apply RenderTexture concept to all UIDrawables (via `sf::RenderTarget`) -// void render(sf::Vector2f, sf::RenderTexture&); -// //IndexTexture* itex; -// //sf::Vector2f pos; -// //float scale; -// //void setPosition(float, float); -// void setPosition(sf::Vector2f); -// sf::Vector2f getPosition(); -// void setScale(sf::Vector2f); -// sf::Vector2f getScale(); -// void setSpriteIndex(int); -// int getSpriteIndex(); -// -// void setTexture(std::shared_ptr _ptex, int _sprite_index=-1); -// std::shared_ptr getTexture(); -// -// PyObjectsEnum derived_type() override final; // { return PyObjectsEnum::UISprite; }; -//}; -// -// UIGridPoint - revised grid data for each point -//class UIGridPoint -//{ -//public: -// sf::Color color, color_overlay; -// bool walkable, transparent; -// int tilesprite, tile_overlay, uisprite; -// UIGridPoint(); -//}; -// -// UIGridPointState - entity-specific info for each cell -//class UIGridPointState -//{ -//public: -// bool visible, discovered; -//}; -// -//class UIGrid; -// -// TODO: make UIEntity a drawable(?) Maybe just rely on UISprite/UIGrid to -// somehow properly render the thing? Poorly designed interface -//class UIEntity//: public UIDrawable -//{ -//public: -// //PyObject* self; -// std::shared_ptr grid; -// std::vector gridstate; -// UISprite sprite; -// sf::Vector2f position; //(x,y) in grid coordinates; float for animation -// void render(sf::Vector2f); //override final; -// -// UIEntity(); -// UIEntity(UIGrid&); -// -//}; -// -//class UIGrid: public UIDrawable -//{ -//private: -// std::shared_ptr ptex; -//public: -// UIGrid(); -// //UIGrid(int, int, IndexTexture*, float, float, float, float); -// UIGrid(int, int, std::shared_ptr, sf::Vector2f, sf::Vector2f); -// void update(); -// void render(sf::Vector2f) override final; -// UIGridPoint& at(int, int); -// PyObjectsEnum derived_type() override final; -// //void setSprite(int); -// virtual UIDrawable* click_at(sf::Vector2f point) override final; -// -// int grid_x, grid_y; -// //int grid_size; // grid sizes are implied by IndexTexture now -// sf::RectangleShape box; -// float center_x, center_y, zoom; -// //IndexTexture* itex; -// std::shared_ptr getTexture(); -// sf::Sprite sprite, output; -// sf::RenderTexture renderTexture; -// std::vector points; -// std::shared_ptr>> entities; -//}; -// -///* -//template -//struct CPythonSharedObject { -// PyObject_HEAD -// std::shared_ptr data; -//}; -// -//typedef CPythonSharedObject PyUIFrameObject; -//*/ -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -//} PyUIFrameObject; -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// PyObject* font; -//} PyUICaptionObject; -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// //PyObject* texture; -//} PyUISpriteObject; -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr>> data; -//} PyUICollectionObject; -// -//typedef struct { -// PyObject_HEAD -// UIGridPoint* data; -// std::shared_ptr grid; -//} PyUIGridPointObject; -// -//typedef struct { -// PyObject_HEAD -// UIGridPointState* data; -// std::shared_ptr grid; -// std::shared_ptr entity; -//} PyUIGridPointStateObject; -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// //PyObject* texture; -//} PyUIEntityObject; -// -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// //PyObject* texture; -//} PyUIGridObject; -// -//namespace mcrfpydef { -// //PyObject* py_instance(std::shared_ptr source); -// // This function segfaults on tp_alloc for an unknown reason, but works inline with mcrfpydef:: methods. -// -//#define RET_PY_INSTANCE(target) { \ -//switch (target->derived_type()) \ -//{ \ -// case PyObjectsEnum::UIFRAME: \ -// { \ -// PyUIFrameObject* o = (PyUIFrameObject*)((&PyUIFrameType)->tp_alloc(&PyUIFrameType, 0)); \ -// if (o) \ -// { \ -// auto p = std::static_pointer_cast(target); \ -// o->data = p; \ -// auto utarget = o->data; \ -// } \ -// return (PyObject*)o; \ -// } \ -// case PyObjectsEnum::UICAPTION: \ -// { \ -// PyUICaptionObject* o = (PyUICaptionObject*)((&PyUICaptionType)->tp_alloc(&PyUICaptionType, 0)); \ -// if (o) \ -// { \ -// auto p = std::static_pointer_cast(target); \ -// o->data = p; \ -// auto utarget = o->data; \ -// } \ -// return (PyObject*)o; \ -// } \ -// case PyObjectsEnum::UISPRITE: \ -// { \ -// PyUISpriteObject* o = (PyUISpriteObject*)((&PyUISpriteType)->tp_alloc(&PyUISpriteType, 0)); \ -// if (o) \ -// { \ -// auto p = std::static_pointer_cast(target); \ -// o->data = p; \ -// auto utarget = o->data; \ -// } \ -// return (PyObject*)o; \ -// } \ -// case PyObjectsEnum::UIGRID: \ -// { \ -// PyUIGridObject* o = (PyUIGridObject*)((&PyUIGridType)->tp_alloc(&PyUIGridType, 0)); \ -// if (o) \ -// { \ -// auto p = std::static_pointer_cast(target); \ -// o->data = p; \ -// auto utarget = o->data; \ -// } \ -// return (PyObject*)o; \ -// } \ -//} \ -//} -// end macro definition -// -// // Color Definitions -// // struct, members, new, set_member, PyTypeObject -// -// /* for reference: the structs to implement -// typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// } PyColorObject; -// -// typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// } PyUIFrameObject; -// -// typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// } PyUICaptionObject; -// -// typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// } PyUISpriteObject; -// */ -// -// -// Clickable / Callable Object Assignment -// -//static PyObject* PyUIDrawable_get_click(PyUIGridObject* self, void* closure) { -// PyObjectsEnum objtype = static_cast(reinterpret_cast(closure)); // trust me bro, it's an Enum -// PyObject* ptr; -// -// switch (objtype) -// { -// case PyObjectsEnum::UIFRAME: -// ptr = ((PyUIFrameObject*)self)->data->click_callable->borrow(); -// break; -// case PyObjectsEnum::UICAPTION: -// ptr = ((PyUICaptionObject*)self)->data->click_callable->borrow(); -// break; -// case PyObjectsEnum::UISPRITE: -// ptr = ((PyUISpriteObject*)self)->data->click_callable->borrow(); -// break; -// case PyObjectsEnum::UIGRID: -// ptr = ((PyUIGridObject*)self)->data->click_callable->borrow(); -// break; -// default: -// PyErr_SetString(PyExc_TypeError, "no idea how you did that; invalid UIDrawable derived instance for _get_click"); -// return NULL; -// } -// if (ptr && ptr != Py_None) -// return ptr; -// else -// return Py_None; -//} -// -//static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* closure) { -// PyObjectsEnum objtype = static_cast(reinterpret_cast(closure)); // trust me bro, it's an Enum -// UIDrawable* target; -// switch (objtype) -// { -// case PyObjectsEnum::UIFRAME: -// target = (((PyUIFrameObject*)self)->data.get()); -// break; -// case PyObjectsEnum::UICAPTION: -// target = (((PyUICaptionObject*)self)->data.get()); -// break; -// case PyObjectsEnum::UISPRITE: -// target = (((PyUISpriteObject*)self)->data.get()); -// break; -// case PyObjectsEnum::UIGRID: -// target = (((PyUIGridObject*)self)->data.get()); -// break; -// default: -// PyErr_SetString(PyExc_TypeError, "no idea how you did that; invalid UIDrawable derived instance for _set_click"); -// return -1; -// } -// -// if (value == Py_None) -// { -// target->click_unregister(); -// } else { -// target->click_register(value); -// } -// return 0; -//} -// -// End Clickability implementation -// -// -// /* -// * -// * Begin PyFontType defs -// * -// */ -// /* -// typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// } PyFontObject; -// -// static int PyFont_init(PyFontObject* self, PyObject* args, PyObject* kwds) -// { -// //std::cout << "Init called\n"; -// static const char* keywords[] = { "filename", nullptr }; -// char* filename; -// -// if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", const_cast(keywords), &filename)) -// { -// return -1; -// } -// self->data->loadFromFile((std::string)filename); -// return 0; -// } -// -// static PyTypeObject PyFontType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Font", -// .tp_basicsize = sizeof(PyFontObject), -// .tp_itemsize = 0, -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("SFML Font Object"), -// .tp_init = (initproc)PyFont_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyFontObject* self = (PyFontObject*)type->tp_alloc(type, 0); -// self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// */ -// -// /* -// * -// * End PyFontType defs -// * -// */ -// -// -// static PyObject* PyColor_get_member(PyColorObject* self, void* closure) -// { -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) -// return PyLong_FromLong(self->data->r); -// else if (member_ptr == 1) -// return PyLong_FromLong(self->data->g); -// else if (member_ptr == 2) -// return PyLong_FromLong(self->data->b); -// else if (member_ptr == 3) -// return PyLong_FromLong(self->data->a); -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// } -// -// static int PyColor_set_member(PyColorObject* self, PyObject* value, void* closure) -// { -// if (PyLong_Check(value)) -// { -// long int_val = PyLong_AsLong(value); -// if (int_val < 0) -// int_val = 0; -// else if (int_val > 255) -// int_val = 255; -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) -// self->data->r = static_cast(int_val); -// else if (member_ptr == 1) -// self->data->g = static_cast(int_val); -// else if (member_ptr == 2) -// self->data->b = static_cast(int_val); -// else if (member_ptr == 3) -// self->data->a = static_cast(int_val); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be an integer."); -// return -1; -// } -// return 0; -// } -// -// static PyGetSetDef PyColor_getsetters[] = { -// {"r", (getter)PyColor_get_member, (setter)PyColor_set_member, "Red component", (void*)0}, -// {"g", (getter)PyColor_get_member, (setter)PyColor_set_member, "Green component", (void*)1}, -// {"b", (getter)PyColor_get_member, (setter)PyColor_set_member, "Blue component", (void*)2}, -// {"a", (getter)PyColor_get_member, (setter)PyColor_set_member, "Alpha component", (void*)3}, -// {NULL} -// }; -// -// -// static PyTypeObject PyColorType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Color", -// .tp_basicsize = sizeof(PyColorObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyColorObject* obj = (PyColorObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// //.tp_repr = (reprfunc)PyUIFrame_repr, -// //.tp_hash = NULL, -// //.tp_iter -// //.tp_iternext -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("SFML Color object (RGBA)"), -// //.tp_methods = PyUIFrame_methods, -// //.tp_members = PyColor_members, -// .tp_getset = PyColor_getsetters, -// //.tp_base = NULL, -// //.tp_init = (initproc)PyUIFrame_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyColorObject* self = (PyColorObject*)type->tp_alloc(type, 0); -// if (self) self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// -// /* -// * -// * Begin template generation for PyUICaptionType -// * -// */ -// -// static PyObject* PyUICaption_get_float_member(PyUICaptionObject* self, void* closure) -// { -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) -// return PyFloat_FromDouble(self->data->text.getPosition().x); -// else if (member_ptr == 1) -// return PyFloat_FromDouble(self->data->text.getPosition().y); -// else if (member_ptr == 4) -// return PyFloat_FromDouble(self->data->text.getOutlineThickness()); -// else if (member_ptr == 5) -// return PyLong_FromLong(self->data->text.getCharacterSize()); -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// } -// -// static int PyUICaption_set_float_member(PyUICaptionObject* self, PyObject* value, void* closure) -// { -// float val; -// auto member_ptr = reinterpret_cast(closure); -// if (PyFloat_Check(value)) -// { -// val = PyFloat_AsDouble(value); -// } -// else if (PyLong_Check(value)) -// { -// val = PyLong_AsLong(value); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be an integer."); -// return -1; -// } -// if (member_ptr == 0) //x -// self->data->text.setPosition(val, self->data->text.getPosition().y); -// else if (member_ptr == 1) //y -// self->data->text.setPosition(self->data->text.getPosition().x, val); -// else if (member_ptr == 4) //outline -// self->data->text.setOutlineThickness(val); -// else if (member_ptr == 5) // character size -// self->data->text.setCharacterSize(val); -// return 0; -// } -// -// static PyObject* PyUICaption_get_vec_member(PyUICaptionObject* self, void* closure) -// { -// return PyVector(self->data->text.getPosition()).pyObject(); -// } -// -// static int PyUICaption_set_vec_member(PyUICaptionObject* self, PyObject* value, void* closure) -// { -// self->data->text.setPosition(PyVector::fromPy(value)); -// return 0; -// } -// -// static PyObject* PyUICaption_get_color_member(PyUICaptionObject* self, void* closure) -// { -// // validate closure (should be impossible to be wrong, but it's thorough) -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr != 0 && member_ptr != 1) -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// -// // TODO: manually calling tp_alloc to create a PyColorObject seems like an antipattern -// /* -// PyTypeObject* colorType = &PyLinkedColorType; -// PyObject* pyColor = colorType->tp_alloc(colorLinkedType, 0); -// if (pyColor == NULL) -// { -// std::cout << "failure to allocate mcrfpy.LinkedColor / PyLinkedColorType" << std::endl; -// return NULL; -// } -// PyColorObject* pyColorObj = reinterpret_cast(pyColor); -// */ -// -// // fetch correct member data -// sf::Color color; -// //sf::Color (*cgetter)(); -// //void (*csetter)(sf::Color); -// //std::function csetter; -// //std::function cgetter; -// if (member_ptr == 0) -// { -// 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; -// //csetter = [s = self->data](sf::Color c){s->text.setFillColor(c);}; -// //cgetter = [s = self->data](){return s->text.getFillColor();}; -// } -// else if (member_ptr == 1) -// { -// 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; -// //csetter = [s = self->data](sf::Color c){s->text.setOutlineColor(c);}; -// //cgetter = [s = self->data](){return s->text.getOutlineColor();}; -// } -// -// // initialize new mcrfpy.Color instance -// //pyColorObj->data = std::make_shared(color); -// //PyLinkedColor::fromPy(pyColorObj).set(color); -// //auto linkedcolor = PyLinkedColor(csetter, cgetter, self->data, member_ptr); -// //linkedcolor.set(color); // don't need to set a linked color! -// -// //return pyColor; -// return PyColor(color).pyObject(); -// } -// -// static int PyUICaption_set_color_member(PyUICaptionObject* self, PyObject* value, void* closure) -// { -// 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)) -// { -// // 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 << "Build LinkedColor" << std::endl; -// //auto lc = PyLinkedColor::fromPy(value); -// auto c = ((PyColorObject*)value)->data; -// //std::cout << "Fetch value" << std::endl; -// //auto c = lc.get(); -// r = c.r; g = c.g; b = c.b; a = c.a; -// std::cout << "got " << int(r) << ", " << int(g) << ", " << int(b) << ", " << int(a) << std::endl; -// } -// else if (!PyTuple_Check(value) || PyTuple_Size(value) < 3 || PyTuple_Size(value) > 4) -// { -// // reject non-Color, non-tuple value -// PyErr_SetString(PyExc_TypeError, "Value must be a tuple of 3 or 4 integers or an mcrfpy.Color object."); -// return -1; -// } -// else // get value from tuples -// { -// r = PyLong_AsLong(PyTuple_GetItem(value, 0)); -// g = PyLong_AsLong(PyTuple_GetItem(value, 1)); -// b = PyLong_AsLong(PyTuple_GetItem(value, 2)); -// a = 255; -// -// if (PyTuple_Size(value) == 4) -// { -// a = PyLong_AsLong(PyTuple_GetItem(value, 3)); -// } -// } -// -// if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255) -// { -// PyErr_SetString(PyExc_ValueError, "Color values must be between 0 and 255."); -// return -1; -// } -// -// if (member_ptr == 0) -// { -// self->data->text.setFillColor(sf::Color(r, g, b, a)); -// } -// else if (member_ptr == 1) -// { -// self->data->text.setOutlineColor(sf::Color(r, g, b, a)); -// } -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return -1; -// } -// -// return 0; -// } -// -// static PyObject* PyUICaption_get_text(PyUICaptionObject* self, void* closure) -// { -// Resources::caption_buffer = self->data->text.getString(); -// return PyUnicode_FromString(Resources::caption_buffer.c_str()); -// } -// -// static int PyUICaption_set_text(PyUICaptionObject* self, PyObject* value, void* closure) -// { -// PyObject* s = PyObject_Str(value); -// PyObject * temp_bytes = PyUnicode_AsEncodedString(s, "UTF-8", "strict"); // Owned reference -// if (temp_bytes != NULL) { -// Resources::caption_buffer = PyBytes_AS_STRING(temp_bytes); // Borrowed pointer -// Py_DECREF(temp_bytes); -// } -// self->data->text.setString(Resources::caption_buffer); -// return 0; -// } -// -// static PyGetSetDef PyUICaption_getsetters[] = { -// {"x", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "X coordinate of top-left corner", (void*)0}, -// {"y", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "Y coordinate of top-left corner", (void*)1}, -// {"pos", (getter)PyUICaption_get_vec_member, (setter)PyUICaption_set_vec_member, "(x, y) vector", (void*)0}, -// //{"w", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "width of the rectangle", (void*)2}, -// //{"h", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "height of the rectangle", (void*)3}, -// {"outline", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "Thickness of the border", (void*)4}, -// {"fill_color", (getter)PyUICaption_get_color_member, (setter)PyUICaption_set_color_member, "Fill color of the text", (void*)0}, -// {"outline_color", (getter)PyUICaption_get_color_member, (setter)PyUICaption_set_color_member, "Outline color of the text", (void*)1}, -// //{"children", (getter)PyUIFrame_get_children, NULL, "UICollection of objects on top of this one", NULL}, -// {"text", (getter)PyUICaption_get_text, (setter)PyUICaption_set_text, "The text displayed", NULL}, -// {"size", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "Text size (integer) in points", (void*)5}, -// {"click", (getter)PyUIDrawable_get_click, (setter)PyUIDrawable_set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UICAPTION}, -// {NULL} -// }; -// -// static PyObject* PyUICaption_repr(PyUICaptionObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// auto text = self->data->text; -// auto fc = text.getFillColor(); -// auto oc = text.getOutlineColor(); -// ss << ""; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static int PyUICaption_init(PyUICaptionObject* self, PyObject* args, PyObject* kwds) -// { -// //std::cout << "Init called\n"; -// static const char* keywords[] = { "x", "y", "text", "font", "fill_color", "outline_color", nullptr }; -// float x = 0.0f, y = 0.0f; -// char* text; -// PyObject* font, fill_color, outline_color; -// -// if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ffzOOO", -// const_cast(keywords), &x, &y, &text, &font, &fill_color, &outline_color)) -// { -// return -1; -// } -// -// // check types for font, fill_color, outline_color -// // -// // Set Font -// // -// std::cout << PyUnicode_AsUTF8(PyObject_Repr(font)) << std::endl; -// if (font != NULL && !PyObject_IsInstance(font, (PyObject*)&PyFontType)){ -// PyErr_SetString(PyExc_TypeError, "font must be a mcrfpy.Font instance"); -// return -1; -// } else if (font != NULL) -// { -// auto font_obj = (PyFontObject*)font; -// self->data->text.setFont(font_obj->data->font); -// self->font = font; -// Py_INCREF(font); -// } else -// { -// // default font -// //self->data->text.setFont(Resources::game->getFont()); -// } -// -// // -// // Set Color -// // -// self->data->text.setPosition(sf::Vector2f(x, y)); -// self->data->text.setString((std::string)text); -// self->data->text.setFillColor(sf::Color(0,0,0,255)); -// self->data->text.setOutlineColor(sf::Color(128,128,128,255)); -// -// return 0; -// } -// -// static PyTypeObject PyUICaptionType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Caption", -// .tp_basicsize = sizeof(PyUICaptionObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUICaptionObject* obj = (PyUICaptionObject*)self; -// // release reference to font object -// if (obj->font) Py_DECREF(obj->font); -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUICaption_repr, -// //.tp_hash = NULL, -// //.tp_iter -// //.tp_iternext -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("docstring"), -// //.tp_methods = PyUIFrame_methods, -// //.tp_members = PyUIFrame_members, -// .tp_getset = PyUICaption_getsetters, -// //.tp_base = NULL, -// .tp_init = (initproc)PyUICaption_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyUICaptionObject* self = (PyUICaptionObject*)type->tp_alloc(type, 0); -// if (self) self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// -// /* -// * -// * End PyUICaptionType generation -// * -// */ -// -// -// /* -// * -// * Begin template generation for PyUIFrameType -// * -// */ -// -// static PyObject* PyUIFrame_get_float_member(PyUIFrameObject* self, void* closure) -// { -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) -// return PyFloat_FromDouble(self->data->box.getPosition().x); -// else if (member_ptr == 1) -// return PyFloat_FromDouble(self->data->box.getPosition().y); -// else if (member_ptr == 2) -// return PyFloat_FromDouble(self->data->box.getSize().x); -// else if (member_ptr == 3) -// return PyFloat_FromDouble(self->data->box.getSize().y); -// else if (member_ptr == 4) -// return PyFloat_FromDouble(self->data->box.getOutlineThickness()); -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// } -// -// static int PyUIFrame_set_float_member(PyUIFrameObject* self, PyObject* value, void* closure) -// { -// float val; -// auto member_ptr = reinterpret_cast(closure); -// if (PyFloat_Check(value)) -// { -// val = PyFloat_AsDouble(value); -// } -// else if (PyLong_Check(value)) -// { -// val = PyLong_AsLong(value); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be an integer."); -// return -1; -// } -// if (member_ptr == 0) //x -// self->data->box.setPosition(val, self->data->box.getPosition().y); -// else if (member_ptr == 1) //y -// self->data->box.setPosition(self->data->box.getPosition().x, val); -// else if (member_ptr == 2) //w -// self->data->box.setSize(sf::Vector2f(val, self->data->box.getSize().y)); -// else if (member_ptr == 3) //h -// self->data->box.setSize(sf::Vector2f(self->data->box.getSize().x, val)); -// else if (member_ptr == 4) //outline -// self->data->box.setOutlineThickness(val); -// return 0; -// } -// -// static PyObject* PyUIFrame_get_color_member(PyUIFrameObject* self, void* closure) -// { -// // validate closure (should be impossible to be wrong, but it's thorough) -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr != 0 && member_ptr != 1) -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// PyTypeObject* colorType = &PyColorType; -// PyObject* pyColor = colorType->tp_alloc(colorType, 0); -// if (pyColor == NULL) -// { -// std::cout << "failure to allocate mcrfpy.Color / PyColorType" << std::endl; -// return NULL; -// } -// PyColorObject* pyColorObj = reinterpret_cast(pyColor); -// -// // fetch correct member data -// sf::Color color; -// if (member_ptr == 0) -// { -// color = self->data->box.getFillColor(); -// //return Py_BuildValue("(iii)", color.r, color.g, color.b); -// } -// else if (member_ptr == 1) -// { -// color = self->data->box.getOutlineColor(); -// //return Py_BuildValue("(iii)", color.r, color.g, color.b); -// } -// -// // initialize new mcrfpy.Color instance -// //pyColorObj->data = std::make_shared(color); -// //PyColor::fromPy(pyColorObj).set(color); -// -// // TODO - supposed to return Linked -// return PyColor(color).pyObject(); -// } -// -// static int PyUIFrame_set_color_member(PyUIFrameObject* self, PyObject* value, void* closure) -// { -// //TODO: this logic of (PyColor instance OR tuple -> sf::color) should be encapsulated for reuse -// auto member_ptr = reinterpret_cast(closure); -// int r, g, b, a; -// 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 = ((PyColorObject*)value)->data; -// 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) -// { -// // reject non-Color, non-tuple value -// PyErr_SetString(PyExc_TypeError, "Value must be a tuple of 3 or 4 integers or an mcrfpy.Color object."); -// return -1; -// } -// else // get value from tuples -// { -// r = PyLong_AsLong(PyTuple_GetItem(value, 0)); -// g = PyLong_AsLong(PyTuple_GetItem(value, 1)); -// b = PyLong_AsLong(PyTuple_GetItem(value, 2)); -// a = 255; -// -// if (PyTuple_Size(value) == 4) -// { -// a = PyLong_AsLong(PyTuple_GetItem(value, 3)); -// } -// } -// -// if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255) -// { -// PyErr_SetString(PyExc_ValueError, "Color values must be between 0 and 255."); -// return -1; -// } -// -// if (member_ptr == 0) -// { -// self->data->box.setFillColor(sf::Color(r, g, b, a)); -// } -// else if (member_ptr == 1) -// { -// self->data->box.setOutlineColor(sf::Color(r, g, b, a)); -// } -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return -1; -// } -// -// return 0; -// } -// -// static PyObject* PyUIFrame_get_children(PyUIFrameObject*, void*); -// // implementation after the PyUICollectionType definition -// -// static PyGetSetDef PyUIFrame_getsetters[] = { -// {"x", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "X coordinate of top-left corner", (void*)0}, -// {"y", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "Y coordinate of top-left corner", (void*)1}, -// {"w", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "width of the rectangle", (void*)2}, -// {"h", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "height of the rectangle", (void*)3}, -// {"outline", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "Thickness of the border", (void*)4}, -// {"fill_color", (getter)PyUIFrame_get_color_member, (setter)PyUIFrame_set_color_member, "Fill color of the rectangle", (void*)0}, -// {"outline_color", (getter)PyUIFrame_get_color_member, (setter)PyUIFrame_set_color_member, "Outline color of the rectangle", (void*)1}, -// {"children", (getter)PyUIFrame_get_children, NULL, "UICollection of objects on top of this one", NULL}, -// {"click", (getter)PyUIDrawable_get_click, (setter)PyUIDrawable_set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UIFRAME}, -// {NULL} -// }; -// -// static PyObject* PyUIFrame_repr(PyUIFrameObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// auto box = self->data->box; -// auto fc = box.getFillColor(); -// auto oc = box.getOutlineColor(); -// ss << "data->children->size() << " child objects" << -// ")>"; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static int PyUIFrame_init(PyUIFrameObject* self, PyObject* args, PyObject* kwds) -// { -// //std::cout << "Init called\n"; -// static const char* keywords[] = { "x", "y", "w", "h", "fill_color", "outline_color", "outline", nullptr }; -// float x = 0.0f, y = 0.0f, w = 0.0f, h=0.0f, outline=0.0f; -// PyObject* fill_color = 0; -// PyObject* outline_color = 0; -// -// if (!PyArg_ParseTupleAndKeywords(args, kwds, "ffff|OOf", const_cast(keywords), &x, &y, &w, &h, &fill_color, &outline_color, &outline)) -// { -// return -1; -// } -// -// //self->data->x = x; -// //self->data->y = y; -// self->data->box.setPosition(sf::Vector2f(x, y)); -// self->data->box.setSize(sf::Vector2f(w, h)); -// self->data->box.setOutlineThickness(outline); -// // getsetter abuse because I haven't standardized Color object parsing (TODO) -// int err_val = 0; -// if (fill_color && fill_color != Py_None) err_val = PyUIFrame_set_color_member(self, fill_color, (void*)0); -// else self->data->box.setFillColor(sf::Color(0,0,0,255)); -// if (err_val) return err_val; -// if (outline_color && outline_color != Py_None) err_val = PyUIFrame_set_color_member(self, outline_color, (void*)1); -// else self->data->box.setOutlineColor(sf::Color(128,128,128,255)); -// if (err_val) return err_val; -// return 0; -// } -// -// static PyTypeObject PyUIFrameType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Frame", -// .tp_basicsize = sizeof(PyUIFrameObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUIFrameObject* obj = (PyUIFrameObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUIFrame_repr, -// //.tp_hash = NULL, -// //.tp_iter -// //.tp_iternext -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("docstring"), -// //.tp_methods = PyUIFrame_methods, -// //.tp_members = PyUIFrame_members, -// .tp_getset = PyUIFrame_getsetters, -// //.tp_base = NULL, -// .tp_init = (initproc)PyUIFrame_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyUIFrameObject* self = (PyUIFrameObject*)type->tp_alloc(type, 0); -// if (self) self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// -// /* -// * -// * End auto-generated PyUIFrameType generation -// * -// */ -// -// /* -// * -// * Begin Python Class Instantiator (iterator helper) -// * -// */ -// -// /* // definition can't go in the header file -// PyObject* py_instance(UIDrawable* obj) -// { -// -// } -// */ -// -// /* -// * -// * End Python Class Instantitator (iterator helper) -// * -// */ -// -// /* -// * -// * Begin template generation for PyUISpriteType -// * -// */ -// -// static PyObject* PyUISprite_get_float_member(PyUISpriteObject* self, void* closure) -// { -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) -// return PyFloat_FromDouble(self->data->getPosition().x); -// else if (member_ptr == 1) -// return PyFloat_FromDouble(self->data->getPosition().y); -// else if (member_ptr == 2) -// return PyFloat_FromDouble(self->data->getScale().x); // scale X and Y are identical, presently -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// } -// -// -// static int PyUISprite_set_float_member(PyUISpriteObject* self, PyObject* value, void* closure) -// { -// float val; -// auto member_ptr = reinterpret_cast(closure); -// if (PyFloat_Check(value)) -// { -// val = PyFloat_AsDouble(value); -// } -// else if (PyLong_Check(value)) -// { -// val = PyLong_AsLong(value); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be a floating point number."); -// return -1; -// } -// if (member_ptr == 0) //x -// self->data->setPosition(sf::Vector2f(val, self->data->getPosition().y)); -// else if (member_ptr == 1) //y -// self->data->setPosition(sf::Vector2f(self->data->getPosition().x, val)); -// else if (member_ptr == 2) // scale -// self->data->setScale(sf::Vector2f(val, val)); -// return 0; -// } -// -// static PyObject* PyUISprite_get_int_member(PyUISpriteObject* self, void* closure) -// { -// auto member_ptr = reinterpret_cast(closure); -// if (true) {} -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -// -// return PyLong_FromDouble(self->data->getSpriteIndex()); -// } -// -// -// static int PyUISprite_set_int_member(PyUISpriteObject* self, PyObject* value, void* closure) -// { -// int val; -// auto member_ptr = reinterpret_cast(closure); -// if (PyLong_Check(value)) -// { -// val = PyLong_AsLong(value); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be an integer."); -// return -1; -// } -// //self->data->sprite_index = val; -// //self->data->sprite.setTextureRect(self->data->itex->spriteCoordinates(val)); -// self->data->setSpriteIndex(val); -// return 0; -// } -// -// static PyObject* PyUISprite_get_texture(PyUISpriteObject* self, void* closure) -// { -// return self->data->getTexture()->pyObject(); -// } -// -// static int PyUISprite_set_texture(PyUISpriteObject* self, PyObject* value, void* closure) -// { -// return -1; -// } -// -// static PyGetSetDef PyUISprite_getsetters[] = { -// {"x", (getter)PyUISprite_get_float_member, (setter)PyUISprite_set_float_member, "X coordinate of top-left corner", (void*)0}, -// {"y", (getter)PyUISprite_get_float_member, (setter)PyUISprite_set_float_member, "Y coordinate of top-left corner", (void*)1}, -// {"scale", (getter)PyUISprite_get_float_member, (setter)PyUISprite_set_float_member, "Size factor", (void*)2}, -// {"sprite_number", (getter)PyUISprite_get_int_member, (setter)PyUISprite_set_int_member, "Which sprite on the texture is shown", NULL}, -// {"texture", (getter)PyUISprite_get_texture, (setter)PyUISprite_set_texture, "Texture object", NULL}, -// {"click", (getter)PyUIDrawable_get_click, (setter)PyUIDrawable_set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UISPRITE}, -// {NULL} -// }; -// -// static PyObject* PyUISprite_repr(PyUISpriteObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// //auto sprite = self->data->sprite; -// ss << ""; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static int PyUISprite_init(PyUISpriteObject* self, PyObject* args, PyObject* kwds) -// { -// //std::cout << "Init called\n"; -// static const char* keywords[] = { "x", "y", "texture", "sprite_index", "scale", nullptr }; -// float x = 0.0f, y = 0.0f, scale = 1.0f; -// int sprite_index; -// PyObject* texture; -// -// if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ffOif", -// const_cast(keywords), &x, &y, &texture, &sprite_index, &scale)) -// { -// return -1; -// } -// -// // check types for texture -// // -// // Set Texture -// // -// if (texture != NULL && !PyObject_IsInstance(texture, (PyObject*)&PyTextureType)){ -// PyErr_SetString(PyExc_TypeError, "texture must be a mcrfpy.Texture instance"); -// return -1; -// } /*else if (texture != NULL) // to be removed: UIObjects don't manage texture references -// { -// self->texture = texture; -// Py_INCREF(texture); -// } else -// { -// // default tex? -// }*/ -// auto pytexture = (PyTextureObject*)texture; -// self->data = std::make_shared(pytexture->data, sprite_index, sf::Vector2f(x, y), scale); -// self->data->setPosition(sf::Vector2f(x, y)); -// -// return 0; -// } -// -// static PyTypeObject PyUISpriteType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Sprite", -// .tp_basicsize = sizeof(PyUISpriteObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUISpriteObject* obj = (PyUISpriteObject*)self; -// // release reference to font object -// //if (obj->texture) Py_DECREF(obj->texture); -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUISprite_repr, -// //.tp_hash = NULL, -// //.tp_iter -// //.tp_iternext -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("docstring"), -// //.tp_methods = PyUIFrame_methods, -// //.tp_members = PyUIFrame_members, -// .tp_getset = PyUISprite_getsetters, -// //.tp_base = NULL, -// .tp_init = (initproc)PyUISprite_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyUISpriteObject* self = (PyUISpriteObject*)type->tp_alloc(type, 0); -// //if (self) self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// /* -// * -// * End template for PyUISpriteType -// * -// */ -// -// -// -// -// /* -// * -// * PyUIGridPoint defs -// * -// */ -// -// TODO: question: are sfColor_to_PyObject and PyObject_to_sfColor duplicitive? How does UIFrame get/set colors? -// -// Utility function to convert sf::Color to PyObject* -//static PyObject* sfColor_to_PyObject(sf::Color color) { -// return Py_BuildValue("(iiii)", color.r, color.g, color.b, color.a); -//} -// -// Utility function to convert PyObject* to sf::Color -//static sf::Color PyObject_to_sfColor(PyObject* obj) { -// int r, g, b, a = 255; // Default alpha to fully opaque if not specified -// if (!PyArg_ParseTuple(obj, "iii|i", &r, &g, &b, &a)) { -// return sf::Color(); // Return default color on parse error -// } -// return sf::Color(r, g, b, a); -//} -// -//static PyObject* PyUIGridPoint_get_color(PyUIGridPointObject* self, void* closure) { -// if (reinterpret_cast(closure) == 0) { // color -// return sfColor_to_PyObject(self->data->color); -// } else { // color_overlay -// return sfColor_to_PyObject(self->data->color_overlay); -// } -//} -// -//static int PyUIGridPoint_set_color(PyUIGridPointObject* self, PyObject* value, void* closure) { -// sf::Color color = PyObject_to_sfColor(value); -// if (reinterpret_cast(closure) == 0) { // color -// self->data->color = color; -// } else { // color_overlay -// self->data->color_overlay = color; -// } -// return 0; -//} -// -//static PyObject* PyUIGridPoint_get_bool_member(PyUIGridPointObject* self, void* closure) { -// if (reinterpret_cast(closure) == 0) { // walkable -// return PyBool_FromLong(self->data->walkable); -// } else { // transparent -// return PyBool_FromLong(self->data->transparent); -// } -//} -// -//static int PyUIGridPoint_set_bool_member(PyUIGridPointObject* self, PyObject* value, void* closure) { -// if (value == Py_True) { -// if (reinterpret_cast(closure) == 0) { // walkable -// self->data->walkable = true; -// } else { // transparent -// self->data->transparent = true; -// } -// } else if (value == Py_False) { -// if (reinterpret_cast(closure) == 0) { // walkable -// self->data->walkable = false; -// } else { // transparent -// self->data->transparent = false; -// } -// } else { -// PyErr_SetString(PyExc_ValueError, "Expected a boolean value"); -// return -1; -// } -// return 0; -//} -// -//static PyObject* PyUIGridPoint_get_int_member(PyUIGridPointObject* self, void* closure) { -// switch(reinterpret_cast(closure)) { -// case 0: return PyLong_FromLong(self->data->tilesprite); -// case 1: return PyLong_FromLong(self->data->tile_overlay); -// case 2: return PyLong_FromLong(self->data->uisprite); -// default: PyErr_SetString(PyExc_RuntimeError, "Invalid closure"); return nullptr; -// } -//} -// -//static int PyUIGridPoint_set_int_member(PyUIGridPointObject* self, PyObject* value, void* closure) { -// long val = PyLong_AsLong(value); -// if (PyErr_Occurred()) return -1; -// -// switch(reinterpret_cast(closure)) { -// case 0: self->data->tilesprite = val; break; -// case 1: self->data->tile_overlay = val; break; -// case 2: self->data->uisprite = val; break; -// default: PyErr_SetString(PyExc_RuntimeError, "Invalid closure"); return -1; -// } -// return 0; -//} -// -//static PyGetSetDef PyUIGridPoint_getsetters[] = { -// {"color", (getter)PyUIGridPoint_get_color, (setter)PyUIGridPoint_set_color, "GridPoint color", (void*)0}, -// {"color_overlay", (getter)PyUIGridPoint_get_color, (setter)PyUIGridPoint_set_color, "GridPoint color overlay", (void*)1}, -// {"walkable", (getter)PyUIGridPoint_get_bool_member, (setter)PyUIGridPoint_set_bool_member, "Is the GridPoint walkable", (void*)0}, -// {"transparent", (getter)PyUIGridPoint_get_bool_member, (setter)PyUIGridPoint_set_bool_member, "Is the GridPoint transparent", (void*)1}, -// {"tilesprite", (getter)PyUIGridPoint_get_int_member, (setter)PyUIGridPoint_set_int_member, "Tile sprite index", (void*)0}, -// {"tile_overlay", (getter)PyUIGridPoint_get_int_member, (setter)PyUIGridPoint_set_int_member, "Tile overlay sprite index", (void*)1}, -// {"uisprite", (getter)PyUIGridPoint_get_int_member, (setter)PyUIGridPoint_set_int_member, "UI sprite index", (void*)2}, -// {NULL} /* Sentinel */ -//}; -// -//static PyTypeObject PyUIGridPointType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.GridPoint", -// .tp_basicsize = sizeof(PyUIGridPointObject), -// .tp_itemsize = 0, -// // Methods omitted for brevity -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = "UIGridPoint objects", -// .tp_getset = PyUIGridPoint_getsetters, -// //.tp_init = (initproc)PyUIGridPoint_init, // TODO Define the init function -// .tp_new = PyType_GenericNew, -//}; -// -// /* -// * -// * end PyUIGridPoint defs -// * -// */ -// -// -// -// /* -// * -// * PyUIGridPointState defs -// * -// */ -// -//static PyObject* PyUIGridPointState_get_bool_member(PyUIGridPointStateObject* self, void* closure) { -// if (reinterpret_cast(closure) == 0) { // visible -// return PyBool_FromLong(self->data->visible); -// } else { // discovered -// return PyBool_FromLong(self->data->discovered); -// } -//} -// -//static int PyUIGridPointState_set_bool_member(PyUIGridPointStateObject* self, PyObject* value, void* closure) { -// if (!PyBool_Check(value)) { -// PyErr_SetString(PyExc_TypeError, "Value must be a boolean"); -// return -1; -// } -// -// int truthValue = PyObject_IsTrue(value); -// if (truthValue < 0) { -// return -1; // PyObject_IsTrue returns -1 on error -// } -// -// if (reinterpret_cast(closure) == 0) { // visible -// self->data->visible = truthValue; -// } else { // discovered -// self->data->discovered = truthValue; -// } -// -// return 0; -//} -// -//static PyGetSetDef PyUIGridPointState_getsetters[] = { -// {"visible", (getter)PyUIGridPointState_get_bool_member, (setter)PyUIGridPointState_set_bool_member, "Is the GridPointState visible", (void*)0}, -// {"discovered", (getter)PyUIGridPointState_get_bool_member, (setter)PyUIGridPointState_set_bool_member, "Has the GridPointState been discovered", (void*)1}, -// {NULL} /* Sentinel */ -//}; -// -//static PyTypeObject PyUIGridPointStateType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.GridPointState", -// .tp_basicsize = sizeof(PyUIGridPointStateObject), -// .tp_itemsize = 0, -// // Methods omitted for brevity -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = "UIGridPointState objects", // TODO: Add PyUIGridPointState tp_init -// .tp_getset = PyUIGridPointState_getsetters, -// .tp_new = PyType_GenericNew, -//}; -// -// -// /* -// * -// * end PyUIGridPointState defs -// * -// */ -// -// /* -// * -// * PyUIEntity defs -// * -// */ -// -// TODO: sf::Vector2f convenience functions here might benefit from a PyVectorObject much like PyColorObject -// Utility function to convert sf::Vector2f to PyObject* -//static PyObject* sfVector2f_to_PyObject(sf::Vector2f vector) { -// return Py_BuildValue("(ff)", vector.x, vector.y); -//} -// -// Utility function to convert PyObject* to sf::Vector2f -//static sf::Vector2f PyObject_to_sfVector2f(PyObject* obj) { -// float x, y; -// if (!PyArg_ParseTuple(obj, "ff", &x, &y)) { -// return sf::Vector2f(); // TODO / reconsider this default: Return default vector on parse error -// } -// return sf::Vector2f(x, y); -//} -// -// Utility function to convert UIGridPointState to PyObject* -//static PyObject* UIGridPointState_to_PyObject(const UIGridPointState& state) { -// PyObject* obj = PyObject_New(PyObject, &PyUIGridPointStateType); -// if (!obj) return PyErr_NoMemory(); -// -// // Assuming PyUIGridPointStateObject structure has a UIGridPointState* member called 'data' -// //((PyUIGridPointStateObject*)obj)->data = new UIGridPointState(state); // Copy constructor // wontimplement / feat - don't use new, get shared_ptr working -// -// return obj; -//} -// -// Function to convert std::vector to a Python list TODO need a PyUICollection style iterable -//static PyObject* UIGridPointStateVector_to_PyList(const std::vector& vec) { -// PyObject* list = PyList_New(vec.size()); -// if (!list) return PyErr_NoMemory(); -// -// for (size_t i = 0; i < vec.size(); ++i) { -// PyObject* obj = UIGridPointState_to_PyObject(vec[i]); -// if (!obj) { // Cleanup on failure -// Py_DECREF(list); -// return NULL; -// } -// PyList_SET_ITEM(list, i, obj); // This steals a reference to obj -// } -// -// return list; -//} -// -//static PyObject* PyUIEntity_get_position(PyUIEntityObject* self, void* closure) { -// return sfVector2f_to_PyObject(self->data->position); -//} -// -//static int PyUIEntity_set_position(PyUIEntityObject* self, PyObject* value, void* closure) { -// self->data->position = PyObject_to_sfVector2f(value); -// return 0; -//} -// -//static PyObject* PyUIEntity_get_gridstate(PyUIEntityObject* self, void* closure) { -// // Assuming a function to convert std::vector to PyObject* list -// return UIGridPointStateVector_to_PyList(self->data->gridstate); -//} -// -//static PyObject* PyUIEntity_get_spritenumber(PyUIEntityObject* self, void* closure) { -// return PyLong_FromDouble(self->data->sprite.getSpriteIndex()); -//} -// -//static int PyUIEntity_set_spritenumber(PyUIEntityObject* self, PyObject* value, void* closure) { -// int val; -// if (PyLong_Check(value)) -// val = PyLong_AsLong(value); -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be an integer."); -// return -1; -// } -// //self->data->sprite.sprite_index = val; -// self->data->sprite.setSpriteIndex(val); // todone - I don't like ".sprite.sprite" in this stack of UIEntity.UISprite.sf::Sprite -// return 0; -//} -// -//static PyObject* PyUIEntity_at(PyUIEntityObject* self, PyObject* o) -//{ -// int x, y; -// if (!PyArg_ParseTuple(o, "ii", &x, &y)) { -// PyErr_SetString(PyExc_TypeError, "UIEntity.at requires two integer arguments: (x, y)"); -// return NULL; -// } -// -// if (self->data->grid == NULL) { -// PyErr_SetString(PyExc_ValueError, "Entity cannot access surroundings because it is not associated with a grid"); -// return NULL; -// } -// -// PyUIGridPointStateObject* obj = (PyUIGridPointStateObject*)((&PyUIGridPointStateType)->tp_alloc(&PyUIGridPointStateType, 0)); -// //auto target = std::static_pointer_cast(target); -// obj->data = &(self->data->gridstate[y + self->data->grid->grid_x * x]); -// obj->grid = self->data->grid; -// obj->entity = self->data; -// return (PyObject*)obj; -//} -// -//static PyMethodDef PyUIEntity_methods[] = { -// {"at", (PyCFunction)PyUIEntity_at, METH_O}, -// {NULL, NULL, 0, NULL} -//}; -// -// Define getters and setters -//static PyGetSetDef PyUIEntity_getsetters[] = { -// {"position", (getter)PyUIEntity_get_position, (setter)PyUIEntity_set_position, "Entity position", NULL}, -// {"gridstate", (getter)PyUIEntity_get_gridstate, NULL, "Grid point states for the entity", NULL}, -// {"sprite_number", (getter)PyUIEntity_get_spritenumber, (setter)PyUIEntity_set_spritenumber, "Sprite number (index) on the texture on the display", NULL}, -// {NULL} /* Sentinel */ -//}; -// -//static int PyUIEntity_init(PyUIEntityObject*, PyObject*, PyObject*); // forward declare -// -// -// -// Define the PyTypeObject for UIEntity -//static PyTypeObject PyUIEntityType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Entity", -// .tp_basicsize = sizeof(PyUIEntityObject), -// .tp_itemsize = 0, -// // Methods omitted for brevity -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = "UIEntity objects", -// .tp_methods = PyUIEntity_methods, -// .tp_getset = PyUIEntity_getsetters, -// .tp_init = (initproc)PyUIEntity_init, -// .tp_new = PyType_GenericNew, -//}; -// -// -// /* -// * -// * end PyUIEntity defs -// * -// */ -// -// /* -// * -// * PyUIGrid defs -// * -// */ -// -//static int PyUIGrid_init(PyUIGridObject* self, PyObject* args, PyObject* kwds) { -// int grid_x, grid_y; -// PyObject* textureObj; -// float box_x, box_y, box_w, box_h; -// -// if (!PyArg_ParseTuple(args, "iiOffff", &grid_x, &grid_y, &textureObj, &box_x, &box_y, &box_w, &box_h)) { -// return -1; // If parsing fails, return an error -// } -// -// // Convert PyObject texture to IndexTexture* -// // This requires the texture object to have been initialized similar to UISprite's texture handling -// if (!PyObject_IsInstance(textureObj, (PyObject*)&PyTextureType)) { -// PyErr_SetString(PyExc_TypeError, "texture must be a mcrfpy.Texture instance"); -// return -1; -// } -// PyTextureObject* pyTexture = reinterpret_cast(textureObj); -// // TODO (7DRL day 2, item 4.) use shared_ptr / PyTextureObject on UIGrid -// //IndexTexture* texture = pyTexture->data.get(); -// -// // Initialize UIGrid -// //self->data = new UIGrid(grid_x, grid_y, texture, sf::Vector2f(box_x, box_y), sf::Vector2f(box_w, box_h)); -// self->data = std::make_shared(grid_x, grid_y, pyTexture->data, -// sf::Vector2f(box_x, box_y), sf::Vector2f(box_w, box_h)); -// return 0; // Success -//} -// -//static PyObject* PyUIGrid_get_grid_size(PyUIGridObject* self, void* closure) { -// return Py_BuildValue("(ii)", self->data->grid_x, self->data->grid_y); -//} -// -//static PyObject* PyUIGrid_get_position(PyUIGridObject* self, void* closure) { -// auto& box = self->data->box; -// return Py_BuildValue("(ff)", box.getPosition().x, box.getPosition().y); -//} -// -//static int PyUIGrid_set_position(PyUIGridObject* self, PyObject* value, void* closure) { -// float x, y; -// if (!PyArg_ParseTuple(value, "ff", &x, &y)) { -// PyErr_SetString(PyExc_ValueError, "Position must be a tuple of two floats"); -// return -1; -// } -// self->data->box.setPosition(x, y); -// return 0; -//} -// -//static PyObject* PyUIGrid_get_size(PyUIGridObject* self, void* closure) { -// auto& box = self->data->box; -// return Py_BuildValue("(ff)", box.getSize().x, box.getSize().y); -//} -// -//static int PyUIGrid_set_size(PyUIGridObject* self, PyObject* value, void* closure) { -// float w, h; -// if (!PyArg_ParseTuple(value, "ff", &w, &h)) { -// PyErr_SetString(PyExc_ValueError, "Size must be a tuple of two floats"); -// return -1; -// } -// self->data->box.setSize(sf::Vector2f(w, h)); -// return 0; -//} -// -//static PyObject* PyUIGrid_get_center(PyUIGridObject* self, void* closure) { -// return Py_BuildValue("(ff)", self->data->center_x, self->data->center_y); -//} -// -//static int PyUIGrid_set_center(PyUIGridObject* self, PyObject* value, void* closure) { -// float x, y; -// if (!PyArg_ParseTuple(value, "ff", &x, &y)) { -// PyErr_SetString(PyExc_ValueError, "Size must be a tuple of two floats"); -// return -1; -// } -// self->data->center_x = x; -// self->data->center_y = y; -// return 0; -//} -// -//static PyObject* PyUIGrid_get_float_member(PyUIGridObject* self, void* closure) -//{ -// auto member_ptr = reinterpret_cast(closure); -// if (member_ptr == 0) // x -// return PyFloat_FromDouble(self->data->box.getPosition().x); -// else if (member_ptr == 1) // y -// return PyFloat_FromDouble(self->data->box.getPosition().y); -// else if (member_ptr == 2) // w -// return PyFloat_FromDouble(self->data->box.getSize().x); -// else if (member_ptr == 3) // h -// return PyFloat_FromDouble(self->data->box.getSize().y); -// else if (member_ptr == 4) // center_x -// return PyFloat_FromDouble(self->data->center_x); -// else if (member_ptr == 5) // center_y -// return PyFloat_FromDouble(self->data->center_y); -// else if (member_ptr == 6) // zoom -// return PyFloat_FromDouble(self->data->zoom); -// else -// { -// PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); -// return nullptr; -// } -//} -// -// -//static int PyUIGrid_set_float_member(PyUIGridObject* self, PyObject* value, void* closure) -//{ -// float val; -// auto member_ptr = reinterpret_cast(closure); -// if (PyFloat_Check(value)) -// { -// val = PyFloat_AsDouble(value); -// } -// else if (PyLong_Check(value)) -// { -// val = PyLong_AsLong(value); -// } -// else -// { -// PyErr_SetString(PyExc_TypeError, "Value must be a floating point number."); -// return -1; -// } -// if (member_ptr == 0) // x -// self->data->box.setPosition(val, self->data->box.getPosition().y); -// else if (member_ptr == 1) // y -// self->data->box.setPosition(self->data->box.getPosition().x, val); -// else if (member_ptr == 2) // w -// self->data->box.setSize(sf::Vector2f(val, self->data->box.getSize().y)); -// else if (member_ptr == 3) // h -// self->data->box.setSize(sf::Vector2f(self->data->box.getSize().x, val)); -// else if (member_ptr == 4) // center_x -// self->data->center_x = val; -// else if (member_ptr == 5) // center_y -// self->data->center_y = val; -// else if (member_ptr == 6) // zoom -// self->data->zoom = val; -// return 0; -//} -// TODO (7DRL Day 2, item 5.) return Texture object -///* -//static PyObject* PyUIGrid_get_texture(PyUIGridObject* self, void* closure) { -// Py_INCREF(self->texture); -// return self->texture; -//} -//*/ -//static PyObject* PyUIGrid_get_texture(PyUIGridObject* self, void* closure) { -// //return self->data->getTexture()->pyObject(); -// PyTextureObject* obj = (PyTextureObject*)((&PyTextureType)->tp_alloc(&PyTextureType, 0)); -// obj->data = self->data->getTexture(); -// return (PyObject*)obj; -//} -// -//static PyObject* PyUIGrid_at(PyUIGridObject* self, PyObject* o) -//{ -// int x, y; -// if (!PyArg_ParseTuple(o, "ii", &x, &y)) { -// PyErr_SetString(PyExc_TypeError, "UIGrid.at requires two integer arguments: (x, y)"); -// return NULL; -// } -// if (x < 0 || x >= self->data->grid_x) { -// PyErr_SetString(PyExc_ValueError, "x value out of range (0, Grid.grid_y)"); -// return NULL; -// } -// if (y < 0 || y >= self->data->grid_y) { -// PyErr_SetString(PyExc_ValueError, "y value out of range (0, Grid.grid_y)"); -// return NULL; -// } -// -// PyUIGridPointObject* obj = (PyUIGridPointObject*)((&PyUIGridPointType)->tp_alloc(&PyUIGridPointType, 0)); -// //auto target = std::static_pointer_cast(target); -// obj->data = &(self->data->points[x + self->data->grid_x * y]); -// obj->grid = self->data; -// return (PyObject*)obj; -//} -// -//static PyMethodDef PyUIGrid_methods[] = { -// {"at", (PyCFunction)PyUIGrid_at, METH_O}, -// {NULL, NULL, 0, NULL} -//}; -// -//static PyObject* PyUIGrid_get_children(PyUIGridObject* self, void* closure); // forward declare -// -//static PyGetSetDef PyUIGrid_getsetters[] = { -// -// // TODO - refactor into get_vector_member with field identifier values `(void*)n` -// {"grid_size", (getter)PyUIGrid_get_grid_size, NULL, "Grid dimensions (grid_x, grid_y)", NULL}, -// {"position", (getter)PyUIGrid_get_position, (setter)PyUIGrid_set_position, "Position of the grid (x, y)", NULL}, -// {"size", (getter)PyUIGrid_get_size, (setter)PyUIGrid_set_size, "Size of the grid (width, height)", NULL}, -// {"center", (getter)PyUIGrid_get_center, (setter)PyUIGrid_set_center, "Grid coordinate at the center of the Grid's view (pan)", NULL}, -// -// {"entities", (getter)PyUIGrid_get_children, NULL, "EntityCollection of entities on this grid", NULL}, -// -// {"x", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "top-left corner X-coordinate", (void*)0}, -// {"y", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "top-left corner Y-coordinate", (void*)1}, -// {"w", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "visible widget width", (void*)2}, -// {"h", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "visible widget height", (void*)3}, -// {"center_x", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "center of the view X-coordinate", (void*)4}, -// {"center_y", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "center of the view Y-coordinate", (void*)5}, -// {"zoom", (getter)PyUIGrid_get_float_member, (setter)PyUIGrid_set_float_member, "zoom factor for displaying the Grid", (void*)6}, -// -// {"click", (getter)PyUIDrawable_get_click, (setter)PyUIDrawable_set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UIGRID}, -// -// {"texture", (getter)PyUIGrid_get_texture, NULL, "Texture of the grid", NULL}, //TODO 7DRL-day2-item5 -// {NULL} /* Sentinel */ -//}; -// -// -///* // TODO standard pointer would need deleted, but I opted for a shared pointer. tp_dealloc currently not even defined in the PyTypeObject -//static void PyUIGrid_dealloc(PyUIGridObject* self) { -// delete self->data; // Clean up the allocated UIGrid object -// Py_TYPE(self)->tp_free((PyObject*)self); -//} -//*/ -// -// static PyTypeObject PyUIGridType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.Grid", -// .tp_basicsize = sizeof(PyUIGridObject), -// .tp_itemsize = 0, -// //.tp_dealloc = (destructor)[](PyObject* self) -// //{ -// // PyUIGridObject* obj = (PyUIGridObject*)self; -// // obj->data.reset(); -// // Py_TYPE(self)->tp_free(self); -// //}, -// //TODO - PyUIGrid REPR def: -// // .tp_repr = (reprfunc)PyUIGrid_repr, -// //.tp_hash = NULL, -// //.tp_iter -// //.tp_iternext -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("docstring"), -// .tp_methods = PyUIGrid_methods, -// //.tp_members = PyUIGrid_members, -// .tp_getset = PyUIGrid_getsetters, -// //.tp_base = NULL, -// .tp_init = (initproc)PyUIGrid_init, -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyUIGridObject* self = (PyUIGridObject*)type->tp_alloc(type, 0); -// if (self) self->data = std::make_shared(); -// return (PyObject*)self; -// } -// }; -// -// -// /* -// * -// * end PyUIGrid defs -// * -// */ -// -// PyUIEntity_init defined here because it depends on the PyUIGridType (to accept grid optional keyword argument) -//static int PyUIEntity_init(PyUIEntityObject* self, PyObject* args, PyObject* kwds) { -// static const char* keywords[] = { "x", "y", "texture", "sprite_index", "grid", nullptr }; -// float x = 0.0f, y = 0.0f, scale = 1.0f; -// int sprite_index = -1; -// PyObject* texture = NULL; -// PyObject* grid = NULL; -// -// if (!PyArg_ParseTupleAndKeywords(args, kwds, "ffOi|O", -// const_cast(keywords), &x, &y, &texture, &sprite_index, &grid)) -// { -// return -1; -// } -// -// // check types for texture -// // -// // Set Texture -// // -// if (texture != NULL && !PyObject_IsInstance(texture, (PyObject*)&PyTextureType)){ -// PyErr_SetString(PyExc_TypeError, "texture must be a mcrfpy.Texture instance"); -// return -1; -// } /*else if (texture != NULL) // this section needs to go; texture isn't optional and isn't managed by the UI objects anymore -// { -// self->texture = texture; -// Py_INCREF(texture); -// } else -// { -// // default tex? -// }*/ -// -// if (grid != NULL && !PyObject_IsInstance(grid, (PyObject*)&PyUIGridType)) { -// PyErr_SetString(PyExc_TypeError, "grid must be a mcrfpy.Grid instance"); -// return -1; -// } -// -// auto pytexture = (PyTextureObject*)texture; -// if (grid == NULL) -// self->data = std::make_shared(); -// else -// self->data = std::make_shared(*((PyUIGridObject*)grid)->data); -// -// // TODO - PyTextureObjects and IndexTextures are a little bit of a mess with shared/unshared pointers -// self->data->sprite = UISprite(pytexture->data, sprite_index, sf::Vector2f(0,0), 1.0); -// self->data->position = sf::Vector2f(x, y); -// if (grid != NULL) { -// PyUIGridObject* pygrid = (PyUIGridObject*)grid; -// self->data->grid = pygrid->data; -// // todone - on creation of Entity with Grid assignment, also append it to the entity list -// pygrid->data->entities->push_back(self->data); -// } -// return 0; -//} -// -///* -// * -// * Begin PyUIEntityCollectionIter defs -// * -// */ -// typedef struct { -// PyObject_HEAD -// std::shared_ptr>> data; -// int index; -// int start_size; -// } PyUIEntityCollectionIterObject; -// -// static int PyUIEntityCollectionIter_init(PyUIEntityCollectionIterObject* self, PyObject* args, PyObject* kwds) -// { -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return -1; -// } -// -// static PyObject* PyUIEntityCollectionIter_next(PyUIEntityCollectionIterObject* self) -// { -// if (self->data->size() != self->start_size) -// { -// PyErr_SetString(PyExc_RuntimeError, "collection changed size during iteration"); -// return NULL; -// } -// -// if (self->index > self->start_size - 1) -// { -// PyErr_SetNone(PyExc_StopIteration); -// return NULL; -// } -// self->index++; -// auto vec = self->data.get(); -// if (!vec) -// { -// PyErr_SetString(PyExc_RuntimeError, "the collection store returned a null pointer"); -// return NULL; -// } -// // Advance list iterator since Entities are not stored in a vector (if this code even worked) -// // vectors only: //auto target = (*vec)[self->index-1]; -// //auto l_front = (*vec).begin(); -// //std::advance(l_front, self->index-1); -// -// // TODO build PyObject* of the correct UIDrawable subclass to return -// //return py_instance(target); -// return NULL; -// } -// -// static PyObject* PyUIEntityCollectionIter_repr(PyUIEntityCollectionIterObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// ss << "data->size() << " child objects, @ index " << self->index << ")>"; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// static PyTypeObject PyUIEntityCollectionIterType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.UICollectionIter", -// .tp_basicsize = sizeof(PyUIEntityCollectionIterObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUIEntityCollectionIterObject* obj = (PyUIEntityCollectionIterObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUIEntityCollectionIter_repr, -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("Iterator for a collection of UI objects"), -// .tp_iternext = (iternextfunc)PyUIEntityCollectionIter_next, -// //.tp_getset = PyUIEntityCollection_getset, -// .tp_init = (initproc)PyUIEntityCollectionIter_init, // just raise an exception -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return NULL; -// } -// }; -// -// /* -// * -// * End PyUIEntityCollectionIter defs -// * -// */ -// -///* -// * -// * Begin PyUIEntityCollection defs -// * -// */ -// typedef struct { -// PyObject_HEAD -// std::shared_ptr>> data; -// std::shared_ptr grid; -// } PyUIEntityCollectionObject; -// -// static Py_ssize_t PyUIEntityCollection_len(PyUIEntityCollectionObject* self) { -// return self->data->size(); -// } -// -// static PyObject* PyUIEntityCollection_getitem(PyUIEntityCollectionObject* self, Py_ssize_t index) { -// // build a Python version of item at self->data[index] -// // Copy pasted:: -// auto vec = self->data.get(); -// if (!vec) -// { -// PyErr_SetString(PyExc_RuntimeError, "the collection store returned a null pointer"); -// return NULL; -// } -// while (index < 0) index += self->data->size(); -// if (index > self->data->size() - 1) -// { -// PyErr_SetString(PyExc_IndexError, "EntityCollection index out of range"); -// return NULL; -// } -// auto l_begin = (*vec).begin(); -// std::advance(l_begin, index); -// auto target = *l_begin; //auto target = (*vec)[index]; -// //RET_PY_INSTANCE(target); -// // construct and return an entity object that points directly into the UIGrid's entity vector -// PyUIEntityObject* o = (PyUIEntityObject*)((&PyUIEntityType)->tp_alloc(&PyUIEntityType, 0)); -// auto p = std::static_pointer_cast(target); -// o->data = p; -// return (PyObject*)o; -// return NULL; -// -// -// } -// -// static PySequenceMethods PyUIEntityCollection_sqmethods = { -// .sq_length = (lenfunc)PyUIEntityCollection_len, -// .sq_item = (ssizeargfunc)PyUIEntityCollection_getitem, -// //.sq_item_by_index = PyUIEntityCollection_getitem -// //.sq_slice - return a subset of the iterable -// //.sq_ass_item - called when `o[x] = y` is executed (x is any object type) -// //.sq_ass_slice - cool; no thanks, for now -// //.sq_contains - called when `x in o` is executed -// //.sq_ass_item_by_index - called when `o[x] = y` is executed (x is explictly an integer) -// }; -// -// static PyObject* PyUIEntityCollection_append(PyUIEntityCollectionObject* self, PyObject* o) -// { -// // if not UIDrawable subclass, reject it -// // self->data->push_back( c++ object inside o ); -// -// // this would be a great use case for .tp_base -// if (!PyObject_IsInstance(o, (PyObject*)&PyUIEntityType)) -// { -// PyErr_SetString(PyExc_TypeError, "Only Entity objects can be added to EntityCollection"); -// return NULL; -// } -// PyUIEntityObject* entity = (PyUIEntityObject*)o; -// self->data->push_back(entity->data); -// entity->data->grid = self->grid; -// -// Py_INCREF(Py_None); -// return Py_None; -// } -// static PyObject* PyUIEntityCollection_remove(PyUIEntityCollectionObject* self, PyObject* o) -// { -// if (!PyLong_Check(o)) -// { -// PyErr_SetString(PyExc_TypeError, "UICollection.remove requires an integer index to remove"); -// return NULL; -// } -// long index = PyLong_AsLong(o); -// if (index >= self->data->size()) -// { -// PyErr_SetString(PyExc_ValueError, "Index out of range"); -// return NULL; -// } -// else if (index < 0) -// { -// PyErr_SetString(PyExc_NotImplementedError, "reverse indexing is not implemented."); -// return NULL; -// } -// -// // release the shared pointer at correct part of the list -// self->data->erase(std::next(self->data->begin(), index)); -// Py_INCREF(Py_None); -// return Py_None; -// } -// -// static PyMethodDef PyUIEntityCollection_methods[] = { -// {"append", (PyCFunction)PyUIEntityCollection_append, METH_O}, -// //{"extend", (PyCFunction)PyUIEntityCollection_extend, METH_O}, // TODO -// {"remove", (PyCFunction)PyUIEntityCollection_remove, METH_O}, -// {NULL, NULL, 0, NULL} -// }; -// -// static PyObject* PyUIEntityCollection_repr(PyUIEntityCollectionObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// ss << "data->size() << " child objects)>"; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static int PyUIEntityCollection_init(PyUIEntityCollectionObject* self, PyObject* args, PyObject* kwds) -// { -// PyErr_SetString(PyExc_TypeError, "EntityCollection cannot be instantiated: a C++ data source is required."); -// return -1; -// } -// -// static PyObject* PyUIEntityCollection_iter(PyUIEntityCollectionObject* self) -// { -// PyUIEntityCollectionIterObject* iterObj; -// iterObj = (PyUIEntityCollectionIterObject*)PyUIEntityCollectionIterType.tp_alloc(&PyUIEntityCollectionIterType, 0); -// if (iterObj == NULL) { -// return NULL; // Failed to allocate memory for the iterator object -// } -// -// iterObj->data = self->data; -// iterObj->index = 0; -// iterObj->start_size = self->data->size(); -// -// return (PyObject*)iterObj; -// } -// static PyTypeObject PyUIEntityCollectionType = { -// //PyVarObject_/HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.EntityCollection", -// .tp_basicsize = sizeof(PyUIEntityCollectionObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUIEntityCollectionObject* obj = (PyUIEntityCollectionObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUIEntityCollection_repr, -// .tp_as_sequence = &PyUIEntityCollection_sqmethods, -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("Iterable, indexable collection of Entities"), -// .tp_iter = (getiterfunc)PyUIEntityCollection_iter, -// .tp_methods = PyUIEntityCollection_methods, // append, remove -// //.tp_getset = PyUIEntityCollection_getset, -// .tp_init = (initproc)PyUIEntityCollection_init, // just raise an exception -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// // Does PyUIEntityCollectionType need __new__ if it's not supposed to be instantiable by the user? -// // Should I just raise an exception? Or is the uninitialized shared_ptr enough of a blocker? -// PyErr_SetString(PyExc_TypeError, "EntityCollection cannot be instantiated: a C++ data source is required."); -// return NULL; -// } -// }; -// -// // Grid's get_children def must follow the EntityCollection def -// static PyObject* PyUIGrid_get_children(PyUIGridObject* self, void* closure) -// { -// // create PyUICollection instance pointing to self->data->children -// PyUIEntityCollectionObject* o = (PyUIEntityCollectionObject*)PyUIEntityCollectionType.tp_alloc(&PyUIEntityCollectionType, 0); -// if (o) { -// o->data = self->data->entities; // todone. / BUGFIX - entities isn't a shared pointer on UIGrid, what to do? -- I made it a sp>> -// o->grid = self->data; -// } -// return (PyObject*)o; -// } -// -// /* -// * -// * End PyUIEntityCollection defs -// * -// */ -// -// -// -// /* -// * -// * Begin PyUICollectionIter defs -// * -// */ -// typedef struct { -// PyObject_HEAD -// std::shared_ptr>> data; -// int index; -// int start_size; -// } PyUICollectionIterObject; -// -// static int PyUICollectionIter_init(PyUICollectionIterObject* self, PyObject* args, PyObject* kwds) -// { -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return -1; -// } -// -// static PyObject* PyUICollectionIter_next(PyUICollectionIterObject* self) -// { -// if (self->data->size() != self->start_size) -// { -// PyErr_SetString(PyExc_RuntimeError, "collection changed size during iteration"); -// return NULL; -// } -// -// if (self->index > self->start_size - 1) -// { -// PyErr_SetNone(PyExc_StopIteration); -// return NULL; -// } -// self->index++; -// auto vec = self->data.get(); -// if (!vec) -// { -// PyErr_SetString(PyExc_RuntimeError, "the collection store returned a null pointer"); -// return NULL; -// } -// auto target = (*vec)[self->index-1]; -// // TODO build PyObject* of the correct UIDrawable subclass to return -// //return py_instance(target); -// return NULL; -// } -// -// static PyObject* PyUICollectionIter_repr(PyUICollectionIterObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// ss << "data->size() << " child objects, @ index " << self->index << ")>"; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static PyTypeObject PyUICollectionIterType = { -// //PyVarObject_HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.UICollectionIter", -// .tp_basicsize = sizeof(PyUICollectionIterObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUICollectionIterObject* obj = (PyUICollectionIterObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUICollectionIter_repr, -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("Iterator for a collection of UI objects"), -// .tp_iternext = (iternextfunc)PyUICollectionIter_next, -// //.tp_getset = PyUICollection_getset, -// .tp_init = (initproc)PyUICollectionIter_init, // just raise an exception -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return NULL; -// } -// }; -// -// /* -// * -// * End PyUICollectionIter defs -// * -// */ -// -// -// /* -// * -// * Begin PyUICollection defs -// * -// */ -// -// static Py_ssize_t PyUICollection_len(PyUICollectionObject* self) { -// return self->data->size(); -// } -// -// static PyObject* PyUICollection_getitem(PyUICollectionObject* self, Py_ssize_t index) { -// // build a Python version of item at self->data[index] -// // Copy pasted:: -// auto vec = self->data.get(); -// if (!vec) -// { -// PyErr_SetString(PyExc_RuntimeError, "the collection store returned a null pointer"); -// return NULL; -// } -// while (index < 0) index += self->data->size(); -// if (index > self->data->size() - 1) -// { -// PyErr_SetString(PyExc_IndexError, "UICollection index out of range"); -// return NULL; -// } -// auto target = (*vec)[index]; -// RET_PY_INSTANCE(target); -// return NULL; -// -// -// } -// -// static PySequenceMethods PyUICollection_sqmethods = { -// .sq_length = (lenfunc)PyUICollection_len, -// .sq_item = (ssizeargfunc)PyUICollection_getitem, -// //.sq_item_by_index = PyUICollection_getitem -// //.sq_slice - return a subset of the iterable -// //.sq_ass_item - called when `o[x] = y` is executed (x is any object type) -// //.sq_ass_slice - cool; no thanks, for now -// //.sq_contains - called when `x in o` is executed -// //.sq_ass_item_by_index - called when `o[x] = y` is executed (x is explictly an integer) -// }; -// -// static PyObject* PyUICollection_append(PyUICollectionObject* self, PyObject* o) -// { -// // if not UIDrawable subclass, reject it -// // self->data->push_back( c++ object inside o ); -// -// // this would be a great use case for .tp_base -// if (!PyObject_IsInstance(o, (PyObject*)&PyUIFrameType) && -// !PyObject_IsInstance(o, (PyObject*)&PyUISpriteType) && -// !PyObject_IsInstance(o, (PyObject*)&PyUICaptionType) && -// !PyObject_IsInstance(o, (PyObject*)&PyUIGridType) -// ) -// { -// PyErr_SetString(PyExc_TypeError, "Only Frame, Caption, Sprite, and Grid objects can be added to UICollection"); -// return NULL; -// } -// -// if (PyObject_IsInstance(o, (PyObject*)&PyUIFrameType)) -// { -// PyUIFrameObject* frame = (PyUIFrameObject*)o; -// self->data->push_back(frame->data); -// } -// if (PyObject_IsInstance(o, (PyObject*)&PyUICaptionType)) -// { -// PyUICaptionObject* caption = (PyUICaptionObject*)o; -// self->data->push_back(caption->data); -// } -// if (PyObject_IsInstance(o, (PyObject*)&PyUISpriteType)) -// { -// PyUISpriteObject* sprite = (PyUISpriteObject*)o; -// self->data->push_back(sprite->data); -// } -// if (PyObject_IsInstance(o, (PyObject*)&PyUIGridType)) -// { -// PyUIGridObject* grid = (PyUIGridObject*)o; -// self->data->push_back(grid->data); -// } -// -// Py_INCREF(Py_None); -// return Py_None; -// } -// -// static PyObject* PyUICollection_remove(PyUICollectionObject* self, PyObject* o) -// { -// if (!PyLong_Check(o)) -// { -// PyErr_SetString(PyExc_TypeError, "UICollection.remove requires an integer index to remove"); -// return NULL; -// } -// long index = PyLong_AsLong(o); -// if (index >= self->data->size()) -// { -// PyErr_SetString(PyExc_ValueError, "Index out of range"); -// return NULL; -// } -// else if (index < 0) -// { -// PyErr_SetString(PyExc_NotImplementedError, "reverse indexing is not implemented."); -// return NULL; -// } -// -// // release the shared pointer at self->data[index]; -// self->data->erase(self->data->begin() + index); -// Py_INCREF(Py_None); -// return Py_None; -// } -// -// static PyMethodDef PyUICollection_methods[] = { -// {"append", (PyCFunction)PyUICollection_append, METH_O}, -// //{"extend", (PyCFunction)PyUICollection_extend, METH_O}, // TODO -// {"remove", (PyCFunction)PyUICollection_remove, METH_O}, -// {NULL, NULL, 0, NULL} -// }; -// -// static PyObject* PyUICollection_repr(PyUICollectionObject* self) -// { -// std::ostringstream ss; -// if (!self->data) ss << ""; -// else { -// ss << "data->size() << " child objects)>"; -// } -// std::string repr_str = ss.str(); -// return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); -// } -// -// static int PyUICollection_init(PyUICollectionObject* self, PyObject* args, PyObject* kwds) -// { -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return -1; -// } -// -// static PyObject* PyUICollection_iter(PyUICollectionObject* self) -// { -// PyUICollectionIterObject* iterObj; -// iterObj = (PyUICollectionIterObject*)PyUICollectionIterType.tp_alloc(&PyUICollectionIterType, 0); -// if (iterObj == NULL) { -// return NULL; // Failed to allocate memory for the iterator object -// } -// -// iterObj->data = self->data; -// iterObj->index = 0; -// iterObj->start_size = self->data->size(); -// -// return (PyObject*)iterObj; -// } -// -// /* -// static PyGetSetDef PyUICollection_getsetters[] = { -// {NULL} -// }; -// */ -// -// static PyTypeObject PyUICollectionType = { -// //PyVarObject_/HEAD_INIT(NULL, 0) -// .tp_name = "mcrfpy.UICollection", -// .tp_basicsize = sizeof(PyUICollectionObject), -// .tp_itemsize = 0, -// .tp_dealloc = (destructor)[](PyObject* self) -// { -// PyUICollectionObject* obj = (PyUICollectionObject*)self; -// obj->data.reset(); -// Py_TYPE(self)->tp_free(self); -// }, -// .tp_repr = (reprfunc)PyUICollection_repr, -// .tp_as_sequence = &PyUICollection_sqmethods, -// .tp_flags = Py_TPFLAGS_DEFAULT, -// .tp_doc = PyDoc_STR("Iterable, indexable collection of UI objects"), -// .tp_iter = (getiterfunc)PyUICollection_iter, -// .tp_methods = PyUICollection_methods, // append, remove -// //.tp_getset = PyUICollection_getset, -// .tp_init = (initproc)PyUICollection_init, // just raise an exception -// .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* -// { -// // Does PyUICollectionType need __new__ if it's not supposed to be instantiable by the user? -// // Should I just raise an exception? Or is the uninitialized shared_ptr enough of a blocker? -// PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required."); -// return NULL; -// } -// }; -// /* -// * -// * End PyUICollection defs -// * -// */ -// -// static PyObject* PyUIFrame_get_children(PyUIFrameObject* self, void* closure) -// { -// // create PyUICollection instance pointing to self->data->children -// PyUICollectionObject* o = (PyUICollectionObject*)PyUICollectionType.tp_alloc(&PyUICollectionType, 0); -// if (o) -// o->data = self->data->children; -// return (PyObject*)o; -// } -// -// -//} // namespace mcrfpydef diff --git a/src/UICaption.cpp b/src/UICaption.cpp index 68f74ab..ffe3976 100644 --- a/src/UICaption.cpp +++ b/src/UICaption.cpp @@ -21,3 +21,238 @@ PyObjectsEnum UICaption::derived_type() { return PyObjectsEnum::UICAPTION; } + +PyObject* UICaption::get_float_member(PyUICaptionObject* self, void* closure) +{ + auto member_ptr = reinterpret_cast(closure); + if (member_ptr == 0) + return PyFloat_FromDouble(self->data->text.getPosition().x); + else if (member_ptr == 1) + return PyFloat_FromDouble(self->data->text.getPosition().y); + else if (member_ptr == 4) + return PyFloat_FromDouble(self->data->text.getOutlineThickness()); + else if (member_ptr == 5) + return PyLong_FromLong(self->data->text.getCharacterSize()); + else + { + PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); + return nullptr; + } +} + +int UICaption::set_float_member(PyUICaptionObject* self, PyObject* value, void* closure) +{ + float val; + auto member_ptr = reinterpret_cast(closure); + if (PyFloat_Check(value)) + { + val = PyFloat_AsDouble(value); + } + else if (PyLong_Check(value)) + { + val = PyLong_AsLong(value); + } + else + { + PyErr_SetString(PyExc_TypeError, "Value must be an integer."); + return -1; + } + if (member_ptr == 0) //x + self->data->text.setPosition(val, self->data->text.getPosition().y); + else if (member_ptr == 1) //y + self->data->text.setPosition(self->data->text.getPosition().x, val); + else if (member_ptr == 4) //outline + self->data->text.setOutlineThickness(val); + else if (member_ptr == 5) // character size + self->data->text.setCharacterSize(val); + return 0; +} + +PyObject* UICaption::get_vec_member(PyUICaptionObject* self, void* closure) +{ + return PyVector(self->data->text.getPosition()).pyObject(); +} + +int UICaption::set_vec_member(PyUICaptionObject* self, PyObject* value, void* closure) +{ + self->data->text.setPosition(PyVector::fromPy(value)); + return 0; +} + +PyObject* UICaption::get_color_member(PyUICaptionObject* self, void* closure) +{ + // TODO: migrate this code to a switch statement - validate closure & return values in one tighter, more extensible structure + + // validate closure (should be impossible to be wrong, but it's thorough) + auto member_ptr = reinterpret_cast(closure); + if (member_ptr != 0 && member_ptr != 1) + { + PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); + return nullptr; + } + + // TODO: manually calling tp_alloc to create a PyColorObject seems like an antipattern + // fetch correct member data + sf::Color color; + + if (member_ptr == 0) + { + color = self->data->text.getFillColor(); + } + else if (member_ptr == 1) + { + color = self->data->text.getOutlineColor(); + } + + return PyColor(color).pyObject(); +} + +int UICaption::set_color_member(PyUICaptionObject* self, PyObject* value, void* closure) +{ + 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*)&mcrfpydef::PyColorType)) + { + // get value from mcrfpy.Color instance + auto c = ((PyColorObject*)value)->data; + r = c.r; g = c.g; b = c.b; a = c.a; + std::cout << "got " << int(r) << ", " << int(g) << ", " << int(b) << ", " << int(a) << std::endl; + } + else if (!PyTuple_Check(value) || PyTuple_Size(value) < 3 || PyTuple_Size(value) > 4) + { + // reject non-Color, non-tuple value + PyErr_SetString(PyExc_TypeError, "Value must be a tuple of 3 or 4 integers or an mcrfpy.Color object."); + return -1; + } + else // get value from tuples + { + r = PyLong_AsLong(PyTuple_GetItem(value, 0)); + g = PyLong_AsLong(PyTuple_GetItem(value, 1)); + b = PyLong_AsLong(PyTuple_GetItem(value, 2)); + a = 255; + + if (PyTuple_Size(value) == 4) + { + a = PyLong_AsLong(PyTuple_GetItem(value, 3)); + } + } + + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255) + { + PyErr_SetString(PyExc_ValueError, "Color values must be between 0 and 255."); + return -1; + } + + if (member_ptr == 0) + { + self->data->text.setFillColor(sf::Color(r, g, b, a)); + } + else if (member_ptr == 1) + { + self->data->text.setOutlineColor(sf::Color(r, g, b, a)); + } + else + { + PyErr_SetString(PyExc_AttributeError, "Invalid attribute"); + return -1; + } + + return 0; +} + + +//TODO: evaluate use of Resources::caption_buffer... can't I do this with a std::string? +PyObject* UICaption::get_text(PyUICaptionObject* self, void* closure) +{ + Resources::caption_buffer = self->data->text.getString(); + return PyUnicode_FromString(Resources::caption_buffer.c_str()); +} + +int UICaption::set_text(PyUICaptionObject* self, PyObject* value, void* closure) +{ + PyObject* s = PyObject_Str(value); + PyObject * temp_bytes = PyUnicode_AsEncodedString(s, "UTF-8", "strict"); // Owned reference + if (temp_bytes != NULL) { + Resources::caption_buffer = PyBytes_AS_STRING(temp_bytes); // Borrowed pointer + Py_DECREF(temp_bytes); + } + self->data->text.setString(Resources::caption_buffer); + return 0; +} + +PyGetSetDef UICaption::getsetters[] = { + {"x", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "X coordinate of top-left corner", (void*)0}, + {"y", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "Y coordinate of top-left corner", (void*)1}, + {"pos", (getter)UICaption::get_vec_member, (setter)UICaption::set_vec_member, "(x, y) vector", (void*)0}, + //{"w", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "width of the rectangle", (void*)2}, + //{"h", (getter)PyUIFrame_get_float_member, (setter)PyUIFrame_set_float_member, "height of the rectangle", (void*)3}, + {"outline", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "Thickness of the border", (void*)4}, + {"fill_color", (getter)UICaption::get_color_member, (setter)UICaption::set_color_member, "Fill color of the text", (void*)0}, + {"outline_color", (getter)UICaption::get_color_member, (setter)UICaption::set_color_member, "Outline color of the text", (void*)1}, + //{"children", (getter)PyUIFrame_get_children, NULL, "UICollection of objects on top of this one", NULL}, + {"text", (getter)UICaption::get_text, (setter)UICaption::set_text, "The text displayed", NULL}, + {"size", (getter)UICaption::get_float_member, (setter)UICaption::set_float_member, "Text size (integer) in points", (void*)5}, + {"click", (getter)UIDrawable::get_click, (setter)UIDrawable::set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UICAPTION}, + {NULL} +}; + +PyObject* UICaption::repr(PyUICaptionObject* self) +{ + std::ostringstream ss; + if (!self->data) ss << ""; + else { + auto text = self->data->text; + auto fc = text.getFillColor(); + auto oc = text.getOutlineColor(); + ss << ""; + } + std::string repr_str = ss.str(); + return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); +} + +int UICaption::init(PyUICaptionObject* self, PyObject* args, PyObject* kwds) +{ + using namespace mcrfpydef; + static const char* keywords[] = { "x", "y", "text", "font", "fill_color", "outline_color", nullptr }; + float x = 0.0f, y = 0.0f; + char* text; + PyObject* font, fill_color, outline_color; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ffzOOO", + const_cast(keywords), &x, &y, &text, &font, &fill_color, &outline_color)) + { + return -1; + } + + // check types for font, fill_color, outline_color + + std::cout << PyUnicode_AsUTF8(PyObject_Repr(font)) << std::endl; + if (font != NULL && !PyObject_IsInstance(font, (PyObject*)&PyFontType)){ + PyErr_SetString(PyExc_TypeError, "font must be a mcrfpy.Font instance"); + return -1; + } else if (font != NULL) + { + auto font_obj = (PyFontObject*)font; + self->data->text.setFont(font_obj->data->font); + self->font = font; + Py_INCREF(font); + } else + { + // default font + //self->data->text.setFont(Resources::game->getFont()); + } + + self->data->text.setPosition(sf::Vector2f(x, y)); + self->data->text.setString((std::string)text); + self->data->text.setFillColor(sf::Color(0,0,0,255)); + self->data->text.setOutlineColor(sf::Color(128,128,128,255)); + + return 0; +} + diff --git a/src/UICaption.h b/src/UICaption.h index f403813..1a1a40d 100644 --- a/src/UICaption.h +++ b/src/UICaption.h @@ -19,19 +19,25 @@ class UICaption: public UIDrawable public: sf::Text text; void render(sf::Vector2f) override final; - PyObjectsEnum derived_type() override final; // { return PyObjectsEnum::UICaption; }; + PyObjectsEnum derived_type() override final; virtual UIDrawable* click_at(sf::Vector2f point) override final; -}; -//class UICaption; -//typedef struct { -// PyObject_HEAD -// std::shared_ptr data; -// PyObject* font; -//} PyUICaptionObject; + static PyObject* get_float_member(PyUICaptionObject* self, void* closure); + static int set_float_member(PyUICaptionObject* self, PyObject* value, void* closure); + static PyObject* get_vec_member(PyUICaptionObject* self, void* closure); + static int set_vec_member(PyUICaptionObject* self, PyObject* value, void* closure); + static PyObject* get_color_member(PyUICaptionObject* self, void* closure); + static int set_color_member(PyUICaptionObject* self, PyObject* value, void* closure); + static PyObject* get_text(PyUICaptionObject* self, void* closure); + static int set_text(PyUICaptionObject* self, PyObject* value, void* closure); + static PyGetSetDef getsetters[]; + static PyObject* repr(PyUICaptionObject* self); + static int init(PyUICaptionObject* self, PyObject* args, PyObject* kwds); +}; namespace mcrfpydef { //TODO: add this method to class scope; move implementation to .cpp file + /* static PyObject* PyUICaption_get_float_member(PyUICaptionObject* self, void* closure) { auto member_ptr = reinterpret_cast(closure); @@ -49,8 +55,10 @@ namespace mcrfpydef { return nullptr; } } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static int PyUICaption_set_float_member(PyUICaptionObject* self, PyObject* value, void* closure) { float val; @@ -78,8 +86,10 @@ namespace mcrfpydef { self->data->text.setCharacterSize(val); return 0; } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static PyObject* PyUICaption_get_vec_member(PyUICaptionObject* self, void* closure) { return PyVector(self->data->text.getPosition()).pyObject(); @@ -91,8 +101,10 @@ namespace mcrfpydef { self->data->text.setPosition(PyVector::fromPy(value)); return 0; } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static PyObject* PyUICaption_get_color_member(PyUICaptionObject* self, void* closure) { // validate closure (should be impossible to be wrong, but it's thorough) @@ -118,8 +130,10 @@ namespace mcrfpydef { return PyColor(color).pyObject(); } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static int PyUICaption_set_color_member(PyUICaptionObject* self, PyObject* value, void* closure) { auto member_ptr = reinterpret_cast(closure); @@ -173,8 +187,10 @@ namespace mcrfpydef { return 0; } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static PyObject* PyUICaption_get_text(PyUICaptionObject* self, void* closure) { Resources::caption_buffer = self->data->text.getString(); @@ -193,8 +209,10 @@ namespace mcrfpydef { self->data->text.setString(Resources::caption_buffer); return 0; } + */ //TODO: add this static array to class scope; move implementation to .cpp file + /* static PyGetSetDef PyUICaption_getsetters[] = { {"x", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "X coordinate of top-left corner", (void*)0}, {"y", (getter)PyUICaption_get_float_member, (setter)PyUICaption_set_float_member, "Y coordinate of top-left corner", (void*)1}, @@ -210,8 +228,10 @@ namespace mcrfpydef { {"click", (getter)UIDrawable::get_click, (setter)UIDrawable::set_click, "Object called with (x, y, button) when clicked", (void*)PyObjectsEnum::UICAPTION}, {NULL} }; + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static PyObject* PyUICaption_repr(PyUICaptionObject* self) { std::ostringstream ss; @@ -230,8 +250,10 @@ namespace mcrfpydef { std::string repr_str = ss.str(); return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); } + */ //TODO: add this method to class scope; move implementation to .cpp file + /* static int PyUICaption_init(PyUICaptionObject* self, PyObject* args, PyObject* kwds) { //std::cout << "Init called\n"; @@ -271,21 +293,24 @@ namespace mcrfpydef { return 0; } + */ static PyTypeObject PyUICaptionType = { //PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "mcrfpy.Caption", .tp_basicsize = sizeof(PyUICaptionObject), .tp_itemsize = 0, + // TODO - move tp_dealloc to .cpp file as static function (UICaption::dealloc) .tp_dealloc = (destructor)[](PyObject* self) { PyUICaptionObject* obj = (PyUICaptionObject*)self; + // TODO - reevaluate with PyFont usage; UICaption does not own the font // release reference to font object if (obj->font) Py_DECREF(obj->font); obj->data.reset(); Py_TYPE(self)->tp_free(self); }, - .tp_repr = (reprfunc)PyUICaption_repr, + .tp_repr = (reprfunc)UICaption::repr, //.tp_hash = NULL, //.tp_iter //.tp_iternext @@ -293,9 +318,10 @@ namespace mcrfpydef { .tp_doc = PyDoc_STR("docstring"), //.tp_methods = PyUIFrame_methods, //.tp_members = PyUIFrame_members, - .tp_getset = PyUICaption_getsetters, + .tp_getset = UICaption::getsetters, //.tp_base = NULL, - .tp_init = (initproc)PyUICaption_init, + .tp_init = (initproc)UICaption::init, + // TODO - move tp_new to .cpp file as a static function (UICaption::new) .tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject* { PyUICaptionObject* self = (PyUICaptionObject*)type->tp_alloc(type, 0); diff --git a/src/UIDrawable.cpp b/src/UIDrawable.cpp index cd898c4..a710095 100644 --- a/src/UIDrawable.cpp +++ b/src/UIDrawable.cpp @@ -75,4 +75,7 @@ int UIDrawable::set_click(PyObject* self, PyObject* value, void* closure) { return 0; } - +void UIDrawable::click_register(PyObject* callable) +{ + click_callable = std::make_unique(callable); +} diff --git a/src/UIEntity.cpp b/src/UIEntity.cpp index 9e21eaf..abfb8b9 100644 --- a/src/UIEntity.cpp +++ b/src/UIEntity.cpp @@ -1,4 +1,5 @@ #include "UIEntity.h" +#include "UIGrid.h" UIEntity::UIEntity() {} // this will not work lol. TODO remove default constructor by finding the shared pointer inits that use it @@ -19,7 +20,7 @@ PyObject* UIEntity::at(PyUIEntityObject* self, PyObject* o) { return NULL; } - PyUIGridPointStateObject* obj = (PyUIGridPointStateObject*)((&PyUIGridPointStateType)->tp_alloc(&PyUIGridPointStateType, 0)); + PyUIGridPointStateObject* obj = (PyUIGridPointStateObject*)((&mcrfpydef::PyUIGridPointStateType)->tp_alloc(&mcrfpydef::PyUIGridPointStateType, 0)); //auto target = std::static_pointer_cast(target); obj->data = &(self->data->gridstate[y + self->data->grid->grid_x * x]); obj->grid = self->data->grid; @@ -28,7 +29,7 @@ PyObject* UIEntity::at(PyUIEntityObject* self, PyObject* o) { } -int PyUIEntity::init(PyUIEntityObject* self, PyObject* args, PyObject* kwds) { +int UIEntity::init(PyUIEntityObject* self, PyObject* args, PyObject* kwds) { static const char* keywords[] = { "x", "y", "texture", "sprite_index", "grid", nullptr }; float x = 0.0f, y = 0.0f, scale = 1.0f; int sprite_index = -1; @@ -57,7 +58,7 @@ int PyUIEntity::init(PyUIEntityObject* self, PyObject* args, PyObject* kwds) { // default tex? }*/ - if (grid != NULL && !PyObject_IsInstance(grid, (PyObject*)&PyUIGridType)) { + if (grid != NULL && !PyObject_IsInstance(grid, (PyObject*)&mcrfpydef::PyUIGridType)) { PyErr_SetString(PyExc_TypeError, "grid must be a mcrfpy.Grid instance"); return -1; } diff --git a/src/UIEntity.h b/src/UIEntity.h index 8088aff..1f37aa6 100644 --- a/src/UIEntity.h +++ b/src/UIEntity.h @@ -15,6 +15,8 @@ #include "UIGridPoint.h" #include "UIDrawable.h" #include "UIBase.h" +#include "UISprite.h" + class UIGrid; //class UIEntity; diff --git a/src/UIFrame.cpp b/src/UIFrame.cpp index c9f42e8..3452a58 100644 --- a/src/UIFrame.cpp +++ b/src/UIFrame.cpp @@ -1,5 +1,6 @@ #include "UIFrame.h" #include "UICollection.h" +#include "GameEngine.h" UIDrawable* UIFrame::click_at(sf::Vector2f point) { @@ -54,10 +55,10 @@ void UIFrame::render(sf::Vector2f offset) } } -PyObject* PyUIFrame::get_children(PyUIFrameObject* self, void* closure) +PyObject* UIFrame::get_children(PyUIFrameObject* self, void* closure) { // create PyUICollection instance pointing to self->data->children - PyUICollectionObject* o = (PyUICollectionObject*)PyUICollectionType.tp_alloc(&PyUICollectionType, 0); + PyUICollectionObject* o = (PyUICollectionObject*)mcrfpydef::PyUICollectionType.tp_alloc(&mcrfpydef::PyUICollectionType, 0); if (o) o->data = self->data->children; return (PyObject*)o; diff --git a/src/UIGrid.cpp b/src/UIGrid.cpp index 207114b..69f2375 100644 --- a/src/UIGrid.cpp +++ b/src/UIGrid.cpp @@ -1,4 +1,5 @@ #include "UIGrid.h" +#include "GameEngine.h" UIGrid::UIGrid() {} @@ -188,3 +189,12 @@ std::shared_ptr UIGrid::getTexture() { return ptex; } + +UIDrawable* UIGrid::click_at(sf::Vector2f point) +{ + if (click_callable) + { + if(box.getGlobalBounds().contains(point)) return this; + } + return NULL; +} diff --git a/src/UIGridPoint.h b/src/UIGridPoint.h index 147f0d9..4827bd9 100644 --- a/src/UIGridPoint.h +++ b/src/UIGridPoint.h @@ -30,6 +30,7 @@ public: }; class UIGrid; +class UIEntity; typedef struct { PyObject_HEAD diff --git a/src/UISprite.cpp b/src/UISprite.cpp index 1f06be1..47acc11 100644 --- a/src/UISprite.cpp +++ b/src/UISprite.cpp @@ -1,4 +1,5 @@ #include "UISprite.h" +#include "GameEngine.h" UIDrawable* UISprite::click_at(sf::Vector2f point) { diff --git a/src/UISprite.h b/src/UISprite.h index dc9faf8..ce22be8 100644 --- a/src/UISprite.h +++ b/src/UISprite.h @@ -12,6 +12,7 @@ #include "PyVector.h" #include "PyFont.h" #include "UIDrawable.h" +#include "UIBase.h" class UISprite: public UIDrawable {