osgEarth 2.1.1
|
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 }