c3dd659bb40f5fb560d68b004972ac952b8009a6
[openblackhole/openblackhole-enigma2.git] / lib / gui / elistbox.cpp
1 #include <lib/gui/elistbox.h>
2 #include <lib/gui/elistboxcontent.h>
3 #include <lib/actions/action.h>
4
5 eListbox::eListbox(eWidget *parent): eWidget(parent)
6 {
7         setContent(new eListboxStringContent());
8
9         ePtr<eActionMap> ptr;
10         eActionMap::getInstance(ptr);
11         
12         m_itemheight = 25;
13         
14         ptr->bindAction("ListboxActions", 0, 0, this);
15 }
16
17 eListbox::~eListbox()
18 {
19         ePtr<eActionMap> ptr;
20         eActionMap::getInstance(ptr);
21         ptr->unbindAction(this, 0);
22 }
23
24 void eListbox::setContent(iListboxContent *content)
25 {
26         m_content = content;
27         if (content)
28                 m_content->setListbox(this);
29         entryReset();
30 }
31
32 void eListbox::moveSelection(int dir)
33 {
34                 /* refuse to do anything without a valid list. */
35         if (!m_content)
36                 return;
37                 
38                 /* we need the old top/sel to see what we have to redraw */
39         int oldtop = m_top;
40         int oldsel = m_selected;
41         
42                 /* first, move cursor */
43         switch (dir)
44         {
45         case moveUp:
46                 m_content->cursorMove(-1);
47                 break;
48         case moveDown:
49                 m_content->cursorMove(1);
50                         /* ok - we could have reached the end. we just go one back then. */
51                 if (!m_content->cursorValid())
52                         m_content->cursorMove(-1);
53                 break;
54         case pageUp:
55                 if (m_content->cursorGet() >= m_items_per_page)
56                 {
57                         m_content->cursorMove(-m_items_per_page);
58                         m_top -= m_items_per_page;
59                         if (m_top < 0)
60                                 m_top = 0;
61                 } else
62                 {
63                         m_top = 0;
64                         m_content->cursorHome();
65                 }
66                 break;
67         case moveTop:
68                 m_content->cursorHome();
69                 m_top = 0; /* align with top, speeds up process */
70                 break;
71
72         case pageDown:
73                 m_content->cursorMove(m_items_per_page);
74                 if (m_content->cursorValid())
75                         break;
76                                 /* fall through */
77         case moveEnd:
78                         /* move to last existing one ("end" is already invalid) */
79                 m_content->cursorEnd(); m_content->cursorMove(-1); 
80                         /* current selection invisible? */
81                 if (m_top + m_items_per_page <= m_content->cursorGet())
82                 {
83                         m_top = m_content->cursorGet() - m_items_per_page + 1;
84                         if (m_top < 0)
85                                 m_top = 0;
86                 }
87                 break;
88         case justCheck:
89                 break;
90         }
91         
92                 /* note that we could be on an invalid cursor position, but we don't
93                    care. this only happens on empty lists, and should have almost no
94                    side effects. */
95         
96                 /* now, look wether the current selection is out of screen */
97         m_selected = m_content->cursorGet();
98         
99         if (m_selected < m_top)
100         {
101                 m_top -= m_items_per_page;
102                 if (m_top < 0)
103                         m_top = 0;
104         } else if (m_selected >= m_top + m_items_per_page)
105         {
106                         /* m_top should be always valid here as it's selected */
107                 m_top += m_items_per_page;
108         }
109
110         if (m_top != oldtop)
111                 invalidate();
112         else if (m_selected != oldsel)
113         {
114                 
115                         /* redraw the old and newly selected */
116                 gRegion inv = eRect(0, m_itemheight * (m_selected-m_top), size().width(), m_itemheight);
117                 inv |= eRect(0, m_itemheight * (oldsel-m_top), size().width(), m_itemheight);
118                 
119                 invalidate(inv);
120         }
121 }
122
123 int eListbox::event(int event, void *data, void *data2)
124 {
125         switch (event)
126         {
127         case evtPaint:
128         {
129                 ePtr<eWindowStyle> style;
130                 
131                 if (!m_content)
132                         return eWidget::event(event, data, data2);
133                 assert(m_content);
134                 
135                 getStyle(style);
136                 
137                 if (!m_content)
138                         return 0;
139                 
140                 gPainter &painter = *(gPainter*)data2;
141                 
142                 m_content->cursorSave();
143                 m_content->cursorMove(m_top - m_selected);
144                 
145                 for (int y = 0, i = 0; i <= m_items_per_page; y += m_itemheight, ++i)
146                 {
147                         m_content->paint(painter, *style, ePoint(0, y), m_selected == m_content->cursorGet() && m_content->size());
148                         m_content->cursorMove(+1);
149                 }
150                 
151                 m_content->cursorRestore();
152                 
153                 return 0;
154         }
155         case evtChangedSize:
156                 recalcSize();
157                 return eWidget::event(event, data, data2);
158                 
159         case evtAction:
160                 if (isVisible())
161                 {
162                         moveSelection((int)data2);
163                         return 1;
164                 }
165                 return 0;
166         default:
167                 return eWidget::event(event, data, data2);
168         }
169 }
170
171 void eListbox::recalcSize()
172 {
173         m_content->setSize(eSize(size().width(), m_itemheight));
174         m_items_per_page = size().height() / m_itemheight;
175 }
176
177 void eListbox::setItemHeight(int h)
178 {
179         if (h)
180                 m_itemheight = h;
181         else
182                 m_itemheight = 20;
183         recalcSize();
184 }
185
186 void eListbox::entryAdded(int index)
187 {
188                 /* manage our local pointers. when the entry was added before the current position, we have to advance. */
189                 
190                 /* we need to check <= - when the new entry has the (old) index of the cursor, the cursor was just moved down. */
191         if (index <= m_selected)
192                 ++m_selected;
193         if (index <= m_top)
194                 ++m_top;
195                 
196                 /* we have to check wether our current cursor is gone out of the screen. */
197                 /* moveSelection will check for this case */
198         moveSelection(justCheck);
199         
200                 /* now, check if the new index is visible. */
201         if ((m_top <= index) && (index < (m_top + m_items_per_page)))
202         {
203                         /* todo, calc exact invalidation... */
204                 invalidate();
205         }
206 }
207
208 void eListbox::entryRemoved(int index)
209 {
210         if (index == m_selected)
211                 m_selected = m_content->cursorGet();
212
213         moveSelection(justCheck);
214         
215         if ((m_top <= index) && (index < (m_top + m_items_per_page)))
216         {
217                         /* todo, calc exact invalidation... */
218                 invalidate();
219         }
220 }
221
222 void eListbox::entryChanged(int index)
223 {
224         if ((m_top <= index) && (index < (m_top + m_items_per_page)))
225         {
226                 gRegion inv = eRect(0, m_itemheight * (index-m_top), size().width(), m_itemheight);
227                 invalidate(inv);
228         }
229 }
230
231 void eListbox::entryReset()
232 {
233         if (m_content)
234                 m_content->cursorHome();
235         m_top = 0;
236         m_selected = 0;
237         invalidate();
238 }