1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <lib/gdi/font.h>
4 #include <lib/python/python.h>
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
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.
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.
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.
25 Although cursorSet is provided, it should be only used when there is no
26 other way, as it involves iterating trough the list.
29 iListboxContent::~iListboxContent()
33 iListboxContent::iListboxContent(): m_listbox(0)
37 void iListboxContent::setListbox(eListbox *lb)
40 m_listbox->setItemHeight(getItemHeight());
43 int iListboxContent::currentCursorSelectable()
48 //////////////////////////////////////
50 DEFINE_REF(eListboxPythonStringContent);
52 eListboxPythonStringContent::eListboxPythonStringContent(): m_itemheight(25), m_cursor(0)
56 eListboxPythonStringContent::~eListboxPythonStringContent()
61 void eListboxPythonStringContent::cursorHome()
66 void eListboxPythonStringContent::cursorEnd()
71 int eListboxPythonStringContent::cursorMove(int count)
77 else if (m_cursor > size())
82 int eListboxPythonStringContent::cursorValid()
84 return ((unsigned int)m_cursor) < size();
87 int eListboxPythonStringContent::cursorSet(int n)
93 else if (m_cursor > size())
98 int eListboxPythonStringContent::cursorGet()
103 int eListboxPythonStringContent::currentCursorSelectable()
105 if (m_list && cursorValid())
107 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
108 if (!PyTuple_Check(item))
110 if (PyTuple_Size(item) >= 2)
116 void eListboxPythonStringContent::cursorSave()
118 m_saved_cursor = m_cursor;
121 void eListboxPythonStringContent::cursorRestore()
123 m_cursor = m_saved_cursor;
126 int eListboxPythonStringContent::size()
130 return PyList_Size(m_list);
133 void eListboxPythonStringContent::setSize(const eSize &size)
138 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
140 ePtr<gFont> fnt = new gFont("Regular", 20);
141 painter.clip(eRect(offset, m_itemsize));
142 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
144 eListboxStyle *local_style = 0;
145 bool cursorValid = this->cursorValid();
147 /* get local listbox style, if present */
149 local_style = m_listbox->getLocalStyle();
155 /* if we have a local background color set, use that. */
156 if (local_style->m_background_color_selected_set)
157 painter.setBackgroundColor(local_style->m_background_color_selected);
158 /* same for foreground */
159 if (local_style->m_foreground_color_selected_set)
160 painter.setForegroundColor(local_style->m_foreground_color_selected);
164 /* if we have a local background color set, use that. */
165 if (local_style->m_background_color_set)
166 painter.setBackgroundColor(local_style->m_background_color);
167 /* same for foreground */
168 if (local_style->m_foreground_color_set)
169 painter.setForegroundColor(local_style->m_foreground_color);
173 /* if we have no transparent background */
174 if (!local_style || !local_style->m_transparent_background)
176 /* blit background picture, if available (otherwise, clear only) */
177 if (local_style && local_style->m_background && cursorValid)
178 painter.blit(local_style->m_background, offset, eRect(), 0);
183 if (local_style->m_background && cursorValid)
184 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
185 else if (selected && !local_style->m_selection)
189 if (m_list && cursorValid)
192 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
193 painter.setFont(fnt);
195 /* the user can supply tuples, in this case the first one will be displayed. */
196 if (PyTuple_Check(item))
198 if (PyTuple_Size(item) == 1)
200 item = PyTuple_GET_ITEM(item, 0);
203 if (selected && local_style && local_style->m_selection)
204 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
209 int half_height = m_itemsize.height() / 2;
210 painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
213 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
214 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
216 painter.setForegroundColor(gRGB(0x808080));
217 painter.renderText(eRect(text_offset, m_itemsize), string);
220 if (selected && (!local_style || !local_style->m_selection))
221 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
227 void eListboxPythonStringContent::setList(ePyObject list)
230 if (!PyList_Check(list))
232 m_list = ePyObject();
240 m_listbox->entryReset(false);
243 PyObject *eListboxPythonStringContent::getCurrentSelection()
245 if (!(m_list && cursorValid()))
248 ePyObject r = PyList_GET_ITEM(m_list, m_cursor);
253 void eListboxPythonStringContent::invalidateEntry(int index)
256 m_listbox->entryChanged(index);
259 void eListboxPythonStringContent::invalidate()
265 m_listbox->moveSelectionTo(s?s-1:0);
267 m_listbox->invalidate();
271 //////////////////////////////////////
273 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
275 ePtr<gFont> fnt = new gFont("Regular", 20);
276 ePtr<gFont> fnt2 = new gFont("Regular", 16);
277 eRect itemrect(offset, m_itemsize);
278 eListboxStyle *local_style = 0;
279 bool cursorValid = this->cursorValid();
281 painter.clip(itemrect);
282 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
284 /* get local listbox style, if present */
286 local_style = m_listbox->getLocalStyle();
292 /* if we have a local background color set, use that. */
293 if (local_style->m_background_color_selected_set)
294 painter.setBackgroundColor(local_style->m_background_color_selected);
295 /* same for foreground */
296 if (local_style->m_foreground_color_selected_set)
297 painter.setForegroundColor(local_style->m_foreground_color_selected);
301 /* if we have a local background color set, use that. */
302 if (local_style->m_background_color_set)
303 painter.setBackgroundColor(local_style->m_background_color);
304 /* same for foreground */
305 if (local_style->m_foreground_color_set)
306 painter.setForegroundColor(local_style->m_foreground_color);
310 if (!local_style || !local_style->m_transparent_background)
311 /* if we have no transparent background */
313 /* blit background picture, if available (otherwise, clear only) */
314 if (local_style && local_style->m_background && cursorValid)
315 painter.blit(local_style->m_background, offset, eRect(), 0);
320 if (local_style->m_background && cursorValid)
321 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
322 else if (selected && !local_style->m_selection)
326 if (m_list && cursorValid)
328 /* get current list item */
329 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
330 ePyObject text, value;
331 painter.setFont(fnt);
333 if (selected && local_style && local_style->m_selection)
334 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
336 /* the first tuple element is a string for the left side.
337 the second one will be called, and the result shall be an tuple.
340 the first one is the type (string).
341 the second one is the value. */
342 if (PyTuple_Check(item))
344 /* handle left part. get item from tuple, convert to string, display. */
346 text = PyTuple_GET_ITEM(item, 0);
347 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
348 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
349 eSize item_left = eSize(m_seperation, m_itemsize.height());
350 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
351 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
354 /* when we have no label, align value to the left. (FIXME:
355 don't we want to specifiy this individually?) */
356 int value_alignment_left = !*string;
358 /* now, handle the value. get 2nd part from tuple*/
359 value = PyTuple_GET_ITEM(item, 1);
362 ePyObject args = PyTuple_New(1);
363 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
365 /* CallObject will call __call__ which should return the value tuple */
366 value = PyObject_CallObject(value, args);
368 if (PyErr_Occurred())
372 /* the PyInt was stolen. */
375 /* check if this is really a tuple */
376 if (value && PyTuple_Check(value))
378 /* convert type to string */
379 ePyObject type = PyTuple_GET_ITEM(value, 0);
380 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
384 if (!strcmp(atype, "text"))
386 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
387 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
388 painter.setFont(fnt2);
389 if (value_alignment_left)
390 painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
392 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
394 /* pvalue is borrowed */
395 } else if (!strcmp(atype, "slider"))
397 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
398 ePyObject psize = PyTuple_GET_ITEM(value, 2);
400 /* convert value to Long. fallback to -1 on error. */
401 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
402 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
404 /* calc. slider length */
405 int width = item_right.width() * value / size;
406 int height = item_right.height();
410 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
411 //hack - make it customizable
412 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
414 /* pvalue is borrowed */
415 } else if (!strcmp(atype, "mtext"))
417 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
418 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
419 int xoffs = value_alignment_left ? 0 : m_seperation;
420 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
422 para->renderString(text, 0);
423 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
424 int glyphs = para->size();
428 if (PyTuple_Size(value) >= 3)
429 plist = PyTuple_GET_ITEM(value, 2);
433 if (plist && PyList_Check(plist))
434 entries = PyList_Size(plist);
436 int left=0, right=0, last=-1;
438 for (int i = 0; i < entries; ++i)
440 ePyObject entry = PyList_GET_ITEM(plist, i);
441 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
443 if ((num < 0) || (num >= glyphs))
444 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
447 if (last+1 != num && last != -1) {
448 bbox = eRect(left, offset.y(), right-left, m_itemsize.height());
451 para->setGlyphFlag(num, GS_INVERT);
452 bbox = para->getGlyphBBox(num);
453 if (last+1 != num || last == -1)
455 right = bbox.left() + bbox.width();
458 /* entry is borrowed */
461 bbox = eRect(left, offset.y(), right-left, m_itemsize.height());
464 painter.renderPara(para, ePoint(0, 0));
465 /* pvalue is borrowed */
466 /* plist is 0 or borrowed */
469 /* type is borrowed */
471 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
476 if (selected && (!local_style || !local_style->m_selection))
477 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
483 int eListboxPythonConfigContent::currentCursorSelectable()
485 return eListboxPythonStringContent::currentCursorSelectable();
488 //////////////////////////////////////
490 /* todo: make a real infrastructure here! */
491 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
493 eListboxPythonMultiContent::eListboxPythonMultiContent()
494 :m_clip(gRegion::invalidRegion()), m_old_clip(gRegion::invalidRegion())
498 eListboxPythonMultiContent::~eListboxPythonMultiContent()
500 Py_XDECREF(m_buildFunc);
501 Py_XDECREF(m_selectableFunc);
504 void eListboxPythonMultiContent::setSelectionClip(eRect &rect, bool update)
506 m_selection_clip = rect;
508 rect.moveBy(ePoint(0, m_listbox->getEntryTop()));
513 if (update && m_listbox)
514 m_listbox->entryChanged(m_cursor);
517 static void clearRegionHelper(gPainter &painter, eListboxStyle *local_style, const ePoint &offset, ePyObject &pbackColor, bool cursorValid, bool clear=true)
521 unsigned int color = PyInt_AsUnsignedLongMask(pbackColor);
522 painter.setBackgroundColor(gRGB(color));
524 else if (local_style)
526 if (local_style && local_style->m_background_color_set)
527 painter.setBackgroundColor(local_style->m_background_color);
528 if (local_style->m_background && cursorValid)
530 if (local_style->m_transparent_background)
531 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
533 painter.blit(local_style->m_background, offset, eRect(), 0);
536 else if (local_style->m_transparent_background)
543 static void clearRegionSelectedHelper(gPainter &painter, eListboxStyle *local_style, const ePoint &offset, ePyObject &pbackColorSelected, bool cursorValid, bool clear=true)
545 if (pbackColorSelected)
547 unsigned int color = PyInt_AsUnsignedLongMask(pbackColorSelected);
548 painter.setBackgroundColor(gRGB(color));
550 else if (local_style)
552 if (local_style && local_style->m_background_color_selected_set)
553 painter.setBackgroundColor(local_style->m_background_color_selected);
554 if (local_style->m_background && cursorValid)
556 if (local_style->m_transparent_background)
557 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
559 painter.blit(local_style->m_background, offset, eRect(), 0);
567 static void clearRegion(gPainter &painter, eWindowStyle &style, eListboxStyle *local_style, ePyObject pforeColor, ePyObject pforeColorSelected, ePyObject pbackColor, ePyObject pbackColorSelected, int selected, gRegion &rc, eRect &sel_clip, const ePoint &offset, bool cursorValid, bool clear=true)
569 if (selected && sel_clip.valid())
571 gRegion part = rc - sel_clip;
575 style.setStyle(painter, eWindowStyle::styleListboxNormal);
576 clearRegionHelper(painter, local_style, offset, pbackColor, cursorValid, clear);
580 part = rc & sel_clip;
584 style.setStyle(painter, eWindowStyle::styleListboxSelected);
585 clearRegionSelectedHelper(painter, local_style, offset, pbackColorSelected, cursorValid, clear);
592 style.setStyle(painter, eWindowStyle::styleListboxSelected);
593 clearRegionSelectedHelper(painter, local_style, offset, pbackColorSelected, cursorValid, clear);
594 if (local_style && local_style->m_selection)
595 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
599 style.setStyle(painter, eWindowStyle::styleListboxNormal);
600 clearRegionHelper(painter, local_style, offset, pbackColor, cursorValid, clear);
605 if (pforeColorSelected)
607 unsigned int color = PyInt_AsUnsignedLongMask(pforeColorSelected);
608 painter.setForegroundColor(gRGB(color));
610 /* if we have a local foreground color set, use that. */
611 else if (local_style && local_style->m_foreground_color_selected_set)
612 painter.setForegroundColor(local_style->m_foreground_color_selected);
618 unsigned int color = PyInt_AsUnsignedLongMask(pforeColor);
619 painter.setForegroundColor(gRGB(color));
621 /* if we have a local foreground color set, use that. */
622 else if (local_style && local_style->m_foreground_color_set)
623 painter.setForegroundColor(local_style->m_foreground_color);
627 static ePyObject lookupColor(ePyObject color, ePyObject data)
629 if (color == Py_None)
632 if ((!color) && (!data))
635 unsigned int icolor = PyInt_AsUnsignedLongMask(color);
637 /* check if we have the "magic" template color */
638 if ((icolor & 0xFF000000) == 0xFF000000)
640 int index = icolor & 0xFFFFFF;
641 eDebug("[eListboxPythonMultiContent] template color index: %d", index);
642 return PyTuple_GetItem(data, index);
645 if (color == Py_None)
651 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
653 gRegion itemregion(eRect(offset, m_itemsize));
654 eListboxStyle *local_style = 0;
655 eRect sel_clip(m_selection_clip);
656 bool cursorValid = this->cursorValid();
657 if (sel_clip.valid())
658 sel_clip.moveBy(offset);
660 /* get local listbox style, if present */
662 local_style = m_listbox->getLocalStyle();
664 painter.clip(itemregion);
665 clearRegion(painter, style, local_style, ePyObject(), ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip, offset, cursorValid);
667 ePyObject items, buildfunc_ret;
669 if (m_list && cursorValid)
671 /* a multicontent list can be used in two ways:
672 either each item is a list of (TYPE,...)-tuples,
673 or there is a template defined, which is a list of (TYPE,...)-tuples,
674 and the list is an unformatted tuple. The template then references items from the list.
676 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
680 if (PyCallable_Check(m_buildFunc)) // when we have a buildFunc then call it
682 if (PyTuple_Check(items))
683 buildfunc_ret = items = PyObject_CallObject(m_buildFunc, items);
685 eDebug("items is no tuple");
688 eDebug("buildfunc is not callable");
693 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
699 if (!PyList_Check(items))
701 eDebug("eListboxPythonMultiContent: list entry %d is not a list (non-templated)", m_cursor);
706 if (!PyTuple_Check(items))
708 eDebug("eListboxPythonMultiContent: list entry %d is not a tuple (templated)", m_cursor);
715 /* if we have a template, use the template for the actual formatting.
716 we will later detect that "data" is present, and refer to that, instead
717 of the immediate value. */
726 int size = PyList_Size(items);
727 for (int i = start; i < size; ++i)
729 ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
733 eDebug("eListboxPythonMultiContent: ?");
737 if (!PyTuple_Check(item))
739 eDebug("eListboxPythonMultiContent did not receive a tuple.");
743 int size = PyTuple_Size(item);
747 eDebug("eListboxPythonMultiContent receive empty tuple.");
751 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
755 case TYPE_TEXT: // text
758 (0, x, y, width, height, fnt, flags, "bla" [, color, colorSelected, backColor, backColorSelected, borderWidth, borderColor] )
760 ePyObject px = PyTuple_GET_ITEM(item, 1),
761 py = PyTuple_GET_ITEM(item, 2),
762 pwidth = PyTuple_GET_ITEM(item, 3),
763 pheight = PyTuple_GET_ITEM(item, 4),
764 pfnt = PyTuple_GET_ITEM(item, 5),
765 pflags = PyTuple_GET_ITEM(item, 6),
766 pstring = PyTuple_GET_ITEM(item, 7),
767 pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
769 if (!(px && py && pwidth && pheight && pfnt && pflags && pstring))
771 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string [, color, backColor, backColorSelected, borderWidth, borderColor])");
776 pforeColor = lookupColor(PyTuple_GET_ITEM(item, 8), data);
779 pforeColorSelected = lookupColor(PyTuple_GET_ITEM(item, 9), data);
782 pbackColor = lookupColor(PyTuple_GET_ITEM(item, 10), data);
785 pbackColorSelected = lookupColor(PyTuple_GET_ITEM(item, 11), data);
789 pborderWidth = PyTuple_GET_ITEM(item, 12);
790 if (pborderWidth == Py_None)
791 pborderWidth=ePyObject();
794 pborderColor = lookupColor(PyTuple_GET_ITEM(item, 13), data);
796 if (PyInt_Check(pstring) && data) /* if the string is in fact a number, it refers to the 'data' list. */
797 pstring = PyTuple_GetItem(data, PyInt_AsLong(pstring));
799 /* don't do anything if we have 'None' as string */
800 if (pstring == Py_None)
803 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
804 int x = PyInt_AsLong(px) + offset.x();
805 int y = PyInt_AsLong(py) + offset.y();
806 int width = PyInt_AsLong(pwidth);
807 int height = PyInt_AsLong(pheight);
808 int flags = PyInt_AsLong(pflags);
809 int fnt = PyInt_AsLong(pfnt);
810 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
812 if (m_font.find(fnt) == m_font.end())
814 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
818 eRect rect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
823 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
824 clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
827 painter.setFont(m_font[fnt]);
828 painter.renderText(rect, string, flags);
834 eRect rect(eRect(x, y, width, height));
838 unsigned int color = PyInt_AsUnsignedLongMask(pborderColor);
839 painter.setForegroundColor(gRGB(color));
842 rect.setRect(x, y, width, bwidth);
845 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
848 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
851 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
858 case TYPE_PROGRESS: // Progress
861 (1, x, y, width, height, filled_percent [, borderWidth, foreColor, backColor, backColorSelected] )
863 ePyObject px = PyTuple_GET_ITEM(item, 1),
864 py = PyTuple_GET_ITEM(item, 2),
865 pwidth = PyTuple_GET_ITEM(item, 3),
866 pheight = PyTuple_GET_ITEM(item, 4),
867 pfilled_perc = PyTuple_GET_ITEM(item, 5),
868 pborderWidth, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected;
870 if (!(px && py && pwidth && pheight && pfilled_perc))
872 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent [,border width, foreColor, backColor, backColorSelected]))");
878 pborderWidth = PyTuple_GET_ITEM(item, 6);
879 if (pborderWidth == Py_None)
880 pborderWidth = ePyObject();
884 pforeColor = PyTuple_GET_ITEM(item, 7);
885 if (pforeColor == Py_None)
886 pforeColor = ePyObject();
890 pforeColorSelected = PyTuple_GET_ITEM(item, 8);
891 if (pforeColorSelected == Py_None)
892 pforeColorSelected=ePyObject();
896 pbackColor = PyTuple_GET_ITEM(item, 9);
897 if (pbackColor == Py_None)
898 pbackColor=ePyObject();
902 pbackColorSelected = PyTuple_GET_ITEM(item, 10);
903 if (pbackColorSelected == Py_None)
904 pbackColorSelected=ePyObject();
907 int x = PyInt_AsLong(px) + offset.x();
908 int y = PyInt_AsLong(py) + offset.y();
909 int width = PyInt_AsLong(pwidth);
910 int height = PyInt_AsLong(pheight);
911 int filled = PyInt_AsLong(pfilled_perc);
913 if ((filled < 0) && data) /* if the string is in a negative number, it refers to the 'data' list. */
914 filled = PyInt_AsLong(PyTuple_GetItem(data, -filled));
916 /* don't do anything if percent out of range */
917 if ((filled < 0) || (filled > 100))
920 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 2;
922 eRect rect(x, y, width, height);
927 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
928 clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
932 rect.setRect(x, y, width, bwidth);
935 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
938 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
941 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
945 rect.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
952 case TYPE_PIXMAP_ALPHABLEND:
953 case TYPE_PIXMAP_ALPHATEST:
954 case TYPE_PIXMAP: // pixmap
957 (2, x, y, width, height, pixmap [, backColor, backColorSelected] )
960 ePyObject px = PyTuple_GET_ITEM(item, 1),
961 py = PyTuple_GET_ITEM(item, 2),
962 pwidth = PyTuple_GET_ITEM(item, 3),
963 pheight = PyTuple_GET_ITEM(item, 4),
964 ppixmap = PyTuple_GET_ITEM(item, 5),
965 pbackColor, pbackColorSelected;
967 if (!(px && py && pwidth && pheight && ppixmap))
969 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap [, backColor, backColorSelected] ))");
973 if (PyInt_Check(ppixmap) && data) /* if the pixemap is in fact a number, it refers to the 'data' list. */
974 ppixmap = PyTuple_GetItem(data, PyInt_AsLong(ppixmap));
976 /* don't do anything if we have 'None' as pixmap */
977 if (ppixmap == Py_None)
980 int x = PyInt_AsLong(px) + offset.x();
981 int y = PyInt_AsLong(py) + offset.y();
982 int width = PyInt_AsLong(pwidth);
983 int height = PyInt_AsLong(pheight);
984 ePtr<gPixmap> pixmap;
985 if (SwigFromPython(pixmap, ppixmap))
987 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
992 pbackColor = lookupColor(PyTuple_GET_ITEM(item, 6), data);
995 pbackColorSelected = lookupColor(PyTuple_GET_ITEM(item, 7), data);
997 eRect rect(x, y, width, height);
1002 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
1003 clearRegion(painter, style, local_style, ePyObject(), ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
1006 painter.blit(pixmap, rect.topLeft(), rect, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : (type == TYPE_PIXMAP_ALPHABLEND) ? gPainter::BT_ALPHABLEND : 0);
1011 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
1017 if (selected && !sel_clip.valid() && (!local_style || !local_style->m_selection))
1018 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
1022 Py_DECREF(buildfunc_ret);
1027 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
1029 Py_XDECREF(m_buildFunc);
1031 Py_XINCREF(m_buildFunc);
1034 void eListboxPythonMultiContent::setSelectableFunc(ePyObject cb)
1036 Py_XDECREF(m_selectableFunc);
1037 m_selectableFunc=cb;
1038 Py_XINCREF(m_selectableFunc);
1041 int eListboxPythonMultiContent::currentCursorSelectable()
1043 /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
1044 if (m_list && cursorValid())
1046 if (m_selectableFunc && PyCallable_Check(m_selectableFunc))
1048 ePyObject args = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
1049 if (PyTuple_Check(args))
1051 ePyObject ret = PyObject_CallObject(m_selectableFunc, args);
1054 bool retval = ret == Py_True;
1058 eDebug("call m_selectableFunc failed!!! assume not callable");
1061 eDebug("m_list[m_cursor] is not a tuple!!! assume not callable");
1065 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
1066 if (PyList_Check(item))
1068 item = PyList_GET_ITEM(item, 0);
1069 if (item != Py_None)
1071 } else if (PyTuple_Check(item))
1073 item = PyTuple_GET_ITEM(item, 0);
1074 if (item != Py_None)
1077 else if (m_buildFunc && PyCallable_Check(m_buildFunc))
1084 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
1092 void eListboxPythonMultiContent::setItemHeight(int height)
1094 m_itemheight = height;
1096 m_listbox->setItemHeight(height);
1099 void eListboxPythonMultiContent::setList(ePyObject list)
1101 m_old_clip = m_clip = gRegion::invalidRegion();
1102 eListboxPythonStringContent::setList(list);
1105 void eListboxPythonMultiContent::updateClip(gRegion &clip)
1110 if (m_old_clip.valid() && !(m_clip-m_old_clip).empty())
1111 m_clip -= m_old_clip;
1112 m_old_clip = m_clip;
1115 m_old_clip = m_clip = gRegion::invalidRegion();
1118 void eListboxPythonMultiContent::entryRemoved(int idx)
1121 m_listbox->entryRemoved(idx);
1124 void eListboxPythonMultiContent::setTemplate(ePyObject tmplate)
1126 m_template = tmplate;