From ab939ff772604770dbc5fe2f5b620b03ea234982 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sat, 16 Mar 2013 12:44:27 +0000 Subject: [PATCH] A real Timer object in Nasal. A persistent timer object which can be stopped, started and restarted. Gosh. Has both singleShot and repeating modes. --- src/Scripting/NasalSys.cxx | 116 ++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index bf1a1a21f..f7a1cbd38 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -28,6 +28,10 @@ #include #include #include + +#include +#include +#include #include #include "NasalSys.hxx" @@ -75,6 +79,91 @@ void FGNasalModuleListener::valueChanged(SGPropertyNode*) } } +////////////////////////////////////////////////////////////////////////// + + +class TimerObj : public SGReferenced +{ +public: + TimerObj(FGNasalSys* sys, naRef f, naRef self, double interval) : + _sys(sys), + _func(f), + _self(self), + _isRunning(false), + _interval(interval), + _singleShot(false) + { + char nm[128]; + snprintf(nm, 128, "nasal-timer-%p", this); + _name = nm; + _gcRoot = sys->gcSave(f); + _gcSelf = sys->gcSave(self); + } + + virtual ~TimerObj() + { + stop(); + _sys->gcRelease(_gcRoot); + _sys->gcRelease(_gcSelf); + } + + void stop() + { + if (_isRunning) { + globals->get_event_mgr()->removeTask(_name); + _isRunning = false; + } + } + + void start() + { + if (_isRunning) { + return; + } + + _isRunning = true; + if (_singleShot) { + globals->get_event_mgr()->addEvent(_name, this, &TimerObj::invoke, _interval); + } else { + globals->get_event_mgr()->addTask(_name, this, &TimerObj::invoke, _interval); + } + } + + // stop and then start - + void restart(double newInterval) + { + _interval = newInterval; + stop(); + start(); + } + + void invoke() + { + naRef *args = NULL; + _sys->callMethod(_func, _self, 0, args, naNil() /* locals */); + } + + void setSingleShot(bool aSingleShot) + { + _singleShot = aSingleShot; + } + + bool isSingleShot() const + { return _singleShot; } +private: + std::string _name; + FGNasalSys* _sys; + naRef _func, _self; + int _gcRoot, _gcSelf; + bool _isRunning; + double _interval; + bool _singleShot; +}; + +typedef SGSharedPtr TimerObjRef; +typedef nasal::Ghost NasalTimerObj; + +/////////////////////////////////////////////////////////////////////////// // Read and return file contents in a single buffer. Note use of // stat() to get the file size. This is a win32 function, believe it @@ -380,6 +469,24 @@ static naRef f_settimer(naContext c, naRef me, int argc, naRef* args) return naNil(); } +static naRef f_makeTimer(naContext c, naRef me, int argc, naRef* args) +{ + if (!naIsNum(args[0])) { + naRuntimeError(c, "bad interval argument to maketimer"); + } + + naRef func, self = naNil(); + if (naIsFunc(args[1])) { + func = args[1]; + } else if ((argc == 3) && naIsFunc(args[2])) { + self = args[1]; + func = args[2]; + } + + TimerObj* timerObj = new TimerObj(nasalSys, func, self, args[0].num); + return NasalTimerObj::create(c, timerObj); +} + // setlistener(func, property, bool) extension function. Falls through to // FGNasalSys::setListener(). See there for docs. static naRef f_setlistener(naContext c, naRef me, int argc, naRef* args) @@ -600,6 +707,7 @@ static struct { const char* name; naCFunction func; } funcs[] = { { "logprint", f_logprint }, { "_fgcommand", f_fgcommand }, { "settimer", f_settimer }, + { "maketimer", f_makeTimer }, { "_setlistener", f_setlistener }, { "removelistener", f_removelistener }, { "addcommand", f_addCommand }, @@ -671,6 +779,12 @@ void FGNasalSys::init() initNasalCanvas(_globals, _context, _gcHash); initNasalCondition(_globals, _context, _gcHash); + NasalTimerObj::init("Timer") + .method("start", &TimerObj::start) + .method("stop", &TimerObj::stop) + .method("restart", &TimerObj::restart) + .member("singleShot", &TimerObj::isSingleShot, &TimerObj::setSingleShot); + // Now load the various source files in the Nasal directory simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal")); loadScriptDirectory(nasalDir); @@ -1129,7 +1243,7 @@ void FGNasalSys::registerToUnload(FGNasalModelData *data) _unloadList.push(data); } - +////////////////////////////////////////////////////////////////////////// // FGNasalListener class. FGNasalListener::FGNasalListener(SGPropertyNode *node, naRef code,