fix handylike jumping in servicelist
[enigma2.git] / lib / service / listboxservice.cpp
1 #include <lib/service/listboxservice.h>
2 #include <lib/service/service.h>
3 #include <lib/gdi/font.h>
4 #include <lib/dvb/epgcache.h>
5
6 void eListboxServiceContent::setRoot(const eServiceReference &root)
7 {
8         m_list.clear();
9         m_root = root;
10         
11         assert(m_service_center);
12         
13         ePtr<iListableService> lst;
14         if (m_service_center->list(m_root, lst))
15                 eDebug("no list available!");
16         else
17                 if (lst->getContent(m_list))
18                         eDebug("getContent failed");
19
20         m_size = m_list.size();
21         cursorHome();
22         
23         if (m_listbox)
24                 m_listbox->entryReset();
25 }
26
27 void eListboxServiceContent::setCurrent(const eServiceReference &ref)
28 {
29         int index=0;
30         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
31                 if ( *i == ref )
32                 {
33                         m_cursor = i;
34                         m_cursor_number = index;
35                         break;
36                 }
37 }
38
39 void eListboxServiceContent::getCurrent(eServiceReference &ref)
40 {
41         if (cursorValid())
42                 ref = *m_cursor;
43         else
44                 ref = eServiceReference();
45 }
46
47 int eListboxServiceContent::getNextBeginningWithChar(char c)
48 {
49 //      printf("Char: %c\n", c);
50         int index=0;
51         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
52         {
53                 std::string text;
54                 ePtr<iStaticServiceInformation> service_info;
55                 m_service_center->info(*i, service_info);
56                 service_info->getName(*i, text);
57 //              printf("%c\n", text.c_str()[0]);
58                 int idx=0;
59                 int len=text.length();
60                 while ( idx <= len )
61                 {
62                         char cc = text[idx++];
63                         if ( cc >= 33 && cc < 127)
64                         {
65                                 if (cc == c)
66                                         return index;
67                                 break;
68                         }
69                 }
70         }
71         return 0;
72 }
73
74 void eListboxServiceContent::initMarked()
75 {
76         m_marked.clear();
77 }
78
79 void eListboxServiceContent::addMarked(const eServiceReference &ref)
80 {
81         m_marked.insert(ref);
82         if (m_listbox)
83                 m_listbox->entryChanged(lookupService(ref));
84 }
85
86 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
87 {
88         m_marked.erase(ref);
89         if (m_listbox)
90                 m_listbox->entryChanged(lookupService(ref));
91 }
92
93 int eListboxServiceContent::isMarked(const eServiceReference &ref)
94 {
95         return m_marked.find(ref) != m_marked.end();
96 }
97
98 void eListboxServiceContent::markedQueryStart()
99 {
100         m_marked_iterator = m_marked.begin();
101 }
102
103 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
104 {
105         if (m_marked_iterator == m_marked.end())
106                 return -1;
107         ref = *m_marked_iterator++;
108         return 0;
109 }
110
111 int eListboxServiceContent::lookupService(const eServiceReference &ref)
112 {
113                 /* shortcut for cursor */
114         if (ref == *m_cursor)
115                 return m_cursor_number;
116                 /* otherwise, search in the list.. */
117         int index = 0;
118         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
119         
120                 /* this is ok even when the index was not found. */
121         return index;
122 }
123
124 void eListboxServiceContent::setVisualMode(int mode)
125 {
126         m_visual_mode = mode;
127         
128         if (m_visual_mode == visModeSimple)
129         {
130                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
131                 m_element_font[celServiceName] = new gFont("Arial", 23);
132                 m_element_position[celServiceNumber] = eRect();
133                 m_element_font[celServiceNumber] = 0;
134                 m_element_position[celIcon] = eRect();
135                 m_element_position[celServiceInfo] = eRect();
136                 m_element_font[celServiceInfo] = 0;
137         }
138 }
139
140 void eListboxServiceContent::setElementPosition(int element, eRect where)
141 {
142         if ((element >= 0) && (element < celElements))
143                 m_element_position[element] = where;
144 }
145
146 void eListboxServiceContent::setElementFont(int element, gFont *font)
147 {
148         if ((element >= 0) && (element < celElements))
149                 m_element_font[element] = font;
150 }
151
152 void eListboxServiceContent::sort()
153 {
154         ePtr<iListableService> lst;
155   if (!m_service_center->list(m_root, lst))
156   {
157                 m_list.sort(iListableServiceCompare(lst));
158                         /* FIXME: is this really required or can we somehow keep the current entry? */
159                 cursorHome();
160                 if (m_listbox)
161                         m_listbox->entryReset();
162         }
163 }
164
165 DEFINE_REF(eListboxServiceContent);
166
167 eListboxServiceContent::eListboxServiceContent()
168         :epgcache(eEPGCache::getInstance()), m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
169 {
170         cursorHome();
171         eServiceCenter::getInstance(m_service_center);
172 }
173
174 void eListboxServiceContent::cursorHome()
175 {
176         if (m_current_marked && m_saved_cursor == m_list.end())
177         {
178                 while (m_cursor_number)
179                 {
180                         std::iter_swap(m_cursor--, m_cursor);
181                         --m_cursor_number;
182                         if (m_listbox && m_cursor_number)
183                                 m_listbox->entryChanged(m_cursor_number);
184                 }
185         }
186         else
187         {
188                 m_cursor = m_list.begin();
189                 m_cursor_number = 0;
190         }
191 }
192
193 void eListboxServiceContent::cursorEnd()
194 {
195         if (m_current_marked && m_saved_cursor == m_list.end())
196         {
197                 while (m_cursor != m_list.end())
198                 {
199                         list::iterator prev = m_cursor++;
200                         ++m_cursor_number;
201                         if ( prev != m_list.end() && m_cursor != m_list.end() )
202                         {
203                                 std::iter_swap(m_cursor, prev);
204                                 if ( m_listbox )
205                                         m_listbox->entryChanged(m_cursor_number);
206                         }
207                 }
208         }
209         else
210         {
211                 m_cursor = m_list.end();
212                 m_cursor_number = m_size;
213         }
214 }
215
216 int eListboxServiceContent::setCurrentMarked(bool state)
217 {
218         bool prev = m_current_marked;
219         m_current_marked = state;
220
221         if (state != prev && m_listbox)
222         {
223                 m_listbox->entryChanged(m_cursor_number);
224                 if (!state)
225                 {
226                         ePtr<iListableService> lst;
227                         if (m_service_center->list(m_root, lst))
228                                 eDebug("no list available!");
229                         else
230                         {
231                                 ePtr<iMutableServiceList> list;
232                                 if (lst->startEdit(list))
233                                         eDebug("no editable list");
234                                 else
235                                 {
236                                         eServiceReference ref;
237                                         getCurrent(ref);
238                                         if(!ref)
239                                                 eDebug("no valid service selected");
240                                         else
241                                         {
242                                                 int pos = cursorGet();
243                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
244                                                 if (list->moveService(ref, cursorGet()))
245                                                         eDebug("failed");
246                                                 else
247                                                         eDebug("ok");
248                                         }
249                                 }
250                         }
251                 }
252         }
253
254         return 0;
255 }
256
257 int eListboxServiceContent::cursorMove(int count)
258 {
259         int prev = m_cursor_number, last = m_cursor_number + count;
260         if (count > 0)
261         {
262                 while(count && m_cursor != m_list.end())
263                 {
264                         list::iterator prev_it = m_cursor++;
265                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
266                         {
267                                 std::iter_swap(prev_it, m_cursor);
268                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
269                                         m_listbox->entryChanged(m_cursor_number);
270                         }
271                         ++m_cursor_number;
272                         --count;
273         }
274         } else if (count < 0)
275         {
276                 while (count && m_cursor != m_list.begin())
277                 {
278                         list::iterator prev_it = m_cursor--;
279                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
280                         {
281                                 std::iter_swap(prev_it, m_cursor);
282                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
283                                         m_listbox->entryChanged(m_cursor_number);
284                         }
285                         --m_cursor_number;
286                         ++count;
287                 }
288         }
289         return 0;
290 }
291
292 int eListboxServiceContent::cursorValid()
293 {
294         return m_cursor != m_list.end();
295 }
296
297 int eListboxServiceContent::cursorSet(int n)
298 {
299         cursorHome();
300         cursorMove(n);
301         return 0;
302 }
303
304 int eListboxServiceContent::cursorGet()
305 {
306         return m_cursor_number;
307 }
308
309 void eListboxServiceContent::cursorSave()
310 {
311         m_saved_cursor = m_cursor;
312         m_saved_cursor_number = m_cursor_number;
313 }
314
315 void eListboxServiceContent::cursorRestore()
316 {
317         m_cursor = m_saved_cursor;
318         m_cursor_number = m_saved_cursor_number;
319         m_saved_cursor = m_list.end();
320 }
321
322 int eListboxServiceContent::size()
323 {
324         return m_size;
325 }
326         
327 void eListboxServiceContent::setSize(const eSize &size)
328 {
329         m_itemsize = size;
330         setVisualMode(m_visual_mode);
331 }
332
333 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
334 {
335         painter.clip(eRect(offset, m_itemsize));
336
337         if (m_current_marked && selected)
338                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
339         else if (cursorValid() && isMarked(*m_cursor))
340                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
341         else
342                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
343         painter.clear();
344         
345         if (cursorValid())
346         {
347                         /* get service information */
348                 ePtr<iStaticServiceInformation> service_info;
349                 m_service_center->info(*m_cursor, service_info);
350                 
351                 for (int e = 0; e < celElements; ++e)
352                 {
353                         if (!m_element_font[e])
354                                 continue;
355                         int flags=gPainter::RT_VALIGN_CENTER;
356
357                         eRect area = m_element_position[e];
358
359                         std::string text = "<n/a>";
360
361                         switch (e)
362                         {
363                         case celIcon:
364                                 // render icon here...
365                                 continue;
366                         case celServiceNumber:
367                         {
368                                 char bla[10];
369                                 sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1);
370                                 text = bla;
371                                 flags|=gPainter::RT_HALIGN_RIGHT;
372                                 break;
373                         }
374                         case celServiceName:
375                         {
376                                 if (service_info)
377                                         service_info->getName(*m_cursor, text);
378                                 break;
379                         }
380                         case celServiceInfo:
381                         {
382                                 ePtr<eServiceEvent> evt;
383                                 time_t t=-1;
384                                 if ( !epgcache->lookupEventTime(*m_cursor, t, evt) )
385                                         text = '(' + evt->getEventName() + ')';
386                                 else
387                                         continue;
388                                 break;
389                         }
390                         }
391
392                         eTextPara *para = new eTextPara(area);
393
394                         para->setFont(m_element_font[e]);
395                         para->renderString(text);
396
397                         if (e == celServiceName)
398                         {
399                                 eRect bbox = para->getBoundBox();
400                                 int name_width = bbox.width()+10;
401                                 m_element_position[celServiceInfo].setLeft(area.left()+name_width);
402                                 m_element_position[celServiceInfo].setTop(area.top());
403                                 m_element_position[celServiceInfo].setWidth(area.width()-name_width);
404                                 m_element_position[celServiceInfo].setHeight(area.height());
405                         }
406
407                         if (flags & gPainter::RT_HALIGN_RIGHT)
408                                 para->realign(eTextPara::dirRight);
409                         else if (flags & gPainter::RT_HALIGN_CENTER)
410                                 para->realign(eTextPara::dirCenter);
411                         else if (flags & gPainter::RT_HALIGN_BLOCK)
412                                 para->realign(eTextPara::dirBlock);
413
414                         ePoint offs = offset;
415
416                         if (flags & gPainter::RT_VALIGN_CENTER)
417                         {
418                                 eRect bbox = para->getBoundBox();
419                                 int vcentered_top = (area.height() - bbox.height()) / 2;
420                                 int correction = vcentered_top - bbox.top();
421                                 offs += ePoint(0, correction);
422                         }
423
424                         painter.renderPara(para, offs);
425                 }
426                 
427                 if (selected)
428                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
429         }
430         
431         painter.clippop();
432 }
433