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