164 lines
6.1 KiB
C++
164 lines
6.1 KiB
C++
#pragma once
|
|
#include "Python.h"
|
|
#include "PyVector.h"
|
|
#include "McRFPy_API.h"
|
|
|
|
// Helper class for standardized position argument parsing across UI classes
|
|
class PyPositionHelper {
|
|
public:
|
|
// Template structure for parsing results
|
|
struct ParseResult {
|
|
float x = 0.0f;
|
|
float y = 0.0f;
|
|
bool has_position = false;
|
|
};
|
|
|
|
struct ParseResultInt {
|
|
int x = 0;
|
|
int y = 0;
|
|
bool has_position = false;
|
|
};
|
|
|
|
// Parse position from multiple formats for UI class constructors
|
|
// Supports: (x, y), x=x, y=y, ((x,y)), (pos=(x,y)), (Vector), pos=Vector
|
|
static ParseResult parse_position(PyObject* args, PyObject* kwds,
|
|
int* arg_index = nullptr)
|
|
{
|
|
ParseResult result;
|
|
float x = 0.0f, y = 0.0f;
|
|
PyObject* pos_obj = nullptr;
|
|
int start_index = arg_index ? *arg_index : 0;
|
|
|
|
// Check for positional tuple (x, y) first
|
|
if (!kwds && PyTuple_Size(args) > start_index + 1) {
|
|
PyObject* first = PyTuple_GetItem(args, start_index);
|
|
PyObject* second = PyTuple_GetItem(args, start_index + 1);
|
|
|
|
// Check if both are numbers
|
|
if ((PyFloat_Check(first) || PyLong_Check(first)) &&
|
|
(PyFloat_Check(second) || PyLong_Check(second))) {
|
|
x = PyFloat_Check(first) ? PyFloat_AsDouble(first) : PyLong_AsLong(first);
|
|
y = PyFloat_Check(second) ? PyFloat_AsDouble(second) : PyLong_AsLong(second);
|
|
result.x = x;
|
|
result.y = y;
|
|
result.has_position = true;
|
|
if (arg_index) *arg_index += 2;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Check for single positional argument that might be tuple or Vector
|
|
if (!kwds && PyTuple_Size(args) > start_index) {
|
|
PyObject* first = PyTuple_GetItem(args, start_index);
|
|
PyVectorObject* vec = PyVector::from_arg(first);
|
|
if (vec) {
|
|
result.x = vec->data.x;
|
|
result.y = vec->data.y;
|
|
result.has_position = true;
|
|
if (arg_index) *arg_index += 1;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Try keyword arguments
|
|
if (kwds) {
|
|
PyObject* x_obj = PyDict_GetItemString(kwds, "x");
|
|
PyObject* y_obj = PyDict_GetItemString(kwds, "y");
|
|
PyObject* pos_kw = PyDict_GetItemString(kwds, "pos");
|
|
|
|
if (x_obj && y_obj) {
|
|
if ((PyFloat_Check(x_obj) || PyLong_Check(x_obj)) &&
|
|
(PyFloat_Check(y_obj) || PyLong_Check(y_obj))) {
|
|
result.x = PyFloat_Check(x_obj) ? PyFloat_AsDouble(x_obj) : PyLong_AsLong(x_obj);
|
|
result.y = PyFloat_Check(y_obj) ? PyFloat_AsDouble(y_obj) : PyLong_AsLong(y_obj);
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (pos_kw) {
|
|
PyVectorObject* vec = PyVector::from_arg(pos_kw);
|
|
if (vec) {
|
|
result.x = vec->data.x;
|
|
result.y = vec->data.y;
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Parse integer position for Grid.at() and similar
|
|
static ParseResultInt parse_position_int(PyObject* args, PyObject* kwds)
|
|
{
|
|
ParseResultInt result;
|
|
|
|
// Check for positional tuple (x, y) first
|
|
if (!kwds && PyTuple_Size(args) >= 2) {
|
|
PyObject* first = PyTuple_GetItem(args, 0);
|
|
PyObject* second = PyTuple_GetItem(args, 1);
|
|
|
|
if (PyLong_Check(first) && PyLong_Check(second)) {
|
|
result.x = PyLong_AsLong(first);
|
|
result.y = PyLong_AsLong(second);
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Check for single tuple argument
|
|
if (!kwds && PyTuple_Size(args) == 1) {
|
|
PyObject* first = PyTuple_GetItem(args, 0);
|
|
if (PyTuple_Check(first) && PyTuple_Size(first) == 2) {
|
|
PyObject* x_obj = PyTuple_GetItem(first, 0);
|
|
PyObject* y_obj = PyTuple_GetItem(first, 1);
|
|
if (PyLong_Check(x_obj) && PyLong_Check(y_obj)) {
|
|
result.x = PyLong_AsLong(x_obj);
|
|
result.y = PyLong_AsLong(y_obj);
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try keyword arguments
|
|
if (kwds) {
|
|
PyObject* x_obj = PyDict_GetItemString(kwds, "x");
|
|
PyObject* y_obj = PyDict_GetItemString(kwds, "y");
|
|
PyObject* pos_obj = PyDict_GetItemString(kwds, "pos");
|
|
|
|
if (x_obj && y_obj && PyLong_Check(x_obj) && PyLong_Check(y_obj)) {
|
|
result.x = PyLong_AsLong(x_obj);
|
|
result.y = PyLong_AsLong(y_obj);
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
|
|
if (pos_obj && PyTuple_Check(pos_obj) && PyTuple_Size(pos_obj) == 2) {
|
|
PyObject* x_val = PyTuple_GetItem(pos_obj, 0);
|
|
PyObject* y_val = PyTuple_GetItem(pos_obj, 1);
|
|
if (PyLong_Check(x_val) && PyLong_Check(y_val)) {
|
|
result.x = PyLong_AsLong(x_val);
|
|
result.y = PyLong_AsLong(y_val);
|
|
result.has_position = true;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Error message helper
|
|
static void set_position_error() {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Position can be specified as: (x, y), x=x, y=y, ((x,y)), pos=(x,y), or pos=Vector");
|
|
}
|
|
|
|
static void set_position_int_error() {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"Position must be specified as: (x, y), x=x, y=y, ((x,y)), or pos=(x,y) with integer values");
|
|
}
|
|
}; |