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()
53 :m_cursor(0), m_itemheight(25)
57 eListboxPythonStringContent::~eListboxPythonStringContent()
62 void eListboxPythonStringContent::cursorHome()
67 void eListboxPythonStringContent::cursorEnd()
72 int eListboxPythonStringContent::cursorMove(int count)
78 else if (m_cursor > size())
83 int eListboxPythonStringContent::cursorValid()
85 return m_cursor < size();
88 int eListboxPythonStringContent::cursorSet(int n)
94 else if (m_cursor > size())
99 int eListboxPythonStringContent::cursorGet()
104 int eListboxPythonStringContent::currentCursorSelectable()
106 if (m_list && cursorValid())
108 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
109 if (!PyTuple_Check(item))
111 if (PyTuple_Size(item) >= 2)
117 void eListboxPythonStringContent::cursorSave()
119 m_saved_cursor = m_cursor;
122 void eListboxPythonStringContent::cursorRestore()
124 m_cursor = m_saved_cursor;
127 int eListboxPythonStringContent::size()
131 return PyList_Size(m_list);
134 void eListboxPythonStringContent::setSize(const eSize &size)
139 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
141 ePtr<gFont> fnt = new gFont("Regular", 20);
142 painter.clip(eRect(offset, m_itemsize));
143 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
145 eListboxStyle *local_style = 0;
146 bool cursorValid = this->cursorValid();
148 /* get local listbox style, if present */
150 local_style = m_listbox->getLocalStyle();
156 /* if we have a local background color set, use that. */
157 if (local_style->m_background_color_selected_set)
158 painter.setBackgroundColor(local_style->m_background_color_selected);
159 /* same for foreground */
160 if (local_style->m_foreground_color_selected_set)
161 painter.setForegroundColor(local_style->m_foreground_color_selected);
165 /* if we have a local background color set, use that. */
166 if (local_style->m_background_color_set)
167 painter.setBackgroundColor(local_style->m_background_color);
168 /* same for foreground */
169 if (local_style->m_foreground_color_set)
170 painter.setForegroundColor(local_style->m_foreground_color);
174 /* if we have no transparent background */
175 if (!local_style || !local_style->m_transparent_background)
177 /* blit background picture, if available (otherwise, clear only) */
178 if (local_style && local_style->m_background && cursorValid)
179 painter.blit(local_style->m_background, offset, eRect(), 0);
184 if (local_style->m_background && cursorValid)
185 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
186 else if (selected && !local_style->m_selection)
190 if (m_list && cursorValid)
193 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
194 painter.setFont(fnt);
196 /* the user can supply tuples, in this case the first one will be displayed. */
197 if (PyTuple_Check(item))
199 if (PyTuple_Size(item) == 1)
201 item = PyTuple_GET_ITEM(item, 0);
204 if (selected && local_style && local_style->m_selection)
205 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
210 int half_height = m_itemsize.height() / 2;
211 painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
214 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
215 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
217 painter.setForegroundColor(gRGB(0x808080));
218 painter.renderText(eRect(text_offset, m_itemsize), string);
221 if (selected && (!local_style || !local_style->m_selection))
222 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
228 void eListboxPythonStringContent::setList(ePyObject list)
231 if (!PyList_Check(list))
233 m_list = ePyObject();
241 m_listbox->entryReset(false);
244 PyObject *eListboxPythonStringContent::getCurrentSelection()
246 if (!(m_list && cursorValid()))
249 ePyObject r = PyList_GET_ITEM(m_list, m_cursor);
254 void eListboxPythonStringContent::invalidateEntry(int index)
257 m_listbox->entryChanged(index);
260 void eListboxPythonStringContent::invalidate()
266 m_listbox->moveSelectionTo(s?s-1:0);
268 m_listbox->invalidate();
272 //////////////////////////////////////
274 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
276 ePtr<gFont> fnt = new gFont("Regular", 20);
277 ePtr<gFont> fnt2 = new gFont("Regular", 16);
278 eRect itemrect(offset, m_itemsize);
279 eListboxStyle *local_style = 0;
280 bool cursorValid = this->cursorValid();
282 painter.clip(itemrect);
283 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
285 /* get local listbox style, if present */
287 local_style = m_listbox->getLocalStyle();
293 /* if we have a local background color set, use that. */
294 if (local_style->m_background_color_selected_set)
295 painter.setBackgroundColor(local_style->m_background_color_selected);
296 /* same for foreground */
297 if (local_style->m_foreground_color_selected_set)
298 painter.setForegroundColor(local_style->m_foreground_color_selected);
302 /* if we have a local background color set, use that. */
303 if (local_style->m_background_color_set)
304 painter.setBackgroundColor(local_style->m_background_color);
305 /* same for foreground */
306 if (local_style->m_foreground_color_set)
307 painter.setForegroundColor(local_style->m_foreground_color);
311 if (!local_style || !local_style->m_transparent_background)
312 /* if we have no transparent background */
314 /* blit background picture, if available (otherwise, clear only) */
315 if (local_style && local_style->m_background && cursorValid)
316 painter.blit(local_style->m_background, offset, eRect(), 0);
321 if (local_style->m_background && cursorValid)
322 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
323 else if (selected && !local_style->m_selection)
327 if (m_list && cursorValid)
329 /* get current list item */
330 ePyObject item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
331 ePyObject text, value;
332 painter.setFont(fnt);
334 if (selected && local_style && local_style->m_selection)
335 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
337 /* the first tuple element is a string for the left side.
338 the second one will be called, and the result shall be an tuple.
341 the first one is the type (string).
342 the second one is the value. */
343 if (PyTuple_Check(item))
345 /* handle left part. get item from tuple, convert to string, display. */
347 text = PyTuple_GET_ITEM(item, 0);
348 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
349 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
350 eSize item_left = eSize(m_seperation, m_itemsize.height());
351 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
352 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
355 /* when we have no label, align value to the left. (FIXME:
356 don't we want to specifiy this individually?) */
357 int value_alignment_left = !*string;
359 /* now, handle the value. get 2nd part from tuple*/
360 value = PyTuple_GET_ITEM(item, 1);
363 ePyObject args = PyTuple_New(1);
364 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
366 /* CallObject will call __call__ which should return the value tuple */
367 value = PyObject_CallObject(value, args);
369 if (PyErr_Occurred())
373 /* the PyInt was stolen. */
376 /* check if this is really a tuple */
377 if (value && PyTuple_Check(value))
379 /* convert type to string */
380 ePyObject type = PyTuple_GET_ITEM(value, 0);
381 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
385 if (!strcmp(atype, "text"))
387 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
388 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
389 painter.setFont(fnt2);
390 if (value_alignment_left)
391 painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
393 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
395 /* pvalue is borrowed */
396 } else if (!strcmp(atype, "slider"))
398 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
399 ePyObject psize = PyTuple_GET_ITEM(value, 2);
401 /* convert value to Long. fallback to -1 on error. */
402 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
403 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
405 /* calc. slider length */
406 int width = item_right.width() * value / size;
407 int height = item_right.height();
411 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
412 //hack - make it customizable
413 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
415 /* pvalue is borrowed */
416 } else if (!strcmp(atype, "mtext"))
418 ePyObject pvalue = PyTuple_GET_ITEM(value, 1);
419 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
420 int xoffs = value_alignment_left ? 0 : m_seperation;
421 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
423 para->renderString(text, 0);
424 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
425 int glyphs = para->size();
429 if (PyTuple_Size(value) >= 3)
430 plist = PyTuple_GET_ITEM(value, 2);
434 if (plist && PyList_Check(plist))
435 entries = PyList_Size(plist);
437 int left=0, right=0, last=-1;
439 for (int i = 0; i < entries; ++i)
441 ePyObject entry = PyList_GET_ITEM(plist, i);
442 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
444 if ((num < 0) || (num >= glyphs))
445 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
448 if (last+1 != num && last != -1) {
449 bbox = eRect(left, offset.y(), right-left, m_itemsize.height());
452 para->setGlyphFlag(num, GS_INVERT);
453 bbox = para->getGlyphBBox(num);
454 if (last+1 != num || last == -1)
456 right = bbox.left() + bbox.width();
459 /* entry is borrowed */
462 bbox = eRect(left, offset.y(), right-left, m_itemsize.height());
465 painter.renderPara(para, ePoint(0, 0));
466 /* pvalue is borrowed */
467 /* plist is 0 or borrowed */
470 /* type is borrowed */
472 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
477 if (selected && (!local_style || !local_style->m_selection))
478 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
484 int eListboxPythonConfigContent::currentCursorSelectable()
486 return eListboxPythonStringContent::currentCursorSelectable();
489 //////////////////////////////////////
491 /* todo: make a real infrastructure here! */
492 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
494 eListboxPythonMultiContent::eListboxPythonMultiContent()
495 :m_clip(gRegion::invalidRegion()), m_old_clip(gRegion::invalidRegion())
499 eListboxPythonMultiContent::~eListboxPythonMultiContent()
501 Py_XDECREF(m_buildFunc);
502 Py_XDECREF(m_selectableFunc);
505 void eListboxPythonMultiContent::setSelectionClip(eRect &rect, bool update)
507 m_selection_clip = rect;
509 rect.moveBy(ePoint(0, m_listbox->getEntryTop()));
514 if (update && m_listbox)
515 m_listbox->entryChanged(m_cursor);
518 static void clearRegionHelper(gPainter &painter, eListboxStyle *local_style, const ePoint &offset, ePyObject &pbackColor, bool cursorValid, bool clear=true)
522 unsigned int color = PyInt_AsUnsignedLongMask(pbackColor);
523 painter.setBackgroundColor(gRGB(color));
525 else if (local_style)
527 if (local_style && local_style->m_background_color_set)
528 painter.setBackgroundColor(local_style->m_background_color);
529 if (local_style->m_background && cursorValid)
531 if (local_style->m_transparent_background)
532 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
534 painter.blit(local_style->m_background, offset, eRect(), 0);
537 else if (local_style->m_transparent_background)
544 static void clearRegionSelectedHelper(gPainter &painter, eListboxStyle *local_style, const ePoint &offset, ePyObject &pbackColorSelected, bool cursorValid, bool clear=true)
546 if (pbackColorSelected)
548 unsigned int color = PyInt_AsUnsignedLongMask(pbackColorSelected);
549 painter.setBackgroundColor(gRGB(color));
551 else if (local_style)
553 if (local_style && local_style->m_background_color_selected_set)
554 painter.setBackgroundColor(local_style->m_background_color_selected);
555 if (local_style->m_background && cursorValid)
557 if (local_style->m_transparent_background)
558 painter.blit(local_style->m_background, offset, eRect(), gPainter::BT_ALPHATEST);
560 painter.blit(local_style->m_background, offset, eRect(), 0);
568 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)
570 if (selected && sel_clip.valid())
572 gRegion part = rc - sel_clip;
576 style.setStyle(painter, eWindowStyle::styleListboxNormal);
577 clearRegionHelper(painter, local_style, offset, pbackColor, cursorValid, clear);
581 part = rc & sel_clip;
585 style.setStyle(painter, eWindowStyle::styleListboxSelected);
586 clearRegionSelectedHelper(painter, local_style, offset, pbackColorSelected, cursorValid, clear);
593 style.setStyle(painter, eWindowStyle::styleListboxSelected);
594 clearRegionSelectedHelper(painter, local_style, offset, pbackColorSelected, cursorValid, clear);
595 if (local_style && local_style->m_selection)
596 painter.blit(local_style->m_selection, offset, eRect(), gPainter::BT_ALPHATEST);
600 style.setStyle(painter, eWindowStyle::styleListboxNormal);
601 clearRegionHelper(painter, local_style, offset, pbackColor, cursorValid, clear);
606 if (pforeColorSelected)
608 unsigned int color = PyInt_AsUnsignedLongMask(pforeColorSelected);
609 painter.setForegroundColor(gRGB(color));
611 /* if we have a local foreground color set, use that. */
612 else if (local_style && local_style->m_foreground_color_selected_set)
613 painter.setForegroundColor(local_style->m_foreground_color_selected);
619 unsigned int color = PyInt_AsUnsignedLongMask(pforeColor);
620 painter.setForegroundColor(gRGB(color));
622 /* if we have a local foreground color set, use that. */
623 else if (local_style && local_style->m_foreground_color_set)
624 painter.setForegroundColor(local_style->m_foreground_color);
628 static ePyObject lookupColor(ePyObject color, ePyObject data)
630 if (color == Py_None)
633 if ((!color) && (!data))
636 unsigned int icolor = PyInt_AsUnsignedLongMask(color);
638 /* check if we have the "magic" template color */
639 if ((icolor & 0xFF000000) == 0xFF000000)
641 int index = icolor & 0xFFFFFF;
642 eDebug("[eListboxPythonMultiContent] template color index: %d", index);
643 return PyTuple_GetItem(data, index);
646 if (color == Py_None)
652 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
654 gRegion itemregion(eRect(offset, m_itemsize));
655 eListboxStyle *local_style = 0;
656 eRect sel_clip(m_selection_clip);
657 bool cursorValid = this->cursorValid();
658 if (sel_clip.valid())
659 sel_clip.moveBy(offset);
661 /* get local listbox style, if present */
663 local_style = m_listbox->getLocalStyle();
665 painter.clip(itemregion);
666 clearRegion(painter, style, local_style, ePyObject(), ePyObject(), ePyObject(), ePyObject(), selected, itemregion, sel_clip, offset, cursorValid);
668 ePyObject items, buildfunc_ret;
670 if (m_list && cursorValid)
672 /* a multicontent list can be used in two ways:
673 either each item is a list of (TYPE,...)-tuples,
674 or there is a template defined, which is a list of (TYPE,...)-tuples,
675 and the list is an unformatted tuple. The template then references items from the list.
677 items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
681 if (PyCallable_Check(m_buildFunc)) // when we have a buildFunc then call it
683 if (PyTuple_Check(items))
684 buildfunc_ret = items = PyObject_CallObject(m_buildFunc, items);
686 eDebug("items is no tuple");
689 eDebug("buildfunc is not callable");
694 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
700 if (!PyList_Check(items))
702 eDebug("eListboxPythonMultiContent: list entry %d is not a list (non-templated)", m_cursor);
707 if (!PyTuple_Check(items))
709 eDebug("eListboxPythonMultiContent: list entry %d is not a tuple (templated)", m_cursor);
716 /* if we have a template, use the template for the actual formatting.
717 we will later detect that "data" is present, and refer to that, instead
718 of the immediate value. */
727 int size = PyList_Size(items);
728 for (int i = start; i < size; ++i)
730 ePyObject item = PyList_GET_ITEM(items, i); // borrowed reference!
734 eDebug("eListboxPythonMultiContent: ?");
738 if (!PyTuple_Check(item))
740 eDebug("eListboxPythonMultiContent did not receive a tuple.");
744 int size = PyTuple_Size(item);
748 eDebug("eListboxPythonMultiContent receive empty tuple.");
752 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
756 case TYPE_TEXT: // text
759 (0, x, y, width, height, fnt, flags, "bla" [, color, colorSelected, backColor, backColorSelected, borderWidth, borderColor] )
761 ePyObject px = PyTuple_GET_ITEM(item, 1),
762 py = PyTuple_GET_ITEM(item, 2),
763 pwidth = PyTuple_GET_ITEM(item, 3),
764 pheight = PyTuple_GET_ITEM(item, 4),
765 pfnt = PyTuple_GET_ITEM(item, 5),
766 pflags = PyTuple_GET_ITEM(item, 6),
767 pstring = PyTuple_GET_ITEM(item, 7),
768 pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, pborderWidth, pborderColor;
770 if (!(px && py && pwidth && pheight && pfnt && pflags && pstring))
772 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string [, color, backColor, backColorSelected, borderWidth, borderColor])");
777 pforeColor = lookupColor(PyTuple_GET_ITEM(item, 8), data);
780 pforeColorSelected = lookupColor(PyTuple_GET_ITEM(item, 9), data);
783 pbackColor = lookupColor(PyTuple_GET_ITEM(item, 10), data);
786 pbackColorSelected = lookupColor(PyTuple_GET_ITEM(item, 11), data);
790 pborderWidth = PyTuple_GET_ITEM(item, 12);
791 if (pborderWidth == Py_None)
792 pborderWidth=ePyObject();
795 pborderColor = lookupColor(PyTuple_GET_ITEM(item, 13), data);
797 if (PyInt_Check(pstring) && data) /* if the string is in fact a number, it refers to the 'data' list. */
798 pstring = PyTuple_GetItem(data, PyInt_AsLong(pstring));
800 /* don't do anything if we have 'None' as string */
801 if (pstring == Py_None)
804 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
805 int x = PyInt_AsLong(px) + offset.x();
806 int y = PyInt_AsLong(py) + offset.y();
807 int width = PyInt_AsLong(pwidth);
808 int height = PyInt_AsLong(pheight);
809 int flags = PyInt_AsLong(pflags);
810 int fnt = PyInt_AsLong(pfnt);
811 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 0;
813 if (m_font.find(fnt) == m_font.end())
815 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
819 eRect rect(x+bwidth, y+bwidth, width-bwidth*2, height-bwidth*2);
824 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
825 clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
828 painter.setFont(m_font[fnt]);
829 painter.renderText(rect, string, flags);
835 eRect rect(eRect(x, y, width, height));
839 unsigned int color = PyInt_AsUnsignedLongMask(pborderColor);
840 painter.setForegroundColor(gRGB(color));
843 rect.setRect(x, y, width, bwidth);
846 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
849 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
852 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
859 case TYPE_PROGRESS: // Progress
862 (1, x, y, width, height, filled_percent [, borderWidth, foreColor, backColor, backColorSelected] )
864 ePyObject px = PyTuple_GET_ITEM(item, 1),
865 py = PyTuple_GET_ITEM(item, 2),
866 pwidth = PyTuple_GET_ITEM(item, 3),
867 pheight = PyTuple_GET_ITEM(item, 4),
868 pfilled_perc = PyTuple_GET_ITEM(item, 5),
869 pborderWidth, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected;
871 if (!(px && py && pwidth && pheight && pfilled_perc))
873 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent [,border width, foreColor, backColor, backColorSelected]))");
879 pborderWidth = PyTuple_GET_ITEM(item, 6);
880 if (pborderWidth == Py_None)
881 pborderWidth = ePyObject();
885 pforeColor = PyTuple_GET_ITEM(item, 7);
886 if (pforeColor == Py_None)
887 pforeColor = ePyObject();
891 pforeColorSelected = PyTuple_GET_ITEM(item, 8);
892 if (pforeColorSelected == Py_None)
893 pforeColorSelected=ePyObject();
897 pbackColor = PyTuple_GET_ITEM(item, 9);
898 if (pbackColor == Py_None)
899 pbackColor=ePyObject();
903 pbackColorSelected = PyTuple_GET_ITEM(item, 10);
904 if (pbackColorSelected == Py_None)
905 pbackColorSelected=ePyObject();
908 int x = PyInt_AsLong(px) + offset.x();
909 int y = PyInt_AsLong(py) + offset.y();
910 int width = PyInt_AsLong(pwidth);
911 int height = PyInt_AsLong(pheight);
912 int filled = PyInt_AsLong(pfilled_perc);
914 if ((filled < 0) && data) /* if the string is in a negative number, it refers to the 'data' list. */
915 filled = PyInt_AsLong(PyTuple_GetItem(data, -filled));
917 /* don't do anything if percent out of range */
918 if ((filled < 0) || (filled > 100))
921 int bwidth = pborderWidth ? PyInt_AsLong(pborderWidth) : 2;
923 eRect rect(x, y, width, height);
928 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
929 clearRegion(painter, style, local_style, pforeColor, pforeColorSelected, pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
933 rect.setRect(x, y, width, bwidth);
936 rect.setRect(x, y+bwidth, bwidth, height-bwidth);
939 rect.setRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
942 rect.setRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
946 rect.setRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
953 case TYPE_PIXMAP_ALPHABLEND:
954 case TYPE_PIXMAP_ALPHATEST:
955 case TYPE_PIXMAP: // pixmap
958 (2, x, y, width, height, pixmap [, backColor, backColorSelected] )
961 ePyObject px = PyTuple_GET_ITEM(item, 1),
962 py = PyTuple_GET_ITEM(item, 2),
963 pwidth = PyTuple_GET_ITEM(item, 3),
964 pheight = PyTuple_GET_ITEM(item, 4),
965 ppixmap = PyTuple_GET_ITEM(item, 5),
966 pbackColor, pbackColorSelected;
968 if (!(px && py && pwidth && pheight && ppixmap))
970 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap [, backColor, backColorSelected] ))");
974 if (PyInt_Check(ppixmap) && data) /* if the pixemap is in fact a number, it refers to the 'data' list. */
975 ppixmap = PyTuple_GetItem(data, PyInt_AsLong(ppixmap));
977 /* don't do anything if we have 'None' as pixmap */
978 if (ppixmap == Py_None)
981 int x = PyInt_AsLong(px) + offset.x();
982 int y = PyInt_AsLong(py) + offset.y();
983 int width = PyInt_AsLong(pwidth);
984 int height = PyInt_AsLong(pheight);
985 ePtr<gPixmap> pixmap;
986 if (SwigFromPython(pixmap, ppixmap))
988 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
993 pbackColor = lookupColor(PyTuple_GET_ITEM(item, 6), data);
996 pbackColorSelected = lookupColor(PyTuple_GET_ITEM(item, 7), data);
998 eRect rect(x, y, width, height);
1003 bool mustClear = (selected && pbackColorSelected) || (!selected && pbackColor);
1004 clearRegion(painter, style, local_style, ePyObject(), ePyObject(), pbackColor, pbackColorSelected, selected, rc, sel_clip, offset, cursorValid, mustClear);
1007 painter.blit(pixmap, rect.topLeft(), rect, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : (type == TYPE_PIXMAP_ALPHABLEND) ? gPainter::BT_ALPHABLEND : 0);
1012 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
1018 if (selected && !sel_clip.valid() && (!local_style || !local_style->m_selection))
1019 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
1023 Py_DECREF(buildfunc_ret);
1028 void eListboxPythonMultiContent::setBuildFunc(ePyObject cb)
1030 Py_XDECREF(m_buildFunc);
1032 Py_XINCREF(m_buildFunc);
1035 void eListboxPythonMultiContent::setSelectableFunc(ePyObject cb)
1037 Py_XDECREF(m_selectableFunc);
1038 m_selectableFunc=cb;
1039 Py_XINCREF(m_selectableFunc);
1042 int eListboxPythonMultiContent::currentCursorSelectable()
1044 /* each list-entry is a list of tuples. if the first of these is none, it's not selectable */
1045 if (m_list && cursorValid())
1047 if (m_selectableFunc && PyCallable_Check(m_selectableFunc))
1049 ePyObject args = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
1050 if (PyTuple_Check(args))
1052 ePyObject ret = PyObject_CallObject(m_selectableFunc, args);
1055 bool retval = ret == Py_True;
1059 eDebug("call m_selectableFunc failed!!! assume not callable");
1062 eDebug("m_list[m_cursor] is not a tuple!!! assume not callable");
1066 ePyObject item = PyList_GET_ITEM(m_list, m_cursor);
1067 if (PyList_Check(item))
1069 item = PyList_GET_ITEM(item, 0);
1070 if (item != Py_None)
1072 } else if (PyTuple_Check(item))
1074 item = PyTuple_GET_ITEM(item, 0);
1075 if (item != Py_None)
1078 else if (m_buildFunc && PyCallable_Check(m_buildFunc))
1085 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)
1093 void eListboxPythonMultiContent::setItemHeight(int height)
1095 m_itemheight = height;
1097 m_listbox->setItemHeight(height);
1100 void eListboxPythonMultiContent::setList(ePyObject list)
1102 m_old_clip = m_clip = gRegion::invalidRegion();
1103 eListboxPythonStringContent::setList(list);
1106 void eListboxPythonMultiContent::updateClip(gRegion &clip)
1111 if (m_old_clip.valid() && !(m_clip-m_old_clip).empty())
1112 m_clip -= m_old_clip;
1113 m_old_clip = m_clip;
1116 m_old_clip = m_clip = gRegion::invalidRegion();
1119 void eListboxPythonMultiContent::entryRemoved(int idx)
1122 m_listbox->entryRemoved(idx);
1125 void eListboxPythonMultiContent::setTemplate(ePyObject tmplate)
1127 m_template = tmplate;