feat: Complete position argument standardization for all UI classes
- Frame and Sprite now support pos keyword override - Entity now accepts x,y arguments (was pos-only before) - All UI classes now consistently support: - (x, y) positional - ((x, y)) tuple - x=x, y=y keywords - pos=(x,y) keyword - pos=Vector keyword - Improves API consistency and flexibility
This commit is contained in:
parent
c48c91e5d7
commit
75f75d250f
|
@ -4,6 +4,7 @@
|
|||
#include <algorithm>
|
||||
#include "PyObjectUtils.h"
|
||||
#include "PyVector.h"
|
||||
#include "PyPositionHelper.h"
|
||||
|
||||
|
||||
UIEntity::UIEntity()
|
||||
|
@ -70,45 +71,51 @@ PyObject* UIEntity::index(PyUIEntityObject* self, PyObject* Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
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;
|
||||
static const char* keywords[] = { "pos", "texture", "sprite_index", "grid", nullptr };
|
||||
PyObject* pos = NULL; // Must initialize to NULL for optional arguments
|
||||
float scale = 1.0f;
|
||||
int sprite_index = 0; // Default to sprite index 0 instead of -1
|
||||
static const char* keywords[] = { "x", "y", "texture", "sprite_index", "grid", "pos", nullptr };
|
||||
float x = 0.0f, y = 0.0f;
|
||||
int sprite_index = 0; // Default to sprite index 0
|
||||
PyObject* texture = NULL;
|
||||
PyObject* grid = NULL;
|
||||
PyObject* pos_obj = NULL;
|
||||
|
||||
// Try to parse all arguments with keywords
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "|ffOiOO",
|
||||
const_cast<char**>(keywords), &x, &y, &texture, &sprite_index, &grid, &pos_obj))
|
||||
{
|
||||
// If pos was provided, it overrides x,y
|
||||
if (pos_obj && pos_obj != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_obj);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
x = vec->data.x;
|
||||
y = vec->data.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear();
|
||||
|
||||
// Try alternative: pos as first argument
|
||||
static const char* alt_keywords[] = { "pos", "texture", "sprite_index", "grid", nullptr };
|
||||
PyObject* pos = NULL;
|
||||
|
||||
//if (!PyArg_ParseTupleAndKeywords(args, kwds, "ffOi|O",
|
||||
// const_cast<char**>(keywords), &x, &y, &texture, &sprite_index, &grid))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOiO",
|
||||
const_cast<char**>(keywords), &pos, &texture, &sprite_index, &grid))
|
||||
const_cast<char**>(alt_keywords), &pos, &texture, &sprite_index, &grid))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Handle position - default to (0, 0) if not provided
|
||||
PyVectorObject* pos_result = nullptr;
|
||||
// Parse position
|
||||
if (pos && pos != Py_None) {
|
||||
pos_result = PyVector::from_arg(pos);
|
||||
if (!pos_result)
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a mcrfpy.Vector instance or arguments to mcrfpy.Vector.__init__");
|
||||
PyVectorObject* vec = PyVector::from_arg(pos);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
// Create default position (0, 0)
|
||||
PyObject* vector_class = PyObject_GetAttrString(McRFPy_API::mcrf_module, "Vector");
|
||||
if (vector_class) {
|
||||
PyObject* pos_obj = PyObject_CallFunction(vector_class, "ff", 0.0f, 0.0f);
|
||||
Py_DECREF(vector_class);
|
||||
if (pos_obj) {
|
||||
pos_result = (PyVectorObject*)pos_obj;
|
||||
}
|
||||
}
|
||||
if (!pos_result) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to create default position vector");
|
||||
return -1;
|
||||
x = vec->data.x;
|
||||
y = vec->data.y;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,12 +162,10 @@ int UIEntity::init(PyUIEntityObject* self, PyObject* args, PyObject* kwds) {
|
|||
// Create an empty sprite for testing
|
||||
self->data->sprite = UISprite();
|
||||
}
|
||||
self->data->position = pos_result->data;
|
||||
|
||||
// Clean up the position object if we created it
|
||||
if (!pos || pos == Py_None) {
|
||||
Py_DECREF(pos_result);
|
||||
}
|
||||
// Set position
|
||||
self->data->position = sf::Vector2f(x, y);
|
||||
self->data->collision_pos = sf::Vector2i(static_cast<int>(x), static_cast<int>(y));
|
||||
|
||||
if (grid != NULL) {
|
||||
PyUIGridObject* pygrid = (PyUIGridObject*)grid;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "UISprite.h"
|
||||
#include "UIGrid.h"
|
||||
#include "McRFPy_API.h"
|
||||
#include "PyPositionHelper.h"
|
||||
|
||||
UIDrawable* UIFrame::click_at(sf::Vector2f point)
|
||||
{
|
||||
|
@ -301,34 +302,51 @@ PyObject* UIFrame::repr(PyUIFrameObject* self)
|
|||
|
||||
int UIFrame::init(PyUIFrameObject* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
//std::cout << "Init called\n";
|
||||
const char* keywords[] = { "x", "y", "w", "h", "fill_color", "outline_color", "outline", "children", "click", nullptr };
|
||||
// Parse position using the standardized helper
|
||||
auto pos_result = PyPositionHelper::parse_position(args, kwds);
|
||||
|
||||
const char* keywords[] = { "x", "y", "w", "h", "fill_color", "outline_color", "outline", "children", "click", "pos", 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;
|
||||
PyObject* children_arg = 0;
|
||||
PyObject* click_handler = 0;
|
||||
PyObject* pos_obj = 0;
|
||||
|
||||
// First try to parse as (x, y, w, h, ...)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ffffOOfOO", const_cast<char**>(keywords), &x, &y, &w, &h, &fill_color, &outline_color, &outline, &children_arg, &click_handler))
|
||||
// Try to parse all arguments including x, y
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "|ffffOOfOOO", const_cast<char**>(keywords),
|
||||
&x, &y, &w, &h, &fill_color, &outline_color, &outline, &children_arg, &click_handler, &pos_obj))
|
||||
{
|
||||
// If pos was provided, it overrides x,y
|
||||
if (pos_obj && pos_obj != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_obj);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
x = vec->data.x;
|
||||
y = vec->data.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear(); // Clear the error
|
||||
|
||||
// Try to parse as ((x,y), w, h, ...) or (Vector, w, h, ...)
|
||||
PyObject* pos_obj = nullptr;
|
||||
const char* alt_keywords[] = { "pos", "w", "h", "fill_color", "outline_color", "outline", "children", "click", nullptr };
|
||||
PyObject* pos_arg = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OffOOfOO", const_cast<char**>(alt_keywords),
|
||||
&pos_obj, &w, &h, &fill_color, &outline_color, &outline, &children_arg, &click_handler))
|
||||
&pos_arg, &w, &h, &fill_color, &outline_color, &outline, &children_arg, &click_handler))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert position argument to x, y if provided
|
||||
if (pos_obj && pos_obj != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_obj);
|
||||
if (pos_arg && pos_arg != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_arg);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "First argument must be a tuple (x, y) or Vector when not providing x, y separately");
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
x = vec->data.x;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "UISprite.h"
|
||||
#include "GameEngine.h"
|
||||
#include "PyVector.h"
|
||||
#include "PyPositionHelper.h"
|
||||
|
||||
UIDrawable* UISprite::click_at(sf::Vector2f point)
|
||||
{
|
||||
|
@ -297,34 +298,47 @@ PyObject* UISprite::repr(PyUISpriteObject* self)
|
|||
|
||||
int UISprite::init(PyUISpriteObject* self, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
//std::cout << "Init called\n";
|
||||
static const char* keywords[] = { "x", "y", "texture", "sprite_index", "scale", "click", nullptr };
|
||||
static const char* keywords[] = { "x", "y", "texture", "sprite_index", "scale", "click", "pos", nullptr };
|
||||
float x = 0.0f, y = 0.0f, scale = 1.0f;
|
||||
int sprite_index = 0;
|
||||
PyObject* texture = NULL;
|
||||
PyObject* click_handler = NULL;
|
||||
PyObject* pos_obj = NULL;
|
||||
|
||||
// First try to parse as (x, y, texture, ...)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ffOifO",
|
||||
const_cast<char**>(keywords), &x, &y, &texture, &sprite_index, &scale, &click_handler))
|
||||
// Try to parse all arguments with keywords
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "|ffOifOO",
|
||||
const_cast<char**>(keywords), &x, &y, &texture, &sprite_index, &scale, &click_handler, &pos_obj))
|
||||
{
|
||||
// If pos was provided, it overrides x,y
|
||||
if (pos_obj && pos_obj != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_obj);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
x = vec->data.x;
|
||||
y = vec->data.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PyErr_Clear(); // Clear the error
|
||||
|
||||
// Try to parse as ((x,y), texture, ...) or (Vector, texture, ...)
|
||||
PyObject* pos_obj = nullptr;
|
||||
// Try alternative: first arg is pos tuple/Vector
|
||||
const char* alt_keywords[] = { "pos", "texture", "sprite_index", "scale", "click", nullptr };
|
||||
PyObject* pos = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOifO", const_cast<char**>(alt_keywords),
|
||||
&pos_obj, &texture, &sprite_index, &scale, &click_handler))
|
||||
&pos, &texture, &sprite_index, &scale, &click_handler))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert position argument to x, y
|
||||
if (pos_obj) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos_obj);
|
||||
if (pos && pos != Py_None) {
|
||||
PyVectorObject* vec = PyVector::from_arg(pos);
|
||||
if (!vec) {
|
||||
PyErr_SetString(PyExc_TypeError, "First argument must be a tuple (x, y) or Vector when not providing x, y separately");
|
||||
PyErr_SetString(PyExc_TypeError, "pos must be a Vector or tuple (x, y)");
|
||||
return -1;
|
||||
}
|
||||
x = vec->data.x;
|
||||
|
|
Loading…
Reference in New Issue