1 #include <lib/gui/elistbox.h>
4 The basic idea is to have an interface which gives all relevant list
5 processing functions, and can be used by the listbox to browse trough
8 The listbox directly uses the implemented cursor. It tries hard to avoid
9 iterating trough the (possibly very large) list, so it should be O(1),
10 i.e. the performance should not be influenced by the size of the list.
12 The list interface knows how to draw the current entry to a specified
13 offset. Different interfaces can be used to adapt different lists,
14 pre-filter lists on the fly etc.
16 cursorSave/Restore is used to avoid re-iterating the list on redraw.
17 The current selection is always selected as cursor position, the
18 cursor is then positioned to the start, and then iterated. This gives
19 at most 2x m_items_per_page cursor movements per redraw, indepenent
20 of the size of the list.
22 Although cursorSet is provided, it should be only used when there is no
23 other way, as it involves iterating trough the list.
26 class eListboxTestContent: public virtual iListboxContent
32 int cursorMove(int count=1);
41 RESULT connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection);
43 // void setOutputDevice ? (for allocating colors, ...) .. requires some work, though
44 void setSize(const eSize &size);
46 /* the following functions always refer to the selected item */
47 void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected);
49 int m_cursor, m_saved_cursor;
53 DEFINE_REF(eListboxTestContent);
55 void eListboxTestContent::cursorHome()
60 void eListboxTestContent::cursorEnd()
65 int eListboxTestContent::cursorMove(int count)
71 else if (m_cursor > size())
76 int eListboxTestContent::cursorValid()
78 return m_cursor < size();
81 int eListboxTestContent::cursorSet(int n)
87 else if (m_cursor > size())
92 int eListboxTestContent::cursorGet()
97 void eListboxTestContent::cursorSave()
99 m_saved_cursor = m_cursor;
102 void eListboxTestContent::cursorRestore()
104 m_cursor = m_saved_cursor;
107 int eListboxTestContent::size()
112 RESULT eListboxTestContent::connectItemChanged(const Slot0<void> &itemChanged, ePtr<eConnection> &connection)
117 void eListboxTestContent::setSize(const eSize &size)
122 void eListboxTestContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
124 ePtr<gFont> fnt = new gFont("Arial", 14);
125 painter.clip(eRect(offset, m_size));
126 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
131 painter.setFont(fnt);
133 sprintf(string, "%d.)", m_cursor);
135 ePoint text_offset = offset + (selected ? ePoint(2, 2) : ePoint(1, 1));
137 painter.renderText(eRect(text_offset, m_size), string);
140 style.drawFrame(painter, eRect(offset, m_size), eWindowStyle::frameListboxEntry);
146 eListbox::eListbox(eWidget *parent): eWidget(parent)
148 setContent(new eListboxTestContent());
149 m_content->cursorHome();
154 void eListbox::setContent(iListboxContent *content)
159 void eListbox::moveSelection(int dir)
161 /* we need the old top/sel to see what we have to redraw */
163 int oldsel = m_selected;
165 /* first, move cursor */
169 m_content->cursorMove(-1);
172 m_content->cursorMove(1);
173 /* ok - we could have reached the end. we just go one back then. */
174 if (!m_content->cursorValid())
175 m_content->cursorMove(-1);
178 m_content->cursorHome();
179 m_top = 0; /* align with top, speeds up process */
182 /* move to last existing one ("end" is already invalid) */
183 m_content->cursorEnd(); m_content->cursorMove(-1);
185 m_top = m_content->cursorGet() - m_items_per_page + 1;
191 /* note that we could be on an invalid cursor position, but we don't
192 care. this only happens on empty lists, and should have almost no
195 /* now, look wether the current selection is out of screen */
196 m_selected = m_content->cursorGet();
197 if (m_selected < m_top)
199 m_top -= m_items_per_page;
202 } else if (m_selected >= m_top + m_items_per_page)
204 /* m_top should be always valid here as it's selected */
205 m_top += m_items_per_page;
212 /* redraw the old and newly selected */
213 gRegion inv = eRect(0, m_itemheight * (m_selected-m_top), size().width(), m_itemheight);
214 inv |= eRect(0, m_itemheight * (oldsel-m_top), size().width(), m_itemheight);
220 int eListbox::event(int event, void *data, void *data2)
226 ePtr<eWindowStyle> style;
229 recalcSize(); // move to event
236 gPainter &painter = *(gPainter*)data2;
238 m_content->cursorSave();
239 m_content->cursorMove(m_top - m_selected);
241 for (int y = 0, i = 0; i < m_items_per_page; y += m_itemheight, ++i)
243 m_content->paint(painter, *style, ePoint(0, y), m_selected == m_content->cursorGet());
244 m_content->cursorMove(+1);
247 m_content->cursorRestore();
252 return eWidget::event(event, data, data2);
256 void eListbox::recalcSize()
259 m_content->setSize(eSize(size().width(), m_itemheight));
260 m_items_per_page = size().height() / m_itemheight;