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