From 1c24acf41ee7513209e8ddc7610c3383ac1d8d95 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 7 Jun 2013 21:48:17 +0200 Subject: [PATCH] canvas::Window: make shadow part of decoration canvas --- src/Canvas/window.cxx | 144 ++++++++++++++++++++++-------------------- src/Canvas/window.hxx | 3 +- 2 files changed, 78 insertions(+), 69 deletions(-) diff --git a/src/Canvas/window.cxx b/src/Canvas/window.cxx index 8deed486c..b42497024 100644 --- a/src/Canvas/window.cxx +++ b/src/Canvas/window.cxx @@ -29,11 +29,13 @@ namespace canvas { + namespace sc = simgear::canvas; + //---------------------------------------------------------------------------- Window::Window(SGPropertyNode* node): PropertyBasedElement(node), _attributes_dirty(0), - _image(simgear::canvas::CanvasPtr(), node), + _image(sc::CanvasPtr(), node), _resizable(false), _capture_events(true), _resize_top(node, "resize-top"), @@ -59,52 +61,13 @@ namespace canvas //---------------------------------------------------------------------------- void Window::update(double delta_time_sec) { - _image.update(delta_time_sec); - - if( _attributes_dirty & SHADOW ) + if( _attributes_dirty & DECORATION ) { - 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; + updateDecoration(); + _attributes_dirty &= ~DECORATION; } - if( _image_shadow ) - _image_shadow->update(delta_time_sec); + _image.update(delta_time_sec); } //---------------------------------------------------------------------------- @@ -119,12 +82,14 @@ namespace canvas doRaise(node); else if( name == "resize" ) _resizable = node->getBoolValue(); + else if( name == "update" ) + update(0); 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; + _attributes_dirty |= DECORATION; else handled = false; } @@ -171,20 +136,20 @@ namespace canvas } //---------------------------------------------------------------------------- - void Window::setCanvas(simgear::canvas::CanvasPtr canvas) + void Window::setCanvas(sc::CanvasPtr canvas) { _canvas_content = canvas; _image.setSrcCanvas(canvas); } //---------------------------------------------------------------------------- - simgear::canvas::CanvasWeakPtr Window::getCanvas() const + sc::CanvasWeakPtr Window::getCanvas() const { return _image.getSrcCanvas(); } //---------------------------------------------------------------------------- - simgear::canvas::CanvasPtr Window::getCanvasDecoration() + sc::CanvasPtr Window::getCanvasDecoration() { return _canvas_decoration; } @@ -208,7 +173,7 @@ namespace canvas } //---------------------------------------------------------------------------- - bool Window::handleMouseEvent(const simgear::canvas::MouseEventPtr& event) + bool Window::handleMouseEvent(const sc::MouseEventPtr& event) { return _image.handleEvent(event); } @@ -261,23 +226,34 @@ namespace canvas } //---------------------------------------------------------------------------- - void Window::parseDecorationBorder( const std::string& str ) + void Window::parseDecorationBorder(const std::string& str) { _decoration_border = simgear::CSSBorder::parse(str); - if( _decoration_border.isNone() ) + _attributes_dirty |= DECORATION; + } + + //---------------------------------------------------------------------------- + void Window::updateDecoration() + { + int shadow_radius = get("shadow-radius") + 0.5; + if( shadow_radius < 2 ) + shadow_radius = 0; + + if( _decoration_border.isNone() && !shadow_radius ) { - simgear::canvas::CanvasPtr canvas_content = _canvas_content.lock(); + sc::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(); + _image_shadow.reset(); _canvas_decoration->destroy(); _canvas_decoration.reset(); return; } - simgear::canvas::CanvasPtr content = _canvas_content.lock(); + sc::CanvasPtr content = _canvas_content.lock(); if( !_canvas_decoration ) { CanvasMgr* mgr = @@ -290,37 +266,69 @@ namespace canvas } _canvas_decoration = mgr->createCanvas("window-decoration"); - _canvas_decoration->getProps()->setStringValue("background", "rgba(0,0,0,0)"); + _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 = _canvas_decoration->getRootGroup() + ->createChild("content"); _image_content->setSrcCanvas(content); + + // Draw content on top of decoration + _image_content->set("z-index", 1); } + sc::GroupPtr group_decoration = + _canvas_decoration->getOrCreateGroup("decoration"); + group_decoration->set("tf/t[0]", shadow_radius); + group_decoration->set("tf/t[1]", shadow_radius); + // TODO do we need clipping or shall we trust the decorator not to draw over + // the shadow? + 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; + int shad2 = 2 * shadow_radius, + outer_width = border.l + content->getViewWidth() + border.r + shad2, + outer_height = border.t + content->getViewHeight() + border.b + shad2; _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); + _image.set("size[0]", outer_width - shad2); + _image.set("size[1]", outer_height - shad2); + _image.set("outset", shadow_radius); assert(_image_content); - _image_content->set("x", border.l); - _image_content->set("y", border.t); + _image_content->set("x", shadow_radius + border.l); + _image_content->set("y", shadow_radius + border.t); + + if( !shadow_radius ) + { + if( _image_shadow ) + { + _image_shadow->destroy(); + _image_shadow.reset(); + } + return; + } + + int shadow_inset = std::max(get("shadow-inset") + 0.5, 0), + slice_width = shadow_radius + shadow_inset; + + _image_shadow = _canvas_decoration->getRootGroup() + ->getOrCreateChild("shadow"); + _image_shadow->set("file", "gui/images/shadow.png"); + _image_shadow->set("slice", 7); + _image_shadow->set("fill", "#000000"); + _image_shadow->set("slice-width", slice_width); + _image_shadow->set("size[0]", outer_width); + _image_shadow->set("size[1]", outer_height); + + // Draw shadow below decoration + _image_shadow->set("z-index", -1); } } // namespace canvas diff --git a/src/Canvas/window.hxx b/src/Canvas/window.hxx index 905b0e4c3..21e4844d2 100644 --- a/src/Canvas/window.hxx +++ b/src/Canvas/window.hxx @@ -77,7 +77,7 @@ namespace canvas enum Attributes { - SHADOW = 1 + DECORATION = 1 }; uint32_t _attributes_dirty; @@ -101,6 +101,7 @@ namespace canvas simgear::CSSBorder _decoration_border; void parseDecorationBorder(const std::string& str); + void updateDecoration(); }; } // namespace canvas -- 2.39.5