Squashed commit of the following: [standardize_vector_handling]
closes #13 Deferring class standardization for the UI.h overhaul. commit5edebdd643
Author: John McCardle <mccardle.john@gmail.com> Date: Sun Mar 31 14:21:07 2024 -0400 PyVector init should be pretty reliable now commitc13e185289
Author: John McCardle <mccardle.john@gmail.com> Date: Sun Mar 31 13:51:29 2024 -0400 PyColor fix - Init corrections commit8871f6be6e
Author: John McCardle <mccardle.john@gmail.com> Date: Sat Mar 30 22:51:55 2024 -0400 Parse arguments: no args & Vector object args work, tuples and bare numerics still do not commit1c12e8719c
Author: John McCardle <mccardle.john@gmail.com> Date: Sat Mar 30 22:32:28 2024 -0400 Not bad for a quick first salvo, but I cannot figure out why init isn't cooperating.
This commit is contained in:
parent
f82508b753
commit
fbf263a038
|
@ -56,7 +56,7 @@ PyObject* PyInit_mcrfpy()
|
|||
using namespace mcrfpydef;
|
||||
PyTypeObject* pytypes[] = {
|
||||
/*SFML exposed types*/
|
||||
&PyColorType, /*&PyLinkedColorType,*/ &PyFontType, &PyTextureType,
|
||||
&PyColorType, /*&PyLinkedColorType,*/ &PyFontType, &PyTextureType, &PyVectorType,
|
||||
|
||||
/*UI widgets*/
|
||||
&PyUICaptionType, &PyUISpriteType, &PyUIFrameType, &PyUIEntityType, &PyUIGridType,
|
||||
|
|
|
@ -65,77 +65,62 @@ PyObject* PyColor::repr(PyObject* obj)
|
|||
}
|
||||
|
||||
|
||||
int PyColor::init(PyColorObject* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
using namespace mcrfpydef;
|
||||
int PyColor::init(PyColorObject* self, PyObject* args, PyObject* kwds) {
|
||||
//using namespace mcrfpydef;
|
||||
static const char* keywords[] = { "r", "g", "b", "a", nullptr };
|
||||
PyObject* leader;
|
||||
int r = -1, g = -1, b = -1, a = 255;
|
||||
if (!PyArg_ParseTupleAndKeywords, args, kwds, "O|iii", leader, &g, &b, &a)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "mcrfpy.Color requires a color object, 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iii", const_cast<char**>(keywords), &leader, &g, &b, &a)) {
|
||||
PyErr_SetString(PyExc_TypeError, "mcrfpy.Color requires a 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if the "r" arg is already a color, yoink that color value
|
||||
if (PyObject_IsInstance(leader, (PyObject*)&PyColorType))
|
||||
{
|
||||
self->data = ((PyColorObject*)leader)->data;
|
||||
return 0;
|
||||
}
|
||||
// else if the "r" arg is a 3-tuple, initialize to (r, g, b, 255)
|
||||
// (if the "r" arg is a 4-tuple, initialize to (r, g, b, a))
|
||||
else if (PyTuple_Check(leader))
|
||||
{
|
||||
if (PyTuple_Size(leader) < 3 && PyTuple_Size(leader) > 4)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid tuple length: mcrfpy.Color requires a color object, 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
//std::cout << "Arg parsing succeeded. Values: " << r << " " << g << " " << b << " " << a <<std::endl;
|
||||
//std::cout << PyUnicode_AsUTF8(PyObject_Repr(leader)) << std::endl;
|
||||
// Tuple cases
|
||||
if (PyTuple_Check(leader)) {
|
||||
Py_ssize_t tupleSize = PyTuple_Size(leader);
|
||||
if (tupleSize < 3 || tupleSize > 4) {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid tuple length: mcrfpy.Color requires a 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
return -1;
|
||||
}
|
||||
r = PyLong_AsLong(PyTuple_GetItem(leader, 0));
|
||||
g = PyLong_AsLong(PyTuple_GetItem(leader, 1));
|
||||
b = PyLong_AsLong(PyTuple_GetItem(leader, 2));
|
||||
//a = 255; //default value
|
||||
|
||||
if (PyTuple_Size(leader) == 4)
|
||||
{
|
||||
if (tupleSize == 4) {
|
||||
a = PyLong_AsLong(PyTuple_GetItem(leader, 3));
|
||||
}
|
||||
}
|
||||
// Color name (not implemented yet)
|
||||
else if (PyUnicode_Check(leader)) {
|
||||
PyErr_SetString(PyExc_NotImplementedError, "Color names aren't ready yet");
|
||||
return -1;
|
||||
}
|
||||
// Check if the leader is actually an integer for the r value
|
||||
else if (PyLong_Check(leader)) {
|
||||
r = PyLong_AsLong(leader);
|
||||
// Additional validation not shown; g, b are required to be parsed
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "mcrfpy.Color requires a 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// value validation
|
||||
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;
|
||||
}
|
||||
self->data = sf::Color(r, g, b, a);
|
||||
}
|
||||
// else if the "r" arg is a string, initialize to {color lookup function value}
|
||||
else if (PyUnicode_Check(leader))
|
||||
{
|
||||
PyErr_SetString(Py_NotImplemented, "Color names aren't ready yet");
|
||||
return -1;
|
||||
}
|
||||
// else -
|
||||
else if (!PyLong_Check(leader))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "mcrfpy.Color requires a color object, 3-tuple, 4-tuple, color name, or integer values within 0-255 (r, g, b, optionally a)");
|
||||
return -1;
|
||||
}
|
||||
r = PyLong_AsLong(leader);
|
||||
// assert r, g, b are present and ints in range (0, 255) - if not enough ints were provided to the args/kwds parsed by init, g and/or b will still hold -1.
|
||||
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255)
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "R, G, B values are required, A value is optional; Color values must be between 0 and 255.");
|
||||
// Validate color values
|
||||
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;
|
||||
}
|
||||
|
||||
self->data = sf::Color(r, g, b, a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* PyColor::pynew(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
return (PyObject*)type->tp_alloc(type, 0);
|
||||
auto obj = (PyObject*)type->tp_alloc(type, 0);
|
||||
//Py_INCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
PyObject* PyColor::get_member(PyObject* obj, void* closure)
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
#include "PyVector.h"
|
||||
|
||||
PyGetSetDef PyVector::getsetters[] = {
|
||||
{"x", (getter)PyVector::get_member, (setter)PyVector::set_member, "X/horizontal component", (void*)0},
|
||||
{"y", (getter)PyVector::get_member, (setter)PyVector::set_member, "Y/vertical component", (void*)1},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyVector::PyVector(sf::Vector2f target)
|
||||
:data(target) {}
|
||||
|
||||
PyObject* PyVector::pyObject()
|
||||
{
|
||||
PyObject* obj = PyType_GenericAlloc(&mcrfpydef::PyVectorType, 0);
|
||||
Py_INCREF(obj);
|
||||
PyVectorObject* self = (PyVectorObject*)obj;
|
||||
self->data = data;
|
||||
return obj;
|
||||
}
|
||||
|
||||
sf::Vector2f PyVector::fromPy(PyObject* obj)
|
||||
{
|
||||
PyVectorObject* self = (PyVectorObject*)obj;
|
||||
return self->data;
|
||||
}
|
||||
|
||||
sf::Vector2f PyVector::fromPy(PyVectorObject* self)
|
||||
{
|
||||
return self->data;
|
||||
}
|
||||
|
||||
Py_hash_t PyVector::hash(PyObject* obj)
|
||||
{
|
||||
auto self = (PyVectorObject*)obj;
|
||||
Py_hash_t value = 0;
|
||||
value += self->data.x;
|
||||
value << 8; value += self->data.y;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
PyObject* PyVector::repr(PyObject* obj)
|
||||
{
|
||||
PyVectorObject* self = (PyVectorObject*)obj;
|
||||
std::ostringstream ss;
|
||||
sf::Vector2f v = self->data;
|
||||
ss << "<Vector (" << v.x << ", " << v.y << ")>";
|
||||
|
||||
std::string repr_str = ss.str();
|
||||
return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace");
|
||||
}
|
||||
|
||||
|
||||
int PyVector::init(PyVectorObject* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
using namespace mcrfpydef;
|
||||
static const char* keywords[] = { "x", "y", nullptr };
|
||||
PyObject* leader = NULL;
|
||||
float x=0, y=0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Of", const_cast<char**>(keywords), &leader, &y))
|
||||
{
|
||||
//PyErr_SetString(PyExc_TypeError, "mcrfpy.Vector requires a 2-tuple or two numeric values");
|
||||
return -1;
|
||||
}
|
||||
if (leader == NULL || leader == Py_None)
|
||||
{
|
||||
self->data = sf::Vector2f();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyTuple_Check(leader))
|
||||
{
|
||||
if (PyTuple_Size(leader) != 2)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid tuple length: mcrfpy.Vector requires a 2-tuple");
|
||||
return -1;
|
||||
}
|
||||
x = PyFloat_AsDouble(PyTuple_GetItem(leader, 0));
|
||||
y = PyFloat_AsDouble(PyTuple_GetItem(leader, 1));
|
||||
|
||||
self->data = sf::Vector2f(x, y);
|
||||
return 0;
|
||||
}
|
||||
// else -
|
||||
else if (!PyFloat_Check(leader) && !(PyLong_Check(leader)))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "mcrfpy.Vector requires a 2-tuple or two numeric values");
|
||||
return -1;
|
||||
}
|
||||
if (PyFloat_Check(leader)) x = PyFloat_AsDouble(leader);
|
||||
else x = PyLong_AsDouble(leader);
|
||||
self->data = sf::Vector2f(x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* PyVector::pynew(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
return (PyObject*)type->tp_alloc(type, 0);
|
||||
}
|
||||
|
||||
PyObject* PyVector::get_member(PyObject* obj, void* closure)
|
||||
{
|
||||
// TODO
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
int PyVector::set_member(PyObject* obj, PyObject* value, void* closure)
|
||||
{
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include "Common.h"
|
||||
#include "Python.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
sf::Vector2f data;
|
||||
} PyVectorObject;
|
||||
|
||||
class PyVector
|
||||
{
|
||||
public:
|
||||
sf::Vector2f data;
|
||||
PyVector(sf::Vector2f);
|
||||
PyVector();
|
||||
PyObject* pyObject();
|
||||
static sf::Vector2f fromPy(PyObject*);
|
||||
static sf::Vector2f fromPy(PyVectorObject*);
|
||||
static PyObject* repr(PyObject*);
|
||||
static Py_hash_t hash(PyObject*);
|
||||
static int init(PyVectorObject*, PyObject*, PyObject*);
|
||||
static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL);
|
||||
static PyObject* get_member(PyObject*, void*);
|
||||
static int set_member(PyObject*, PyObject*, void*);
|
||||
|
||||
static PyGetSetDef getsetters[];
|
||||
};
|
||||
|
||||
namespace mcrfpydef {
|
||||
static PyTypeObject PyVectorType = {
|
||||
.tp_name = "mcrfpy.Vector",
|
||||
.tp_basicsize = sizeof(PyVectorObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_repr = PyVector::repr,
|
||||
.tp_hash = PyVector::hash,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = PyDoc_STR("SFML Vector Object"),
|
||||
.tp_getset = PyVector::getsetters,
|
||||
.tp_init = (initproc)PyVector::init,
|
||||
.tp_new = PyVector::pynew,
|
||||
};
|
||||
}
|
13
src/UI.h
13
src/UI.h
|
@ -12,6 +12,7 @@
|
|||
#include "PyTexture.h"
|
||||
#include "PyColor.h"
|
||||
//#include "PyLinkedColor.h"
|
||||
#include "PyVector.h"
|
||||
|
||||
enum PyObjectsEnum : int
|
||||
{
|
||||
|
@ -587,6 +588,17 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c
|
|||
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)
|
||||
|
@ -730,6 +742,7 @@ static int PyUIDrawable_set_click(PyUIGridObject* self, PyObject* value, void* c
|
|||
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},
|
||||
|
|
Loading…
Reference in New Issue