]> git.mxchange.org Git - flightgear.git/commitdiff
Canvas: Support for text selection.
authorThomas Geymayer <tomgey@gmail.com>
Tue, 24 Jul 2012 22:11:55 +0000 (00:11 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 31 Jul 2012 21:19:23 +0000 (23:19 +0200)
 - Expose nearest hit for text/character selection
 - Fix culling

src/Canvas/canvas.cxx
src/Canvas/elements/text.cxx
src/Canvas/elements/text.hxx

index 43878a124280f5ba6547bf67d878239b4096e69b..673e9f12c7bed964e445e963c73a3cc81fc72375 100644 (file)
 
 #include <Canvas/property_helper.hxx>
 #include <Main/globals.hxx>
+#include <Viewer/CameraGroup.hxx>
 #include <Viewer/renderer.hxx>
 
+#include <simgear/scene/util/RenderConstants.hxx>
+
 #include <osg/Camera>
 #include <osg/Geode>
 #include <osgText/Text>
@@ -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;
 
index 291765d3c8d3217d797ac13388facc648175c019..725d67e1264473db3e4de5645789f6dd7e59cd77 100644 (file)
 
 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<int>(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)
   {
index 38c7f13350d6a401502db15dc8f9ccf79a2c3cb4..6147e4367ba33c3770113800cb706990af21b9f8 100644 (file)
@@ -49,7 +49,8 @@ namespace canvas
         FONT_SIZE       = LAST_ATTRIBUTE << 1, // Font size and aspect ration
       };
 
-      osg::ref_ptr<osgText::Text>   _text;
+      class TextOSG;
+      osg::ref_ptr<TextOSG> _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<osgText::Font> font_ptr;
       static font_ptr getFont(const std::string& name);
   };