]> git.tdb.fi Git - libs/gltk.git/blob - source/text.cpp
Update text information when widget style changes
[libs/gltk.git] / source / text.cpp
1 #include <msp/gl/immediate.h>
2 #include <msp/gl/matrix.h>
3 #include "style.h"
4 #include "text.h"
5
6 using namespace std;
7
8 namespace Msp {
9 namespace GLtk {
10
11 Text::Text(const Style *const &s):
12         style(s)
13 { }
14
15 Text::Text(const Style *const &s, const string &t):
16         style(s)
17 {
18         set(t);
19 }
20
21 unsigned Text::get_width() const
22 {
23         unsigned width=0;
24         for(vector<Line>::const_iterator i=lines.begin(); i!=lines.end(); ++i)
25                 width=max(width, i->width);
26         return width;
27 }
28
29 unsigned Text::get_height() const
30 {
31         const GL::Font *font=style->get_font();
32         float font_size=font->get_default_size();
33         unsigned line_height=static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
34         unsigned line_spacing=line_height*6/5;
35         return line_height+(lines.size()-1)*line_spacing;
36 }
37
38 void Text::set(const string &t)
39 {
40         text=t;
41         find_lines();
42 }
43
44 void Text::erase(unsigned pos, unsigned len)
45 {
46         text.erase(pos, len);
47
48         vector<Line>::iterator i;
49         for(i=lines.begin(); (i!=lines.end() && i->start+i->length<pos); ++i) ;
50
51         if(pos+len>i->start+i->length)
52                 find_lines();
53         else
54         {
55                 i->length-=len;
56
57                 for(++i; i!=lines.end(); ++i)
58                         i->start-=len;
59         }
60 }
61
62 void Text::insert(unsigned pos, const string &s)
63 {
64         text.insert(pos, s);
65
66         if(s.find('\n')!=string::npos)
67                 find_lines();
68         else
69         {
70                 vector<Line>::iterator i;
71                 for(i=lines.begin(); (i!=lines.end() && i->start+i->length<pos); ++i) ;
72
73                 i->length+=s.size();
74
75                 for(++i; i!=lines.end(); ++i)
76                         i->start+=s.size();
77         }
78 }
79
80 void Text::update_style()
81 {
82         float font_size=style->get_font()->get_default_size();
83         for(vector<Line>::iterator i=lines.begin(); i!=lines.end(); ++i)
84                 i->width=static_cast<unsigned>(style->get_font()->get_string_width(text.substr(i->start, i->length))*font_size);
85 }
86
87 void Text::render(const Part &part, const Geometry &geom) const
88 {
89         if(lines.empty())
90                 return;
91
92         const GL::Font *font=style->get_font();
93         float font_size=font->get_default_size();
94         unsigned line_height=static_cast<unsigned>((font->get_ascent()-font->get_descent())*font_size);
95         unsigned line_spacing=font_size*6/5;
96         unsigned height=line_height+(lines.size()-1)*line_spacing;
97         int y_offset=static_cast<int>(-font->get_descent()*font_size);
98
99         const GL::Color &color=style->get_font_color();
100         GL::Immediate imm((GL::COLOR4_UBYTE, GL::TEXCOORD2, GL::VERTEX2));
101         imm.color(color.r, color.g, color.b);
102         for(unsigned i=0; i<lines.size(); ++i)
103         {
104                 const Line &line=lines[i];
105
106                 Geometry rgeom;
107                 rgeom.w=line.width;
108                 rgeom.h=height;
109                 rgeom.y=(lines.size()-1-i)*line_spacing+y_offset;
110                 part.get_alignment().apply(rgeom, geom, part.get_margin());
111
112                 GL::push_matrix();
113                 GL::translate(rgeom.x, rgeom.y, 0);
114                 GL::scale_uniform(font_size);
115
116                 font->draw_string(text.substr(line.start, line.length), imm);
117
118                 GL::pop_matrix();
119         }
120 }
121
122 Text &Text::operator=(const string &t)
123 {
124         set(t);
125         return *this;
126 }
127
128 void Text::find_lines()
129 {
130         lines.clear();
131         float font_size=style->get_font()->get_default_size();
132         string::size_type start=0;
133         while(1)
134         {
135                 string::size_type newline=text.find('\n', start);
136
137                 Line line;
138                 line.start=start;
139                 line.length=(newline==string::npos ? text.size() : newline)-start;
140                 line.width=static_cast<unsigned>(style->get_font()->get_string_width(text.substr(line.start, line.length))*font_size);
141                 lines.push_back(line);
142
143                 if(newline==string::npos)
144                         break;
145                 start=newline+1;
146         }
147 }
148
149 } // namespace GLtk
150 } // namespace Msp