From 9c421d55a99e5aa312a58acd937c020b8c29bb03 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sun, 18 May 2014 13:29:48 +0200 Subject: [PATCH] Canvas: support for custom events and event dispatching. --- simgear/canvas/CMakeLists.txt | 2 +- simgear/canvas/Canvas.cxx | 13 +- simgear/canvas/Canvas.hxx | 2 + simgear/canvas/CanvasEvent.cxx | 70 +++++++--- simgear/canvas/CanvasEvent.hxx | 38 +++++- simgear/canvas/CanvasEventManager.cxx | 145 ++++++++++----------- simgear/canvas/CanvasEventManager.hxx | 14 +- simgear/canvas/CanvasEventVisitor.cxx | 8 +- simgear/canvas/CanvasObjectPlacement.cxx | 2 +- simgear/canvas/CanvasWindow.hxx | 2 +- simgear/canvas/canvas_fwd.hxx | 9 +- simgear/canvas/elements/CanvasElement.cxx | 35 +++-- simgear/canvas/elements/CanvasElement.hxx | 5 +- simgear/canvas/elements/CanvasGroup.cxx | 2 +- simgear/canvas/elements/CanvasImage.cxx | 8 +- simgear/canvas/events/CMakeLists.txt | 18 +++ simgear/canvas/events/CustomEvent.cxx | 51 ++++++++ simgear/canvas/events/CustomEvent.hxx | 71 ++++++++++ simgear/canvas/events/MouseEvent.cxx | 70 ++++++++++ simgear/canvas/{ => events}/MouseEvent.hxx | 26 +--- simgear/canvas/events/event_test.cpp | 36 +++++ simgear/structure/map.hxx | 2 +- 22 files changed, 467 insertions(+), 162 deletions(-) create mode 100644 simgear/canvas/events/CMakeLists.txt create mode 100644 simgear/canvas/events/CustomEvent.cxx create mode 100644 simgear/canvas/events/CustomEvent.hxx create mode 100644 simgear/canvas/events/MouseEvent.cxx rename simgear/canvas/{ => events}/MouseEvent.hxx (82%) create mode 100644 simgear/canvas/events/event_test.cpp diff --git a/simgear/canvas/CMakeLists.txt b/simgear/canvas/CMakeLists.txt index cbeffbaa..fea5a22d 100644 --- a/simgear/canvas/CMakeLists.txt +++ b/simgear/canvas/CMakeLists.txt @@ -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}") diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index f7ba3228..c199f54f 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -19,8 +19,8 @@ #include "Canvas.hxx" #include "CanvasEventManager.hxx" #include "CanvasEventVisitor.hxx" -#include -#include +#include "CanvasPlacement.hxx" +#include #include #include @@ -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 ) diff --git a/simgear/canvas/Canvas.hxx b/simgear/canvas/Canvas.hxx index a65ff018..380dac8b 100644 --- a/simgear/canvas/Canvas.hxx +++ b/simgear/canvas/Canvas.hxx @@ -146,6 +146,8 @@ namespace canvas SGRect getViewport() const; bool handleMouseEvent(const MouseEventPtr& event); + bool propagateEvent( EventPtr const& event, + EventPropagationPath const& path ); virtual void childAdded( SGPropertyNode * parent, SGPropertyNode * child ); diff --git a/simgear/canvas/CanvasEvent.cxx b/simgear/canvas/CanvasEvent.cxx index 414d1993..6c2684bc 100644 --- a/simgear/canvas/CanvasEvent.cxx +++ b/simgear/canvas/CanvasEvent.cxx @@ -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 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::const_iterator it = type_map.by().find(str); + if( it == type_map.by().end() ) return UNKNOWN; + return it->second; + } + + //---------------------------------------------------------------------------- + std::string Event::typeToStr(int type) + { + TypeMap const& type_map = getTypeMap(); + TypeMap::map_by::const_iterator it = type_map.by().find(type); + if( it == type_map.by().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 diff --git a/simgear/canvas/CanvasEvent.hxx b/simgear/canvas/CanvasEvent.hxx index c3121269..0e98c6f1 100644 --- a/simgear/canvas/CanvasEvent.hxx +++ b/simgear/canvas/CanvasEvent.hxx @@ -20,13 +20,15 @@ #define CANVAS_EVENT_HXX_ #include "canvas_fwd.hxx" +#include 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 ///, + boost::bimaps::tagged + > TypeMap; + + static TypeMap& getTypeMap(); }; diff --git a/simgear/canvas/CanvasEventManager.cxx b/simgear/canvas/CanvasEventManager.cxx index 21d97c78..cf8ac789 100644 --- a/simgear/canvas/CanvasEventManager.cxx +++ b/simgear/canvas/CanvasEventManager.cxx @@ -17,7 +17,7 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include "CanvasEventManager.hxx" -#include "MouseEvent.hxx" +#include #include #include @@ -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(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(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, diff --git a/simgear/canvas/CanvasEventManager.hxx b/simgear/canvas/CanvasEventManager.hxx index 8ea44d9a..5e3738c8 100644 --- a/simgear/canvas/CanvasEventManager.hxx +++ b/simgear/canvas/CanvasEventManager.hxx @@ -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 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 diff --git a/simgear/canvas/CanvasEventVisitor.cxx b/simgear/canvas/CanvasEventVisitor.cxx index 98953034..efb12dbb 100644 --- a/simgear/canvas/CanvasEventVisitor.cxx +++ b/simgear/canvas/CanvasEventVisitor.cxx @@ -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; diff --git a/simgear/canvas/CanvasObjectPlacement.cxx b/simgear/canvas/CanvasObjectPlacement.cxx index fc0b738f..d4a8a85c 100644 --- a/simgear/canvas/CanvasObjectPlacement.cxx +++ b/simgear/canvas/CanvasObjectPlacement.cxx @@ -21,7 +21,7 @@ #include "Canvas.hxx" #include "CanvasObjectPlacement.hxx" -#include "MouseEvent.hxx" +#include #include #include diff --git a/simgear/canvas/CanvasWindow.hxx b/simgear/canvas/CanvasWindow.hxx index 74bdf33f..57068a84 100644 --- a/simgear/canvas/CanvasWindow.hxx +++ b/simgear/canvas/CanvasWindow.hxx @@ -20,7 +20,7 @@ #define CANVAS_WINDOW_HXX_ #include -#include +#include #include #include #include diff --git a/simgear/canvas/canvas_fwd.hxx b/simgear/canvas/canvas_fwd.hxx index 6b34e028..b14d2886 100644 --- a/simgear/canvas/canvas_fwd.hxx +++ b/simgear/canvas/canvas_fwd.hxx @@ -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##Ptr;\ typedef boost::weak_ptr 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 EventPropagationPath; + typedef std::map Style; typedef ElementPtr (*ElementFactory)( const CanvasWeakPtr&, const SGPropertyNode_ptr&, diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index 82fc659c..c763ab86 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -17,8 +17,9 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include "CanvasElement.hxx" +#include #include -#include +#include #include #include #include @@ -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, diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index 62f71a19..f8b4bcf5 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -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 Listener; - typedef std::map ListenerMap; + typedef std::map ListenerMap; ListenerMap _listener; diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx index 9548c95e..ce86320a 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -22,7 +22,7 @@ #include "CanvasPath.hxx" #include "CanvasText.hxx" #include -#include +#include #include #include diff --git a/simgear/canvas/elements/CanvasImage.cxx b/simgear/canvas/elements/CanvasImage.cxx index c2b2315f..8577459f 100644 --- a/simgear/canvas/elements/CanvasImage.cxx +++ b/simgear/canvas/elements/CanvasImage.cxx @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -449,7 +449,7 @@ namespace canvas if( !src_canvas ) return handled; - MouseEventPtr mouse_event = boost::dynamic_pointer_cast(event); + MouseEventPtr mouse_event = dynamic_cast(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 index 00000000..cfac3f69 --- /dev/null +++ b/simgear/canvas/events/CMakeLists.txt @@ -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 index 00000000..3ca8ff18 --- /dev/null +++ b/simgear/canvas/events/CustomEvent.cxx @@ -0,0 +1,51 @@ +// Canvas user defined event +// +// Copyright (C) 2014 Thomas Geymayer +// +// 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::type const& type_map = getTypeMap().by(); +// 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 index 00000000..cb48becc --- /dev/null +++ b/simgear/canvas/events/CustomEvent.hxx @@ -0,0 +1,71 @@ +///@file Canvas user defined event +// +// Copyright (C) 2014 Thomas Geymayer +// +// 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 +#include + +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; // +// +// 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/MouseEvent.hxx b/simgear/canvas/events/MouseEvent.hxx similarity index 82% rename from simgear/canvas/MouseEvent.hxx rename to simgear/canvas/events/MouseEvent.hxx index 182115a1..d50b5238 100644 --- a/simgear/canvas/MouseEvent.hxx +++ b/simgear/canvas/events/MouseEvent.hxx @@ -1,4 +1,4 @@ -// Mouse event +///@file Mouse event // // Copyright (C) 2012 Thomas Geymayer // @@ -19,7 +19,7 @@ #ifndef CANVAS_MOUSE_EVENT_HXX_ #define CANVAS_MOUSE_EVENT_HXX_ -#include "CanvasEvent.hxx" +#include #include namespace simgear @@ -31,26 +31,10 @@ namespace canvas public Event { public: - MouseEvent(): - button(0), - buttons(0), - modifiers(0), - click_count(0) - {} + MouseEvent(); + MouseEvent(const osgGA::GUIEventAdapter& ea); - 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; - } + virtual bool canBubble() const; osg::Vec2f getScreenPos() const { return screen_pos; } osg::Vec2f getClientPos() const { return client_pos; } diff --git a/simgear/canvas/events/event_test.cpp b/simgear/canvas/events/event_test.cpp new file mode 100644 index 00000000..841eaa67 --- /dev/null +++ b/simgear/canvas/events/event_test.cpp @@ -0,0 +1,36 @@ +/// Unit tests for reference counting and smart pointer classes +#define BOOST_TEST_MODULE structure +#include + +#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 ); +} diff --git a/simgear/structure/map.hxx b/simgear/structure/map.hxx index 49493128..20c5afca 100644 --- a/simgear/structure/map.hxx +++ b/simgear/structure/map.hxx @@ -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) { -- 2.39.5