Fix #221: Add grid_pos and grid_size properties for Grid children

UIDrawables placed in a Grid's children collection now have:
- grid_pos: Position in tile coordinates (get/set)
- grid_size: Size in tile coordinates (get/set)

Raises RuntimeError if accessed when parent is not a Grid.
UIGrid only gets grid_pos (grid_size conflicts with existing property).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
John McCardle 2026-01-19 22:23:47 -05:00
commit 14a6520593
10 changed files with 251 additions and 0 deletions

View file

@ -448,6 +448,8 @@ PyGetSetDef UIArc::getsetters[] = {
"Name for finding this element.", (void*)PyObjectsEnum::UIARC}, "Name for finding this element.", (void*)PyObjectsEnum::UIARC},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos,
"Position as a Vector (same as center).", (void*)PyObjectsEnum::UIARC}, "Position as a Vector (same as center).", (void*)PyObjectsEnum::UIARC},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UIARC},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UIARC},
UIDRAWABLE_GETSETTERS, UIDRAWABLE_GETSETTERS,
UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UIARC), UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UIARC),
UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UIARC), UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UIARC),

View file

@ -285,6 +285,8 @@ PyGetSetDef UICaption::getsetters[] = {
{"x", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "X coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 0)}, {"x", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "X coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 0)},
{"y", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "Y coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 1)}, {"y", (getter)UIDrawable::get_float_member, (setter)UIDrawable::set_float_member, "Y coordinate of top-left corner", (void*)((intptr_t)PyObjectsEnum::UICAPTION << 8 | 1)},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "(x, y) vector", (void*)PyObjectsEnum::UICAPTION}, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "(x, y) vector", (void*)PyObjectsEnum::UICAPTION},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UICAPTION},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UICAPTION},
{"size", (getter)UICaption::get_size, NULL, "Text dimensions as Vector (read-only)", NULL}, {"size", (getter)UICaption::get_size, NULL, "Text dimensions as Vector (read-only)", NULL},
{"w", (getter)UICaption::get_w, NULL, "Text width in pixels (read-only)", NULL}, {"w", (getter)UICaption::get_w, NULL, "Text width in pixels (read-only)", NULL},
{"h", (getter)UICaption::get_h, NULL, "Text height in pixels (read-only)", NULL}, {"h", (getter)UICaption::get_h, NULL, "Text height in pixels (read-only)", NULL},

View file

@ -394,6 +394,8 @@ PyGetSetDef UICircle::getsetters[] = {
"Name for finding this element.", (void*)PyObjectsEnum::UICIRCLE}, "Name for finding this element.", (void*)PyObjectsEnum::UICIRCLE},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos,
"Position as a Vector (same as center).", (void*)PyObjectsEnum::UICIRCLE}, "Position as a Vector (same as center).", (void*)PyObjectsEnum::UICIRCLE},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UICIRCLE},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UICIRCLE},
UIDRAWABLE_GETSETTERS, UIDRAWABLE_GETSETTERS,
UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UICIRCLE), UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UICIRCLE),
UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UICIRCLE), UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UICIRCLE),

View file

@ -578,6 +578,228 @@ int UIDrawable::set_pos(PyObject* self, PyObject* value, void* closure) {
return 0; return 0;
} }
// #221 - Grid coordinate properties (only valid when parent is UIGrid)
PyObject* UIDrawable::get_grid_pos(PyObject* self, void* closure) {
PyObjectsEnum objtype = static_cast<PyObjectsEnum>(reinterpret_cast<intptr_t>(closure));
UIDrawable* drawable = extractDrawable(self, objtype);
if (!drawable) return NULL;
// Check if parent is a UIGrid
auto parent_ptr = drawable->getParent();
if (!parent_ptr) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a child of a Grid");
return NULL;
}
UIGrid* grid = dynamic_cast<UIGrid*>(parent_ptr.get());
if (!grid) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a direct child of a Grid");
return NULL;
}
// Calculate grid position from pixel position
sf::Vector2f cell_size = grid->getEffectiveCellSize();
float grid_x = drawable->position.x / cell_size.x;
float grid_y = drawable->position.y / cell_size.y;
// Return as Vector
PyObject* vector_type = PyObject_GetAttrString(McRFPy_API::mcrf_module, "Vector");
if (!vector_type) return NULL;
PyObject* args = Py_BuildValue("(ff)", grid_x, grid_y);
PyObject* result = PyObject_CallObject(vector_type, args);
Py_DECREF(vector_type);
Py_DECREF(args);
return result;
}
int UIDrawable::set_grid_pos(PyObject* self, PyObject* value, void* closure) {
PyObjectsEnum objtype = static_cast<PyObjectsEnum>(reinterpret_cast<intptr_t>(closure));
UIDrawable* drawable = extractDrawable(self, objtype);
if (!drawable) return -1;
// Check if parent is a UIGrid
auto parent_ptr = drawable->getParent();
if (!parent_ptr) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a child of a Grid");
return -1;
}
UIGrid* grid = dynamic_cast<UIGrid*>(parent_ptr.get());
if (!grid) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a direct child of a Grid");
return -1;
}
// Parse the grid position value
float grid_x, grid_y;
if (PyTuple_Check(value) && PyTuple_Size(value) == 2) {
PyObject* x_obj = PyTuple_GetItem(value, 0);
PyObject* y_obj = PyTuple_GetItem(value, 1);
if (PyFloat_Check(x_obj) || PyLong_Check(x_obj)) {
grid_x = PyFloat_Check(x_obj) ? PyFloat_AsDouble(x_obj) : static_cast<float>(PyLong_AsLong(x_obj));
} else {
PyErr_SetString(PyExc_TypeError, "grid_pos x must be a number");
return -1;
}
if (PyFloat_Check(y_obj) || PyLong_Check(y_obj)) {
grid_y = PyFloat_Check(y_obj) ? PyFloat_AsDouble(y_obj) : static_cast<float>(PyLong_AsLong(y_obj));
} else {
PyErr_SetString(PyExc_TypeError, "grid_pos y must be a number");
return -1;
}
} else if (PyObject_HasAttrString(value, "x") && PyObject_HasAttrString(value, "y")) {
// Vector-like object
PyObject* x_attr = PyObject_GetAttrString(value, "x");
PyObject* y_attr = PyObject_GetAttrString(value, "y");
if (x_attr && (PyFloat_Check(x_attr) || PyLong_Check(x_attr))) {
grid_x = PyFloat_Check(x_attr) ? PyFloat_AsDouble(x_attr) : static_cast<float>(PyLong_AsLong(x_attr));
} else {
Py_XDECREF(x_attr);
Py_XDECREF(y_attr);
PyErr_SetString(PyExc_TypeError, "grid_pos x must be a number");
return -1;
}
if (y_attr && (PyFloat_Check(y_attr) || PyLong_Check(y_attr))) {
grid_y = PyFloat_Check(y_attr) ? PyFloat_AsDouble(y_attr) : static_cast<float>(PyLong_AsLong(y_attr));
} else {
Py_XDECREF(x_attr);
Py_XDECREF(y_attr);
PyErr_SetString(PyExc_TypeError, "grid_pos y must be a number");
return -1;
}
Py_DECREF(x_attr);
Py_DECREF(y_attr);
} else {
PyErr_SetString(PyExc_TypeError, "grid_pos must be a tuple (x, y) or Vector");
return -1;
}
// Convert grid position to pixel position
sf::Vector2f cell_size = grid->getEffectiveCellSize();
drawable->position.x = grid_x * cell_size.x;
drawable->position.y = grid_y * cell_size.y;
drawable->onPositionChanged();
return 0;
}
PyObject* UIDrawable::get_grid_size(PyObject* self, void* closure) {
PyObjectsEnum objtype = static_cast<PyObjectsEnum>(reinterpret_cast<intptr_t>(closure));
UIDrawable* drawable = extractDrawable(self, objtype);
if (!drawable) return NULL;
// Check if parent is a UIGrid
auto parent_ptr = drawable->getParent();
if (!parent_ptr) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a child of a Grid");
return NULL;
}
UIGrid* grid = dynamic_cast<UIGrid*>(parent_ptr.get());
if (!grid) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a direct child of a Grid");
return NULL;
}
// Calculate grid size from pixel size
sf::FloatRect bounds = drawable->get_bounds();
sf::Vector2f cell_size = grid->getEffectiveCellSize();
float grid_w = bounds.width / cell_size.x;
float grid_h = bounds.height / cell_size.y;
// Return as Vector
PyObject* vector_type = PyObject_GetAttrString(McRFPy_API::mcrf_module, "Vector");
if (!vector_type) return NULL;
PyObject* args = Py_BuildValue("(ff)", grid_w, grid_h);
PyObject* result = PyObject_CallObject(vector_type, args);
Py_DECREF(vector_type);
Py_DECREF(args);
return result;
}
int UIDrawable::set_grid_size(PyObject* self, PyObject* value, void* closure) {
PyObjectsEnum objtype = static_cast<PyObjectsEnum>(reinterpret_cast<intptr_t>(closure));
UIDrawable* drawable = extractDrawable(self, objtype);
if (!drawable) return -1;
// Check if parent is a UIGrid
auto parent_ptr = drawable->getParent();
if (!parent_ptr) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a child of a Grid");
return -1;
}
UIGrid* grid = dynamic_cast<UIGrid*>(parent_ptr.get());
if (!grid) {
PyErr_SetString(PyExc_RuntimeError, "drawable is not a direct child of a Grid");
return -1;
}
// Parse the grid size value
float grid_w, grid_h;
if (PyTuple_Check(value) && PyTuple_Size(value) == 2) {
PyObject* w_obj = PyTuple_GetItem(value, 0);
PyObject* h_obj = PyTuple_GetItem(value, 1);
if (PyFloat_Check(w_obj) || PyLong_Check(w_obj)) {
grid_w = PyFloat_Check(w_obj) ? PyFloat_AsDouble(w_obj) : static_cast<float>(PyLong_AsLong(w_obj));
} else {
PyErr_SetString(PyExc_TypeError, "grid_size width must be a number");
return -1;
}
if (PyFloat_Check(h_obj) || PyLong_Check(h_obj)) {
grid_h = PyFloat_Check(h_obj) ? PyFloat_AsDouble(h_obj) : static_cast<float>(PyLong_AsLong(h_obj));
} else {
PyErr_SetString(PyExc_TypeError, "grid_size height must be a number");
return -1;
}
} else if (PyObject_HasAttrString(value, "x") && PyObject_HasAttrString(value, "y")) {
// Vector-like object
PyObject* x_attr = PyObject_GetAttrString(value, "x");
PyObject* y_attr = PyObject_GetAttrString(value, "y");
if (x_attr && (PyFloat_Check(x_attr) || PyLong_Check(x_attr))) {
grid_w = PyFloat_Check(x_attr) ? PyFloat_AsDouble(x_attr) : static_cast<float>(PyLong_AsLong(x_attr));
} else {
Py_XDECREF(x_attr);
Py_XDECREF(y_attr);
PyErr_SetString(PyExc_TypeError, "grid_size width must be a number");
return -1;
}
if (y_attr && (PyFloat_Check(y_attr) || PyLong_Check(y_attr))) {
grid_h = PyFloat_Check(y_attr) ? PyFloat_AsDouble(y_attr) : static_cast<float>(PyLong_AsLong(y_attr));
} else {
Py_XDECREF(x_attr);
Py_XDECREF(y_attr);
PyErr_SetString(PyExc_TypeError, "grid_size height must be a number");
return -1;
}
Py_DECREF(x_attr);
Py_DECREF(y_attr);
} else {
PyErr_SetString(PyExc_TypeError, "grid_size must be a tuple (w, h) or Vector");
return -1;
}
// Convert grid size to pixel size and resize
sf::Vector2f cell_size = grid->getEffectiveCellSize();
drawable->resize(grid_w * cell_size.x, grid_h * cell_size.y);
return 0;
}
// #122 - Parent-child hierarchy implementation // #122 - Parent-child hierarchy implementation
void UIDrawable::setParent(std::shared_ptr<UIDrawable> new_parent) { void UIDrawable::setParent(std::shared_ptr<UIDrawable> new_parent) {
parent = new_parent; parent = new_parent;

View file

@ -93,6 +93,12 @@ public:
static PyObject* get_pos(PyObject* self, void* closure); static PyObject* get_pos(PyObject* self, void* closure);
static int set_pos(PyObject* self, PyObject* value, void* closure); static int set_pos(PyObject* self, PyObject* value, void* closure);
// #221 - Grid coordinate properties (only valid when parent is UIGrid)
static PyObject* get_grid_pos(PyObject* self, void* closure);
static int set_grid_pos(PyObject* self, PyObject* value, void* closure);
static PyObject* get_grid_size(PyObject* self, void* closure);
static int set_grid_size(PyObject* self, PyObject* value, void* closure);
// Z-order for rendering (lower values rendered first, higher values on top) // Z-order for rendering (lower values rendered first, higher values on top)
int z_index = 0; int z_index = 0;

View file

@ -464,6 +464,8 @@ PyGetSetDef UIFrame::getsetters[] = {
), (void*)PyObjectsEnum::UIFRAME}, ), (void*)PyObjectsEnum::UIFRAME},
{"name", (getter)UIDrawable::get_name, (setter)UIDrawable::set_name, "Name for finding elements", (void*)PyObjectsEnum::UIFRAME}, {"name", (getter)UIDrawable::get_name, (setter)UIDrawable::set_name, "Name for finding elements", (void*)PyObjectsEnum::UIFRAME},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position as a Vector", (void*)PyObjectsEnum::UIFRAME}, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position as a Vector", (void*)PyObjectsEnum::UIFRAME},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UIFRAME},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UIFRAME},
{"clip_children", (getter)UIFrame::get_clip_children, (setter)UIFrame::set_clip_children, "Whether to clip children to frame bounds", NULL}, {"clip_children", (getter)UIFrame::get_clip_children, (setter)UIFrame::set_clip_children, "Whether to clip children to frame bounds", NULL},
{"cache_subtree", (getter)UIFrame::get_cache_subtree, (setter)UIFrame::set_cache_subtree, "#144: Cache subtree rendering to texture for performance", NULL}, {"cache_subtree", (getter)UIFrame::get_cache_subtree, (setter)UIFrame::set_cache_subtree, "#144: Cache subtree rendering to texture for performance", NULL},
UIDRAWABLE_GETSETTERS, UIDRAWABLE_GETSETTERS,

View file

@ -2177,6 +2177,7 @@ PyGetSetDef UIGrid::getsetters[] = {
{"grid_h", (getter)UIGrid::get_grid_h, NULL, "Grid height in cells", NULL}, {"grid_h", (getter)UIGrid::get_grid_h, NULL, "Grid height in cells", NULL},
{"position", (getter)UIGrid::get_position, (setter)UIGrid::set_position, "Position of the grid (x, y)", NULL}, {"position", (getter)UIGrid::get_position, (setter)UIGrid::set_position, "Position of the grid (x, y)", NULL},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position of the grid as Vector", (void*)PyObjectsEnum::UIGRID}, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position of the grid as Vector", (void*)PyObjectsEnum::UIGRID},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in parent grid's tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UIGRID},
{"size", (getter)UIGrid::get_size, (setter)UIGrid::set_size, "Size of the grid as Vector (width, height)", NULL}, {"size", (getter)UIGrid::get_size, (setter)UIGrid::set_size, "Size of the grid as Vector (width, height)", NULL},
{"center", (getter)UIGrid::get_center, (setter)UIGrid::set_center, "Grid coordinate at the center of the Grid's view (pan)", NULL}, {"center", (getter)UIGrid::get_center, (setter)UIGrid::set_center, "Grid coordinate at the center of the Grid's view (pan)", NULL},
@ -2383,6 +2384,13 @@ std::optional<sf::Vector2i> UIGrid::screenToCell(sf::Vector2f screen_pos) const
return sf::Vector2i(cell_x, cell_y); return sf::Vector2i(cell_x, cell_y);
} }
// #221 - Get effective cell size (texture size * zoom)
sf::Vector2f UIGrid::getEffectiveCellSize() const {
float cell_w = ptex ? static_cast<float>(ptex->sprite_width) : static_cast<float>(DEFAULT_CELL_WIDTH);
float cell_h = ptex ? static_cast<float>(ptex->sprite_height) : static_cast<float>(DEFAULT_CELL_HEIGHT);
return sf::Vector2f(cell_w * zoom, cell_h * zoom);
}
// #142 - Update cell hover state and fire callbacks // #142 - Update cell hover state and fire callbacks
void UIGrid::updateCellHover(sf::Vector2f mousepos) { void UIGrid::updateCellHover(sf::Vector2f mousepos) {
auto new_cell = screenToCell(mousepos); auto new_cell = screenToCell(mousepos);

View file

@ -135,6 +135,9 @@ public:
// #142 - Cell coordinate conversion (screen pos -> cell coords) // #142 - Cell coordinate conversion (screen pos -> cell coords)
std::optional<sf::Vector2i> screenToCell(sf::Vector2f screen_pos) const; std::optional<sf::Vector2i> screenToCell(sf::Vector2f screen_pos) const;
// #221 - Get effective cell size (texture size * zoom)
sf::Vector2f getEffectiveCellSize() const;
// #142 - Update cell hover state (called from PyScene) // #142 - Update cell hover state (called from PyScene)
void updateCellHover(sf::Vector2f mousepos); void updateCellHover(sf::Vector2f mousepos);

View file

@ -464,6 +464,8 @@ PyGetSetDef UILine::getsetters[] = {
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos,
MCRF_PROPERTY(pos, "Position as a Vector (midpoint of line)."), MCRF_PROPERTY(pos, "Position as a Vector (midpoint of line)."),
(void*)PyObjectsEnum::UILINE}, (void*)PyObjectsEnum::UILINE},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UILINE},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UILINE},
UIDRAWABLE_GETSETTERS, UIDRAWABLE_GETSETTERS,
UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UILINE), UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UILINE),
UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UILINE), UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UILINE),

View file

@ -354,6 +354,8 @@ PyGetSetDef UISprite::getsetters[] = {
), (void*)PyObjectsEnum::UISPRITE}, ), (void*)PyObjectsEnum::UISPRITE},
{"name", (getter)UIDrawable::get_name, (setter)UIDrawable::set_name, "Name for finding elements", (void*)PyObjectsEnum::UISPRITE}, {"name", (getter)UIDrawable::get_name, (setter)UIDrawable::set_name, "Name for finding elements", (void*)PyObjectsEnum::UISPRITE},
{"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position as a Vector", (void*)PyObjectsEnum::UISPRITE}, {"pos", (getter)UIDrawable::get_pos, (setter)UIDrawable::set_pos, "Position as a Vector", (void*)PyObjectsEnum::UISPRITE},
{"grid_pos", (getter)UIDrawable::get_grid_pos, (setter)UIDrawable::set_grid_pos, "Position in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UISPRITE},
{"grid_size", (getter)UIDrawable::get_grid_size, (setter)UIDrawable::set_grid_size, "Size in grid tile coordinates (only when parent is Grid)", (void*)PyObjectsEnum::UISPRITE},
UIDRAWABLE_GETSETTERS, UIDRAWABLE_GETSETTERS,
UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UISPRITE), UIDRAWABLE_PARENT_GETSETTERS(PyObjectsEnum::UISPRITE),
UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UISPRITE), UIDRAWABLE_ALIGNMENT_GETSETTERS(PyObjectsEnum::UISPRITE),