add possibility to set a callable check function
[enigma2.git] / lib / gui / elistboxcontent.cpp
1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <lib/gdi/font.h>
4 #include <lib/python/python.h>
5
6 /*
7     The basic idea is to have an interface which gives all relevant list
8     processing functions, and can be used by the listbox to browse trough
9     the list.
10     
11     The listbox directly uses the implemented cursor. It tries hard to avoid
12     iterating trough the (possibly very large) list, so it should be O(1),
13     i.e. the performance should not be influenced by the size of the list.
14     
15     The list interface knows how to draw the current entry to a specified 
16     offset. Different interfaces can be used to adapt different lists,
17     pre-filter lists on the fly etc.
18     
19                 cursorSave/Restore is used to avoid re-iterating the list on redraw.
20                 The current selection is always selected as cursor position, the
21     cursor is then positioned to the start, and then iterated. This gives
22     at most 2x m_items_per_page cursor movements per redraw, indepenent
23     of the size of the list.
24     
25     Although cursorSet is provided, it should be only used when there is no
26     other way, as it involves iterating trough the list.
27  */
28
29 iListboxContent::~iListboxContent()
30 {
31 }
32
33 iListboxContent::iListboxContent(): m_listbox(0)
34 {
35 }
36
37 void iListboxContent::setListbox(eListbox *lb)
38 {
39         m_listbox = lb;
40         m_listbox->setItemHeight(getItemHeight());
41 }
42
43 int iListboxContent::currentCursorSelectable()
44 {
45         return 1;
46 }
47
48 //////////////////////////////////////
49
50 DEFINE_REF(eListboxPythonStringContent);
51
52 eListboxPythonStringContent::eListboxPythonStringContent(): m_itemheight(25)
53 {
54 }
55
56 eListboxPythonStringContent::~eListboxPythonStringContent()
57 {
58         Py_XDECREF(m_list);
59 }
60
61 void eListboxPythonStringContent::cursorHome()
62 {
63         m_cursor = 0;
64 }
65
66 void eListboxPythonStringContent::cursorEnd()
67 {
68         m_cursor = size();
69 }
70
71 int eListboxPythonStringContent::cursorMove(int count)
72 {
73         m_cursor += count;
74         
75         if (m_cursor < 0)
76                 cursorHome();
77         else if (m_cursor > size())
78                 cursorEnd();
79         return 0;
80 }
81
82 int eListboxPythonStringContent::cursorValid()
83 {
84         return m_cursor < size();
85 }
86
87 int eListboxPythonStringContent::cursorSet(int n)
88 {
89         m_cursor = n;
90         
91         if (m_cursor < 0)
92                 cursorHome();
93         else if (m_cursor > size())
94                 cursorEnd();
95         return 0;
96 }
97
98 int eListboxPythonStringContent::cursorGet()
99 {
100         return m_cursor;
101 }
102
103 int eListboxPythonStringContent::currentCursorSelectable()
104 {
105         if (m_list && cursorValid())
106         {
107                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
108                 if (!PyTuple_Check(item))
109                         return 1;
110                 if (PyTuple_Size(item) >= 2)
111                         return 1;
112         }
113         return 0;
114 }
115
116 void eListboxPythonStringContent::cursorSave()
117 {
118         m_saved_cursor = m_cursor;
119 }
120
121 void eListboxPythonStringContent::cursorRestore()
122 {
123         m_cursor = m_saved_cursor;
124 }
125
126 int eListboxPythonStringContent::size()
127 {
128         if (!m_list)
129                 return 0;
130         return PyList_Size(m_list);
131 }
132         
133 void eListboxPythonStringContent::setSize(const eSize &size)
134 {
135         m_itemsize = size;
136 }
137
138 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
139 {
140         ePtr<gFont> fnt = new gFont("Regular", 20);
141         painter.clip(eRect(offset, m_itemsize));
142         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
143         painter.clear();
144
145         if (m_list && cursorValid())
146         {
147                 int gray = 0;
148                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
149                 painter.setFont(fnt);
150
151                         /* the user can supply tuples, in this case the first one will be displayed. */         
152                 if (PyTuple_Check(item))
153                 {
154                         if (PyTuple_Size(item) == 1)
155                                 gray = 1;
156                         item = PyTuple_GET_ITEM(item, 0);
157                 }
158                 
159                 if (item == Py_None)
160                 {
161                         int half_height = m_itemsize.height() / 2;
162                         
163                         painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
164                 } else
165                 {
166                         const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
167                         ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
168                         if (gray)
169                                 painter.setForegroundColor(gRGB(0x808080));
170                         painter.renderText(eRect(text_offset, m_itemsize), string);
171                 }
172                 
173                 if (selected)
174                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
175         }
176         
177         painter.clippop();
178 }
179
180 void eListboxPythonStringContent::setList(ePyObject list)
181 {
182         Py_XDECREF(m_list);
183         if (!PyList_Check(list))
184         {
185                 m_list = ePyObject();
186         } else
187         {
188                 m_list = list;
189                 Py_INCREF(m_list);
190         }
191
192         if (m_listbox)
193                 m_listbox->entryReset(false);
194 }
195
196 PyObject *eListboxPythonStringContent::getCurrentSelection()
197 {
198         if (!(m_list && cursorValid()))
199                 Py_RETURN_NONE;
200
201         ePyObject r = PyList_GET_ITEM(m_list, m_cursor);
202         Py_XINCREF(r);
203         return r;
204 }
205
206 void eListboxPythonStringContent::invalidateEntry(int index)
207 {
208         if (m_listbox)
209                 m_listbox->entryChanged(index);
210 }
211
212 void eListboxPythonStringContent::invalidate()
213 {
214         if (m_listbox)
215         {
216                 int s = size();
217                 if ( m_cursor >= s )
218                         m_listbox->moveSelectionTo(s?s-1:0);
219                 m_listbox->invalidate();
220         }
221 }
222
223 //////////////////////////////////////
224
225 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
226 {
227         ePtr<gFont> fnt = new gFont("Regular", 20);
228         ePtr<gFont> fnt2 = new gFont("Regular", 16);
229         eRect itemrect(offset, m_itemsize);
230         painter.clip(itemrect);
231         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
232         painter.clear();
233
234         if (m_list && cursorValid())
235         {
236                         /* get current list item */
237                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
238                 ePyObject text, value;
239                 painter.setFont(fnt);
240
241                         /* the first tuple element is a string for the left side.
242                            the second one will be called, and the result shall be an tuple.
243                            
244                            of this tuple,
245                            the first one is the type (string).
246                            the second one is the value. */
247                 if (PyTuple_Check(item))
248                 {
249                                 /* handle left part. get item from tuple, convert to string, display. */
250                                 
251                         text = PyTuple_GET_ITEM(item, 0);
252                         text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
253                         const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
254                         eSize item_left = eSize(m_seperation, m_itemsize.height());
255                         eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
256                         painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
257                         Py_XDECREF(text);
258                         
259                                 /* when we have no label, align value to the left. (FIXME: 
260                                    don't we want to specifiy this individually?) */
261                         int value_alignment_left = !*string;
262                         
263                                 /* now, handle the value. get 2nd part from tuple*/
264                         value = PyTuple_GET_ITEM(item, 1);
265                         if (value)
266                         {
267                                 ePyObject args = PyTuple_New(1);
268                                 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
269                                 
270                                         /* CallObject will call __call__ which should return the value tuple */
271                                 value = PyObject_CallObject(value, args);
272                                 
273                                 if (PyErr_Occurred())
274                                         PyErr_Print();
275
276                                 Py_DECREF(args);
277                                         /* the PyInt was stolen. */
278                         }
279                         
280                                 /*  check if this is really a tuple */
281                         if (value && PyTuple_Check(value))
282                         {
283                                         /* convert type to string */
284                                 ePyObject type = PyTuple_GET_ITEM(value, 0);
285                                 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
286                                 
287                                 if (atype)
288                                 {
289                                         if (!strcmp(atype, "text"))
290                                         {
291                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
292                                                 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
293                                                 painter.setFont(fnt2);
294                                                 if (value_alignment_left)
295                                                         painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
296                                                 else
297                                                         painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
298
299                                                         /* pvalue is borrowed */
300                                         } else if (!strcmp(atype, "slider"))
301                                         {
302                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
303                                                 ePyObject psize = PyTuple_GET_ITEM(value, 2);
304                                                 
305                                                         /* convert value to Long. fallback to -1 on error. */
306                                                 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
307                                                 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
308                                                 
309                                                         /* calc. slider length */
310                                                 int width = item_right.width() * value / size;
311                                                 int height = item_right.height();
312                                                 
313                                                                                                 
314                                                         /* draw slider */
315                                                 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
316                                                 //hack - make it customizable
317                                                 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
318                                                 
319                                                         /* pvalue is borrowed */
320                                         } else if (!strcmp(atype, "mtext"))
321                                         {
322                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
323                                                 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
324                                                 int xoffs = value_alignment_left ? 0 : m_seperation;
325                                                 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
326                                                 para->setFont(fnt2);
327                                                 para->renderString(text, 0);
328                                                 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
329                                                 int glyphs = para->size();
330                                                 
331                                                 ePyObject plist;
332                                                 
333                                                 if (PyTuple_Size(value) >= 3)
334                                                         plist = PyTuple_GET_ITEM(value, 2);
335                                                 
336                                                 int entries = 0;
337
338                                                 if (plist && PyList_Check(plist))
339                                                         entries = PyList_Size(plist);
340                                                 
341                                                 for (int i = 0; i < entries; ++i)
342                                                 {
343                                                         ePyObject entry = PyList_GET_ITEM(plist, i);
344                                                         int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
345                                                         
346                                                         if ((num < 0) || (num >= glyphs))
347                                                                 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
348                                                         else
349                                                         {
350                                                                 para->setGlyphFlag(num, GS_INVERT);
351                                                                 eRect bbox;
352                                                                 bbox = para->getGlyphBBox(num);
353                                                                 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
354                                                                 painter.fill(bbox);
355                                                         }
356                                                                 /* entry is borrowed */
357                                                 }
358                                                 
359                                                 painter.renderPara(para, ePoint(0, 0));
360                                                         /* pvalue is borrowed */
361                                                         /* plist is 0 or borrowed */
362                                         }
363                                 }
364                                         /* type is borrowed */
365                         } else
366                                 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
367                                 /* value is borrowed */
368                 }
369
370                 if (selected)
371                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
372         }
373         
374         painter.clippop();
375 }
376
377 int eListboxPythonConfigContent::currentCursorSelectable()
378 {
379         return eListboxPythonStringContent::currentCursorSelectable();
380 }
381
382 //////////////////////////////////////
383
384         /* todo: make a real infrastructure here! */
385 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
386
387 eListboxPythonMultiContent::eListboxPythonMultiContent()
388         :m_temp_clip(gRegion::invalidRegion())
389 {
390 }
391
392 eListboxPythonMultiContent::~eListboxPythonMultiContent()
393 {
394         Py_XDECREF(m_buildFunc);
395         Py_XDECREF(m_callableFunc);
396 }
397
398 void eListboxPythonMultiContent::setSelectionClip(eRect &rect, bool update)
399 {
400         if (update && m_selection_clip.valid())
401         {
402                 m_temp_clip = m_selection_clip;
403                 m_temp_clip |= rect;
404                 m_selection_clip = rect;
405                 if (m_listbox)
406                         m_listbox->entryChanged(m_cursor);
407         }
408         else
409                 m_selection_clip = rect;
410 }
411
412 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
413 {
414         gRegion itemregion(eRect(offset, m_itemsize));
415
416         eRect sel_clip(m_selection_clip);
417         if (sel_clip.valid())
418                 sel_clip.moveBy(offset);
419
420         if (m_temp_clip.valid())
421         {
422                 m_temp_clip.moveBy(offset);
423                 itemregion &= m_temp_clip;
424                 m_temp_clip = eRect();
425         }
426
427         painter.clip(itemregion);
428
429         ePyObject items;
430
431         if (m_list && cursorValid())
432         {
433                 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
434
435                 if (m_buildFunc)
436                 {
437                         if (PyCallable_Check(m_buildFunc))  // when we have a buildFunc then call it
438                         {
439                                 if (PyTuple_Check(items))
440                                         items = PyObject_CallObject(m_buildFunc, items);
441                                 else
442                                         eDebug("items is no tuple");
443                         }
444                         else
445                                 eDebug("buildfunc is not callable");
446                 }
447
448                 if (!items)
449                 {
450                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
451                         goto error_out;
452                 }
453
454                 if (!PyList_Check(items))
455                 {
456                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
457                         goto error_out;
458                 }
459
460                 int size = PyList_Size(items);
461                 for (int i = 1; i < size; ++i)
462                 {
463                         ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
464
465                         if (!item)
466                         {
467                                 eDebug("eListboxPythonMultiContent: ?");
468                                 goto error_out;
469                         }
470
471                         if (!PyTuple_Check(item))
472                         {
473                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
474                                 goto error_out;
475                         }
476
477                         int size = PyTuple_Size(item);
478
479                         if (!size)
480                         {
481                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
482                                 goto error_out;
483                         }
484
485                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
486
487                         switch (type)
488                         {
489                         case TYPE_TEXT: // text
490                         {
491                         /*
492                                 (0, x, y, width, height, fnt, flags, "bla" [, color] )
493                         */
494                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
495                                                         py = PyTuple_GET_ITEM(item, 2),
496                                                         pwidth = PyTuple_GET_ITEM(item, 3),
497                                                         pheight = PyTuple_GET_ITEM(item, 4),
498                                                         pfnt = PyTuple_GET_ITEM(item, 5),
499                                                         pflags = PyTuple_GET_ITEM(item, 6),
500                                                         pstring = PyTuple_GET_ITEM(item, 7),
501                                                         pforeColor, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
502
503                                 if (!(px && py && pwidth && pheight && pfnt && pflags && pstring))
504                                 {
505                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string, [color, ]...])");
506                                         goto error_out;
507                                 }
508
509                                 if (size > 8)
510                                 {
511                                         pforeColor = PyTuple_GET_ITEM(item, 8);
512                                         if (pforeColor == Py_None)
513                                                 pforeColor=ePyObject();
514                                 }
515                                 if (size > 9)
516                                 {
517                                         pbackColor = PyTuple_GET_ITEM(item, 9);
518                                         if (pbackColor == Py_None)
519                                                 pbackColor=ePyObject();
520                                 }
521                                 if (size > 10)
522                                 {
523                                         pbackColorSelected = PyTuple_GET_ITEM(item, 10);
524                                         if (pbackColorSelected == Py_None)
525                                                 pbackColorSelected=ePyObject();
526                                 }
527                                 if (size > 11)
528                                         pborderWidth = PyTuple_GET_ITEM(item, 11);
529                                 if (size > 12)
530                                         pborderColor = PyTuple_GET_ITEM(item, 12);
531
532                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
533                                 int x = PyInt_AsLong(px) + offset.x();
534                                 int y = PyInt_AsLong(py) + offset.y();
535                                 int width = PyInt_AsLong(pwidth);
536                                 int height = PyInt_AsLong(pheight);
537                                 int flags = PyInt_AsLong(pflags);
538                                 int fnt = PyInt_AsLong(pfnt);
539                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
540
541                                 if (m_font.find(fnt) == m_font.end())
542                                 {
543                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
544                                         goto error_out;
545                                 }
546
547                                 eRect rect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
548                                 gRegion rc(rect);
549                                 rc &= itemregion;
550                                 painter.clip(rc);
551                                 itemregion -= rc;
552                                 if (selected && sel_clip.valid())
553                                 {
554                                         painter.clip(rc-sel_clip);
555                                         if (pbackColor)
556                                         {
557                                                 int color = PyInt_AsLong(pbackColor);
558                                                 painter.setBackgroundColor(gRGB(color));
559                                         }
560                                         else
561                                                 style.setStyle(painter, eWindowStyle::styleListboxNormal);
562                                         painter.clear();
563                                         painter.clippop();
564                                         painter.clip(rc&sel_clip);
565                                         style.setStyle(painter, eWindowStyle::styleListboxSelected);
566                                         if (pbackColorSelected)
567                                         {
568                                                 int color = PyInt_AsLong(pbackColorSelected);
569                                                 painter.setBackgroundColor(gRGB(color));
570                                         }
571                                         painter.clear();
572                                         painter.clippop();
573                                 }
574                                 else
575                                 {
576                                         if (selected)
577                                         {
578                                                 style.setStyle(painter, eWindowStyle::styleListboxSelected);
579                                                 if (pbackColorSelected)
580                                                 {
581                                                         int color = PyInt_AsLong(pbackColorSelected);
582                                                         painter.setBackgroundColor(gRGB(color));
583                                                 }
584                                         }
585                                         else
586                                         {
587                                                 style.setStyle(painter, eWindowStyle::styleListboxNormal);
588                                                 if (pbackColor)
589                                                 {
590                                                         int color = PyInt_AsLong(pbackColor);
591                                                         painter.setBackgroundColor(gRGB(color));
592                                                 }
593                                         }
594                                         painter.clear();
595                                 }
596
597                                 if (pforeColor)
598                                 {
599                                         int color = PyInt_AsLong(pforeColor);
600                                         painter.setForegroundColor(gRGB(color));
601                                 }
602
603                                 painter.setFont(m_font[fnt]);
604                                 painter.renderText(rect, string, flags);
605                                 painter.clippop();
606
607                                 // draw border
608                                 if (bwidth)
609                                 {
610                                         eRect rect(eRect(x, y, width, height));
611                                         gRegion rc(rect);
612                                         rc &= itemregion;
613                                         painter.clip(rc);
614                                         itemregion -= rc;
615                                         if (pborderColor)
616                                         {
617                                                 int color = PyInt_AsLong(pborderColor);
618                                                 painter.setForegroundColor(gRGB(color));
619                                         }
620                                         else if (pforeColor) // reset to normal color
621                                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
622
623                                         rect.setRect(x, y, width, bwidth);
624                                         painter.fill(rect);
625
626                                         rect.setRect(x, y+bwidth, bwidth, height-bwidth);
627                                         painter.fill(rect);
628
629                                         rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
630                                         painter.fill(rect);
631
632                                         rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
633                                         painter.fill(rect);
634
635                                         painter.clippop();
636                                 }
637                                 break;
638                         }
639                         case TYPE_PROGRESS: // Progress
640                         {
641                         /*
642                                 (1, x, y, width, height, filled_percent )
643                         */
644                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
645                                                         py = PyTuple_GET_ITEM(item, 2),
646                                                         pwidth = PyTuple_GET_ITEM(item, 3),
647                                                         pheight = PyTuple_GET_ITEM(item, 4),
648                                                         pfilled_perc = PyTuple_GET_ITEM(item, 5);
649
650                                 if (!(px && py && pwidth && pheight && pfilled_perc))
651                                 {
652                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
653                                         goto error_out;
654                                 }
655
656                                 int x = PyInt_AsLong(px) + offset.x();
657                                 int y = PyInt_AsLong(py) + offset.y();
658                                 int width = PyInt_AsLong(pwidth);
659                                 int height = PyInt_AsLong(pheight);
660                                 int filled = PyInt_AsLong(pfilled_perc);
661
662                                 eRect rect(x, y, width, height);
663                                 gRegion rc(rect);
664                                 rc &= itemregion;
665                                 painter.clip(rc);
666                                 itemregion -= rc;
667                                 if (selected && sel_clip.valid())
668                                 {
669                                         painter.clip(rc-sel_clip);
670                                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
671                                         painter.clear();
672                                         painter.clippop();
673                                         painter.clip(rc&sel_clip);
674                                         style.setStyle(painter, eWindowStyle::styleListboxSelected);
675                                         painter.clear();
676                                         painter.clippop();
677                                 }
678                                 else
679                                 {
680                                         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
681                                         painter.clear();
682                                 }
683
684                                 int bwidth=2;  // borderwidth hardcoded yet
685
686                                 // border
687                                 rect.setRect(x, y, width, bwidth);
688                                 painter.fill(rect);
689
690                                 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
691                                 painter.fill(rect);
692
693                                 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
694                                 painter.fill(rect);
695
696                                 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
697                                 painter.fill(rect);
698
699                                 // progress
700                                 rect.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
701                                 painter.fill(rect);
702
703                                 painter.clippop();
704
705                                 break;
706                         }
707                         case TYPE_PIXMAP_ALPHATEST:
708                         case TYPE_PIXMAP: // pixmap
709                         {
710                         /*
711                                 (2, x, y, width, height, pixmap )
712                         */
713
714                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
715                                                         py = PyTuple_GET_ITEM(item, 2),
716                                                         pwidth = PyTuple_GET_ITEM(item, 3),
717                                                         pheight = PyTuple_GET_ITEM(item, 4),
718                                                         ppixmap = PyTuple_GET_ITEM(item, 5);
719
720                                 if (!(px && py && pwidth && pheight && ppixmap))
721                                 {
722                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
723                                         goto error_out;
724                                 }
725
726                                 int x = PyInt_AsLong(px) + offset.x();
727                                 int y = PyInt_AsLong(py) + offset.y();
728                                 int width = PyInt_AsLong(pwidth);
729                                 int height = PyInt_AsLong(pheight);
730                                 ePtr<gPixmap> pixmap;
731                                 if (SwigFromPython(pixmap, ppixmap))
732                                 {
733                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
734                                         goto error_out;
735                                 }
736
737                                 eRect rect(x, y, width, height);
738                                 gRegion rc(rect);
739                                 rc &= itemregion;
740                                 painter.clip(rc);
741                                 itemregion -= rc;
742
743                                 if (selected && sel_clip.valid())
744                                 {
745                                         painter.clip(rc-sel_clip);
746                                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
747                                         painter.clear();
748                                         painter.clippop();
749                                         painter.clip(rc&sel_clip);
750                                         style.setStyle(painter, eWindowStyle::styleListboxSelected);
751                                         painter.clear();
752                                         painter.clippop();
753                                 }
754                                 else
755                                 {
756                                         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
757                                         painter.clear();
758                                 }
759
760                                 painter.blit(pixmap, rect.topLeft(), rect, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
761                                 painter.clippop();
762
763                                 break;
764                         }
765                         default:
766                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
767                                 goto error_out;
768                         }
769                 }
770         }
771
772         if (selected && sel_clip.valid())
773         {
774                 painter.clip(itemregion-sel_clip);
775                 style.setStyle(painter, eWindowStyle::styleListboxNormal);
776                 painter.clear();
777                 painter.clippop();
778                 itemregion &= sel_clip;
779                 painter.clip(itemregion);
780                 style.setStyle(painter, eWindowStyle::styleListboxSelected);
781                 painter.clear();
782                 painter.clippop();
783         }
784         else
785         {
786                 painter.clip(itemregion);
787                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
788                 painter.clear();
789                 painter.clippop();
790         }
791
792         if (selected)
793                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
794
795 error_out:
796         if (m_buildFunc && PyCallable_Check(m_buildFunc) && items)
797                 Py_DECREF(items);
798
799         painter.clippop();
800 }
801
802 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
803 {
804         Py_XDECREF(m_buildFunc);
805         m_buildFunc=cb;
806         Py_XINCREF(m_buildFunc);
807 }
808
809 void eListboxPythonMultiContent::setCallableFunc(ePyObject cb)
810 {
811         Py_XDECREF(m_callableFunc);
812         m_callableFunc=cb;
813         Py_XINCREF(m_callableFunc);
814 }
815
816 int eListboxPythonMultiContent::currentCursorSelectable()
817 {
818         /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
819         if (m_list && cursorValid())
820         {
821                 if (m_callableFunc && PyCallable_Check(m_callableFunc))
822                 {
823                         ePyObject args = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
824                         if (PyTuple_Check(args))
825                         {
826                                 ePyObject ret = PyObject_CallObject(m_callableFunc, args);
827                                 if (ret)
828                                         return ret == Py_True;
829                                 eDebug("call m_callableFunc failed!!! assume not callable");
830                         }
831                         else
832                                 eDebug("m_list[m_cursor] is not a tuple!!! assume not callable");
833                 }
834                 else
835                 {
836                         ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
837                         if (PyList_Check(item))
838                         {
839                                 item = PyList_GET_ITEM(item, 0);
840                                 if (item != Py_None)
841                                         return 1;
842                         }
843                         else if (m_buildFunc && PyCallable_Check(m_buildFunc))
844                                 return 1;
845                 }
846         }
847         return 0;
848 }
849
850 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
851 {
852         if (font)
853                 m_font[fnt] = font;
854         else
855                 m_font.erase(fnt);
856 }
857
858 void eListboxPythonMultiContent::setItemHeight(int height)
859 {
860         m_itemheight = height;
861         if (m_listbox)
862                 m_listbox->setItemHeight(height);
863 }