diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 7811895b2..ac5c98d1d 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -896,8 +896,9 @@ int FGNasalSys::_listenerId = 0; // setlistener(property, func, bool) extension function. The first argument // is either a ghost (SGPropertyNode_ptr*) or a string (global property -// path), the second is a Nasal function, the optional third one a bool. -// If the bool is true, then the listener is executed initially. The +// path), the second is a Nasal function, the optional third one an integer. +// If it is 1, then the listener is executed initially. If it's 2, then +// the listener is only triggered when the node value actually changed. The // setlistener() function returns a unique id number, that can be used // as argument to the removelistener() function. naRef FGNasalSys::setListener(naContext c, int argc, naRef* args) @@ -921,11 +922,10 @@ naRef FGNasalSys::setListener(naContext c, int argc, naRef* args) return naNil(); } - bool initial = argc > 2 && naTrue(args[2]); - + int type = argc > 2 && naIsNum(args[2]) ? args[2].num : 0; FGNasalListener *nl = new FGNasalListener(node, handler, this, - gcSave(handler), _listenerId); - node->addChangeListener(nl, initial); + gcSave(handler), _listenerId, type); + node->addChangeListener(nl, type != 0); _listener[_listenerId] = nl; return naNum(_listenerId++); @@ -960,15 +960,21 @@ naRef FGNasalSys::removeListener(naContext c, int argc, naRef* args) // FGNasalListener class. FGNasalListener::FGNasalListener(SGPropertyNode_ptr node, naRef handler, - FGNasalSys* nasal, int key, int id) : + FGNasalSys* nasal, int key, int id, + int type) : _node(node), _handler(handler), _gcKey(key), _id(id), + _type(type), _nas(nasal), _active(0), - _dead(false) + _dead(false), + _first_call(true), + _last_int(0L), + _last_float(0.0) { + unchanged(node); } FGNasalListener::~FGNasalListener() @@ -982,14 +988,51 @@ void FGNasalListener::valueChanged(SGPropertyNode* node) // drop recursive listener calls if(_active || _dead) return; + if(_type == 2 && !_first_call && unchanged(node)) + return; SG_LOG(SG_NASAL, SG_DEBUG, "trigger listener #" << _id); _active++; _nas->_cmdArg = node; _nas->call(_handler, naNil()); _active--; + _first_call = false; } +bool FGNasalListener::unchanged(SGPropertyNode* node) +{ + SGPropertyNode::Type type = node->getType(); + if(type == SGPropertyNode::NONE) return true; + if(type == SGPropertyNode::UNSPECIFIED) return false; + + bool result; + switch(type) { + case SGPropertyNode::BOOL: + case SGPropertyNode::INT: + case SGPropertyNode::LONG: + { + long l = node->getLongValue(); + result = l == _last_int; + _last_int = l; + return result; + } + case SGPropertyNode::FLOAT: + case SGPropertyNode::DOUBLE: + { + double d = node->getDoubleValue(); + result = d == _last_float; + _last_float = d; + return result; + } + default: + { + string s = node->getStringValue(); + result = s == _last_string; + _last_string = s; + return result; + } + } +} diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx index a68317570..0e46e9f20 100644 --- a/src/Scripting/NasalSys.hxx +++ b/src/Scripting/NasalSys.hxx @@ -132,10 +132,11 @@ private: class FGNasalListener : public SGPropertyChangeListener { public: FGNasalListener(SGPropertyNode_ptr node, naRef handler, - FGNasalSys* nasal, int key, int id); + FGNasalSys* nasal, int key, int id, int type); ~FGNasalListener(); void valueChanged(SGPropertyNode* node); + bool unchanged(SGPropertyNode* node); private: friend class FGNasalSys; @@ -143,9 +144,14 @@ private: naRef _handler; int _gcKey; int _id; + int _type; FGNasalSys* _nas; unsigned int _active; bool _dead; + bool _first_call; + long _last_int; + double _last_float; + string _last_string; };