]> git.mxchange.org Git - simgear.git/blob - simgear/canvas/elements/CanvasElement.cxx
Canvas: Prepare for DOM Level 2 like event model.
[simgear.git] / simgear / canvas / elements / CanvasElement.cxx
1 // Interface for 2D Canvas element
2 //
3 // Copyright (C) 2012  Thomas Geymayer <tomgey@gmail.com>
4 //
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.
9 //
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.
14 //
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
18
19 #include "CanvasElement.hxx"
20 #include <simgear/canvas/CanvasEventVisitor.hxx>
21 #include <simgear/canvas/MouseEvent.hxx>
22
23 #include <osg/Drawable>
24 #include <osg/Geode>
25
26 #include <boost/foreach.hpp>
27
28 #include <cassert>
29 #include <cstring>
30
31 namespace simgear
32 {
33 namespace canvas
34 {
35   const std::string NAME_TRANSFORM = "tf";
36
37   //----------------------------------------------------------------------------
38   void Element::removeListener()
39   {
40     _node->removeChangeListener(this);
41   }
42
43   //----------------------------------------------------------------------------
44   Element::~Element()
45   {
46     removeListener();
47
48     BOOST_FOREACH(osg::Group* parent, _transform->getParents())
49     {
50       parent->removeChild(_transform);
51     }
52   }
53
54   //----------------------------------------------------------------------------
55   void Element::update(double dt)
56   {
57     if( !_transform->getNodeMask() )
58       // Don't do anything if element is hidden
59       return;
60
61     if( _transform_dirty )
62     {
63       osg::Matrix m;
64       for( size_t i = 0; i < _transform_types.size(); ++i )
65       {
66         // Skip unused indizes...
67         if( _transform_types[i] == TT_NONE )
68           continue;
69
70         SGPropertyNode* tf_node = _node->getChild("tf", i, true);
71
72         // Build up the matrix representation of the current transform node
73         osg::Matrix tf;
74         switch( _transform_types[i] )
75         {
76           case TT_MATRIX:
77             tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1),
78                               tf_node->getDoubleValue("m[1]", 0), 0, 0,
79
80                               tf_node->getDoubleValue("m[2]", 0),
81                               tf_node->getDoubleValue("m[3]", 1), 0, 0,
82
83                               0,    0,    1, 0,
84                               tf_node->getDoubleValue("m[4]", 0),
85                               tf_node->getDoubleValue("m[5]", 0), 0, 1 );
86             break;
87           case TT_TRANSLATE:
88             tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0),
89                                           tf_node->getDoubleValue("t[1]", 0),
90                                           0 ) );
91             break;
92           case TT_ROTATE:
93             tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 );
94             break;
95           case TT_SCALE:
96           {
97             float sx = tf_node->getDoubleValue("s[0]", 1);
98             // sy defaults to sx...
99             tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 );
100             break;
101           }
102           default:
103             break;
104         }
105         m.postMult( tf );
106       }
107       _transform->setMatrix(m);
108       _transform_dirty = false;
109     }
110   }
111
112   //----------------------------------------------------------------------------
113   naRef Element::addEventListener(const nasal::CallContext& ctx)
114   {
115     std::cout << "addEventListener " << _node->getPath() << std::endl;
116     return naNil();
117   }
118
119   //----------------------------------------------------------------------------
120   SGConstPropertyNode_ptr Element::getProps() const
121   {
122     return _node;
123   }
124
125   //----------------------------------------------------------------------------
126   SGPropertyNode_ptr Element::getProps()
127   {
128     return  _node;
129   }
130
131   //----------------------------------------------------------------------------
132   bool Element::accept(EventVisitor& visitor)
133   {
134     return visitor.apply(*this);
135   }
136
137   //----------------------------------------------------------------------------
138   bool Element::ascend(EventVisitor& visitor)
139   {
140     if( _parent )
141       return _parent->accept(visitor);
142     return true;
143   }
144
145   //----------------------------------------------------------------------------
146   bool Element::traverse(EventVisitor& visitor)
147   {
148     return true;
149   }
150
151   //----------------------------------------------------------------------------
152   bool Element::hitBound(const osg::Vec2f& pos) const
153   {
154     const osg::Vec3f pos3(pos, 0);
155
156     // Drawables have a bounding box...
157     if( _drawable )
158     {
159       if( !_drawable->getBound().contains(pos3) )
160         return false;
161     }
162     // ... for other elements, i.e. groups only a bounding sphere is available
163     else if( !_transform->getBound().contains(pos3) )
164       return false;
165
166     return true;
167   }
168
169   //----------------------------------------------------------------------------
170   osg::ref_ptr<osg::MatrixTransform> Element::getMatrixTransform()
171   {
172     return _transform;
173   }
174
175   //----------------------------------------------------------------------------
176   void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
177   {
178     if(    parent == _node
179         && child->getNameString() == NAME_TRANSFORM )
180     {
181       if( child->getIndex() >= static_cast<int>(_transform_types.size()) )
182         _transform_types.resize( child->getIndex() + 1 );
183
184       _transform_types[ child->getIndex() ] = TT_NONE;
185       _transform_dirty = true;
186       return;
187     }
188     else if(    parent->getParent() == _node
189              && parent->getNameString() == NAME_TRANSFORM )
190     {
191       assert(parent->getIndex() < static_cast<int>(_transform_types.size()));
192
193       const std::string& name = child->getNameString();
194
195       TransformType& type = _transform_types[parent->getIndex()];
196
197       if(      name == "m" )
198         type = TT_MATRIX;
199       else if( name == "t" )
200         type = TT_TRANSLATE;
201       else if( name == "rot" )
202         type = TT_ROTATE;
203       else if( name == "s" )
204         type = TT_SCALE;
205
206       _transform_dirty = true;
207       return;
208     }
209
210     childAdded(child);
211   }
212
213   //----------------------------------------------------------------------------
214   void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
215   {
216     if( parent == _node && child->getNameString() == NAME_TRANSFORM )
217     {
218       assert(child->getIndex() < static_cast<int>(_transform_types.size()));
219       _transform_types[ child->getIndex() ] = TT_NONE;
220
221       while( !_transform_types.empty() && _transform_types.back() == TT_NONE )
222         _transform_types.pop_back();
223
224       _transform_dirty = true;
225       return;
226     }
227
228     childRemoved(child);
229   }
230
231   //----------------------------------------------------------------------------
232   void Element::valueChanged(SGPropertyNode* child)
233   {
234     SGPropertyNode *parent = child->getParent();
235     if( parent == _node )
236     {
237       if( setStyle(child) )
238         return;
239       else if( child->getNameString() == "update" )
240         return update(0);
241       else if( child->getNameString() == "visible" )
242         // TODO check if we need another nodemask
243         return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
244     }
245     else if(   parent->getParent() == _node
246             && parent->getNameString() == NAME_TRANSFORM )
247     {
248       _transform_dirty = true;
249       return;
250     }
251
252     childChanged(child);
253   }
254
255   //----------------------------------------------------------------------------
256   void Element::setBoundingBox(const osg::BoundingBox& bb)
257   {
258     if( _bounding_box.empty() )
259     {
260       SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
261       _bounding_box.resize(4);
262       _bounding_box[0] = bb_node->getChild("min-x", 0, true);
263       _bounding_box[1] = bb_node->getChild("min-y", 0, true);
264       _bounding_box[2] = bb_node->getChild("max-x", 0, true);
265       _bounding_box[3] = bb_node->getChild("max-y", 0, true);
266     }
267
268     _bounding_box[0]->setFloatValue(bb._min.x());
269     _bounding_box[1]->setFloatValue(bb._min.y());
270     _bounding_box[2]->setFloatValue(bb._max.x());
271     _bounding_box[3]->setFloatValue(bb._max.y());
272   }
273
274   //----------------------------------------------------------------------------
275   Element::Element( const CanvasWeakPtr& canvas,
276                     const SGPropertyNode_ptr& node,
277                     const Style& parent_style,
278                     Element* parent ):
279     _canvas( canvas ),
280     _parent( parent ),
281     _transform_dirty( false ),
282     _transform( new osg::MatrixTransform ),
283     _node( node ),
284     _style( parent_style ),
285     _drawable( 0 )
286   {
287     assert( _node );
288     _node->addChangeListener(this);
289
290     SG_LOG
291     (
292       SG_GL,
293       SG_DEBUG,
294       "New canvas element " << node->getPath()
295     );
296   }
297
298   //----------------------------------------------------------------------------
299   void Element::callListeners(canvas::Event& event)
300   {
301     ListenerMap::iterator listeners = _listener.find(event.getType());
302     if( listeners == _listener.end() )
303       return;
304   }
305
306   //----------------------------------------------------------------------------
307   void Element::setDrawable( osg::Drawable* drawable )
308   {
309     _drawable = drawable;
310     assert( _drawable );
311
312     osg::ref_ptr<osg::Geode> geode = new osg::Geode;
313     geode->addDrawable(_drawable);
314     _transform->addChild(geode);
315   }
316
317   //----------------------------------------------------------------------------
318   void Element::setupStyle()
319   {
320     BOOST_FOREACH( Style::value_type style, _style )
321       setStyle(style.second);
322   }
323
324   //----------------------------------------------------------------------------
325   bool Element::setStyle(const SGPropertyNode* child)
326   {
327     StyleSetters::const_iterator setter =
328       _style_setters.find(child->getNameString());
329     if( setter == _style_setters.end() )
330       return false;
331
332     setter->second(child);
333     return true;
334   }
335
336 } // namespace canvas
337 } // namespace simgear