1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <lib/gdi/font.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)
42 DEFINE_REF(eListboxTestContent);
44 void eListboxTestContent::cursorHome()
49 void eListboxTestContent::cursorEnd()
54 int eListboxTestContent::cursorMove(int count)
60 else if (m_cursor > size())
65 int eListboxTestContent::cursorValid()
67 return m_cursor < size();
70 int eListboxTestContent::cursorSet(int n)
76 else if (m_cursor > size())
81 int eListboxTestContent::cursorGet()
86 void eListboxTestContent::cursorSave()
88 m_saved_cursor = m_cursor;
91 void eListboxTestContent::cursorRestore()
93 m_cursor = m_saved_cursor;
96 int eListboxTestContent::size()
101 RESULT eListboxTestContent::connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection)
106 void eListboxTestContent::setSize(const eSize &size)
111 void eListboxTestContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
113 ePtr<gFont> fnt = new gFont("Regular", 20);
114 painter.clip(eRect(offset, m_size));
115 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
120 painter.setFont(fnt);
122 sprintf(string, "%d.)", m_cursor);
124 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
126 painter.renderText(eRect(text_offset, m_size), string);
129 style.drawFrame(painter, eRect(offset, m_size), eWindowStyle::frameListboxEntry);
135 //////////////////////////////////////
137 DEFINE_REF(eListboxStringContent);
139 eListboxStringContent::eListboxStringContent()
145 void eListboxStringContent::cursorHome()
147 m_cursor = m_list.begin();
151 void eListboxStringContent::cursorEnd()
153 m_cursor = m_list.end();
154 m_cursor_number = m_size;
157 int eListboxStringContent::cursorMove(int count)
161 while (count && (m_cursor != m_list.end()))
167 } else if (count < 0)
169 while (count && (m_cursor != m_list.begin()))
180 int eListboxStringContent::cursorValid()
182 return m_cursor != m_list.end();
185 int eListboxStringContent::cursorSet(int n)
193 int eListboxStringContent::cursorGet()
195 return m_cursor_number;
198 void eListboxStringContent::cursorSave()
200 m_saved_cursor = m_cursor;
201 m_saved_cursor_number = m_cursor_number;
204 void eListboxStringContent::cursorRestore()
206 m_cursor = m_saved_cursor;
207 m_cursor_number = m_saved_cursor_number;
210 int eListboxStringContent::size()
215 void eListboxStringContent::setSize(const eSize &size)
220 void eListboxStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
222 ePtr<gFont> fnt = new gFont("Regular", 20);
223 painter.clip(eRect(offset, m_itemsize));
224 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
227 eDebug("item %d", m_cursor_number);
230 eDebug("is valid..");
231 painter.setFont(fnt);
233 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
235 painter.renderText(eRect(text_offset, m_itemsize), *m_cursor);
238 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
244 void eListboxStringContent::setList(std::list<std::string> &list)
247 m_size = list.size();
249 m_listbox->entryReset(false);
252 //////////////////////////////////////
254 DEFINE_REF(eListboxPythonStringContent);
256 eListboxPythonStringContent::eListboxPythonStringContent()
261 eListboxPythonStringContent::~eListboxPythonStringContent()
266 void eListboxPythonStringContent::cursorHome()
271 void eListboxPythonStringContent::cursorEnd()
276 int eListboxPythonStringContent::cursorMove(int count)
282 else if (m_cursor > size())
287 int eListboxPythonStringContent::cursorValid()
289 return m_cursor < size();
292 int eListboxPythonStringContent::cursorSet(int n)
298 else if (m_cursor > size())
303 int eListboxPythonStringContent::cursorGet()
308 void eListboxPythonStringContent::cursorSave()
310 m_saved_cursor = m_cursor;
313 void eListboxPythonStringContent::cursorRestore()
315 m_cursor = m_saved_cursor;
318 int eListboxPythonStringContent::size()
322 return PyList_Size(m_list);
325 void eListboxPythonStringContent::setSize(const eSize &size)
330 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
332 ePtr<gFont> fnt = new gFont("Regular", 20);
333 painter.clip(eRect(offset, m_itemsize));
334 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
337 if (m_list && cursorValid())
339 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
340 painter.setFont(fnt);
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);
346 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
348 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
350 painter.renderText(eRect(text_offset, m_itemsize), string);
353 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
359 void eListboxPythonStringContent::setList(PyObject *list)
362 if (!PyList_Check(list))
372 m_listbox->entryReset(false);
375 PyObject *eListboxPythonStringContent::getCurrentSelection()
377 if (!(m_list && cursorValid()))
382 PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
387 void eListboxPythonStringContent::invalidateEntry(int index)
390 m_listbox->entryChanged(index);
393 void eListboxPythonStringContent::invalidate()
396 m_listbox->invalidate();
399 //////////////////////////////////////
401 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
403 ePtr<gFont> fnt = new gFont("Regular", 20);
404 ePtr<gFont> fnt2 = new gFont("Regular", 16);
405 eRect itemrect(offset, m_itemsize);
406 painter.clip(itemrect);
407 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
410 if (m_list && cursorValid())
412 /* get current list item */
413 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
414 PyObject *text = 0, *value = 0;
415 painter.setFont(fnt);
417 /* the first tuple element is a string for the left side.
418 the second one will be called, and the result shall be an tuple.
421 the first one is the type (string).
422 the second one is the value. */
423 if (PyTuple_Check(item))
425 /* handle left part. get item from tuple, convert to string, display. */
427 text = PyTuple_GET_ITEM(item, 0);
428 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
429 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
430 eSize item_left = eSize(m_seperation, m_itemsize.height());
431 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
432 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
435 /* when we have no label, align value to the left. (FIXME:
436 don't we want to specifiy this individually?) */
437 int value_alignment_left = !*string;
439 /* now, handle the value. get 2nd part from tuple*/
440 value = PyTuple_GET_ITEM(item, 1);
443 PyObject *args = PyTuple_New(1);
444 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
446 /* CallObject will call __call__ which should return the value tuple */
447 value = PyObject_CallObject(value, args);
449 if (PyErr_Occurred())
453 /* the PyInt was stolen. */
456 /* check if this is really a tuple */
457 if (value && PyTuple_Check(value))
459 /* convert type to string */
460 PyObject *type = PyTuple_GET_ITEM(value, 0);
461 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
465 if (!strcmp(atype, "text"))
467 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
468 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
469 painter.setFont(fnt2);
470 if (value_alignment_left)
471 painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
473 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
475 /* pvalue is borrowed */
476 } else if (!strcmp(atype, "slider"))
478 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
479 PyObject *psize = PyTuple_GET_ITEM(value, 2);
481 /* convert value to Long. fallback to -1 on error. */
482 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
483 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
485 /* calc. slider length */
486 int width = item_right.width() * value / size;
487 int height = item_right.height();
491 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
492 //hack - make it customizable
493 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
495 /* pvalue is borrowed */
496 } else if (!strcmp(atype, "mtext"))
498 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
499 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
500 int xoffs = value_alignment_left ? 0 : m_seperation;
501 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
503 para->renderString(text, 0);
504 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
505 int glyphs = para->size();
509 if (PyTuple_Size(value) >= 3)
510 plist = PyTuple_GET_ITEM(value, 2);
514 if (plist && PyList_Check(plist))
515 entries = PyList_Size(plist);
517 for (int i = 0; i < entries; ++i)
519 PyObject *entry = PyList_GET_ITEM(plist, i);
520 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
522 if ((num < 0) || (num >= glyphs))
523 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
526 para->setGlyphFlag(num, GS_INVERT);
528 bbox = para->getGlyphBBox(num);
529 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
532 /* entry is borrowed */
535 painter.renderPara(para, ePoint(0, 0));
536 /* pvalue is borrowed */
537 /* plist is 0 or borrowed */
540 /* type is borrowed */
542 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
543 /* value is borrowed */
547 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
553 //////////////////////////////////////
555 /* todo: make a real infrastructure here! */
556 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
558 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
560 eRect itemrect(offset, m_itemsize);
561 painter.clip(itemrect);
562 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
565 if (m_list && cursorValid())
567 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
571 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
575 if (!PyList_Check(items))
577 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
581 int size = PyList_Size(items);
582 for (int i = 1; i < size; ++i)
584 PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
588 eDebug("eListboxPythonMultiContent: ?");
592 PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
595 we have a list of tuples:
597 (0, x, y, width, height, fnt, flags, "bla" ),
600 (1, x, y, width, height, filled_percent )
604 (2, x, y, width, height, pixmap )
608 if (!PyTuple_Check(item))
610 eDebug("eListboxPythonMultiContent did not receive a tuple.");
614 int size = PyTuple_Size(item);
618 eDebug("eListboxPythonMultiContent receive empty tuple.");
622 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
626 px = PyTuple_GET_ITEM(item, 1);
627 py = PyTuple_GET_ITEM(item, 2);
628 pwidth = PyTuple_GET_ITEM(item, 3);
629 pheight = PyTuple_GET_ITEM(item, 4);
630 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
633 pflags = PyTuple_GET_ITEM(item, 6);
634 pstring = PyTuple_GET_ITEM(item, 7);
640 case TYPE_TEXT: // text
642 if (!(px && py && pwidth && pheight && pfnt && pstring))
644 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
648 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
649 int x = PyInt_AsLong(px);
650 int y = PyInt_AsLong(py);
651 int width = PyInt_AsLong(pwidth);
652 int height = PyInt_AsLong(pheight);
653 int flags = PyInt_AsLong(pflags);
654 int fnt = PyInt_AsLong(pfnt);
656 if (m_font.find(fnt) == m_font.end())
658 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
662 eRect r = eRect(x, y, width, height);
666 painter.setFont(m_font[fnt]);
669 painter.renderText(r, string, flags);
673 case TYPE_PROGRESS: // Progress
675 if (!(px && py && pwidth && pheight && pfnt))
677 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
680 int x = PyInt_AsLong(px);
681 int y = PyInt_AsLong(py);
682 int width = PyInt_AsLong(pwidth);
683 int height = PyInt_AsLong(pheight);
684 int filled = PyInt_AsLong(pfnt);
686 eRect r = eRect(x, y, width, height);
691 int bwidth=2; // borderwidth hardcoded yet
694 eRect rc = eRect(x, y, width, bwidth);
698 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
702 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
706 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
711 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
719 case TYPE_PIXMAP_ALPHATEST:
720 case TYPE_PIXMAP: // pixmap
722 if (!(px && py && pwidth && pheight && pfnt))
724 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
727 int x = PyInt_AsLong(px);
728 int y = PyInt_AsLong(py);
729 int width = PyInt_AsLong(pwidth);
730 int height = PyInt_AsLong(pheight);
731 ePtr<gPixmap> pixmap;
732 if (SwigFromPython(pixmap, pfnt))
734 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
738 eRect r = eRect(x, y, width, height);
743 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
749 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
756 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
762 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)