add function to set the selection rect (for partial selections),
[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, pfillColor, 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                                         pfillColor = PyTuple_GET_ITEM(item, 9);
535                                         if (pfillColor == Py_None)
536                                                 pfillColor=ePyObject();
537                                 }
538                                 if (size > 10)
539                                         pborderWidth = PyTuple_GET_ITEM(item, 10);
540                                 if (size > 11)
541                                         pborderColor = PyTuple_GET_ITEM(item, 11);
542                         }
543                         
544                         switch (type)
545                         {
546                         case TYPE_TEXT: // text
547                         {
548                                 if (!(px && py && pwidth && pheight && pfnt && pstring))
549                                 {
550                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string, [color, ]...])");
551                                         goto error_out;
552                                 }
553                                 
554                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
555                                 int x = PyInt_AsLong(px);
556                                 int y = PyInt_AsLong(py);
557                                 int width = PyInt_AsLong(pwidth);
558                                 int height = PyInt_AsLong(pheight);
559                                 int flags = PyInt_AsLong(pflags);
560                                 int fnt = PyInt_AsLong(pfnt);
561                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
562
563                                 if (pcolor)
564                                 {
565                                         int color = PyInt_AsLong(pcolor);
566                                         painter.setForegroundColor(gRGB(color));
567                                 }
568
569                                 if (m_font.find(fnt) == m_font.end())
570                                 {
571                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
572                                         goto error_out;
573                                 }
574
575                                 eRect rc = eRect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
576                                 rc.moveBy(offset);
577                                 rc &= itemrect;
578                                 painter.clip(rc);
579
580                                 if (pfillColor && !selected)
581                                 {
582                                         int color = PyInt_AsLong(pfillColor);
583                                         painter.setBackgroundColor(gRGB(color));
584                                         painter.clear();
585                                 }
586
587                                 painter.setFont(m_font[fnt]);
588                                 painter.renderText(rc, string, flags);
589                                 painter.clippop();
590
591                                 // draw border
592                                 if (bwidth)
593                                 {
594                                         rc.setRect(x, y, width, height);
595                                         rc.moveBy(offset);
596                                         rc &= itemrect;
597                                         painter.clip(rc);
598                                         if (pborderColor)
599                                         {
600                                                 int color = PyInt_AsLong(pborderColor);
601                                                 painter.setForegroundColor(gRGB(color));
602                                         }
603                                         else if (pcolor)
604                                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
605
606                                         rc.setRect(x, y, width, bwidth);
607                                         rc.moveBy(offset);
608                                         painter.fill(rc);
609
610                                         rc.setRect(x, y+bwidth, bwidth, height-bwidth);
611                                         rc.moveBy(offset);
612                                         painter.fill(rc);
613
614                                         rc.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
615                                         rc.moveBy(offset);
616                                         painter.fill(rc);
617
618                                         rc.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
619                                         rc.moveBy(offset);
620                                         painter.fill(rc);
621
622                                         painter.clippop();
623                                 }
624
625                                 break;
626                         }
627                         case TYPE_PROGRESS: // Progress
628                         {
629                                 if (!(px && py && pwidth && pheight && pfnt))
630                                 {
631                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
632                                         goto error_out;
633                                 }
634                                 int x = PyInt_AsLong(px);
635                                 int y = PyInt_AsLong(py);
636                                 int width = PyInt_AsLong(pwidth);
637                                 int height = PyInt_AsLong(pheight);
638                                 int filled = PyInt_AsLong(pfnt);
639
640                                 eRect rc = eRect(x, y, width, height);
641                                 rc.moveBy(offset);
642                                 rc &= itemrect;
643
644                                 painter.clip(rc);
645                                 int bwidth=2;  // borderwidth hardcoded yet
646
647                                 // border
648                                 rc.setRect(x, y, width, bwidth);
649                                 rc.moveBy(offset);
650                                 painter.fill(rc);
651
652                                 rc.setRect(x, y+bwidth, bwidth, height-bwidth);
653                                 rc.moveBy(offset);
654                                 painter.fill(rc);
655
656                                 rc.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
657                                 rc.moveBy(offset);
658                                 painter.fill(rc);
659
660                                 rc.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
661                                 rc.moveBy(offset);
662                                 painter.fill(rc);
663
664                                 // progress
665                                 rc.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
666                                 rc.moveBy(offset);
667                                 painter.fill(rc);
668
669                                 painter.clippop();
670
671                                 break;
672                         }
673                         case TYPE_PIXMAP_ALPHATEST:
674                         case TYPE_PIXMAP: // pixmap
675                         {
676                                 if (!(px && py && pwidth && pheight && pfnt))
677                                 {
678                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
679                                         goto error_out;
680                                 }
681                                 int x = PyInt_AsLong(px);
682                                 int y = PyInt_AsLong(py);
683                                 int width = PyInt_AsLong(pwidth);
684                                 int height = PyInt_AsLong(pheight);
685                                 ePtr<gPixmap> pixmap;
686                                 if (SwigFromPython(pixmap, pfnt))
687                                 {
688                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
689                                         goto error_out;
690                                 }
691
692                                 eRect r = eRect(x, y, width, height);
693                                 r.moveBy(offset);
694                                 r &= itemrect;
695                                 
696                                 painter.clip(r);
697                                 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
698                                 painter.clippop();
699
700                                 break;
701                         }
702                         default:
703                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
704                                 goto error_out;
705                         }
706                         
707                         if (pcolor || pborderColor || pfillColor)
708                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
709                 }
710         }
711         
712         if (selected)
713                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
714
715 error_out:
716         if (m_buildFunc && PyCallable_Check(m_buildFunc) && items)
717                 Py_DECREF(items);
718
719         painter.clippop();
720 }
721
722 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
723 {
724         if (m_buildFunc)
725                 Py_DECREF(m_buildFunc);
726         m_buildFunc=cb;
727         if (cb)
728                 Py_INCREF(m_buildFunc);
729 }
730
731 int eListboxPythonMultiContent::currentCursorSelectable()
732 {
733         /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
734         if (m_list && cursorValid())
735         {
736                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
737                 if (PyList_Check(item))
738                 {
739                         item = PyList_GET_ITEM(item, 0);
740                         if (item != Py_None)
741                                 return 1;
742                 }
743                 else if (m_buildFunc && PyCallable_Check(m_buildFunc))
744                 // FIXME .. how we can detect non selectable entrys when we have a buildFunc callback
745                         return 1;
746         }
747         return 0;
748 }
749
750 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
751 {
752         if (font)
753                 m_font[fnt] = font;
754         else
755                 m_font.erase(fnt);
756 }
757
758 void eListboxPythonMultiContent::setItemHeight(int height)
759 {
760         m_itemheight = height;
761         if (m_listbox)
762                 m_listbox->setItemHeight(height);
763 }