Grid/GridView API unification: mcrfpy.Grid now returns GridView, closes #252
mcrfpy.Grid() now creates a GridView that internally owns a GridData (UIGrid). The old UIGrid type is renamed to _GridData (internal). Attribute access on Grid delegates to the underlying UIGrid via tp_getattro/tp_setattro, so all existing Grid properties (grid_w, grid_h, entities, cells, layers, etc.) work transparently. Key changes: - GridView init has two modes: factory (Grid(grid_size=...)) and explicit view (Grid(grid=existing_grid, ...)) for future multi-view support - Entity.grid getter returns GridView wrapper via owning_view back-reference - Entity.grid setter accepts GridView objects - GridLayer set_grid handles GridView (extracts underlying UIGrid) - UIDrawable::removeFromParent handles UIGRIDVIEW type correctly - UIFrame children init accepts GridView objects - Animation system supports GridView (center, zoom, shader.* properties) - PythonObjectCache registration preserves subclass identity - All 263 tests pass (100%) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a61f05229f
commit
109bc21d90
10 changed files with 616 additions and 146 deletions
|
|
@ -86,8 +86,16 @@ public:
|
|||
// Python API
|
||||
// =========================================================================
|
||||
static int init(PyUIGridViewObject* self, PyObject* args, PyObject* kwds);
|
||||
static int init_with_data(PyUIGridViewObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* repr(PyUIGridViewObject* self);
|
||||
|
||||
// #252 - Attribute delegation to underlying Grid
|
||||
static PyObject* getattro(PyObject* self, PyObject* name);
|
||||
static int setattro(PyObject* self, PyObject* name, PyObject* value);
|
||||
|
||||
// Helper: get the underlying Grid as a Python object (borrowed-like via cache)
|
||||
static PyObject* get_grid_pyobj(PyUIGridViewObject* self);
|
||||
|
||||
static PyObject* get_grid(PyUIGridViewObject* self, void* closure);
|
||||
static int set_grid(PyUIGridViewObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_center(PyUIGridViewObject* self, void* closure);
|
||||
|
|
@ -97,6 +105,8 @@ public:
|
|||
static PyObject* get_fill_color(PyUIGridViewObject* self, void* closure);
|
||||
static int set_fill_color(PyUIGridViewObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_texture(PyUIGridViewObject* self, void* closure);
|
||||
static PyObject* get_float_member_gv(PyUIGridViewObject* self, void* closure);
|
||||
static int set_float_member_gv(PyUIGridViewObject* self, PyObject* value, void* closure);
|
||||
|
||||
static PyMethodDef methods[];
|
||||
static PyGetSetDef getsetters[];
|
||||
|
|
@ -106,9 +116,12 @@ public:
|
|||
extern PyMethodDef UIGridView_all_methods[];
|
||||
|
||||
namespace mcrfpydef {
|
||||
// #252: GridView is the primary user-facing type. "mcrfpy.Grid" is an alias.
|
||||
// Grid() auto-creates a GridData (UIGrid internally); GridView(grid=...) wraps existing data.
|
||||
// Attribute access delegates to underlying Grid for data properties/methods.
|
||||
inline PyTypeObject PyUIGridViewType = {
|
||||
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
|
||||
.tp_name = "mcrfpy.GridView",
|
||||
.tp_name = "mcrfpy.Grid", // #252: primary name is Grid
|
||||
.tp_basicsize = sizeof(PyUIGridViewObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_dealloc = (destructor)[](PyObject* self)
|
||||
|
|
@ -118,27 +131,53 @@ namespace mcrfpydef {
|
|||
if (obj->weakreflist != NULL) {
|
||||
PyObject_ClearWeakRefs(self);
|
||||
}
|
||||
// Clear owning_view back-reference before releasing grid_data
|
||||
if (obj->data && obj->data->grid_data) {
|
||||
obj->data->grid_data->owning_view.reset();
|
||||
}
|
||||
obj->data.reset();
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
},
|
||||
.tp_repr = (reprfunc)UIGridView::repr,
|
||||
.tp_getattro = UIGridView::getattro, // #252: attribute delegation to Grid
|
||||
.tp_setattro = UIGridView::setattro, // #252: attribute delegation to Grid
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_doc = PyDoc_STR(
|
||||
"GridView(grid=None, pos=None, size=None, **kwargs)\n\n"
|
||||
"A rendering view for a Grid's data. Multiple GridViews can display\n"
|
||||
"the same Grid with different camera positions, zoom levels, etc.\n\n"
|
||||
"Grid(grid_size=None, pos=None, size=None, texture=None, **kwargs)\n\n"
|
||||
"A grid-based UI element for tile-based rendering and entity management.\n"
|
||||
"Creates and owns grid data (cells, entities, layers) with an integrated\n"
|
||||
"rendering view (camera, zoom, perspective).\n\n"
|
||||
"Can also be constructed as a view of existing grid data:\n"
|
||||
" Grid(grid=existing_grid, pos=..., size=...)\n\n"
|
||||
"Args:\n"
|
||||
" grid (Grid): The Grid to render. Required.\n"
|
||||
" grid_size (tuple): Grid dimensions as (grid_w, grid_h). Default: (2, 2)\n"
|
||||
" pos (tuple): Position as (x, y). Default: (0, 0)\n"
|
||||
" size (tuple): Size as (w, h). Default: (256, 256)\n\n"
|
||||
" size (tuple): Size as (w, h). Default: auto-calculated\n"
|
||||
" texture (Texture): Tile texture atlas. Default: default texture\n\n"
|
||||
"Keyword Args:\n"
|
||||
" grid (Grid): Existing Grid to view (creates view of shared data).\n"
|
||||
" fill_color (Color): Background fill color.\n"
|
||||
" on_click (callable): Click event handler.\n"
|
||||
" center_x, center_y (float): Camera center coordinates.\n"
|
||||
" zoom (float): Zoom level. Default: 1.0\n"
|
||||
" center (tuple): Camera center (x, y) in pixels. Default: grid center\n"
|
||||
" fill_color (Color): Background color. Default: dark gray\n"),
|
||||
" visible (bool): Visibility. Default: True\n"
|
||||
" opacity (float): Opacity (0.0-1.0). Default: 1.0\n"
|
||||
" z_index (int): Rendering order. Default: 0\n"
|
||||
" name (str): Element name.\n"
|
||||
" layers (list): List of ColorLayer/TileLayer objects.\n"),
|
||||
.tp_traverse = [](PyObject* self, visitproc visit, void* arg) -> int {
|
||||
PyUIGridViewObject* obj = (PyUIGridViewObject*)self;
|
||||
if (obj->data && obj->data->click_callable) {
|
||||
PyObject* callback = obj->data->click_callable->borrow();
|
||||
if (callback && callback != Py_None) Py_VISIT(callback);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
.tp_clear = [](PyObject* self) -> int {
|
||||
PyUIGridViewObject* obj = (PyUIGridViewObject*)self;
|
||||
if (obj->data) {
|
||||
obj->data->click_unregister();
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
.tp_methods = UIGridView_all_methods,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue