change direction of content to left aligned when length of text is zero
[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                                 /* now, handle the value. get 2nd part from tuple*/
435                         value = PyTuple_GET_ITEM(item, 1);
436                         if (value)
437                         {
438                                 PyObject *args = PyTuple_New(1);
439                                 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
440                                 
441                                         /* CallObject will call __call__ which should return the value tuple */
442                                 value = PyObject_CallObject(value, args);
443                                 
444                                 if (PyErr_Occurred())
445                                         PyErr_Print();
446
447                                 Py_DECREF(args);
448                                         /* the PyInt was stolen. */
449                         }
450                         
451                                 /*  check if this is really a tuple */
452                         if (value && PyTuple_Check(value))
453                         {
454                                         /* convert type to string */
455                                 PyObject *type = PyTuple_GET_ITEM(value, 0);
456                                 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
457                                 
458                                 if (atype)
459                                 {
460                                         if (!strcmp(atype, "text"))
461                                         {
462                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
463                                                 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
464                                                 painter.setFont(fnt2);
465                                                 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
466
467                                                         /* pvalue is borrowed */
468                                         } else if (!strcmp(atype, "slider"))
469                                         {
470                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
471                                                 
472                                                         /* convert value to Long. fallback to -1 on error. */
473                                                 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
474                                                 
475                                                         /* calc. slider length */
476                                                 int width = item_right.width() * value / 100;
477                                                 int height = item_right.height();
478                                                 
479                                                                                                 
480                                                         /* draw slider */
481                                                 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
482                                                 //hack - make it customizable
483                                                 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
484                                                 
485                                                         /* pvalue is borrowed */
486                                         } else if (!strcmp(atype, "mtext"))
487                                         {
488                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
489                                                 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
490                                                 
491                                                 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
492                                                 para->setFont(fnt2);
493                                                 para->renderString(text, 0);
494                                                 if (strlen(text) != 0)
495                                                         para->realign(eTextPara::dirRight);
496                                                 else
497                                                         para->realign(eTextPara::dirLeft);
498                                                 int glyphs = para->size();
499                                                 
500                                                 PyObject *plist = 0;
501                                                 
502                                                 if (PyTuple_Size(value) >= 3)
503                                                         plist = PyTuple_GET_ITEM(value, 2);
504                                                 
505                                                 int entries = 0;
506
507                                                 if (plist && PyList_Check(plist))
508                                                         entries = PyList_Size(plist);
509                                                 
510                                                 for (int i = 0; i < entries; ++i)
511                                                 {
512                                                         PyObject *entry = PyList_GET_ITEM(plist, i);
513                                                         int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
514                                                         
515                                                         if ((num < 0) || (num >= glyphs))
516                                                                 eWarning("glyph index %d in PythonConfigList out of bounds!");
517                                                         else
518                                                         {
519                                                                 para->setGlyphFlag(num, GS_INVERT);
520                                                                 eRect bbox;
521                                                                 bbox = para->getGlyphBBox(num);
522                                                                 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
523                                                                 painter.fill(bbox);
524                                                         }
525                                                                 /* entry is borrowed */
526                                                 }
527                                                 
528                                                 painter.renderPara(para, ePoint(0, 0));
529                                                         /* pvalue is borrowed */
530                                                         /* plist is 0 or borrowed */
531                                         }
532                                 }
533                                         /* type is borrowed */
534                         } else
535                                 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
536                                 /* value is borrowed */
537                 }
538
539                 if (selected)
540                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
541         }
542         
543         painter.clippop();
544 }
545
546 //////////////////////////////////////
547
548         /* todo: make a real infrastructure here! */
549 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
550
551 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
552 {
553         eRect itemrect(offset, m_itemsize);
554         painter.clip(itemrect);
555         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
556         painter.clear();
557
558         if (m_list && cursorValid())
559         {
560                 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
561                 
562                 if (!items)
563                 {
564                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
565                         goto error_out;
566                 }
567                 
568                 if (!PyList_Check(items))
569                 {
570                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
571                         goto error_out;
572                 }
573                 
574                 int size = PyList_Size(items);
575                 for (int i = 1; i < size; ++i)
576                 {
577                         PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
578                         
579                         if (!item)
580                         {
581                                 eDebug("eListboxPythonMultiContent: ?");
582                                 goto error_out;
583                         }
584                         
585                         PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
586                 
587                         /*
588                                 we have a list of tuples:
589                                 
590                                 (0, x, y, width, height, fnt, flags, "bla" ),
591
592                                 or, for a progress:
593                                 (1, x, y, width, height, filled_percent )
594
595                                 or, for a pixmap:
596                                 
597                                 (2, x, y, width, height, pixmap )
598                                 
599                          */
600                         
601                         if (!PyTuple_Check(item))
602                         {
603                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
604                                 goto error_out;
605                         }
606
607                         int size = PyTuple_Size(item);
608
609                         if (!size)
610                         {
611                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
612                                 goto error_out;
613                         }
614
615                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
616
617                         if (size > 5)
618                         {
619                                 px = PyTuple_GET_ITEM(item, 1);
620                                 py = PyTuple_GET_ITEM(item, 2);
621                                 pwidth = PyTuple_GET_ITEM(item, 3);
622                                 pheight = PyTuple_GET_ITEM(item, 4);
623                                 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
624                                 if (size > 7)
625                                 {
626                                         pflags = PyTuple_GET_ITEM(item, 6);
627                                         pstring = PyTuple_GET_ITEM(item, 7);
628                                 }
629                         }
630                         
631                         switch (type)
632                         {
633                         case TYPE_TEXT: // text
634                         {
635                                 if (!(px && py && pwidth && pheight && pfnt && pstring))
636                                 {
637                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
638                                         goto error_out;
639                                 }
640                                 
641                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
642                                 int x = PyInt_AsLong(px);
643                                 int y = PyInt_AsLong(py);
644                                 int width = PyInt_AsLong(pwidth);
645                                 int height = PyInt_AsLong(pheight);
646                                 int flags = PyInt_AsLong(pflags);
647                                 int fnt = PyInt_AsLong(pfnt);
648                                 
649                                 if (m_font.find(fnt) == m_font.end())
650                                 {
651                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
652                                         goto error_out;
653                                 }
654                                 
655                                 eRect r = eRect(x, y, width, height);
656                                 r.moveBy(offset);
657                                 r &= itemrect;
658                                 
659                                 painter.setFont(m_font[fnt]);
660                                 
661                                 painter.clip(r);
662                                 painter.renderText(r, string, flags);
663                                 painter.clippop();
664                                 break;
665                         }
666                         case TYPE_PROGRESS: // Progress
667                         {
668                                 if (!(px && py && pwidth && pheight && pfnt))
669                                 {
670                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
671                                         goto error_out;
672                                 }
673                                 int x = PyInt_AsLong(px);
674                                 int y = PyInt_AsLong(py);
675                                 int width = PyInt_AsLong(pwidth);
676                                 int height = PyInt_AsLong(pheight);
677                                 int filled = PyInt_AsLong(pfnt);
678
679                                 eRect r = eRect(x, y, width, height);
680                                 r.moveBy(offset);
681                                 r &= itemrect;
682
683                                 painter.clip(r);
684                                 int bwidth=2;  // borderwidth hardcoded yet
685
686                                 // border
687                                 eRect rc = eRect(x, y, width, bwidth);
688                                 rc.moveBy(offset);
689                                 painter.fill(rc);
690
691                                 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
692                                 rc.moveBy(offset);
693                                 painter.fill(rc);
694
695                                 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
696                                 rc.moveBy(offset);
697                                 painter.fill(rc);
698
699                                 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
700                                 rc.moveBy(offset);
701                                 painter.fill(rc);
702
703                                 // progress
704                                 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
705                                 rc.moveBy(offset);
706                                 painter.fill(rc);
707
708                                 painter.clippop();
709
710                                 break;
711                         }
712                         case TYPE_PIXMAP: // pixmap
713                         {
714                                 if (!(px && py && pwidth && pheight && pfnt))
715                                 {
716                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
717                                         goto error_out;
718                                 }
719                                 int x = PyInt_AsLong(px);
720                                 int y = PyInt_AsLong(py);
721                                 int width = PyInt_AsLong(pwidth);
722                                 int height = PyInt_AsLong(pheight);
723                                 ePtr<gPixmap> pixmap;
724                                 if (SwigFromPython(pixmap, pfnt))
725                                 {
726                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
727                                         goto error_out;
728                                 }
729
730                                 eRect r = eRect(x, y, width, height);
731                                 r.moveBy(offset);
732                                 r &= itemrect;
733                                 
734                                 painter.clip(r);
735                                 painter.blit(pixmap, r.topLeft(), r);
736                                 painter.clippop();
737
738                                 break;
739                         }
740                         default:
741                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
742                                 goto error_out;
743                         }
744                 }
745         }
746         
747         if (selected)
748                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
749
750 error_out:
751         painter.clippop();
752 }
753
754 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
755 {
756         if (font)
757                 m_font[fnt] = font;
758         else
759                 m_font.erase(fnt);
760 }