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 const std::string Window::TYPE_NAME = "window";
37 //----------------------------------------------------------------------------
38 Window::Window( const simgear::canvas::CanvasWeakPtr& canvas,
39 const SGPropertyNode_ptr& node,
40 const Style& parent_style,
42 Image(canvas, node, parent_style, parent),
45 _capture_events(true),
46 _resize_top(node, "resize-top"),
47 _resize_right(node, "resize-right"),
48 _resize_bottom(node, "resize-bottom"),
49 _resize_left(node, "resize-left"),
50 _resize_status(node, "resize-status")
52 node->setFloatValue("source/right", 1);
53 node->setFloatValue("source/bottom", 1);
54 node->setBoolValue("source/normalized", true);
57 //----------------------------------------------------------------------------
60 if( _canvas_decoration )
61 _canvas_decoration->destroy();
64 //----------------------------------------------------------------------------
65 void Window::update(double delta_time_sec)
67 if( _attributes_dirty & DECORATION )
70 _attributes_dirty &= ~DECORATION;
73 Image::update(delta_time_sec);
76 //----------------------------------------------------------------------------
77 void Window::valueChanged(SGPropertyNode * node)
80 if( node->getParent() == _node )
83 const std::string& name = node->getNameString();
84 if( name == "resize" )
85 _resizable = node->getBoolValue();
86 else if( name == "update" )
88 else if( name == "capture-events" )
89 _capture_events = node->getBoolValue();
90 else if( name == "decoration-border" )
91 parseDecorationBorder(node->getStringValue());
92 else if( boost::starts_with(name, "shadow-")
93 || name == "content-size" )
94 _attributes_dirty |= DECORATION;
100 Image::valueChanged(node);
103 //----------------------------------------------------------------------------
104 osg::Group* Window::getGroup()
106 return getMatrixTransform();
109 //----------------------------------------------------------------------------
110 const SGVec2<float> Window::getPosition() const
112 const osg::Matrix& m = getMatrixTransform()->getMatrix();
113 return SGVec2<float>( m(3, 0), m(3, 1) );
116 //----------------------------------------------------------------------------
117 const SGRect<float> Window::getScreenRegion() const
119 return getPosition() + getRegion();
122 //----------------------------------------------------------------------------
123 void Window::setCanvasContent(sc::CanvasPtr canvas)
125 _canvas_content = canvas;
128 // Placement within decoration canvas
129 _image_content->setSrcCanvas(canvas);
131 setSrcCanvas(canvas);
134 //----------------------------------------------------------------------------
135 sc::CanvasWeakPtr Window::getCanvasContent() const
137 return _canvas_content;
140 //----------------------------------------------------------------------------
141 sc::CanvasPtr Window::getCanvasDecoration()
143 return _canvas_decoration;
146 //----------------------------------------------------------------------------
147 bool Window::isResizable() const
152 //----------------------------------------------------------------------------
153 bool Window::isCapturingEvents() const
155 return _capture_events;
158 //----------------------------------------------------------------------------
161 // on writing the z-index the window always is moved to the top of all other
162 // windows with the same z-index.
163 set<int>("z-index", get<int>("z-index", 0));
166 //----------------------------------------------------------------------------
167 void Window::handleResize( uint8_t mode,
168 const osg::Vec2f& offset )
175 else if( mode & INIT )
177 _resize_top = getRegion().t();
178 _resize_right = getRegion().r();
179 _resize_bottom = getRegion().b();
180 _resize_left = getRegion().l();
185 _resize_bottom = getRegion().b() + offset.y();
186 else if( mode & TOP )
187 _resize_top = getRegion().t() + offset.y();
189 if( mode & canvas::Window::RIGHT )
190 _resize_right = getRegion().r() + offset.x();
191 else if( mode & canvas::Window::LEFT )
192 _resize_left = getRegion().l() + offset.x();
195 //----------------------------------------------------------------------------
196 void Window::parseDecorationBorder(const std::string& str)
198 _decoration_border = simgear::CSSBorder::parse(str);
199 _attributes_dirty |= DECORATION;
202 //----------------------------------------------------------------------------
203 void Window::updateDecoration()
205 int shadow_radius = get<float>("shadow-radius") + 0.5;
206 if( shadow_radius < 2 )
209 sc::CanvasPtr content = _canvas_content.lock();
210 SGRect<int> content_view
214 get<int>("content-size[0]", content->getViewWidth()),
215 get<int>("content-size[1]", content->getViewHeight())
218 if( _decoration_border.isNone() && !shadow_radius )
220 setSrcCanvas(content);
221 set<int>("size[0]", content_view.width());
222 set<int>("size[1]", content_view.height());
224 _image_content.reset();
225 _image_shadow.reset();
226 if( _canvas_decoration )
227 _canvas_decoration->destroy();
228 _canvas_decoration.reset();
232 if( !_canvas_decoration )
235 dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
239 SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
243 _canvas_decoration = mgr->createCanvas("window-decoration");
244 _canvas_decoration->getProps()
245 ->setStringValue("background", "rgba(0,0,0,0)");
246 setSrcCanvas(_canvas_decoration);
248 _image_content = _canvas_decoration->getRootGroup()
249 ->createChild<sc::Image>("content");
250 _image_content->setSrcCanvas(content);
252 // Draw content on top of decoration
253 _image_content->set<int>("z-index", 1);
256 sc::GroupPtr group_decoration =
257 _canvas_decoration->getOrCreateGroup("decoration");
258 group_decoration->set<int>("tf/t[0]", shadow_radius);
259 group_decoration->set<int>("tf/t[1]", shadow_radius);
260 // TODO do we need clipping or shall we trust the decorator not to draw over
263 simgear::CSSBorder::Offsets const border =
264 _decoration_border.getAbsOffsets(content_view);
266 int shad2 = 2 * shadow_radius,
267 outer_width = border.l + content_view.width() + border.r + shad2,
268 outer_height = border.t + content_view.height() + border.b + shad2;
270 _canvas_decoration->setSizeX( outer_width );
271 _canvas_decoration->setSizeY( outer_height );
272 _canvas_decoration->setViewWidth( outer_width );
273 _canvas_decoration->setViewHeight( outer_height );
275 set<int>("size[0]", outer_width - shad2);
276 set<int>("size[1]", outer_height - shad2);
277 set<int>("outset", shadow_radius);
279 assert(_image_content);
280 _image_content->set<int>("x", shadow_radius + border.l);
281 _image_content->set<int>("y", shadow_radius + border.t);
282 _image_content->set<int>("size[0]", content_view.width());
283 _image_content->set<int>("size[1]", content_view.height());
289 _image_shadow->destroy();
290 _image_shadow.reset();
295 int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
296 slice_width = shadow_radius + shadow_inset;
298 _image_shadow = _canvas_decoration->getRootGroup()
299 ->getOrCreateChild<sc::Image>("shadow");
300 _image_shadow->set<std::string>("file", "gui/images/shadow.png");
301 _image_shadow->set<float>("slice", 7);
302 _image_shadow->set<std::string>("fill", "#000000");
303 _image_shadow->set<float>("slice-width", slice_width);
304 _image_shadow->set<int>("size[0]", outer_width);
305 _image_shadow->set<int>("size[1]", outer_height);
307 // Draw shadow below decoration
308 _image_shadow->set<int>("z-index", -1);
311 } // namespace canvas