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 int iListboxContent::currentCursorSelectable()
47 //////////////////////////////////////
49 DEFINE_REF(eListboxPythonStringContent);
51 eListboxPythonStringContent::eListboxPythonStringContent()
56 eListboxPythonStringContent::~eListboxPythonStringContent()
61 void eListboxPythonStringContent::cursorHome()
66 void eListboxPythonStringContent::cursorEnd()
71 int eListboxPythonStringContent::cursorMove(int count)
77 else if (m_cursor > size())
82 int eListboxPythonStringContent::cursorValid()
84 return m_cursor < size();
87 int eListboxPythonStringContent::cursorSet(int n)
93 else if (m_cursor > size())
98 int eListboxPythonStringContent::cursorGet()
103 int eListboxPythonStringContent::currentCursorSelectable()
105 if (m_list && cursorValid())
107 PyObject *item = PyList_GET_ITEM(m_list, m_cursor);
108 if (!PyTuple_Check(item))
110 if (PyTuple_Size(item) >= 2)
116 void eListboxPythonStringContent::cursorSave()
118 m_saved_cursor = m_cursor;
121 void eListboxPythonStringContent::cursorRestore()
123 m_cursor = m_saved_cursor;
126 int eListboxPythonStringContent::size()
130 return PyList_Size(m_list);
133 void eListboxPythonStringContent::setSize(const eSize &size)
138 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
140 ePtr<gFont> fnt = new gFont("Regular", 20);
141 painter.clip(eRect(offset, m_itemsize));
142 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
145 if (m_list && cursorValid())
148 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
149 painter.setFont(fnt);
151 /* the user can supply tuples, in this case the first one will be displayed. */
152 if (PyTuple_Check(item))
154 if (PyTuple_Size(item) == 1)
156 item = PyTuple_GET_ITEM(item, 0);
161 int half_height = m_itemsize.height() / 2;
163 painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
166 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
167 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
169 painter.setForegroundColor(gRGB(0x808080));
170 painter.renderText(eRect(text_offset, m_itemsize), string);
174 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
180 void eListboxPythonStringContent::setList(PyObject *list)
183 if (!PyList_Check(list))
193 m_listbox->entryReset(false);
196 PyObject *eListboxPythonStringContent::getCurrentSelection()
198 if (!(m_list && cursorValid()))
203 PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
208 void eListboxPythonStringContent::invalidateEntry(int index)
211 m_listbox->entryChanged(index);
214 void eListboxPythonStringContent::invalidate()
217 m_listbox->invalidate();
220 //////////////////////////////////////
222 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
224 ePtr<gFont> fnt = new gFont("Regular", 20);
225 ePtr<gFont> fnt2 = new gFont("Regular", 16);
226 eRect itemrect(offset, m_itemsize);
227 painter.clip(itemrect);
228 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
231 if (m_list && cursorValid())
233 /* get current list item */
234 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
235 PyObject *text = 0, *value = 0;
236 painter.setFont(fnt);
238 /* the first tuple element is a string for the left side.
239 the second one will be called, and the result shall be an tuple.
242 the first one is the type (string).
243 the second one is the value. */
244 if (PyTuple_Check(item))
246 /* handle left part. get item from tuple, convert to string, display. */
248 text = PyTuple_GET_ITEM(item, 0);
249 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
250 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
251 eSize item_left = eSize(m_seperation, m_itemsize.height());
252 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
253 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
256 /* when we have no label, align value to the left. (FIXME:
257 don't we want to specifiy this individually?) */
258 int value_alignment_left = !*string;
260 /* now, handle the value. get 2nd part from tuple*/
261 value = PyTuple_GET_ITEM(item, 1);
264 PyObject *args = PyTuple_New(1);
265 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
267 /* CallObject will call __call__ which should return the value tuple */
268 value = PyObject_CallObject(value, args);
270 if (PyErr_Occurred())
274 /* the PyInt was stolen. */
277 /* check if this is really a tuple */
278 if (value && PyTuple_Check(value))
280 /* convert type to string */
281 PyObject *type = PyTuple_GET_ITEM(value, 0);
282 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
286 if (!strcmp(atype, "text"))
288 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
289 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
290 painter.setFont(fnt2);
291 if (value_alignment_left)
292 painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
294 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
296 /* pvalue is borrowed */
297 } else if (!strcmp(atype, "slider"))
299 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
300 PyObject *psize = PyTuple_GET_ITEM(value, 2);
302 /* convert value to Long. fallback to -1 on error. */
303 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
304 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
306 /* calc. slider length */
307 int width = item_right.width() * value / size;
308 int height = item_right.height();
312 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
313 //hack - make it customizable
314 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
316 /* pvalue is borrowed */
317 } else if (!strcmp(atype, "mtext"))
319 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
320 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
321 int xoffs = value_alignment_left ? 0 : m_seperation;
322 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
324 para->renderString(text, 0);
325 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
326 int glyphs = para->size();
330 if (PyTuple_Size(value) >= 3)
331 plist = PyTuple_GET_ITEM(value, 2);
335 if (plist && PyList_Check(plist))
336 entries = PyList_Size(plist);
338 for (int i = 0; i < entries; ++i)
340 PyObject *entry = PyList_GET_ITEM(plist, i);
341 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
343 if ((num < 0) || (num >= glyphs))
344 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
347 para->setGlyphFlag(num, GS_INVERT);
349 bbox = para->getGlyphBBox(num);
350 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
353 /* entry is borrowed */
356 painter.renderPara(para, ePoint(0, 0));
357 /* pvalue is borrowed */
358 /* plist is 0 or borrowed */
361 /* type is borrowed */
363 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
364 /* value is borrowed */
368 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
374 int eListboxPythonConfigContent::currentCursorSelectable()
376 return eListboxPythonStringContent::currentCursorSelectable();
379 //////////////////////////////////////
381 /* todo: make a real infrastructure here! */
382 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
384 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
386 eRect itemrect(offset, m_itemsize);
387 painter.clip(itemrect);
388 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
391 if (m_list && cursorValid())
393 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
397 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
401 if (!PyList_Check(items))
403 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
407 int size = PyList_Size(items);
408 for (int i = 1; i < size; ++i)
410 PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
414 eDebug("eListboxPythonMultiContent: ?");
418 PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0, *pcolor = 0;
421 we have a list of tuples:
423 (0, x, y, width, height, fnt, flags, "bla"[, color] ),
426 (1, x, y, width, height, filled_percent )
430 (2, x, y, width, height, pixmap )
434 if (!PyTuple_Check(item))
436 eDebug("eListboxPythonMultiContent did not receive a tuple.");
440 int size = PyTuple_Size(item);
444 eDebug("eListboxPythonMultiContent receive empty tuple.");
448 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
452 px = PyTuple_GET_ITEM(item, 1);
453 py = PyTuple_GET_ITEM(item, 2);
454 pwidth = PyTuple_GET_ITEM(item, 3);
455 pheight = PyTuple_GET_ITEM(item, 4);
456 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
459 pflags = PyTuple_GET_ITEM(item, 6);
460 pstring = PyTuple_GET_ITEM(item, 7);
463 pcolor = PyTuple_GET_ITEM(item, 8);
468 case TYPE_TEXT: // text
470 if (!(px && py && pwidth && pheight && pfnt && pstring))
472 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string, [color, ]...])");
476 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
477 int x = PyInt_AsLong(px);
478 int y = PyInt_AsLong(py);
479 int width = PyInt_AsLong(pwidth);
480 int height = PyInt_AsLong(pheight);
481 int flags = PyInt_AsLong(pflags);
482 int fnt = PyInt_AsLong(pfnt);
486 int color = PyInt_AsLong(pcolor);
487 painter.setForegroundColor(gRGB(color));
490 if (m_font.find(fnt) == m_font.end())
492 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
496 eRect r = eRect(x, y, width, height);
500 painter.setFont(m_font[fnt]);
503 painter.renderText(r, string, flags);
507 case TYPE_PROGRESS: // Progress
509 if (!(px && py && pwidth && pheight && pfnt))
511 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
514 int x = PyInt_AsLong(px);
515 int y = PyInt_AsLong(py);
516 int width = PyInt_AsLong(pwidth);
517 int height = PyInt_AsLong(pheight);
518 int filled = PyInt_AsLong(pfnt);
520 eRect r = eRect(x, y, width, height);
525 int bwidth=2; // borderwidth hardcoded yet
528 eRect rc = eRect(x, y, width, bwidth);
532 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
536 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
540 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
545 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
553 case TYPE_PIXMAP_ALPHATEST:
554 case TYPE_PIXMAP: // pixmap
556 if (!(px && py && pwidth && pheight && pfnt))
558 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
561 int x = PyInt_AsLong(px);
562 int y = PyInt_AsLong(py);
563 int width = PyInt_AsLong(pwidth);
564 int height = PyInt_AsLong(pheight);
565 ePtr<gPixmap> pixmap;
566 if (SwigFromPython(pixmap, pfnt))
568 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
572 eRect r = eRect(x, y, width, height);
577 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
583 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
588 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
593 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
599 int eListboxPythonMultiContent::currentCursorSelectable()
601 if (m_list && cursorValid())
603 PyObject *item = PyList_GET_ITEM(m_list, m_cursor);
605 if (PyList_Check(item))
607 item = PyList_GET_ITEM(item, 0);
608 if (PyTuple_Check(item))
610 item = PyTuple_GET_ITEM(item, 0);
619 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)