feat: implement mcrfpy.Timer object with pause/resume/cancel capabilities closes #103
- Created PyTimer.h/cpp with object-oriented timer interface - Enhanced PyTimerCallable with pause/resume state tracking - Added timer control methods: pause(), resume(), cancel(), restart() - Added timer properties: interval, remaining, paused, active, callback - Fixed timing logic to prevent rapid catch-up after resume - Timer objects automatically register with game engine - Added comprehensive test demonstrating all functionality
This commit is contained in:
parent
1aa35202e1
commit
27db9a4184
|
@ -164,6 +164,15 @@ void GameEngine::run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PyTimerCallable> GameEngine::getTimer(const std::string& name)
|
||||||
|
{
|
||||||
|
auto it = timers.find(name);
|
||||||
|
if (it != timers.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void GameEngine::manageTimer(std::string name, PyObject* target, int interval)
|
void GameEngine::manageTimer(std::string name, PyObject* target, int interval)
|
||||||
{
|
{
|
||||||
auto it = timers.find(name);
|
auto it = timers.find(name);
|
||||||
|
|
|
@ -29,12 +29,12 @@ class GameEngine
|
||||||
bool headless = false;
|
bool headless = false;
|
||||||
McRogueFaceConfig config;
|
McRogueFaceConfig config;
|
||||||
|
|
||||||
sf::Clock runtime;
|
|
||||||
//std::map<std::string, Timer> timers;
|
|
||||||
std::map<std::string, std::shared_ptr<PyTimerCallable>> timers;
|
|
||||||
void testTimers();
|
void testTimers();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
sf::Clock runtime;
|
||||||
|
//std::map<std::string, Timer> timers;
|
||||||
|
std::map<std::string, std::shared_ptr<PyTimerCallable>> timers;
|
||||||
std::string scene;
|
std::string scene;
|
||||||
GameEngine();
|
GameEngine();
|
||||||
GameEngine(const McRogueFaceConfig& cfg);
|
GameEngine(const McRogueFaceConfig& cfg);
|
||||||
|
@ -54,6 +54,7 @@ public:
|
||||||
float getFrameTime() { return frameTime; }
|
float getFrameTime() { return frameTime; }
|
||||||
sf::View getView() { return visible; }
|
sf::View getView() { return visible; }
|
||||||
void manageTimer(std::string, PyObject*, int);
|
void manageTimer(std::string, PyObject*, int);
|
||||||
|
std::shared_ptr<PyTimerCallable> getTimer(const std::string& name);
|
||||||
void setWindowScale(float);
|
void setWindowScale(float);
|
||||||
bool isHeadless() const { return headless; }
|
bool isHeadless() const { return headless; }
|
||||||
void processEvent(const sf::Event& event);
|
void processEvent(const sf::Event& event);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "PyAnimation.h"
|
#include "PyAnimation.h"
|
||||||
#include "PyDrawable.h"
|
#include "PyDrawable.h"
|
||||||
|
#include "PyTimer.h"
|
||||||
#include "GameEngine.h"
|
#include "GameEngine.h"
|
||||||
#include "UI.h"
|
#include "UI.h"
|
||||||
#include "Resources.h"
|
#include "Resources.h"
|
||||||
|
@ -85,6 +86,9 @@ PyObject* PyInit_mcrfpy()
|
||||||
|
|
||||||
/*animation*/
|
/*animation*/
|
||||||
&PyAnimationType,
|
&PyAnimationType,
|
||||||
|
|
||||||
|
/*timer*/
|
||||||
|
&PyTimerType,
|
||||||
nullptr};
|
nullptr};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
auto t = pytypes[i];
|
auto t = pytypes[i];
|
||||||
|
|
|
@ -16,21 +16,24 @@ PyObject* PyCallable::call(PyObject* args, PyObject* kwargs)
|
||||||
return PyObject_Call(target, args, kwargs);
|
return PyObject_Call(target, args, kwargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PyCallable::isNone()
|
bool PyCallable::isNone() const
|
||||||
{
|
{
|
||||||
return (target == Py_None || target == NULL);
|
return (target == Py_None || target == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTimerCallable::PyTimerCallable(PyObject* _target, int _interval, int now)
|
PyTimerCallable::PyTimerCallable(PyObject* _target, int _interval, int now)
|
||||||
: PyCallable(_target), interval(_interval), last_ran(now)
|
: PyCallable(_target), interval(_interval), last_ran(now),
|
||||||
|
paused(false), pause_start_time(0), total_paused_time(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
PyTimerCallable::PyTimerCallable()
|
PyTimerCallable::PyTimerCallable()
|
||||||
: PyCallable(Py_None), interval(0), last_ran(0)
|
: PyCallable(Py_None), interval(0), last_ran(0),
|
||||||
|
paused(false), pause_start_time(0), total_paused_time(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool PyTimerCallable::hasElapsed(int now)
|
bool PyTimerCallable::hasElapsed(int now)
|
||||||
{
|
{
|
||||||
|
if (paused) return false;
|
||||||
return now >= last_ran + interval;
|
return now >= last_ran + interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +63,62 @@ bool PyTimerCallable::test(int now)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PyTimerCallable::pause(int current_time)
|
||||||
|
{
|
||||||
|
if (!paused) {
|
||||||
|
paused = true;
|
||||||
|
pause_start_time = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyTimerCallable::resume(int current_time)
|
||||||
|
{
|
||||||
|
if (paused) {
|
||||||
|
paused = false;
|
||||||
|
int paused_duration = current_time - pause_start_time;
|
||||||
|
total_paused_time += paused_duration;
|
||||||
|
// Adjust last_ran to account for the pause
|
||||||
|
last_ran += paused_duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyTimerCallable::restart(int current_time)
|
||||||
|
{
|
||||||
|
last_ran = current_time;
|
||||||
|
paused = false;
|
||||||
|
pause_start_time = 0;
|
||||||
|
total_paused_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyTimerCallable::cancel()
|
||||||
|
{
|
||||||
|
// Cancel by setting target to None
|
||||||
|
if (target && target != Py_None) {
|
||||||
|
Py_DECREF(target);
|
||||||
|
}
|
||||||
|
target = Py_None;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyTimerCallable::getRemaining(int current_time) const
|
||||||
|
{
|
||||||
|
if (paused) {
|
||||||
|
// When paused, calculate time remaining from when it was paused
|
||||||
|
int elapsed_when_paused = pause_start_time - last_ran;
|
||||||
|
return interval - elapsed_when_paused;
|
||||||
|
}
|
||||||
|
int elapsed = current_time - last_ran;
|
||||||
|
return interval - elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyTimerCallable::setCallback(PyObject* new_callback)
|
||||||
|
{
|
||||||
|
if (target && target != Py_None) {
|
||||||
|
Py_DECREF(target);
|
||||||
|
}
|
||||||
|
target = Py_XNewRef(new_callback);
|
||||||
|
}
|
||||||
|
|
||||||
PyClickCallable::PyClickCallable(PyObject* _target)
|
PyClickCallable::PyClickCallable(PyObject* _target)
|
||||||
: PyCallable(_target)
|
: PyCallable(_target)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -10,7 +10,7 @@ protected:
|
||||||
~PyCallable();
|
~PyCallable();
|
||||||
PyObject* call(PyObject*, PyObject*);
|
PyObject* call(PyObject*, PyObject*);
|
||||||
public:
|
public:
|
||||||
bool isNone();
|
bool isNone() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PyTimerCallable: public PyCallable
|
class PyTimerCallable: public PyCallable
|
||||||
|
@ -19,11 +19,32 @@ private:
|
||||||
int interval;
|
int interval;
|
||||||
int last_ran;
|
int last_ran;
|
||||||
void call(int);
|
void call(int);
|
||||||
|
|
||||||
|
// Pause/resume support
|
||||||
|
bool paused;
|
||||||
|
int pause_start_time;
|
||||||
|
int total_paused_time;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool hasElapsed(int);
|
bool hasElapsed(int);
|
||||||
bool test(int);
|
bool test(int);
|
||||||
PyTimerCallable(PyObject*, int, int);
|
PyTimerCallable(PyObject*, int, int);
|
||||||
PyTimerCallable();
|
PyTimerCallable();
|
||||||
|
|
||||||
|
// Timer control methods
|
||||||
|
void pause(int current_time);
|
||||||
|
void resume(int current_time);
|
||||||
|
void restart(int current_time);
|
||||||
|
void cancel();
|
||||||
|
|
||||||
|
// Timer state queries
|
||||||
|
bool isPaused() const { return paused; }
|
||||||
|
bool isActive() const { return !isNone() && !paused; }
|
||||||
|
int getInterval() const { return interval; }
|
||||||
|
void setInterval(int new_interval) { interval = new_interval; }
|
||||||
|
int getRemaining(int current_time) const;
|
||||||
|
PyObject* getCallback() { return target; }
|
||||||
|
void setCallback(PyObject* new_callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PyClickCallable: public PyCallable
|
class PyClickCallable: public PyCallable
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
#include "PyTimer.h"
|
||||||
|
#include "PyCallable.h"
|
||||||
|
#include "GameEngine.h"
|
||||||
|
#include "Resources.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
PyObject* PyTimer::repr(PyObject* self) {
|
||||||
|
PyTimerObject* timer = (PyTimerObject*)self;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "<Timer name='" << timer->name << "' ";
|
||||||
|
|
||||||
|
if (timer->data) {
|
||||||
|
oss << "interval=" << timer->data->getInterval() << "ms ";
|
||||||
|
oss << (timer->data->isPaused() ? "paused" : "active");
|
||||||
|
} else {
|
||||||
|
oss << "uninitialized";
|
||||||
|
}
|
||||||
|
oss << ">";
|
||||||
|
|
||||||
|
return PyUnicode_FromString(oss.str().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::pynew(PyTypeObject* type, PyObject* args, PyObject* kwds) {
|
||||||
|
PyTimerObject* self = (PyTimerObject*)type->tp_alloc(type, 0);
|
||||||
|
if (self) {
|
||||||
|
new(&self->name) std::string(); // Placement new for std::string
|
||||||
|
self->data = nullptr;
|
||||||
|
}
|
||||||
|
return (PyObject*)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyTimer::init(PyTimerObject* self, PyObject* args, PyObject* kwds) {
|
||||||
|
static char* kwlist[] = {"name", "callback", "interval", NULL};
|
||||||
|
const char* name = nullptr;
|
||||||
|
PyObject* callback = nullptr;
|
||||||
|
int interval = 0;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sOi", kwlist,
|
||||||
|
&name, &callback, &interval)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyCallable_Check(callback)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "callback must be callable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interval <= 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "interval must be positive");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->name = name;
|
||||||
|
|
||||||
|
// Get current time from game engine
|
||||||
|
int current_time = 0;
|
||||||
|
if (Resources::game) {
|
||||||
|
current_time = Resources::game->runtime.getElapsedTime().asMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the timer callable
|
||||||
|
self->data = std::make_shared<PyTimerCallable>(callback, interval, current_time);
|
||||||
|
|
||||||
|
// Register with game engine
|
||||||
|
if (Resources::game) {
|
||||||
|
Resources::game->timers[self->name] = self->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PyTimer::dealloc(PyTimerObject* self) {
|
||||||
|
// Remove from game engine if still registered
|
||||||
|
if (Resources::game && !self->name.empty()) {
|
||||||
|
auto it = Resources::game->timers.find(self->name);
|
||||||
|
if (it != Resources::game->timers.end() && it->second == self->data) {
|
||||||
|
Resources::game->timers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly destroy std::string
|
||||||
|
self->name.~basic_string();
|
||||||
|
|
||||||
|
// Clear shared_ptr
|
||||||
|
self->data.reset();
|
||||||
|
|
||||||
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer control methods
|
||||||
|
PyObject* PyTimer::pause(PyTimerObject* self, PyObject* Py_UNUSED(ignored)) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int current_time = 0;
|
||||||
|
if (Resources::game) {
|
||||||
|
current_time = Resources::game->runtime.getElapsedTime().asMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->pause(current_time);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::resume(PyTimerObject* self, PyObject* Py_UNUSED(ignored)) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int current_time = 0;
|
||||||
|
if (Resources::game) {
|
||||||
|
current_time = Resources::game->runtime.getElapsedTime().asMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->resume(current_time);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::cancel(PyTimerObject* self, PyObject* Py_UNUSED(ignored)) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from game engine
|
||||||
|
if (Resources::game && !self->name.empty()) {
|
||||||
|
auto it = Resources::game->timers.find(self->name);
|
||||||
|
if (it != Resources::game->timers.end() && it->second == self->data) {
|
||||||
|
Resources::game->timers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->cancel();
|
||||||
|
self->data.reset();
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::restart(PyTimerObject* self, PyObject* Py_UNUSED(ignored)) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int current_time = 0;
|
||||||
|
if (Resources::game) {
|
||||||
|
current_time = Resources::game->runtime.getElapsedTime().asMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->restart(current_time);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Property getters/setters
|
||||||
|
PyObject* PyTimer::get_interval(PyTimerObject* self, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromLong(self->data->getInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyTimer::set_interval(PyTimerObject* self, PyObject* value, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyLong_Check(value)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "interval must be an integer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long interval = PyLong_AsLong(value);
|
||||||
|
if (interval <= 0) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "interval must be positive");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->setInterval(interval);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::get_remaining(PyTimerObject* self, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int current_time = 0;
|
||||||
|
if (Resources::game) {
|
||||||
|
current_time = Resources::game->runtime.getElapsedTime().asMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyLong_FromLong(self->data->getRemaining(current_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::get_paused(PyTimerObject* self, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyBool_FromLong(self->data->isPaused());
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::get_active(PyTimerObject* self, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
return Py_False;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyBool_FromLong(self->data->isActive());
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* PyTimer::get_callback(PyTimerObject* self, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* callback = self->data->getCallback();
|
||||||
|
if (!callback) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(callback);
|
||||||
|
return callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PyTimer::set_callback(PyTimerObject* self, PyObject* value, void* closure) {
|
||||||
|
if (!self->data) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Timer not initialized");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyCallable_Check(value)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "callback must be callable");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->data->setCallback(value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyGetSetDef PyTimer::getsetters[] = {
|
||||||
|
{"interval", (getter)PyTimer::get_interval, (setter)PyTimer::set_interval,
|
||||||
|
"Timer interval in milliseconds", NULL},
|
||||||
|
{"remaining", (getter)PyTimer::get_remaining, NULL,
|
||||||
|
"Time remaining until next trigger in milliseconds", NULL},
|
||||||
|
{"paused", (getter)PyTimer::get_paused, NULL,
|
||||||
|
"Whether the timer is paused", NULL},
|
||||||
|
{"active", (getter)PyTimer::get_active, NULL,
|
||||||
|
"Whether the timer is active and not paused", NULL},
|
||||||
|
{"callback", (getter)PyTimer::get_callback, (setter)PyTimer::set_callback,
|
||||||
|
"The callback function to be called", NULL},
|
||||||
|
{NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMethodDef PyTimer::methods[] = {
|
||||||
|
{"pause", (PyCFunction)PyTimer::pause, METH_NOARGS,
|
||||||
|
"Pause the timer"},
|
||||||
|
{"resume", (PyCFunction)PyTimer::resume, METH_NOARGS,
|
||||||
|
"Resume a paused timer"},
|
||||||
|
{"cancel", (PyCFunction)PyTimer::cancel, METH_NOARGS,
|
||||||
|
"Cancel the timer and remove it from the system"},
|
||||||
|
{"restart", (PyCFunction)PyTimer::restart, METH_NOARGS,
|
||||||
|
"Restart the timer from the current time"},
|
||||||
|
{NULL}
|
||||||
|
};
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Python.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class PyTimerCallable;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
std::shared_ptr<PyTimerCallable> data;
|
||||||
|
std::string name;
|
||||||
|
} PyTimerObject;
|
||||||
|
|
||||||
|
class PyTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Python type methods
|
||||||
|
static PyObject* repr(PyObject* self);
|
||||||
|
static int init(PyTimerObject* self, PyObject* args, PyObject* kwds);
|
||||||
|
static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL);
|
||||||
|
static void dealloc(PyTimerObject* self);
|
||||||
|
|
||||||
|
// Timer control methods
|
||||||
|
static PyObject* pause(PyTimerObject* self, PyObject* Py_UNUSED(ignored));
|
||||||
|
static PyObject* resume(PyTimerObject* self, PyObject* Py_UNUSED(ignored));
|
||||||
|
static PyObject* cancel(PyTimerObject* self, PyObject* Py_UNUSED(ignored));
|
||||||
|
static PyObject* restart(PyTimerObject* self, PyObject* Py_UNUSED(ignored));
|
||||||
|
|
||||||
|
// Timer property getters
|
||||||
|
static PyObject* get_interval(PyTimerObject* self, void* closure);
|
||||||
|
static int set_interval(PyTimerObject* self, PyObject* value, void* closure);
|
||||||
|
static PyObject* get_remaining(PyTimerObject* self, void* closure);
|
||||||
|
static PyObject* get_paused(PyTimerObject* self, void* closure);
|
||||||
|
static PyObject* get_active(PyTimerObject* self, void* closure);
|
||||||
|
static PyObject* get_callback(PyTimerObject* self, void* closure);
|
||||||
|
static int set_callback(PyTimerObject* self, PyObject* value, void* closure);
|
||||||
|
|
||||||
|
static PyGetSetDef getsetters[];
|
||||||
|
static PyMethodDef methods[];
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mcrfpydef {
|
||||||
|
static PyTypeObject PyTimerType = {
|
||||||
|
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
|
||||||
|
.tp_name = "mcrfpy.Timer",
|
||||||
|
.tp_basicsize = sizeof(PyTimerObject),
|
||||||
|
.tp_itemsize = 0,
|
||||||
|
.tp_dealloc = (destructor)PyTimer::dealloc,
|
||||||
|
.tp_repr = PyTimer::repr,
|
||||||
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||||
|
.tp_doc = PyDoc_STR("Timer object for scheduled callbacks"),
|
||||||
|
.tp_methods = PyTimer::methods,
|
||||||
|
.tp_getset = PyTimer::getsetters,
|
||||||
|
.tp_init = (initproc)PyTimer::init,
|
||||||
|
.tp_new = PyTimer::pynew,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue