]> git.tdb.fi Git - libs/gltk.git/blob - source/entry.cpp
Implement autosize for List and use it from Dropdown
[libs/gltk.git] / source / entry.cpp
1 /* $Id$
2
3 This file is part of libmspgltk
4 Copyright © 2007-2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/gl/matrix.h>
9 #include <msp/gl/texture.h>
10 #include <msp/gl/transform.h>
11 #include <msp/input/keys.h>
12 #include "entry.h"
13 #include "graphic.h"
14 #include "part.h"
15 #include "style.h"
16 #include "vslider.h"
17
18 using namespace std;
19
20 namespace Msp {
21 namespace GLtk {
22
23 Entry::Entry(const Resources &r, const string &t):
24         Widget(r),
25         Container(r),
26         text(),
27         multiline(false),
28         edit_pos(0),
29         first_row(0),
30         visible_rows(1),
31         text_part(0),
32         slider(0)
33 {
34         update_style();
35         set_text(t);
36 }
37
38 void Entry::set_text(const string &t)
39 {
40         text = t;
41         edit_pos = text.size();
42
43         if(multiline)
44                 check_view_range();
45 }
46
47 void Entry::set_multiline(bool m)
48 {
49         multiline = m;
50         if(multiline)
51         {
52                 if(!slider)
53                 {
54                         slider = new VSlider(res);
55                         add(*slider);
56                         slider->set_step(1);
57                         slider->signal_value_changed.connect(sigc::mem_fun(this, &Entry::slider_value_changed));
58                         reposition_slider();
59                 }
60                 check_view_range();
61         }
62 }
63
64 void Entry::key_press(unsigned key, unsigned, wchar_t ch)
65 {
66         if(key==Input::KEY_LEFT)
67         {
68                 if(edit_pos>0)
69                 {
70                         --edit_pos;
71                         check_view_range();
72                 }
73         }
74         else if(key==Input::KEY_RIGHT)
75         {
76                 if(edit_pos<text.size())
77                 {
78                         ++edit_pos;
79                         check_view_range();
80                 }
81         }
82         else if(key==Input::KEY_DOWN && multiline)
83         {
84                 unsigned row, col;
85                 text.offset_to_coords(edit_pos, row, col);
86                 edit_pos = text.coords_to_offset(row+1, col);
87                 check_view_range();
88         }
89         else if(key==Input::KEY_UP && multiline)
90         {
91                 unsigned row, col;
92                 text.offset_to_coords(edit_pos, row, col);
93                 if(row>0)
94                 {
95                         edit_pos = text.coords_to_offset(row-1, col);
96                         check_view_range();
97                 }
98                 else
99                         edit_pos = 0;
100         }
101         else if(key==Input::KEY_BACKSPACE)
102         {
103                 if(edit_pos>0)
104                 {
105                         text.erase(--edit_pos, 1);
106                         check_view_range();
107                 }
108         }
109         else if(key==Input::KEY_ENTER)
110         {
111                 if(multiline)
112                 {
113                         text.insert(edit_pos++, "\n");
114                         check_view_range();
115                 }
116                 else
117                         signal_enter.emit();
118         }
119         else if(ch>=' ')
120         {
121                 text.insert(edit_pos, Codecs::encode<Codecs::Utf8>(Codecs::ustring(1, ch)));
122                 ++edit_pos;
123         }
124 }
125
126 void Entry::render_special(const Part &part) const
127 {
128         if(part.get_name()=="text")
129                 text.render(part, geom, first_row);
130         else if(part.get_name()=="cursor")
131         {
132                 if(!text_part || !part.get_graphic(state))
133                         return;
134
135                 unsigned row, col;
136                 text.offset_to_coords(edit_pos, row, col);
137
138                 if(row<first_row || row>=first_row+visible_rows)
139                         return;
140
141                 Geometry rgeom = text.coords_to_geometry(*text_part, geom, first_row, row, col);
142
143                 GL::push_matrix();
144                 GL::translate(rgeom.x, rgeom.y, 0);
145                 part.get_graphic(state)->render(part.get_geometry().w, part.get_geometry().h);
146                 GL::pop_matrix();
147         }
148         else if(part.get_name()=="slider")
149                 slider->render();
150 }
151
152 void Entry::on_geometry_change()
153 {
154         reposition_slider();
155
156         if(multiline)
157                 check_view_range();
158 }
159
160 void Entry::on_style_change()
161 {
162         text_part = style->get_part("text");
163
164         text.set_style(style);
165         reposition_slider();
166
167         if(multiline)
168                 check_view_range();
169 }
170
171 void Entry::reposition_slider()
172 {
173         if(!slider)
174                 return;
175
176         if(const Part *slider_part = style->get_part("slider"))
177         {
178                 Geometry sgeom = slider_part->get_geometry();
179                 slider_part->get_alignment().apply(sgeom, geom, slider_part->get_margin());
180                 slider->set_geometry(sgeom);
181         }
182 }
183
184 void Entry::slider_value_changed(double value)
185 {
186         if(text.get_n_lines()>visible_rows)
187                 first_row = text.get_n_lines()-visible_rows-static_cast<unsigned>(value);
188 }
189
190 void Entry::check_view_range()
191 {
192         if(!multiline || !text_part)
193                 return;
194
195         const GL::Font *font = style->get_font();
196         float font_size = font->get_default_size();
197         unsigned line_spacing = static_cast<unsigned>(font_size*6/5);
198
199         const Sides &margin = text_part->get_margin();
200         visible_rows = max((geom.h-margin.top-margin.bottom)/line_spacing, 1U);
201
202         unsigned row, col;
203         text.offset_to_coords(edit_pos, row, col);
204
205         if(first_row>row)
206                 first_row = row;
207         else if(row>=first_row+visible_rows)
208                 first_row = row+1-visible_rows;
209
210         if(slider)
211         {
212                 unsigned scroll = max(text.get_n_lines(), visible_rows)-visible_rows;
213                 slider->set_range(0, scroll);
214                 slider->set_value(scroll-first_row);
215         }
216 }
217
218
219 Entry::Loader::Loader(Entry &ent):
220         Widget::Loader(ent)
221 { }
222
223 } // namespace GLtk
224 } // namespace Msp