// 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)
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++);
// 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()
// 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;
+ }
+ }
+}