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()
265 void eListboxPythonStringContent::cursorHome()
270 void eListboxPythonStringContent::cursorEnd()
275 int eListboxPythonStringContent::cursorMove(int count)
281 else if (m_cursor > size())
286 int eListboxPythonStringContent::cursorValid()
288 return m_cursor < size();
291 int eListboxPythonStringContent::cursorSet(int n)
297 else if (m_cursor > size())
302 int eListboxPythonStringContent::cursorGet()
307 void eListboxPythonStringContent::cursorSave()
309 m_saved_cursor = m_cursor;
312 void eListboxPythonStringContent::cursorRestore()
314 m_cursor = m_saved_cursor;
317 int eListboxPythonStringContent::size()
321 return PyList_Size(m_list);
324 void eListboxPythonStringContent::setSize(const eSize &size)
329 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
331 ePtr<gFont> fnt = new gFont("Regular", 20);
332 painter.clip(eRect(offset, m_itemsize));
333 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
336 if (m_list && cursorValid())
338 PyObject *item = PyList_GetItem(m_list, m_cursor); // borrowed reference!
339 painter.setFont(fnt);
341 /* the user can supply tuples, in this case the first one will be displayed. */
342 if (PyTuple_Check(item))
343 item = PyTuple_GetItem(item, 0);
345 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
347 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
349 painter.renderText(eRect(text_offset, m_itemsize), string);
352 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
358 void eListboxPythonStringContent::setList(PyObject *list)
361 if (!PyList_Check(list))
371 m_listbox->entryReset(false);
374 PyObject *eListboxPythonStringContent::getCurrentSelection()
380 PyObject *r = PyList_GetItem(m_list, m_cursor);
385 void eListboxPythonStringContent::invalidateEntry(int index)
388 m_listbox->entryChanged(index);
391 void eListboxPythonStringContent::invalidate()
394 m_listbox->invalidate();
397 //////////////////////////////////////
399 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
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);
408 if (m_list && cursorValid())
410 /* get current list item */
411 PyObject *item = PyList_GetItem(m_list, m_cursor); // borrowed reference!
412 PyObject *text = 0, *value = 0;
413 painter.setFont(fnt);
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.
419 the first one is the type (string).
420 the second one is the value. */
421 if (PyTuple_Check(item))
423 /* handle left part. get item from tuple, convert to string, display. */
425 text = PyTuple_GetItem(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);
433 /* now, handle the value. get 2nd part from tuple*/
434 value = PyTuple_GetItem(item, 1);
437 PyObject *args = PyTuple_New(1);
438 PyTuple_SetItem(args, 0, PyInt_FromLong(selected));
440 /* CallObject will call __call__ which should return the value tuple */
441 value = PyObject_CallObject(value, args);
443 if (PyErr_Occurred())
447 /* the PyInt was stolen. */
450 /* check if this is really a tuple */
451 if (value && PyTuple_Check(value))
453 /* convert type to string */
454 PyObject *type = PyTuple_GetItem(value, 0);
455 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
459 if (!strcmp(atype, "text"))
461 PyObject *pvalue = PyTuple_GetItem(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);
466 /* pvalue is borrowed */
467 } else if (!strcmp(atype, "slider"))
469 PyObject *pvalue = PyTuple_GetItem(value, 1);
471 /* convert value to Long. fallback to -1 on error. */
472 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
474 /* calc. slider length */
475 int width = item_right.width() * value / 100;
476 int height = item_right.height();
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));
484 /* pvalue is borrowed */
485 } else if (!strcmp(atype, "mtext"))
487 PyObject *pvalue = PyTuple_GetItem(value, 1);
488 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
490 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
492 para->renderString(text, 0);
493 para->realign(eTextPara::dirRight);
494 int glyphs = para->size();
498 if (PyTuple_Size(value) >= 3)
499 plist = PyTuple_GetItem(value, 2);
503 if (plist && PyList_Check(plist))
504 entries = PyList_Size(plist);
506 for (int i = 0; i < entries; ++i)
508 PyObject *entry = PyList_GetItem(plist, i);
509 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
511 if ((num < 0) || (num >= glyphs))
512 eWarning("glyph index %d in PythonConfigList out of bounds!");
515 para->setGlyphFlag(num, GS_INVERT);
517 bbox = para->getGlyphBBox(num);
518 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
521 /* entry is borrowed */
524 painter.renderPara(para, ePoint(0, 0));
525 /* pvalue is borrowed */
526 /* plist is 0 or borrowed */
529 /* type is borrowed */
531 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
532 /* value is borrowed */
536 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
542 //////////////////////////////////////
544 /* todo: make a real infrastructure here! */
545 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
547 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
549 eRect itemrect(offset, m_itemsize);
550 painter.clip(itemrect);
551 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
554 if (m_list && cursorValid())
556 PyObject *items = PyList_GetItem(m_list, m_cursor); // borrowed reference!
560 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
564 if (!PyList_Check(items))
566 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
570 int size = PyList_Size(items);
571 for (int i = 1; i < size; ++i)
573 PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
577 eDebug("eListboxPythonMultiContent: ?");
581 PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
584 we have a list of tuples:
586 (0, x, y, width, height, fnt, flags, "bla" ),
589 (1, x, y, width, height, filled_percent )
593 (2, x, y, width, height, pixmap )
597 if (!PyTuple_Check(item))
599 eDebug("eListboxPythonMultiContent did not receive a tuple.");
603 int size = PyTuple_Size(item);
607 eDebug("eListboxPythonMultiContent receive empty tuple.");
611 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
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) */
622 pflags = PyTuple_GET_ITEM(item, 6);
623 pstring = PyTuple_GET_ITEM(item, 7);
629 case TYPE_TEXT: // text
631 if (!(px && py && pwidth && pheight && pfnt && pstring))
633 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
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);
645 if (m_font.find(fnt) == m_font.end())
647 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
651 eRect r = eRect(x, y, width, height);
655 painter.setFont(m_font[fnt]);
658 painter.renderText(r, string, flags);
662 case TYPE_PROGRESS: // Progress
664 if (!(px && py && pwidth && pheight && pfnt))
666 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
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);
675 eRect r = eRect(x, y, width, height);
680 int bwidth=2; // borderwidth hardcoded yet
683 eRect rc = eRect(x, y, width, bwidth);
687 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
691 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
695 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
700 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
708 case TYPE_PIXMAP: // pixmap
710 if (!(px && py && pwidth && pheight && pfnt))
712 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
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))
722 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
726 eRect r = eRect(x, y, width, height);
731 painter.blit(pixmap, r.topLeft(), r);
737 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
744 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
750 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)