]> git.mxchange.org Git - flightgear.git/blob - src/Canvas/window.cxx
Base canvas::Window on simgear::canvas::Image
[flightgear.git] / src / Canvas / window.cxx
1 // Window for placing a Canvas onto it (for dialogs, menus, etc.)
2 //
3 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
4 //
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.
9 //
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.
14 //
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.
18
19 #include "canvas_mgr.hxx"
20 #include "window.hxx"
21 #include <Main/globals.hxx>
22 #include <simgear/canvas/Canvas.hxx>
23 #include <simgear/scene/util/OsgMath.hxx>
24
25 #include <osgGA/GUIEventHandler>
26
27 #include <boost/algorithm/string/predicate.hpp>
28 #include <boost/foreach.hpp>
29
30 namespace canvas
31 {
32   namespace sc = simgear::canvas;
33
34   //----------------------------------------------------------------------------
35   Window::Window(SGPropertyNode* node):
36     Image(sc::CanvasPtr(), node),
37     _attributes_dirty(0),
38     _resizable(false),
39     _capture_events(true),
40     _resize_top(node, "resize-top"),
41     _resize_right(node, "resize-right"),
42     _resize_bottom(node, "resize-bottom"),
43     _resize_left(node, "resize-left"),
44     _resize_status(node, "resize-status")
45   {
46     node->setFloatValue("source/right", 1);
47     node->setFloatValue("source/bottom", 1);
48     node->setBoolValue("source/normalized", true);
49   }
50
51   //----------------------------------------------------------------------------
52   Window::~Window()
53   {
54     if( _canvas_decoration )
55       _canvas_decoration->destroy();
56   }
57
58   //----------------------------------------------------------------------------
59   void Window::update(double delta_time_sec)
60   {
61     if( _attributes_dirty & DECORATION )
62     {
63       updateDecoration();
64       _attributes_dirty &= ~DECORATION;
65     }
66
67     Image::update(delta_time_sec);
68   }
69
70   //----------------------------------------------------------------------------
71   void Window::valueChanged(SGPropertyNode * node)
72   {
73     bool handled = false;
74     if( node->getParent() == _node )
75     {
76       handled = true;
77       const std::string& name = node->getNameString();
78       if( name == "raise-top" )
79         doRaise(node);
80       else if( name  == "resize" )
81         _resizable = node->getBoolValue();
82       else if( name == "update" )
83         update(0);
84       else if( name == "capture-events" )
85         _capture_events = node->getBoolValue();
86       else if( name == "decoration-border" )
87         parseDecorationBorder(node->getStringValue());
88       else if( boost::starts_with(name, "shadow-") )
89         _attributes_dirty |= DECORATION;
90       else
91         handled = false;
92     }
93
94     if( !handled )
95       Image::valueChanged(node);
96   }
97
98   //----------------------------------------------------------------------------
99   osg::Group* Window::getGroup()
100   {
101     return getMatrixTransform();
102   }
103
104   //----------------------------------------------------------------------------
105   const SGVec2<float> Window::getPosition() const
106   {
107     const osg::Matrix& m = getMatrixTransform()->getMatrix();
108     return SGVec2<float>( m(3, 0), m(3, 1) );
109   }
110
111   //----------------------------------------------------------------------------
112   const SGRect<float> Window::getScreenRegion() const
113   {
114     return getPosition() + getRegion();
115   }
116
117   //----------------------------------------------------------------------------
118   void Window::setCanvas(sc::CanvasPtr canvas)
119   {
120     _canvas_content = canvas;
121     setSrcCanvas(canvas);
122   }
123
124   //----------------------------------------------------------------------------
125   sc::CanvasWeakPtr Window::getCanvas() const
126   {
127     return getSrcCanvas();
128   }
129
130   //----------------------------------------------------------------------------
131   sc::CanvasPtr Window::getCanvasDecoration()
132   {
133     return _canvas_decoration;
134   }
135
136   //----------------------------------------------------------------------------
137   bool Window::isResizable() const
138   {
139     return _resizable;
140   }
141
142   //----------------------------------------------------------------------------
143   bool Window::isCapturingEvents() const
144   {
145     return _capture_events;
146   }
147
148   //----------------------------------------------------------------------------
149   void Window::handleResize(uint8_t mode, const osg::Vec2f& delta)
150   {
151     if( mode == NONE )
152     {
153       _resize_status = 0;
154       return;
155     }
156     else if( mode & INIT )
157     {
158       _resize_top    = getRegion().t();
159       _resize_right  = getRegion().r();
160       _resize_bottom = getRegion().b();
161       _resize_left   = getRegion().l();
162       _resize_status = 1;
163     }
164
165     if( mode & BOTTOM )
166       _resize_bottom += delta.y();
167     else if( mode & TOP )
168       _resize_top += delta.y();
169
170     if( mode & canvas::Window::RIGHT )
171       _resize_right += delta.x();
172     else if( mode & canvas::Window::LEFT )
173       _resize_left += delta.x();
174   }
175
176   //----------------------------------------------------------------------------
177   void Window::doRaise(SGPropertyNode* node_raise)
178   {
179     if( node_raise && !node_raise->getBoolValue() )
180       return;
181
182     // Keep a reference to ensure the window is not deleted between removing and
183     // adding it back to the scenegraph
184     osg::ref_ptr<osg::Group> window = getGroup();
185
186     BOOST_FOREACH(osg::Group* parent, getGroup()->getParents())
187     {
188       // Remove window...
189       parent->removeChild(window);
190
191       // ...and add again as topmost window
192       parent->addChild(window);
193     }
194
195     if( node_raise )
196       node_raise->setBoolValue(false);
197   }
198
199   //----------------------------------------------------------------------------
200   void Window::parseDecorationBorder(const std::string& str)
201   {
202     _decoration_border = simgear::CSSBorder::parse(str);
203     _attributes_dirty |= DECORATION;
204   }
205
206   //----------------------------------------------------------------------------
207   void Window::updateDecoration()
208   {
209     int shadow_radius = get<float>("shadow-radius") + 0.5;
210     if( shadow_radius < 2 )
211       shadow_radius = 0;
212
213     if( _decoration_border.isNone() && !shadow_radius )
214     {
215       sc::CanvasPtr canvas_content = _canvas_content.lock();
216       setSrcCanvas(canvas_content);
217       set<int>("size[0]", canvas_content->getViewWidth());
218       set<int>("size[1]", canvas_content->getViewHeight());
219
220       _image_content.reset();
221       _image_shadow.reset();
222       _canvas_decoration->destroy();
223       _canvas_decoration.reset();
224       return;
225     }
226
227     sc::CanvasPtr content = _canvas_content.lock();
228     if( !_canvas_decoration )
229     {
230       CanvasMgr* mgr =
231         dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas"));
232
233       if( !mgr )
234       {
235         SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
236         return;
237       }
238
239       _canvas_decoration = mgr->createCanvas("window-decoration");
240       _canvas_decoration->getProps()
241                         ->setStringValue("background", "rgba(0,0,0,0)");
242       setSrcCanvas(_canvas_decoration);
243
244       _image_content = _canvas_decoration->getRootGroup()
245                                          ->createChild<sc::Image>("content");
246       _image_content->setSrcCanvas(content);
247
248       // Draw content on top of decoration
249       _image_content->set<int>("z-index", 1);
250     }
251
252     sc::GroupPtr group_decoration =
253       _canvas_decoration->getOrCreateGroup("decoration");
254     group_decoration->set<int>("tf/t[0]", shadow_radius);
255     group_decoration->set<int>("tf/t[1]", shadow_radius);
256     // TODO do we need clipping or shall we trust the decorator not to draw over
257     //      the shadow?
258
259     simgear::CSSBorder::Offsets const border =
260       _decoration_border.getAbsOffsets(content->getViewport());
261
262     int shad2 = 2 * shadow_radius,
263         outer_width  = border.l + content->getViewWidth()  + border.r + shad2,
264         outer_height = border.t + content->getViewHeight() + border.b + shad2;
265
266     _canvas_decoration->setSizeX( outer_width );
267     _canvas_decoration->setSizeY( outer_height );
268     _canvas_decoration->setViewWidth( outer_width );
269     _canvas_decoration->setViewHeight( outer_height );
270
271     set<int>("size[0]", outer_width - shad2);
272     set<int>("size[1]", outer_height - shad2);
273     set<int>("outset", shadow_radius);
274
275     assert(_image_content);
276     _image_content->set<int>("x", shadow_radius + border.l);
277     _image_content->set<int>("y", shadow_radius + border.t);
278
279     if( !shadow_radius )
280     {
281       if( _image_shadow )
282       {
283         _image_shadow->destroy();
284         _image_shadow.reset();
285       }
286       return;
287     }
288
289     int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
290         slice_width  = shadow_radius + shadow_inset;
291
292     _image_shadow = _canvas_decoration->getRootGroup()
293                                       ->getOrCreateChild<sc::Image>("shadow");
294     _image_shadow->set<std::string>("file", "gui/images/shadow.png");
295     _image_shadow->set<float>("slice", 7);
296     _image_shadow->set<std::string>("fill", "#000000");
297     _image_shadow->set<float>("slice-width", slice_width);
298     _image_shadow->set<int>("size[0]", outer_width);
299     _image_shadow->set<int>("size[1]", outer_height);
300
301     // Draw shadow below decoration
302     _image_shadow->set<int>("z-index", -1);
303   }
304
305 } // namespace canvas