209b525094537fd09cec612252f20f79a591a9c7
[enigma2.git] / lib / gui / elistboxcontent.cpp
1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <Python.h>
4
5 /*
6     The basic idea is to have an interface which gives all relevant list
7     processing functions, and can be used by the listbox to browse trough
8     the list.
9     
10     The listbox directly uses the implemented cursor. It tries hard to avoid
11     iterating trough the (possibly very large) list, so it should be O(1),
12     i.e. the performance should not be influenced by the size of the list.
13     
14     The list interface knows how to draw the current entry to a specified 
15     offset. Different interfaces can be used to adapt different lists,
16     pre-filter lists on the fly etc.
17     
18                 cursorSave/Restore is used to avoid re-iterating the list on redraw.
19                 The current selection is always selected as cursor position, the
20     cursor is then positioned to the start, and then iterated. This gives
21     at most 2x m_items_per_page cursor movements per redraw, indepenent
22     of the size of the list.
23     
24     Although cursorSet is provided, it should be only used when there is no
25     other way, as it involves iterating trough the list.
26  */
27
28 iListboxContent::~iListboxContent()
29 {
30 }
31
32 iListboxContent::iListboxContent(): m_listbox(0)
33 {
34 }
35
36 void iListboxContent::setListbox(eListbox *lb)
37 {
38         m_listbox = lb;
39 }
40
41 DEFINE_REF(eListboxTestContent);
42
43 void eListboxTestContent::cursorHome()
44 {
45         m_cursor = 0;
46 }
47
48 void eListboxTestContent::cursorEnd()
49 {
50         m_cursor = size();
51 }
52
53 int eListboxTestContent::cursorMove(int count)
54 {
55         m_cursor += count;
56         
57         if (m_cursor < 0)
58                 cursorHome();
59         else if (m_cursor > size())
60                 cursorEnd();
61         return 0;
62 }
63
64 int eListboxTestContent::cursorValid()
65 {
66         return m_cursor < size();
67 }
68
69 int eListboxTestContent::cursorSet(int n)
70 {
71         m_cursor = n;
72         
73         if (m_cursor < 0)
74                 cursorHome();
75         else if (m_cursor > size())
76                 cursorEnd();
77         return 0;
78 }
79
80 int eListboxTestContent::cursorGet()
81 {
82         return m_cursor;
83 }
84
85 void eListboxTestContent::cursorSave()
86 {
87         m_saved_cursor = m_cursor;
88 }
89
90 void eListboxTestContent::cursorRestore()
91 {
92         m_cursor = m_saved_cursor;
93 }
94
95 int eListboxTestContent::size()
96 {
97         return 10;
98 }
99         
100 RESULT eListboxTestContent::connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection)
101 {
102         return 0;
103 }
104
105 void eListboxTestContent::setSize(const eSize &size)
106 {
107         m_size = size;
108 }
109
110 void eListboxTestContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
111 {
112         ePtr<gFont> fnt = new gFont("Arial", 14);
113         painter.clip(eRect(offset, m_size));
114         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
115         painter.clear();
116
117         if (cursorValid())
118         {
119                 painter.setFont(fnt);
120                 char string[10];
121                 sprintf(string, "%d.)", m_cursor);
122                 
123                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
124                 
125                 painter.renderText(eRect(text_offset, m_size), string);
126                 
127                 if (selected)
128                         style.drawFrame(painter, eRect(offset, m_size), eWindowStyle::frameListboxEntry);
129         }
130         
131         painter.clippop();
132 }
133
134 //////////////////////////////////////
135
136 DEFINE_REF(eListboxStringContent);
137
138 eListboxStringContent::eListboxStringContent()
139 {
140         m_size = 0;
141         cursorHome();
142 }
143
144 void eListboxStringContent::cursorHome()
145 {
146         m_cursor = m_list.begin();
147         m_cursor_number = 0;
148 }
149
150 void eListboxStringContent::cursorEnd()
151 {
152         m_cursor = m_list.end();
153         m_cursor_number = m_size;
154 }
155
156 int eListboxStringContent::cursorMove(int count)
157 {
158         if (count > 0)
159         {
160                 while (count && (m_cursor != m_list.end()))
161                 {
162                         ++m_cursor;
163                         ++m_cursor_number;
164                         --count;
165                 }
166         } else if (count < 0)
167         {
168                 while (count && (m_cursor != m_list.begin()))
169                 {
170                         --m_cursor;
171                         --m_cursor_number;
172                         ++count;
173                 }
174         }
175         
176         return 0;
177 }
178
179 int eListboxStringContent::cursorValid()
180 {
181         return m_cursor != m_list.end();
182 }
183
184 int eListboxStringContent::cursorSet(int n)
185 {
186         cursorHome();
187         cursorMove(n);
188         
189         return 0;
190 }
191
192 int eListboxStringContent::cursorGet()
193 {
194         return m_cursor_number;
195 }
196
197 void eListboxStringContent::cursorSave()
198 {
199         m_saved_cursor = m_cursor;
200         m_saved_cursor_number = m_cursor_number;
201 }
202
203 void eListboxStringContent::cursorRestore()
204 {
205         m_cursor = m_saved_cursor;
206         m_cursor_number = m_saved_cursor_number;
207 }
208
209 int eListboxStringContent::size()
210 {
211         return m_size;
212 }
213         
214 void eListboxStringContent::setSize(const eSize &size)
215 {
216         m_itemsize = size;
217 }
218
219 void eListboxStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
220 {
221         ePtr<gFont> fnt = new gFont("Arial", 14);
222         painter.clip(eRect(offset, m_itemsize));
223         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
224         painter.clear();
225         
226         eDebug("item %d", m_cursor_number);
227         if (cursorValid())
228         {
229                 eDebug("is valid..");
230                 painter.setFont(fnt);
231                 
232                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
233                 
234                 painter.renderText(eRect(text_offset, m_itemsize), *m_cursor);
235                 
236                 if (selected)
237                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
238         }
239         
240         painter.clippop();
241 }
242
243 void eListboxStringContent::setList(std::list<std::string> &list)
244 {
245         m_list = list;
246         m_size = list.size();
247         cursorHome();
248 }
249
250 //////////////////////////////////////
251
252 DEFINE_REF(eListboxPythonStringContent);
253
254 eListboxPythonStringContent::eListboxPythonStringContent()
255 {
256         m_list = 0;
257 }
258
259 eListboxPythonStringContent::~eListboxPythonStringContent()
260 {
261 }
262
263 void eListboxPythonStringContent::cursorHome()
264 {
265         m_cursor = 0;
266 }
267
268 void eListboxPythonStringContent::cursorEnd()
269 {
270         m_cursor = size();
271 }
272
273 int eListboxPythonStringContent::cursorMove(int count)
274 {
275         m_cursor += count;
276         
277         if (m_cursor < 0)
278                 cursorHome();
279         else if (m_cursor > size())
280                 cursorEnd();
281         return 0;
282 }
283
284 int eListboxPythonStringContent::cursorValid()
285 {
286         return m_cursor < size();
287 }
288
289 int eListboxPythonStringContent::cursorSet(int n)
290 {
291         m_cursor = n;
292         
293         if (m_cursor < 0)
294                 cursorHome();
295         else if (m_cursor > size())
296                 cursorEnd();
297         return 0;
298 }
299
300 int eListboxPythonStringContent::cursorGet()
301 {
302         return m_cursor;
303 }
304
305 void eListboxPythonStringContent::cursorSave()
306 {
307         m_saved_cursor = m_cursor;
308 }
309
310 void eListboxPythonStringContent::cursorRestore()
311 {
312         m_cursor = m_saved_cursor;
313 }
314
315 int eListboxPythonStringContent::size()
316 {
317         if (!m_list)
318                 return 0;
319         return PyList_Size(m_list);
320 }
321         
322 void eListboxPythonStringContent::setSize(const eSize &size)
323 {
324         m_itemsize = size;
325 }
326
327 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
328 {
329         ePtr<gFont> fnt = new gFont("Arial", 14);
330         painter.clip(eRect(offset, m_itemsize));
331         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
332         painter.clear();
333
334         if (m_list && cursorValid())
335         {
336                 PyObject *item = PyList_GetItem(m_list, m_cursor); // borrowed reference!
337                 painter.setFont(fnt);
338
339                         /* the user can supply tuples, in this case the first one will be displayed. */         
340                 if (PyTuple_Check(item))
341                         item = PyTuple_GetItem(item, 0);
342                 
343                 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
344                 
345                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
346                 
347                 painter.renderText(eRect(text_offset, m_itemsize), string);
348                 
349                 if (selected)
350                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
351         }
352         
353         painter.clippop();
354 }
355
356 void eListboxPythonStringContent::setList(PyObject *list)
357 {
358         Py_XDECREF(m_list);
359         if (!PyList_Check(list))
360         {
361                 m_list = 0;
362         } else
363         {
364                 m_list = list;
365                 Py_INCREF(m_list);
366         }
367 }
368
369 PyObject *eListboxPythonStringContent::getCurrentSelection()
370 {
371         if (!m_list)
372                 return 0;
373         if (!cursorValid())
374                 return 0;
375         PyObject *r = PyList_GetItem(m_list, m_cursor);
376         Py_XINCREF(r);
377         return r;
378 }
379
380 //////////////////////////////////////