1
0
Fork 0

add _setlistener() function, so that slow property polling loops can be

replaced with efficient listener callbacks. One use is the new FPS display.
This is reviewed and OK'ed by Andy, relatively trivial and separated from
the rest of Nasal, so problems are quite unlikely and confined to users of
this function.

The callback is executed whenever the property is written to -- even if
the value didn't change. The triggering Node is available via cmdarg().

Examples:  _setlistener("/sim/crashed", func {print("haha!")});
           _setlistener("/foo/bar", func { print(cmdarg().getPath() ~ " changed")})
This commit is contained in:
mfranz 2005-12-16 19:11:03 +00:00
parent 249a1264ff
commit 96c0a7bbc1
2 changed files with 52 additions and 0 deletions

View file

@ -234,6 +234,15 @@ static naRef f_settimer(naContext c, naRef me, int argc, naRef* args)
return naNil();
}
// setlistener(func, property) extension function. Falls through to
// FGNasalSys::setListener(). See there for docs.
static naRef f_setlistener(naContext c, naRef me, int argc, naRef* args)
{
FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal");
nasal->setListener(argc, args);
return naNil();
}
// Returns a ghost handle to the argument to the currently executing
// command
static naRef f_cmdarg(naContext c, naRef me, int argc, naRef* args)
@ -285,6 +294,7 @@ static struct { char* name; naCFunction func; } funcs[] = {
{ "print", f_print },
{ "_fgcommand", f_fgcommand },
{ "settimer", f_settimer },
{ "_setlistener", f_setlistener },
{ "_cmdarg", f_cmdarg },
{ "_interpolate", f_interpolate },
{ "rand", f_rand },
@ -553,3 +563,22 @@ void FGNasalSys::NasalTimer::timerExpired()
nasal->handleTimer(this);
delete this;
}
// setlistener(property, func) extension function. The first argument
// is either a ghost (SGPropertyNode_ptr*) or a string (global property
// path), the second is a Nasal function.
void FGNasalSys::setListener(int argc, naRef* args)
{
SGPropertyNode* node;
naRef prop = argc > 0 ? args[0] : naNil();
if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
else return;
naRef handler = argc > 1 ? args[1] : naNil();
if(!(naIsCode(handler) || naIsCCode(handler) || naIsFunc(handler)))
return;
node->addChangeListener(new FGNasalListener(handler, this, gcSave(handler)));
}

View file

@ -36,6 +36,9 @@ public:
// Implementation of the settimer extension function
void setTimer(int argc, naRef* args);
// Implementation of the setlistener extension function
void setListener(int argc, naRef* args);
// Returns a ghost wrapper for the current _cmdArg
naRef cmdArgGhost();
@ -47,6 +50,7 @@ public:
private:
friend class FGNasalScript;
friend class FGNasalListener;
//
// FGTimer subclass for handling Nasal timer callbacks.
@ -103,4 +107,23 @@ private:
FGNasalSys* _nas;
};
class FGNasalListener : public SGPropertyChangeListener {
public:
FGNasalListener(naRef handler, FGNasalSys* nasal, int gcKey)
: _handler(handler), _gcKey(gcKey), _nas(nasal) {}
void valueChanged(SGPropertyNode* node) {
_nas->_cmdArg = node;
naCall(_nas->_context, _handler, 0, 0, naNil(), naNil());
if(naGetError(_nas->_context))
_nas->logError();
}
private:
friend class FGNasalSys;
naRef _handler;
int _gcKey;
FGNasalSys* _nas;
};
#endif // __NASALSYS_HXX