From: Thomas Geymayer Date: Tue, 24 Jul 2012 22:11:55 +0000 (+0200) Subject: Canvas: Support for text selection. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=5f08e10c0a0e383d7974bf69f5f51d4df28beb1e;p=flightgear.git Canvas: Support for text selection. - Expose nearest hit for text/character selection - Fix culling --- diff --git a/src/Canvas/canvas.cxx b/src/Canvas/canvas.cxx index 43878a124..673e9f12c 100644 --- a/src/Canvas/canvas.cxx +++ b/src/Canvas/canvas.cxx @@ -21,8 +21,11 @@ #include #include
+#include #include +#include + #include #include #include @@ -41,7 +44,8 @@ class CameraCullCallback: public: CameraCullCallback(): - _render( true ) + _render( true ), + _render_frame( 0 ) {} /** @@ -55,14 +59,17 @@ class CameraCullCallback: private: bool _render; + unsigned int _render_frame; virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - if( _render ) - { - traverse(node, nv); - _render = false; - } + if( !_render && nv->getTraversalNumber() != _render_frame ) + return; + + traverse(node, nv); + + _render = false; + _render_frame = nv->getTraversalNumber(); } }; @@ -87,7 +94,9 @@ class PlacementCullCallback: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { - _camera_cull->enableRendering(); + if( nv->getTraversalMask() & simgear::MODEL_BIT ) + _camera_cull->enableRendering(); + traverse(node, nv); } }; @@ -419,13 +428,16 @@ GLuint Canvas::getTexId() const if( !tex ) return 0; - osgViewer::Viewer::Contexts contexts; - globals->get_renderer()->getViewer()->getContexts(contexts); +// osgViewer::Viewer::Contexts contexts; +// globals->get_renderer()->getViewer()->getContexts(contexts); +// +// if( contexts.empty() ) +// return 0; - if( contexts.empty() ) - return 0; + osg::Camera* guiCamera = + flightgear::getGUICamera(flightgear::CameraGroup::getDefault()); - osg::State* state = contexts[0]->getState(); + osg::State* state = guiCamera->getGraphicsContext()->getState(); //contexts[0]->getState(); if( !state ) return 0; diff --git a/src/Canvas/elements/text.cxx b/src/Canvas/elements/text.cxx index 291765d3c..725d67e12 100644 --- a/src/Canvas/elements/text.cxx +++ b/src/Canvas/elements/text.cxx @@ -26,11 +26,96 @@ namespace canvas { + class Text::TextOSG: + public osgText::Text + { + public: + osg::Vec2 handleHit(float x, float y); + }; + + //---------------------------------------------------------------------------- + osg::Vec2 Text::TextOSG::handleHit(float x, float y) + { + float line_height = _characterHeight + _lineSpacing; + + // TODO check with align other than TOP + float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight; + size_t line = std::max(0, (y - first_line_y) / line_height); + + if( _textureGlyphQuadMap.empty() ) + return osg::Vec2(-1, -1); + + // TODO check when it can be larger + assert( _textureGlyphQuadMap.size() == 1 ); + + const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second; + const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs; + const GlyphQuads::Coords2& coords = glyphquad._coords; + const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers; + + const float HIT_FRACTION = 0.6; + const float character_width = getCharacterHeight() + * getCharacterAspectRatio(); + + y = (line + 0.5) * line_height; + + bool line_found = false; + for(size_t i = 0; i < line_numbers.size(); ++i) + { + if( line_numbers[i] != line ) + { + if( !line_found ) + { + if( line_numbers[i] < line ) + // Wait for the correct line... + continue; + + // We have already passed the correct line -> It's empty... + return osg::Vec2(0, y); + } + + // Next line and not returned -> not before any character + // -> return position after last character of line + return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y); + } + + line_found = true; + + // Get threshold for mouse x position for setting cursor before or after + // current character + float threshold = coords[i * 4].x() + + HIT_FRACTION * glyphs[i]->getHorizontalAdvance() + * character_width; + + if( x <= threshold ) + { + if( i == 0 || line_numbers[i - 1] != line ) + // first character of line + x = coords[i * 4].x(); + else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() ) + // If previous character width is zero set to begin of next character + // (Happens eg. with spaces) + x = coords[i * 4].x(); + else + // position at center between characters + x = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x()); + + return osg::Vec2(x, y); + } + } + + // Nothing found -> return position after last character + return osg::Vec2 + ( + coords.back().x(), + (_lineCount - 0.5) * line_height + ); + } //---------------------------------------------------------------------------- Text::Text(SGPropertyNode_ptr node): Element(node, COLOR | COLOR_FILL | BOUNDING_BOX), - _text( new osgText::Text ), + _text( new Text::TextOSG() ), _font_size( 0 ), _font_aspect( 0 ) { @@ -146,17 +231,25 @@ namespace canvas //---------------------------------------------------------------------------- void Text::childChanged(SGPropertyNode* child) { - if( _font_size == child || _font_aspect == child ) + const std::string& name = child->getNameString(); + + if( name == "hit-y" ) + handleHit + ( + _node->getFloatValue("hit-x"), + _node->getFloatValue("hit-y") + ); + else if( _font_size == child || _font_aspect == child ) _attributes_dirty |= FONT_SIZE; - else if( child->getNameString() == "text" ) + else if( name == "text" ) _text->setText ( osgText::String( child->getStringValue(), osgText::String::ENCODING_UTF8 ) ); - else if( child->getNameString() == "max-width" ) + else if( name == "max-width" ) _text->setMaximumWidth( child->getFloatValue() ); - else if( child->getNameString() == "font" ) + else if( name == "font" ) setFont( child->getStringValue() ); } @@ -172,6 +265,14 @@ namespace canvas _text->setBoundingBoxColor(color); } + //---------------------------------------------------------------------------- + void Text::handleHit(float x, float y) + { + const osg::Vec2& pos = _text->handleHit(x, y); + _node->setFloatValue("cursor-x", pos.x()); + _node->setFloatValue("cursor-y", pos.y()); + } + //---------------------------------------------------------------------------- Text::font_ptr Text::getFont(const std::string& name) { diff --git a/src/Canvas/elements/text.hxx b/src/Canvas/elements/text.hxx index 38c7f1335..6147e4367 100644 --- a/src/Canvas/elements/text.hxx +++ b/src/Canvas/elements/text.hxx @@ -49,7 +49,8 @@ namespace canvas FONT_SIZE = LAST_ATTRIBUTE << 1, // Font size and aspect ration }; - osg::ref_ptr _text; + class TextOSG; + osg::ref_ptr _text; SGPropertyNode_ptr _font_size, _font_aspect; @@ -58,6 +59,8 @@ namespace canvas virtual void colorChanged(const osg::Vec4& color); virtual void colorFillChanged(const osg::Vec4& color); + void handleHit(float x, float y); + typedef osg::ref_ptr font_ptr; static font_ptr getFont(const std::string& name); };