]> git.vomp.tv Git - vompclient.git/blob - vepglistadvanced.cc
Fix text corruption in channel number display on live tv
[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   struct tm btime;
491
492   char startTimeStr[16];
493   char endTimeStr[16];
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(startTimeStr, 16, "%d/%m/%y %H:%M", &btime);
509       LOCALTIME_R(&eventEndTime, &btime);
510       strftime(endTimeStr, 16, "%H:%M", &btime);
511       std::string eventText = fmt::format("\t {}\n \t \t{} - {}", currentEvent->title, startTimeStr, endTimeStr);
512
513       // New TVMedia stuff
514       TVMediaInfo* info = new TVMediaInfo();
515       info->setPosterThumb(channelNumber, currentEvent->id);
516       info->setStaticFallback(sa_defposter);
517
518       currentEvent->index = sl.addOption(eventText, reinterpret_cast<void*>(currentEvent->id), first, info);
519       first = 0;
520     }
521   }
522
523   if (doIndexPop)
524   {
525     sl.hintSetCurrent(0);
526   }
527   else
528   {
529     sl.hintSetCurrent(saveIndex);
530     sl.hintSetTop(saveTop);
531   }
532
533   updateSelection();
534 }
535
536 void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop)
537 {
538   int saveIndex = sl.getCurrentOption();
539   int saveTop = sl.getTopOption();
540   sl.clear();
541   sl.addColumn(0);
542   sl.addColumn(42 );
543   sl.addColumn(160);
544
545   int first = 1;
546
547   char startTimeStr[16];
548   char endTimeStr[16];
549   struct tm btime;
550
551   Event* currentEvent = NULL;
552   EventList::iterator j;
553   UINT minevents = 1;
554
555   if (next) minevents++;
556
557   int setcurrenthelper = 0;
558
559   unsigned int chanlistsize = chanList->size();
560
561   std::string eventText;
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(startTimeStr, 16, "%H:%M", &btime);
580       LOCALTIME_R(&eventEndTime, &btime);
581       strftime(endTimeStr, 16, "%H:%M", &btime);
582
583       eventText = fmt::format("{}\n{}\t{} - {}", currentEvent->title, chan->name, startTimeStr, endTimeStr);
584     }
585     else
586     {
587       eventText = fmt::format("\n{}", chan->name);
588     }
589
590     TVMediaInfo* info = new TVMediaInfo();
591
592     if ((*chanList)[listIndex]->number == channelNumber)
593     {
594       first = 1;
595       setcurrenthelper = listIndex;
596     }
597
598     info->setChannelLogo((*chanList)[listIndex]->number);
599     info->setStaticFallback(sa_tv);
600     int index = sl.addOption(eventText, reinterpret_cast<void*>(listIndex), first, info);
601
602     if (currentEvent) currentEvent->index = index;
603
604     first = 0;
605   }
606
607   if (doIndexPop)
608   {
609     sl.hintSetCurrent(setcurrenthelper);
610   }
611   else
612   {
613     sl.hintSetCurrent(saveIndex);
614     sl.hintSetTop(saveTop);
615   }
616
617   updateSelection();
618 }
619
620 void VEpgListAdvanced::draw(bool doIndexPop)
621 {
622   // Single channel mode
623   switch (mode)
624   {
625     case OneChannel:
626     {
627       char tempA[300];
628       unsigned int chanlistsize = chanList->size();
629       Channel* chan;
630       UINT listIndex;
631
632       for (listIndex = 0; listIndex < chanlistsize; listIndex++)
633       {
634         chan = (*chanList)[listIndex];
635
636         if (chan->number == channelNumber) break;
637       }
638
639       sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name);
640       setTitleText(tempA);
641       break;
642     }
643     case Now:
644     {
645       setTitleText(tr("Now"));
646       break;
647     }
648     case Next:
649     {
650       setTitleText(tr("Next"));
651       break;
652     }
653   };
654
655   drawData(doIndexPop);
656
657   TBBoxx::draw();
658
659
660   char freeSpace[50];
661   struct tm btime;
662   time_t now;
663
664   time(&now);
665   LOCALTIME_R(&now, &btime);
666   strftime(freeSpace, 299, "%d/%m/%y", &btime);
667   drawTextRJ(freeSpace, getWidth(), 5, DrawStyle::LIGHTTEXT);
668
669   // Symbols
670
671   WSymbol w;
672   TEMPADD(&w);
673
674   w.nextSymbol = WSymbol::UP;
675   w.setPosition(20, area.h - 35);
676   w.draw();
677
678   w.nextSymbol = WSymbol::DOWN;
679   w.setPosition(50, area.h - 35);
680   w.draw();
681
682   w.nextSymbol = WSymbol::SKIPBACK;
683   w.setPosition(85, area.h - 35);
684   w.draw();
685
686   w.nextSymbol = WSymbol::SKIPFORWARD;
687   w.setPosition(115, area.h - 35);
688   w.draw();
689
690   drawTextRJ(tr("[ok] = info"), 560 + 70, sl.getY2() + 4, DrawStyle::LIGHTTEXT);
691
692   // All static stuff done
693 }
694
695 Event* VEpgListAdvanced::getCurrentOptionEvent(ULONG& channel)
696 {
697   if (mode == OneChannel)
698   {
699     channel = channelNumber;
700
701     EventList* eventList = eventLista[0];
702     if (!eventList) return NULL;
703
704     for (Event* currentEvent : *eventList)
705     {
706       if (currentEvent->index == sl.getCurrentOption()) return currentEvent;
707     }
708   }
709   else if ((mode == Now) || (mode == Next))
710   {
711     ULONG slCurrentOptionData = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
712     EventList* eventList = eventLista[slCurrentOptionData];
713     if (!eventList) return NULL;
714     channel = (*chanList)[slCurrentOptionData]->number;
715
716     if      ((mode == Now) && (eventList->size() > 0)) return (*eventList)[0];
717     else if ((mode == Next) && (eventList->size() > 1)) return (*eventList)[1];
718   }
719
720   return NULL;
721 }
722
723 void VEpgListAdvanced::updateSelection()
724 {
725   ULONG channel = 0;
726
727   if (mode == OneChannel)
728   {
729     TVMediaInfo* info = new TVMediaInfo();
730     info->setChannelLogo(channelNumber);
731     info->setStaticFallback(sa_tv);
732     setTitleBarIcon(info);
733   }
734
735   Event* toShow = getCurrentOptionEvent(channel);
736
737   if (toShow)
738   {
739     toShow->loadinfos(channel);
740     std::stringstream description;
741
742     description << "\n" << toShow->title  << "\n\n";
743     description << toShow->subtitle << "\n";
744     description << toShow->description;
745
746     TVMedia poster;
747     poster.height = 0;
748
749     if (toShow->movieInfo)
750     {
751       poster = toShow->movieInfo->poster;
752     }
753
754     if (toShow->seriesInfo)
755     {
756       if (toShow->seriesInfo->seasonposter.height)
757       {
758         poster = toShow->seriesInfo->seasonposter;
759       }
760       else if (toShow->seriesInfo->posters.size())
761       {
762         poster = toShow->seriesInfo->posters[0];
763       }
764     }
765
766     if (poster.height)
767     {
768       epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal);
769       epgTVmedia.setVisible(true);
770     }
771     else
772     {
773       if (toShow->epgImage)
774       {
775         TVMediaInfo info;
776         info.setPosterThumb(channel, toShow->id);
777         epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
778         epgTVmedia.setVisible(true);
779       }
780       else if (mode != OneChannel)
781       {
782         TVMediaInfo info;
783         info.setChannelLogo(channel);
784         epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
785         epgTVmedia.setVisible(true);
786       }
787       else
788       {
789         epgTVmedia.setVisible(false);
790       }
791     }
792
793     epg.setText(description.str().c_str());
794   }
795   else
796   {
797     epg.setText("");
798
799     if (mode != OneChannel)
800     {
801       TVMediaInfo info;
802       info.setChannelLogo(channel);
803       epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
804       epgTVmedia.setVisible(true);
805     }
806     else
807     {
808       epgTVmedia.setVisible(false);
809     }
810   }
811 }
812
813 int VEpgListAdvanced::handleCommand(int command)
814 {
815   switch (command)
816   {
817     case Input::UP:
818     {
819       sl.up();
820       quickUpdate();
821
822       boxstack->update(this);
823       return 2;
824     }
825
826     case Input::DOWN:
827     {
828       sl.down();
829       quickUpdate();
830
831       boxstack->update(this);
832       return 2;
833     }
834
835     case Input::SKIPBACK:
836     {
837       sl.pageUp();
838       quickUpdate();
839
840       boxstack->update(this);
841       return 2;
842     }
843
844     case Input::SKIPFORWARD:
845     {
846       sl.pageDown();
847       quickUpdate();
848
849       boxstack->update(this);
850       return 2;
851     }
852
853     case Input::RED:
854     {
855       doRed();
856       return 2;
857     }
858
859     case Input::GREEN:
860     {
861       doGreen();
862       return 2;
863     }
864
865     case Input::YELLOW:
866     {
867       doYellow();
868       return 2;
869     }
870
871     case Input::BLUE:
872     {
873       doBlue();
874       return 2;
875     }
876
877     case Input::OK:
878     {
879       if (sl.getNumOptions() == 0) return 2;
880
881       ULONG channel;
882       Event* current = getCurrentOptionEvent(channel);
883
884       if (current)
885       {
886         LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title.c_str(), current->id);
887         unsigned int chanlistsize = chanList->size();
888         Channel* chan;
889         UINT listIndex;
890
891         for (listIndex = 0; listIndex < chanlistsize; listIndex++)
892         {
893           chan = (*chanList)[listIndex];
894           if (chan->number == channel) break;
895         }
896
897         VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]);
898         vr->draw();
899         boxstack->add(vr);
900         boxstack->update(vr);
901
902         return 2;
903       }
904
905       // should not get to here
906       return 1;
907     }
908
909     case Input::BACK:
910     {
911       return 4;
912     }
913   }
914
915   // stop command getting to any more views
916   return 1;
917 }
918
919 void VEpgListAdvanced::processMessage(Message* m)
920 {
921   LogNT::getInstance()->debug(TAG, "Got message value {}", m->message);
922
923   if (m->message == Message::MOUSE_MOVE)
924   {
925     if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
926     {
927       quickUpdate();
928       boxstack->update(this);
929     }
930   }
931   else if (m->message == Message::MOUSE_LBDOWN)
932   {
933     int x = m->parameter - getScreenX();
934     int y = m->tag - getScreenY();
935     if (sl.mouseLBDOWN(x, y))
936     {
937       boxstack->handleCommand(Input::OK); //simulate OK press
938     }
939     else if (boxRed.mouseLBDOWN(x, y))
940     {
941       boxstack->handleCommand(Input::RED);
942     }
943     else if (boxGreen.mouseLBDOWN(x, y))
944     {
945       boxstack->handleCommand(Input::GREEN); // FIXME all these green? is this right?
946     }
947     else if (boxYellow.mouseLBDOWN(x, y))
948     {
949       boxstack->handleCommand(Input::GREEN);
950     }
951     else if (boxBlue.mouseLBDOWN(x, y))
952     {
953       boxstack->handleCommand(Input::GREEN);
954     }
955     else
956     {
957       if (coordsOutsideBox(m))
958       {
959         boxstack->handleCommand(Input::BACK); //simulate cancel press
960       }
961     }
962   }
963 }
964
965 void VEpgListAdvanced::quickUpdate()   //only quick for plattform that need it!
966 {
967   updateEpgData();
968   updateSelection();
969 #ifdef GRADIENT_DRAWING
970   draw();
971 #else
972   sl.draw();
973   epg.draw();
974 #endif
975 }