1 // Window for placing a Canvas onto it (for dialogs, menus, etc.)
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Library General Public License for more details.
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "CanvasMgr.hxx"
20 #include "CanvasSystemAdapter.hxx"
21 #include "CanvasWindow.hxx"
23 #include <simgear/canvas/Canvas.hxx>
24 #include <simgear/scene/util/OsgMath.hxx>
26 #include <osgGA/GUIEventHandler>
28 #include <boost/algorithm/string/predicate.hpp>
29 #include <boost/foreach.hpp>
36 //----------------------------------------------------------------------------
37 const std::string Window::TYPE_NAME = "window";
39 //----------------------------------------------------------------------------
40 Window::Window( const CanvasWeakPtr& canvas,
41 const SGPropertyNode_ptr& node,
42 const Style& parent_style,
44 Image(canvas, node, parent_style, parent),
47 _capture_events(true),
48 _resize_top(node, "resize-top"),
49 _resize_right(node, "resize-right"),
50 _resize_bottom(node, "resize-bottom"),
51 _resize_left(node, "resize-left"),
52 _resize_status(node, "resize-status")
54 node->setFloatValue("source/right", 1);
55 node->setFloatValue("source/bottom", 1);
56 node->setBoolValue("source/normalized", true);
59 //----------------------------------------------------------------------------
62 if( _canvas_decoration )
63 _canvas_decoration->destroy();
66 //----------------------------------------------------------------------------
67 void Window::update(double delta_time_sec)
69 if( _attributes_dirty & DECORATION )
72 _attributes_dirty &= ~DECORATION;
75 Image::update(delta_time_sec);
78 //----------------------------------------------------------------------------
79 void Window::valueChanged(SGPropertyNode * node)
82 if( node->getParent() == _node )
85 const std::string& name = node->getNameString();
86 if( name == "resize" )
87 _resizable = node->getBoolValue();
88 else if( name == "update" )
90 else if( name == "capture-events" )
91 _capture_events = node->getBoolValue();
92 else if( name == "decoration-border" )
93 parseDecorationBorder(node->getStringValue());
94 else if( boost::starts_with(name, "shadow-")
95 || name == "content-size" )
96 _attributes_dirty |= DECORATION;
102 Image::valueChanged(node);
105 //----------------------------------------------------------------------------
106 osg::Group* Window::getGroup()
108 return getMatrixTransform();
111 //----------------------------------------------------------------------------
112 const SGVec2<float> Window::getPosition() const
114 const osg::Matrix& m = getMatrixTransform()->getMatrix();
115 return SGVec2<float>( m(3, 0), m(3, 1) );
118 //----------------------------------------------------------------------------
119 const SGRect<float> Window::getScreenRegion() const
121 return getPosition() + getRegion();
124 //----------------------------------------------------------------------------
125 void Window::setCanvasContent(CanvasPtr canvas)
127 _canvas_content = canvas;
130 canvas->setLayout(_layout);
135 // Placement within decoration canvas
136 _image_content->setSrcCanvas(canvas);
138 setSrcCanvas(canvas);
141 //----------------------------------------------------------------------------
142 CanvasWeakPtr Window::getCanvasContent() const
144 return _canvas_content;
147 //----------------------------------------------------------------------------
148 void Window::setLayout(const LayoutRef& layout)
150 CanvasPtr canvas = _canvas_content.lock();
152 canvas->setLayout(layout);
154 _layout = layout; // keep layout until content canvas is set
157 //----------------------------------------------------------------------------
158 CanvasPtr Window::getCanvasDecoration() const
160 return _canvas_decoration;
163 //----------------------------------------------------------------------------
164 bool Window::isResizable() const
169 //----------------------------------------------------------------------------
170 bool Window::isCapturingEvents() const
172 return _capture_events;
175 //----------------------------------------------------------------------------
176 void Window::setVisible(bool visible)
178 LayoutItem::setVisible(visible);
179 Element::setVisible(LayoutItem::isVisible());
182 //----------------------------------------------------------------------------
183 bool Window::isVisible() const
185 return Element::isVisible();
188 //----------------------------------------------------------------------------
191 // on writing the z-index the window always is moved to the top of all other
192 // windows with the same z-index.
193 set<int>("z-index", get<int>("z-index", 0));
196 //----------------------------------------------------------------------------
197 void Window::handleResize( uint8_t mode,
198 const osg::Vec2f& offset )
205 else if( mode & INIT )
207 _resize_top = getRegion().t();
208 _resize_right = getRegion().r();
209 _resize_bottom = getRegion().b();
210 _resize_left = getRegion().l();
215 _resize_bottom = getRegion().b() + offset.y();
216 else if( mode & TOP )
217 _resize_top = getRegion().t() + offset.y();
219 if( mode & canvas::Window::RIGHT )
220 _resize_right = getRegion().r() + offset.x();
221 else if( mode & canvas::Window::LEFT )
222 _resize_left = getRegion().l() + offset.x();
225 //----------------------------------------------------------------------------
226 void Window::parseDecorationBorder(const std::string& str)
228 _decoration_border = simgear::CSSBorder::parse(str);
229 _attributes_dirty |= DECORATION;
232 //----------------------------------------------------------------------------
233 void Window::updateDecoration()
235 int shadow_radius = get<float>("shadow-radius") + 0.5;
236 if( shadow_radius < 2 )
239 CanvasPtr content = _canvas_content.lock();
240 SGRect<int> content_view
244 get<int>("content-size[0]", content ? content->getViewWidth() : 400),
245 get<int>("content-size[1]", content ? content->getViewHeight() : 300)
248 if( _decoration_border.isNone() && !shadow_radius )
250 setSrcCanvas(content);
251 set<int>("size[0]", content_view.width());
252 set<int>("size[1]", content_view.height());
254 _image_content.reset();
255 _image_shadow.reset();
256 if( _canvas_decoration )
257 _canvas_decoration->destroy();
258 _canvas_decoration.reset();
262 if( !_canvas_decoration )
264 CanvasMgr* mgr = dynamic_cast<CanvasMgr*>(
265 Canvas::getSystemAdapter()->getSubsystem("Canvas")
270 SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
274 _canvas_decoration = mgr->createCanvas("window-decoration");
275 _canvas_decoration->getProps()
276 ->setStringValue("background", "rgba(0,0,0,0)");
277 setSrcCanvas(_canvas_decoration);
279 _image_content = _canvas_decoration->getRootGroup()
280 ->createChild<Image>("content");
281 _image_content->setSrcCanvas(content);
283 // Forward keyboard events to content
284 _image_content->setFocus();
286 // Draw content on top of decoration
287 _image_content->set<int>("z-index", 1);
290 GroupPtr group_decoration =
291 _canvas_decoration->getOrCreateGroup("decoration");
292 group_decoration->set<int>("tf/t[0]", shadow_radius);
293 group_decoration->set<int>("tf/t[1]", shadow_radius);
294 // TODO do we need clipping or shall we trust the decorator not to draw over
297 CSSBorder::Offsets const border =
298 _decoration_border.getAbsOffsets(content_view);
300 int shad2 = 2 * shadow_radius,
301 outer_width = border.l + content_view.width() + border.r + shad2,
302 outer_height = border.t + content_view.height() + border.b + shad2;
304 _canvas_decoration->setSizeX( outer_width );
305 _canvas_decoration->setSizeY( outer_height );
306 _canvas_decoration->setViewWidth( outer_width );
307 _canvas_decoration->setViewHeight( outer_height );
309 set<int>("size[0]", outer_width - shad2);
310 set<int>("size[1]", outer_height - shad2);
311 set<int>("outset", shadow_radius);
313 assert(_image_content);
314 _image_content->set<int>("x", shadow_radius + border.l);
315 _image_content->set<int>("y", shadow_radius + border.t);
316 _image_content->set<int>("size[0]", content_view.width());
317 _image_content->set<int>("size[1]", content_view.height());
323 _image_shadow->destroy();
324 _image_shadow.reset();
329 int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
330 slice_width = shadow_radius + shadow_inset;
332 _image_shadow = _canvas_decoration->getRootGroup()
333 ->getOrCreateChild<Image>("shadow");
334 _image_shadow->set<std::string>("src", "gui/images/shadow.png");
335 _image_shadow->set<float>("slice", 7);
336 _image_shadow->set<std::string>("fill", "#000000");
337 _image_shadow->set<float>("slice-width", slice_width);
338 _image_shadow->set<int>("size[0]", outer_width);
339 _image_shadow->set<int>("size[1]", outer_height);
341 // Draw shadow below decoration
342 _image_shadow->set<int>("z-index", -1);
345 } // namespace canvas
346 } // namespace simgear