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