From 28f2779c4b09841e9ddae1a1ed1f46ea686e6143 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sun, 2 Dec 2012 13:27:37 +0100 Subject: [PATCH] Forward mouse events from (PUI) CanvasWidget to Canvas for new DOM like callbacks --- src/Canvas/FGCanvasSystemAdapter.cxx | 6 +++ src/Canvas/FGCanvasSystemAdapter.hxx | 1 + src/Canvas/gui_mgr.cxx | 7 +-- src/GUI/CanvasWidget.cxx | 69 ++++++++++++++++++++++++---- src/GUI/CanvasWidget.hxx | 5 +- src/GUI/FGPUIDialog.cxx | 46 +++++++++++++++---- src/GUI/FGPUIDialog.hxx | 1 + src/Scripting/NasalCanvas.cxx | 22 +++++++-- 8 files changed, 133 insertions(+), 24 deletions(-) diff --git a/src/Canvas/FGCanvasSystemAdapter.cxx b/src/Canvas/FGCanvasSystemAdapter.cxx index 84db82d55..f6c94522e 100644 --- a/src/Canvas/FGCanvasSystemAdapter.cxx +++ b/src/Canvas/FGCanvasSystemAdapter.cxx @@ -87,6 +87,12 @@ namespace canvas return nasal_sys; } + //---------------------------------------------------------------------------- + naContext FGCanvasSystemAdapter::getNasalContext() const + { + return getNasalSys()->context(); + } + //---------------------------------------------------------------------------- int FGCanvasSystemAdapter::gcSave(naRef r) { diff --git a/src/Canvas/FGCanvasSystemAdapter.hxx b/src/Canvas/FGCanvasSystemAdapter.hxx index 0f13057cc..d56397a08 100644 --- a/src/Canvas/FGCanvasSystemAdapter.hxx +++ b/src/Canvas/FGCanvasSystemAdapter.hxx @@ -21,6 +21,7 @@ namespace canvas virtual void removeCamera(osg::Camera* camera) const; virtual osg::Image* getImage(const std::string& path) const; + virtual naContext getNasalContext() const; virtual int gcSave(naRef r); virtual void gcRelease(int key); virtual naRef callMethod( naRef code, diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx index d2a0b332f..02d8073c7 100644 --- a/src/Canvas/gui_mgr.cxx +++ b/src/Canvas/gui_mgr.cxx @@ -336,9 +336,10 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) event->type = sc::Event::MOUSE_UP; break; -// case osgGA::GUIEventAdapter::DRAG: -// target_window = _last_push.lock(); -// break; + case osgGA::GUIEventAdapter::DRAG: + target_window = _last_push.lock(); + event->type = sc::Event::DRAG; + break; default: return false; diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx index 624ef1aca..8c8ea3158 100644 --- a/src/GUI/CanvasWidget.cxx +++ b/src/GUI/CanvasWidget.cxx @@ -16,6 +16,7 @@ #include #include +#include //------------------------------------------------------------------------------ CanvasWidget::CanvasWidget( int x, int y, @@ -25,7 +26,9 @@ CanvasWidget::CanvasWidget( int x, int y, puObject(x, y, width, height), _canvas_mgr( dynamic_cast(globals->get_subsystem("Canvas")) ), _tex_id(0), - _no_tex_cnt(0) + _no_tex_cnt(0), + _last_x(0), + _last_y(0) { if( !_canvas_mgr ) { @@ -100,6 +103,62 @@ void CanvasWidget::doHit(int button, int updown, int x, int y) if( fgGetKeyModifiers() & (KEYMOD_CTRL | KEYMOD_SHIFT) ) return; + namespace sc = simgear::canvas; + sc::MouseEventPtr event(new sc::MouseEvent); + event->pos.set(x - abox.min[0], y - abox.min[1]); + event->delta.set(x - _last_x, y - _last_y); + + _last_x = x; + _last_y = y; + + switch( button ) + { + case PU_LEFT_BUTTON: + event->button = osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON; + break; + case PU_MIDDLE_BUTTON: + event->button = osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON; + break; + case PU_RIGHT_BUTTON: + event->button = osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON; + break; + case PU_SCROLL_UP_BUTTON: + case PU_SCROLL_DOWN_BUTTON: + // Only let PU_DOWN trigger a scroll wheel event + if( updown != PU_DOWN ) + return; + + event->type = sc::Event::WHEEL; + event->delta.y() = button == PU_SCROLL_UP_BUTTON ? 1 : -1; + + _canvas->handleMouseEvent(event); + + return; + default: + SG_LOG(SG_INPUT, SG_WARN, "CanvasWidget: Unknown button: " << button); + return; + } + + switch( updown ) + { + case PU_DOWN: + event->type = sc::Event::MOUSE_DOWN; + puSetActiveWidget(this, x, y); + break; + case PU_UP: + event->type = sc::Event::MOUSE_UP; + puDeactivateWidget(); + break; + case PU_DRAG: + event->type = sc::Event::DRAG; + break; + default: + SG_LOG(SG_INPUT, SG_WARN, "CanvasWidget: Unknown updown: " << updown); + return; + } + + _canvas->handleMouseEvent(event); + _mouse_x->setIntValue(x - abox.min[0]); _mouse_y->setIntValue(abox.max[1] - y); @@ -107,14 +166,6 @@ void CanvasWidget::doHit(int button, int updown, int x, int y) _mouse_drag->setIntValue(button); else if( updown == PU_DOWN ) _mouse_down->setIntValue(button); - - if( button != active_mouse_button ) - return; - - if (updown == PU_UP) - puDeactivateWidget(); - else if (updown == PU_DOWN) - puSetActiveWidget(this, x, y); } //------------------------------------------------------------------------------ diff --git a/src/GUI/CanvasWidget.hxx b/src/GUI/CanvasWidget.hxx index 3297eafc1..976b336ae 100644 --- a/src/GUI/CanvasWidget.hxx +++ b/src/GUI/CanvasWidget.hxx @@ -26,7 +26,7 @@ class CanvasWidget: virtual ~CanvasWidget(); virtual void doHit (int button, int updown, int x, int y); - virtual int checkKey(int key , int updown); + virtual int checkKey(int key, int updown); virtual void setSize ( int w, int h ); virtual void draw(int dx, int dy); @@ -44,6 +44,9 @@ class CanvasWidget: *_mouse_y, *_mouse_down, *_mouse_drag; + + int _last_x, + _last_y; }; #endif /* CANVASWIDGET_HXX_ */ diff --git a/src/GUI/FGPUIDialog.cxx b/src/GUI/FGPUIDialog.cxx index 3555d5039..ebaba3cd0 100644 --- a/src/GUI/FGPUIDialog.cxx +++ b/src/GUI/FGPUIDialog.cxx @@ -139,7 +139,6 @@ void GUIInfo::apply_format(SGPropertyNode *n) } - /** * Key handler. */ @@ -225,9 +224,16 @@ int fgPopup::checkHit(int button, int updown, int x, int y) int hit = getHitObjects(this, x, y); if (hit & PUCLASS_LIST) // ctrl-click in property browser (toggle bool) return result; - if (!global_resize && hit & (PUCLASS_BUTTON|PUCLASS_ONESHOT|PUCLASS_INPUT - |PUCLASS_LARGEINPUT|PUCLASS_SCROLLBAR)) + if( !global_resize + && ( (hit & (PUCLASS_BUTTON|PUCLASS_ONESHOT|PUCLASS_INPUT + |PUCLASS_LARGEINPUT|PUCLASS_SCROLLBAR)) + // The canvas should handle drag events on its own so exit + // here if mouse is over a CanvasWidget + || (!global_drag && checkHitCanvas(this, x, y)) + ) ) + { return result; + } getPosition(&_dlgX, &_dlgY); getSize(&_dlgW, &_dlgH); @@ -340,6 +346,32 @@ int fgPopup::getHitObjects(puObject *object, int x, int y) return type; } +bool fgPopup::checkHitCanvas(puObject* object, int x, int y) +{ + if( !object->isVisible() ) + return 0; + + if( object->getType() & PUCLASS_GROUP ) + { + for( puObject* obj = ((puGroup*)object)->getFirstChild(); + obj; + obj = obj->getNextObject() ) + { + if( checkHitCanvas(obj, x, y) ) + return true; + } + } + + int cx, cy, cw, ch; + object->getAbsolutePosition(&cx, &cy); + object->getSize(&cw, &ch); + if( x >= cx && x < cx + cw + && y >= cy && y < cy + ch + && dynamic_cast(object) ) + return true; + return false; +} + void fgPopup::applySize(puObject *object) { // compound plib widgets use setUserData() for internal purposes, so refuse @@ -405,7 +437,8 @@ void FGPUIDialog::ConditionalObject::update(FGPUIDialog* aDlg) aDlg->setNeedsLayout(); } - //////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// // Callbacks. //////////////////////////////////////////////////////////////////////// @@ -428,7 +461,6 @@ action_callback (puObject *object) } - //////////////////////////////////////////////////////////////////////// // Static helper functions. //////////////////////////////////////////////////////////////////////// @@ -511,7 +543,6 @@ copy_from_pui (puObject *object, SGPropertyNode *node) } - //////////////////////////////////////////////////////////////////////// // Implementation of FGDialog. //////////////////////////////////////////////////////////////////////// @@ -1186,7 +1217,7 @@ FGPUIDialog::getKeyCode(const char *str) return key; } -void FGPUIDialog::relayout() +void FGPUIDialog::relayout() { _needsRelayout = false; @@ -1291,7 +1322,6 @@ FGPUIDialog::PropertyObject::PropertyObject(const char *n, - //////////////////////////////////////////////////////////////////////// // Implementation of fgValueList and derived pui widgets //////////////////////////////////////////////////////////////////////// diff --git a/src/GUI/FGPUIDialog.hxx b/src/GUI/FGPUIDialog.hxx index e3a158e8b..71024ca83 100644 --- a/src/GUI/FGPUIDialog.hxx +++ b/src/GUI/FGPUIDialog.hxx @@ -210,6 +210,7 @@ public: int checkHit(int b, int up, int x, int y); int checkKey(int key, int updown); int getHitObjects(puObject *, int x, int y); + bool checkHitCanvas(puObject *, int x, int y); puObject *getKeyObject(puObject *, int key); puObject *getActiveInputField(puObject *); void applySize(puObject *); diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx index df5c69363..8c70b51ac 100644 --- a/src/Scripting/NasalCanvas.cxx +++ b/src/Scripting/NasalCanvas.cxx @@ -149,16 +149,32 @@ naRef f_groupGetElementById(sc::Group& group, const nasal::CallContext& ctx) ); } +// TODO allow directly exposing functions without parameters and return type +naRef f_eventStopPropagation(sc::Event& event, const nasal::CallContext& ctx) +{ + if( ctx.argc != 0 ) + naRuntimeError(ctx.c, "Event::stopPropagation no argument expected"); + event.stopPropagation(); + return naNil(); +} + naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave) { - NasalEvent::init("canvas.Event"); + NasalEvent::init("canvas.Event") + .member("type", &sc::Event::getTypeString) + .method_func<&f_eventStopPropagation>("stopPropagation"); NasalMouseEvent::init("canvas.MouseEvent") - .bases(); + .bases() + .member("x", &sc::MouseEvent::getPosX) + .member("y", &sc::MouseEvent::getPosY) + .member("deltaX", &sc::MouseEvent::getDeltaX) + .member("deltaY", &sc::MouseEvent::getDeltaY); NasalCanvas::init("Canvas") .member("_node_ghost", &elementGetNode) .member("size_x", &sc::Canvas::getSizeX) .member("size_y", &sc::Canvas::getSizeY) - .method_func<&f_canvasCreateGroup>("_createGroup"); + .method_func<&f_canvasCreateGroup>("_createGroup") + .method<&sc::Canvas::addEventListener>("addEventListener"); NasalElement::init("canvas.Element") .member("_node_ghost", &elementGetNode) .method<&sc::Element::addEventListener>("addEventListener");