McRogueFace/src/PySceneObject.h

98 lines
No EOL
4.4 KiB
C++

#pragma once
#include "Common.h"
#include "Python.h"
#include <string>
#include <memory>
// Forward declarations
class PyScene;
// Python object structure for Scene
typedef struct {
PyObject_HEAD
std::string name;
std::shared_ptr<PyScene> scene; // Reference to the C++ scene
bool initialized;
} PySceneObject;
// C++ interface for Python Scene class
class PySceneClass
{
public:
// Type methods
static PyObject* __new__(PyTypeObject* type, PyObject* args, PyObject* kwds);
static int __init__(PySceneObject* self, PyObject* args, PyObject* kwds);
static void __dealloc(PyObject* self);
static PyObject* __repr__(PySceneObject* self);
// Scene methods
static PyObject* activate(PySceneObject* self, PyObject* args, PyObject* kwds);
// Properties
static PyObject* get_name(PySceneObject* self, void* closure);
static PyObject* get_active(PySceneObject* self, void* closure);
// Lifecycle callbacks (called from C++)
static void call_on_enter(PySceneObject* self);
static void call_on_exit(PySceneObject* self);
static void call_on_key(PySceneObject* self, const std::string& key, const std::string& action);
static void call_update(PySceneObject* self, float dt);
static void call_on_resize(PySceneObject* self, sf::Vector2u new_size);
// #183: Lookup scene by name (returns new reference or nullptr)
static PyObject* get_scene_by_name(const std::string& name);
static PyGetSetDef getsetters[];
static PyMethodDef methods[];
};
namespace mcrfpydef {
static PyTypeObject PySceneType = {
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
.tp_name = "mcrfpy.Scene",
.tp_basicsize = sizeof(PySceneObject),
.tp_itemsize = 0,
.tp_dealloc = (destructor)PySceneClass::__dealloc,
.tp_repr = (reprfunc)PySceneClass::__repr__,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // Allow subclassing
.tp_doc = PyDoc_STR(
"Scene(name: str)\n\n"
"Object-oriented scene management with lifecycle callbacks.\n\n"
"This is the recommended approach for scene management, replacing module-level\n"
"functions like createScene(), setScene(), and sceneUI(). Key advantage: you can\n"
"set on_key handlers on ANY scene, not just the currently active one.\n\n"
"Args:\n"
" name: Unique identifier for this scene. Used for scene transitions.\n\n"
"Properties:\n"
" name (str, read-only): Scene's unique identifier.\n"
" active (bool, read-only): Whether this scene is currently displayed.\n"
" children (UICollection, read-only): UI elements in this scene. Modify to add/remove elements.\n"
" on_key (callable): Keyboard handler. Set on ANY scene, regardless of which is active!\n"
" pos (Vector): Position offset for all UI elements.\n"
" visible (bool): Whether the scene renders.\n"
" opacity (float): Scene transparency (0.0-1.0).\n\n"
"Lifecycle Callbacks (override in subclass):\n"
" on_enter(): Called when scene becomes active via activate().\n"
" on_exit(): Called when scene is deactivated (another scene activates).\n"
" on_key(key: str, action: str): Called for keyboard events (subclass method).\n"
" update(dt: float): Called every frame with delta time in seconds.\n"
" on_resize(new_size: Vector): Called when window is resized.\n\n"
"Example:\n"
" # Basic usage (replacing module functions):\n"
" scene = mcrfpy.Scene('main_menu')\n"
" scene.children.append(mcrfpy.Caption(text='Welcome', pos=(100, 100)))\n"
" scene.on_key = lambda key, action: print(f'Key: {key}')\n"
" scene.activate() # Switch to this scene\n\n"
" # Subclassing for lifecycle:\n"
" class GameScene(mcrfpy.Scene):\n"
" def on_enter(self):\n"
" print('Game started!')\n"
" def update(self, dt):\n"
" self.player.move(dt)\n"
),
.tp_methods = nullptr, // Set in McRFPy_API.cpp
.tp_getset = nullptr, // Set in McRFPy_API.cpp
.tp_init = (initproc)PySceneClass::__init__,
.tp_new = PySceneClass::__new__,
};
}