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()
381 PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
386 void eListboxPythonStringContent::invalidateEntry(int index)
389 m_listbox->entryChanged(index);
392 void eListboxPythonStringContent::invalidate()
395 m_listbox->invalidate();
398 //////////////////////////////////////
400 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
402 ePtr<gFont> fnt = new gFont("Regular", 20);
403 ePtr<gFont> fnt2 = new gFont("Regular", 16);
404 eRect itemrect(offset, m_itemsize);
405 painter.clip(itemrect);
406 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
409 if (m_list && cursorValid())
411 /* get current list item */
412 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
413 PyObject *text = 0, *value = 0;
414 painter.setFont(fnt);
416 /* the first tuple element is a string for the left side.
417 the second one will be called, and the result shall be an tuple.
420 the first one is the type (string).
421 the second one is the value. */
422 if (PyTuple_Check(item))
424 /* handle left part. get item from tuple, convert to string, display. */
426 text = PyTuple_GET_ITEM(item, 0);
427 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
428 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
429 eSize item_left = eSize(m_seperation, m_itemsize.height());
430 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
431 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
434 /* now, handle the value. get 2nd part from tuple*/
435 value = PyTuple_GET_ITEM(item, 1);
438 PyObject *args = PyTuple_New(1);
439 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
441 /* CallObject will call __call__ which should return the value tuple */
442 value = PyObject_CallObject(value, args);
444 if (PyErr_Occurred())
448 /* the PyInt was stolen. */
451 /* check if this is really a tuple */
452 if (value && PyTuple_Check(value))
454 /* convert type to string */
455 PyObject *type = PyTuple_GET_ITEM(value, 0);
456 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
460 if (!strcmp(atype, "text"))
462 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
463 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
464 painter.setFont(fnt2);
465 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
467 /* pvalue is borrowed */
468 } else if (!strcmp(atype, "slider"))
470 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
472 /* convert value to Long. fallback to -1 on error. */
473 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
475 /* calc. slider length */
476 int width = item_right.width() * value / 100;
477 int height = item_right.height();
481 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
482 //hack - make it customizable
483 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
485 /* pvalue is borrowed */
486 } else if (!strcmp(atype, "mtext"))
488 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
489 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
491 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
493 para->renderString(text, 0);
494 if (strlen(text) != 0)
495 para->realign(eTextPara::dirRight);
497 para->realign(eTextPara::dirLeft);
498 int glyphs = para->size();
502 if (PyTuple_Size(value) >= 3)
503 plist = PyTuple_GET_ITEM(value, 2);
507 if (plist && PyList_Check(plist))
508 entries = PyList_Size(plist);
510 for (int i = 0; i < entries; ++i)
512 PyObject *entry = PyList_GET_ITEM(plist, i);
513 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
515 if ((num < 0) || (num >= glyphs))
516 eWarning("glyph index %d in PythonConfigList out of bounds!");
519 para->setGlyphFlag(num, GS_INVERT);
521 bbox = para->getGlyphBBox(num);
522 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
525 /* entry is borrowed */
528 painter.renderPara(para, ePoint(0, 0));
529 /* pvalue is borrowed */
530 /* plist is 0 or borrowed */
533 /* type is borrowed */
535 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
536 /* value is borrowed */
540 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
546 //////////////////////////////////////
548 /* todo: make a real infrastructure here! */
549 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
551 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
553 eRect itemrect(offset, m_itemsize);
554 painter.clip(itemrect);
555 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
558 if (m_list && cursorValid())
560 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
564 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
568 if (!PyList_Check(items))
570 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
574 int size = PyList_Size(items);
575 for (int i = 1; i < size; ++i)
577 PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
581 eDebug("eListboxPythonMultiContent: ?");
585 PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
588 we have a list of tuples:
590 (0, x, y, width, height, fnt, flags, "bla" ),
593 (1, x, y, width, height, filled_percent )
597 (2, x, y, width, height, pixmap )
601 if (!PyTuple_Check(item))
603 eDebug("eListboxPythonMultiContent did not receive a tuple.");
607 int size = PyTuple_Size(item);
611 eDebug("eListboxPythonMultiContent receive empty tuple.");
615 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
619 px = PyTuple_GET_ITEM(item, 1);
620 py = PyTuple_GET_ITEM(item, 2);
621 pwidth = PyTuple_GET_ITEM(item, 3);
622 pheight = PyTuple_GET_ITEM(item, 4);
623 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
626 pflags = PyTuple_GET_ITEM(item, 6);
627 pstring = PyTuple_GET_ITEM(item, 7);
633 case TYPE_TEXT: // text
635 if (!(px && py && pwidth && pheight && pfnt && pstring))
637 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
641 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
642 int x = PyInt_AsLong(px);
643 int y = PyInt_AsLong(py);
644 int width = PyInt_AsLong(pwidth);
645 int height = PyInt_AsLong(pheight);
646 int flags = PyInt_AsLong(pflags);
647 int fnt = PyInt_AsLong(pfnt);
649 if (m_font.find(fnt) == m_font.end())
651 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
655 eRect r = eRect(x, y, width, height);
659 painter.setFont(m_font[fnt]);
662 painter.renderText(r, string, flags);
666 case TYPE_PROGRESS: // Progress
668 if (!(px && py && pwidth && pheight && pfnt))
670 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
673 int x = PyInt_AsLong(px);
674 int y = PyInt_AsLong(py);
675 int width = PyInt_AsLong(pwidth);
676 int height = PyInt_AsLong(pheight);
677 int filled = PyInt_AsLong(pfnt);
679 eRect r = eRect(x, y, width, height);
684 int bwidth=2; // borderwidth hardcoded yet
687 eRect rc = eRect(x, y, width, bwidth);
691 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
695 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
699 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
704 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
712 case TYPE_PIXMAP: // pixmap
714 if (!(px && py && pwidth && pheight && pfnt))
716 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
719 int x = PyInt_AsLong(px);
720 int y = PyInt_AsLong(py);
721 int width = PyInt_AsLong(pwidth);
722 int height = PyInt_AsLong(pheight);
723 ePtr<gPixmap> pixmap;
724 if (SwigFromPython(pixmap, pfnt))
726 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
730 eRect r = eRect(x, y, width, height);
735 painter.blit(pixmap, r.topLeft(), r);
741 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
748 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
754 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)