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