small fixes for PIG
[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
144         eListboxStyle *local_style = 0;
145
146                 /* get local listbox style, if present */
147         if (m_listbox)
148                 local_style = m_listbox->getLocalStyle();
149
150                 /* if we have a local background color set, use that. */
151         if (local_style && local_style->m_background_color_set)
152                 painter.setBackgroundColor(local_style->m_background_color);
153
154                 /* same for foreground */
155         if (local_style && local_style->m_foreground_color_set)
156                 painter.setBackgroundColor(local_style->m_foreground_color);
157
158                 /* if we have no transparent background */
159         if (!local_style || !local_style->m_transparent_background)
160         {
161                         /* blit background picture, if available (otherwise, clear only) */
162                 if (local_style && local_style->m_background)
163                         painter.blit(local_style->m_background, offset, eRect(), 0);
164                 else
165                         painter.clear();
166         } else
167         {
168                 if (local_style && local_style->m_background)
169                         painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
170         }
171
172         if (m_list && cursorValid())
173         {
174                 int gray = 0;
175                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
176                 painter.setFont(fnt);
177
178                         /* the user can supply tuples, in this case the first one will be displayed. */         
179                 if (PyTuple_Check(item))
180                 {
181                         if (PyTuple_Size(item) == 1)
182                                 gray = 1;
183                         item = PyTuple_GET_ITEM(item, 0);
184                 }
185
186                 if (selected && local_style && local_style->m_selection)
187                         painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
188
189                 if (item == Py_None)
190                 {
191                                 /* seperator */
192                         int half_height = m_itemsize.height() / 2;
193                         painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
194                 } else
195                 {
196                         const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
197                         ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
198                         if (gray)
199                                 painter.setForegroundColor(gRGB(0x808080));
200                         painter.renderText(eRect(text_offset, m_itemsize), string);
201                 }
202
203                 if (selected && (!local_style || !local_style->m_selection))
204                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
205         }
206
207         painter.clippop();
208 }
209
210 void eListboxPythonStringContent::setList(ePyObject list)
211 {
212         Py_XDECREF(m_list);
213         if (!PyList_Check(list))
214         {
215                 m_list = ePyObject();
216         } else
217         {
218                 m_list = list;
219                 Py_INCREF(m_list);
220         }
221
222         if (m_listbox)
223                 m_listbox->entryReset(false);
224 }
225
226 PyObject *eListboxPythonStringContent::getCurrentSelection()
227 {
228         if (!(m_list && cursorValid()))
229                 Py_RETURN_NONE;
230
231         ePyObject r = PyList_GET_ITEM(m_list, m_cursor);
232         Py_XINCREF(r);
233         return r;
234 }
235
236 void eListboxPythonStringContent::invalidateEntry(int index)
237 {
238         if (m_listbox)
239                 m_listbox->entryChanged(index);
240 }
241
242 void eListboxPythonStringContent::invalidate()
243 {
244         if (m_listbox)
245         {
246                 int s = size();
247                 if ( m_cursor >= s )
248                         m_listbox->moveSelectionTo(s?s-1:0);
249                 m_listbox->invalidate();
250         }
251 }
252
253 //////////////////////////////////////
254
255 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
256 {
257         ePtr<gFont> fnt = new gFont("Regular", 20);
258         ePtr<gFont> fnt2 = new gFont("Regular", 16);
259         eRect itemrect(offset, m_itemsize);
260         painter.clip(itemrect);
261         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
262         painter.clear();
263
264         if (m_list && cursorValid())
265         {
266                         /* get current list item */
267                 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
268                 ePyObject text, value;
269                 painter.setFont(fnt);
270
271                         /* the first tuple element is a string for the left side.
272                            the second one will be called, and the result shall be an tuple.
273                            
274                            of this tuple,
275                            the first one is the type (string).
276                            the second one is the value. */
277                 if (PyTuple_Check(item))
278                 {
279                                 /* handle left part. get item from tuple, convert to string, display. */
280                                 
281                         text = PyTuple_GET_ITEM(item, 0);
282                         text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
283                         const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
284                         eSize item_left = eSize(m_seperation, m_itemsize.height());
285                         eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
286                         painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
287                         Py_XDECREF(text);
288                         
289                                 /* when we have no label, align value to the left. (FIXME: 
290                                    don't we want to specifiy this individually?) */
291                         int value_alignment_left = !*string;
292                         
293                                 /* now, handle the value. get 2nd part from tuple*/
294                         value = PyTuple_GET_ITEM(item, 1);
295                         if (value)
296                         {
297                                 ePyObject args = PyTuple_New(1);
298                                 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
299                                 
300                                         /* CallObject will call __call__ which should return the value tuple */
301                                 value = PyObject_CallObject(value, args);
302                                 
303                                 if (PyErr_Occurred())
304                                         PyErr_Print();
305
306                                 Py_DECREF(args);
307                                         /* the PyInt was stolen. */
308                         }
309                         
310                                 /*  check if this is really a tuple */
311                         if (value && PyTuple_Check(value))
312                         {
313                                         /* convert type to string */
314                                 ePyObject type = PyTuple_GET_ITEM(value, 0);
315                                 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
316                                 
317                                 if (atype)
318                                 {
319                                         if (!strcmp(atype, "text"))
320                                         {
321                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
322                                                 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
323                                                 painter.setFont(fnt2);
324                                                 if (value_alignment_left)
325                                                         painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
326                                                 else
327                                                         painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
328
329                                                         /* pvalue is borrowed */
330                                         } else if (!strcmp(atype, "slider"))
331                                         {
332                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
333                                                 ePyObject psize = PyTuple_GET_ITEM(value, 2);
334                                                 
335                                                         /* convert value to Long. fallback to -1 on error. */
336                                                 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
337                                                 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
338                                                 
339                                                         /* calc. slider length */
340                                                 int width = item_right.width() * value / size;
341                                                 int height = item_right.height();
342                                                 
343                                                                                                 
344                                                         /* draw slider */
345                                                 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
346                                                 //hack - make it customizable
347                                                 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
348                                                 
349                                                         /* pvalue is borrowed */
350                                         } else if (!strcmp(atype, "mtext"))
351                                         {
352                                                 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
353                                                 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
354                                                 int xoffs = value_alignment_left ? 0 : m_seperation;
355                                                 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
356                                                 para->setFont(fnt2);
357                                                 para->renderString(text, 0);
358                                                 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
359                                                 int glyphs = para->size();
360                                                 
361                                                 ePyObject plist;
362                                                 
363                                                 if (PyTuple_Size(value) >= 3)
364                                                         plist = PyTuple_GET_ITEM(value, 2);
365                                                 
366                                                 int entries = 0;
367
368                                                 if (plist && PyList_Check(plist))
369                                                         entries = PyList_Size(plist);
370                                                 
371                                                 for (int i = 0; i < entries; ++i)
372                                                 {
373                                                         ePyObject entry = PyList_GET_ITEM(plist, i);
374                                                         int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
375                                                         
376                                                         if ((num < 0) || (num >= glyphs))
377                                                                 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
378                                                         else
379                                                         {
380                                                                 para->setGlyphFlag(num, GS_INVERT);
381                                                                 eRect bbox;
382                                                                 bbox = para->getGlyphBBox(num);
383                                                                 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
384                                                                 painter.fill(bbox);
385                                                         }
386                                                                 /* entry is borrowed */
387                                                 }
388                                                 
389                                                 painter.renderPara(para, ePoint(0, 0));
390                                                         /* pvalue is borrowed */
391                                                         /* plist is 0 or borrowed */
392                                         }
393                                 }
394                                         /* type is borrowed */
395                         } else
396                                 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
397                                 /* value is borrowed */
398                 }
399
400                 if (selected)
401                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
402         }
403         
404         painter.clippop();
405 }
406
407 int eListboxPythonConfigContent::currentCursorSelectable()
408 {
409         return eListboxPythonStringContent::currentCursorSelectable();
410 }
411
412 //////////////////////////////////////
413
414         /* todo: make a real infrastructure here! */
415 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
416
417 eListboxPythonMultiContent::eListboxPythonMultiContent()
418         :m_temp_clip(gRegion::invalidRegion())
419 {
420 }
421
422 eListboxPythonMultiContent::~eListboxPythonMultiContent()
423 {
424         Py_XDECREF(m_buildFunc);
425         Py_XDECREF(m_selectableFunc);
426 }
427
428 void eListboxPythonMultiContent::setSelectionClip(eRect &rect, bool update)
429 {
430         if (update && m_selection_clip.valid())
431         {
432                 m_temp_clip = m_selection_clip;
433                 m_temp_clip |= rect;
434                 m_selection_clip = rect;
435                 if (m_listbox)
436                         m_listbox->entryChanged(m_cursor);
437         }
438         else
439                 m_selection_clip = rect;
440 }
441
442 static void clearRegion(gPainter &painter, eWindowStyle &style, ePyObject pforeColor, ePyObject pbackColor, ePyObject pbackColorSelected, int selected, gRegion &rc, eRect &sel_clip)
443 {
444         if (selected && sel_clip.valid())
445         {
446                 painter.clip(rc-sel_clip);
447                 if (pbackColor)
448                 {
449                         int color = PyInt_AsLong(pbackColor);
450                         painter.setBackgroundColor(gRGB(color));
451                 }
452                 else
453                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
454                 painter.clear();
455                 painter.clippop();
456                 painter.clip(rc&sel_clip);
457                 style.setStyle(painter, eWindowStyle::styleListboxSelected);
458                 if (pbackColorSelected)
459                 {
460                         int color = PyInt_AsLong(pbackColorSelected);
461                         painter.setBackgroundColor(gRGB(color));
462                 }
463                 painter.clear();
464                 painter.clippop();
465         }
466         else
467         {
468                 if (selected)
469                 {
470                         style.setStyle(painter, eWindowStyle::styleListboxSelected);
471                         if (pbackColorSelected)
472                         {
473                                 int color = PyInt_AsLong(pbackColorSelected);
474                                 painter.setBackgroundColor(gRGB(color));
475                         }
476                 }
477                 else
478                 {
479                         style.setStyle(painter, eWindowStyle::styleListboxNormal);
480                         if (pbackColor)
481                         {
482                                 int color = PyInt_AsLong(pbackColor);
483                                 painter.setBackgroundColor(gRGB(color));
484                         }
485                 }
486                 painter.clear();
487         }
488         if (pforeColor)
489         {
490                 int color = PyInt_AsLong(pforeColor);
491                 painter.setForegroundColor(gRGB(color));
492         }
493 }
494
495 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
496 {
497         gRegion itemregion(eRect(offset, m_itemsize));
498
499         eRect sel_clip(m_selection_clip);
500         if (sel_clip.valid())
501                 sel_clip.moveBy(offset);
502
503         if (m_temp_clip.valid())
504         {
505                 m_temp_clip.moveBy(offset);
506                 itemregion &= m_temp_clip;
507                 m_temp_clip = eRect();
508         }
509
510         painter.clip(itemregion);
511
512         clearRegion(painter, style, ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip);
513
514         ePyObject items;
515
516         if (m_list && cursorValid())
517         {
518                 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
519
520                 if (m_buildFunc)
521                 {
522                         if (PyCallable_Check(m_buildFunc))  // when we have a buildFunc then call it
523                         {
524                                 if (PyTuple_Check(items))
525                                         items = PyObject_CallObject(m_buildFunc, items);
526                                 else
527                                         eDebug("items is no tuple");
528                         }
529                         else
530                                 eDebug("buildfunc is not callable");
531                 }
532
533                 if (!items)
534                 {
535                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
536                         goto error_out;
537                 }
538
539                 if (!PyList_Check(items))
540                 {
541                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
542                         goto error_out;
543                 }
544
545                 int size = PyList_Size(items);
546                 for (int i = 1; i < size; ++i)
547                 {
548                         ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
549                         bool reset_colors=false;
550
551                         if (!item)
552                         {
553                                 eDebug("eListboxPythonMultiContent: ?");
554                                 goto error_out;
555                         }
556
557                         if (!PyTuple_Check(item))
558                         {
559                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
560                                 goto error_out;
561                         }
562
563                         int size = PyTuple_Size(item);
564
565                         if (!size)
566                         {
567                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
568                                 goto error_out;
569                         }
570
571                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
572
573                         switch (type)
574                         {
575                         case TYPE_TEXT: // text
576                         {
577                         /*
578                                 (0, x, y, width, height, fnt, flags, "bla" [, color, backColor, backColorSelected, borderWidth, borderColor] )
579                         */
580                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
581                                                         py = PyTuple_GET_ITEM(item, 2),
582                                                         pwidth = PyTuple_GET_ITEM(item, 3),
583                                                         pheight = PyTuple_GET_ITEM(item, 4),
584                                                         pfnt = PyTuple_GET_ITEM(item, 5),
585                                                         pflags = PyTuple_GET_ITEM(item, 6),
586                                                         pstring = PyTuple_GET_ITEM(item, 7),
587                                                         pforeColor, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
588
589                                 if (!(px && py && pwidth && pheight && pfnt && pflags && pstring))
590                                 {
591                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string [, color, backColor, backColorSelected, borderWidth, borderColor])");
592                                         goto error_out;
593                                 }
594
595                                 if (size > 8)
596                                 {
597                                         pforeColor = PyTuple_GET_ITEM(item, 8);
598                                         if (pforeColor == Py_None)
599                                                 pforeColor=ePyObject();
600                                 }
601                                 if (size > 9)
602                                 {
603                                         pbackColor = PyTuple_GET_ITEM(item, 9);
604                                         if (pbackColor == Py_None)
605                                                 pbackColor=ePyObject();
606                                 }
607                                 if (size > 10)
608                                 {
609                                         pbackColorSelected = PyTuple_GET_ITEM(item, 10);
610                                         if (pbackColorSelected == Py_None)
611                                                 pbackColorSelected=ePyObject();
612                                 }
613                                 if (size > 11)
614                                         pborderWidth = PyTuple_GET_ITEM(item, 11);
615                                 if (size > 12)
616                                         pborderColor = PyTuple_GET_ITEM(item, 12);
617
618                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
619                                 int x = PyInt_AsLong(px) + offset.x();
620                                 int y = PyInt_AsLong(py) + offset.y();
621                                 int width = PyInt_AsLong(pwidth);
622                                 int height = PyInt_AsLong(pheight);
623                                 int flags = PyInt_AsLong(pflags);
624                                 int fnt = PyInt_AsLong(pfnt);
625                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
626
627                                 if (m_font.find(fnt) == m_font.end())
628                                 {
629                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
630                                         goto error_out;
631                                 }
632
633                                 eRect rect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
634                                 painter.clip(rect);
635                                 if (pbackColor || pbackColorSelected || pforeColor)
636                                 {
637                                         gRegion rc(rect);
638                                         clearRegion(painter, style, pforeColor, pbackColor, pbackColorSelected, selected, rc, sel_clip);
639                                         reset_colors=true;
640                                 }
641
642                                 painter.setFont(m_font[fnt]);
643                                 painter.renderText(rect, string, flags);
644                                 painter.clippop();
645
646                                 // draw border
647                                 if (bwidth)
648                                 {
649                                         eRect rect(eRect(x, y, width, height));
650                                         painter.clip(rect);
651                                         if (pborderColor)
652                                         {
653                                                 int color = PyInt_AsLong(pborderColor);
654                                                 painter.setForegroundColor(gRGB(color));
655                                         }
656                                         else if (pforeColor) // reset to normal color
657                                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
658
659                                         rect.setRect(x, y, width, bwidth);
660                                         painter.fill(rect);
661
662                                         rect.setRect(x, y+bwidth, bwidth, height-bwidth);
663                                         painter.fill(rect);
664
665                                         rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
666                                         painter.fill(rect);
667
668                                         rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
669                                         painter.fill(rect);
670
671                                         painter.clippop();
672                                 }
673                                 break;
674                         }
675                         case TYPE_PROGRESS: // Progress
676                         {
677                         /*
678                                 (1, x, y, width, height, filled_percent [, borderWidth, foreColor, backColor, backColorSelected] )
679                         */
680                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
681                                                         py = PyTuple_GET_ITEM(item, 2),
682                                                         pwidth = PyTuple_GET_ITEM(item, 3),
683                                                         pheight = PyTuple_GET_ITEM(item, 4),
684                                                         pfilled_perc = PyTuple_GET_ITEM(item, 5),
685                                                         pborderWidth, pforeColor, pbackColor, pbackColorSelected;
686
687                                 if (!(px && py && pwidth && pheight && pfilled_perc))
688                                 {
689                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent [,border width, foreColor, backColor, backColorSelected]))");
690                                         goto error_out;
691                                 }
692
693                                 if (size > 6)
694                                         pborderWidth = PyTuple_GET_ITEM(item, 6);
695                                 if (size > 7)
696                                         pforeColor = PyTuple_GET_ITEM(item, 7);
697                                 if (size > 8)
698                                 {
699                                         pbackColor = PyTuple_GET_ITEM(item, 8);
700                                         if (pbackColor == Py_None)
701                                                 pbackColor=ePyObject();
702                                 }
703                                 if (size > 9)
704                                 {
705                                         pbackColorSelected = PyTuple_GET_ITEM(item, 9);
706                                         if (pbackColorSelected == Py_None)
707                                                 pbackColorSelected=ePyObject();
708                                 }
709
710                                 int x = PyInt_AsLong(px) + offset.x();
711                                 int y = PyInt_AsLong(py) + offset.y();
712                                 int width = PyInt_AsLong(pwidth);
713                                 int height = PyInt_AsLong(pheight);
714                                 int filled = PyInt_AsLong(pfilled_perc);
715                                 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 2;
716
717                                 eRect rect(x, y, width, height);
718                                 painter.clip(rect);
719                                 if (pbackColor || pbackColorSelected || pforeColor)
720                                 {
721                                         gRegion rc(rect);
722                                         clearRegion(painter, style, pforeColor, pbackColor, pbackColorSelected, selected, rc, sel_clip);
723                                         reset_colors=true;
724                                 }
725
726                                 // border
727                                 rect.setRect(x, y, width, bwidth);
728                                 painter.fill(rect);
729
730                                 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
731                                 painter.fill(rect);
732
733                                 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
734                                 painter.fill(rect);
735
736                                 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
737                                 painter.fill(rect);
738
739                                 // progress
740                                 rect.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
741                                 painter.fill(rect);
742
743                                 painter.clippop();
744
745                                 break;
746                         }
747                         case TYPE_PIXMAP_ALPHATEST:
748                         case TYPE_PIXMAP: // pixmap
749                         {
750                         /*
751                                 (2, x, y, width, height, pixmap [, backColor, backColorSelected] )
752                         */
753
754                                 ePyObject px = PyTuple_GET_ITEM(item, 1),
755                                                         py = PyTuple_GET_ITEM(item, 2),
756                                                         pwidth = PyTuple_GET_ITEM(item, 3),
757                                                         pheight = PyTuple_GET_ITEM(item, 4),
758                                                         ppixmap = PyTuple_GET_ITEM(item, 5),
759                                                         pbackColor, pbackColorSelected;
760
761                                 if (!(px && py && pwidth && pheight && ppixmap))
762                                 {
763                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap [, backColor, backColorSelected] ))");
764                                         goto error_out;
765                                 }
766
767                                 int x = PyInt_AsLong(px) + offset.x();
768                                 int y = PyInt_AsLong(py) + offset.y();
769                                 int width = PyInt_AsLong(pwidth);
770                                 int height = PyInt_AsLong(pheight);
771                                 ePtr<gPixmap> pixmap;
772                                 if (SwigFromPython(pixmap, ppixmap))
773                                 {
774                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
775                                         goto error_out;
776                                 }
777
778                                 if (size > 6)
779                                 {
780                                         pbackColor = PyTuple_GET_ITEM(item, 6);
781                                         if (pbackColor == Py_None)
782                                                 pbackColor=ePyObject();
783                                 }
784                                 if (size > 7)
785                                 {
786                                         pbackColorSelected = PyTuple_GET_ITEM(item, 7);
787                                         if (pbackColorSelected == Py_None)
788                                                 pbackColorSelected=ePyObject();
789                                 }
790
791                                 eRect rect(x, y, width, height);
792                                 painter.clip(rect);
793                                 if (pbackColor || pbackColorSelected)
794                                 {
795                                         gRegion rc(rect);
796                                         clearRegion(painter, style, ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip);
797                                         reset_colors=true;
798                                 }
799                                 
800                                 painter.blit(pixmap, rect.topLeft(), rect, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
801                                 painter.clippop();
802                                 break;
803                         }
804                         default:
805                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
806                                 goto error_out;
807                         }
808                         if (reset_colors)
809                                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
810                 }
811         }
812
813         if (selected)
814                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
815
816 error_out:
817         if (m_buildFunc && PyCallable_Check(m_buildFunc) && items)
818                 Py_DECREF(items);
819
820         painter.clippop();
821 }
822
823 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
824 {
825         Py_XDECREF(m_buildFunc);
826         m_buildFunc=cb;
827         Py_XINCREF(m_buildFunc);
828 }
829
830 void eListboxPythonMultiContent::setSelectableFunc(ePyObject cb)
831 {
832         Py_XDECREF(m_selectableFunc);
833         m_selectableFunc=cb;
834         Py_XINCREF(m_selectableFunc);
835 }
836
837 int eListboxPythonMultiContent::currentCursorSelectable()
838 {
839         /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
840         if (m_list && cursorValid())
841         {
842                 if (m_selectableFunc && PyCallable_Check(m_selectableFunc))
843                 {
844                         ePyObject args = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
845                         if (PyTuple_Check(args))
846                         {
847                                 ePyObject ret = PyObject_CallObject(m_selectableFunc, args);
848                                 if (ret)
849                                         return ret == Py_True;
850                                 eDebug("call m_selectableFunc failed!!! assume not callable");
851                         }
852                         else
853                                 eDebug("m_list[m_cursor] is not a tuple!!! assume not callable");
854                 }
855                 else
856                 {
857                         ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
858                         if (PyList_Check(item))
859                         {
860                                 item = PyList_GET_ITEM(item, 0);
861                                 if (item != Py_None)
862                                         return 1;
863                         }
864                         else if (m_buildFunc && PyCallable_Check(m_buildFunc))
865                                 return 1;
866                 }
867         }
868         return 0;
869 }
870
871 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
872 {
873         if (font)
874                 m_font[fnt] = font;
875         else
876                 m_font.erase(fnt);
877 }
878
879 void eListboxPythonMultiContent::setItemHeight(int height)
880 {
881         m_itemheight = height;
882         if (m_listbox)
883                 m_listbox->setItemHeight(height);
884 }