]> git.mxchange.org Git - simgear.git/commitdiff
First working version of DOM like Canvas event handling
authorThomas Geymayer <tomgey@gmail.com>
Sun, 2 Dec 2012 12:19:35 +0000 (13:19 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 2 Dec 2012 12:22:37 +0000 (13:22 +0100)
 - Now it is possible to attach listeners to canvas
   elements and also the canvas itself, which get
   called upon different mouse events (Currently
   only basic mouse events supported. click/dblclick
   etc. are missing)

15 files changed:
simgear/canvas/Canvas.cxx
simgear/canvas/Canvas.hxx
simgear/canvas/CanvasEvent.cxx
simgear/canvas/CanvasEvent.hxx
simgear/canvas/CanvasEventListener.cxx
simgear/canvas/CanvasEventListener.hxx
simgear/canvas/CanvasEventTypes.hxx
simgear/canvas/CanvasEventVisitor.cxx
simgear/canvas/CanvasEventVisitor.hxx
simgear/canvas/CanvasSystemAdapter.hxx
simgear/canvas/MouseEvent.hxx
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/nasal/cppbind/Ghost.hxx
simgear/nasal/cppbind/cppbind_test.cxx

index d2dc2358174a0408f8597033807ca7209651205e..58c115a85eb74adf11c07e8c44319f4ae236b12e 100644 (file)
@@ -256,6 +256,15 @@ namespace canvas
     }
   }
 
+  //----------------------------------------------------------------------------
+  naRef Canvas::addEventListener(const nasal::CallContext& ctx)
+  {
+    if( !_root_group.get() )
+      naRuntimeError(ctx.c, "Canvas: No root group!");
+
+    return _root_group->addEventListener(ctx);
+  }
+
   //----------------------------------------------------------------------------
   void Canvas::setSizeX(int sx)
   {
index 4ad23527d7ff0b62f5c00a7a1b0ca8f6831a17e0..594d67cf22ee937fda0e711fc27bff109672edd4 100644 (file)
@@ -103,6 +103,8 @@ namespace canvas
 
       void update(double delta_time_sec);
 
+      naRef addEventListener(const nasal::CallContext& ctx);
+
       void setSizeX(int sx);
       void setSizeY(int sy);
 
index 36b73ecf313919b00af9f99f1b69dbe43bb72f38..1e9815e8bb0d1c2207c9bf22d1810679ae7f306f 100644 (file)
@@ -1,4 +1,4 @@
-// Canvas Event for event model similar to DOM Level 2 Event Model
+// Canvas Event for event model similar to DOM Level 3 Event Model
 //
 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
 //
@@ -25,7 +25,14 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   Event::Event():
-    type(UNKNOWN)
+    type(UNKNOWN),
+    propagation_stopped(false)
+  {
+
+  }
+
+  //----------------------------------------------------------------------------
+  Event::~Event()
   {
 
   }
@@ -55,5 +62,31 @@ namespace canvas
     return target;
   }
 
+  //----------------------------------------------------------------------------
+  void Event::stopPropagation()
+  {
+    propagation_stopped = true;
+  }
+
+  //----------------------------------------------------------------------------
+  Event::Type Event::strToType(const std::string& str)
+  {
+    typedef std::map<std::string, Type> TypeMap;
+    static TypeMap type_map;
+
+    if( type_map.empty() )
+    {
+#     define ENUM_MAPPING(type, str) type_map[ str ] = type;
+#       include "CanvasEventTypes.hxx"
+#     undef ENUM_MAPPING
+    }
+
+    TypeMap::const_iterator it = type_map.find(str);
+    if( it == type_map.end() )
+      return UNKNOWN;
+
+    return it->second;
+  }
+
 } // namespace canvas
 } // namespace simgear
index b8babfb54682423d1c335acdca8e218882e38068..9ac9d475675b98fe156d427fa8ae4f1d9ced56d6 100644 (file)
@@ -1,4 +1,4 @@
-// Canvas Event for event model similar to DOM Level 2 Event Model
+// Canvas Event for event model similar to DOM Level 3 Event Model
 //
 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
 //
@@ -42,11 +42,21 @@ namespace canvas
 
       Type              type;
       ElementWeakPtr    target;
+      bool              propagation_stopped;
 
       Event();
+
+      // We need a vtable to allow nasal::Ghost to determine the dynamic type
+      // of the actual event instances.
+      virtual ~Event();
+
       Type getType() const;
       std::string getTypeString() const;
+
       ElementWeakPtr getTarget() const;
+      void stopPropagation();
+
+      static Type strToType(const std::string& str);
 
   };
 
index b94928b2ba009310bdb0364a60591d896fa4d1df..70f458fb8a0584bb17bfe59780caa650618a40be 100644 (file)
 // License along with this library; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
+#include "CanvasEvent.hxx"
 #include "CanvasEventListener.hxx"
 #include "CanvasSystemAdapter.hxx"
 
-#include <simgear/nasal/nasal.h>
+#include <simgear/nasal/cppbind/Ghost.hxx>
 
 namespace simgear
 {
@@ -52,13 +53,16 @@ namespace canvas
   }
 
   //------------------------------------------------------------------------------
-  void EventListener::call()
+  void EventListener::call(const canvas::EventPtr& event)
   {
-    const size_t num_args = 1;
-    naRef args[num_args] = {
-      naNil()
+    SystemAdapterPtr sys = _sys.lock();
+
+    naRef args[] = {
+      nasal::Ghost<EventPtr>::create(sys->getNasalContext(), event)
     };
-    _sys.lock()->callMethod(_code, naNil(), num_args, args, naNil());
+    const int num_args = sizeof(args)/sizeof(args[0]);
+
+    sys->callMethod(_code, naNil(), num_args, args, naNil());
   }
 
 
index 022b76a11be73d6904398ed14208050c164e183d..b8e39c5021d239904a5f8d42e58c4d4825eac17e 100644 (file)
@@ -34,7 +34,7 @@ namespace canvas
                      const SystemAdapterPtr& sys_adapter );
       ~EventListener();
 
-      void call();
+      void call(const canvas::EventPtr& event);
 
     protected:
       naRef _code;
index 6e428ee596cd59b6b128375e54b7ca40a239e179..78c772a7d2ec68320698a9298cdfc0dc8584da69 100644 (file)
@@ -24,6 +24,8 @@ ENUM_MAPPING(MOUSE_DOWN,  "mousedown")
 ENUM_MAPPING(MOUSE_UP,    "mouseup")
 ENUM_MAPPING(CLICK,       "click")
 ENUM_MAPPING(DBL_CLICK,   "dblclick")
+ENUM_MAPPING(DRAG,        "drag")
+ENUM_MAPPING(WHEEL,       "wheel")
 ENUM_MAPPING(MOUSE_MOVE,  "mousemove")
 ENUM_MAPPING(MOUSE_OVER,  "mouseover")
 ENUM_MAPPING(MOUSE_OUT,   "mouseout")
index 9970d8d9da4b4701b615fac4bc0390c44a7b1aea..b74ee171690923b46ba5510d472bbbbb34b97524 100644 (file)
@@ -1,5 +1,5 @@
 // Visitor for traversing a canvas element hierarchy similar to the traversal
-// of the DOM Level 2 Event Model
+// of the DOM Level 3 Event Model
 //
 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
 //
@@ -70,7 +70,10 @@ namespace canvas
         m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1)
       );
 
-      if( !el.hitBound(local_pos) )
+      // Don't check collision with root element (2nd element in _target_path)
+      // do event listeners attached to the canvas itself (its root group)
+      // always get called even if no element has been hit.
+      if( _target_path.size() > 2 && !el.hitBound(local_pos) )
         return false;
 
       const osg::Vec2f& delta = _target_path.back().local_delta;
@@ -83,7 +86,7 @@ namespace canvas
       EventTarget target = {&el, local_pos, local_delta};
       _target_path.push_back(target);
 
-      if( el.traverse(*this) )
+      if( el.traverse(*this) || _target_path.size() <= 2 )
         return true;
 
       _target_path.pop_back();
@@ -96,7 +99,10 @@ namespace canvas
   //----------------------------------------------------------------------------
   bool EventVisitor::propagateEvent(const EventPtr& event)
   {
-//    std::cout << "Propagate event " << event->getTypeString() << "\n";
+    // Event propagation similar to DOM Level 3 event flow:
+    // http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
+
+    // Capturing phase
 //    for( EventTargets::iterator it = _target_path.begin();
 //                                it != _target_path.end();
 //                              ++it )
@@ -106,6 +112,20 @@ namespace canvas
 //                  << "(" << it->local_pos.x() << "|" << it->local_pos.y() << ")\n";
 //    }
 
+    // Bubbling phase
+    for( EventTargets::reverse_iterator it = _target_path.rbegin();
+                                        it != _target_path.rend();
+                                      ++it )
+    {
+      if( !it->element )
+        continue;
+
+      it->element->callListeners(event);
+
+      if( event->propagation_stopped )
+        return true;
+    }
+
     return true;
   }
 
index 415641b0dbc6b57c7c31fec8a7054659939e7d60..e12b908856086abefd5bfc78884dbb8a3d4cfee6 100644 (file)
@@ -1,5 +1,5 @@
 // Visitor for traversing a canvas element hierarchy similar to the traversal
-// of the DOM Level 2 Event Model
+// of the DOM Level 3 Event Model
 //
 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
 //
index 6a608d9a2497fe6a360ff9a89ea35e1b999f77ec..a2bb1fe281ec4edf27bfd9f8812da548f2673e92 100644 (file)
@@ -20,7 +20,7 @@
 #define SG_CANVAS_SYSTEM_ADAPTER_HXX_
 
 #include "canvas_fwd.hxx"
-#include <simgear/nasal/naref.h>
+#include <simgear/nasal/nasal.h>
 
 namespace simgear
 {
@@ -37,6 +37,8 @@ namespace canvas
       virtual void removeCamera(osg::Camera* camera) const = 0;
       virtual osg::Image* getImage(const std::string& path) const = 0;
 
+      virtual naContext getNasalContext() const = 0;
+
       /**
        * Save passed reference to Nasal object from being deleted by the
        * garbage collector.
index 39a6404d7ffbfe905fcf15594f00deee7e31f6db..3193f27819e49cb7fa74374d77c1d05cfbc0e14b 100644 (file)
@@ -41,6 +41,12 @@ namespace canvas
       osg::Vec3f getPos3() const { return osg::Vec3f(pos, 0); }
       osg::Vec2f getDelta() const { return delta; }
 
+      float getPosX() const { return pos.x(); }
+      float getPosY() const { return pos.y(); }
+
+      float getDeltaX() const { return delta.x(); }
+      float getDeltaY() const { return delta.y(); }
+
       osg::Vec2f  pos,
                   delta;
       int         button, //<! Button for this event
index 2059c6586b083f4b669de33ceca729a294959b78..934767cf491acd8504bd28a21df1eb53e46a47b2 100644 (file)
@@ -17,6 +17,8 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "CanvasElement.hxx"
+#include <simgear/canvas/Canvas.hxx>
+#include <simgear/canvas/CanvasEventListener.hxx>
 #include <simgear/canvas/CanvasEventVisitor.hxx>
 #include <simgear/canvas/MouseEvent.hxx>
 
@@ -24,6 +26,7 @@
 #include <osg/Geode>
 
 #include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
 
 #include <cassert>
 #include <cstring>
@@ -112,7 +115,28 @@ namespace canvas
   //----------------------------------------------------------------------------
   naRef Element::addEventListener(const nasal::CallContext& ctx)
   {
-    std::cout << "addEventListener " << _node->getPath() << std::endl;
+    const std::string type_str = ctx.requireArg<std::string>(0);
+    naRef code = ctx.requireArg<naRef>(1);
+
+    SG_LOG
+    (
+      SG_NASAL,
+      SG_INFO,
+      "addEventListener(" << _node->getPath() << ", " << type_str << ")"
+    );
+
+    Event::Type type = Event::strToType(type_str);
+    if( type == Event::UNKNOWN )
+      naRuntimeError( ctx.c,
+                      "addEventListener: Unknown event type %s",
+                      type_str.c_str() );
+
+    _listener[ type ].push_back
+    (
+      boost::make_shared<EventListener>( code,
+                                         _canvas.lock()->getSystemAdapter() )
+    );
+
     return naNil();
   }
 
@@ -148,6 +172,17 @@ namespace canvas
     return true;
   }
 
+  //----------------------------------------------------------------------------
+  void Element::callListeners(const canvas::EventPtr& event)
+  {
+    ListenerMap::iterator listeners = _listener.find(event->getType());
+    if( listeners == _listener.end() )
+      return;
+
+    BOOST_FOREACH(EventListenerPtr listener, listeners->second)
+      listener->call(event);
+  }
+
   //----------------------------------------------------------------------------
   bool Element::hitBound(const osg::Vec2f& pos) const
   {
@@ -295,14 +330,6 @@ namespace canvas
     );
   }
 
-  //----------------------------------------------------------------------------
-  void Element::callListeners(canvas::Event& event)
-  {
-    ListenerMap::iterator listeners = _listener.find(event.getType());
-    if( listeners == _listener.end() )
-      return;
-  }
-
   //----------------------------------------------------------------------------
   void Element::setDrawable( osg::Drawable* drawable )
   {
index bf71a4cd52b0a98727837231e0dcfd1c46f99776..0f4b31edf6a4d1a48c12b66f1e301c1a8d1d569a 100644 (file)
@@ -78,6 +78,8 @@ namespace canvas
       virtual bool ascend(EventVisitor& visitor);
       virtual bool traverse(EventVisitor& visitor);
 
+      void callListeners(const canvas::EventPtr& event);
+
       virtual bool hitBound(const osg::Vec2f& pos) const;
 
 
@@ -168,8 +170,6 @@ namespace canvas
         return boost::bind(setter, instance, boost::bind(&getValue<T1>, _1));
       }
 
-      void callListeners(canvas::Event& event);
-
       virtual void childAdded(SGPropertyNode * child)  {}
       virtual void childRemoved(SGPropertyNode * child){}
       virtual void childChanged(SGPropertyNode * child){}
index bc32f9ed14256388dbb734034451504e2506944d..d2a5d22c9906b80610750537961cb6f4720706ad 100644 (file)
@@ -26,6 +26,7 @@
 #include <simgear/debug/logstream.hxx>
 
 #include <boost/bind.hpp>
+#include <boost/call_traits.hpp>
 #include <boost/function.hpp>
 #include <boost/lambda/lambda.hpp>
 #include <boost/utility/enable_if.hpp>
@@ -457,12 +458,13 @@ namespace nasal
       template<class Var>
       Ghost& member( const std::string& field,
                      Var (raw_type::*getter)() const,
-                     void (raw_type::*setter)(Var) = 0 )
+                     void (raw_type::*setter)(typename boost::call_traits<Var>::param_type) = 0 )
       {
         member_t m;
         if( getter )
         {
-          naRef (*to_nasal_)(naContext, Var) = &nasal::to_nasal;
+          typedef typename boost::call_traits<Var>::param_type param_type;
+          naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal;
 
           // Getter signature: naRef(naContext, raw_type&)
           m.getter = boost::bind(to_nasal_, _1, boost::bind(getter, _2));
index ef1b4674e788969242e73411df4a6fbcf1ba820a..47a437bcb01aa8dbd8f06240875df38422dbff38 100644 (file)
@@ -17,6 +17,9 @@ struct Base
 {
   naRef member(const nasal::CallContext&) { return naNil(); }
   virtual ~Base(){};
+
+  std::string getString() const { return ""; }
+  void setString(const std::string&) {}
 };
 struct Derived:
   public Base
@@ -96,7 +99,8 @@ int main(int argc, char* argv[])
   mod.set("parent", hash);
 
   Ghost<Base>::init("Base")
-    .method<&Base::member>("member");
+    .method<&Base::member>("member")
+    .member("str", &Base::getString, &Base::setString);
   Ghost<Derived>::init("Derived")
     .bases<Base>()
     .member("x", &Derived::getX, &Derived::setX)