1
0
Fork 0

Canvas: Support for text selection.

- Expose nearest hit for text/character selection
 - Fix culling
This commit is contained in:
Thomas Geymayer 2012-07-25 00:11:55 +02:00
parent 91c3f63110
commit 5f08e10c0a
3 changed files with 134 additions and 18 deletions

View file

@ -21,8 +21,11 @@
#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;

View file

@ -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<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)
{

View 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);
};