support for renderer
[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         if (m_listbox)
52                 m_listbox->moveSelectionTo(index);
53 }
54
55 void eListboxServiceContent::getCurrent(eServiceReference &ref)
56 {
57         if (cursorValid())
58                 ref = *m_cursor;
59         else
60                 ref = eServiceReference();
61 }
62
63 int eListboxServiceContent::getNextBeginningWithChar(char c)
64 {
65 //      printf("Char: %c\n", c);
66         int index=0;
67         for (list::iterator i(m_list.begin()); i != m_list.end(); ++i, ++index)
68         {
69                 std::string text;
70                 ePtr<iStaticServiceInformation> service_info;
71                 m_service_center->info(*i, service_info);
72                 service_info->getName(*i, text);
73 //              printf("%c\n", text.c_str()[0]);
74                 int idx=0;
75                 int len=text.length();
76                 while ( idx <= len )
77                 {
78                         char cc = text[idx++];
79                         if ( cc >= 33 && cc < 127)
80                         {
81                                 if (cc == c)
82                                         return index;
83                                 break;
84                         }
85                 }
86         }
87         return 0;
88 }
89
90 void eListboxServiceContent::initMarked()
91 {
92         m_marked.clear();
93 }
94
95 void eListboxServiceContent::addMarked(const eServiceReference &ref)
96 {
97         m_marked.insert(ref);
98         if (m_listbox)
99                 m_listbox->entryChanged(lookupService(ref));
100 }
101
102 void eListboxServiceContent::removeMarked(const eServiceReference &ref)
103 {
104         m_marked.erase(ref);
105         if (m_listbox)
106                 m_listbox->entryChanged(lookupService(ref));
107 }
108
109 int eListboxServiceContent::isMarked(const eServiceReference &ref)
110 {
111         return m_marked.find(ref) != m_marked.end();
112 }
113
114 void eListboxServiceContent::markedQueryStart()
115 {
116         m_marked_iterator = m_marked.begin();
117 }
118
119 int eListboxServiceContent::markedQueryNext(eServiceReference &ref)
120 {
121         if (m_marked_iterator == m_marked.end())
122                 return -1;
123         ref = *m_marked_iterator++;
124         return 0;
125 }
126
127 int eListboxServiceContent::lookupService(const eServiceReference &ref)
128 {
129                 /* shortcut for cursor */
130         if (ref == *m_cursor)
131                 return m_cursor_number;
132                 /* otherwise, search in the list.. */
133         int index = 0;
134         for (list::const_iterator i(m_list.begin()); i != m_list.end(); ++i, ++index);
135         
136                 /* this is ok even when the index was not found. */
137         return index;
138 }
139
140 void eListboxServiceContent::setVisualMode(int mode)
141 {
142         m_visual_mode = mode;
143         
144         if (m_visual_mode == visModeSimple)
145         {
146                 m_element_position[celServiceName] = eRect(ePoint(0, 0), m_itemsize);
147                 m_element_font[celServiceName] = new gFont("Regular", 23);
148                 m_element_position[celServiceNumber] = eRect();
149                 m_element_font[celServiceNumber] = 0;
150                 m_element_position[celServiceInfo] = eRect();
151                 m_element_font[celServiceInfo] = 0;
152         }
153 }
154
155 void eListboxServiceContent::setElementPosition(int element, eRect where)
156 {
157         if ((element >= 0) && (element < celElements))
158                 m_element_position[element] = where;
159 }
160
161 void eListboxServiceContent::setElementFont(int element, gFont *font)
162 {
163         if ((element >= 0) && (element < celElements))
164                 m_element_font[element] = font;
165 }
166
167 void eListboxServiceContent::setPixmap(int type, ePtr<gPixmap> &pic)
168 {
169         if ((type >=0) && (type < picElements))
170                 m_pixmaps[type] = pic;
171 }
172
173 void eListboxServiceContent::sort()
174 {
175         ePtr<iListableService> lst;
176         if (!m_service_center->list(m_root, lst))
177         {
178                 m_list.sort(iListableServiceCompare(lst));
179                         /* FIXME: is this really required or can we somehow keep the current entry? */
180                 cursorHome();
181                 if (m_listbox)
182                         m_listbox->entryReset();
183         }
184 }
185
186 DEFINE_REF(eListboxServiceContent);
187
188 eListboxServiceContent::eListboxServiceContent()
189         :m_visual_mode(visModeSimple), m_size(0), m_current_marked(false), m_numberoffset(0)
190 {
191         cursorHome();
192         eServiceCenter::getInstance(m_service_center);
193 }
194
195 void eListboxServiceContent::cursorHome()
196 {
197         if (m_current_marked && m_saved_cursor == m_list.end())
198         {
199                 if (m_cursor_number >= m_size)
200                 {
201                         m_cursor_number = m_size-1;
202                         --m_cursor;
203                 }
204                 while (m_cursor_number)
205                 {
206                         std::iter_swap(m_cursor--, m_cursor);
207                         --m_cursor_number;
208                         if (m_listbox && m_cursor_number)
209                                 m_listbox->entryChanged(m_cursor_number);
210                 }
211         }
212         else
213         {
214                 m_cursor = m_list.begin();
215                 m_cursor_number = 0;
216         }
217 }
218
219 void eListboxServiceContent::cursorEnd()
220 {
221         if (m_current_marked && m_saved_cursor == m_list.end())
222         {
223                 while (m_cursor != m_list.end())
224                 {
225                         list::iterator prev = m_cursor++;
226                         ++m_cursor_number;
227                         if ( prev != m_list.end() && m_cursor != m_list.end() )
228                         {
229                                 std::iter_swap(m_cursor, prev);
230                                 if ( m_listbox )
231                                         m_listbox->entryChanged(m_cursor_number);
232                         }
233                 }
234         }
235         else
236         {
237                 m_cursor = m_list.end();
238                 m_cursor_number = m_size;
239         }
240 }
241
242 int eListboxServiceContent::setCurrentMarked(bool state)
243 {
244         bool prev = m_current_marked;
245         m_current_marked = state;
246
247         if (state != prev && m_listbox)
248         {
249                 m_listbox->entryChanged(m_cursor_number);
250                 if (!state)
251                 {
252                         ePtr<iListableService> lst;
253                         if (m_service_center->list(m_root, lst))
254                                 eDebug("no list available!");
255                         else
256                         {
257                                 ePtr<iMutableServiceList> list;
258                                 if (lst->startEdit(list))
259                                         eDebug("no editable list");
260                                 else
261                                 {
262                                         eServiceReference ref;
263                                         getCurrent(ref);
264                                         if(!ref)
265                                                 eDebug("no valid service selected");
266                                         else
267                                         {
268                                                 int pos = cursorGet();
269                                                 eDebugNoNewLine("move %s to %d ", ref.toString().c_str(), pos);
270                                                 if (list->moveService(ref, cursorGet()))
271                                                         eDebug("failed");
272                                                 else
273                                                         eDebug("ok");
274                                         }
275                                 }
276                         }
277                 }
278         }
279
280         return 0;
281 }
282
283 int eListboxServiceContent::cursorMove(int count)
284 {
285         int prev = m_cursor_number, last = m_cursor_number + count;
286         if (count > 0)
287         {
288                 while(count && m_cursor != m_list.end())
289                 {
290                         list::iterator prev_it = m_cursor++;
291                         if ( m_current_marked && m_cursor != m_list.end() && m_saved_cursor == m_list.end() )
292                         {
293                                 std::iter_swap(prev_it, m_cursor);
294                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
295                                         m_listbox->entryChanged(m_cursor_number);
296                         }
297                         ++m_cursor_number;
298                         --count;
299         }
300         } else if (count < 0)
301         {
302                 while (count && m_cursor != m_list.begin())
303                 {
304                         list::iterator prev_it = m_cursor--;
305                         if ( m_current_marked && m_cursor != m_list.end() && prev_it != m_list.end() && m_saved_cursor == m_list.end() )
306                         {
307                                 std::iter_swap(prev_it, m_cursor);
308                                 if ( m_listbox && prev != m_cursor_number && last != m_cursor_number )
309                                         m_listbox->entryChanged(m_cursor_number);
310                         }
311                         --m_cursor_number;
312                         ++count;
313                 }
314         }
315         return 0;
316 }
317
318 int eListboxServiceContent::cursorValid()
319 {
320         return m_cursor != m_list.end();
321 }
322
323 int eListboxServiceContent::cursorSet(int n)
324 {
325         cursorHome();
326         cursorMove(n);
327         return 0;
328 }
329
330 int eListboxServiceContent::cursorGet()
331 {
332         return m_cursor_number;
333 }
334
335 void eListboxServiceContent::cursorSave()
336 {
337         m_saved_cursor = m_cursor;
338         m_saved_cursor_number = m_cursor_number;
339 }
340
341 void eListboxServiceContent::cursorRestore()
342 {
343         m_cursor = m_saved_cursor;
344         m_cursor_number = m_saved_cursor_number;
345         m_saved_cursor = m_list.end();
346 }
347
348 int eListboxServiceContent::size()
349 {
350         return m_size;
351 }
352         
353 void eListboxServiceContent::setSize(const eSize &size)
354 {
355         m_itemsize = size;
356         setVisualMode(m_visual_mode);
357 }
358
359 void eListboxServiceContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected)
360 {
361         painter.clip(eRect(offset, m_itemsize));
362
363         if (m_current_marked && selected)
364                 style.setStyle(painter, eWindowStyle::styleListboxMarked);
365         else if (cursorValid() && isMarked(*m_cursor))
366                 style.setStyle(painter, selected ? eWindowStyle::styleListboxMarkedAndSelected : eWindowStyle::styleListboxMarked);
367         else
368                 style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal);
369         painter.clear();
370         
371         if (cursorValid())
372         {
373                         /* get service information */
374                 ePtr<iStaticServiceInformation> service_info;
375                 m_service_center->info(*m_cursor, service_info);
376
377                 if (m_is_playable_ignore.valid() && service_info && !service_info->isPlayable(*m_cursor, m_is_playable_ignore))
378                         painter.setForegroundColor(gRGB(0xbbbbbb));
379
380                 int xoffset=0;  // used as offset when painting the folder symbol
381
382                 for (int e = 0; e < celElements; ++e)
383                 {
384                         if (m_element_font[e])
385                         {
386                                 int flags=gPainter::RT_VALIGN_CENTER,
387                                         yoffs = 0,
388                                         xoffs = xoffset;
389                                 eRect &area = m_element_position[e];
390                                 std::string text = "<n/a>";
391                                 xoffset=0;
392
393                                 switch (e)
394                                 {
395                                 case celServiceNumber:
396                                 {
397                                         char bla[10];
398                                         sprintf(bla, "%d", m_numberoffset + m_cursor_number + 1);
399                                         text = bla;
400                                         flags|=gPainter::RT_HALIGN_RIGHT;
401                                         break;
402                                 }
403                                 case celServiceName:
404                                 {
405                                         if (service_info)
406                                                 service_info->getName(*m_cursor, text);
407                                         break;
408                                 }
409                                 case celServiceInfo:
410                                 {
411                                         ePtr<eServiceEvent> evt;
412                                         if ( !service_info->getEvent(*m_cursor, evt) )
413                                         {
414                                                 std::string name = evt->getEventName();
415                                                 if (!name.length())
416                                                         continue;
417                                                 text = '(' + evt->getEventName() + ')';
418                                         }
419                                         else
420                                                 continue;
421                                         break;
422                                 }
423                                 }
424
425                                 eRect tmp = area;
426                                 tmp.setWidth(tmp.width()-xoffs);
427
428                                 eTextPara *para = new eTextPara(tmp);
429                                 para->setFont(m_element_font[e]);
430                                 para->renderString(text);
431
432                                 if (e == celServiceName)
433                                 {
434                                         eRect bbox = para->getBoundBox();
435                                         int name_width = bbox.width()+8;
436                                         m_element_position[celServiceInfo].setLeft(area.left()+name_width);
437                                         m_element_position[celServiceInfo].setTop(area.top());
438                                         m_element_position[celServiceInfo].setWidth(area.width()-name_width);
439                                         m_element_position[celServiceInfo].setHeight(area.height());
440                                 }
441
442                                 if (flags & gPainter::RT_HALIGN_RIGHT)
443                                         para->realign(eTextPara::dirRight);
444                                 else if (flags & gPainter::RT_HALIGN_CENTER)
445                                         para->realign(eTextPara::dirCenter);
446                                 else if (flags & gPainter::RT_HALIGN_BLOCK)
447                                         para->realign(eTextPara::dirBlock);
448
449                                 if (flags & gPainter::RT_VALIGN_CENTER)
450                                 {
451                                         eRect bbox = para->getBoundBox();
452                                         int vcentered_top = (area.height() - bbox.height()) / 2;
453                                         yoffs = vcentered_top - bbox.top();
454                                 }
455
456                                 painter.renderPara(para, offset+ePoint(xoffs, yoffs));
457                         }
458                         else if (e == celServiceTypePixmap || e == celFolderPixmap)
459                         {
460                                 int orbpos = m_cursor->getUnsignedData(4) >> 16;
461                                 ePtr<gPixmap> &pixmap =
462                                         (e == celFolderPixmap) ? m_pixmaps[picFolder] :
463                                         (orbpos == 0xFFFF) ? m_pixmaps[picDVB_C] :
464                                         (orbpos == 0xEEEE) ? m_pixmaps[picDVB_T] : m_pixmaps[picDVB_S];
465                                 if (pixmap)
466                                 {
467                                         eSize pixmap_size = pixmap->size();
468                                         eRect area = m_element_position[e == celFolderPixmap ? celServiceName : celServiceInfo];
469                                         int correction = (area.height() - pixmap_size.height()) / 2;
470
471                                         if (m_cursor->flags & eServiceReference::flagDirectory)
472                                         {
473                                                 if (e != celFolderPixmap)
474                                                         continue;
475                                                 xoffset = pixmap_size.width() + 8;
476                                         }
477                                         else
478                                         {
479                                                 if (e != celServiceTypePixmap)
480                                                         continue;
481                                                 m_element_position[celServiceInfo] = area;
482                                                 m_element_position[celServiceInfo].setLeft(area.left() + pixmap_size.width() + 8);
483                                                 m_element_position[celServiceInfo].setWidth(area.width() - pixmap_size.width() - 8);
484                                         }
485
486                                         area.moveBy(offset);
487                                         painter.clip(area);
488                                         painter.blit(pixmap, offset+ePoint(area.left(), correction), area, gPainter::BT_ALPHATEST);
489                                         painter.clippop();
490                                 }
491                         }
492                 }
493                 
494                 if (selected)
495                         style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry);
496         }
497         
498         painter.clippop();
499 }
500
501 void eListboxServiceContent::setIgnoreService( const eServiceReference &service )
502 {
503         m_is_playable_ignore=service;
504 }