]> git.mxchange.org Git - simgear.git/commitdiff
Canvas: support for custom events and event dispatching.
authorThomas Geymayer <tomgey@gmail.com>
Sun, 18 May 2014 11:29:48 +0000 (13:29 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 18 May 2014 22:17:23 +0000 (00:17 +0200)
23 files changed:
simgear/canvas/CMakeLists.txt
simgear/canvas/Canvas.cxx
simgear/canvas/Canvas.hxx
simgear/canvas/CanvasEvent.cxx
simgear/canvas/CanvasEvent.hxx
simgear/canvas/CanvasEventManager.cxx
simgear/canvas/CanvasEventManager.hxx
simgear/canvas/CanvasEventVisitor.cxx
simgear/canvas/CanvasObjectPlacement.cxx
simgear/canvas/CanvasWindow.hxx
simgear/canvas/MouseEvent.hxx [deleted file]
simgear/canvas/canvas_fwd.hxx
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/CanvasGroup.cxx
simgear/canvas/elements/CanvasImage.cxx
simgear/canvas/events/CMakeLists.txt [new file with mode: 0644]
simgear/canvas/events/CustomEvent.cxx [new file with mode: 0644]
simgear/canvas/events/CustomEvent.hxx [new file with mode: 0644]
simgear/canvas/events/MouseEvent.cxx [new file with mode: 0644]
simgear/canvas/events/MouseEvent.hxx [new file with mode: 0644]
simgear/canvas/events/event_test.cpp [new file with mode: 0644]
simgear/structure/map.hxx

index cbeffbaa5ffc329e7628ef0f3ca7fd0330898aca..fea5a22d7896f81f5e7596b497debf0f35eaf28f 100644 (file)
@@ -12,7 +12,6 @@ set(HEADERS
   CanvasPlacement.hxx
   CanvasSystemAdapter.hxx
   CanvasWindow.hxx
-  MouseEvent.hxx
   ODGauge.hxx
   VGInitOperation.hxx
 )
@@ -32,5 +31,6 @@ set(SOURCES
 
 add_subdirectory(ShivaVG/src)
 add_subdirectory(elements)
+add_subdirectory(events)
 
 simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
index f7ba3228cef1e89c9af370a54d3ef6a5a90d2fa7..c199f54f3745501667ff0ba43b2d786feb268273 100644 (file)
@@ -19,8 +19,8 @@
 #include "Canvas.hxx"
 #include "CanvasEventManager.hxx"
 #include "CanvasEventVisitor.hxx"
-#include <simgear/canvas/MouseEvent.hxx>
-#include <simgear/canvas/CanvasPlacement.hxx>
+#include "CanvasPlacement.hxx"
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/scene/util/parse_color.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
 
@@ -418,7 +418,7 @@ namespace canvas
   //----------------------------------------------------------------------------
   bool Canvas::handleMouseEvent(const MouseEventPtr& event)
   {
-    if( !_root_group.get() )
+    if( !_root_group )
       return false;
 
     EventVisitor visitor( EventVisitor::TRAVERSE_DOWN,
@@ -430,6 +430,13 @@ namespace canvas
     return _event_manager->handleEvent(event, visitor.getPropagationPath());
   }
 
+  //----------------------------------------------------------------------------
+  bool Canvas::propagateEvent( EventPtr const& event,
+                               EventPropagationPath const& path )
+  {
+    return _event_manager->propagateEvent(event, path);
+  }
+
   //----------------------------------------------------------------------------
   void Canvas::childAdded( SGPropertyNode * parent,
                            SGPropertyNode * child )
index a65ff01862a9cd7f8cea0e1871347e4bfd14f44f..380dac8b802d36ce4168b90842416fa80727b7fc 100644 (file)
@@ -146,6 +146,8 @@ namespace canvas
       SGRect<int> getViewport() const;
 
       bool handleMouseEvent(const MouseEventPtr& event);
+      bool propagateEvent( EventPtr const& event,
+                           EventPropagationPath const& path );
 
       virtual void childAdded( SGPropertyNode * parent,
                                SGPropertyNode * child );
index 414d19938eb775485f3510fa6ec97e829084b2b5..6c2684bc47ef724fc545b2557059d426bd6a9503 100644 (file)
@@ -26,6 +26,7 @@ namespace canvas
   //----------------------------------------------------------------------------
   Event::Event():
     type(UNKNOWN),
+    time(-1),
     propagation_stopped(false)
   {
 
@@ -38,7 +39,13 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  Event::Type Event::getType() const
+  bool Event::canBubble() const
+  {
+    return true;
+  }
+
+  //----------------------------------------------------------------------------
+  int Event::getType() const
   {
     return type;
   }
@@ -46,14 +53,7 @@ namespace canvas
   //----------------------------------------------------------------------------
   std::string Event::getTypeString() const
   {
-    switch( type )
-    {
-#     define ENUM_MAPPING(name, str) case name: return str;
-#       include "CanvasEventTypes.hxx"
-#     undef ENUM_MAPPING
-      default:
-        return "unknown";
-    }
+    return typeToStr(type);
   }
 
   //----------------------------------------------------------------------------
@@ -81,24 +81,58 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  Event::Type Event::strToType(const std::string& str)
+  int Event::getOrRegisterType(const std::string& type_str)
   {
-    typedef std::map<std::string, Type> TypeMap;
-    static TypeMap type_map;
+    int type = strToType(type_str);
 
-    if( type_map.empty() )
+    if( type == UNKNOWN )
     {
-#     define ENUM_MAPPING(type, str) type_map[ str ] = type;
-#       include "CanvasEventTypes.hxx"
-#     undef ENUM_MAPPING
+      // Register new type
+      TypeMap& type_map = getTypeMap();
+      type = type_map.size() + 1; // ids start with 1 (after UNKNOWN)
+      type_map.insert(TypeMap::value_type(type_str, type));
     }
 
-    TypeMap::const_iterator it = type_map.find(str);
-    if( it == type_map.end() )
+    return type;
+  }
+
+  //----------------------------------------------------------------------------
+  int Event::strToType(const std::string& str)
+  {
+    TypeMap const& type_map = getTypeMap();
+
+    TypeMap::map_by<name>::const_iterator it = type_map.by<name>().find(str);
+    if( it == type_map.by<name>().end() )
       return UNKNOWN;
+    return it->second;
+  }
+
+  //----------------------------------------------------------------------------
+  std::string Event::typeToStr(int type)
+  {
+    TypeMap const& type_map = getTypeMap();
 
+    TypeMap::map_by<id>::const_iterator it = type_map.by<id>().find(type);
+    if( it == type_map.by<id>().end() )
+      return "unknown";
     return it->second;
   }
 
+  //----------------------------------------------------------------------------
+  Event::TypeMap& Event::getTypeMap()
+  {
+    static TypeMap type_map;
+
+    if( type_map.empty() )
+    {
+#   define ENUM_MAPPING(type, str)\
+      type_map.insert(TypeMap::value_type(str, type));
+#     include "CanvasEventTypes.hxx"
+#   undef ENUM_MAPPING
+    }
+
+    return type_map;
+  }
+
 } // namespace canvas
 } // namespace simgear
index c3121269e90c90435e16eab424bac5f34c3ab5d1..0e98c6f1e07976f54196424cc1cbd74ec5e1022d 100644 (file)
 #define CANVAS_EVENT_HXX_
 
 #include "canvas_fwd.hxx"
+#include <boost/bimap.hpp>
 
 namespace simgear
 {
 namespace canvas
 {
 
-  class Event
+  class Event:
+    public SGReferenced
   {
     public:
 
@@ -36,11 +38,11 @@ namespace canvas
 #       define ENUM_MAPPING(name, str) name,
 #         include "CanvasEventTypes.hxx"
 #       undef ENUM_MAPPING
-        USER_TYPE ///<! first unused id to be used for user defined types (not
-                  ///   implemented yet)
+        CUSTOM_EVENT ///<! all user defined event types share the same id. They
+                     ///   are just differentiated by using the type string.
       };
 
-      Type              type;
+      int               type;
       ElementWeakPtr    target,
                         current_target;
       double            time;
@@ -52,7 +54,19 @@ namespace canvas
       // of the actual event instances.
       virtual ~Event();
 
-      Type getType() const;
+      /**
+       * Get whether this events support bubbling
+       */
+      virtual bool canBubble() const;
+
+      /**
+       * Set type of event.
+       *
+       * If no such type exists it is registered.
+       */
+      void setType(const std::string& type);
+
+      int getType() const;
       std::string getTypeString() const;
 
       ElementWeakPtr getTarget() const;
@@ -62,7 +76,19 @@ namespace canvas
 
       void stopPropagation();
 
-      static Type strToType(const std::string& str);
+      static int getOrRegisterType(const std::string& type);
+      static int strToType(const std::string& type);
+      static std::string typeToStr(int type);
+
+    protected:
+      struct name {};
+      struct id {};
+      typedef boost::bimaps::bimap<
+        boost::bimaps::tagged<std::string, name>,
+        boost::bimaps::tagged<int, id>
+      > TypeMap;
+
+      static TypeMap& getTypeMap();
 
   };
 
index 21d97c78de2e8014566d4ef955bcffe90c9b5ea4..cf8ac789bf22e405439534ee3da9016269f38697 100644 (file)
@@ -17,7 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "CanvasEventManager.hxx"
-#include "MouseEvent.hxx"
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/canvas/elements/CanvasElement.hxx>
 #include <cmath>
 
@@ -144,6 +144,71 @@ namespace canvas
     return handled | propagateEvent(event, path);
   }
 
+  //----------------------------------------------------------------------------
+  bool EventManager::propagateEvent( const EventPtr& event,
+                                     const EventPropagationPath& path )
+  {
+    event->target = path.back().element;
+    MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
+
+    // Event propagation similar to DOM Level 3 event flow:
+    // http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
+
+    // Position update only needed for drag event (as event needs to be
+    // delivered to element of initial mousedown, but with update positions)
+    if( mouse_event && mouse_event->type == MouseEvent::DRAG )
+    {
+      osg::Vec2f local_pos = mouse_event->client_pos;
+
+      // Capturing phase (currently just update position)
+      for( EventPropagationPath::const_iterator it = path.begin();
+                                                it != path.end();
+                                              ++it )
+      {
+        ElementPtr el = it->element.lock();
+        if( !el )
+          continue;
+
+        it->local_pos = local_pos = el->posToLocal(local_pos);
+      }
+    }
+
+    bool const do_bubble = event->canBubble();
+
+    // Bubbling phase
+    for( EventPropagationPath::const_reverse_iterator
+           it = path.rbegin();
+           it != path.rend();
+         ++it )
+    {
+      ElementPtr el = it->element.lock();
+
+      if( !el )
+      {
+        // Ignore element if it has been destroyed while traversing the event
+        // (eg. removed by another event handler)
+        if( do_bubble )
+          continue;
+        else
+          break;
+      }
+
+      // TODO provide functions to convert delta to local coordinates on demand.
+      //      Maybe also provide a clone method for events as local coordinates
+      //      might differ between different elements receiving the same event.
+      if( mouse_event )
+        mouse_event->local_pos = it->local_pos;
+
+      event->current_target = el;
+      el->handleEvent(event);
+
+      if( event->propagation_stopped || !do_bubble )
+        return true;
+    }
+
+    return true;
+  }
+
   //----------------------------------------------------------------------------
   bool EventManager::handleClick( const MouseEventPtr& event,
                                   const EventPropagationPath& path )
@@ -249,84 +314,6 @@ namespace canvas
     return handled;
   }
 
-  //----------------------------------------------------------------------------
-  bool EventManager::propagateEvent( const EventPtr& event,
-                                     const EventPropagationPath& path )
-  {
-    event->target = path.back().element;
-    MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
-
-    // Event propagation similar to DOM Level 3 event flow:
-    // http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
-
-    // Position update only needed for drag event (as event needs to be
-    // delivered to element of initial mousedown, but with update positions)
-    if( mouse_event && mouse_event->type == MouseEvent::DRAG )
-    {
-      osg::Vec2f local_pos = mouse_event->client_pos;
-
-      // Capturing phase (currently just update position)
-      for( EventPropagationPath::const_iterator it = path.begin();
-                                                it != path.end();
-                                              ++it )
-      {
-        ElementPtr el = it->element.lock();
-        if( !el )
-          continue;
-
-        it->local_pos = local_pos = el->posToLocal(local_pos);
-      }
-    }
-
-    // Check if event supports bubbling
-    const Event::Type types_no_bubbling[] = {
-      Event::MOUSE_ENTER,
-      Event::MOUSE_LEAVE,
-    };
-    const size_t num_types_no_bubbling = sizeof(types_no_bubbling)
-                                       / sizeof(types_no_bubbling[0]);
-    bool do_bubble = true;
-    for( size_t i = 0; i < num_types_no_bubbling; ++i )
-      if( event->type == types_no_bubbling[i] )
-      {
-        do_bubble = false;
-        break;
-      }
-
-    // Bubbling phase
-    for( EventPropagationPath::const_reverse_iterator
-           it = path.rbegin();
-           it != path.rend();
-         ++it )
-    {
-      ElementPtr el = it->element.lock();
-
-      if( !el )
-      {
-        // Ignore element if it has been destroyed while traversing the event
-        // (eg. removed by another event handler)
-        if( do_bubble )
-          continue;
-        else
-          break;
-      }
-
-      // TODO provide functions to convert delta to local coordinates on demand.
-      //      Maybe also provide a clone method for events as local coordinates
-      //      might differ between different elements receiving the same event.
-      if( mouse_event )
-        mouse_event->local_pos = it->local_pos;
-
-      event->current_target = el;
-      el->handleEvent(event);
-
-      if( event->propagation_stopped || !do_bubble )
-        return true;
-    }
-
-    return true;
-  }
-
   //----------------------------------------------------------------------------
   bool
   EventManager::checkClickDistance( const osg::Vec2f& pos1,
index 8ea44d9a5e1ae309ce8436e68b0eae78c4877644..5e3738c8a6a7287f159ced968e7a58fd20e07ffc 100644 (file)
@@ -33,8 +33,14 @@ namespace canvas
 
     // Used as storage by EventManager during event propagation
     mutable osg::Vec2f  local_pos;
+
+    EventTarget( Element* el,
+                 const osg::Vec2f pos = osg::Vec2f() ):
+      element(el),
+      local_pos(pos)
+    {}
   };
-  typedef std::deque<EventTarget> EventPropagationPath;
+
   inline bool operator==(const EventTarget& t1, const EventTarget& t2)
   {
     return t1.element.lock() == t2.element.lock();
@@ -48,6 +54,9 @@ namespace canvas
       bool handleEvent( const MouseEventPtr& event,
                         const EventPropagationPath& path );
 
+      bool propagateEvent( const EventPtr& event,
+                           const EventPropagationPath& path );
+
     protected:
       struct StampedPropagationPath
       {
@@ -89,9 +98,6 @@ namespace canvas
       bool handleMove( const MouseEventPtr& event,
                        const EventPropagationPath& path );
 
-      bool propagateEvent( const EventPtr& event,
-                           const EventPropagationPath& path );
-
       /**
        * Check if two click events (either mousedown/up or two consecutive
        * clicks) are inside a maximum distance to still create a click or
index 98953034b6842377b451b834ef681fae339d9c78..efb12dbb49ad0073c0558d869765f75021dd17b6 100644 (file)
@@ -34,10 +34,7 @@ namespace canvas
     _root(root)
   {
     if( mode == TRAVERSE_DOWN )
-    {
-      EventTarget target = {ElementWeakPtr(), pos};
-      _target_path.push_back(target);
-    }
+      _target_path.push_back( EventTarget(NULL, pos) );
   }
 
   //----------------------------------------------------------------------------
@@ -72,8 +69,7 @@ namespace canvas
           && !el.hitBound(_target_path.front().local_pos, pos, local_pos) )
         return false;
 
-      EventTarget target = {ElementPtr(&el), local_pos};
-      _target_path.push_back(target);
+      _target_path.push_back( EventTarget(&el, local_pos) );
 
       if( el.traverse(*this) || &el == _root.get() )
         return true;
index fc0b738f34efa5c929d35e9df97f9f36abb341f0..d4a8a85cafc1eb9a21f02d50695e17d9c15f59fa 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "Canvas.hxx"
 #include "CanvasObjectPlacement.hxx"
-#include "MouseEvent.hxx"
+#include <simgear/canvas/events/MouseEvent.hxx>
 
 #include <simgear/props/props.hxx>
 #include <simgear/scene/util/SGPickCallback.hxx>
index 74bdf33fed7e10e4cd20ffa0080f25fabb3c9a93..57068a84e914b66fba986e648e1e187804780dc3 100644 (file)
@@ -20,7 +20,7 @@
 #define CANVAS_WINDOW_HXX_
 
 #include <simgear/canvas/elements/CanvasImage.hxx>
-#include <simgear/canvas/MouseEvent.hxx>
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/props/PropertyBasedElement.hxx>
 #include <simgear/props/propertyObject.hxx>
 #include <simgear/misc/CSSBorder.hxx>
diff --git a/simgear/canvas/MouseEvent.hxx b/simgear/canvas/MouseEvent.hxx
deleted file mode 100644 (file)
index 182115a..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-// Mouse event
-//
-// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
-
-#ifndef CANVAS_MOUSE_EVENT_HXX_
-#define CANVAS_MOUSE_EVENT_HXX_
-
-#include "CanvasEvent.hxx"
-#include <osgGA/GUIEventAdapter>
-
-namespace simgear
-{
-namespace canvas
-{
-
-  class MouseEvent:
-    public Event
-  {
-    public:
-      MouseEvent():
-        button(0),
-        buttons(0),
-        modifiers(0),
-        click_count(0)
-      {}
-
-      MouseEvent(const osgGA::GUIEventAdapter& ea):
-        button(0),
-        buttons(ea.getButtonMask()),
-        modifiers(ea.getModKeyMask()),
-        click_count(0)
-      {
-        time = ea.getTime();
-
-        // Convert button mask to index
-        int button_mask = ea.getButton();
-        while( (button_mask >>= 1) > 0 )
-          button += 1;
-      }
-
-      osg::Vec2f getScreenPos() const { return screen_pos; }
-      osg::Vec2f getClientPos() const { return client_pos; }
-      osg::Vec2f getLocalPos()  const { return  local_pos; }
-      osg::Vec2f getDelta() const { return delta; }
-
-      float getScreenX() const { return screen_pos.x(); }
-      float getScreenY() const { return screen_pos.y(); }
-
-      float getClientX() const { return client_pos.x(); }
-      float getClientY() const { return client_pos.y(); }
-
-      float getLocalX() const { return local_pos.x(); }
-      float getLocalY() const { return local_pos.y(); }
-
-      float getDeltaX() const { return delta.x(); }
-      float getDeltaY() const { return delta.y(); }
-
-      int getButton() const { return button; }
-      int getButtonMask() const { return buttons; }
-      int getModifiers() const { return modifiers; }
-
-      int getCurrentClickCount() const { return click_count; }
-
-      osg::Vec2f  screen_pos,   //<! Position in screen coordinates
-                  client_pos,   //<! Position in window/canvas coordinates
-                  local_pos,    //<! Position in local/element coordinates
-                  delta;
-      int         button,       //<! Button for this event
-                  buttons,      //<! Current button state
-                  modifiers,    //<! Keyboard modifier state
-                  click_count;  //<! Current click count
-  };
-
-} // namespace canvas
-} // namespace simgear
-
-#endif /* CANVAS_MOUSE_EVENT_HXX_ */
index 6b34e028f0f4147954ce25e357eb5cf61ebe9b39..b14d2886cd01845fd538ee4f4c6925e5b82390e3 100644 (file)
@@ -51,6 +51,10 @@ namespace canvas
   SG_FWD_DECL(Text)
   SG_FWD_DECL(Window)
 
+  SG_FWD_DECL(Event)
+  SG_FWD_DECL(CustomEvent)
+  SG_FWD_DECL(MouseEvent)
+
 #undef SG_FWD_DECL
 
 #define SG_FWD_DECL(name)\
@@ -58,8 +62,6 @@ namespace canvas
   typedef boost::shared_ptr<name> name##Ptr;\
   typedef boost::weak_ptr<name> name##WeakPtr;
 
-  SG_FWD_DECL(Event)
-  SG_FWD_DECL(MouseEvent)
   SG_FWD_DECL(Placement)
   SG_FWD_DECL(SystemAdapter)
 
@@ -68,6 +70,9 @@ namespace canvas
   class EventManager;
   class EventVisitor;
 
+  struct EventTarget;
+  typedef std::deque<EventTarget> EventPropagationPath;
+
   typedef std::map<std::string, const SGPropertyNode*> Style;
   typedef ElementPtr (*ElementFactory)( const CanvasWeakPtr&,
                                         const SGPropertyNode_ptr&,
index 82fc659c86aecf1584a5a7bf50285a47d5d0b105..c763ab865be90d2f92c48a9cb48ee706d0f79c25 100644 (file)
@@ -17,8 +17,9 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
 
 #include "CanvasElement.hxx"
+#include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasEventVisitor.hxx>
-#include <simgear/canvas/MouseEvent.hxx>
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/math/SGMisc.hxx>
 #include <simgear/misc/strutils.hxx>
 #include <simgear/scene/material/parseBlendFunc.hxx>
@@ -211,17 +212,7 @@ namespace canvas
       "addEventListener(" << _node->getPath() << ", " << type_str << ")"
     );
 
-    Event::Type type = Event::strToType(type_str);
-    if( type == Event::UNKNOWN )
-    {
-      SG_LOG( SG_GENERAL,
-              SG_WARN,
-              "addEventListener: Unknown event type " << type_str );
-      return false;
-    }
-
-    _listener[ type ].push_back(cb);
-
+    _listener[ Event::getOrRegisterType(type_str) ].push_back(cb);
     return true;
   }
 
@@ -255,7 +246,7 @@ namespace canvas
   }
 
   //----------------------------------------------------------------------------
-  bool Element::handleEvent(canvas::EventPtr event)
+  bool Element::handleEvent(EventPtr event)
   {
     ListenerMap::iterator listeners = _listener.find(event->getType());
     if( listeners == _listener.end() )
@@ -267,6 +258,24 @@ namespace canvas
     return true;
   }
 
+  //----------------------------------------------------------------------------
+  bool Element::dispatchEvent(EventPtr event)
+  {
+    EventPropagationPath path;
+    path.push_back( EventTarget(this) );
+
+    for( Element* parent = _parent;
+                  parent != NULL;
+                  parent = parent->_parent )
+      path.push_front( EventTarget(parent) );
+
+    CanvasPtr canvas = _canvas.lock();
+    if( !canvas )
+      return false;
+
+    return canvas->propagateEvent(event, path);
+  }
+
   //----------------------------------------------------------------------------
   bool Element::hitBound( const osg::Vec2f& global_pos,
                           const osg::Vec2f& parent_pos,
index 62f71a199c72da20b09c507c581670670fd5b338..f8b4bcf57a0c31d3bb6ad7531fbe76df64ea4f12 100644 (file)
@@ -108,7 +108,8 @@ namespace canvas
       virtual bool ascend(EventVisitor& visitor);
       virtual bool traverse(EventVisitor& visitor);
 
-      virtual bool handleEvent(canvas::EventPtr event);
+      virtual bool handleEvent(EventPtr event);
+      bool dispatchEvent(EventPtr event);
 
       /**
        *
@@ -233,7 +234,7 @@ namespace canvas
       RelativeScissor  *_scissor;
 
       typedef std::vector<EventListener> Listener;
-      typedef std::map<Event::Type, Listener> ListenerMap;
+      typedef std::map<int, Listener> ListenerMap;
 
       ListenerMap _listener;
 
index 9548c95e262b93a8630a2d3004acf0f96254cec0..ce86320abe1e4ab09eb99af339ac3b0af2bc16da 100644 (file)
@@ -22,7 +22,7 @@
 #include "CanvasPath.hxx"
 #include "CanvasText.hxx"
 #include <simgear/canvas/CanvasEventVisitor.hxx>
-#include <simgear/canvas/MouseEvent.hxx>
+#include <simgear/canvas/events/MouseEvent.hxx>
 
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
index c2b2315f1cbaeeaa6fd71f9e60bf403655d36155..8577459fe28c3159eacfa29e687e0aa9278beb52 100644 (file)
@@ -21,7 +21,7 @@
 #include <simgear/canvas/Canvas.hxx>
 #include <simgear/canvas/CanvasMgr.hxx>
 #include <simgear/canvas/CanvasSystemAdapter.hxx>
-#include <simgear/canvas/MouseEvent.hxx>
+#include <simgear/canvas/events/MouseEvent.hxx>
 #include <simgear/scene/util/OsgMath.hxx>
 #include <simgear/scene/util/parse_color.hxx>
 #include <simgear/misc/sg_path.hxx>
@@ -449,7 +449,7 @@ namespace canvas
     if( !src_canvas )
       return handled;
 
-    MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
+    MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
     if( mouse_event )
     {
       mouse_event.reset( new MouseEvent(*mouse_event) );
@@ -473,9 +473,11 @@ namespace canvas
       mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x();
       mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y();
       mouse_event->local_pos = mouse_event->client_pos;
+
+      handled |= src_canvas->handleMouseEvent(mouse_event);
     }
 
-    return handled | src_canvas->handleMouseEvent(mouse_event);
+    return handled;
   }
 
   //----------------------------------------------------------------------------
diff --git a/simgear/canvas/events/CMakeLists.txt b/simgear/canvas/events/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cfac3f6
--- /dev/null
@@ -0,0 +1,18 @@
+include (SimGearComponent)
+
+set(HEADERS
+  CustomEvent.hxx
+  MouseEvent.hxx
+)
+
+set(SOURCES
+  CustomEvent.cxx
+  MouseEvent.cxx
+)
+
+simgear_scene_component(canvas-events canvas/events "${SOURCES}" "${HEADERS}")
+
+add_boost_test(canvas_event
+  SOURCES event_test.cpp
+  LIBRARIES ${TEST_LIBS}
+)
\ No newline at end of file
diff --git a/simgear/canvas/events/CustomEvent.cxx b/simgear/canvas/events/CustomEvent.cxx
new file mode 100644 (file)
index 0000000..3ca8ff1
--- /dev/null
@@ -0,0 +1,51 @@
+// Canvas user defined event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// 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 "CustomEvent.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+  //----------------------------------------------------------------------------
+  CustomEvent::CustomEvent( std::string const& type_str,
+                            StringMap const& data ):
+    detail(data)
+  {
+    type = getOrRegisterType(type_str);
+  }
+
+  //----------------------------------------------------------------------------
+  CustomEvent::CustomEvent( int type_id,
+                            StringMap const& data ):
+    detail(data)
+  {
+    type = type_id;
+//    TypeMap::map_by<id>::type const& type_map = getTypeMap().by<id>();
+//    assert( type_map.find(type_id) != type_map.end() );
+  }
+
+  //----------------------------------------------------------------------------
+  void CustomEvent::setDetail(StringMap const& data)
+  {
+    detail = data;
+  }
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/events/CustomEvent.hxx b/simgear/canvas/events/CustomEvent.hxx
new file mode 100644 (file)
index 0000000..cb48bec
--- /dev/null
@@ -0,0 +1,71 @@
+///@file Canvas user defined event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef CANVAS_CUSTOM_EVENT_HXX_
+#define CANVAS_CUSTOM_EVENT_HXX_
+
+#include <simgear/canvas/CanvasEvent.hxx>
+#include <simgear/structure/map.hxx>
+
+namespace simgear
+{
+namespace canvas
+{
+
+  class CustomEvent:
+    public Event
+  {
+    public:
+
+      /**
+       *
+       * @param type_str    Event type name (if name does not exist yet it will
+       *                    be registered as new event type)
+       * @param data        Optional user data stored in event
+       */
+      CustomEvent( std::string const& type_str,
+                   StringMap const& data = StringMap() );
+
+      /**
+       *
+       * @param type_id     Event type id
+       * @param data        Optional user data stored in event
+       */
+      CustomEvent( int type_id,
+                   StringMap const& data = StringMap() );
+
+      /**
+       * Set user data
+       */
+      void setDetail(StringMap const& data);
+
+      /**
+       * Get user data
+       */
+      StringMap const& getDetail() const { return detail; }
+
+      virtual bool canBubble() const { return bubbles; }
+
+      StringMap detail; //<! user data map
+      bool bubbles;
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_CUSTOM_EVENT_HXX_ */
diff --git a/simgear/canvas/events/MouseEvent.cxx b/simgear/canvas/events/MouseEvent.cxx
new file mode 100644 (file)
index 0000000..86c18bd
--- /dev/null
@@ -0,0 +1,70 @@
+// Mouse event
+//
+// Copyright (C) 2014  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// 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 "MouseEvent.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+  //----------------------------------------------------------------------------
+  MouseEvent::MouseEvent():
+    button(0),
+    buttons(0),
+    modifiers(0),
+    click_count(0)
+  {
+
+  }
+
+  //----------------------------------------------------------------------------
+  MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
+    button(0),
+    buttons(ea.getButtonMask()),
+    modifiers(ea.getModKeyMask()),
+    click_count(0)
+  {
+    time = ea.getTime();
+
+    // Convert button mask to index
+    int button_mask = ea.getButton();
+    while( (button_mask >>= 1) > 0 )
+      button += 1;
+  }
+
+  //----------------------------------------------------------------------------
+  bool MouseEvent::canBubble() const
+  {
+    // Check if event supports bubbling
+    const Event::Type types_no_bubbling[] = {
+      Event::MOUSE_ENTER,
+      Event::MOUSE_LEAVE,
+    };
+    const size_t num_types_no_bubbling = sizeof(types_no_bubbling)
+                                       / sizeof(types_no_bubbling[0]);
+
+    for( size_t i = 0; i < num_types_no_bubbling; ++i )
+      if( type == types_no_bubbling[i] )
+        return false;
+
+    return true;
+  }
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/events/MouseEvent.hxx b/simgear/canvas/events/MouseEvent.hxx
new file mode 100644 (file)
index 0000000..d50b523
--- /dev/null
@@ -0,0 +1,75 @@
+///@file Mouse event
+//
+// Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef CANVAS_MOUSE_EVENT_HXX_
+#define CANVAS_MOUSE_EVENT_HXX_
+
+#include <simgear/canvas/CanvasEvent.hxx>
+#include <osgGA/GUIEventAdapter>
+
+namespace simgear
+{
+namespace canvas
+{
+
+  class MouseEvent:
+    public Event
+  {
+    public:
+      MouseEvent();
+      MouseEvent(const osgGA::GUIEventAdapter& ea);
+
+      virtual bool canBubble() const;
+
+      osg::Vec2f getScreenPos() const { return screen_pos; }
+      osg::Vec2f getClientPos() const { return client_pos; }
+      osg::Vec2f getLocalPos()  const { return  local_pos; }
+      osg::Vec2f getDelta() const { return delta; }
+
+      float getScreenX() const { return screen_pos.x(); }
+      float getScreenY() const { return screen_pos.y(); }
+
+      float getClientX() const { return client_pos.x(); }
+      float getClientY() const { return client_pos.y(); }
+
+      float getLocalX() const { return local_pos.x(); }
+      float getLocalY() const { return local_pos.y(); }
+
+      float getDeltaX() const { return delta.x(); }
+      float getDeltaY() const { return delta.y(); }
+
+      int getButton() const { return button; }
+      int getButtonMask() const { return buttons; }
+      int getModifiers() const { return modifiers; }
+
+      int getCurrentClickCount() const { return click_count; }
+
+      osg::Vec2f  screen_pos,   //<! Position in screen coordinates
+                  client_pos,   //<! Position in window/canvas coordinates
+                  local_pos,    //<! Position in local/element coordinates
+                  delta;
+      int         button,       //<! Button for this event
+                  buttons,      //<! Current button state
+                  modifiers,    //<! Keyboard modifier state
+                  click_count;  //<! Current click count
+  };
+
+} // namespace canvas
+} // namespace simgear
+
+#endif /* CANVAS_MOUSE_EVENT_HXX_ */
diff --git a/simgear/canvas/events/event_test.cpp b/simgear/canvas/events/event_test.cpp
new file mode 100644 (file)
index 0000000..841eaa6
--- /dev/null
@@ -0,0 +1,36 @@
+/// Unit tests for reference counting and smart pointer classes
+#define BOOST_TEST_MODULE structure
+#include <BoostTestTargetConfig.h>
+
+#include "MouseEvent.hxx"
+#include "CustomEvent.hxx"
+
+namespace sc = simgear::canvas;
+
+BOOST_AUTO_TEST_CASE( canvas_event_types )
+{
+  // Register type
+  BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
+                       sc::Event::UNKNOWN );
+  BOOST_REQUIRE_EQUAL( sc::Event::getOrRegisterType("test"),
+                       sc::Event::CUSTOM_EVENT );
+  BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
+                       sc::Event::CUSTOM_EVENT );
+  BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::CUSTOM_EVENT),
+                       "test" );
+
+  // Basic internal type
+  BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::MOUSE_DOWN),
+                       "mousedown" );
+  BOOST_REQUIRE_EQUAL( sc::Event::strToType("mousedown"),
+                       sc::Event::MOUSE_DOWN );
+
+  // Unknown type
+  BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(123),
+                       "unknown" );
+
+  // Register type through custom event instance
+  sc::CustomEvent e("blub");
+  BOOST_REQUIRE_EQUAL( e.getTypeString(), "blub" );
+  BOOST_REQUIRE_NE( e.getType(), sc::Event::UNKNOWN );
+}
index 49493128cdf3e84d52d3b40f47a9094b5bb5a7e3..20c5afca0b6d7fb1e1e20eeceee3e97f87238550 100644 (file)
@@ -33,7 +33,7 @@ namespace simgear
       Map() {}
 
       /**
-       * Initilize a new mape with the given key/value pair.
+       * Initialize a new map with the given key/value pair.
        */
       Map(const Key& key, const Value& value)
       {