1 // Window for placing a Canvas onto it (for dialogs, menus, etc.)
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "canvas_mgr.hxx"
21 #include <Main/globals.hxx>
22 #include <simgear/canvas/Canvas.hxx>
23 #include <simgear/scene/util/OsgMath.hxx>
25 #include <osgGA/GUIEventHandler>
27 #include <boost/algorithm/string/predicate.hpp>
28 #include <boost/foreach.hpp>
32 namespace sc = simgear::canvas;
34 //----------------------------------------------------------------------------
35 Window::Window(SGPropertyNode* node):
36 PropertyBasedElement(node),
38 _image(sc::CanvasPtr(), node),
40 _capture_events(true),
41 _resize_top(node, "resize-top"),
42 _resize_right(node, "resize-right"),
43 _resize_bottom(node, "resize-bottom"),
44 _resize_left(node, "resize-left"),
45 _resize_status(node, "resize-status")
47 _image.removeListener();
49 node->setFloatValue("source/right", 1);
50 node->setFloatValue("source/bottom", 1);
51 node->setBoolValue("source/normalized", true);
54 //----------------------------------------------------------------------------
57 if( _canvas_decoration )
58 _canvas_decoration->destroy();
61 //----------------------------------------------------------------------------
62 void Window::update(double delta_time_sec)
64 if( _attributes_dirty & DECORATION )
67 _attributes_dirty &= ~DECORATION;
70 _image.update(delta_time_sec);
73 //----------------------------------------------------------------------------
74 void Window::valueChanged(SGPropertyNode * node)
77 if( node->getParent() == _node )
80 const std::string& name = node->getNameString();
81 if( name == "raise-top" )
83 else if( name == "resize" )
84 _resizable = node->getBoolValue();
85 else if( name == "update" )
87 else if( name == "capture-events" )
88 _capture_events = node->getBoolValue();
89 else if( name == "decoration-border" )
90 parseDecorationBorder(node->getStringValue());
91 else if( boost::starts_with(name, "shadow-") )
92 _attributes_dirty |= DECORATION;
98 _image.valueChanged(node);
101 //----------------------------------------------------------------------------
102 void Window::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
104 _image.childAdded(parent, child);
107 //----------------------------------------------------------------------------
108 void Window::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
110 _image.childRemoved(parent, child);
113 //----------------------------------------------------------------------------
114 osg::Group* Window::getGroup()
116 return _image.getMatrixTransform();
119 //----------------------------------------------------------------------------
120 const SGRect<float>& Window::getRegion() const
122 return _image.getRegion();
125 //----------------------------------------------------------------------------
126 const SGVec2<float> Window::getPosition() const
128 const osg::Matrix& m = _image.getMatrixTransform()->getMatrix();
129 return SGVec2<float>( m(3, 0), m(3, 1) );
132 //----------------------------------------------------------------------------
133 const SGRect<float> Window::getScreenRegion() const
135 return getPosition() + getRegion();
138 //----------------------------------------------------------------------------
139 void Window::setCanvas(sc::CanvasPtr canvas)
141 _canvas_content = canvas;
142 _image.setSrcCanvas(canvas);
145 //----------------------------------------------------------------------------
146 sc::CanvasWeakPtr Window::getCanvas() const
148 return _image.getSrcCanvas();
151 //----------------------------------------------------------------------------
152 sc::CanvasPtr Window::getCanvasDecoration()
154 return _canvas_decoration;
157 //----------------------------------------------------------------------------
158 bool Window::isVisible() const
160 return _image.isVisible();
163 //----------------------------------------------------------------------------
164 bool Window::isResizable() const
169 //----------------------------------------------------------------------------
170 bool Window::isCapturingEvents() const
172 return _capture_events;
175 //----------------------------------------------------------------------------
176 bool Window::handleMouseEvent(const sc::MouseEventPtr& event)
178 return _image.handleEvent(event);
181 //----------------------------------------------------------------------------
182 void Window::handleResize(uint8_t mode, const osg::Vec2f& delta)
189 else if( mode & INIT )
191 _resize_top = getRegion().t();
192 _resize_right = getRegion().r();
193 _resize_bottom = getRegion().b();
194 _resize_left = getRegion().l();
199 _resize_bottom += delta.y();
200 else if( mode & TOP )
201 _resize_top += delta.y();
203 if( mode & canvas::Window::RIGHT )
204 _resize_right += delta.x();
205 else if( mode & canvas::Window::LEFT )
206 _resize_left += delta.x();
209 //----------------------------------------------------------------------------
210 void Window::doRaise(SGPropertyNode* node_raise)
212 if( node_raise && !node_raise->getBoolValue() )
215 BOOST_FOREACH(osg::Group* parent, getGroup()->getParents())
218 parent->removeChild(getGroup());
220 // ...and add again as topmost window
221 parent->addChild(getGroup());
225 node_raise->setBoolValue(false);
228 //----------------------------------------------------------------------------
229 void Window::parseDecorationBorder(const std::string& str)
231 _decoration_border = simgear::CSSBorder::parse(str);
232 _attributes_dirty |= DECORATION;
235 //----------------------------------------------------------------------------
236 void Window::updateDecoration()
238 int shadow_radius = get<float>("shadow-radius") + 0.5;
239 if( shadow_radius < 2 )
242 if( _decoration_border.isNone() && !shadow_radius )
244 sc::CanvasPtr canvas_content = _canvas_content.lock();
245 _image.setSrcCanvas(canvas_content);
246 _image.set<int>("size[0]", canvas_content->getViewWidth());
247 _image.set<int>("size[1]", canvas_content->getViewHeight());
249 _image_content.reset();
250 _image_shadow.reset();
251 _canvas_decoration->destroy();
252 _canvas_decoration.reset();
256 sc::CanvasPtr content = _canvas_content.lock();
257 if( !_canvas_decoration )
260 dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
264 SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
268 _canvas_decoration = mgr->createCanvas("window-decoration");
269 _canvas_decoration->getProps()
270 ->setStringValue("background", "rgba(0,0,0,0)");
271 _image.setSrcCanvas(_canvas_decoration);
273 _image_content = _canvas_decoration->getRootGroup()
274 ->createChild<sc::Image>("content");
275 _image_content->setSrcCanvas(content);
277 // Draw content on top of decoration
278 _image_content->set<int>("z-index", 1);
281 sc::GroupPtr group_decoration =
282 _canvas_decoration->getOrCreateGroup("decoration");
283 group_decoration->set<int>("tf/t[0]", shadow_radius);
284 group_decoration->set<int>("tf/t[1]", shadow_radius);
285 // TODO do we need clipping or shall we trust the decorator not to draw over
288 simgear::CSSBorder::Offsets const border =
289 _decoration_border.getAbsOffsets(content->getViewport());
291 int shad2 = 2 * shadow_radius,
292 outer_width = border.l + content->getViewWidth() + border.r + shad2,
293 outer_height = border.t + content->getViewHeight() + border.b + shad2;
295 _canvas_decoration->setSizeX( outer_width );
296 _canvas_decoration->setSizeY( outer_height );
297 _canvas_decoration->setViewWidth( outer_width );
298 _canvas_decoration->setViewHeight( outer_height );
300 _image.set<int>("size[0]", outer_width - shad2);
301 _image.set<int>("size[1]", outer_height - shad2);
302 _image.set<int>("outset", shadow_radius);
304 assert(_image_content);
305 _image_content->set<int>("x", shadow_radius + border.l);
306 _image_content->set<int>("y", shadow_radius + border.t);
312 _image_shadow->destroy();
313 _image_shadow.reset();
318 int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
319 slice_width = shadow_radius + shadow_inset;
321 _image_shadow = _canvas_decoration->getRootGroup()
322 ->getOrCreateChild<sc::Image>("shadow");
323 _image_shadow->set<std::string>("file", "gui/images/shadow.png");
324 _image_shadow->set<float>("slice", 7);
325 _image_shadow->set<std::string>("fill", "#000000");
326 _image_shadow->set<float>("slice-width", slice_width);
327 _image_shadow->set<int>("size[0]", outer_width);
328 _image_shadow->set<int>("size[1]", outer_height);
330 // Draw shadow below decoration
331 _image_shadow->set<int>("z-index", -1);
334 } // namespace canvas