event_mgr.hxx \
subsystem_mgr.hxx \
SGAtomic.hxx \
+ SGBinding.hxx \
SGReferenced.hxx \
SGSharedPtr.hxx
exception.cxx \
event_mgr.cxx\
subsystem_mgr.cxx \
- SGAtomic.cxx
+ SGAtomic.cxx \
+ SGBinding.cxx
INCLUDES = -I$(top_srcdir)
--- /dev/null
+/**
+ * \file commands.hxx
+ * Interface definition for encapsulated commands.
+ * Started Spring 2001 by David Megginson, david@megginson.com
+ * This code is released into the Public Domain.
+ *
+ * $Id$
+ */
+
+#include <simgear/compiler.h>
+#include "SGBinding.hxx"
+
+SGBinding::SGBinding()
+ : _command(0),
+ _arg(new SGPropertyNode),
+ _setting(0)
+{
+}
+
+SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root)
+ : _command(0),
+ _arg(0),
+ _setting(0)
+{
+ read(node, root);
+}
+
+SGBinding::~SGBinding()
+{
+ _arg->getParent()->removeChild(_arg->getName(), _arg->getIndex(), false);
+}
+
+void
+SGBinding::read(const SGPropertyNode* node, SGPropertyNode* root)
+{
+ const SGPropertyNode * conditionNode = node->getChild("condition");
+ if (conditionNode != 0)
+ setCondition(sgReadCondition(root, conditionNode));
+
+ _command_name = node->getStringValue("command", "");
+ if (_command_name.empty()) {
+ SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
+ _command = 0;
+ return;
+ }
+
+ _arg = const_cast<SGPropertyNode*>(node);
+ _setting = 0;
+}
+
+void
+SGBinding::fire () const
+{
+ if (test()) {
+ if (_command == 0)
+ _command = SGCommandMgr::instance()->getCommand(_command_name);
+ if (_command == 0) {
+ SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
+ } else if (!(*_command)(_arg)) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
+ << _command_name);
+ }
+ }
+}
+
+void
+SGBinding::fire (double offset, double max) const
+{
+ if (test()) {
+ _arg->setDoubleValue("offset", offset/max);
+ fire();
+ }
+}
+
+void
+SGBinding::fire (double setting) const
+{
+ if (test()) {
+ // A value is automatically added to
+ // the args
+ if (_setting == 0) // save the setting node for efficiency
+ _setting = _arg->getChild("setting", 0, true);
+ _setting->setDoubleValue(setting);
+ fire();
+ }
+}
--- /dev/null
+/**
+ * \file commands.hxx
+ * Interface definition for encapsulated commands.
+ * Started Spring 2001 by David Megginson, david@megginson.com
+ * This code is released into the Public Domain.
+ *
+ * $Id$
+ */
+
+#ifndef __SGBINDING_HXX
+#define __SGBINDING_HXX
+
+
+#include <simgear/compiler.h>
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/condition.hxx>
+
+#include "commands.hxx"
+
+/**
+ * An input binding of some sort.
+ *
+ * <p>This class represents a binding that can be assigned to a
+ * keyboard key, a joystick button or axis, or even a panel
+ * instrument.</p>
+ */
+class SGBinding : public SGConditional
+{
+public:
+
+ /**
+ * Default constructor.
+ */
+ SGBinding ();
+
+
+ /**
+ * Convenience constructor.
+ *
+ * @param node The binding will be built from this node.
+ */
+ SGBinding (const SGPropertyNode * node, SGPropertyNode* root);
+
+
+ /**
+ * Destructor.
+ */
+ virtual ~SGBinding ();
+
+
+ /**
+ * Get the command name.
+ *
+ * @return The string name of the command for this binding.
+ */
+ const string &getCommandName () const { return _command_name; }
+
+
+ /**
+ * Get the command itself.
+ *
+ * @return The command associated with this binding, or 0 if none
+ * is present.
+ */
+ SGCommandMgr::command_t getCommand () const { return _command; }
+
+
+ /**
+ * Get the argument that will be passed to the command.
+ *
+ * @return A property node that will be passed to the command as its
+ * argument, or 0 if none was supplied.
+ */
+ const SGPropertyNode * getArg () { return _arg; }
+
+
+ /**
+ * Read a binding from a property node.
+ *
+ * @param node The property node containing the binding.
+ */
+ void read (const SGPropertyNode * node, SGPropertyNode* root);
+
+
+ /**
+ * Fire a binding.
+ */
+ void fire () const;
+
+
+ /**
+ * Fire a binding with a scaled movement (rather than absolute position).
+ */
+ void fire (double offset, double max) const;
+
+
+ /**
+ * Fire a binding with a setting (i.e. joystick axis).
+ *
+ * A double 'setting' property will be added to the arguments.
+ *
+ * @param setting The input setting, usually between -1.0 and 1.0.
+ */
+ void fire (double setting) const;
+
+
+private:
+ // just to be safe.
+ SGBinding (const SGBinding &binding);
+
+ std::string _command_name;
+ mutable SGCommandMgr::command_t _command;
+ mutable SGPropertyNode_ptr _arg;
+ mutable SGPropertyNode_ptr _setting;
+};
+
+typedef std::vector<SGSharedPtr<SGBinding> > SGBindingList;
+typedef std::map<unsigned,SGBindingList> SGBindingMap;
+
+#endif
//
// $Id$
+#include <memory>
#include <simgear/props/props_io.hxx>
+#include <simgear/threads/SGThread.hxx>
+#include <simgear/threads/SGGuard.hxx>
#include "commands.hxx"
// no-op
}
+SGCommandMgr*
+SGCommandMgr::instance()
+{
+ static std::auto_ptr<SGCommandMgr> mgr;
+ if (mgr.get())
+ return mgr.get();
+
+ static SGMutex lock;
+ SGGuard<SGMutex> guard(lock);
+ if (mgr.get())
+ return mgr.get();
+
+ mgr = std::auto_ptr<SGCommandMgr>(new SGCommandMgr);
+ return mgr.get();
+}
+
void
SGCommandMgr::addCommand (const string &name, command_t command)
{
typedef bool (*command_t) (const SGPropertyNode * arg);
- /**
- * Default constructor.
- */
- SGCommandMgr ();
-
-
/**
* Destructor.
*/
virtual ~SGCommandMgr ();
+ /**
+ * Implement the classical singleton.
+ */
+ static SGCommandMgr* instance();
/**
* Register a new command with the manager.
*/
virtual bool execute (const string &name, const SGPropertyNode * arg) const;
+protected:
+ /**
+ * Default constructor.
+ */
+ SGCommandMgr ();
+
+
private:
typedef map<string,command_t> command_map;