add graphical multiepg plugin (like e1)
[vuplus_dvbapp] / 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_selectableFunc);
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 static void clearRegion(gPainter &painter, eWindowStyle &style, ePyObject pforeColor, ePyObject pbackColor, ePyObject pbackColorSelected, int selected, gRegion &rc, eRect &sel_clip)
413 {
414         if (selected && sel_clip.valid())
415         {
416                 painter.clip(rc-sel_clip);
417                 if (pbackColor)
418                 {
419                         int color = PyInt_AsLong(pbackColor);
420                         painter.setBackgroundColor(gRGB(color));
421                 }
422                 else
423                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
424                 painter.clear();
425                 painter.clippop();
426                 painter.clip(rc&sel_clip);
427                 style.setStyle(painter, eWindowStyle::styleListboxSelected);
428                 if (pbackColorSelected)
429                 {
430                         int color = PyInt_AsLong(pbackColorSelected);
431                         painter.setBackgroundColor(gRGB(color));
432                 }
433                 painter.clear();
434                 painter.clippop();
435         }
436         else
437         {
438                 if (selected)
439                 {
440                         style.setStyle(painter, eWindowStyle::styleListboxSelected);
441                         if (pbackColorSelected)
442                         {
443                                 int color = PyInt_AsLong(pbackColorSelected);
444                                 painter.setBackgroundColor(gRGB(color));
445                         }
446                 }
447                 else
448                 {
449                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
450                         if (pbackColor)
451                         {
452                                 int color = PyInt_AsLong(pbackColor);
453                                 painter.setBackgroundColor(gRGB(color));
454                         }
455                 }
456                 painter.clear();
457         }
458         if (pforeColor)
459         {
460                 int color = PyInt_AsLong(pforeColor);
461                 painter.setForegroundColor(gRGB(color));
462         }
463 }
464
465 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
466 {
467         gRegion itemregion(eRect(offset, m_itemsize));
468
469         eRect sel_clip(m_selection_clip);
470         if (sel_clip.valid())
471                 sel_clip.moveBy(offset);
472
473         if (m_temp_clip.valid())
474         {
475                 m_temp_clip.moveBy(offset);
476                 itemregion &= m_temp_clip;
477                 m_temp_clip = eRect();
478         }
479
480         painter.clip(itemregion);
481
482         clearRegion(painter, style, ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip);
483
484         ePyObject items;
485
486         if (m_list && cursorValid())
487         {
488                 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
489
490                 if (m_buildFunc)
491                 {
492                         if (PyCallable_Check(m_buildFunc))  // when we have a buildFunc then call it
493                         {
494                                 if (PyTuple_Check(items))
495                                         items = PyObject_CallObject(m_buildFunc, items);
496                                 else
497                                         eDebug("items is no tuple");
498                         }
499                         else
500                                 eDebug("buildfunc is not callable");
501                 }
502
503                 if (!items)
504                 {
505                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
506                         goto error_out;
507                 }
508
509                 if (!PyList_Check(items))
510                 {
511                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
512                         goto error_out;
513                 }
514
515                 int size = PyList_Size(items);
516                 for (int i = 1; i < size; ++i)
517                 {
518                         ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
519                         bool reset_colors=false;
520
521                         if (!item)
522                         {
523                                 eDebug("eListboxPythonMultiContent: ?");
524                                 goto error_out;
525                         }
526
527                         if (!PyTuple_Check(item))
528                         {
529                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
530                                 goto error_out;
531                         }
532
533                         int size = PyTuple_Size(item);
534
535                         if (!size)
536                         {
537                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
538                                 goto error_out;
539                         }
540
541                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
542
543                         switch (type)
544                         {
545                         case TYPE_TEXT: // text
546                         {
547                         /*
548                                 (0, x, y, width, height, fnt, flags, "bla" [, color, backColor, backColorSelected, borderWidth, borderColor] )
549                         */
550                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
551                                                         py = PyTuple_GET_ITEM(item, 2),
552                                                         pwidth = PyTuple_GET_ITEM(item, 3),
553                                                         pheight = PyTuple_GET_ITEM(item, 4),
554                                                         pfnt = PyTuple_GET_ITEM(item, 5),
555                                                         pflags = PyTuple_GET_ITEM(item, 6),
556                                                         pstring = PyTuple_GET_ITEM(item, 7),
557                                                         pforeColor, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
558
559                                 if (!(px && py && pwidth && pheight && pfnt && pflags && pstring))
560                                 {
561                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string [, color, backColor, backColorSelected, borderWidth, borderColor])");
562                                         goto error_out;
563                                 }
564
565                                 if (size > 8)
566                                 {
567                                         pforeColor = PyTuple_GET_ITEM(item, 8);
568                                         if (pforeColor == Py_None)
569                                                 pforeColor=ePyObject();
570                                 }
571                                 if (size > 9)
572                                 {
573                                         pbackColor = PyTuple_GET_ITEM(item, 9);
574                                         if (pbackColor == Py_None)
575                                                 pbackColor=ePyObject();
576                                 }
577                                 if (size > 10)
578                                 {
579                                         pbackColorSelected = PyTuple_GET_ITEM(item, 10);
580                                         if (pbackColorSelected == Py_None)
581                                                 pbackColorSelected=ePyObject();
582                                 }
583                                 if (size > 11)
584                                         pborderWidth = PyTuple_GET_ITEM(item, 11);
585                                 if (size > 12)
586                                         pborderColor = PyTuple_GET_ITEM(item, 12);
587
588                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
589                                 int x = PyInt_AsLong(px) + offset.x();
590                                 int y = PyInt_AsLong(py) + offset.y();
591                                 int width = PyInt_AsLong(pwidth);
592                                 int height = PyInt_AsLong(pheight);
593                                 int flags = PyInt_AsLong(pflags);
594                                 int fnt = PyInt_AsLong(pfnt);
595                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
596
597                                 if (m_font.find(fnt) == m_font.end())
598                                 {
599                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
600                                         goto error_out;
601                                 }
602
603                                 eRect rect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
604                                 painter.clip(rect);
605                                 if (pbackColor || pbackColorSelected || pforeColor)
606                                 {
607                                         gRegion rc(rect);
608                                         clearRegion(painter, style, pforeColor, pbackColor, pbackColorSelected, selected, rc, sel_clip);
609                                         reset_colors=true;
610                                 }
611
612                                 painter.setFont(m_font[fnt]);
613                                 painter.renderText(rect, string, flags);
614                                 painter.clippop();
615
616                                 // draw border
617                                 if (bwidth)
618                                 {
619                                         eRect rect(eRect(x, y, width, height));
620                                         painter.clip(rect);
621                                         if (pborderColor)
622                                         {
623                                                 int color = PyInt_AsLong(pborderColor);
624                                                 painter.setForegroundColor(gRGB(color));
625                                         }
626                                         else if (pforeColor) // reset to normal color
627                                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
628
629                                         rect.setRect(x, y, width, bwidth);
630                                         painter.fill(rect);
631
632                                         rect.setRect(x, y+bwidth, bwidth, height-bwidth);
633                                         painter.fill(rect);
634
635                                         rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
636                                         painter.fill(rect);
637
638                                         rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
639                                         painter.fill(rect);
640
641                                         painter.clippop();
642                                 }
643                                 break;
644                         }
645                         case TYPE_PROGRESS: // Progress
646                         {
647                         /*
648                                 (1, x, y, width, height, filled_percent [, borderWidth, foreColor, backColor, backColorSelected] )
649                         */
650                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
651                                                         py = PyTuple_GET_ITEM(item, 2),
652                                                         pwidth = PyTuple_GET_ITEM(item, 3),
653                                                         pheight = PyTuple_GET_ITEM(item, 4),
654                                                         pfilled_perc = PyTuple_GET_ITEM(item, 5),
655                                                         pborderWidth, pforeColor, pbackColor, pbackColorSelected;
656
657                                 if (!(px && py && pwidth && pheight && pfilled_perc))
658                                 {
659                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent [,border width, foreColor, backColor, backColorSelected]))");
660                                         goto error_out;
661                                 }
662
663                                 if (size > 6)
664                                         pborderWidth = PyTuple_GET_ITEM(item, 6);
665                                 if (size > 7)
666                                         pforeColor = PyTuple_GET_ITEM(item, 7);
667                                 if (size > 8)
668                                 {
669                                         pbackColor = PyTuple_GET_ITEM(item, 8);
670                                         if (pbackColor == Py_None)
671                                                 pbackColor=ePyObject();
672                                 }
673                                 if (size > 9)
674                                 {
675                                         pbackColorSelected = PyTuple_GET_ITEM(item, 9);
676                                         if (pbackColorSelected == Py_None)
677                                                 pbackColorSelected=ePyObject();
678                                 }
679
680                                 int x = PyInt_AsLong(px) + offset.x();
681                                 int y = PyInt_AsLong(py) + offset.y();
682                                 int width = PyInt_AsLong(pwidth);
683                                 int height = PyInt_AsLong(pheight);
684                                 int filled = PyInt_AsLong(pfilled_perc);
685                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 2;
686
687                                 eRect rect(x, y, width, height);
688                                 painter.clip(rect);
689                                 if (pbackColor || pbackColorSelected || pforeColor)
690                                 {
691                                         gRegion rc(rect);
692                                         clearRegion(painter, style, pforeColor, pbackColor, pbackColorSelected, selected, rc, sel_clip);
693                                         reset_colors=true;
694                                 }
695
696                                 // border
697                                 rect.setRect(x, y, width, bwidth);
698                                 painter.fill(rect);
699
700                                 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
701                                 painter.fill(rect);
702
703                                 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
704                                 painter.fill(rect);
705
706                                 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
707                                 painter.fill(rect);
708
709                                 // progress
710                                 rect.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
711                                 painter.fill(rect);
712
713                                 painter.clippop();
714
715                                 break;
716                         }
717                         case TYPE_PIXMAP_ALPHATEST:
718                         case TYPE_PIXMAP: // pixmap
719                         {
720                         /*
721                                 (2, x, y, width, height, pixmap [, foreColor, backColor, backColorSelected] )
722                         */
723
724                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
725                                                         py = PyTuple_GET_ITEM(item, 2),
726                                                         pwidth = PyTuple_GET_ITEM(item, 3),
727                                                         pheight = PyTuple_GET_ITEM(item, 4),
728                                                         ppixmap = PyTuple_GET_ITEM(item, 5),
729                                                         pbackColor, pbackColorSelected;
730
731                                 if (!(px && py && pwidth && pheight && ppixmap))
732                                 {
733                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap [, backColor, backColorSelected] ))");
734                                         goto error_out;
735                                 }
736
737                                 int x = PyInt_AsLong(px) + offset.x();
738                                 int y = PyInt_AsLong(py) + offset.y();
739                                 int width = PyInt_AsLong(pwidth);
740                                 int height = PyInt_AsLong(pheight);
741                                 ePtr<gPixmap> pixmap;
742                                 if (SwigFromPython(pixmap, ppixmap))
743                                 {
744                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
745                                         goto error_out;
746                                 }
747
748                                 if (size > 6)
749                                 {
750                                         pbackColor = PyTuple_GET_ITEM(item, 6);
751                                         if (pbackColor == Py_None)
752                                                 pbackColor=ePyObject();
753                                 }
754                                 if (size > 7)
755                                 {
756                                         pbackColorSelected = PyTuple_GET_ITEM(item, 7);
757                                         if (pbackColorSelected == Py_None)
758                                                 pbackColorSelected=ePyObject();
759                                 }
760
761                                 eRect rect(x, y, width, height);
762                                 painter.clip(rect);
763                                 if (pbackColor || pbackColorSelected)
764                                 {
765                                         gRegion rc(rect);
766                                         clearRegion(painter, style, ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip);
767                                         reset_colors=true;
768                                 }
769                                 
770                                 painter.blit(pixmap, rect.topLeft(), rect, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
771                                 painter.clippop();
772                                 break;
773                         }
774                         default:
775                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
776                                 goto error_out;
777                         }
778                         if (reset_colors)
779                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
780                 }
781         }
782
783         if (selected)
784                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
785
786 error_out:
787         if (m_buildFunc && PyCallable_Check(m_buildFunc) && items)
788                 Py_DECREF(items);
789
790         painter.clippop();
791 }
792
793 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
794 {
795         Py_XDECREF(m_buildFunc);
796         m_buildFunc=cb;
797         Py_XINCREF(m_buildFunc);
798 }
799
800 void eListboxPythonMultiContent::setSelectableFunc(ePyObject cb)
801 {
802         Py_XDECREF(m_selectableFunc);
803         m_selectableFunc=cb;
804         Py_XINCREF(m_selectableFunc);
805 }
806
807 int eListboxPythonMultiContent::currentCursorSelectable()
808 {
809         /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
810         if (m_list && cursorValid())
811         {
812                 if (m_selectableFunc && PyCallable_Check(m_selectableFunc))
813                 {
814                         ePyObject args = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
815                         if (PyTuple_Check(args))
816                         {
817                                 ePyObject ret = PyObject_CallObject(m_selectableFunc, args);
818                                 if (ret)
819                                         return ret == Py_True;
820                                 eDebug("call m_selectableFunc failed!!! assume not callable");
821                         }
822                         else
823                                 eDebug("m_list[m_cursor] is not a tuple!!! assume not callable");
824                 }
825                 else
826                 {
827                         ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
828                         if (PyList_Check(item))
829                         {
830                                 item = PyList_GET_ITEM(item, 0);
831                                 if (item != Py_None)
832                                         return 1;
833                         }
834                         else if (m_buildFunc && PyCallable_Check(m_buildFunc))
835                                 return 1;
836                 }
837         }
838         return 0;
839 }
840
841 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
842 {
843         if (font)
844                 m_font[fnt] = font;
845         else
846                 m_font.erase(fnt);
847 }
848
849 void eListboxPythonMultiContent::setItemHeight(int height)
850 {
851         m_itemheight = height;
852         if (m_listbox)
853                 m_listbox->setItemHeight(height);
854 }