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, *pcolor = 0;
415 we have a list of tuples:
417 (0, x, y, width, height, fnt, flags, "bla"[, color] ),
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);
457 pcolor = PyTuple_GET_ITEM(item, 8);
462 case TYPE_TEXT: // text
464 if (!(px && py && pwidth && pheight && pfnt && pstring))
466 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_TEXT, x, y, width, height, fnt, flags, string, [color, ]...])");
470 const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : "<not-a-string>";
471 int x = PyInt_AsLong(px);
472 int y = PyInt_AsLong(py);
473 int width = PyInt_AsLong(pwidth);
474 int height = PyInt_AsLong(pheight);
475 int flags = PyInt_AsLong(pflags);
476 int fnt = PyInt_AsLong(pfnt);
480 int color = PyInt_AsLong(pcolor);
481 painter.setForegroundColor(gRGB(color));
484 if (m_font.find(fnt) == m_font.end())
486 eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt);
490 eRect r = eRect(x, y, width, height);
494 painter.setFont(m_font[fnt]);
497 painter.renderText(r, string, flags);
501 case TYPE_PROGRESS: // Progress
503 if (!(px && py && pwidth && pheight && pfnt))
505 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PROGRESS, x, y, width, height, filled percent))");
508 int x = PyInt_AsLong(px);
509 int y = PyInt_AsLong(py);
510 int width = PyInt_AsLong(pwidth);
511 int height = PyInt_AsLong(pheight);
512 int filled = PyInt_AsLong(pfnt);
514 eRect r = eRect(x, y, width, height);
519 int bwidth=2; // borderwidth hardcoded yet
522 eRect rc = eRect(x, y, width, bwidth);
526 rc = eRect(x, y+bwidth, bwidth, height-bwidth);
530 rc = eRect(x+bwidth, y+height-bwidth, width-bwidth, bwidth);
534 rc = eRect(x+width-bwidth, y+bwidth, bwidth, height-bwidth);
539 rc = eRect(x+bwidth, y+bwidth, (width-bwidth*2) * filled / 100, height-bwidth*2);
547 case TYPE_PIXMAP_ALPHATEST:
548 case TYPE_PIXMAP: // pixmap
550 if (!(px && py && pwidth && pheight && pfnt))
552 eDebug("eListboxPythonMultiContent received too small tuple (must be (TYPE_PIXMAP, x, y, width, height, pixmap))");
555 int x = PyInt_AsLong(px);
556 int y = PyInt_AsLong(py);
557 int width = PyInt_AsLong(pwidth);
558 int height = PyInt_AsLong(pheight);
559 ePtr<gPixmap> pixmap;
560 if (SwigFromPython(pixmap, pfnt))
562 eDebug("eListboxPythonMultiContent (Pixmap) get pixmap failed");
566 eRect r = eRect(x, y, width, height);
571 painter.blit(pixmap, r.topLeft(), r, (type == TYPE_PIXMAP_ALPHATEST) ? gPainter::BT_ALPHATEST : 0);
577 eWarning("eListboxPythonMultiContent received unknown type (%d)", type);
582 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
587 style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
593 int eListboxPythonMultiContent::currentCursorSelectable()
595 if (m_list && cursorValid())
597 PyObject *item = PyList_GET_ITEM(m_list, m_cursor);
599 if (PyList_Check(item))
601 item = PyList_GET_ITEM(item, 0);
602 if (PyTuple_Check(item))
604 item = PyTuple_GET_ITEM(item, 0);
613 void eListboxPythonMultiContent::setFont(int fnt, gFont *font)