]> git.vomp.tv Git - vompclient.git/blob - vepglistadvanced.cc
Fix crash when ffwd/rev after pause. Some log fixes
[vompclient.git] / vepglistadvanced.cc
1 /*
2     Copyright 2004-2020 Chris Tallon, 2014 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <sstream>
21
22 #include "boxstack.h"
23 #include "input.h"
24 #include "wsymbol.h"
25 #include "boxstack.h"
26 #include "vdr.h"
27 #include "colour.h"
28 #include "video.h"
29 #include "i18n.h"
30 #include "messagequeue.h"
31 #include "log.h"
32 #include "movieinfo.h"
33 #include "seriesinfo.h"
34 #include "event.h"
35 #include "channel.h"
36 #include "vepgsummary.h"
37 #include "vepgsettimer.h"
38 #include "vepg.h"
39 #include "staticartwork.h"
40
41 #include "vepglistadvanced.h"
42
43 static const char* TAG = "VEpgListAdvanced";
44
45 VEpgListAdvanced::VEpgListAdvanced(VVideoLiveTV* tvideolive, ChannelList* tchanList, ULONG initialChannelNumber)
46 {
47   channelNumber = initialChannelNumber;
48   chanList = tchanList;
49   videolive = tvideolive;
50   boxstack = BoxStack::getInstance();
51
52   mode = OneChannel;
53
54   setSize(640 + 40, 500 + 40); //old   setSize(570, 420);
55   createBuffer();
56
57   setPosition(20, 20);
58
59   setTitleBarOn(1);
60   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
61   TVMediaInfo* info = new TVMediaInfo();
62   info->setChannelLogo(channelNumber);
63   info->setStaticFallback(sa_tv);
64   setTitleBarIcon(info);
65
66   sl.setPosition(10, 30 + 5);
67   sl.setSize(area.w * 42 / 100 - 20, area.h - 30 - 15 - 30);
68   sl.setLinesPerOption(2.4f);
69   add(&sl);
70
71   Region slarea = sl.getRegionR();
72
73   epg.setParaMode(true);
74   epg.setPosition(slarea.x  + slarea.w + 10, 30 + 5);
75   epg.setSize(area.w - slarea.x - slarea.w - 10, area.h - 30 - 15 - 30);
76   add(&epg);
77   epg.setText("");
78   epg.setVideoBackground();
79   epg.setBackgroundColour(DrawStyle::VIEWTRANSPARENTBACKGROUND);
80
81   epgTVmedia.setPosition(epg.getRegionR().w - 100 - 10, 10);
82   epgTVmedia.setSize(100, static_cast<UINT>(150 / Osd::getInstance()->getPixelAspect()));
83   epg.add(&epgTVmedia);
84
85   boxRed.setBackgroundColour(DrawStyle::RED);
86   boxRed.setPosition(165 /*54*/, sl.getY2() + 8);
87   boxRed.setSize(18, 16);
88   add(&boxRed);
89
90   textRed.setPosition(boxRed.getX2(), sl.getY2() + 4);
91   textRed.setSize(116, 30);
92
93   add(&textRed);
94
95   boxGreen.setBackgroundColour(DrawStyle::GREEN);
96   boxGreen.setPosition(165 + 1 * 110, sl.getY2() + 8);
97   boxGreen.setSize(18, 16);
98   add(&boxGreen);
99
100   textGreen.setPosition(boxGreen.getX2(), sl.getY2() + 4);
101   textGreen.setSize(116, 30);
102   add(&textGreen);
103
104   boxYellow.setBackgroundColour(DrawStyle::YELLOW);
105   boxYellow.setPosition(165 + 2 * 110, sl.getY2() + 8);
106   boxYellow.setSize(18, 16);
107   add(&boxYellow);
108
109   textYellow.setPosition(boxYellow.getX2(), sl.getY2() + 4);
110   textYellow.setSize(116, 30);
111   add(&textYellow);
112
113   boxBlue.setBackgroundColour(DrawStyle::BLUE);
114   boxBlue.setPosition(165 + 3 * 110, sl.getY2() + 8);
115   boxBlue.setSize(18, 16);
116   add(&boxBlue);
117
118   textBlue.setPosition(boxBlue.getX2(), sl.getY2() + 4);
119   textBlue.setSize(116, 30);
120   add(&textBlue);
121
122   setButtonText();
123
124   updateEpgDataChannel();
125 }
126
127 VEpgListAdvanced::~VEpgListAdvanced()
128 {
129   clearEventList();
130 }
131
132 void VEpgListAdvanced::setButtonText()
133 {
134   switch (mode)
135   {
136     case OneChannel:
137     {
138       textRed.setText(tr("Record"));
139       textGreen.setText(tr("Now"));
140       textYellow.setText(tr("Next"));
141       textBlue.setText(tr("Guide"));
142       break;
143     }
144     case Now:
145     {
146       textRed.setText(tr("Record"));
147       textGreen.setText(tr("Next"));
148       textYellow.setText(tr("Schedule"));
149       textBlue.setText(tr("Switch"));
150       break;
151     }
152     case Next:
153     {
154       textRed.setText(tr("Record"));
155       textGreen.setText(tr("Now"));
156       textYellow.setText(tr("Schedule"));
157       textBlue.setText(tr("Switch"));
158       break;
159     }
160   };
161 }
162
163 void VEpgListAdvanced::doRed()
164 {
165   doRecord();
166 }
167
168 void VEpgListAdvanced::doGreen()
169 {
170   switch (mode)
171   {
172     case Now:
173     {
174       doNext();
175       break;
176     }
177     case OneChannel:
178     case Next:
179     {
180       doNow();
181       break;
182     }
183   };
184 }
185
186 void VEpgListAdvanced::doYellow()
187 {
188   switch (mode)
189   {
190     case OneChannel:
191     {
192       doNext();
193       break;
194     }
195     case Next:
196     case Now:
197     {
198       doProgramm();
199       break;
200     }
201   };
202 }
203
204 void VEpgListAdvanced::doBlue()
205 {
206   switch (mode)
207   {
208     case OneChannel:
209     {
210       doGrid();
211       break;
212     }
213     case Next:
214     case Now:
215     {
216       doSwitch();
217       break;
218     }
219   };
220 }
221
222 void VEpgListAdvanced::doNext()
223 {
224   LogNT::getInstance()->debug(TAG, "doNext");
225   ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
226
227   if (mode != OneChannel)
228   {
229     Channel* chan = (*chanList)[slCurrentOption];
230     channelNumber = chan->number;
231   }
232
233   mode = Next;
234   updateEpgDataNowNext(true);
235   setButtonText();
236   TVMediaInfo* info = new TVMediaInfo();
237   info->setStaticArtwork(sa_tv);
238   setTitleBarIcon(info);
239   draw(true);
240   boxstack->update(this);
241 }
242
243 void VEpgListAdvanced::doNow()
244 {
245   LogNT::getInstance()->debug(TAG, "doNow");
246   ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
247
248   if (mode != OneChannel)
249   {
250     Channel* chan = (*chanList)[slCurrentOption];
251     channelNumber = chan->number;
252   }
253
254   mode = Now;
255   updateEpgDataNowNext(true);
256   setButtonText();
257   TVMediaInfo* info = new TVMediaInfo();
258   info->setStaticArtwork(sa_tv);
259   setTitleBarIcon(info);
260   draw(true);
261   boxstack->update(this);
262 }
263
264 void VEpgListAdvanced::doProgramm()
265 {
266   LogNT::getInstance()->debug(TAG, "doProgram");
267   mode = OneChannel;
268   ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
269   Channel* chan = (*chanList)[slCurrentOption];
270   channelNumber = chan->number;
271   updateEpgDataChannel();
272   setButtonText();
273   TVMediaInfo* info = new TVMediaInfo();
274   info->setChannelLogo(channelNumber);
275   info->setStaticFallback(sa_tv);
276   setTitleBarIcon(info);
277   draw(true);
278   boxstack->update(this);
279 }
280
281 void VEpgListAdvanced::doSwitch()
282 {
283   if (videolive)
284   {
285     if (mode != OneChannel)
286     {
287       ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
288       Channel* chan = (*chanList)[slCurrentOption];
289       channelNumber = chan->number;
290     }
291
292     LogNT::getInstance()->debug(TAG, "doSwitch {}", channelNumber);
293     Message* m = new Message(); // Must be done after this view deleted
294     m->from = this;
295     m->to = videolive;
296     m->message = Message::CHANNEL_CHANGE;
297     m->parameter = channelNumber;
298     m->tag = 0;
299     MessageQueue::getInstance()->postMessage(m);
300   }
301 }
302
303 #if WIN32
304   // FIXME win pragma
305   #pragma warning(disable : 4703)
306 #endif
307
308 void VEpgListAdvanced::doRecord()
309 {
310   ULONG channel;
311   Event* current = getCurrentOptionEvent(channel);
312
313   if (current)
314   {
315     LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title, current->id);
316     unsigned int chanlistsize = chanList->size();
317     Channel* chan;
318     UINT listIndex;
319
320     for (listIndex = 0; listIndex < chanlistsize; listIndex++)
321     {
322       chan = (*chanList)[listIndex];
323
324       if (chan->number == channel) break;
325     }
326
327     LogNT::getInstance()->debug(TAG, "ID {} TIME {} DURATION {} TITLE {}",
328                             current->id, current->time, current->duration, current->title);
329     VEpgSetTimer* vs = new VEpgSetTimer(current, chan);
330     vs->draw();
331     boxstack->add(vs);
332     boxstack->update(vs);
333   }
334 }
335
336 void VEpgListAdvanced::doGrid()
337 {
338   if (mode != OneChannel)
339   {
340     ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
341     Channel* chan = (*chanList)[slCurrentOption];
342     channelNumber = chan->number;
343   }
344
345   UINT listIndex;
346   unsigned int chanlistsize = chanList->size();
347   Channel* chan;
348
349   for (listIndex = 0; listIndex < chanlistsize; listIndex++)
350   {
351     chan = (*chanList)[listIndex];
352     if (chan->number == channelNumber) break;
353   }
354
355   VEpg* vepg = new VEpg(videolive, listIndex, chanList);
356   vepg->draw();
357   boxstack->add(vepg);
358   boxstack->update(vepg);
359 }
360
361 void VEpgListAdvanced::clearEventList()
362 {
363   std::vector<EventList*>::iterator itty = eventLista.begin();
364
365   while (itty != eventLista.end())
366   {
367     if (*itty)
368     {
369       (*itty)->clear();
370       delete (*itty);
371     }
372
373     itty++;
374   }
375
376   eventLista.clear();
377 }
378
379 /* Prototype
380  *
381  *   if (!chanList) return;
382   Channel* chan;
383   for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
384   {
385     if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
386       continue;
387     chan = (*chanList)[listTop + listIndex];
388     eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, window_width * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window
389   }
390
391  */
392
393 void VEpgListAdvanced::updateEpgData()
394 {
395   switch (mode)
396   {
397     case OneChannel:
398     {
399       //updateEpgDataChannel();
400       break;
401     }
402     case Next:
403     case Now:
404     {
405       updateEpgDataNowNext(false);
406       break;
407     }
408   };
409 }
410
411 void VEpgListAdvanced::updateEpgDataNowNext(bool changeState)
412 {
413   int startupdate = 0;
414   int endupdate = 0;
415
416   UINT chanlistsize = chanList->size();
417
418   if (changeState)
419   {
420     clearEventList();
421     eventLista.resize(chanList->size());
422     Channel* chan;
423
424     for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
425     {
426       if (listIndex >= chanlistsize) continue;
427
428       chan = (*chanList)[listIndex];
429
430       if (chan->number == channelNumber)
431       {
432         startupdate = listIndex - sl.getNumOptionsDisplayable() - 2;
433         endupdate = listIndex + sl.getNumOptionsDisplayable() + 2;
434         break;
435       }
436     }
437   }
438   else
439   {
440     startupdate = sl.getTopOption() - 2;
441     endupdate = sl.getBottomOption() + 1;
442   }
443
444   time_t now;
445   time(&now);
446
447   Channel* chan;
448
449   for (int listIndex = startupdate; listIndex < endupdate; listIndex++)
450   {
451     if (listIndex < 0) continue;
452     if (listIndex >= static_cast<int>(chanlistsize)) continue;
453
454     chan = (*chanList)[listIndex];
455
456     if (!eventLista[listIndex]) eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, now, 4 * 60 * 60);
457   }
458 }
459
460 void VEpgListAdvanced::updateEpgDataChannel()
461 {
462   clearEventList();
463   eventLista.resize(1);
464   time_t now;
465   time(&now);
466   eventLista[0] = VDR::getInstance()->getChannelSchedule(channelNumber, now, 24 * 60 * 60 * 30); // one month
467   LogNT::getInstance()->debug(TAG, "Eventlist {:#x} {}", (void*)eventLista[0], channelNumber);
468 }
469
470 void VEpgListAdvanced::drawData(bool doIndexPop)
471 {
472   if      (mode == OneChannel) drawDataChannel(doIndexPop);
473   else if (mode == Next)       drawDataNowNext(true, doIndexPop);
474   else if (mode == Now)        drawDataNowNext(false, doIndexPop);
475 }
476
477 void VEpgListAdvanced::drawDataChannel(bool doIndexPop)
478 {
479   int saveIndex = sl.getCurrentOption();
480   int saveTop = sl.getTopOption();
481   sl.clear();
482   sl.addColumn(0);
483   sl.addColumn(25 );
484   sl.addColumn(25 + 7);
485   sl.addColumn(25 + 7 + 7);
486   //sl.addColumn(118);
487
488   int first = 1;
489
490   char tempA[300]; // FIXME  this is guesswork!
491   char tempB[300]; // FIXME
492   char tempC[300]; // FIXME
493   struct tm btime;
494
495   Event* currentEvent = NULL;
496   EventList::iterator j;
497   EventList* eventList = eventLista[0];
498
499   if (eventList)
500   {
501     for (j = eventList->begin(); j != eventList->end(); j++)
502     {
503       currentEvent = *j;
504       time_t eventStartTime = static_cast<time_t>(currentEvent->time);
505       time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
506
507       LOCALTIME_R(&eventStartTime, &btime);
508       strftime(tempA, 300, "%d/%m/%y %H:%M ", &btime);
509       LOCALTIME_R(&eventEndTime, &btime);
510       strftime(tempB, 300, "- %H:%M ", &btime);
511       int check = SNPRINTF(tempC, 300, "\t %s\n \t \t%s%s", currentEvent->title.c_str(), tempA, tempB);
512
513       if ((check < 0) || (check > 299)) LogNT::getInstance()->debug(TAG, "String too big");
514
515       // New TVMedia stuff
516       TVMediaInfo* info = new TVMediaInfo();
517       info->setPosterThumb(channelNumber, currentEvent->id);
518       info->setStaticFallback(sa_defposter);
519       currentEvent->index = sl.addOption(tempC, reinterpret_cast<void*>(currentEvent->id), first, info);
520       first = 0;
521     }
522   }
523
524   if (doIndexPop)
525   {
526     sl.hintSetCurrent(0);
527   }
528   else
529   {
530     sl.hintSetCurrent(saveIndex);
531     sl.hintSetTop(saveTop);
532   }
533
534   updateSelection();
535 }
536
537 void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop)
538 {
539   int saveIndex = sl.getCurrentOption();
540   int saveTop = sl.getTopOption();
541   sl.clear();
542   sl.addColumn(0);
543   sl.addColumn(42 );
544   sl.addColumn(160);
545
546   int first = 1;
547
548   char tempA[300]; // FIXME  this is guesswork!
549   char tempB[300]; // FIXME
550   char tempC[300]; // FIXME
551   struct tm btime;
552
553   Event* currentEvent = NULL;
554   EventList::iterator j;
555   UINT minevents = 1;
556
557   if (next) minevents++;
558
559   int setcurrenthelper = 0;
560
561   unsigned int chanlistsize = chanList->size();
562
563   for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
564   {
565     Channel* chan;
566     chan = (*chanList)[listIndex];
567
568     EventList* eventList = eventLista[listIndex];
569
570     if (eventList && (eventList->size() >= minevents))
571     {
572       j = eventList->begin();
573
574       currentEvent = j[minevents - 1];
575       time_t eventStartTime = static_cast<time_t>(currentEvent->time);
576       time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
577
578       LOCALTIME_R(&eventStartTime, &btime);
579       strftime(tempA, 300, "%H:%M ", &btime);
580       LOCALTIME_R(&eventEndTime, &btime);
581       strftime(tempB, 300, "- %H:%M ", &btime);
582       int check = SNPRINTF(tempC, 300, "%s\n%s\t %s%s", currentEvent->title.c_str(), chan->name, tempA, tempB);
583
584       if ((check < 0) || (check > 299)) LogNT::getInstance()->debug(TAG, "String too big");
585     }
586     else
587     {
588       sprintf(tempC, "\n%s", chan->name);
589     }
590
591     TVMediaInfo* info = new TVMediaInfo();
592
593     if ((*chanList)[listIndex]->number == channelNumber)
594     {
595       first = 1;
596       setcurrenthelper = listIndex;
597     }
598
599     info->setChannelLogo((*chanList)[listIndex]->number);
600     info->setStaticFallback(sa_tv);
601     int index = sl.addOption(tempC, reinterpret_cast<void*>(listIndex), first, info);
602
603     if (currentEvent) currentEvent->index = index;
604
605     first = 0;
606   }
607
608   if (doIndexPop)
609   {
610     sl.hintSetCurrent(setcurrenthelper);
611   }
612   else
613   {
614     sl.hintSetCurrent(saveIndex);
615     sl.hintSetTop(saveTop);
616   }
617
618   updateSelection();
619 }
620
621 void VEpgListAdvanced::draw(bool doIndexPop)
622 {
623   // Single channel mode
624   switch (mode)
625   {
626     case OneChannel:
627     {
628       char tempA[300];
629       unsigned int chanlistsize = chanList->size();
630       Channel* chan;
631       UINT listIndex;
632
633       for (listIndex = 0; listIndex < chanlistsize; listIndex++)
634       {
635         chan = (*chanList)[listIndex];
636
637         if (chan->number == channelNumber) break;
638       }
639
640       sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name);
641       setTitleText(tempA);
642       break;
643     }
644     case Now:
645     {
646       setTitleText(tr("Now"));
647       break;
648     }
649     case Next:
650     {
651       setTitleText(tr("Next"));
652       break;
653     }
654   };
655
656   drawData(doIndexPop);
657
658   TBBoxx::draw();
659
660
661   char freeSpace[50];
662   struct tm btime;
663   time_t now;
664
665   time(&now);
666   LOCALTIME_R(&now, &btime);
667   strftime(freeSpace, 299, "%d/%m/%y", &btime);
668   drawTextRJ(freeSpace, getWidth(), 5, DrawStyle::LIGHTTEXT);
669
670   // Symbols
671
672   WSymbol w;
673   TEMPADD(&w);
674
675   w.nextSymbol = WSymbol::UP;
676   w.setPosition(20, area.h - 35);
677   w.draw();
678
679   w.nextSymbol = WSymbol::DOWN;
680   w.setPosition(50, area.h - 35);
681   w.draw();
682
683   w.nextSymbol = WSymbol::SKIPBACK;
684   w.setPosition(85, area.h - 35);
685   w.draw();
686
687   w.nextSymbol = WSymbol::SKIPFORWARD;
688   w.setPosition(115, area.h - 35);
689   w.draw();
690
691   drawTextRJ(tr("[ok] = info"), 560 + 70, sl.getY2() + 4, DrawStyle::LIGHTTEXT);
692
693   // All static stuff done
694 }
695
696 Event* VEpgListAdvanced::getCurrentOptionEvent(ULONG& channel)
697 {
698   if (mode == OneChannel)
699   {
700     channel = channelNumber;
701
702     EventList* eventList = eventLista[0];
703     if (!eventList) return NULL;
704
705     for (Event* currentEvent : *eventList)
706     {
707       if (currentEvent->index == sl.getCurrentOption()) return currentEvent;
708     }
709   }
710   else if ((mode == Now) || (mode == Next))
711   {
712     ULONG slCurrentOptionData = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
713     EventList* eventList = eventLista[slCurrentOptionData];
714     if (!eventList) return NULL;
715     channel = (*chanList)[slCurrentOptionData]->number;
716
717     if      ((mode == Now) && (eventList->size() > 0)) return (*eventList)[0];
718     else if ((mode == Next) && (eventList->size() > 1)) return (*eventList)[1];
719   }
720
721   return NULL;
722 }
723
724 void VEpgListAdvanced::updateSelection()
725 {
726   ULONG channel = 0;
727
728   if (mode == OneChannel)
729   {
730     TVMediaInfo* info = new TVMediaInfo();
731     info->setChannelLogo(channelNumber);
732     info->setStaticFallback(sa_tv);
733     setTitleBarIcon(info);
734   }
735
736   Event* toShow = getCurrentOptionEvent(channel);
737
738   if (toShow)
739   {
740     toShow->loadinfos(channel);
741     std::stringstream description;
742
743     description << "\n" << toShow->title  << "\n\n";
744     description << toShow->subtitle << "\n";
745     description << toShow->description;
746
747     TVMedia poster;
748     poster.height = 0;
749
750     if (toShow->movieInfo)
751     {
752       poster = toShow->movieInfo->poster;
753     }
754
755     if (toShow->seriesInfo)
756     {
757       if (toShow->seriesInfo->seasonposter.height)
758       {
759         poster = toShow->seriesInfo->seasonposter;
760       }
761       else if (toShow->seriesInfo->posters.size())
762       {
763         poster = toShow->seriesInfo->posters[0];
764       }
765     }
766
767     if (poster.height)
768     {
769       epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal);
770       epgTVmedia.setVisible(true);
771     }
772     else
773     {
774       if (toShow->epgImage)
775       {
776         TVMediaInfo info;
777         info.setPosterThumb(channel, toShow->id);
778         epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
779         epgTVmedia.setVisible(true);
780       }
781       else if (mode != OneChannel)
782       {
783         TVMediaInfo info;
784         info.setChannelLogo(channel);
785         epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
786         epgTVmedia.setVisible(true);
787       }
788       else
789       {
790         epgTVmedia.setVisible(false);
791       }
792     }
793
794     epg.setText(description.str().c_str());
795   }
796   else
797   {
798     epg.setText("");
799
800     if (mode != OneChannel)
801     {
802       TVMediaInfo info;
803       info.setChannelLogo(channel);
804       epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
805       epgTVmedia.setVisible(true);
806     }
807     else
808     {
809       epgTVmedia.setVisible(false);
810     }
811   }
812 }
813
814 int VEpgListAdvanced::handleCommand(int command)
815 {
816   switch (command)
817   {
818     case Input::UP:
819     {
820       sl.up();
821       quickUpdate();
822
823       boxstack->update(this);
824       return 2;
825     }
826
827     case Input::DOWN:
828     {
829       sl.down();
830       quickUpdate();
831
832       boxstack->update(this);
833       return 2;
834     }
835
836     case Input::SKIPBACK:
837     {
838       sl.pageUp();
839       quickUpdate();
840
841       boxstack->update(this);
842       return 2;
843     }
844
845     case Input::SKIPFORWARD:
846     {
847       sl.pageDown();
848       quickUpdate();
849
850       boxstack->update(this);
851       return 2;
852     }
853
854     case Input::RED:
855     {
856       doRed();
857       return 2;
858     }
859
860     case Input::GREEN:
861     {
862       doGreen();
863       return 2;
864     }
865
866     case Input::YELLOW:
867     {
868       doYellow();
869       return 2;
870     }
871
872     case Input::BLUE:
873     {
874       doBlue();
875       return 2;
876     }
877
878     case Input::OK:
879     {
880       if (sl.getNumOptions() == 0) return 2;
881
882       ULONG channel;
883       Event* current = getCurrentOptionEvent(channel);
884
885       if (current)
886       {
887         LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title.c_str(), current->id);
888         unsigned int chanlistsize = chanList->size();
889         Channel* chan;
890         UINT listIndex;
891
892         for (listIndex = 0; listIndex < chanlistsize; listIndex++)
893         {
894           chan = (*chanList)[listIndex];
895           if (chan->number == channel) break;
896         }
897
898         VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]);
899         vr->draw();
900         boxstack->add(vr);
901         boxstack->update(vr);
902
903         return 2;
904       }
905
906       // should not get to here
907       return 1;
908     }
909
910     case Input::BACK:
911     {
912       return 4;
913     }
914   }
915
916   // stop command getting to any more views
917   return 1;
918 }
919
920 void VEpgListAdvanced::processMessage(Message* m)
921 {
922   LogNT::getInstance()->debug(TAG, "Got message value {}", m->message);
923
924   if (m->message == Message::MOUSE_MOVE)
925   {
926     if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
927     {
928       quickUpdate();
929       boxstack->update(this);
930     }
931   }
932   else if (m->message == Message::MOUSE_LBDOWN)
933   {
934     int x = m->parameter - getScreenX();
935     int y = m->tag - getScreenY();
936     if (sl.mouseLBDOWN(x, y))
937     {
938       boxstack->handleCommand(Input::OK); //simulate OK press
939     }
940     else if (boxRed.mouseLBDOWN(x, y))
941     {
942       boxstack->handleCommand(Input::RED);
943     }
944     else if (boxGreen.mouseLBDOWN(x, y))
945     {
946       boxstack->handleCommand(Input::GREEN); // FIXME all these green? is this right?
947     }
948     else if (boxYellow.mouseLBDOWN(x, y))
949     {
950       boxstack->handleCommand(Input::GREEN);
951     }
952     else if (boxBlue.mouseLBDOWN(x, y))
953     {
954       boxstack->handleCommand(Input::GREEN);
955     }
956     else
957     {
958       if (coordsOutsideBox(m))
959       {
960         boxstack->handleCommand(Input::BACK); //simulate cancel press
961       }
962     }
963   }
964 }
965
966 void VEpgListAdvanced::quickUpdate()   //only quick for plattform that need it!
967 {
968   updateEpgData();
969   updateSelection();
970 #ifdef GRADIENT_DRAWING
971   draw();
972 #else
973   sl.draw();
974   epg.draw();
975 #endif
976 }