5421f2529555720b1a7f744111a4cd4894fdd579
[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 <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 }
41
42 DEFINE_REF(eListboxTestContent);
43
44 void eListboxTestContent::cursorHome()
45 {
46         m_cursor = 0;
47 }
48
49 void eListboxTestContent::cursorEnd()
50 {
51         m_cursor = size();
52 }
53
54 int eListboxTestContent::cursorMove(int count)
55 {
56         m_cursor += count;
57         
58         if (m_cursor < 0)
59                 cursorHome();
60         else if (m_cursor > size())
61                 cursorEnd();
62         return 0;
63 }
64
65 int eListboxTestContent::cursorValid()
66 {
67         return m_cursor < size();
68 }
69
70 int eListboxTestContent::cursorSet(int n)
71 {
72         m_cursor = n;
73         
74         if (m_cursor < 0)
75                 cursorHome();
76         else if (m_cursor > size())
77                 cursorEnd();
78         return 0;
79 }
80
81 int eListboxTestContent::cursorGet()
82 {
83         return m_cursor;
84 }
85
86 void eListboxTestContent::cursorSave()
87 {
88         m_saved_cursor = m_cursor;
89 }
90
91 void eListboxTestContent::cursorRestore()
92 {
93         m_cursor = m_saved_cursor;
94 }
95
96 int eListboxTestContent::size()
97 {
98         return 10;
99 }
100         
101 RESULT eListboxTestContent::connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection)
102 {
103         return 0;
104 }
105
106 void eListboxTestContent::setSize(const eSize &size)
107 {
108         m_size = size;
109 }
110
111 void eListboxTestContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
112 {
113         ePtr<gFont> fnt = new gFont("Regular", 20);
114         painter.clip(eRect(offset, m_size));
115         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
116         painter.clear();
117
118         if (cursorValid())
119         {
120                 painter.setFont(fnt);
121                 char string[10];
122                 sprintf(string, "%d.)", m_cursor);
123                 
124                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
125                 
126                 painter.renderText(eRect(text_offset, m_size), string);
127                 
128                 if (selected)
129                         style.drawFrame(painter, eRect(offset, m_size), eWindowStyle::frameListboxEntry);
130         }
131         
132         painter.clippop();
133 }
134
135 //////////////////////////////////////
136
137 DEFINE_REF(eListboxStringContent);
138
139 eListboxStringContent::eListboxStringContent()
140 {
141         m_size = 0;
142         cursorHome();
143 }
144
145 void eListboxStringContent::cursorHome()
146 {
147         m_cursor = m_list.begin();
148         m_cursor_number = 0;
149 }
150
151 void eListboxStringContent::cursorEnd()
152 {
153         m_cursor = m_list.end();
154         m_cursor_number = m_size;
155 }
156
157 int eListboxStringContent::cursorMove(int count)
158 {
159         if (count > 0)
160         {
161                 while (count && (m_cursor != m_list.end()))
162                 {
163                         ++m_cursor;
164                         ++m_cursor_number;
165                         --count;
166                 }
167         } else if (count < 0)
168         {
169                 while (count && (m_cursor != m_list.begin()))
170                 {
171                         --m_cursor;
172                         --m_cursor_number;
173                         ++count;
174                 }
175         }
176         
177         return 0;
178 }
179
180 int eListboxStringContent::cursorValid()
181 {
182         return m_cursor != m_list.end();
183 }
184
185 int eListboxStringContent::cursorSet(int n)
186 {
187         cursorHome();
188         cursorMove(n);
189         
190         return 0;
191 }
192
193 int eListboxStringContent::cursorGet()
194 {
195         return m_cursor_number;
196 }
197
198 void eListboxStringContent::cursorSave()
199 {
200         m_saved_cursor = m_cursor;
201         m_saved_cursor_number = m_cursor_number;
202 }
203
204 void eListboxStringContent::cursorRestore()
205 {
206         m_cursor = m_saved_cursor;
207         m_cursor_number = m_saved_cursor_number;
208 }
209
210 int eListboxStringContent::size()
211 {
212         return m_size;
213 }
214         
215 void eListboxStringContent::setSize(const eSize &size)
216 {
217         m_itemsize = size;
218 }
219
220 void eListboxStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
221 {
222         ePtr<gFont> fnt = new gFont("Regular", 20);
223         painter.clip(eRect(offset, m_itemsize));
224         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
225         painter.clear();
226         
227         eDebug("item %d", m_cursor_number);
228         if (cursorValid())
229         {
230                 eDebug("is valid..");
231                 painter.setFont(fnt);
232                 
233                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
234                 
235                 painter.renderText(eRect(text_offset, m_itemsize), *m_cursor);
236                 
237                 if (selected)
238                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
239         }
240         
241         painter.clippop();
242 }
243
244 void eListboxStringContent::setList(std::list<std::string> &list)
245 {
246         m_list = list;
247         m_size = list.size();
248         cursorHome();
249         m_listbox->entryReset(false);
250 }
251
252 //////////////////////////////////////
253
254 DEFINE_REF(eListboxPythonStringContent);
255
256 eListboxPythonStringContent::eListboxPythonStringContent()
257 {
258         m_list = 0;
259 }
260
261 eListboxPythonStringContent::~eListboxPythonStringContent()
262 {
263         Py_XDECREF(m_list);
264 }
265
266 void eListboxPythonStringContent::cursorHome()
267 {
268         m_cursor = 0;
269 }
270
271 void eListboxPythonStringContent::cursorEnd()
272 {
273         m_cursor = size();
274 }
275
276 int eListboxPythonStringContent::cursorMove(int count)
277 {
278         m_cursor += count;
279         
280         if (m_cursor < 0)
281                 cursorHome();
282         else if (m_cursor > size())
283                 cursorEnd();
284         return 0;
285 }
286
287 int eListboxPythonStringContent::cursorValid()
288 {
289         return m_cursor < size();
290 }
291
292 int eListboxPythonStringContent::cursorSet(int n)
293 {
294         m_cursor = n;
295         
296         if (m_cursor < 0)
297                 cursorHome();
298         else if (m_cursor > size())
299                 cursorEnd();
300         return 0;
301 }
302
303 int eListboxPythonStringContent::cursorGet()
304 {
305         return m_cursor;
306 }
307
308 void eListboxPythonStringContent::cursorSave()
309 {
310         m_saved_cursor = m_cursor;
311 }
312
313 void eListboxPythonStringContent::cursorRestore()
314 {
315         m_cursor = m_saved_cursor;
316 }
317
318 int eListboxPythonStringContent::size()
319 {
320         if (!m_list)
321                 return 0;
322         return PyList_Size(m_list);
323 }
324         
325 void eListboxPythonStringContent::setSize(const eSize &size)
326 {
327         m_itemsize = size;
328 }
329
330 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
331 {
332         ePtr<gFont> fnt = new gFont("Regular", 20);
333         painter.clip(eRect(offset, m_itemsize));
334         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
335         painter.clear();
336
337         if (m_list && cursorValid())
338         {
339                 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
340                 painter.setFont(fnt);
341
342                         /* the user can supply tuples, in this case the first one will be displayed. */         
343                 if (PyTuple_Check(item))
344                         item = PyTuple_GET_ITEM(item, 0);
345                 
346                 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
347                 
348                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
349                 
350                 painter.renderText(eRect(text_offset, m_itemsize), string);
351                 
352                 if (selected)
353                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
354         }
355         
356         painter.clippop();
357 }
358
359 void eListboxPythonStringContent::setList(PyObject *list)
360 {
361         Py_XDECREF(m_list);
362         if (!PyList_Check(list))
363         {
364                 m_list = 0;
365         } else
366         {
367                 m_list = list;
368                 Py_INCREF(m_list);
369         }
370
371         if (m_listbox)
372                 m_listbox->entryReset(false);
373 }
374
375 PyObject *eListboxPythonStringContent::getCurrentSelection()
376 {
377         if (!m_list)
378                 return 0;
379         if (!cursorValid())
380                 return 0;
381         PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
382         Py_XINCREF(r);
383         return r;
384 }
385
386 void eListboxPythonStringContent::invalidateEntry(int index)
387 {
388         if (m_listbox)
389                 m_listbox->entryChanged(index);
390 }
391
392 void eListboxPythonStringContent::invalidate()
393 {
394         if (m_listbox)
395                 m_listbox->invalidate();
396 }
397
398 //////////////////////////////////////
399
400 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
401 {
402         ePtr<gFont> fnt = new gFont("Regular", 20);
403         ePtr<gFont> fnt2 = new gFont("Regular", 16);
404         eRect itemrect(offset, m_itemsize);
405         painter.clip(itemrect);
406         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
407         painter.clear();
408
409         if (m_list && cursorValid())
410         {
411                         /* get current list item */
412                 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
413                 PyObject *text = 0, *value = 0;
414                 painter.setFont(fnt);
415
416                         /* the first tuple element is a string for the left side.
417                            the second one will be called, and the result shall be an tuple.
418                            
419                            of this tuple,
420                            the first one is the type (string).
421                            the second one is the value. */
422                 if (PyTuple_Check(item))
423                 {
424                                 /* handle left part. get item from tuple, convert to string, display. */
425                                 
426                         text = PyTuple_GET_ITEM(item, 0);
427                         text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
428                         const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
429                         eSize item_left = eSize(m_seperation, m_itemsize.height());
430                         eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
431                         painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
432                         Py_XDECREF(text);
433                         
434                                 /* when we have no label, align value to the left. (FIXME: 
435                                    don't we want to specifiy this individually?) */
436                         int value_alignment_left = !*string;
437                         
438                                 /* now, handle the value. get 2nd part from tuple*/
439                         value = PyTuple_GET_ITEM(item, 1);
440                         if (value)
441                         {
442                                 PyObject *args = PyTuple_New(1);
443                                 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
444                                 
445                                         /* CallObject will call __call__ which should return the value tuple */
446                                 value = PyObject_CallObject(value, args);
447                                 
448                                 if (PyErr_Occurred())
449                                         PyErr_Print();
450
451                                 Py_DECREF(args);
452                                         /* the PyInt was stolen. */
453                         }
454                         
455                                 /*  check if this is really a tuple */
456                         if (value && PyTuple_Check(value))
457                         {
458                                         /* convert type to string */
459                                 PyObject *type = PyTuple_GET_ITEM(value, 0);
460                                 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
461                                 
462                                 if (atype)
463                                 {
464                                         if (!strcmp(atype, "text"))
465                                         {
466                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
467                                                 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
468                                                 painter.setFont(fnt2);
469                                                 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, value_alignment_left ? gPainter::RT_HALIGN_LEFT : gPainter::RT_HALIGN_RIGHT);
470
471                                                         /* pvalue is borrowed */
472                                         } else if (!strcmp(atype, "slider"))
473                                         {
474                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
475                                                 
476                                                         /* convert value to Long. fallback to -1 on error. */
477                                                 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
478                                                 
479                                                         /* calc. slider length */
480                                                 int width = item_right.width() * value / 100;
481                                                 int height = item_right.height();
482                                                 
483                                                                                                 
484                                                         /* draw slider */
485                                                 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
486                                                 //hack - make it customizable
487                                                 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
488                                                 
489                                                         /* pvalue is borrowed */
490                                         } else if (!strcmp(atype, "mtext"))
491                                         {
492                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
493                                                 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
494                                                 
495                                                 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
496                                                 para->setFont(fnt2);
497                                                 para->renderString(text, 0);
498                                                 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
499                                                 int glyphs = para->size();
500                                                 
501                                                 PyObject *plist = 0;
502                                                 
503                                                 if (PyTuple_Size(value) >= 3)
504                                                         plist = PyTuple_GET_ITEM(value, 2);
505                                                 
506                                                 int entries = 0;
507
508                                                 if (plist && PyList_Check(plist))
509                                                         entries = PyList_Size(plist);
510                                                 
511                                                 for (int i = 0; i < entries; ++i)
512                                                 {
513                                                         PyObject *entry = PyList_GET_ITEM(plist, i);
514                                                         int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
515                                                         
516                                                         if ((num < 0) || (num >= glyphs))
517                                                                 eWarning("glyph index %d in PythonConfigList out of bounds!");
518                                                         else
519                                                         {
520                                                                 para->setGlyphFlag(num, GS_INVERT);
521                                                                 eRect bbox;
522                                                                 bbox = para->getGlyphBBox(num);
523                                                                 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
524                                                                 painter.fill(bbox);
525                                                         }
526                                                                 /* entry is borrowed */
527                                                 }
528                                                 
529                                                 painter.renderPara(para, ePoint(0, 0));
530                                                         /* pvalue is borrowed */
531                                                         /* plist is 0 or borrowed */
532                                         }
533                                 }
534                                         /* type is borrowed */
535                         } else
536                                 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
537                                 /* value is borrowed */
538                 }
539
540                 if (selected)
541                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
542         }
543         
544         painter.clippop();
545 }
546
547 //////////////////////////////////////
548
549         /* todo: make a real infrastructure here! */
550 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
551
552 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
553 {
554         eRect itemrect(offset, m_itemsize);
555         painter.clip(itemrect);
556         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
557         painter.clear();
558
559         if (m_list && cursorValid())
560         {
561                 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
562                 
563                 if (!items)
564                 {
565                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
566                         goto error_out;
567                 }
568                 
569                 if (!PyList_Check(items))
570                 {
571                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
572                         goto error_out;
573                 }
574                 
575                 int size = PyList_Size(items);
576                 for (int i = 1; i < size; ++i)
577                 {
578                         PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
579                         
580                         if (!item)
581                         {
582                                 eDebug("eListboxPythonMultiContent: ?");
583                                 goto error_out;
584                         }
585                         
586                         PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
587                 
588                         /*
589                                 we have a list of tuples:
590                                 
591                                 (0, x, y, width, height, fnt, flags, "bla" ),
592
593                                 or, for a progress:
594                                 (1, x, y, width, height, filled_percent )
595
596                                 or, for a pixmap:
597                                 
598                                 (2, x, y, width, height, pixmap )
599                                 
600                          */
601                         
602                         if (!PyTuple_Check(item))
603                         {
604                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
605                                 goto error_out;
606                         }
607
608                         int size = PyTuple_Size(item);
609
610                         if (!size)
611                         {
612                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
613                                 goto error_out;
614                         }
615
616                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
617
618                         if (size > 5)
619                         {
620                                 px = PyTuple_GET_ITEM(item, 1);
621                                 py = PyTuple_GET_ITEM(item, 2);
622                                 pwidth = PyTuple_GET_ITEM(item, 3);
623                                 pheight = PyTuple_GET_ITEM(item, 4);
624                                 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
625                                 if (size > 7)
626                                 {
627                                         pflags = PyTuple_GET_ITEM(item, 6);
628                                         pstring = PyTuple_GET_ITEM(item, 7);
629                                 }
630                         }
631                         
632                         switch (type)
633                         {
634                         case TYPE_TEXT: // text
635                         {
636                                 if (!(px && py && pwidth && pheight && pfnt && pstring))
637                                 {
638                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
639                                         goto error_out;
640                                 }
641                                 
642                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
643                                 int x = PyInt_AsLong(px);
644                                 int y = PyInt_AsLong(py);
645                                 int width = PyInt_AsLong(pwidth);
646                                 int height = PyInt_AsLong(pheight);
647                                 int flags = PyInt_AsLong(pflags);
648                                 int fnt = PyInt_AsLong(pfnt);
649                                 
650                                 if (m_font.find(fnt) == m_font.end())
651                                 {
652                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
653                                         goto error_out;
654                                 }
655                                 
656                                 eRect r = eRect(x, y, width, height);
657                                 r.moveBy(offset);
658                                 r &= itemrect;
659                                 
660                                 painter.setFont(m_font[fnt]);
661                                 
662                                 painter.clip(r);
663                                 painter.renderText(r, string, flags);
664                                 painter.clippop();
665                                 break;
666                         }
667                         case TYPE_PROGRESS: // Progress
668                         {
669                                 if (!(px && py && pwidth && pheight && pfnt))
670                                 {
671                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
672                                         goto error_out;
673                                 }
674                                 int x = PyInt_AsLong(px);
675                                 int y = PyInt_AsLong(py);
676                                 int width = PyInt_AsLong(pwidth);
677                                 int height = PyInt_AsLong(pheight);
678                                 int filled = PyInt_AsLong(pfnt);
679
680                                 eRect r = eRect(x, y, width, height);
681                                 r.moveBy(offset);
682                                 r &= itemrect;
683
684                                 painter.clip(r);
685                                 int bwidth=2;  // borderwidth hardcoded yet
686
687                                 // border
688                                 eRect rc = eRect(x, y, width, bwidth);
689                                 rc.moveBy(offset);
690                                 painter.fill(rc);
691
692                                 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
693                                 rc.moveBy(offset);
694                                 painter.fill(rc);
695
696                                 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
697                                 rc.moveBy(offset);
698                                 painter.fill(rc);
699
700                                 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
701                                 rc.moveBy(offset);
702                                 painter.fill(rc);
703
704                                 // progress
705                                 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
706                                 rc.moveBy(offset);
707                                 painter.fill(rc);
708
709                                 painter.clippop();
710
711                                 break;
712                         }
713                         case TYPE_PIXMAP: // pixmap
714                         {
715                                 if (!(px && py && pwidth && pheight && pfnt))
716                                 {
717                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
718                                         goto error_out;
719                                 }
720                                 int x = PyInt_AsLong(px);
721                                 int y = PyInt_AsLong(py);
722                                 int width = PyInt_AsLong(pwidth);
723                                 int height = PyInt_AsLong(pheight);
724                                 ePtr<gPixmap> pixmap;
725                                 if (SwigFromPython(pixmap, pfnt))
726                                 {
727                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
728                                         goto error_out;
729                                 }
730
731                                 eRect r = eRect(x, y, width, height);
732                                 r.moveBy(offset);
733                                 r &= itemrect;
734                                 
735                                 painter.clip(r);
736                                 painter.blit(pixmap, r.topLeft(), r);
737                                 painter.clippop();
738
739                                 break;
740                         }
741                         default:
742                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
743                                 goto error_out;
744                         }
745                 }
746         }
747         
748         if (selected)
749                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
750
751 error_out:
752         painter.clippop();
753 }
754
755 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
756 {
757         if (font)
758                 m_font[fnt] = font;
759         else
760                 m_font.erase(fnt);
761 }