- add overwrite support
[enigma2.git] / lib / gui / einput.cpp
1 #include <lib/gui/einput.h>
2 #include <lib/gdi/font.h>
3 #include <lib/actions/action.h>
4 #include <linux/input.h>
5
6 eInput::eInput(eWidget *parent): eLabel(parent)
7 {
8                 /* default to center alignment */
9         m_valign = alignCenter;
10         m_halign = alignCenter;
11
12         m_mode = 0;
13 }
14
15 eInput::~eInput()
16 {
17         mayKillFocus();
18 }
19
20 void eInput::setOverwriteMode(int m)
21 {
22         int om = m_mode;
23         m_mode = m;
24         if (om != m_mode)
25                 invalidate();
26 }
27
28 void eInput::setContent(eInputContent *content)
29 {
30         if (m_content)
31                 m_content->setInput(0);
32         m_content = content;
33         if (m_content)
34                 m_content->setInput(this);
35 }
36
37 int eInput::event(int event, void *data, void *data2)
38 {
39         switch (event)
40         {
41         case evtPaint:
42         {
43                 gPainter &painter = *(gPainter*)data2;
44                 ePtr<eWindowStyle> style;
45                 
46                 getStyle(style);
47                 
48                 eWidget::event(event, data, data2);
49                 
50                 ePtr<eTextPara> para = new eTextPara(eRect(0, 0, size().width(), size().height()));
51                 
52                 std::string text;
53                 int cursor = -1;
54                 
55                 if (m_content)
56                         m_content->getDisplay(text, cursor);
57                 
58                 eDebug("cursor is %d", cursor);
59                 para->setFont(m_font);
60                 para->renderString(text, 0);
61                 int glyphs = para->size();
62                 
63                 if (m_mode && cursor < glyphs)
64                 {
65                                 /* in overwrite mode, when not at end of line, invert the current cursor position. */
66                         para->setGlyphFlag(cursor, GS_INVERT);
67                         eRect bbox = para->getGlyphBBox(cursor);
68                         bbox = eRect(bbox.left(), 0, bbox.width() + 2, size().height());
69                         painter.fill(bbox);
70                 } else
71                 {
72                                 /* otherwise, insert small cursor */
73                         eRect bbox;
74                         if (cursor < glyphs)
75                         {
76                                 bbox = para->getGlyphBBox(cursor);
77                                 bbox = eRect(bbox.left()-1, 0, 2, size().height());
78                         } else
79                         {
80                                 bbox = para->getGlyphBBox(cursor - 1);
81                                 bbox = eRect(bbox.right(), 0, 2, size().height());
82                         }
83                         painter.fill(bbox);
84                 }
85                 
86                 painter.renderPara(para, ePoint(0, 0));
87                 
88                 return 0;
89         }
90         case evtAction:
91                 if (isVisible())
92                 {
93                         switch((int)data2)
94                         {
95                         case moveLeft:
96                                 m_content->moveCursor(eInputContent::dirLeft);
97                                 break;
98                         case moveRight:
99                                 m_content->moveCursor(eInputContent::dirRight);
100                                 break;
101                         case moveHome:
102                                 m_content->moveCursor(eInputContent::dirHome);
103                                 break;
104                         case moveEnd:
105                                 m_content->moveCursor(eInputContent::dirEnd);
106                                 break;
107                         case deleteForward:
108                                 m_content->deleteChar(eInputContent::deleteForward);
109                                 break;
110                         case deleteBackward:
111                                 m_content->deleteChar(eInputContent::deleteBackward);
112                                 break;
113                         case toggleOverwrite:
114                                 setOverwriteMode(!m_mode);
115                                 break;
116                         }
117                         return 1;
118                 }
119                 return 0;
120         case evtKey:
121         {
122                 int key = (int)data;
123                 int flags = (int)data2;
124                 if (m_content && !(flags & 1)) // only make/repeat, no break
125                         return m_content->haveKey(key, m_mode);
126                 break;
127         }
128         case evtFocusGot:
129         {
130                 eDebug("focus got in %p", this);
131                 ePtr<eActionMap> ptr;
132                 eActionMap::getInstance(ptr);
133                 ptr->bindAction("InputActions", 0, 0, this);
134                         // bind all keys
135                 ptr->bindAction("", 0, 1, this);
136                 break;
137         }
138         case evtFocusLost:
139         {
140                 eDebug("focus lostin %p", this);
141                 ePtr<eActionMap> ptr;
142                 eActionMap::getInstance(ptr);
143                 ptr->unbindAction(this, 0);
144                 ptr->unbindAction(this, 1);
145                 break;
146         }
147         default:
148                 break;
149         }
150         return eLabel::event(event, data, data2);
151 }
152
153 int eInput::getNumber()
154 {
155         return atoi(m_text.c_str());
156 }
157
158 DEFINE_REF(eInputContentNumber);
159
160 void eInputContent::setInput(eInput *widget)
161 {
162         m_input = widget;
163 }
164
165 eInputContentNumber::eInputContentNumber(int cur, int min, int max)
166 {
167         m_min = min;
168         m_max = max;
169         m_value = cur;
170         m_cursor = 0;
171         m_input = 0;
172         recalcLen();
173 }
174
175 void eInputContentNumber::getDisplay(std::string &res, int &cursor)
176 {
177         // TODO
178         char r[128];
179         sprintf(r, "%d", m_value);
180         res = r;
181         cursor = m_cursor;
182 }
183
184 void eInputContentNumber::moveCursor(int dir)
185 {
186         eDebug("move cursor..");
187         int old_cursor = m_cursor;
188         
189         switch (dir)
190         {
191         case dirLeft:
192                 --m_cursor;
193                 break;
194         case dirRight:
195                 ++m_cursor;
196                 break;
197         case dirHome:
198                 m_cursor = 0;
199                 break;
200         case dirEnd:
201                 m_cursor = m_len;
202                 break;
203         }
204         
205         if (m_cursor < 0)
206                 m_cursor = 0;
207         if (m_cursor > m_len)
208                 m_cursor = m_len;
209         
210         if (m_cursor != old_cursor)
211                 if (m_input)
212                         m_input->invalidate();
213 }
214
215 int eInputContentNumber::haveKey(int code, int overwrite)
216 {
217         int have_digit = -1;
218
219 #define ASCII(x) (x | 0x8000)
220 #define DIGIT(x) case KEY_##x: case KEY_KP##x: case ASCII(x|0x30): have_digit=x; break;
221         switch (code)
222         {
223         DIGIT(0);
224         DIGIT(1);
225         DIGIT(2);
226         DIGIT(3);
227         DIGIT(4);
228         DIGIT(5);
229         DIGIT(6);
230         DIGIT(7);
231         DIGIT(8);
232         DIGIT(9);
233         default:
234                 return 0;
235         }
236         
237         if (have_digit != -1)
238         {
239                 insertDigit(m_cursor, have_digit);
240                         /* if overwrite and not end of line, erase char first. */
241                 if (overwrite && m_cursor < m_len)
242                         insertDigit(m_cursor + 1, -1);
243                 m_cursor++;
244                 
245                 recalcLen();
246                 
247                                 // can happen when 0 -> x
248                 if (m_cursor > m_len)
249                         m_cursor = m_len;
250  
251                 if (m_input)
252                         m_input->invalidate();
253                 return 1;
254         }
255         return 0;
256 }
257
258 void eInputContentNumber::deleteChar(int dir)
259 {
260         if (dir == deleteForward)
261         {
262                 eDebug("forward");
263                 if (m_cursor != m_len)
264                         ++m_cursor;
265                 else
266                         return;
267         }
268                 /* backward delete at begin */
269         if (!m_cursor)
270                 return;
271         insertDigit(m_cursor, -1);
272         
273         if (m_len > 1)
274                 m_cursor--;
275         recalcLen();
276         if (m_input)
277                 m_input->invalidate();
278 }
279
280 int eInputContentNumber::isValid()
281 {
282         return m_value >= m_min && m_value <= m_max;
283 }
284
285 void eInputContentNumber::recalcLen()
286 {
287         int v = m_value;
288         m_len = 0;
289         while (v)
290         {
291                 ++m_len;
292                 v /= 10;
293         }
294         
295         if (!m_len) /* zero */
296                 m_len = 1;
297 }
298
299 void eInputContentNumber::insertDigit(int pos, int dig)
300 {
301                 /* get stuff left from cursor */
302         int exp = 1;
303         int i;
304         for (i = 0; i < (m_len - pos); ++i)
305                 exp *= 10;
306         
307                 /* now it's 1...max */
308         int left = m_value / exp;
309         int right = m_value % exp;
310         
311         if (dig >= 0)
312         {
313                 left *= 10;
314                 left += dig;
315         } else if (dig == -1) /* delete */
316         {
317                 left /= 10;
318         }
319         
320         left *= exp;
321         left += right;
322         m_value = left;
323 }