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))
109 item = PyTuple_GET_ITEM(item, 0);
117 void eListboxPythonStringContent::cursorSave()
119 m_saved_cursor = m_cursor;
122 void eListboxPythonStringContent::cursorRestore()
124 m_cursor = m_saved_cursor;
127 int eListboxPythonStringContent::size()
131 return PyList_Size(m_list);
134 void eListboxPythonStringContent::setSize(const eSize &size)
139 void eListboxPythonStringContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
141 ePtr<gFont> fnt = new gFont("Regular", 20);
142 painter.clip(eRect(offset, m_itemsize));
143 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
146 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))
153 item = PyTuple_GET_ITEM(item, 0);
157 int half_height = m_itemsize.height() / 2;
159 painter.fill(eRect(offset.x() + half_height, offset.y() + half_height - 2, m_itemsize.width() - m_itemsize.height(), 4));
162 const char *string = PyString_Check(item) ? PyString_AsString(item) : "<not-a-string>";
163 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
164 painter.renderText(eRect(text_offset, m_itemsize), string);
168 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
174 void eListboxPythonStringContent::setList(PyObject *list)
177 if (!PyList_Check(list))
187 m_listbox->entryReset(false);
190 PyObject *eListboxPythonStringContent::getCurrentSelection()
192 if (!(m_list && cursorValid()))
197 PyObject *r = PyList_GET_ITEM(m_list, m_cursor);
202 void eListboxPythonStringContent::invalidateEntry(int index)
205 m_listbox->entryChanged(index);
208 void eListboxPythonStringContent::invalidate()
211 m_listbox->invalidate();
214 //////////////////////////////////////
216 void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
218 ePtr<gFont> fnt = new gFont("Regular", 20);
219 ePtr<gFont> fnt2 = new gFont("Regular", 16);
220 eRect itemrect(offset, m_itemsize);
221 painter.clip(itemrect);
222 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
225 if (m_list && cursorValid())
227 /* get current list item */
228 PyObject *item = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
229 PyObject *text = 0, *value = 0;
230 painter.setFont(fnt);
232 /* the first tuple element is a string for the left side.
233 the second one will be called, and the result shall be an tuple.
236 the first one is the type (string).
237 the second one is the value. */
238 if (PyTuple_Check(item))
240 /* handle left part. get item from tuple, convert to string, display. */
242 text = PyTuple_GET_ITEM(item, 0);
243 text = PyObject_Str(text); /* creates a new object - old object was borrowed! */
244 const char *string = (text && PyString_Check(text)) ? PyString_AsString(text) : "<not-a-string>";
245 eSize item_left = eSize(m_seperation, m_itemsize.height());
246 eSize item_right = eSize(m_itemsize.width() - m_seperation, m_itemsize.height());
247 painter.renderText(eRect(offset, item_left), string, gPainter::RT_HALIGN_LEFT);
250 /* when we have no label, align value to the left. (FIXME:
251 don't we want to specifiy this individually?) */
252 int value_alignment_left = !*string;
254 /* now, handle the value. get 2nd part from tuple*/
255 value = PyTuple_GET_ITEM(item, 1);
258 PyObject *args = PyTuple_New(1);
259 PyTuple_SET_ITEM(args, 0, PyInt_FromLong(selected));
261 /* CallObject will call __call__ which should return the value tuple */
262 value = PyObject_CallObject(value, args);
264 if (PyErr_Occurred())
268 /* the PyInt was stolen. */
271 /* check if this is really a tuple */
272 if (value && PyTuple_Check(value))
274 /* convert type to string */
275 PyObject *type = PyTuple_GET_ITEM(value, 0);
276 const char *atype = (type && PyString_Check(type)) ? PyString_AsString(type) : 0;
280 if (!strcmp(atype, "text"))
282 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
283 const char *value = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
284 painter.setFont(fnt2);
285 if (value_alignment_left)
286 painter.renderText(eRect(offset, item_right), value, gPainter::RT_HALIGN_LEFT);
288 painter.renderText(eRect(offset + eSize(m_seperation, 0), item_right), value, gPainter::RT_HALIGN_RIGHT);
290 /* pvalue is borrowed */
291 } else if (!strcmp(atype, "slider"))
293 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
294 PyObject *psize = PyTuple_GET_ITEM(value, 2);
296 /* convert value to Long. fallback to -1 on error. */
297 int value = (pvalue && PyInt_Check(pvalue)) ? PyInt_AsLong(pvalue) : -1;
298 int size = (pvalue && PyInt_Check(psize)) ? PyInt_AsLong(psize) : 100;
300 /* calc. slider length */
301 int width = item_right.width() * value / size;
302 int height = item_right.height();
306 //painter.fill(eRect(offset.x() + m_seperation, offset.y(), width, height));
307 //hack - make it customizable
308 painter.fill(eRect(offset.x() + m_seperation, offset.y() + 5, width, height-10));
310 /* pvalue is borrowed */
311 } else if (!strcmp(atype, "mtext"))
313 PyObject *pvalue = PyTuple_GET_ITEM(value, 1);
314 const char *text = (pvalue && PyString_Check(pvalue)) ? PyString_AsString(pvalue) : "<not-a-string>";
315 int xoffs = value_alignment_left ? 0 : m_seperation;
316 ePtr<eTextPara> para = new eTextPara(eRect(offset + eSize(xoffs, 0), item_right));
318 para->renderString(text, 0);
319 para->realign(value_alignment_left ? eTextPara::dirLeft : eTextPara::dirRight);
320 int glyphs = para->size();
324 if (PyTuple_Size(value) >= 3)
325 plist = PyTuple_GET_ITEM(value, 2);
329 if (plist && PyList_Check(plist))
330 entries = PyList_Size(plist);
332 for (int i = 0; i < entries; ++i)
334 PyObject *entry = PyList_GET_ITEM(plist, i);
335 int num = PyInt_Check(entry) ? PyInt_AsLong(entry) : -1;
337 if ((num < 0) || (num >= glyphs))
338 eWarning("glyph index %d in PythonConfigList out of bounds!", num);
341 para->setGlyphFlag(num, GS_INVERT);
343 bbox = para->getGlyphBBox(num);
344 bbox = eRect(bbox.left(), offset.y(), bbox.width(), m_itemsize.height());
347 /* entry is borrowed */
350 painter.renderPara(para, ePoint(0, 0));
351 /* pvalue is borrowed */
352 /* plist is 0 or borrowed */
355 /* type is borrowed */
357 eWarning("eListboxPythonConfigContent: second value of tuple is not a tuple.");
358 /* value is borrowed */
362 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
368 int eListboxPythonConfigContent::currentCursorSelectable()
370 return eListboxPythonStringContent::currentCursorSelectable();
373 //////////////////////////////////////
375 /* todo: make a real infrastructure here! */
376 RESULT SwigFromPython(ePtr<gPixmap> &res, PyObject *obj);
378 void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
380 eRect itemrect(offset, m_itemsize);
381 painter.clip(itemrect);
382 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
385 if (m_list && cursorValid())
387 PyObject *items = PyList_GET_ITEM(m_list, m_cursor); // borrowed reference!
391 eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor);
395 if (!PyList_Check(items))
397 eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor);
401 int size = PyList_Size(items);
402 for (int i = 1; i < size; ++i)
404 PyObject *item = PyList_GET_ITEM(items, i); // borrowed reference!
408 eDebug("eListboxPythonMultiContent: ?");
412 PyObject *px = 0, *py = 0, *pwidth = 0, *pheight = 0, *pfnt = 0, *pstring = 0, *pflags = 0;
415 we have a list of tuples:
417 (0, x, y, width, height, fnt, flags, "bla" ),
420 (1, x, y, width, height, filled_percent )
424 (2, x, y, width, height, pixmap )
428 if (!PyTuple_Check(item))
430 eDebug("eListboxPythonMultiContent did not receive a tuple.");
434 int size = PyTuple_Size(item);
438 eDebug("eListboxPythonMultiContent receive empty tuple.");
442 int type = PyInt_AsLong(PyTuple_GET_ITEM(item, 0));
446 px = PyTuple_GET_ITEM(item, 1);
447 py = PyTuple_GET_ITEM(item, 2);
448 pwidth = PyTuple_GET_ITEM(item, 3);
449 pheight = PyTuple_GET_ITEM(item, 4);
450 pfnt = PyTuple_GET_ITEM(item, 5); /* could also be an pixmap or an int (progress filled percent) */
453 pflags = PyTuple_GET_ITEM(item, 6);
454 pstring = PyTuple_GET_ITEM(item, 7);
460 case TYPE_TEXT: // text
462 if (!(px && py && pwidth && pheight && pfnt && pstring))
464 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string[, ...])");
468 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
469 int x = PyInt_AsLong(px);
470 int y = PyInt_AsLong(py);
471 int width = PyInt_AsLong(pwidth);
472 int height = PyInt_AsLong(pheight);
473 int flags = PyInt_AsLong(pflags);
474 int fnt = PyInt_AsLong(pfnt);
476 if (m_font.find(fnt) == m_font.end())
478 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
482 eRect r = eRect(x, y, width, height);
486 painter.setFont(m_font[fnt]);
489 painter.renderText(r, string, flags);
493 case TYPE_PROGRESS: // Progress
495 if (!(px && py && pwidth && pheight && pfnt))
497 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
500 int x = PyInt_AsLong(px);
501 int y = PyInt_AsLong(py);
502 int width = PyInt_AsLong(pwidth);
503 int height = PyInt_AsLong(pheight);
504 int filled = PyInt_AsLong(pfnt);
506 eRect r = eRect(x, y, width, height);
511 int bwidth=2; // borderwidth hardcoded yet
514 eRect rc = eRect(x, y, width, bwidth);
518 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
522 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
526 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
531 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
539 case TYPE_PIXMAP_ALPHATEST:
540 case TYPE_PIXMAP: // pixmap
542 if (!(px && py && pwidth && pheight && pfnt))
544 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
547 int x = PyInt_AsLong(px);
548 int y = PyInt_AsLong(py);
549 int width = PyInt_AsLong(pwidth);
550 int height = PyInt_AsLong(pheight);
551 ePtr<gPixmap> pixmap;
552 if (SwigFromPython(pixmap, pfnt))
554 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
558 eRect r = eRect(x, y, width, height);
563 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
569 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
576 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
582 int eListboxPythonMultiContent::currentCursorSelectable()
584 return eListboxPythonStringContent::currentCursorSelectable();
587 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)