osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/Controls.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include <osgEarthUtil/Controls>
00020 #include <osgEarth/FindNode>
00021 #include <osg/Geometry>
00022 #include <osg/NodeCallback>
00023 #include <osg/Depth>
00024 #include <osg/TextureRectangle>
00025 #include <osgGA/GUIEventHandler>
00026 #include <osgText/Text>
00027 #include <osgEarthSymbology/Geometry>
00028 #include <osgEarthSymbology/GeometryRasterizer>
00029 #include <osg/Version>
00030 #include <osgEarth/Common>
00031 
00032 using namespace osgEarth;
00033 using namespace osgEarth::Symbology;
00034 using namespace osgEarth::Util;
00035 using namespace osgEarth::Util::Controls;
00036 
00037 #define LC "[Controls] "
00038 
00039 // ---------------------------------------------------------------------------
00040 
00041 namespace
00042 {
00043     // ControlNodeBin shaders.
00044 
00045     char* s_controlVertexShader =
00046         "void main() \n"
00047         "{ \n"
00048         "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n"
00049         "    gl_TexCoord[0] = gl_MultiTexCoord0; \n"
00050         "    gl_FrontColor = gl_Color; \n"
00051         "} \n";
00052 
00053     char* s_imageControlFragmentShader =
00054         "uniform sampler2D tex0; \n"
00055         "uniform float visibleTime; \n"
00056         "uniform float osg_FrameTime; \n"
00057         "void main() \n"
00058         "{ \n"
00059         "    float opacity = clamp( osg_FrameTime - visibleTime, 0.0, 1.0 ); \n"
00060         "    vec4 texel = texture2D(tex0, gl_TexCoord[0].st); \n"
00061         "    gl_FragColor = vec4(texel.rgb, texel.a * opacity); \n"
00062         "} \n";
00063 
00064     char* s_labelControlFragmentShader =
00065         "uniform sampler2D tex0; \n"
00066         "uniform float visibleTime; \n"
00067         "uniform float osg_FrameTime; \n"
00068         "void main() \n"
00069         "{ \n"
00070         "    float opacity = clamp( osg_FrameTime - visibleTime, 0.0, 1.0 ); \n"
00071         "    vec4 texel = texture2D(tex0, gl_TexCoord[0].st); \n"       
00072         "    gl_FragColor = vec4(gl_Color.rgb, texel.a * opacity); \n"
00073         "} \n";
00074 }
00075 
00076 // ---------------------------------------------------------------------------
00077 
00078 namespace
00079 {
00080     void calculateRotatedSize( float w, float h, float angle_rad, float& out_w, float& out_h )
00081     {
00082         float x1 = -w/2, x2 = w/2, x3 =  w/2, x4 = -w/2;
00083         float y1 =  h/2, y2 = h/2, y3 = -h/2, y4 = -h/2;
00084 
00085         float cosa = cos(angle_rad);
00086         float sina = sin(angle_rad);
00087 
00088         float
00089             x11 =  x1*cosa + y1*sina,
00090             y11 = -x1*sina + y1*cosa,
00091             x21 =  x2*cosa + y2*sina,
00092             y21 = -x2*sina + y2*cosa,
00093             x31 =  x3*cosa + y3*sina,
00094             y31 = -x3*sina + y3*cosa,
00095             x41 =  x4*cosa + y4*sina,
00096             y41 = -x4*sina + y3*cosa;
00097 
00098         float xmin = std::min(x11, std::min(x21, std::min(x31, x41)));
00099         float ymin = std::min(y11, std::min(y21, std::min(y31, y41)));
00100 
00101         float xmax = std::max(x11, std::max(x21, std::max(x31, x41)));
00102         float ymax = std::max(y11, std::max(y21, std::max(y31, y41)));
00103 
00104         out_w = xmax-xmin;
00105         out_h = ymax-ymin;
00106     }
00107 
00108     void rot( float x, float y, const osg::Vec2f& c, float angle_rad, osg::Vec3f& out )
00109     {
00110         float cosa = cos(angle_rad);
00111         float sina = sin(angle_rad);
00112         out.x() = (c.x()-x)*cosa - (c.y()-y)*sina + c.x();
00113         out.y() = (c.y()-y)*cosa + (c.x()-x)*sina + c.y();
00114         out.z() = 0.0f;
00115     }
00116 }
00117 
00118 // ---------------------------------------------------------------------------
00119 
00120 Control::Control() :
00121 _x(0), _y(0), _width(1), _height(1),
00122 _margin( Gutter(0) ),
00123 _padding( Gutter(2) ),
00124 _visible( true ),
00125 _valign( ALIGN_NONE ),
00126 _halign( ALIGN_NONE ),
00127 _backColor( osg::Vec4f(0,0,0,0) ),
00128 _foreColor( osg::Vec4f(1,1,1,1) ),
00129 _activeColor( osg::Vec4f(.4,.4,.4,1) ),
00130 _active( false ),
00131 _absorbEvents( false ),
00132 _hfill( false ),
00133 _vfill( false )
00134 {
00135     //nop
00136 }
00137 
00138 void
00139 Control::setVisible( bool value ) {
00140     if ( value != _visible ) {
00141         _visible = value;
00142         dirty();
00143     }
00144 }
00145 
00146 void
00147 Control::setX( float value ) {
00148     if ( value != _x.value() ) {
00149         _x = value;
00150         dirty();
00151     }
00152 }
00153 
00154 void
00155 Control::setY( float value ) {
00156     if ( value != _y.value() ) {
00157         _y = value;
00158         dirty();
00159     }
00160 }
00161 
00162 void
00163 Control::setPosition( float x, float y ) {
00164     setX( x );
00165     setY( y );
00166 }
00167 
00168 void
00169 Control::setWidth( float value ) {
00170     if ( value != _width.value() ) {
00171         _width = value;
00172         dirty();
00173     }
00174 }
00175 
00176 void 
00177 Control::setHeight( float value ) {
00178     if ( value != _height.value() ) {
00179         _height = value;
00180         dirty();
00181     }
00182 }
00183 
00184 void
00185 Control::setSize( float w, float h ) {
00186     setWidth( w );
00187     setHeight( h );
00188 }
00189 
00190 void
00191 Control::setMargin( const Gutter& value ) {
00192     if ( value != _margin ) {
00193         _margin = value;
00194         dirty();
00195     }
00196 }
00197 
00198 void
00199 Control::setPadding( const Gutter& value )
00200 {
00201     if ( value != _padding ) {
00202         _padding = value;
00203         dirty();
00204     }
00205 }
00206 
00207 void
00208 Control::setPadding( float value ) {
00209     Gutter g(value);
00210     if ( g != _padding ) {
00211         _padding = g;
00212         dirty();
00213     }
00214 }
00215 
00216 void
00217 Control::setHorizAlign( const Alignment& value ) {
00218     if ( !_halign.isSetTo( value ) ) {
00219         _halign = value;
00220         _x.unset();  // horiz align is mutex with abs positioning
00221         dirty();
00222     }
00223 }
00224 
00225 void
00226 Control::setVertAlign( const Alignment& value ) {
00227     if ( !_valign.isSetTo( value ) ) {
00228         _valign = value;
00229         _y.unset(); // vert align is mutex with abs positioning
00230         dirty();
00231     }
00232 }
00233 
00234 void
00235 Control::setHorizFill( bool hfill, float minWidth ) {
00236     if ( hfill != _hfill || !_width.isSetTo(minWidth) ) { //minWidth != _width.value() ) {
00237         _hfill = hfill;
00238         if ( hfill )
00239             setWidth( minWidth );
00240         else
00241             _width.unset();
00242         dirty();
00243     }
00244 }
00245 
00246 void
00247 Control::setVertFill( bool vfill, float minHeight ) {
00248     if ( vfill != _hfill || minHeight != _height.value() ) {
00249         _vfill = vfill;
00250         if ( vfill )
00251             setHeight( minHeight );
00252         else
00253             _height.unset();
00254         dirty();
00255     }
00256 }
00257 
00258 void
00259 Control::setForeColor( const osg::Vec4f& value ) {
00260     if ( value != _foreColor.value() ) {
00261         _foreColor = value;
00262         dirty();
00263     }
00264 }
00265 
00266 void
00267 Control::setBackColor( const osg::Vec4f& value ) {
00268     if ( value != _backColor.value() ) {
00269         _backColor = value;
00270         dirty();
00271     }
00272 }
00273 
00274 void
00275 Control::setActiveColor( const osg::Vec4f& value ) {
00276     if ( value != _activeColor.value() ) {
00277         _activeColor = value;
00278         if ( _active )
00279             dirty();
00280     }
00281 }
00282 
00283 void
00284 Control::addEventHandler( ControlEventHandler* handler )
00285 {
00286     _eventHandlers.push_back( handler );
00287 }
00288 
00289 bool
00290 Control::getParent( osg::ref_ptr<Control>& out ) const
00291 {
00292     out = _parent.get();
00293     return out.valid();
00294 }
00295 
00296 void
00297 Control::setActive( bool value ) {
00298     if ( value != _active ) {
00299         _active = value;
00300         if ( _activeColor.isSet() )
00301             dirty();
00302     }
00303 }
00304 
00305 void
00306 Control::dirty()
00307 {
00308     _dirty = true;
00309     osg::ref_ptr<Control> parent;
00310     if ( getParent( parent ) )
00311     {
00312         parent->dirty();
00313         parent.release();
00314     }
00315 }
00316 
00317 void
00318 Control::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
00319 {
00320     if ( visible() == true )
00321     {
00322         _renderSize.set( 
00323             width().value()  + padding().x(),
00324             height().value() + padding().y() );
00325 
00326         out_size.set(
00327             _renderSize.x() + margin().x(),
00328             _renderSize.y() + margin().y() );
00329     }
00330     else
00331     {
00332         out_size.set(0,0);
00333     }
00334 }
00335 
00336 void
00337 Control::calcPos(const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
00338 {
00339     if ( _x.isSet() )
00340     {
00341         _renderPos.x() = cursor.x() + margin().left() + padding().left() + *x();
00342     }
00343     else
00344     {
00345         if ( _halign == ALIGN_CENTER )
00346         {
00347             _renderPos.x() = cursor.x() + 0.5*(parentSize.x() - _renderSize.x());
00348         }
00349         else if ( _halign == ALIGN_RIGHT )
00350         {
00351             _renderPos.x() = cursor.x() + parentSize.x() - margin().right() - _renderSize.x() + padding().left();
00352         }
00353         else
00354         {
00355             _renderPos.x() = cursor.x() + margin().left() + padding().left();
00356         }
00357     }
00358 
00359     if ( _y.isSet() )
00360     {
00361         _renderPos.y() = cursor.y() + margin().top() + padding().top() + *y();
00362     }
00363     else
00364     {
00365         if ( _valign == ALIGN_CENTER )
00366         {
00367             //_renderPos.y() = cursor.y() + 0.5*(parentSize.y() - _renderSize.y());
00368             _renderPos.y() = cursor.y() + 0.5*parentSize.y() - 0.5*(_renderSize.y() - padding().y());
00369         }
00370         else if ( _valign == ALIGN_BOTTOM )
00371         {
00372             _renderPos.y() = cursor.y() + parentSize.y() - margin().bottom() - _renderSize.y() + padding().top();
00373         }
00374         else
00375         {
00376             _renderPos.y() = cursor.y() + margin().top() + padding().top();
00377         }
00378     }
00379 }
00380         
00381 bool
00382 Control::intersects( float x, float y ) const
00383 {
00384     return
00385         x >= _renderPos.x() - padding().left() && x <= _renderPos.x() - padding().left() + _renderSize.x() &&
00386         y >= _renderPos.y() - padding().top() && y <= _renderPos.y() - padding().top() + _renderSize.y();
00387 }
00388 
00389 void
00390 Control::draw(const ControlContext& cx, DrawableList& out )
00391 {
00392     // by default, rendering a Control directly results in a colored quad. Usually however
00393     // you will not render a Control directly, but rather one of its subclasses.
00394     if ( visible() == true )
00395     {
00396         if ( !(_backColor.isSet() && _backColor->a() == 0) && _renderSize.x() > 0 && _renderSize.y() > 0 )
00397         {
00398             float vph = cx._vp->height(); // - padding().bottom();
00399 
00400             _geom = new osg::Geometry();
00401 
00402             float rx = _renderPos.x() - padding().left();
00403             float ry = _renderPos.y() - padding().top();
00404 
00405             osg::Vec3Array* verts = new osg::Vec3Array(4);
00406             _geom->setVertexArray( verts );
00407             (*verts)[0].set( rx, vph - ry, 0 );
00408             (*verts)[1].set( rx, vph - ry - _renderSize.y(), 0 );
00409             (*verts)[2].set( rx + _renderSize.x(), vph - ry - _renderSize.y(), 0 );
00410             (*verts)[3].set( rx + _renderSize.x(), vph - ry, 0 );
00411             _geom->addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 4 ) );
00412 
00413             osg::Vec4Array* colors = new osg::Vec4Array(1);
00414             (*colors)[0] = _active && _activeColor.isSet() ? _activeColor.value() : _backColor.value();
00415             _geom->setColorArray( colors );
00416             _geom->setColorBinding( osg::Geometry::BIND_OVERALL );
00417 
00418             out.push_back( _geom.get() );
00419         }
00420 
00421         _dirty = false;
00422     }
00423 }
00424 
00425 bool
00426 Control::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
00427 {
00428     bool handled = false;    
00429 
00430     if ( _eventHandlers.size() > 0 )
00431     {    
00432         handled = true;
00433 
00434         if ( !_active )
00435         {
00436             if ( ea.getEventType() == osgGA::GUIEventAdapter::MOVE )
00437             {
00438                 cx._active.push( this );
00439             }
00440         }
00441         else 
00442         {            
00443             if ( ea.getEventType() == osgGA::GUIEventAdapter::RELEASE )
00444             {
00445                 for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
00446                 {
00447                     osg::Vec2f relXY( ea.getX() - _renderPos.x(), cx._vp->height() - ea.getY() - _renderPos.y() );
00448                     i->get()->onClick( this, relXY, ea.getButtonMask() );
00449                 }
00450             }
00451         }
00452     }
00453 
00454     return handled || _absorbEvents;
00455 }
00456 
00457 // ---------------------------------------------------------------------------
00458 
00459 // override osg Text to get at some of the internal properties
00460 struct LabelText : public osgText::Text
00461 {
00462     const osg::BoundingBox& getTextBB() const { return _textBB; }
00463     const osg::Matrix& getATMatrix(int contextID) const { return _autoTransformCache[contextID]._matrix; }
00464 };
00465 
00466 LabelControl::LabelControl(const std::string& text,
00467                            float fontSize,
00468                            const osg::Vec4f& foreColor)
00469 {
00470     setText( text );
00471     setFont( osgText::readFontFile( "arial.ttf" ) ); // TODO: cache this?
00472     setFontSize( fontSize );
00473     setBackColor( osg::Vec4f(0,0,0,0) );
00474     setForeColor( foreColor );
00475 }
00476 
00477 LabelControl::LabelControl(const std::string& text,
00478                            const osg::Vec4f& foreColor)
00479 {
00480     setText( text );
00481     setFont( osgText::readFontFile( "arial.ttf" ) ); // TODO: cache this?
00482     setFontSize( 18.0f );
00483     setBackColor( osg::Vec4f(0,0,0,0) );
00484     setForeColor( foreColor );
00485 }
00486 
00487 void
00488 LabelControl::setText( const std::string& value )
00489 {
00490     if ( value != _text ) {
00491         _text = value;
00492         dirty();
00493     }
00494 }
00495 
00496 void
00497 LabelControl::setFont( osgText::Font* value )
00498 {
00499     if ( value != _font.get() ) {
00500         _font = value;
00501         dirty();
00502     }
00503 }
00504 
00505 void
00506 LabelControl::setFontSize( float value )
00507 {
00508     if ( value != _fontSize ) {
00509         _fontSize = value;
00510         dirty();
00511     }
00512 }
00513 
00514 void
00515 LabelControl::setHaloColor( const osg::Vec4f& value )
00516 {
00517     if ( !_haloColor.isSet() || *_haloColor != value ) {
00518         _haloColor = value;
00519         dirty();
00520     }
00521 }
00522 
00523 void
00524 LabelControl::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
00525 {
00526     if ( visible() == true )
00527     {
00528         // we have to create the drawable during the layout pass so we can calculate its size.
00529         LabelText* t = new LabelText();
00530 
00531 #if 1
00532         // needs a special shader
00533         // todo: doesn't work. why?
00534         osg::Program* program = new osg::Program();
00535         program->addShader( new osg::Shader( osg::Shader::VERTEX, s_controlVertexShader ) );
00536         program->addShader( new osg::Shader( osg::Shader::FRAGMENT, s_labelControlFragmentShader ) );
00537         t->getOrCreateStateSet()->setAttributeAndModes( program, osg::StateAttribute::ON );
00538 #endif
00539 
00540         t->setText( _text );
00541         // yes, object coords. screen coords won't work becuase the bounding box will be wrong.
00542         t->setCharacterSizeMode( osgText::Text::OBJECT_COORDS );
00543         t->setCharacterSize( _fontSize );
00544         // always align to top. layout alignment gets calculated layer in Control::calcPos().
00545         t->setAlignment( osgText::Text::LEFT_TOP ); 
00546         t->setColor( foreColor().value() );
00547         if ( _font.valid() )
00548             t->setFont( _font.get() );
00549 
00550         if ( haloColor().isSet() )
00551         {
00552             t->setBackdropType( osgText::Text::OUTLINE );
00553             t->setBackdropOffset( 0.03 );
00554             t->setBackdropColor( haloColor().value() );
00555         }
00556 
00557         osg::BoundingBox bbox = t->getTextBB();
00558         if ( cx._viewContextID != ~0u )
00559         {
00560             //the Text's autoTransformCache matrix puts some mojo on the bounding box
00561             osg::Matrix m = t->getATMatrix( cx._viewContextID );
00562             _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() ) * m;
00563             _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() ) * m;
00564         }
00565         else
00566         {
00567             _bmin = osg::Vec3( bbox.xMin(), bbox.yMin(), bbox.zMin() );
00568             _bmax = osg::Vec3( bbox.xMax(), bbox.yMax(), bbox.zMax() );
00569         }
00570 
00571         _renderSize.set(
00572             (_bmax.x() - _bmin.x()) + padding().x(),
00573             (_bmax.y() - _bmin.y()) + padding().y() );
00574 
00575         _drawable = t;
00576 
00577         out_size.set(
00578             margin().x() + _renderSize.x(),
00579             margin().y() + _renderSize.y() );
00580     }
00581     else
00582     {
00583         out_size.set(0,0);
00584     }
00585 
00586     //_dirty = false;
00587 }
00588 
00589 void
00590 LabelControl::draw( const ControlContext& cx, DrawableList& out )
00591 {
00592     if ( _drawable.valid() && visible() == true )
00593     {
00594         Control::draw( cx, out );
00595 
00596         float vph = cx._vp->height(); // - padding().bottom();
00597 
00598         LabelText* t = static_cast<LabelText*>( _drawable.get() );
00599         osg::BoundingBox bbox = t->getTextBB();
00600         t->setPosition( osg::Vec3( _renderPos.x(), vph - _renderPos.y(), 0 ) );
00601         out.push_back( _drawable.get() );
00602     }
00603 }
00604 
00605 // ---------------------------------------------------------------------------
00606 
00607 ImageControl::ImageControl( osg::Image* image ) :
00608 _rotation( 0.0, Units::RADIANS ),
00609 _fixSizeForRot( false )
00610 {
00611     setImage( image );
00612 }
00613 
00614 void
00615 ImageControl::setImage( osg::Image* image )
00616 {
00617     if ( image != _image.get() ) {
00618         _image = image;
00619         dirty();
00620     }
00621 }
00622 
00623 void
00624 ImageControl::setRotation( const Angular& angle )
00625 {
00626     if ( angle != _rotation ) {
00627         _rotation = angle;
00628         dirty();
00629     }
00630 }
00631 
00632 void
00633 ImageControl::setFixSizeForRotation( bool value ) 
00634 {
00635     if ( _fixSizeForRot != value ) {
00636         _fixSizeForRot = value;
00637         dirty();
00638     }
00639 }
00640 
00641 void
00642 ImageControl::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
00643 {
00644     if ( visible() == true )
00645     {
00646         _renderSize.set( 0, 0 );
00647 
00648         //First try the explicit settings
00649         if (width().isSet() && height().isSet())
00650         {
00651             _renderSize.set(width().value(), height().value());
00652         }
00653         //Second try the size of the image itself
00654         else if (_image.valid())
00655         {
00656             _renderSize.set( _image->s(), _image->t() );
00657         }
00658         //Lastly just use the default values for width and height
00659         else
00660         {
00661             _renderSize.set( width().value(), height().value());
00662         }
00663 
00664         //if there's a rotation angle, rotate
00665         float rot = _fixSizeForRot ? osg::PI_4 : _rotation.as(Units::RADIANS);
00666         if ( rot != 0.0f )
00667         {
00668             calculateRotatedSize( 
00669                 _renderSize.x(), _renderSize.y(), 
00670                 rot,
00671                 _renderSize.x(), _renderSize.y() );
00672         }
00673         
00674         out_size.set(
00675             margin().left() + margin().right() + _renderSize.x(),
00676             margin().top() + margin().bottom() + _renderSize.y() );
00677 
00678         //_dirty = false;
00679     }
00680     else
00681     {
00682         out_size.set(0,0);
00683     }
00684 }
00685 
00686 #undef IMAGECONTROL_TEXRECT
00687 
00688 void
00689 ImageControl::draw( const ControlContext& cx, DrawableList& out )
00690 {
00691     if ( visible() == true && _image.valid() )
00692     {
00693         //TODO: this is not precisely correct..images get deformed slightly..
00694         osg::Geometry* g = new osg::Geometry();
00695 
00696         float rx = osg::round( _renderPos.x() );
00697         float ry = osg::round( _renderPos.y() );
00698         float vph = cx._vp->height();
00699 
00700         osg::Vec3Array* verts = new osg::Vec3Array(4);
00701         g->setVertexArray( verts );
00702 
00703         if ( _rotation.as(Units::RADIANS) != 0.0f || _fixSizeForRot == true )
00704         {
00705             osg::Vec2f rc( rx+_renderSize.x()/2, (vph-ry)-_renderSize.y()/2 );
00706             float ra = osg::PI - _rotation.as(Units::RADIANS);
00707 
00708             rx += 0.5*_renderSize.x() - 0.5*(float)_image->s();
00709             ry += 0.5*_renderSize.y() - 0.5*(float)_image->t();
00710 
00711             rot( rx, vph-ry, rc, ra, (*verts)[0] );
00712             rot( rx, vph-ry-_image->t(), rc, ra, (*verts)[1] );
00713             rot( rx+_image->s(), vph-ry-_image->t(), rc, ra, (*verts)[2] );
00714             rot( rx+_image->s(), vph-ry, rc, ra, (*verts)[3] );
00715         }
00716         else
00717         {
00718             (*verts)[0].set( rx, vph - ry, 0 );
00719             (*verts)[1].set( rx, vph - ry - _renderSize.y(), 0 );
00720             (*verts)[2].set( rx + _renderSize.x(), vph - ry - _renderSize.y(), 0 );
00721             (*verts)[3].set( rx + _renderSize.x(), vph - ry, 0 );
00722         }
00723 
00724         g->addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 0, 4 ) );
00725 
00726         osg::Vec4Array* c = new osg::Vec4Array(1);
00727         (*c)[0] = osg::Vec4f(1,1,1,1);
00728         g->setColorArray( c );
00729         g->setColorBinding( osg::Geometry::BIND_OVERALL );
00730 
00731         bool flip = _image->getOrigin()==osg::Image::TOP_LEFT;
00732 
00733         osg::Vec2Array* t = new osg::Vec2Array(4);
00734 
00735 #ifdef IMAGECONTROL_TEXRECT
00736 
00737         (*t)[0].set( 0, flip? 0: _image->t()-1 );
00738         (*t)[1].set( 0, flip? _image->t()-1: 0 );
00739         (*t)[2].set( _image->s()-1, flip? _image->t()-1: 0 );
00740         (*t)[3].set( _image->s()-1, flip? 0: _image->t()-1 );
00741         osg::TextureRectangle* tex = new osg::TextureRectangle( _image.get() );
00742 
00743 #else
00744 
00745         (*t)[0].set( 0, flip? 0 : 1 );
00746         (*t)[1].set( 0, flip? 1 : 0 );
00747         (*t)[2].set( 1, flip? 1 : 0 );
00748         (*t)[3].set( 1, flip? 0 : 1 );
00749         osg::Texture2D* tex = new osg::Texture2D( _image.get() );
00750 #endif
00751 
00752         g->setTexCoordArray( 0, t );
00753 
00754         tex->setResizeNonPowerOfTwoHint(false);
00755 
00756         tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::NEAREST );
00757         tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
00758         g->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex, osg::StateAttribute::ON );
00759 
00760         osg::TexEnv* texenv = new osg::TexEnv( osg::TexEnv::MODULATE );
00761         g->getStateSet()->setTextureAttributeAndModes( 0, texenv, osg::StateAttribute::ON );
00762         
00763 #ifndef IMAGECONTROL_TEXRECT
00764         osg::Program* program = new osg::Program();
00765         program->addShader( new osg::Shader( osg::Shader::VERTEX, s_controlVertexShader ) );
00766         program->addShader( new osg::Shader( osg::Shader::FRAGMENT, s_imageControlFragmentShader ) );
00767         g->getStateSet()->setAttributeAndModes( program, osg::StateAttribute::ON );
00768 #endif
00769 
00770         out.push_back( g );
00771 
00772         _dirty = false;
00773     }
00774 }
00775 
00776 // ---------------------------------------------------------------------------
00777 
00778 HSliderControl::HSliderControl( float min, float max, float value ) :
00779 _min(min),
00780 _max(max),
00781 _value(value)
00782 {
00783    if ( _max <= _min )
00784        _max = _min+1.0f;
00785    if ( _value < _min )
00786        _value = _min;
00787    if ( _value > _max )
00788        _value = _max;
00789 
00790    setHorizFill( true );
00791 }
00792 
00793 void
00794 HSliderControl::fireValueChanged()
00795 {
00796     for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
00797     {
00798         i->get()->onValueChanged( this, _value );
00799     }
00800 }
00801 
00802 void
00803 HSliderControl::setValue( float value, bool notify )
00804 {
00805     value = osg::clampBetween( value, _min, _max );
00806     if ( value != _value )
00807     {
00808         _value = value;
00809         if ( notify )
00810             fireValueChanged();
00811         dirty();
00812     }
00813 }
00814 
00815 void
00816 HSliderControl::setMin( float min, bool notify )
00817 {
00818     if ( min != _min )
00819     {
00820         _min = min;
00821         if ( _min >= _max )
00822             _max = _min+1.0f;
00823 
00824         if ( _value < _min || _value > _max ) 
00825         {
00826             _value = _min;
00827             if ( notify )
00828                 fireValueChanged();
00829         }
00830         dirty();
00831     }
00832 }
00833 
00834 void
00835 HSliderControl::setMax( float max, bool notify )
00836 {
00837     if ( max != _max )
00838     {
00839         _max = max;
00840         if ( _max <= _min )
00841             _max = _min+1.0f;
00842 
00843         if ( _value < _min || _value > _max )
00844         {
00845             _value = _max;
00846             if ( notify )
00847                 fireValueChanged();
00848         }
00849         dirty();
00850     }
00851 }
00852 
00853 void
00854 HSliderControl::draw( const ControlContext& cx, DrawableList& out )
00855 {
00856     Control::draw( cx, out );
00857 
00858     if ( visible() == true )
00859     {
00860         osg::ref_ptr<osg::Geometry> g = new osg::Geometry();
00861 
00862         float rx = osg::round( _renderPos.x() );
00863         float ry = osg::round( _renderPos.y() );
00864         float rw = osg::round( _renderSize.x() - padding().x() );
00865         float rh = osg::round( _renderSize.y() - padding().y() );
00866 
00867         if ( rw > 0.0f && rh > 0.0f )
00868         {
00869             float vph = cx._vp->height();
00870 
00871             osg::Vec3Array* verts = new osg::Vec3Array(8);
00872             g->setVertexArray( verts );
00873 
00874             (*verts)[0].set( rx, vph - ry, 0 );
00875             (*verts)[1].set( rx + rw, vph - ry, 0 );
00876             (*verts)[2].set( rx + rw, vph - (ry + rh), 0 );
00877             (*verts)[3].set( rx, vph - (ry + rh), 0 );
00878             g->addPrimitiveSet( new osg::DrawArrays( GL_LINE_LOOP, 0, 4 ) );
00879 
00880             float hx = rx + rw * ( (_value-_min)/(_max-_min) );
00881 
00882             (*verts)[4].set( hx-4, vph - ry + 3, 0 );
00883             (*verts)[5].set( hx+4, vph - ry + 3, 0 );
00884             (*verts)[6].set( hx+4, vph - (ry + rh + 3), 0 );
00885             (*verts)[7].set( hx-4, vph - (ry + rh + 3), 0 );
00886             g->addPrimitiveSet( new osg::DrawArrays( GL_QUADS, 4, 4 ) );
00887 
00888             osg::Vec4Array* c = new osg::Vec4Array(1);
00889             (*c)[0] = *foreColor();
00890             g->setColorArray( c );
00891             g->setColorBinding( osg::Geometry::BIND_OVERALL );
00892 
00893             out.push_back( g.get() );
00894         }
00895     }
00896 }
00897 
00898 bool
00899 HSliderControl::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
00900 {
00901     if ( ea.getEventType() == osgGA::GUIEventAdapter::DRAG )
00902     {
00903         float relX = ea.getX() - _renderPos.x();
00904 
00905         setValue( _min + (_max-_min) * ( relX/_renderSize.x() ) );
00906         return true;
00907     }
00908     return Control::handle( ea, aa, cx );
00909 }
00910 
00911 // ---------------------------------------------------------------------------
00912 
00913 CheckBoxControl::CheckBoxControl( bool value ) :
00914 _value( value )
00915 {
00916     setWidth( 16 );
00917     setHeight( 16 );
00918 }
00919 
00920 CheckBoxControl::CheckBoxControl( bool value, ControlEventHandler* handler ) :
00921 _value( value )
00922 {
00923     this->addEventHandler( handler );
00924     setWidth( 16 );
00925     setHeight( 16 );
00926 }
00927 
00928 void
00929 CheckBoxControl::fireValueChanged()
00930 {
00931     for( ControlEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i )
00932     {
00933         i->get()->onValueChanged( this, _value );
00934     }
00935 }
00936 
00937 void
00938 CheckBoxControl::setValue( bool value )
00939 {
00940     if ( value != _value )
00941     {
00942         _value = value;
00943         fireValueChanged();
00944         dirty();
00945     }
00946 }
00947 
00948 void
00949 CheckBoxControl::draw( const ControlContext& cx, DrawableList& out )
00950 {
00951     Control::draw( cx, out );
00952 
00953     if ( visible() == true )
00954     {
00955         osg::Geometry* g = new osg::Geometry();
00956 
00957         float rx = osg::round( _renderPos.x() );
00958         float ry = osg::round( _renderPos.y() );
00959         float rw = _renderSize.x() - padding().x();
00960         float rh = _renderSize.y() - padding().y();
00961         float vph = cx._vp->height(); // - padding().bottom();
00962 
00963         osg::Vec3Array* verts = new osg::Vec3Array(4);
00964         g->setVertexArray( verts );
00965 
00966         (*verts)[0].set( rx, vph - ry, 0 );
00967         (*verts)[1].set( rx + rw, vph - ry, 0 );
00968         (*verts)[2].set( rx + rw, vph - (ry + rh), 0 );
00969         (*verts)[3].set( rx, vph - (ry + rh), 0 );
00970 
00971         g->addPrimitiveSet( new osg::DrawArrays( GL_LINE_LOOP, 0, 4 ) );
00972 
00973         if ( _value )
00974         {
00975             osg::DrawElementsUByte* e = new osg::DrawElementsUByte( GL_LINES );
00976             e->push_back( 0 );
00977             e->push_back( 2 );
00978             e->push_back( 1 );
00979             e->push_back( 3 );
00980             g->addPrimitiveSet( e );
00981         }
00982 
00983         osg::Vec4Array* c = new osg::Vec4Array(1);
00984         (*c)[0] = *foreColor();
00985         g->setColorArray( c );
00986         g->setColorBinding( osg::Geometry::BIND_OVERALL );
00987 
00988         out.push_back( g );
00989     }
00990 }
00991 
00992 bool
00993 CheckBoxControl::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
00994 {
00995     if ( ea.getEventType() == osgGA::GUIEventAdapter::PUSH )
00996     {
00997         setValue( !_value );
00998         return true;
00999     }
01000     return Control::handle( ea, aa, cx );
01001 }
01002 
01003 // ---------------------------------------------------------------------------
01004 
01005 Frame::Frame()
01006 {
01007     setPadding( 0 );
01008 }
01009 
01010 void
01011 Frame::calcPos(const ControlContext& context, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
01012 {
01013     _renderPos = cursor;
01014 }
01015 
01016 void
01017 Frame::draw( const ControlContext& cx, DrawableList& out )
01018 {
01019     if ( !getImage() || getImage()->s() != _renderSize.x() || getImage()->t() != _renderSize.y() )
01020     {
01021         // a simple colored border frame
01022         osg::ref_ptr<Geometry> geom = new Ring();
01023         geom->push_back( osg::Vec3d( 0, 0, 0 ) );
01024         geom->push_back( osg::Vec3d( _renderSize.x()-1, 0, 0 ) );
01025         geom->push_back( osg::Vec3d( _renderSize.x()-1, _renderSize.y()-1, 0 ) );
01026         geom->push_back( osg::Vec3d( 0, _renderSize.y()-1, 0 ) );
01027 
01028         Style style;
01029         LineSymbol* line = style.getOrCreate<LineSymbol>();
01030         line->stroke()->color() = Color::White;
01031         line->stroke()->width() = 2.5f;
01032         GeometryRasterizer ras( (int)_renderSize.x(), (int)_renderSize.y(), style );
01033         ras.draw( geom.get() );
01034 
01035         osg::Image* image = ras.finalize();
01036         const_cast<Frame*>(this)->setImage( image );
01037     }
01038 
01039     Control::draw( cx, out );       // draws the background
01040     ImageControl::draw( cx, out );  // draws the border
01041 }
01042 
01043 // ---------------------------------------------------------------------------
01044 
01045 RoundedFrame::RoundedFrame()
01046 {
01047     //nop
01048 }
01049 
01050 void
01051 RoundedFrame::draw( const ControlContext& cx, DrawableList& out )
01052 {
01053     if ( Geometry::hasBufferOperation() )
01054     {
01055         if ( !getImage() || getImage()->s() != _renderSize.x() || getImage()->t() != _renderSize.y() )
01056         {
01057             // create a rounded rectangle by buffering a rectangle. "buffer" value affects how rounded
01058             // the corners are.
01059             float buffer = Geometry::hasBufferOperation() ? 10.0f : 0.0f;
01060 
01061             osg::ref_ptr<Geometry> geom = new Polygon();
01062             geom->push_back( osg::Vec3d( buffer, buffer, 0 ) );
01063             geom->push_back( osg::Vec3d( _renderSize.x()-1-buffer, buffer, 0 ) );
01064             geom->push_back( osg::Vec3d( _renderSize.x()-1-buffer, _renderSize.y()-1-buffer, 0 ) );
01065             geom->push_back( osg::Vec3d( buffer, _renderSize.y()-1-buffer, 0 ) );
01066 
01067             BufferParameters bp;
01068             bp._capStyle = BufferParameters::CAP_ROUND;
01069             geom->buffer( buffer-1.0f, geom, bp );
01070 
01071             GeometryRasterizer ras( (int)_renderSize.x(), (int)_renderSize.y() );
01072             ras.draw( geom.get(), backColor().value() );
01073 
01074             osg::Image* image = ras.finalize();
01075             const_cast<RoundedFrame*>(this)->setImage( image );
01076         }
01077 
01078         ImageControl::draw( cx, out );
01079     }
01080     else
01081     {
01082         // fallback: draw a non-rounded frame.
01083         Frame::draw( cx, out );
01084     }
01085 }
01086 
01087 // ---------------------------------------------------------------------------
01088 
01089 Container::Container() :
01090 _spacing( 1 )
01091 {
01092     //nop
01093 }
01094 
01095 void
01096 Container::setFrame( Frame* frame )
01097 {
01098     if ( frame != _frame.get() ) {
01099         _frame = frame;
01100         dirty();
01101     }
01102 }
01103 
01104 void
01105 Container::setChildSpacing( float value )
01106 {
01107     if ( value != _spacing ) {
01108         _spacing = value;
01109         dirty();
01110     }
01111 }
01112 
01113 void
01114 Container::setChildHorizAlign( Alignment value )
01115 {
01116     if ( !_childhalign.isSet() || _childhalign != value )
01117     {
01118         _childhalign = value;
01119         applyChildAligns();
01120     }
01121 }
01122 
01123 void
01124 Container::setChildVertAlign( Alignment value )
01125 {
01126     if ( !_childvalign.isSet() || _childvalign != value )
01127     {
01128         _childvalign = value;
01129         applyChildAligns();
01130     }
01131 }
01132 
01133 void
01134 Container::applyChildAligns()
01135 {
01136     if ( _childhalign.isSet() || _childvalign.isSet() )
01137     {
01138         for( ControlList::iterator i = mutable_children().begin(); i != mutable_children().end(); ++i )
01139         {
01140             Control* child = i->get();
01141 
01142             if ( _childvalign.isSet() && !child->vertAlign().isSet() )
01143                 child->setVertAlign( *_childvalign );
01144 
01145             if ( _childhalign.isSet() && !child->horizAlign().isSet() )
01146                 child->setHorizAlign( *_childhalign );
01147         }
01148 
01149         dirty();
01150     }
01151 }
01152 
01153 void
01154 Container::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
01155 {
01156     if ( visible() == true )
01157     {
01158         if ( _frame.valid() )
01159         {
01160             _frame->setWidth( _renderSize.x() );
01161             _frame->setHeight( _renderSize.y() );
01162 
01163             osg::Vec2f dummy;
01164             _frame->calcSize( cx, dummy );
01165         }
01166 
01167         // no need to set the output vars.
01168 
01169         //_dirty = false;
01170     }
01171 }
01172 
01173 void
01174 Container::calcFill(const ControlContext& cx)
01175 {
01176     for( ControlList::iterator i = mutable_children().begin(); i != mutable_children().end(); ++i )
01177     {
01178         Control* child = i->get();
01179         child->calcFill( cx );
01180     }
01181 }
01182 
01183 void
01184 Container::calcPos(const ControlContext& context, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
01185 {
01186     Control::calcPos( context, cursor, parentSize );
01187 
01188     // process the frame.. it's not a child of the container
01189     if ( visible() == true && _frame.valid() )
01190     {
01191         _frame->calcPos( context, _renderPos - padding().offset(), parentSize );
01192     }
01193 }
01194 
01195 void
01196 Container::draw( const ControlContext& cx, DrawableList& out )
01197 {
01198     if ( visible() == true )
01199     {
01200         Control::draw( cx, out );
01201         if ( _frame.valid() )
01202             _frame->draw( cx, out );
01203     }
01204 }
01205 
01206 bool
01207 Container::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, ControlContext& cx )
01208 {
01209     bool handled = false;
01210     for( ControlList::const_reverse_iterator i = children().rbegin(); i != children().rend(); ++i )
01211     {
01212         Control* child = i->get();
01213         if (ea.getEventType() == osgGA::GUIEventAdapter::FRAME || child->intersects( ea.getX(), cx._vp->height() - ea.getY() ) )
01214             handled = child->handle( ea, aa, cx );
01215         if ( handled )
01216             break;
01217     }
01218 
01219     return handled ? handled : Control::handle( ea, aa, cx );
01220 }
01221 
01222 void
01223 Container::addControls( const ControlVector& controls )
01224 {
01225     for( ControlVector::const_iterator i = controls.begin(); i != controls.end(); ++i )
01226     {
01227         addControl( i->get() );
01228     }
01229 }
01230 
01231 // ---------------------------------------------------------------------------
01232 
01233 VBox::VBox()
01234 {
01235     //nop
01236 }
01237 
01238 void
01239 VBox::addControl( Control* control, int index )
01240 {
01241     if ( index < 0 )
01242         _controls.push_back( control );
01243     else
01244         _controls.insert( _controls.begin() + osg::minimum(index,(int)_controls.size()-1), control );
01245     control->setParent( this );
01246 
01247     applyChildAligns();
01248     dirty();
01249 }
01250 
01251 void
01252 VBox::clearControls()
01253 {
01254     _controls.clear();
01255     dirty();
01256 }
01257 
01258 void
01259 VBox::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
01260 {
01261     if ( visible() == true )
01262     {
01263         _renderSize.set( 0, 0 );
01264 
01265         // collect all the members, growing the container size vertically
01266         for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01267         {
01268             Control* child = i->get();
01269             osg::Vec2f childSize;
01270             bool first = i == _controls.begin();
01271 
01272             child->calcSize( cx, childSize );
01273 
01274             _renderSize.x() = osg::maximum( _renderSize.x(), childSize.x() );
01275             _renderSize.y() += first ? childSize.y() : childSpacing() + childSize.y();
01276         }
01277 
01278         _renderSize.set(
01279             _renderSize.x() + padding().x(),
01280             _renderSize.y() + padding().y() );
01281 
01282         // process fills:
01283 
01284 
01285         out_size.set(
01286             _renderSize.x() + margin().x(),
01287             _renderSize.y() + margin().y() );
01288 
01289         Container::calcSize( cx, out_size );
01290     }
01291     else
01292     {
01293         out_size.set(0,0);
01294     }
01295 }
01296 
01297 void
01298 VBox::calcFill(const ControlContext& cx)
01299 {
01300     //Container::calcFill( cx );
01301 
01302     float used_x = padding().x();
01303     float used_y = padding().y() - childSpacing();
01304 
01305     Control* hc = 0L;
01306     Control* vc = 0L;
01307 
01308     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end() && (!hc || !vc); ++i )
01309     {
01310         Control* child = i->get();
01311 
01312         used_y += child->margin().y() + childSpacing();
01313         if ( !hc && child->horizFill() )
01314         {
01315             hc = child;
01316             used_x += child->margin().x();
01317         }
01318 
01319         if ( !vc && child->vertFill() )
01320             vc = child;
01321         else
01322             used_y += child->renderSize().y();
01323     }
01324 
01325     if ( hc && renderWidth(hc) < (_renderSize.x() - used_x) )
01326         renderWidth(hc) = _renderSize.x() - used_x;
01327 
01328     if ( vc && renderHeight(vc) < (_renderSize.y() - used_y) )
01329         renderHeight(vc) = _renderSize.y() - used_y;
01330    
01331     Container::calcFill( cx );
01332 }
01333 
01334 void
01335 VBox::calcPos(const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
01336 {
01337     Container::calcPos( cx, cursor, parentSize );
01338 
01339     osg::Vec2f childCursor = _renderPos;
01340 
01341     osg::Vec2f renderArea = _renderSize - padding().size();
01342 
01343     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01344     {
01345         Control* child = i->get();
01346         child->calcPos( cx, childCursor, renderArea ); // GW1
01347         float deltaY = child->margin().top() + child->renderSize().y() + child->margin().bottom() + childSpacing();
01348         childCursor.y() += deltaY;
01349         renderArea.y() -= deltaY;
01350     }
01351 }
01352 
01353 void
01354 VBox::draw( const ControlContext& cx, DrawableList& out )
01355 {
01356     if ( visible() == true )
01357     {
01358         Container::draw( cx, out );
01359         for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01360             i->get()->draw( cx, out );
01361     }
01362 }
01363 
01364 // ---------------------------------------------------------------------------
01365 
01366 HBox::HBox()
01367 {
01368     //nop
01369 }
01370 
01371 void
01372 HBox::addControl( Control* control, int index )
01373 {
01374     if ( index < 0 )
01375         _controls.push_back( control );
01376     else
01377         _controls.insert( _controls.begin() + osg::minimum(index,(int)_controls.size()-1), control );
01378     
01379     control->setParent( this );
01380     applyChildAligns();
01381 
01382     dirty();
01383 }
01384 
01385 void
01386 HBox::clearControls()
01387 {
01388     _controls.clear();
01389     dirty();
01390 }
01391 
01392 void
01393 HBox::calcSize(const ControlContext& cx, osg::Vec2f& out_size)
01394 {
01395     if ( visible() == true )
01396     {
01397         _renderSize.set( 0, 0 );
01398 
01399         // collect all the members, growing the container is its orientation.
01400         for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01401         {
01402             Control* child = i->get();
01403             osg::Vec2f childSize;
01404             bool first = i == _controls.begin();
01405 
01406             child->calcSize( cx, childSize );
01407 
01408             _renderSize.x() += first ? childSize.x() : childSpacing() + childSize.x();
01409             _renderSize.y() = osg::maximum( _renderSize.y(), childSize.y() );
01410         }
01411 
01412         _renderSize.set(
01413             _renderSize.x() + padding().x(),
01414             _renderSize.y() + padding().y() );
01415 
01416         out_size.set(
01417             _renderSize.x() + margin().x(),
01418             _renderSize.y() + margin().y() );
01419 
01420         Container::calcSize( cx, out_size );
01421     }
01422 }
01423 
01424 void
01425 HBox::calcFill(const ControlContext& cx)
01426 {
01427     //Container::calcFill( cx );
01428 
01429     float used_x = padding().x() - childSpacing();
01430     float used_y = padding().y();
01431 
01432     Control* hc = 0L;
01433     Control* vc = 0L;
01434 
01435     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end() && (!hc || !vc); ++i )
01436     {
01437         Control* child = i->get();
01438 
01439         //child->calcFill(cx);
01440 
01441         used_x += child->margin().x() + childSpacing();
01442         if ( !hc && child->horizFill() )
01443             hc = child;
01444         else
01445             used_x += child->renderSize().x();
01446 
01447         if ( !vc && child->vertFill() )
01448         {
01449             vc = child;
01450             used_y += child->margin().y();
01451         }
01452     }
01453 
01454     if ( hc && renderWidth(hc) < (_renderSize.x() - used_x) )
01455         renderWidth(hc) = _renderSize.x() - used_x;
01456 
01457     if ( vc && renderHeight(vc) < (_renderSize.y() - used_y) )
01458         renderHeight(vc) = _renderSize.y() - used_y;
01459    
01460     Container::calcFill( cx );
01461 }
01462 
01463 void
01464 HBox::calcPos(const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize)
01465 {
01466     Container::calcPos( cx, cursor, parentSize );
01467 
01468     osg::Vec2f childCursor = _renderPos;
01469 
01470 #if 0
01471     // collect all the members
01472     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01473     {
01474         Control* child = i->get();
01475         child->calcPos( cx, childCursor, _renderSize - padding().size() ); // GW1
01476         childCursor.x() += child->margin().left() + child->renderSize().x() + child->margin().right() + childSpacing();
01477     }
01478 #endif
01479 
01480     osg::Vec2f renderArea = _renderSize - padding().size();
01481     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01482     {
01483         Control* child = i->get();
01484         child->calcPos( cx, childCursor, renderArea );
01485         float deltaX = child->margin().left() + child->renderSize().x() + child->margin().right() + childSpacing();
01486         childCursor.x() += deltaX;
01487         renderArea.x() -= deltaX;        
01488     }
01489 }
01490 
01491 void
01492 HBox::draw( const ControlContext& cx, DrawableList& out ) 
01493 {
01494     Container::draw( cx, out );
01495     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
01496         i->get()->draw( cx, out );
01497 }
01498 
01499 // ---------------------------------------------------------------------------
01500 
01501 Grid::Grid()
01502 {
01503     //nop
01504 }
01505 
01506 void
01507 Grid::setControl( int col, int row, Control* child )
01508 {
01509     if ( !child ) return;
01510 
01511     expandToInclude( col, row );
01512 
01513     Control* oldControl = cell( col, row ).get();
01514     if ( oldControl ) {
01515         ControlList::iterator i = std::find( _children.begin(), _children.end(), oldControl );
01516         if ( i != _children.end() ) 
01517             _children.erase( i );
01518     }
01519 
01520     cell( col, row ) = child;
01521     _children.push_back( child );
01522 
01523     child->setParent( this );
01524     applyChildAligns();
01525 
01526     dirty();
01527 }
01528 
01529 osg::ref_ptr<Control>&
01530 Grid::cell(int col, int row)
01531 {
01532     return _rows[row][col];
01533 }
01534 
01535 void
01536 Grid::expandToInclude( int col, int row )
01537 {
01538     while( (int)_rows.size() <= row )
01539         _rows.push_back( Row() );
01540 
01541     int maxCol = col;
01542     for( RowVector::iterator i = _rows.begin(); i != _rows.end(); ++i ) {
01543         if ( ((int)i->size())-1 > maxCol )
01544             maxCol = ((int)i->size())-1;
01545     }
01546 
01547     for( RowVector::iterator i = _rows.begin(); i != _rows.end(); ++i ) {
01548         Row& row = *i;
01549         while( (int)row.size() <= maxCol )
01550             row.push_back( 0L );
01551     }
01552 }
01553 
01554 void
01555 Grid::addControl( Control* control, int index )
01556 {
01557     // creates a new row and puts the control in its first column
01558     setControl( 0, _rows.size(), control );
01559 }
01560 
01561 void
01562 Grid::addControls( const ControlVector& controls )
01563 {
01564     unsigned row = _rows.size();
01565     unsigned col = 0;
01566     for( ControlVector::const_iterator i = controls.begin(); i != controls.end(); ++i, ++col )
01567     {
01568         if ( i->valid() )
01569         {
01570             setControl( col, row, i->get() );
01571         }
01572     }
01573 }
01574 
01575 void
01576 Grid::clearControls()
01577 {
01578     _rows.clear();
01579     _children.clear();
01580     _rowHeights.clear();
01581     _colWidths.clear();
01582     dirty();
01583 }
01584 
01585 void
01586 Grid::calcSize( const ControlContext& cx, osg::Vec2f& out_size )
01587 {
01588     if ( visible() == true )
01589     {
01590         _renderSize.set( 0, 0 );
01591 
01592         int numRows = _rows.size();
01593         int numCols = numRows > 0 ? _rows[0].size() : 0;
01594 
01595         _rowHeights.assign( numRows, 0.0f );
01596         _colWidths.assign( numCols, 0.0f );
01597 
01598         if ( numRows > 0 && numCols > 0 )
01599         {
01600             for( int r=0; r<numRows; ++r )
01601             { 
01602                 //for( int c=0; c<_rows[r].size(); ++c )
01603                 for( int c=0; c<numCols; ++c )
01604                 {
01605                     Control* child = cell(c,r).get();
01606                     if ( child )
01607                     {
01608                         osg::Vec2f childSize;
01609                         child->calcSize( cx, childSize );
01610 
01611                         if ( childSize.x() > _colWidths[c] )
01612                             _colWidths[c] = childSize.x();
01613                         if ( childSize.y() > _rowHeights[r] )
01614                             _rowHeights[r] = childSize.y();
01615                     }
01616                 }
01617             }
01618 
01619             for( int c=0; c<numCols; ++c )
01620                 _renderSize.x() += _colWidths[c];
01621             _renderSize.x() += childSpacing() * (numCols-1);
01622 
01623             for( int r=0; r<numRows; ++r )
01624                 _renderSize.y() += _rowHeights[r];
01625             _renderSize.y() += childSpacing() * (numRows-1);
01626         }
01627         
01628         _renderSize.set(
01629             _renderSize.x() + padding().x(),
01630             _renderSize.y() + padding().y() );
01631 
01632         out_size.set(
01633             _renderSize.x() + margin().x(),
01634             _renderSize.y() + margin().y() );
01635 
01636         Container::calcSize( cx, out_size );
01637     }
01638 }
01639 
01640 void
01641 Grid::calcFill(const ControlContext& cx)
01642 {
01643     Container::calcFill( cx );
01644 
01645     int numRows = _rows.size();
01646     int numCols = numRows > 0 ? _rows[0].size() : 0;
01647 
01648     for( int r=0; r<numRows; ++r )
01649     {
01650         for( int c=0; c<numCols; ++c ) //<_rows[r].size(); ++c )
01651         {
01652             Control* child = cell(c,r).get();
01653 
01654             if ( child )
01655             {
01656                 if ( child->horizFill() )
01657                     renderWidth(child) = _colWidths[c] - child->margin().x();
01658                 if ( child->vertFill() )
01659                     renderHeight(child) = _rowHeights[r] - child->margin().y();
01660             }
01661         }
01662     }
01663 
01664     //Container::calcFill( cx );
01665 }
01666 
01667 void
01668 Grid::calcPos( const ControlContext& cx, const osg::Vec2f& cursor, const osg::Vec2f& parentSize )
01669 {
01670     Container::calcPos( cx, cursor, parentSize );
01671 
01672     int numRows = _rows.size();
01673     int numCols = numRows > 0 ? _rows[0].size() : 0;
01674 
01675     osg::Vec2f childCursor = _renderPos;
01676 
01677     for( int r=0; r<numRows; ++r )
01678     {
01679         for( int c=0; c<numCols; ++c )
01680         {
01681             Control* child = cell(c,r).get();
01682             if ( child )
01683             {
01684                 osg::Vec2f cellSize( _colWidths[c], _rowHeights[r] );
01685                 child->calcPos( cx, childCursor, cellSize );
01686             }
01687             childCursor.x() += _colWidths[c] + childSpacing();
01688         }
01689         childCursor.x() = _renderPos.x();
01690         childCursor.y() += _rowHeights[r] + childSpacing();
01691     }
01692 }
01693 
01694 void
01695 Grid::draw( const ControlContext& cx, DrawableList& out )
01696 {
01697     if (visible() == true)
01698     {
01699         Container::draw( cx, out );
01700         for( ControlList::const_iterator i = _children.begin(); i != _children.end(); ++i )
01701             i->get()->draw( cx, out );
01702     }
01703 }
01704 
01705 // ---------------------------------------------------------------------------
01706 
01707 namespace osgEarth { namespace Util { namespace Controls
01708 {
01709     // This handler keeps an eye on the viewport and informs the control surface when it changes.
01710     // We need this info since controls position from the upper-left corner.
01711     struct ViewportHandler : public osgGA::GUIEventHandler
01712     {
01713         ViewportHandler( ControlCanvas* cs ) : _cs(cs), _width(0), _height(0), _first(true) { }
01714 
01715         bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
01716         {
01717             if ( ea.getEventType() == osgGA::GUIEventAdapter::RESIZE || _first )
01718             {
01719                 osg::Camera* cam = aa.asView()->getCamera();
01720                 if ( cam && cam->getViewport() )
01721                 {
01722                     const osg::Viewport* vp = cam->getViewport();
01723                     if ( _first || vp->width() != _width || vp->height() != _height )
01724                     {
01725                         _cs->setProjectionMatrix(osg::Matrix::ortho2D( 0, vp->width()-1, 0, vp->height()-1 ) );
01726 
01727                         ControlContext cx;
01728                         cx._view = aa.asView();
01729                         cx._vp = new osg::Viewport( 0, 0, vp->width(), vp->height() );
01730                         cx._viewContextID = aa.asView()->getCamera()->getGraphicsContext()->getState()->getContextID();
01731                         _cs->setControlContext( cx );
01732 
01733                         _width  = (int)vp->width();
01734                         _height = (int)vp->height();
01735                     }
01736                     if ( vp->width() != 0 && vp->height() != 0 )
01737                     {
01738                         _first = false;
01739                     }
01740                 }
01741             }
01742             return false;
01743         }
01744         ControlCanvas* _cs;
01745         int _width, _height;
01746         bool _first;
01747     };
01748 
01749     struct ControlCanvasEventHandler : public osgGA::GUIEventHandler
01750     {
01751         ControlCanvasEventHandler( ControlCanvas* cs ) : _cs(cs) { }
01752 
01753         bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
01754         {
01755             return _cs->handle( ea, aa );
01756         }
01757 
01758         ControlCanvas* _cs;
01759     };
01760 
01761     // This callback installs a control canvas under a view.
01762     struct CanvasInstaller : public osg::NodeCallback
01763     {
01764         CanvasInstaller( ControlCanvas* canvas, osg::Camera* camera )
01765             : _canvas( canvas )
01766         {
01767             _oldCallback = camera->getUpdateCallback();
01768             camera->setUpdateCallback( this );
01769         }
01770         
01771         void operator()( osg::Node* node, osg::NodeVisitor* nv )
01772         {
01773             osg::Camera* camera = static_cast<osg::Camera*>(node);
01774             osgViewer::View* view2 = dynamic_cast<osgViewer::View*>(camera->getView());
01775             install( view2, _canvas.get() );
01776             camera->setUpdateCallback( _oldCallback.get() );
01777         }
01778 
01779         static void install( osgViewer::View* view2, ControlCanvas* canvas )
01780         {
01781             osg::Node* node = view2->getSceneData();
01782             osg::Group* group = new osg::Group();
01783             if ( node )
01784                 group->addChild( node );
01785             group->addChild( canvas );
01786             
01787             // must save the manipulator matrix b/c calling setSceneData causes
01788             // the view to call home() on the manipulator.
01789             osg::Matrixd savedMatrix;
01790             osgGA::MatrixManipulator* manip = view2->getCameraManipulator();
01791             if ( manip )
01792                 savedMatrix = manip->getMatrix();
01793 
01794             view2->setSceneData( group );
01795 
01796             // restore it
01797             if ( manip )
01798                 manip->setByMatrix( savedMatrix );
01799         }
01800 
01801         osg::ref_ptr<ControlCanvas>     _canvas;
01802         osg::ref_ptr<osg::NodeCallback> _oldCallback;
01803     };
01804 
01805 } } } // namespace osgEarth::Util::Controls
01806 
01807 // ---------------------------------------------------------------------------
01808 
01809 ControlNode::ControlNode( Control* control, float priority ) :
01810 _control ( control ),
01811 _priority( priority )
01812 {
01813     setCullingActive( false );
01814 }
01815 
01816 osg::BoundingSphere
01817 ControlNode::computeBound() const
01818 {
01819     return osg::BoundingSphere( osg::Vec3(0,0,0), 0.5 );
01820 }
01821 
01822 void
01823 ControlNode::traverse( osg::NodeVisitor& nv )
01824 {
01825     if ( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
01826     {
01827         static osg::Vec3d s_zero(0,0,0);
01828         static osg::Vec4d s_zero_w(0,0,0,1);
01829         osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>( &nv );
01830 
01831         //setCullingActive( true );
01832         //cv->setSmallFeatureCullingPixelSize(0);
01833 
01834         // pull up the per-view data for this view:
01835         PerViewData& data = _perViewData[cv->getCurrentCamera()->getView()];
01836 
01837         // if it's uninitialized, find the corresponding control canvas and 
01838         // cache a reference to its control node bin:
01839         if ( !data._canvas.valid() )
01840         {
01841             data._canvas = ControlCanvas::get( cv->getCurrentCamera()->getView(), true );
01842             if ( data._canvas.valid() )
01843             {
01844                 ControlNodeBin* bin = static_cast<ControlCanvas*>(data._canvas.get())->getControlNodeBin();
01845                 bin->addNode( this );
01846             }
01847         }
01848 
01849         if ( data._canvas.valid() )
01850         {
01851             // calculate its screen position:
01852             //data._screenPos = s_zero * (*cv->getMVPW());
01853 
01854             osg::Vec4d clip = s_zero_w * (*cv->getModelViewMatrix()) * (*cv->getProjectionMatrix());
01855             osg::Vec3d clip_ndc( clip.x()/clip.w(), clip.y()/clip.w(), clip.z()/clip.w() );
01856             data._screenPos = clip_ndc * cv->getWindowMatrix();
01857 
01858             if ( clip_ndc.z() > 1.0 ) // node is behind the near clip plane
01859             {
01860                 data._obscured = true;
01861             }
01862             else if ( data._obscured == true )
01863             {
01864                 data._obscured = false;
01865                 data._visibleTime = cv->getFrameStamp()->getReferenceTime();
01866             }
01867         }
01868 
01869         data._visitFrame = cv->getFrameStamp()->getFrameNumber();
01870     }
01871 
01872     // ControlNode has no children, so no point in calling traverse.
01873     osg::Node::traverse(nv);
01874 }
01875 
01876 ControlNode::PerViewData::PerViewData() :
01877 _obscured   ( true ),
01878 _visibleTime( 0.0 ),
01879 _screenPos  ( 0.0, 0.0, 0.0 )
01880 {
01881     //nop
01882 }
01883 
01884 // ---------------------------------------------------------------------------
01885 
01886 ControlNodeBin::ControlNodeBin() :
01887 _sortingEnabled( true ),
01888 _sortByDistance( true ),
01889 _fading        ( true )
01890 {
01891     _group = new Group();
01892 
01893     osg::StateSet* stateSet = _group->getOrCreateStateSet();
01894 
01895     osg::Program* program = new osg::Program();
01896     program->addShader( new osg::Shader( osg::Shader::VERTEX, s_controlVertexShader ) );
01897     program->addShader( new osg::Shader( osg::Shader::FRAGMENT, s_labelControlFragmentShader ) );
01898     stateSet->setAttributeAndModes( program, osg::StateAttribute::ON );
01899 
01900     osg::Uniform* defaultOpacity = new osg::Uniform( osg::Uniform::FLOAT, "opacity" );
01901     defaultOpacity->set( 1.0f );
01902     stateSet->addUniform( defaultOpacity );
01903 
01904     osg::Uniform* defaultVisibleTime = new osg::Uniform( osg::Uniform::FLOAT, "visibleTime" );
01905     defaultVisibleTime->set( 0.0f );
01906     stateSet->addUniform( defaultVisibleTime );    
01907 }
01908 
01909 void
01910 ControlNodeBin::setFading( bool value )
01911 {
01912     _fading = value;
01913 }
01914 
01915 void
01916 ControlNodeBin::draw( const ControlContext& context, bool newContext, int bin )
01917 {
01918     const osg::Viewport* vp = context._vp.get();
01919     osg::Vec2f surfaceSize( context._vp->width(), context._vp->height() );
01920 
01921     // we don't really need to keep this list in the object, but that prevents it from having to
01922     // reallocate it each time
01923     _taken.clear();
01924 
01925     ControlNodeCollection* drawList = 0L;
01926     ControlNodeCollection byDepth;
01927 
01928     if ( _sortingEnabled && _sortByDistance )
01929     {
01930         for( ControlNodeCollection::iterator i = _controlNodes.begin(); i != _controlNodes.end(); i++) 
01931         {
01932             ControlNode* node = i->second.get();
01933             if ( node->getNumParents() == 0 )
01934             {
01935               _renderNodes.erase( node );
01936               _controlNodes.erase( i );
01937             }
01938             else
01939             {
01940                 ControlNode::PerViewData& nodeData = node->getData( context._view );
01941                 byDepth.insert( ControlNodePair(nodeData._screenPos.z(), node) );
01942             }
01943         }
01944 
01945         drawList = &byDepth;
01946     }
01947     else
01948     {
01949         drawList = &_controlNodes;
01950     }
01951 
01952     for( ControlNodeCollection::iterator i = drawList->begin(); i != drawList->end(); ) 
01953     {
01954         ControlNode* node = i->second.get();
01955         osg::MatrixTransform* xform = _renderNodes[node];
01956 
01957         // check to see if the node as removed
01958         bool nodeActive = node->getNumParents() > 0;
01959 
01960         if ( nodeActive )
01961         {
01962           ControlNode::PerViewData& nodeData = node->getData( context._view );
01963           Control* control = node->getControl();
01964 
01965           // if the context changed (e.g., viewport resize), we need to mark all nodes as dirty
01966           // even if they're obscured...that way they will regenerate properly next time
01967           if ( newContext )
01968           {
01969               control->dirty();
01970           }
01971 
01972           bool visible = true;
01973 
01974           if ( context._frameStamp->getFrameNumber() - nodeData._visitFrame > 2 )
01975           {
01976               visible = false;
01977           }
01978 
01979           else if ( nodeData._obscured == false )
01980           {
01981               const osg::Vec3f& nPos = nodeData._screenPos;
01982               const osg::Vec2f& size = control->renderSize();
01983 
01984               // calculate the rendering offset based on alignment:
01985               float x, y;
01986 
01987               if ( node->anchorPoint().isSet() )
01988               {
01989                   //TODO!!
01990               }
01991               else
01992               {
01993                   x =
01994                     control->horizAlign() == Control::ALIGN_LEFT  ? nPos.x() - size.x() :
01995                     control->horizAlign() == Control::ALIGN_RIGHT ? nPos.x() :
01996                     nPos.x() - size.x()*0.5;
01997 
01998                   y =
01999                     control->vertAlign() == Control::ALIGN_BOTTOM ? nPos.y() :
02000                     control->vertAlign() == Control::ALIGN_TOP    ? nPos.y() + size.y() :
02001                     nPos.y() + size.y()*0.5;
02002               }
02003 
02004               xform->setMatrix( osg::Matrixd::translate(x, y-context._vp->height(), 0) );
02005 
02006               osg::BoundingBox bbox( x, y, 0.0, x+size.x(), y+size.y(), 1.0 );
02007               if ( _sortingEnabled )
02008               {
02009                   // prevent overlap.
02010                   for( std::vector<osg::BoundingBox>::iterator u = _taken.begin(); u != _taken.end(); ++u )
02011                   {
02012                       if ( u->intersects( bbox ) )
02013                       {
02014                           nodeData._obscured = true;
02015                           break;
02016                       }
02017                   }
02018               }
02019 
02020               if ( nodeData._obscured == false )
02021               {
02022                   if ( _sortingEnabled )
02023                     _taken.push_back( bbox );
02024 
02025                   // the geode holding this node's geometry:
02026                   osg::Geode* geode = static_cast<osg::Geode*>( xform->getChild(0) );
02027 
02028                   // if the control changed, we need to rebuild its drawables:
02029                   if ( control->isDirty() )
02030                   {
02031                       // clear out the geode:
02032                       geode->removeDrawables( 0, geode->getNumDrawables() );
02033 
02034                       // calculate the size of the control in screen space:
02035                       osg::Vec2f dummySize;
02036                       control->calcSize( context, dummySize );
02037                       control->calcFill( context );
02038 
02039                       // only need to do this if the control has children ... (pos is always 0,0)
02040                       control->calcPos( context, osg::Vec2f(0,0), size );
02041                    
02042                       // build the drawables for the geode and insert them:
02043                       DrawableList drawables;
02044                       control->draw( context, drawables );
02045 
02046                       for( DrawableList::iterator j = drawables.begin(); j != drawables.end(); ++j )
02047                       {
02048                           j->get()->setDataVariance( osg::Object::DYNAMIC );
02049 
02050                           osg::StateSet* stateSet = j->get()->getOrCreateStateSet();
02051                           stateSet->setRenderBinDetails( bin++, "RenderBin" );
02052                           geode->addDrawable( j->get() );
02053                       }
02054                   }
02055 
02056                   if ( _fading )
02057                   {
02058                       // update the "visible time" uniform if it's changed. this will cause the
02059                       // shader to "fade in" the label when it becomes visible.
02060                       if ( !nodeData._uniform.valid() )
02061                       {
02062                           nodeData._uniform = new osg::Uniform( osg::Uniform::FLOAT, "visibleTime" );
02063                           geode->getOrCreateStateSet()->addUniform( nodeData._uniform.get() );
02064                       }
02065 
02066                       float oldValue;
02067                       nodeData._uniform->get( oldValue );
02068                       if ( oldValue != nodeData._visibleTime )
02069                           nodeData._uniform->set( nodeData._visibleTime );
02070                   }
02071               }
02072 
02073               visible = !nodeData._obscured;
02074           }
02075           
02076           // adjust the visibility
02077           xform->setNodeMask( visible ? ~0 : 0 );
02078 
02079           ++i;
02080         }
02081         else
02082         {
02083           _renderNodes.erase( node );
02084           _controlNodes.erase( i++ );
02085         }
02086     }
02087 }
02088 
02089 void
02090 ControlNodeBin::addNode( ControlNode* controlNode )
02091 {
02092     // if we see a node with a non-zero priority, assume we're sorting
02093     // by priority.
02094     if ( controlNode->getPriority() != 0.0f )
02095         _sortByDistance = false;
02096 
02097     // record the node in priority order.
02098     ControlNodeCollection::iterator ptr = _controlNodes.insert(
02099         ControlNodePair( -controlNode->getPriority(), controlNode ) );
02100 
02101     // record it in the index.
02102     _index.insert( ControlIndexPair(controlNode->getControl(), ptr) );
02103 
02104     // create and cache a transform/geode pair for the node. the xform will position
02105     // the geode in 2D space.
02106     osg::MatrixTransform* xform = new osg::MatrixTransform();
02107     osg::Geode* geode = new osg::Geode();
02108     xform->addChild( geode );
02109     _renderNodes.insert( RenderNodePair(controlNode, xform) );
02110 
02111     // put it in the render graph.
02112     _group->addChild( xform );
02113 }
02114 
02115 // ---------------------------------------------------------------------------
02116 
02117 ControlCanvas::ViewCanvasMap ControlCanvas::_viewCanvasMap;
02118 OpenThreads::Mutex           ControlCanvas::_viewCanvasMapMutex;
02119 
02120 ControlCanvas*
02121 ControlCanvas::get( osg::View* view, bool installInSceneData )
02122 {
02123     ControlCanvas* canvas = 0L;
02124 
02125     OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _viewCanvasMapMutex );
02126 
02127     ViewCanvasMap::iterator i = _viewCanvasMap.find( view );
02128     if ( i != _viewCanvasMap.end() )
02129     {
02130         canvas = i->second;
02131     }
02132 
02133     else
02134     {
02135         // Not found, so create one. If requested, add a callback that will
02136         // automatically install it in the view's scene data during the 
02137         // next update traversal.
02138         osgViewer::View* view2 = dynamic_cast<osgViewer::View*>(view);
02139         if ( view2 )
02140         {
02141             canvas = new ControlCanvas( view2, false );
02142             _viewCanvasMap[view] = canvas;
02143 
02144             if ( installInSceneData )
02145                 new CanvasInstaller( canvas, view->getCamera() );
02146         }
02147     }
02148 
02149     return canvas;
02150 }
02151 
02152 // ---------------------------------------------------------------------------
02153 
02154 ControlCanvas::ControlCanvas( osgViewer::View* view ) :
02155 _contextDirty(true)
02156 {
02157     init( view, true );
02158 }
02159 
02160 ControlCanvas::ControlCanvas( osgViewer::View* view, bool registerCanvas ) :
02161 _contextDirty( true )
02162 {
02163     init( view, registerCanvas );
02164 }
02165 
02166 void
02167 ControlCanvas::init( osgViewer::View* view, bool registerCanvas )
02168 {
02169     this->setDataVariance( osg::Object::DYNAMIC );
02170 
02171     view->addEventHandler( new ViewportHandler(this) );
02172     view->addEventHandler( new ControlCanvasEventHandler(this) );
02173 
02174     setReferenceFrame(osg::Transform::ABSOLUTE_RF);
02175     setViewMatrix(osg::Matrix::identity());
02176     setClearMask(GL_DEPTH_BUFFER_BIT);
02177     setRenderOrder(osg::Camera::POST_RENDER); 
02178     setAllowEventFocus( true );
02179     
02180     // activate the update traversal
02181     ADJUST_UPDATE_TRAV_COUNT( this, 1 );
02182 
02183     osg::StateSet* ss = getOrCreateStateSet();
02184     ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE );
02185     ss->setMode( GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
02186     ss->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL, 0, 1, false ) );
02187 
02188     // this is necessary b/c osgText puts things in this bin too and we can't override that
02189     ss->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
02190     ss->setBinNumber(999999);
02191 
02192     _controlNodeBin = new ControlNodeBin();
02193     this->addChild( _controlNodeBin->getControlGroup() );
02194 
02195     // register this canvas.
02196     if ( registerCanvas )
02197     {
02198         OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _viewCanvasMapMutex );
02199         _viewCanvasMap[view] = this;
02200     }
02201 }
02202 
02203 ControlCanvas::~ControlCanvas()
02204 {
02205     OpenThreads::ScopedLock<OpenThreads::Mutex> lock( _viewCanvasMapMutex );
02206     _viewCanvasMap.erase( _context._view );
02207 }
02208 
02209 void
02210 ControlCanvas::setAllowControlNodeOverlap( bool value )
02211 {
02212     getControlNodeBin()->_sortingEnabled = !value;
02213 }
02214 
02215 void
02216 ControlCanvas::addControl( Control* control )
02217 {
02218     osg::Geode* geode = new osg::Geode();
02219     _geodeTable[control] = geode;
02220     addChild( geode );
02221     control->dirty();    
02222     _controls.push_back( control );
02223 }
02224 
02225 void
02226 ControlCanvas::removeControl( Control* control )
02227 {
02228     GeodeTable::iterator i = _geodeTable.find( control );
02229     if ( i != _geodeTable.end() )
02230     {
02231          removeChild( i->second );
02232          _geodeTable.erase( i );
02233     }
02234     ControlList::iterator j = std::find( _controls.begin(), _controls.end(), control );
02235     if ( j != _controls.end() )
02236         _controls.erase( j );
02237 }
02238 
02239 Control*
02240 ControlCanvas::getControlAtMouse( float x, float y ) const
02241 {
02242     for( ControlList::const_iterator i = _controls.begin(); i != _controls.end(); ++i )
02243     {
02244         Control* control = i->get();
02245         if ( control->intersects( x, _context._vp->height() - y ) )
02246             return control;
02247     }
02248     return 0L;
02249 }
02250 
02251 bool
02252 ControlCanvas::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
02253 {
02254         for (ControlList::reverse_iterator i = _controls.rbegin(); i != _controls.rend(); ++i)
02255         {
02256                 Control* control = i->get();
02257                 if (control->isDirty())
02258                 {
02259                         aa.requestRedraw();
02260                         break;
02261                 }
02262         }
02263 
02264         bool handled = false;
02265     //Send a frame event to all controls
02266     if ( ea.getEventType() == osgGA::GUIEventAdapter::FRAME )
02267     {
02268         for( ControlList::const_reverse_iterator i = _controls.rbegin(); i != _controls.rend(); ++i )
02269         {
02270             i->get()->handle(ea, aa, _context);
02271         }
02272         return handled;
02273     }
02274 
02275 
02276     float invY = _context._vp->height() - ea.getY();
02277 
02278     for( ControlList::reverse_iterator i = _controls.rbegin(); i != _controls.rend(); ++i )
02279     {
02280         Control* control = i->get();
02281         if ( control->intersects( ea.getX(), invY ) )
02282         {
02283             handled = control->handle( ea, aa, _context );
02284             if ( handled )
02285                 break;
02286         }
02287     }
02288 
02289     if ( _context._active.size() > 1 )
02290     {
02291         _context._active.front()->setActive( false );
02292         _context._active.pop();
02293     }
02294 
02295     if ( _context._active.size() > 0 )
02296     {
02297         bool hit = _context._active.front()->intersects( ea.getX(), invY );
02298         _context._active.front()->setActive( hit );
02299         if ( !hit )
02300             _context._active.pop();
02301     }
02302 
02303     return handled; //_context._active.size() > 0;
02304 }
02305 
02306 void
02307 ControlCanvas::update( const osg::FrameStamp* frameStamp )
02308 {
02309     _context._frameStamp = frameStamp;
02310 
02311     int bin = 0;
02312     for( ControlList::iterator i = _controls.begin(); i != _controls.end(); ++i )
02313     {
02314         Control* control = i->get();
02315         if ( control->isDirty() || _contextDirty )
02316         {
02317             osg::Vec2f size;
02318             control->calcSize( _context, size );
02319             control->calcFill( _context );
02320 
02321             osg::Vec2f surfaceSize( _context._vp->width(), _context._vp->height() );
02322             control->calcPos( _context, osg::Vec2f(0,0), surfaceSize );
02323 
02324             osg::Geode* geode = _geodeTable[control];
02325             geode->removeDrawables( 0, geode->getNumDrawables() );
02326             DrawableList drawables;
02327             control->draw( _context, drawables );
02328 
02329             for( DrawableList::iterator j = drawables.begin(); j != drawables.end(); ++j )
02330             {
02331                 j->get()->setDataVariance( osg::Object::DYNAMIC );
02332                 j->get()->getOrCreateStateSet()->setBinNumber( bin++ );
02333                 geode->addDrawable( j->get() );
02334             }
02335         }
02336     }
02337 
02338     if ( _controlNodeBin.valid() )
02339     {
02340         _controlNodeBin->draw( _context, _contextDirty, bin );
02341     }
02342 
02343     _contextDirty = false;
02344 }
02345 
02346 void
02347 ControlCanvas::traverse( osg::NodeVisitor& nv )
02348 {
02349     if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
02350     {
02351         update( nv.getFrameStamp() );
02352     }
02353 
02354     osg::Camera::traverse( nv );
02355 }
02356 
02357 void
02358 ControlCanvas::setControlContext( const ControlContext& cx )
02359 {
02360     _context = cx;
02361     _contextDirty = true;
02362 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines