}
}
+ //----------------------------------------------------------------------------
+ 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)
{
void update(double delta_time_sec);
+ naRef addEventListener(const nasal::CallContext& ctx);
+
void setSizeX(int sx);
void setSizeY(int sy);
-// 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>
//
//----------------------------------------------------------------------------
Event::Event():
- type(UNKNOWN)
+ type(UNKNOWN),
+ propagation_stopped(false)
+ {
+
+ }
+
+ //----------------------------------------------------------------------------
+ Event::~Event()
{
}
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
-// 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>
//
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);
};
// 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
{
}
//------------------------------------------------------------------------------
- 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());
}
const SystemAdapterPtr& sys_adapter );
~EventListener();
- void call();
+ void call(const canvas::EventPtr& event);
protected:
naRef _code;
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")
// 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>
//
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;
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();
//----------------------------------------------------------------------------
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 )
// << "(" << 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;
}
// 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>
//
#define SG_CANVAS_SYSTEM_ADAPTER_HXX_
#include "canvas_fwd.hxx"
-#include <simgear/nasal/naref.h>
+#include <simgear/nasal/nasal.h>
namespace simgear
{
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.
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
// 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>
#include <osg/Geode>
#include <boost/foreach.hpp>
+#include <boost/make_shared.hpp>
#include <cassert>
#include <cstring>
//----------------------------------------------------------------------------
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();
}
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
{
);
}
- //----------------------------------------------------------------------------
- void Element::callListeners(canvas::Event& event)
- {
- ListenerMap::iterator listeners = _listener.find(event.getType());
- if( listeners == _listener.end() )
- return;
- }
-
//----------------------------------------------------------------------------
void Element::setDrawable( osg::Drawable* drawable )
{
virtual bool ascend(EventVisitor& visitor);
virtual bool traverse(EventVisitor& visitor);
+ void callListeners(const canvas::EventPtr& event);
+
virtual bool hitBound(const osg::Vec2f& pos) const;
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){}
#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>
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));
{
naRef member(const nasal::CallContext&) { return naNil(); }
virtual ~Base(){};
+
+ std::string getString() const { return ""; }
+ void setString(const std::string&) {}
};
struct Derived:
public Base
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)