- work on einput widget
[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         ePtr<eActionMap> ptr;
13         eActionMap::getInstance(ptr);
14         ptr->bindAction("InputActions", 0, 0, this);
15         
16                 // bind all keys
17         ptr->bindAction("", 0, 1, this);
18 }
19
20 eInput::~eInput()
21 {
22         ePtr<eActionMap> ptr;
23         eActionMap::getInstance(ptr);
24         ptr->unbindAction(this, 0);
25         ptr->unbindAction(this, 1);
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                 
62                 int glyphs = para->size();
63                 eRect bbox;
64                 if (cursor < glyphs)
65                 {
66                         bbox = para->getGlyphBBox(cursor);
67                         bbox = eRect(bbox.left()-1, 0, 2, size().height());
68                 } else
69                 {
70                         bbox = para->getGlyphBBox(cursor - 1);
71                         bbox = eRect(bbox.right(), 0, 2, size().height());
72                 }
73                 painter.fill(bbox);
74                 
75                 painter.renderPara(para, ePoint(0, 0));
76                 
77                 return 0;
78         }
79         case evtAction:
80                 if (isVisible())
81                 {
82                         switch((int)data2)
83                         {
84                         case moveLeft:
85                                 m_content->moveCursor(eInputContent::dirLeft);
86                                 break;
87                         case moveRight:
88                                 m_content->moveCursor(eInputContent::dirRight);
89                                 break;
90                         case moveHome:
91                                 m_content->moveCursor(eInputContent::dirHome);
92                                 break;
93                         case moveEnd:
94                                 m_content->moveCursor(eInputContent::dirEnd);
95                                 break;
96                         case deleteForward:
97                                 m_content->deleteChar(eInputContent::deleteForward);
98                                 break;
99                         case deleteBackward:
100                                 m_content->deleteChar(eInputContent::deleteBackward);
101                                 break;
102                         }
103                         return 1;
104                 }
105                 return 0;
106         case evtKey:
107         {
108                 int key = (int)data;
109                 int flags = (int)data2;
110                 if (m_content && !(flags & 1))
111                         m_content->haveKey(key);
112                 break;
113         }
114         default:
115                 break;
116         }
117         return eLabel::event(event, data, data2);
118 }
119
120 int eInput::getNumber()
121 {
122         return atoi(m_text.c_str());
123 }
124
125 DEFINE_REF(eInputContentNumber);
126
127 void eInputContent::setInput(eInput *widget)
128 {
129         m_input = widget;
130 }
131
132 eInputContentNumber::eInputContentNumber(int cur, int min, int max)
133 {
134         m_min = min;
135         m_max = max;
136         m_value = cur;
137         m_cursor = 0;
138         m_input = 0;
139         recalcLen();
140 }
141
142 void eInputContentNumber::getDisplay(std::string &res, int &cursor)
143 {
144         // TODO
145         char r[128];
146         sprintf(r, "%d", m_value);
147         res = r;
148         cursor = m_cursor;
149 }
150
151 void eInputContentNumber::moveCursor(int dir)
152 {
153         eDebug("move cursor..");
154         int old_cursor = m_cursor;
155         
156         switch (dir)
157         {
158         case dirLeft:
159                 --m_cursor;
160                 break;
161         case dirRight:
162                 ++m_cursor;
163                 break;
164         case dirHome:
165                 m_cursor = 0;
166                 break;
167         case dirEnd:
168                 m_cursor = m_len;
169                 break;
170         }
171         
172         if (m_cursor < 0)
173                 m_cursor = 0;
174         if (m_cursor > m_len)
175                 m_cursor = m_len;
176         
177         if (m_cursor != old_cursor)
178                 if (m_input)
179                         m_input->invalidate();
180 }
181
182 int eInputContentNumber::haveKey(int code)
183 {
184         int have_digit = -1;
185
186 #define ASCII(x) (x | 0x8000)
187 #define DIGIT(x) case KEY_##x: case KEY_KP##x: case ASCII(x|0x30): have_digit=x; break;
188         switch (code)
189         {
190         DIGIT(0);
191         DIGIT(1);
192         DIGIT(2);
193         DIGIT(3);
194         DIGIT(4);
195         DIGIT(5);
196         DIGIT(6);
197         DIGIT(7);
198         DIGIT(8);
199         DIGIT(9);
200         }
201         
202         if (have_digit != -1)
203         {
204                 insertDigit(m_cursor, have_digit);
205                 m_cursor++;
206                 
207                 recalcLen();
208                 
209                                 // can happen when 0 -> x
210                 if (m_cursor > m_len)
211                         m_cursor = m_len;
212  
213                 if (m_input)
214                         m_input->invalidate();
215         }
216         return 0;
217 }
218
219 void eInputContentNumber::deleteChar(int dir)
220 {
221         if (dir == deleteForward)
222         {
223                 eDebug("forward");
224                 if (m_cursor != m_len)
225                         ++m_cursor;
226                 else
227                         return;
228         }
229                 /* backward delete at begin */
230         if (!m_cursor)
231                 return;
232         insertDigit(m_cursor, -1);
233         
234         if (m_len > 1)
235                 m_cursor--;
236         recalcLen();
237         if (m_input)
238                 m_input->invalidate();
239 }
240
241 int eInputContentNumber::isValid()
242 {
243         return m_value >= m_min && m_value <= m_max;
244 }
245
246 void eInputContentNumber::recalcLen()
247 {
248         int v = m_value;
249         m_len = 0;
250         while (v)
251         {
252                 ++m_len;
253                 v /= 10;
254         }
255         
256         if (!m_len) /* zero */
257                 m_len = 1;
258 }
259
260 void eInputContentNumber::insertDigit(int pos, int dig)
261 {
262                 /* get stuff left from cursor */
263         int exp = 1;
264         int i;
265         for (i = 0; i < (m_len - pos); ++i)
266                 exp *= 10;
267         
268                 /* now it's 1...max */
269         int left = m_value / exp;
270         int right = m_value % exp;
271         
272         if (dig >= 0)
273         {
274                 left *= 10;
275                 left += dig;
276         } else if (dig == -1) /* delete */
277         {
278                 left /= 10;
279         }
280         
281         left *= exp;
282         left += right;
283         m_value = left;
284 }