cba25a181f85b9df8e067b0b8609570b733bb01c
[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 {
389 }
390
391 eListboxPythonMultiContent::~eListboxPythonMultiContent()
392 {
393         if (m_buildFunc)
394                 Py_DECREF(m_buildFunc);
395 }
396
397 void eListboxPythonMultiContent::setSelectionClip(eRect &rect, bool update)
398 {
399         if (update && m_selection_clip.valid())
400         {
401 // redraw old selection
402                 m_temp_clip = m_selection_clip;
403                 m_selection_clip = eRect();
404                 if (m_listbox)
405                         m_listbox->entryChanged(m_cursor);
406 // redraw new selection
407                 m_selection_clip = rect;
408                 m_temp_clip = rect;
409                 if (m_listbox)
410                         m_listbox->entryChanged(m_cursor);
411                 m_temp_clip = eRect();
412         }
413         else
414                 m_selection_clip = rect;
415 }
416
417 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
418 {
419         eRect itemrect(offset, m_itemsize);
420         if (m_temp_clip.valid())
421         {
422                 eRect tmp = m_temp_clip;
423                 tmp.moveBy(offset);
424                 itemrect &= tmp;
425         }
426
427         painter.clip(itemrect);
428         style.setStyle(painter, selected && !m_selection_clip.valid() ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
429         painter.clear();
430         if (selected && m_selection_clip.valid())
431         {
432                 eRect tmp = m_selection_clip;
433                 tmp.moveBy(offset);
434                 painter.clip(tmp);
435                 style.setStyle(painter, eWindowStyle::styleListboxSelected );
436                 painter.clear();
437                 painter.clippop();
438         }
439
440         ePyObject items;
441
442         if (m_list && cursorValid())
443         {
444                 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
445
446                 if (m_buildFunc)
447                 {
448                         if (PyCallable_Check(m_buildFunc))  // when we have a buildFunc then call it
449                         {
450                                 if (PyTuple_Check(items))
451                                         items = PyObject_CallObject(m_buildFunc, items);
452                                 else
453                                         eDebug("items is no tuple");
454                         }
455                         else
456                                 eDebug("buildfunc is not callable");
457                 }
458
459                 if (!items)
460                 {
461                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
462                         goto error_out;
463                 }
464                 
465                 if (!PyList_Check(items))
466                 {
467                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
468                         goto error_out;
469                 }
470                 
471                 int size = PyList_Size(items);
472                 for (int i = 1; i < size; ++i)
473                 {
474                         ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
475                         
476                         if (!item)
477                         {
478                                 eDebug("eListboxPythonMultiContent: ?");
479                                 goto error_out;
480                         }
481                         
482                         ePyObject px, py, pwidth, pheight, pfnt, pstring, pflags, pcolor, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
483                 
484                         /*
485                                 we have a list of tuples:
486                                 
487                                 (0, x, y, width, height, fnt, flags, "bla"[, color] ),
488
489                                 or, for a progress:
490                                 (1, x, y, width, height, filled_percent )
491
492                                 or, for a pixmap:
493                                 
494                                 (2, x, y, width, height, pixmap )
495                                 
496                          */
497                         
498                         if (!PyTuple_Check(item))
499                         {
500                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
501                                 goto error_out;
502                         }
503
504                         int size = PyTuple_Size(item);
505
506                         if (!size)
507                         {
508                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
509                                 goto error_out;
510                         }
511
512                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
513
514                         if (size > 5)
515                         {
516                                 px = PyTuple_GET_ITEM(item, 1);
517                                 py = PyTuple_GET_ITEM(item, 2);
518                                 pwidth = PyTuple_GET_ITEM(item, 3);
519                                 pheight = PyTuple_GET_ITEM(item, 4);
520                                 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
521                                 if (size > 7)
522                                 {
523                                         pflags = PyTuple_GET_ITEM(item, 6);
524                                         pstring = PyTuple_GET_ITEM(item, 7);
525                                 }
526                                 if (size > 8)
527                                 {
528                                         pcolor = PyTuple_GET_ITEM(item, 8);
529                                         if (pcolor == Py_None)
530                                                 pcolor=ePyObject();
531                                 }
532                                 if (size > 9)
533                                 {
534                                         pbackColor = PyTuple_GET_ITEM(item, 9);
535                                         if (pbackColor == Py_None)
536                                                 pbackColor=ePyObject();
537                                 }
538                                 if (size > 10)
539                                 {
540                                         pbackColorSelected = PyTuple_GET_ITEM(item, 10);
541                                         if (pbackColorSelected == Py_None)
542                                                 pbackColorSelected=ePyObject();
543                                 }
544                                 if (size > 11)
545                                         pborderWidth = PyTuple_GET_ITEM(item, 11);
546                                 if (size > 12)
547                                         pborderColor = PyTuple_GET_ITEM(item, 12);
548                         }
549                         
550                         switch (type)
551                         {
552                         case TYPE_TEXT: // text
553                         {
554                                 if (!(px && py && pwidth && pheight && pfnt && pstring))
555                                 {
556                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string, [color, ]...])");
557                                         goto error_out;
558                                 }
559                                 
560                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
561                                 int x = PyInt_AsLong(px);
562                                 int y = PyInt_AsLong(py);
563                                 int width = PyInt_AsLong(pwidth);
564                                 int height = PyInt_AsLong(pheight);
565                                 int flags = PyInt_AsLong(pflags);
566                                 int fnt = PyInt_AsLong(pfnt);
567                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
568
569                                 if (pcolor)
570                                 {
571                                         int color = PyInt_AsLong(pcolor);
572                                         painter.setForegroundColor(gRGB(color));
573                                 }
574
575                                 if (m_font.find(fnt) == m_font.end())
576                                 {
577                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
578                                         goto error_out;
579                                 }
580
581                                 eRect rc = eRect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
582                                 rc.moveBy(offset);
583                                 rc &= itemrect;
584                                 painter.clip(rc);
585
586                                 if (pbackColor && !selected)
587                                 {
588                                         int color = PyInt_AsLong(pbackColor);
589                                         painter.setBackgroundColor(gRGB(color));
590                                         painter.clear();
591                                 }
592                                 else if (pbackColorSelected && selected)
593                                 {
594                                         int color = PyInt_AsLong(pbackColorSelected);
595                                         painter.setBackgroundColor(gRGB(color));
596                                         painter.clear();
597                                 }
598
599                                 painter.setFont(m_font[fnt]);
600                                 painter.renderText(rc, string, flags);
601                                 painter.clippop();
602
603                                 // draw border
604                                 if (bwidth)
605                                 {
606                                         rc.setRect(x, y, width, height);
607                                         rc.moveBy(offset);
608                                         rc &= itemrect;
609                                         painter.clip(rc);
610                                         if (pborderColor)
611                                         {
612                                                 int color = PyInt_AsLong(pborderColor);
613                                                 painter.setForegroundColor(gRGB(color));
614                                         }
615                                         else if (pcolor) // reset to normal color
616                                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
617
618                                         rc.setRect(x, y, width, bwidth);
619                                         rc.moveBy(offset);
620                                         painter.fill(rc);
621
622                                         rc.setRect(x, y+bwidth, bwidth, height-bwidth);
623                                         rc.moveBy(offset);
624                                         painter.fill(rc);
625
626                                         rc.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
627                                         rc.moveBy(offset);
628                                         painter.fill(rc);
629
630                                         rc.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
631                                         rc.moveBy(offset);
632                                         painter.fill(rc);
633
634                                         painter.clippop();
635                                 }
636
637                                 break;
638                         }
639                         case TYPE_PROGRESS: // Progress
640                         {
641                                 if (!(px && py && pwidth && pheight && pfnt))
642                                 {
643                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
644                                         goto error_out;
645                                 }
646                                 int x = PyInt_AsLong(px);
647                                 int y = PyInt_AsLong(py);
648                                 int width = PyInt_AsLong(pwidth);
649                                 int height = PyInt_AsLong(pheight);
650                                 int filled = PyInt_AsLong(pfnt);
651
652                                 eRect rc = eRect(x, y, width, height);
653                                 rc.moveBy(offset);
654                                 rc &= itemrect;
655
656                                 painter.clip(rc);
657                                 int bwidth=2;  // borderwidth hardcoded yet
658
659                                 // border
660                                 rc.setRect(x, y, width, bwidth);
661                                 rc.moveBy(offset);
662                                 painter.fill(rc);
663
664                                 rc.setRect(x, y+bwidth, bwidth, height-bwidth);
665                                 rc.moveBy(offset);
666                                 painter.fill(rc);
667
668                                 rc.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
669                                 rc.moveBy(offset);
670                                 painter.fill(rc);
671
672                                 rc.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
673                                 rc.moveBy(offset);
674                                 painter.fill(rc);
675
676                                 // progress
677                                 rc.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
678                                 rc.moveBy(offset);
679                                 painter.fill(rc);
680
681                                 painter.clippop();
682
683                                 break;
684                         }
685                         case TYPE_PIXMAP_ALPHATEST:
686                         case TYPE_PIXMAP: // pixmap
687                         {
688                                 if (!(px && py && pwidth && pheight && pfnt))
689                                 {
690                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
691                                         goto error_out;
692                                 }
693                                 int x = PyInt_AsLong(px);
694                                 int y = PyInt_AsLong(py);
695                                 int width = PyInt_AsLong(pwidth);
696                                 int height = PyInt_AsLong(pheight);
697                                 ePtr<gPixmap> pixmap;
698                                 if (SwigFromPython(pixmap, pfnt))
699                                 {
700                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
701                                         goto error_out;
702                                 }
703
704                                 eRect r = eRect(x, y, width, height);
705                                 r.moveBy(offset);
706                                 r &= itemrect;
707                                 
708                                 painter.clip(r);
709                                 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
710                                 painter.clippop();
711
712                                 break;
713                         }
714                         default:
715                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
716                                 goto error_out;
717                         }
718                         
719                         if (pcolor || pborderColor || pbackColor || pbackColorSelected)
720                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
721                 }
722         }
723         
724         if (selected)
725                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
726
727 error_out:
728         if (m_buildFunc && PyCallable_Check(m_buildFunc) && items)
729                 Py_DECREF(items);
730
731         painter.clippop();
732 }
733
734 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
735 {
736         if (m_buildFunc)
737                 Py_DECREF(m_buildFunc);
738         m_buildFunc=cb;
739         if (cb)
740                 Py_INCREF(m_buildFunc);
741 }
742
743 int eListboxPythonMultiContent::currentCursorSelectable()
744 {
745         /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
746         if (m_list && cursorValid())
747         {
748                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
749                 if (PyList_Check(item))
750                 {
751                         item = PyList_GET_ITEM(item, 0);
752                         if (item != Py_None)
753                                 return 1;
754                 }
755                 else if (m_buildFunc && PyCallable_Check(m_buildFunc))
756                 // FIXME .. how we can detect non selectable entrys when we have a buildFunc callback
757                         return 1;
758         }
759         return 0;
760 }
761
762 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
763 {
764         if (font)
765                 m_font[fnt] = font;
766         else
767                 m_font.erase(fnt);
768 }
769
770 void eListboxPythonMultiContent::setItemHeight(int height)
771 {
772         m_itemheight = height;
773         if (m_listbox)
774                 m_listbox->setItemHeight(height);
775 }