diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx index 3bb86bc69..5ea1d8166 100644 --- a/src/Canvas/gui_mgr.cxx +++ b/src/Canvas/gui_mgr.cxx @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -351,9 +352,9 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) continue; float margin = window->isResizable() ? resize_margin_pos : 0; - if( window->getRegion().contains( event->getScreenX(), - event->getScreenY(), - margin ) ) + if( window->getScreenRegion().contains( event->getScreenX(), + event->getScreenY(), + margin ) ) { window_at_cursor = window; break; @@ -366,7 +367,7 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) if( window_at_cursor ) { - const SGRect& reg = window_at_cursor->getRegion(); + const SGRect& reg = window_at_cursor->getScreenRegion(); if( window_at_cursor->isResizable() && ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE @@ -459,6 +460,8 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) { sc::MouseEventPtr move_event( new sc::MouseEvent(*event) ); move_event->type = sc::Event::MOUSE_LEAVE; + move_event->client_pos -= toOsg(last_mouse_over->getPosition()); + move_event->local_pos = move_event->client_pos; last_mouse_over->handleMouseEvent(move_event); } @@ -482,7 +485,11 @@ bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea) } if( target_window ) + { + event->client_pos -= toOsg(target_window->getPosition()); + event->local_pos = event->client_pos; return target_window->handleMouseEvent(event); + } else return false; } diff --git a/src/Canvas/window.cxx b/src/Canvas/window.cxx index cdebb5d0e..8deed486c 100644 --- a/src/Canvas/window.cxx +++ b/src/Canvas/window.cxx @@ -16,11 +16,15 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +#include "canvas_mgr.hxx" #include "window.hxx" +#include
#include +#include #include +#include #include namespace canvas @@ -28,9 +32,8 @@ namespace canvas //---------------------------------------------------------------------------- Window::Window(SGPropertyNode* node): PropertyBasedElement(node), - _image( simgear::canvas::CanvasPtr(), - node, - simgear::canvas::Style() ), + _attributes_dirty(0), + _image(simgear::canvas::CanvasPtr(), node), _resizable(false), _capture_events(true), _resize_top(node, "resize-top"), @@ -41,12 +44,6 @@ namespace canvas { _image.removeListener(); - // TODO probably better remove default position and size - node->setFloatValue("x", 50); - node->setFloatValue("y", 100); - node->setFloatValue("size[0]", 400); - node->setFloatValue("size[1]", 300); - node->setFloatValue("source/right", 1); node->setFloatValue("source/bottom", 1); node->setBoolValue("source/normalized", true); @@ -55,13 +52,59 @@ namespace canvas //---------------------------------------------------------------------------- Window::~Window() { - + if( _canvas_decoration ) + _canvas_decoration->destroy(); } //---------------------------------------------------------------------------- void Window::update(double delta_time_sec) { _image.update(delta_time_sec); + + if( _attributes_dirty & SHADOW ) + { + float radius = get("shadow-radius"), + inset = get("shadow-inset"), + slice_width = radius + inset; + + if( slice_width <= 1 || _canvas_content.expired() ) + { + if( _image_shadow ) + { + getGroup()->removeChild(_image_shadow->getMatrixTransform()); + _image_shadow.reset(); + } + } + else + { + if( !_image_shadow ) + { + _image_shadow.reset(new simgear::canvas::Image( + _canvas_content, + _node->getChild("image-shadow", 0, true) + )); + _image_shadow->set("file", "gui/images/shadow.png"); + _image_shadow->set("slice", 7); + _image_shadow->set("fill", "#000000"); + getGroup()->insertChild(0, _image_shadow->getMatrixTransform()); + } + + simgear::canvas::CanvasPtr canvas = _canvas_decoration + ? _canvas_decoration + : _canvas_content.lock(); + + _image_shadow->set("slice-width", slice_width); + _image_shadow->set("x", -radius); + _image_shadow->set("y", -radius); + _image_shadow->set("size[0]", canvas->getViewWidth() + 2 * radius); + _image_shadow->set("size[1]", canvas->getViewHeight()+ 2 * radius); + } + + _attributes_dirty &= ~SHADOW; + } + + if( _image_shadow ) + _image_shadow->update(delta_time_sec); } //---------------------------------------------------------------------------- @@ -71,12 +114,17 @@ namespace canvas if( node->getParent() == _node ) { handled = true; - if( node->getNameString() == "raise-top" ) + const std::string& name = node->getNameString(); + if( name == "raise-top" ) doRaise(node); - else if( node->getNameString() == "resize" ) + else if( name == "resize" ) _resizable = node->getBoolValue(); - else if( node->getNameString() == "capture-events" ) + else if( name == "capture-events" ) _capture_events = node->getBoolValue(); + else if( name == "decoration-border" ) + parseDecorationBorder(node->getStringValue()); + else if( boost::starts_with(name, "shadow-") ) + _attributes_dirty |= SHADOW; else handled = false; } @@ -85,6 +133,18 @@ namespace canvas _image.valueChanged(node); } + //---------------------------------------------------------------------------- + void Window::childAdded(SGPropertyNode* parent, SGPropertyNode* child) + { + _image.childAdded(parent, child); + } + + //---------------------------------------------------------------------------- + void Window::childRemoved(SGPropertyNode* parent, SGPropertyNode* child) + { + _image.childRemoved(parent, child); + } + //---------------------------------------------------------------------------- osg::Group* Window::getGroup() { @@ -97,9 +157,23 @@ namespace canvas return _image.getRegion(); } + //---------------------------------------------------------------------------- + const SGVec2 Window::getPosition() const + { + const osg::Matrix& m = _image.getMatrixTransform()->getMatrix(); + return SGVec2( m(3, 0), m(3, 1) ); + } + + //---------------------------------------------------------------------------- + const SGRect Window::getScreenRegion() const + { + return getPosition() + getRegion(); + } + //---------------------------------------------------------------------------- void Window::setCanvas(simgear::canvas::CanvasPtr canvas) { + _canvas_content = canvas; _image.setSrcCanvas(canvas); } @@ -109,6 +183,12 @@ namespace canvas return _image.getSrcCanvas(); } + //---------------------------------------------------------------------------- + simgear::canvas::CanvasPtr Window::getCanvasDecoration() + { + return _canvas_decoration; + } + //---------------------------------------------------------------------------- bool Window::isVisible() const { @@ -180,4 +260,67 @@ namespace canvas node_raise->setBoolValue(false); } + //---------------------------------------------------------------------------- + void Window::parseDecorationBorder( const std::string& str ) + { + _decoration_border = simgear::CSSBorder::parse(str); + if( _decoration_border.isNone() ) + { + simgear::canvas::CanvasPtr canvas_content = _canvas_content.lock(); + _image.setSrcCanvas(canvas_content); + _image.set("size[0]", canvas_content->getViewWidth()); + _image.set("size[1]", canvas_content->getViewHeight()); + + _image_content.reset(); + _canvas_decoration->destroy(); + _canvas_decoration.reset(); + return; + } + + simgear::canvas::CanvasPtr content = _canvas_content.lock(); + if( !_canvas_decoration ) + { + CanvasMgr* mgr = + dynamic_cast(globals->get_subsystem("Canvas")); + + if( !mgr ) + { + SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!"); + return; + } + + _canvas_decoration = mgr->createCanvas("window-decoration"); + _canvas_decoration->getProps()->setStringValue("background", "rgba(0,0,0,0)"); + _image.setSrcCanvas(_canvas_decoration); + + // Decoration should be drawn first... + _canvas_decoration->createGroup("decoration"); + + // ...to allow drawing the actual content on top of the decoration + _image_content = + boost::dynamic_pointer_cast( + _canvas_decoration->getRootGroup()->createChild("image", "content") + ); + _image_content->setSrcCanvas(content); + } + + simgear::CSSBorder::Offsets const border = + _decoration_border.getAbsOffsets(content->getViewport()); + + int outer_width = border.l + content->getViewWidth() + border.r, + outer_height = border.t + content->getViewHeight() + border.b; + + _canvas_decoration->setSizeX( outer_width ); + _canvas_decoration->setSizeY( outer_height ); + _canvas_decoration->setViewWidth( outer_width ); + _canvas_decoration->setViewHeight( outer_height ); + + _image.set("size[0]", outer_width); + _image.set("size[1]", outer_height); + + assert(_image_content); + _image_content->set("x", border.l); + _image_content->set("y", border.t); + } + } // namespace canvas diff --git a/src/Canvas/window.hxx b/src/Canvas/window.hxx index 44bfafaea..905b0e4c3 100644 --- a/src/Canvas/window.hxx +++ b/src/Canvas/window.hxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -49,13 +50,19 @@ namespace canvas virtual void update(double delta_time_sec); virtual void valueChanged(SGPropertyNode* node); + virtual void childAdded(SGPropertyNode* parent, SGPropertyNode* child); + virtual void childRemoved(SGPropertyNode* parent, SGPropertyNode* child); osg::Group* getGroup(); const SGRect& getRegion() const; + const SGVec2 getPosition() const; + const SGRect getScreenRegion() const; void setCanvas(simgear::canvas::CanvasPtr canvas); simgear::canvas::CanvasWeakPtr getCanvas() const; + simgear::canvas::CanvasPtr getCanvasDecoration(); + bool isVisible() const; bool isResizable() const; bool isCapturingEvents() const; @@ -68,7 +75,20 @@ namespace canvas protected: - simgear::canvas::Image _image; + enum Attributes + { + SHADOW = 1 + }; + + uint32_t _attributes_dirty; + + simgear::canvas::CanvasPtr _canvas_decoration; + simgear::canvas::CanvasWeakPtr _canvas_content; + + simgear::canvas::Image _image; + simgear::canvas::ImagePtr _image_content, + _image_shadow; + bool _resizable, _capture_events; @@ -78,6 +98,9 @@ namespace canvas _resize_left, _resize_status; + simgear::CSSBorder _decoration_border; + + void parseDecorationBorder(const std::string& str); }; } // namespace canvas diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx index f6ab47ac5..78540f90e 100644 --- a/src/Scripting/NasalCanvas.cxx +++ b/src/Scripting/NasalCanvas.cxx @@ -232,7 +232,8 @@ naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave) .method("getNearestCursor", &sc::Text::getNearestCursor); NasalWindow::init("canvas.Window") - .member("_node_ghost", &elementGetNode); + .member("_node_ghost", &elementGetNode) + .method("_getCanvasDecoration", &canvas::Window::getCanvasDecoration); nasal::Hash globals_module(globals, c), canvas_module = globals_module.createHash("canvas");