1 #include <msp/gl/immediate.h>
2 #include <msp/gl/matrix.h>
3 #include <msp/gl/texture2d.h>
12 struct Text::RenderData
14 GL::PrimitiveBuilder *bld;
17 struct Text::CoordsToGeomData
29 Text::Text(const Style &s, const string &t):
35 void Text::set_style(const Style *s)
41 float font_size = style->get_font()->get_default_size();
42 for(vector<Line>::iterator i=lines.begin(); i!=lines.end(); ++i)
43 i->width = static_cast<unsigned>(style->get_font()->get_string_width(text.substr(i->start, i->length))*font_size);
47 unsigned Text::get_width() const
50 for(vector<Line>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
51 width = max(width, i->width);
55 unsigned Text::get_height() const
60 const GL::Font *font = style->get_font();
61 float font_size = font->get_default_size();
62 unsigned line_height = static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
63 unsigned line_spacing = line_height*6/5;
64 return line_height+(lines.size()-1)*line_spacing;
67 void Text::set(const string &t)
73 void Text::erase(unsigned pos, unsigned len)
77 vector<Line>::iterator i;
78 for(i=lines.begin(); (i!=lines.end() && i->start+i->length<pos); ++i) ;
80 if(pos+len>i->start+i->length)
86 for(++i; i!=lines.end(); ++i)
91 void Text::insert(unsigned pos, const string &s)
95 if(s.find('\n')!=string::npos)
99 vector<Line>::iterator i;
100 for(i=lines.begin(); (i!=lines.end() && i->start+i->length<pos); ++i) ;
102 i->length += s.size();
104 for(++i; i!=lines.end(); ++i)
105 i->start += s.size();
109 unsigned Text::get_line_length(unsigned i) const
112 throw out_of_range("Text::get_line_length");
113 return lines[i].length;
116 void Text::offset_to_coords(unsigned offs, unsigned &row, unsigned &col) const
125 for(unsigned i=0; i<lines.size(); ++i)
126 if(offs>=lines[i].start && offs<=lines[i].start+lines[i].length)
129 col = offs-lines[i].start;
134 unsigned Text::coords_to_offset(unsigned row, unsigned col) const
136 if(row>=lines.size())
139 return lines[row].start+min(col, lines[row].length);
142 Geometry Text::coords_to_geometry(const Part &part, const Geometry &parent, unsigned first_row, unsigned row, unsigned col) const
144 if(row>=lines.size())
145 row = lines.size()-1;
146 const Line &line = lines[row];
150 CoordsToGeomData data;
154 process_lines<CoordsToGeomData, &Text::coords_to_geom_line>(part, parent, first_row, data);
159 void Text::render(const Part &part, const Geometry &parent, unsigned first_row) const
161 if(!style || lines.empty())
164 const GL::Font *font = style->get_font();
165 const GL::Color &color = style->get_font_color();
166 GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
167 imm.color(color.r, color.g, color.b);
172 GL::Bind bind_tex(font->get_texture());
174 process_lines<RenderData, &Text::render_line>(part, parent, first_row, data);
177 Text &Text::operator=(const string &t)
183 void Text::find_lines()
186 float font_size = (style ? style->get_font()->get_default_size() : 1);
187 string::size_type start = 0;
190 string::size_type newline = text.find('\n', start);
194 line.length = (newline==string::npos ? text.size() : newline)-start;
195 line.width = line.length;
198 string str = text.substr(line.start, line.length);
199 line.width = static_cast<unsigned>(style->get_font()->get_string_width(str)*font_size);
201 lines.push_back(line);
203 if(newline==string::npos)
209 template<typename T, void (Text::*func)(unsigned, const Geometry &, T &) const>
210 void Text::process_lines(const Part &part, const Geometry &parent, unsigned first_row, T &data) const
215 const GL::Font *font = style->get_font();
216 float font_size = font->get_default_size();
217 unsigned line_height = static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
218 unsigned line_spacing = static_cast<unsigned>(font_size*6/5);
219 unsigned height = line_height+(lines.size()-1)*line_spacing;
220 int y_offset = static_cast<int>(-font->get_descent()*font_size);
222 const Sides &margin = part.get_margin();
223 unsigned n_lines = min(lines.size(), max((parent.h-margin.top-margin.bottom)/line_spacing, 1U));
224 first_row = min(first_row, lines.size()-n_lines);
226 for(unsigned i=0; i<n_lines; ++i)
228 const Line &line = lines[first_row+i];
231 rgeom.w = line.width;
233 rgeom.y = (n_lines-1-i)*line_spacing+y_offset;
234 part.get_alignment().apply(rgeom, parent, part.get_margin());
236 (this->*func)(first_row+i, rgeom, data);
240 void Text::render_line(unsigned i, const Geometry &rgeom, RenderData &data) const
242 const Line &line = lines[i];
243 const GL::Font *font = style->get_font();
245 GL::PushMatrix _pushm;
246 GL::translate(rgeom.x, rgeom.y, 0);
247 GL::scale_uniform(font->get_default_size());
249 font->build_string(text.substr(line.start, line.length), *data.bld);
252 void Text::coords_to_geom_line(unsigned i, const Geometry &rgeom, CoordsToGeomData &data) const
256 const Line &line = lines[i];
257 const GL::Font *font = style->get_font();
260 data.result.x += static_cast<unsigned>(font->get_string_width(text.substr(line.start, data.col))*font->get_default_size());