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("Arial", 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("Arial", 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();
251 //////////////////////////////////////
253 DEFINE_REF(eListboxPythonStringContent);
255 eListboxPythonStringContent::eListboxPythonStringContent()
260 eListboxPythonStringContent::~eListboxPythonStringContent()
264 void eListboxPythonStringContent::cursorHome()
269 void eListboxPythonStringContent::cursorEnd()
274 int eListboxPythonStringContent::cursorMove(int count)
280 else if (m_cursor > size())
285 int eListboxPythonStringContent::cursorValid()
287 return m_cursor < size();
290 int eListboxPythonStringContent::cursorSet(int n)
296 else if (m_cursor > size())
301 int eListboxPythonStringContent::cursorGet()
306 void eListboxPythonStringContent::cursorSave()
308 m_saved_cursor = m_cursor;
311 void eListboxPythonStringContent::cursorRestore()
313 m_cursor = m_saved_cursor;
316 int eListboxPythonStringContent::size()
320 return PyList_Size(m_list);
323 void eListboxPythonStringContent::setSize(const eSize &size)
328 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
330 ePtr<gFont> fnt = new gFont("Arial", 20);
331 painter.clip(eRect(offset, m_itemsize));
332 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
335 if (m_list && cursorValid())
337 PyObject *item = PyList_GetItem(m_list, m_cursor); // borrowed reference!
338 painter.setFont(fnt);
340 /* the user can supply tuples, in this case the first one will be displayed. */
341 if (PyTuple_Check(item))
342 item = PyTuple_GetItem(item, 0);
344 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
346 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
348 painter.renderText(eRect(text_offset, m_itemsize), string);
351 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
357 void eListboxPythonStringContent::setList(PyObject *list)
360 if (!PyList_Check(list))
370 PyObject *eListboxPythonStringContent::getCurrentSelection()
376 PyObject *r = PyList_GetItem(m_list, m_cursor);
381 void eListboxPythonStringContent::invalidateEntry(int index)
384 m_listbox->entryChanged(index);
387 void eListboxPythonStringContent::invalidate()
390 m_listbox->entryReset();
393 //////////////////////////////////////
395 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
397 ePtr<gFont> fnt = new gFont("Arial", 20);
398 ePtr<gFont> fnt2 = new gFont("Arial", 16);
399 painter.clip(eRect(offset, m_itemsize));
400 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
403 if (m_list && cursorValid())
405 /* get current list item */
406 PyObject *item = PyList_GetItem(m_list, m_cursor); // borrowed reference!
407 PyObject *text = 0, *value = 0;
408 painter.setFont(fnt);
410 /* the first tuple element is a string for the left side.
411 the second one will be called, and the result shall be an tuple.
414 the first one is the type (string).
415 the second one is the value. */
416 if (PyTuple_Check(item))
418 /* handle left part. get item from tuple, convert to string, display. */
420 text = PyTuple_GetItem(item, 0);
421 text = PyObject_Str(text);
422 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
423 eSize item_left = eSize(m_seperation, m_itemsize.height());
424 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
425 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
428 /* now, handle the value. get 2nd part from tuple*/
429 value = PyTuple_GetItem(item, 1);
432 PyObject *args = PyTuple_New(1);
433 PyTuple_SetItem(args, 0, PyInt_FromLong(selected));
435 /* CallObject will call __call__ which should return the value tuple */
436 value = PyObject_CallObject(value, args);
438 if (PyErr_Occurred())
442 /* the PyInt was stolen. */
445 /* check if this is really a tuple */
446 if (value && PyTuple_Check(value))
448 /* convert type to string */
449 PyObject *type = PyTuple_GetItem(value, 0);
450 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
454 if (!strcmp(atype, "text"))
456 PyObject *pvalue = PyTuple_GetItem(value, 1);
457 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
458 painter.setFont(fnt2);
459 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
461 /* pvalue is borrowed */
462 } else if (!strcmp(atype, "slider"))
464 PyObject *pvalue = PyTuple_GetItem(value, 1);
466 /* convert value to Long. fallback to -1 on error. */
467 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
469 /* calc. slider length */
470 int width = item_right.width() * value / 100;
471 int height = item_right.height();
475 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
476 //hack - make it customizable
477 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
479 /* pvalue is borrowed */
480 } else if (!strcmp(atype, "mtext"))
482 PyObject *pvalue = PyTuple_GetItem(value, 1);
483 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
485 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(m_seperation, 0), item_right));
487 para->renderString(text, 0);
488 para->realign(eTextPara::dirRight);
489 int glyphs = para->size();
493 if (PyTuple_Size(value) >= 3)
494 plist = PyTuple_GetItem(value, 2);
498 if (plist && PyList_Check(plist))
499 entries = PyList_Size(plist);
501 for (int i = 0; i < entries; ++i)
503 PyObject *entry = PyList_GetItem(plist, i);
504 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
506 if ((num < 0) || (num >= glyphs))
507 eWarning("glyph index %d in PythonConfigList out of bounds!");
510 para->setGlyphFlag(num, GS_INVERT);
512 bbox = para->getGlyphBBox(num);
513 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
516 /* entry is borrowed */
519 painter.renderPara(para, ePoint(0, 0));
520 /* pvalue is borrowed */
521 /* plist is 0 or borrowed */
526 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
527 /* value is borrowed */
531 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
537 //////////////////////////////////////
539 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
541 painter.clip(eRect(offset, m_itemsize));
542 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
545 if (m_list && cursorValid())
547 PyObject *items = PyList_GetItem(m_list, m_cursor); // borrowed reference!
551 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
556 if (!PyList_Check(items))
558 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
563 int size = PyList_Size(items);
564 for (int i = 1; i < size; ++i)
566 PyObject *item = PyList_GetItem(items, i); // borrowed reference!
570 eDebug("eListboxPythonMultiContent: ?");
576 PyObject *px, *py, *pwidth, *pheight, *pfnt, *pstring, *pflags;
579 we have a list of tuples:
581 (x, y, width, height, fnt, flags, "bla" ),
585 if (!PyTuple_Check(item))
587 eDebug("eListboxPythonMultiContent did not receive a tuple.");
592 px = PyTuple_GetItem(item, 0);
593 py = PyTuple_GetItem(item, 1);
594 pwidth = PyTuple_GetItem(item, 2);
595 pheight = PyTuple_GetItem(item, 3);
596 pfnt = PyTuple_GetItem(item, 4);
597 pflags = PyTuple_GetItem(item, 5);
598 pstring = PyTuple_GetItem(item, 6);
600 if (!(px && py && pwidth && pheight && pfnt && pstring))
602 eDebug("eListboxPythonMultiContent received too small tuple (must be (x, y, width, height, fnt, flags, string[, ...])");
607 pstring = PyObject_Str(pstring);
609 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
611 int x = PyInt_AsLong(px);
612 int y = PyInt_AsLong(py);
613 int width = PyInt_AsLong(pwidth);
614 int height = PyInt_AsLong(pheight);
615 int flags = PyInt_AsLong(pflags);
617 int fnt = PyInt_AsLong(pfnt);
619 if (m_font.find(fnt) == m_font.end())
621 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
627 eRect r = eRect(x, y, width, height);
630 painter.setFont(m_font[fnt]);
632 painter.renderText(r, string, flags);
637 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
644 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)