1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <lib/gui/eslider.h>
4 #include <lib/actions/action.h>
6 eListbox::eListbox(eWidget *parent)
7 :eWidget(parent), m_scrollbar_mode(showNever), m_prev_scrollbar_page(-1)
8 ,m_content_changed(false), m_top(0), m_selected(0), m_itemheight(25)
9 ,m_items_per_page(0), m_selection_enabled(1), m_scrollbar(NULL)
11 // setContent(new eListboxStringContent());
14 eActionMap::getInstance(ptr);
15 ptr->bindAction("ListboxActions", 0, 0, this);
24 eActionMap::getInstance(ptr);
25 ptr->unbindAction(this, 0);
28 void eListbox::setScrollbarMode(int mode)
30 m_scrollbar_mode = mode;
33 if ( m_scrollbar_mode == showNever )
41 m_scrollbar = new eSlider(this);
43 m_scrollbar->setBorderWidth(1);
44 m_scrollbar->setOrientation(eSlider::orVertical);
45 m_scrollbar->setRange(0,100);
49 void eListbox::setContent(iListboxContent *content)
51 int oldsel = m_selected;
54 m_content->setListbox(this);
56 if (oldsel == m_selected)
57 /* emit */ selectionChanged();
60 void eListbox::moveSelection(int dir)
62 /* refuse to do anything without a valid list. */
65 /* if our list does not have one entry, don't do anything. */
66 if (!m_items_per_page)
68 /* we need the old top/sel to see what we have to redraw */
70 int oldsel = m_selected;
71 /* first, move cursor */
75 m_content->cursorMove(-1);
78 m_content->cursorMove(1);
79 /* ok - we could have reached the end. we just go one back then. */
80 if (!m_content->cursorValid())
81 m_content->cursorMove(-1);
84 if (m_content->cursorGet() >= m_items_per_page)
86 m_content->cursorMove(-m_items_per_page);
87 m_top -= m_items_per_page;
93 m_content->cursorHome();
97 m_content->cursorHome();
98 m_top = 0; /* align with top, speeds up process */
102 m_content->cursorMove(m_items_per_page);
103 if (m_content->cursorValid())
107 /* move to last existing one ("end" is already invalid) */
108 m_content->cursorEnd(); m_content->cursorMove(-1);
109 /* current selection invisible? */
110 if (m_top + m_items_per_page <= m_content->cursorGet())
112 int rest = m_content->size() % m_items_per_page;
114 m_top = m_content->cursorGet() - rest + 1;
116 m_top = m_content->cursorGet() - m_items_per_page + 1;
125 /* note that we could be on an invalid cursor position, but we don't
126 care. this only happens on empty lists, and should have almost no
129 /* now, look wether the current selection is out of screen */
130 m_selected = m_content->cursorGet();
131 while (m_selected < m_top)
133 m_top -= m_items_per_page;
137 while (m_selected >= m_top + m_items_per_page)
138 /* m_top should be always valid here as it's selected */
139 m_top += m_items_per_page;
141 if (oldsel != m_selected)
142 /* emit */ selectionChanged();
148 else if (m_selected != oldsel)
150 /* redraw the old and newly selected */
151 gRegion inv = eRect(0, m_itemheight * (m_selected-m_top), size().width(), m_itemheight);
152 inv |= eRect(0, m_itemheight * (oldsel-m_top), size().width(), m_itemheight);
158 void eListbox::moveSelectionTo(int index)
162 m_content->cursorHome();
163 m_content->cursorMove(index);
164 moveSelection(justCheck);
168 int eListbox::getCurrentIndex()
170 if ( m_content && m_content->cursorValid() )
171 return m_content->cursorGet();
175 void eListbox::updateScrollBar()
177 if (!m_content || m_scrollbar_mode == showNever )
179 int entries = m_content->size();
180 if ( m_content_changed )
182 int width = size().width();
183 int height = size().height();
184 m_content_changed = false;
185 if ( entries > m_items_per_page || m_scrollbar_mode == showAlways )
187 int sbarwidth=width/16;
188 if ( sbarwidth < 18 )
190 if ( sbarwidth > 22 )
192 m_scrollbar->move(ePoint(width-sbarwidth, 0));
193 m_scrollbar->resize(eSize(sbarwidth, height));
194 m_content->setSize(eSize(width-sbarwidth-5, m_itemheight));
199 m_content->setSize(eSize(width, m_itemheight));
203 if ( m_items_per_page && entries )
205 int curVisiblePage = m_top / m_items_per_page;
206 if (m_prev_scrollbar_page != curVisiblePage)
208 m_prev_scrollbar_page = curVisiblePage;
209 int pages = entries / m_items_per_page;
210 if ( (pages*m_items_per_page) < entries )
212 int start=(m_top*100)/(pages*m_items_per_page);
213 int vis=(m_items_per_page*100)/(pages*m_items_per_page);
216 m_scrollbar->setStartEnd(start,start+vis);
221 int eListbox::event(int event, void *data, void *data2)
227 ePtr<eWindowStyle> style;
230 return eWidget::event(event, data, data2);
238 gPainter &painter = *(gPainter*)data2;
240 m_content->cursorSave();
241 m_content->cursorMove(m_top - m_selected);
243 for (int y = 0, i = 0; i <= m_items_per_page; y += m_itemheight, ++i)
245 m_content->paint(painter, *style, ePoint(0, y), m_selected == m_content->cursorGet() && m_content->size() && m_selection_enabled);
246 m_content->cursorMove(+1);
249 if ( m_scrollbar && m_scrollbar->isVisible() )
251 painter.clip(eRect(m_scrollbar->position() - ePoint(5,0), eSize(5,m_scrollbar->size().height())));
256 m_content->cursorRestore();
262 return eWidget::event(event, data, data2);
267 moveSelection((int)data2);
272 return eWidget::event(event, data, data2);
276 void eListbox::recalcSize()
278 m_content_changed=true;
279 m_prev_scrollbar_page=-1;
280 m_content->setSize(eSize(size().width(), m_itemheight));
281 m_items_per_page = size().height() / m_itemheight;
283 if (m_items_per_page < 0) /* TODO: whyever - our size could be invalid, or itemheigh could be wrongly specified. */
284 m_items_per_page = 0;
286 moveSelection(justCheck);
289 void eListbox::setItemHeight(int h)
298 void eListbox::setSelectionEnable(int en)
300 if (m_selection_enabled == en)
302 m_selection_enabled = en;
303 entryChanged(m_selected); /* redraw current entry */
306 void eListbox::entryAdded(int index)
308 /* manage our local pointers. when the entry was added before the current position, we have to advance. */
310 /* we need to check <= - when the new entry has the (old) index of the cursor, the cursor was just moved down. */
311 if (index <= m_selected)
316 /* we have to check wether our current cursor is gone out of the screen. */
317 /* moveSelection will check for this case */
318 moveSelection(justCheck);
320 /* now, check if the new index is visible. */
321 if ((m_top <= index) && (index < (m_top + m_items_per_page)))
323 /* todo, calc exact invalidation... */
328 void eListbox::entryRemoved(int index)
330 if (index == m_selected)
331 m_selected = m_content->cursorGet();
333 moveSelection(justCheck);
335 if ((m_top <= index) && (index < (m_top + m_items_per_page)))
337 /* todo, calc exact invalidation... */
342 void eListbox::entryChanged(int index)
344 if ((m_top <= index) && (index < (m_top + m_items_per_page)))
346 gRegion inv = eRect(0, m_itemheight * (index-m_top), size().width(), m_itemheight);
351 void eListbox::entryReset(bool cursorHome)
353 m_content_changed=true;
354 m_prev_scrollbar_page=-1;
358 m_content->cursorHome();
362 moveSelection(justCheck);