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