1 // A text on the canvas
3 // Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include <Canvas/property_helper.hxx>
22 #include <Main/globals.hxx>
23 #include <Main/fg_props.hxx>
25 #include <osgText/Text>
34 void setCharacterAspect(float aspect);
35 void setFill(const std::string& fill);
36 void setBackgroundColor(const std::string& fill);
38 osg::Vec2 handleHit(float x, float y);
40 virtual osg::BoundingBox computeBound() const;
43 //----------------------------------------------------------------------------
44 void Text::TextOSG::setCharacterAspect(float aspect)
46 setCharacterSize(getCharacterHeight(), aspect);
49 //----------------------------------------------------------------------------
50 void Text::TextOSG::setFill(const std::string& fill)
52 // if( fill == "none" )
55 setColor( parseColor(fill) );
58 //----------------------------------------------------------------------------
59 void Text::TextOSG::setBackgroundColor(const std::string& fill)
61 setBoundingBoxColor( parseColor(fill) );
64 //----------------------------------------------------------------------------
65 osg::Vec2 Text::TextOSG::handleHit(float x, float y)
67 float line_height = _characterHeight + _lineSpacing;
69 // TODO check with align other than TOP
70 float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
71 size_t line = std::max<int>(0, (y - first_line_y) / line_height);
73 if( _textureGlyphQuadMap.empty() )
74 return osg::Vec2(-1, -1);
76 // TODO check when it can be larger
77 assert( _textureGlyphQuadMap.size() == 1 );
79 const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
80 const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
81 const GlyphQuads::Coords2& coords = glyphquad._coords;
82 const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
84 const float HIT_FRACTION = 0.6;
85 const float character_width = getCharacterHeight()
86 * getCharacterAspectRatio();
88 y = (line + 0.5) * line_height;
90 bool line_found = false;
91 for(size_t i = 0; i < line_numbers.size(); ++i)
93 if( line_numbers[i] != line )
97 if( line_numbers[i] < line )
98 // Wait for the correct line...
101 // We have already passed the correct line -> It's empty...
102 return osg::Vec2(0, y);
105 // Next line and not returned -> not before any character
106 // -> return position after last character of line
107 return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
112 // Get threshold for mouse x position for setting cursor before or after
114 float threshold = coords[i * 4].x()
115 + HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
120 if( i == 0 || line_numbers[i - 1] != line )
121 // first character of line
122 x = coords[i * 4].x();
123 else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
124 // If previous character width is zero set to begin of next character
125 // (Happens eg. with spaces)
126 x = coords[i * 4].x();
128 // position at center between characters
129 x = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
131 return osg::Vec2(x, y);
135 // Nothing found -> return position after last character
139 (_lineCount - 0.5) * line_height
143 //----------------------------------------------------------------------------
144 osg::BoundingBox Text::TextOSG::computeBound() const
146 osg::BoundingBox bb = osgText::Text::computeBound();
150 // TODO bounding box still doesn't seem always right (eg. with center
151 // horizontal alignment not completely accurate)
152 bb._min.y() += _offset.y();
153 bb._max.y() += _offset.y();
158 //----------------------------------------------------------------------------
159 Text::Text(SGPropertyNode_ptr node, const Style& parent_style):
160 Element(node, parent_style, BOUNDING_BOX),
161 _text( new Text::TextOSG() )
164 _text->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
165 _text->setAxisAlignment(osgText::Text::USER_DEFINED_ROTATION);
166 _text->setRotation(osg::Quat(osg::PI, osg::X_AXIS));
168 addStyle("fill", &TextOSG::setFill, _text);
169 addStyle("background", &TextOSG::setBackgroundColor, _text);
170 addStyle("character-size",
171 static_cast<void (TextOSG::*)(float)>(&TextOSG::setCharacterSize),
173 addStyle("character-aspect-ratio", &TextOSG::setCharacterAspect, _text);
174 addStyle("padding", &TextOSG::setBoundingBoxMargin, _text);
177 // FILLEDBOUNDINGBOX = 4
179 addStyle<int>("draw-mode", &TextOSG::setDrawMode, _text);
180 addStyle("max-width", &TextOSG::setMaximumWidth, _text);
181 addStyle("font", &Text::setFont, this);
182 addStyle("alignment", &Text::setAlignment, this);
183 addStyle("text", &Text::setText, this);
188 //----------------------------------------------------------------------------
194 //----------------------------------------------------------------------------
195 void Text::setText(const char* text)
197 _text->setText(text, osgText::String::ENCODING_UTF8);
200 //----------------------------------------------------------------------------
201 void Text::setFont(const char* name)
203 _text->setFont( getFont(name) );
206 //----------------------------------------------------------------------------
207 void Text::setAlignment(const char* align)
209 const std::string align_string(align);
211 #define ENUM_MAPPING(enum_val, string_val) \
212 else if( align_string == string_val )\
213 _text->setAlignment( osgText::Text::enum_val );
214 #include "text-alignment.hxx"
218 if( !align_string.empty() )
223 "canvas::Text: unknown alignment '" << align_string << "'"
225 _text->setAlignment(osgText::Text::LEFT_BASE_LINE);
229 //----------------------------------------------------------------------------
231 const char* Text::getAlignment() const
233 switch( _text->getAlignment() )
235 #define ENUM_MAPPING(enum_val, string_val) \
236 case osgText::Text::enum_val:\
238 #include "text-alignment.hxx"
246 //----------------------------------------------------------------------------
247 void Text::childChanged(SGPropertyNode* child)
249 if( child->getParent() != _node )
252 const std::string& name = child->getNameString();
253 if( name == "hit-y" )
256 _node->getFloatValue("hit-x"),
257 _node->getFloatValue("hit-y")
261 //----------------------------------------------------------------------------
262 void Text::handleHit(float x, float y)
264 const osg::Vec2& pos = _text->handleHit(x, y);
265 _node->setFloatValue("cursor-x", pos.x());
266 _node->setFloatValue("cursor-y", pos.y());
269 //----------------------------------------------------------------------------
270 Text::font_ptr Text::getFont(const std::string& name)
272 SGPath path = globals->resolve_ressource_path("Fonts/" + name);
279 "canvas::Text: No such font: " << name
288 "canvas::Text: using font file " << path.str()
291 font_ptr font = osgText::readFontFile(path.c_str());
297 "canvas::Text: Failed to open font file " << path.c_str()
303 } // namespace canvas