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