d72b21bcd05a3a1e2ea1930245a6893f4a3c62e7
[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 }
264
265 void eListboxPythonStringContent::cursorHome()
266 {
267         m_cursor = 0;
268 }
269
270 void eListboxPythonStringContent::cursorEnd()
271 {
272         m_cursor = size();
273 }
274
275 int eListboxPythonStringContent::cursorMove(int count)
276 {
277         m_cursor += count;
278         
279         if (m_cursor < 0)
280                 cursorHome();
281         else if (m_cursor > size())
282                 cursorEnd();
283         return 0;
284 }
285
286 int eListboxPythonStringContent::cursorValid()
287 {
288         return m_cursor < size();
289 }
290
291 int eListboxPythonStringContent::cursorSet(int n)
292 {
293         m_cursor = n;
294         
295         if (m_cursor < 0)
296                 cursorHome();
297         else if (m_cursor > size())
298                 cursorEnd();
299         return 0;
300 }
301
302 int eListboxPythonStringContent::cursorGet()
303 {
304         return m_cursor;
305 }
306
307 void eListboxPythonStringContent::cursorSave()
308 {
309         m_saved_cursor = m_cursor;
310 }
311
312 void eListboxPythonStringContent::cursorRestore()
313 {
314         m_cursor = m_saved_cursor;
315 }
316
317 int eListboxPythonStringContent::size()
318 {
319         if (!m_list)
320                 return 0;
321         return PyList_Size(m_list);
322 }
323         
324 void eListboxPythonStringContent::setSize(const eSize &size)
325 {
326         m_itemsize = size;
327 }
328
329 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
330 {
331         ePtr<gFont> fnt = new gFont("Regular", 20);
332         painter.clip(eRect(offset, m_itemsize));
333         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
334         painter.clear();
335
336         if (m_list && cursorValid())
337         {
338                 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
339                 painter.setFont(fnt);
340
341                         /* the user can supply tuples, in this case the first one will be displayed. */         
342                 if (PyTuple_Check(item))
343                         item = PyTuple_GET_ITEM(item, 0);
344                 
345                 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
346                 
347                 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
348                 
349                 painter.renderText(eRect(text_offset, m_itemsize), string);
350                 
351                 if (selected)
352                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
353         }
354         
355         painter.clippop();
356 }
357
358 void eListboxPythonStringContent::setList(PyObject *list)
359 {
360         Py_XDECREF(m_list);
361         if (!PyList_Check(list))
362         {
363                 m_list = 0;
364         } else
365         {
366                 m_list = list;
367                 Py_INCREF(m_list);
368         }
369
370         if (m_listbox)
371                 m_listbox->entryReset(false);
372 }
373
374 PyObject *eListboxPythonStringContent::getCurrentSelection()
375 {
376         if (!m_list)
377                 return 0;
378         if (!cursorValid())
379                 return 0;
380         PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
381         Py_XINCREF(r);
382         return r;
383 }
384
385 void eListboxPythonStringContent::invalidateEntry(int index)
386 {
387         if (m_listbox)
388                 m_listbox->entryChanged(index);
389 }
390
391 void eListboxPythonStringContent::invalidate()
392 {
393         if (m_listbox)
394                 m_listbox->invalidate();
395 }
396
397 //////////////////////////////////////
398
399 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
400 {
401         ePtr<gFont> fnt = new gFont("Regular", 20);
402         ePtr<gFont> fnt2 = new gFont("Regular", 16);
403         eRect itemrect(offset, m_itemsize);
404         painter.clip(itemrect);
405         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
406         painter.clear();
407
408         if (m_list && cursorValid())
409         {
410                         /* get current list item */
411                 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
412                 PyObject *text = 0, *value = 0;
413                 painter.setFont(fnt);
414
415                         /* the first tuple element is a string for the left side.
416                            the second one will be called, and the result shall be an tuple.
417                            
418                            of this tuple,
419                            the first one is the type (string).
420                            the second one is the value. */
421                 if (PyTuple_Check(item))
422                 {
423                                 /* handle left part. get item from tuple, convert to string, display. */
424                                 
425                         text = PyTuple_GET_ITEM(item, 0);
426 //                      text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
427                         const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
428                         eSize item_left = eSize(m_seperation, m_itemsize.height());
429                         eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
430                         painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
431 //                      Py_XDECREF(text);
432                         
433                                 /* now, handle the value. get 2nd part from tuple*/
434                         value = PyTuple_GET_ITEM(item, 1);
435                         if (value)
436                         {
437                                 PyObject *args = PyTuple_New(1);
438                                 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
439                                 
440                                         /* CallObject will call __call__ which should return the value tuple */
441                                 value = PyObject_CallObject(value, args);
442                                 
443                                 if (PyErr_Occurred())
444                                         PyErr_Print();
445
446                                 Py_DECREF(args);
447                                         /* the PyInt was stolen. */
448                         }
449                         
450                                 /*  check if this is really a tuple */
451                         if (value && PyTuple_Check(value))
452                         {
453                                         /* convert type to string */
454                                 PyObject *type = PyTuple_GET_ITEM(value, 0);
455                                 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
456                                 
457                                 if (atype)
458                                 {
459                                         if (!strcmp(atype, "text"))
460                                         {
461                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
462                                                 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
463                                                 painter.setFont(fnt2);
464                                                 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
465
466                                                         /* pvalue is borrowed */
467                                         } else if (!strcmp(atype, "slider"))
468                                         {
469                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
470                                                 
471                                                         /* convert value to Long. fallback to -1 on error. */
472                                                 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
473                                                 
474                                                         /* calc. slider length */
475                                                 int width = item_right.width() * value / 100;
476                                                 int height = item_right.height();
477                                                 
478                                                                                                 
479                                                         /* draw slider */
480                                                 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
481                                                 //hack - make it customizable
482                                                 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
483                                                 
484                                                         /* pvalue is borrowed */
485                                         } else if (!strcmp(atype, "mtext"))
486                                         {
487                                                 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
488                                                 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
489                                                 
490                                                 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
491                                                 para->setFont(fnt2);
492                                                 para->renderString(text, 0);
493                                                 para->realign(eTextPara::dirRight);
494                                                 int glyphs = para->size();
495                                                 
496                                                 PyObject *plist = 0;
497                                                 
498                                                 if (PyTuple_Size(value) >= 3)
499                                                         plist = PyTuple_GET_ITEM(value, 2);
500                                                 
501                                                 int entries = 0;
502
503                                                 if (plist && PyList_Check(plist))
504                                                         entries = PyList_Size(plist);
505                                                 
506                                                 for (int i = 0; i < entries; ++i)
507                                                 {
508                                                         PyObject *entry = PyList_GET_ITEM(plist, i);
509                                                         int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
510                                                         
511                                                         if ((num < 0) || (num >= glyphs))
512                                                                 eWarning("glyph index %d in PythonConfigList out of bounds!");
513                                                         else
514                                                         {
515                                                                 para->setGlyphFlag(num, GS_INVERT);
516                                                                 eRect bbox;
517                                                                 bbox = para->getGlyphBBox(num);
518                                                                 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
519                                                                 painter.fill(bbox);
520                                                         }
521                                                                 /* entry is borrowed */
522                                                 }
523                                                 
524                                                 painter.renderPara(para, ePoint(0, 0));
525                                                         /* pvalue is borrowed */
526                                                         /* plist is 0 or borrowed */
527                                         }
528                                 }
529                                         /* type is borrowed */
530                         } else
531                                 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
532                                 /* value is borrowed */
533                 }
534
535                 if (selected)
536                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
537         }
538         
539         painter.clippop();
540 }
541
542 //////////////////////////////////////
543
544         /* todo: make a real infrastructure here! */
545 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
546
547 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
548 {
549         eRect itemrect(offset, m_itemsize);
550         painter.clip(itemrect);
551         style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
552         painter.clear();
553
554         if (m_list && cursorValid())
555         {
556                 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
557                 
558                 if (!items)
559                 {
560                         eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
561                         goto error_out;
562                 }
563                 
564                 if (!PyList_Check(items))
565                 {
566                         eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
567                         goto error_out;
568                 }
569                 
570                 int size = PyList_Size(items);
571                 for (int i = 1; i < size; ++i)
572                 {
573                         PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
574                         
575                         if (!item)
576                         {
577                                 eDebug("eListboxPythonMultiContent: ?");
578                                 goto error_out;
579                         }
580                         
581                         PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
582                 
583                         /*
584                                 we have a list of tuples:
585                                 
586                                 (0, x, y, width, height, fnt, flags, "bla" ),
587
588                                 or, for a progress:
589                                 (1, x, y, width, height, filled_percent )
590
591                                 or, for a pixmap:
592                                 
593                                 (2, x, y, width, height, pixmap )
594                                 
595                          */
596                         
597                         if (!PyTuple_Check(item))
598                         {
599                                 eDebug("eListboxPythonMultiContent did not receive a tuple.");
600                                 goto error_out;
601                         }
602
603                         int size = PyTuple_Size(item);
604
605                         if (!size)
606                         {
607                                 eDebug("eListboxPythonMultiContent receive empty tuple.");
608                                 goto error_out;
609                         }
610
611                         int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
612
613                         if (size > 5)
614                         {
615                                 px = PyTuple_GET_ITEM(item, 1);
616                                 py = PyTuple_GET_ITEM(item, 2);
617                                 pwidth = PyTuple_GET_ITEM(item, 3);
618                                 pheight = PyTuple_GET_ITEM(item, 4);
619                                 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
620                                 if (size > 7)
621                                 {
622                                         pflags = PyTuple_GET_ITEM(item, 6);
623                                         pstring = PyTuple_GET_ITEM(item, 7);
624                                 }
625                         }
626                         
627                         switch (type)
628                         {
629                         case TYPE_TEXT: // text
630                         {
631                                 if (!(px && py && pwidth && pheight && pfnt && pstring))
632                                 {
633                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
634                                         goto error_out;
635                                 }
636                                 
637                                 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
638                                 int x = PyInt_AsLong(px);
639                                 int y = PyInt_AsLong(py);
640                                 int width = PyInt_AsLong(pwidth);
641                                 int height = PyInt_AsLong(pheight);
642                                 int flags = PyInt_AsLong(pflags);
643                                 int fnt = PyInt_AsLong(pfnt);
644                                 
645                                 if (m_font.find(fnt) == m_font.end())
646                                 {
647                                         eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
648                                         goto error_out;
649                                 }
650                                 
651                                 eRect r = eRect(x, y, width, height);
652                                 r.moveBy(offset);
653                                 r &= itemrect;
654                                 
655                                 painter.setFont(m_font[fnt]);
656                                 
657                                 painter.clip(r);
658                                 painter.renderText(r, string, flags);
659                                 painter.clippop();
660                                 break;
661                         }
662                         case TYPE_PROGRESS: // Progress
663                         {
664                                 if (!(px && py && pwidth && pheight && pfnt))
665                                 {
666                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
667                                         goto error_out;
668                                 }
669                                 int x = PyInt_AsLong(px);
670                                 int y = PyInt_AsLong(py);
671                                 int width = PyInt_AsLong(pwidth);
672                                 int height = PyInt_AsLong(pheight);
673                                 int filled = PyInt_AsLong(pfnt);
674
675                                 eRect r = eRect(x, y, width, height);
676                                 r.moveBy(offset);
677                                 r &= itemrect;
678
679                                 painter.clip(r);
680                                 int bwidth=2;  // borderwidth hardcoded yet
681
682                                 // border
683                                 eRect rc = eRect(x, y, width, bwidth);
684                                 rc.moveBy(offset);
685                                 painter.fill(rc);
686
687                                 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
688                                 rc.moveBy(offset);
689                                 painter.fill(rc);
690
691                                 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
692                                 rc.moveBy(offset);
693                                 painter.fill(rc);
694
695                                 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
696                                 rc.moveBy(offset);
697                                 painter.fill(rc);
698
699                                 // progress
700                                 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
701                                 rc.moveBy(offset);
702                                 painter.fill(rc);
703
704                                 painter.clippop();
705
706                                 break;
707                         }
708                         case TYPE_PIXMAP: // pixmap
709                         {
710                                 if (!(px && py && pwidth && pheight && pfnt))
711                                 {
712                                         eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
713                                         goto error_out;
714                                 }
715                                 int x = PyInt_AsLong(px);
716                                 int y = PyInt_AsLong(py);
717                                 int width = PyInt_AsLong(pwidth);
718                                 int height = PyInt_AsLong(pheight);
719                                 ePtr<gPixmap> pixmap;
720                                 if (SwigFromPython(pixmap, pfnt))
721                                 {
722                                         eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
723                                         goto error_out;
724                                 }
725
726                                 eRect r = eRect(x, y, width, height);
727                                 r.moveBy(offset);
728                                 r &= itemrect;
729                                 
730                                 painter.clip(r);
731                                 painter.blit(pixmap, r.topLeft(), r);
732                                 painter.clippop();
733
734                                 break;
735                         }
736                         default:
737                                 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
738                                 goto error_out;
739                         }
740                 }
741         }
742         
743         if (selected)
744                 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
745
746 error_out:
747         painter.clippop();
748 }
749
750 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
751 {
752         if (font)
753                 m_font[fnt] = font;
754         else
755                 m_font.erase(fnt);
756 }