]> git.vomp.tv Git - vompclient.git/blob - vvideolivetv.cc
Mouse code for windows
[vompclient.git] / vvideolivetv.cc
1 /*
2     Copyright 2007-2008 Chris Tallon
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, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "vvideolivetv.h"
22
23 #include "vchannellist.h"
24 #include "video.h"
25 #include "playerlive.h"
26 #include "playerlivetv.h"
27 #include "playerliveradio.h"
28 #include "channel.h"
29 #include "boxstack.h"
30 #include "colour.h"
31 #include "osd.h"
32 #include "command.h"
33 #include "i18n.h"
34 #include "wtextbox.h"
35 #include "remote.h"
36 #include "vaudioselector.h"
37 #include "colour.h"
38 #include "event.h"
39 #include "timers.h"
40 #include "vepg.h"
41
42 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
43 {
44   vdr = VDR::getInstance();
45   boxstack = BoxStack::getInstance();
46   video = Video::getInstance();
47   
48   vas = NULL;
49
50   chanList = tchanList;
51   vchannelList = tvchannelList;
52   numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
53
54   currentChannelIndex = 0;
55   previousChannelIndex = 0;
56   osdChannelIndex = 0;
57   keying = 0;
58
59   playing = false;
60
61   // Convert channel number to index
62   UINT i;
63   for(i = 0; i < chanList->size(); i++)
64   {
65     if ((*chanList)[i]->number == (UINT)initialChannelNumber)
66     {
67       currentChannelIndex = i;
68       osdChannelIndex = i;
69       break;
70     }
71   }
72
73   eventList = NULL;
74
75   videoMode = video->getMode();
76   
77   if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
78   {
79     streamType = VDR::VIDEO;
80     player = new PlayerLiveTV(Command::getInstance(), this, chanList);
81   }
82   else
83   {
84     streamType = VDR::RADIO;
85     player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
86   }
87   player->init();
88
89   setSize(video->getScreenWidth(), video->getScreenHeight());
90   createBuffer();
91   Colour transparent(0, 0, 0, 0);
92   setBackgroundColour(transparent);
93
94   dowss = false;
95   char* optionWSS = vdr->configLoad("General", "WSS");
96   if (optionWSS)
97   {
98     if (strstr(optionWSS, "Yes")) dowss = true;
99     delete[] optionWSS;
100   }
101   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
102
103   if (dowss)
104   {
105     wss.setFormat(video->getFormat());
106     wss.setWide(true);
107     add(&wss);
108     
109     wssRegion.x = 0;
110     wssRegion.y = 6;
111     wssRegion.w = video->getScreenWidth();
112     wssRegion.h = 2;
113   }
114   
115   Colour osdBack = Colour(0, 0, 0, 128);
116   
117   osd.setBackgroundColour(osdBack);
118   osd.setPosition(0, video->getScreenHeight() - 150);
119   osd.setSize(video->getScreenWidth(), 150);
120   osd.setVisible(false);
121   add(&osd);
122   
123   clock.setBackgroundColour(osdBack);
124   clock.setPosition(osd.getWidth() - 100, 4);
125   clock.setSize(90, 30);
126   osd.add(&clock);
127
128   osdChanNum.setBackgroundColour(osdBack);
129   osdChanNum.setPosition(40, 4);
130   osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
131   osd.add(&osdChanNum);  
132
133   osdChanName.setBackgroundColour(osdBack);
134   osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
135   osdChanName.setSize(300, 30);
136   osd.add(&osdChanName);
137   
138   boxRed.setBackgroundColour(Colour::RED);
139   boxRed.setPosition(50, 104);
140   boxRed.setSize(18, 16);
141   osd.add(&boxRed);
142
143   boxGreen.setBackgroundColour(Colour::GREEN);
144   boxGreen.setPosition(220, 104);
145   boxGreen.setSize(18, 16);
146   osd.add(&boxGreen);
147
148   boxYellow.setBackgroundColour(Colour::YELLOW);
149   boxYellow.setPosition(390, 104);
150   boxYellow.setSize(18, 16);
151   osd.add(&boxYellow);
152
153   boxBlue.setBackgroundColour(Colour::BLUE);
154   boxBlue.setPosition(560, 104);
155   boxBlue.setSize(18, 16);
156   osd.add(&boxBlue);  
157   
158   textRed.setBackgroundColour(osdBack);
159   textRed.setPosition(boxRed.getX()+18, 98);
160   textRed.setSize(120, 30);
161   textRed.setText("Summary");
162   osd.add(&textRed);  
163     
164   if (streamType == VDR::VIDEO)
165   {
166     textGreen.setBackgroundColour(osdBack);
167     textGreen.setPosition(boxGreen.getX()+18, 98);
168     textGreen.setSize(120, 30);
169     textGreen.setText("Audio");
170     osd.add(&textGreen);  
171   }
172     
173   textYellow.setBackgroundColour(osdBack);
174   textYellow.setPosition(boxYellow.getX()+18, 98);
175   textYellow.setSize(120, 30);
176   textYellow.setText("");
177   osd.add(&textYellow);  
178     
179   textBlue.setBackgroundColour(osdBack);
180   textBlue.setPosition(boxBlue.getX()+18, 98);
181   textBlue.setSize(90, 30);
182   textBlue.setText("EPG");
183   osd.add(&textBlue);  
184     
185   sl.setBackgroundColour(osdBack);
186   sl.setPosition(70, 36);
187   sl.setSize(500, 58);
188   sl.setNoLoop();
189   osd.add(&sl);
190   
191   // Summary Box
192   summary.setBackgroundColour(osdBack);
193   summary.setPosition(0, video->getScreenHeight() - 300);
194   summary.setSize(video->getScreenWidth(), 150);
195   summary.setVisible(false);
196   add(&summary);  
197   
198   textSummary.setBackgroundColour(osdBack);
199   textSummary.setPosition(40, 10);
200   textSummary.setSize(video->getScreenWidth() - 80, 130);
201   textSummary.setParaMode(true);
202   summary.add(&textSummary);
203   
204   summaryBlackLine.setBackgroundColour(Colour::BLACK);
205   summaryBlackLine.setPosition(0, summary.getHeight() - 4);
206   summaryBlackLine.setSize(summary.getWidth(), 4);
207   summary.add(&summaryBlackLine);
208   
209   // FIXME painful
210   Region r1 = summary.getRegionR();
211   Region r2 = osd.getRegionR();
212   osdSummaryRegion = r1 + r2;
213 }
214
215 VVideoLiveTV::~VVideoLiveTV()
216 {
217   if (playing) stop();
218
219   delete player;
220   video->setDefaultAspect();
221   delData();
222 }
223
224 void VVideoLiveTV::delData()
225 {
226   if (eventList)
227   {
228     int eventListSize = eventList->size();
229     for(int i = 0; i < eventListSize; i++)
230     {
231       delete (*eventList)[i];
232     }
233     eventList->clear();
234     delete eventList;
235
236   }
237   sl.clear();
238 }
239
240 int VVideoLiveTV::handleCommand(int command)
241 {
242   switch(command)
243   {
244     case Remote::BACK:
245     {
246       if (osd.getVisible())
247       {
248         clearScreen();
249         return 2;
250       }
251       // else drop through to stop
252     }
253     case Remote::STOP:
254     {
255       stop();
256       vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
257       return 4;
258     }
259     case Remote::UP:
260     {
261       // New remote only
262       // epg data up
263       doUpDown(false);
264       return 2;
265     }
266     case Remote::DOWN:
267     {
268       // New remote only
269       // epg data down
270       doUpDown(true);
271       return 2;
272     }
273     case Remote::LEFT:
274     {
275       // New remote only
276       // epg data ch down
277       doLeftRight(false);
278       return 2;
279     }
280     case Remote::RIGHT:
281     {
282       // New remote only
283       // epg data ch up
284       doLeftRight(true);
285       return 2;
286     }
287     case Remote::DF_UP:
288     case Remote::CHANNELUP:
289     {
290       doChanUpDown(UP);
291       return 2;
292     }
293     case Remote::DF_DOWN:
294     case Remote::CHANNELDOWN:
295     {
296       doChanUpDown(DOWN);
297       return 2;
298     }
299     case Remote::PREVCHANNEL:
300     {
301       channelChange(PREVIOUS, 0);
302       return 2;
303     }
304     case Remote::OK:
305     {
306       doOK();
307       return 2;
308     }
309     case Remote::RED:
310     case Remote::MENU:
311     {
312       doSummary();
313       return 2;
314     }
315     case Remote::FULL:
316     case Remote::TV:
317     {
318       toggleChopSides();
319       return 2;
320     }
321
322     case Remote::ZERO:
323     case Remote::ONE:
324     case Remote::TWO:
325     case Remote::THREE:
326     case Remote::FOUR:
327     case Remote::FIVE:
328     case Remote::SIX:
329     case Remote::SEVEN:
330     case Remote::EIGHT:
331     case Remote::NINE:
332     {
333       // key in channel number
334       doKey(command);
335       return 2;
336     }
337
338     case Remote::GREEN:
339     {
340       if (streamType == VDR::VIDEO) doAudioSelector();
341       return 2;   
342     }
343     case Remote::YELLOW:
344     {
345       return 2;
346     }
347     case Remote::GUIDE:
348     case Remote::BLUE:
349     {
350       doEPG();
351       return 2;
352     }
353   }
354
355   return 1;
356 }
357
358 void VVideoLiveTV::go()
359 {
360   playing = true;
361   draw();
362   boxstack->update(this);
363
364   setClock();
365   displayOSD(true);
366   
367   player->go(currentChannelIndex);
368 }
369
370 void VVideoLiveTV::stop()
371 {
372   Timers::getInstance()->cancelTimer(this, 1);
373   Timers::getInstance()->cancelTimer(this, 2);
374   player->stop();
375   playing = false;
376 }
377
378 void VVideoLiveTV::doLeftRight(bool right)
379 {
380   if (osd.getVisible())
381   {
382     if (right) osdChannelIndex = upChannel(osdChannelIndex);
383     else       osdChannelIndex = downChannel(osdChannelIndex);
384   }
385   else
386   {
387     osdChannelIndex = currentChannelIndex;
388   }
389   displayOSD(true);
390 }
391
392 void VVideoLiveTV::doUpDown(bool down)
393 {
394   if (osd.getVisible())
395   {
396     if (down) sl.down();
397     else      sl.up();
398     sl.draw();
399     
400     displayOSD(false);
401   }
402   else
403   {
404     displayOSD(true);
405   }
406 }
407
408 void VVideoLiveTV::doChanUpDown(int which)
409 {
410   channelChange(OFFSET, which);
411   osdChannelIndex = currentChannelIndex;
412   displayOSD(true);
413 }
414
415 void VVideoLiveTV::doOK()
416 {
417   if (osd.getVisible())
418   {
419     if (keying)
420     {
421       UINT newChannel = 0;
422       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
423       
424       channelChange(NUMBER, newChannel);
425       osdChannelIndex = currentChannelIndex;
426       displayOSD(true);
427     }
428     else if (osdChannelIndex == currentChannelIndex)
429     {
430       clearScreen();
431     }
432     else
433     {
434       channelChange(INDEX, osdChannelIndex);
435       displayOSD(true);
436     }
437   }
438   else
439   {
440     osdChannelIndex = currentChannelIndex;
441     displayOSD(true);
442   }
443 }
444
445 void VVideoLiveTV::doSummary()
446 {
447   if (summary.getVisible())
448   {
449     summary.setVisible(false);
450     draw();
451     boxstack->update(this, summary.getRegion());
452     Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
453     return;
454   }
455
456   summary.setVisible(true);
457
458   if (osd.getVisible())
459   {
460     Timers::getInstance()->cancelTimer(this, 1);
461     displayOSD(false);
462   }
463   else
464   {
465     displayOSD(true);
466   }
467 }
468
469 void VVideoLiveTV::doKey(int command)
470 {
471   if (!osd.getVisible()) // First key. prep the data
472   {
473     setNowNextData();
474     keying = 0;    
475   }
476
477   int i;
478   for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
479   keyingInput[0] = command;
480   keying++;
481
482   char* keyingString = new char[numberWidth + 1];
483   for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
484   keyingString[numberWidth] = '\0';
485
486   for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
487   
488   if (keying == numberWidth)
489   {
490     UINT newChannel = 0;
491     for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
492     
493     channelChange(NUMBER, newChannel);
494     osdChannelIndex = currentChannelIndex;
495     Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
496     displayOSD(true); // this will put one back if required
497   }
498   else
499   {
500     osdChanNum.setText(keyingString);
501
502     if (!osd.getVisible())
503     {
504       osd.setVisible(true);
505       draw();
506     }
507     else
508     {
509       osdChanNum.draw();
510     }
511     boxstack->update(this, osd.getRegion());
512     Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
513   }
514   delete[] keyingString;
515 }
516
517 void VVideoLiveTV::doAudioSelector()
518 {
519   // If the osd is already visisble there might be a timer for it
520   Timers::getInstance()->cancelTimer(this, 1);
521
522   // Cancel keying
523   if (keying)
524   {
525     keying = 0;
526     // and reset the display - this is a copy from setNowNextData
527     char formatChanNum[20];
528     SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
529     osdChanNum.setText(formatChanNum);
530     osdChanName.setText((*chanList)[osdChannelIndex]->name);
531   }
532
533   // Draw the selector
534   vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel());
535   Colour osdBack = Colour(0, 0, 0, 128);
536   vas->setBackgroundColour(osdBack);
537   vas->setPosition(0, osd.getScreenY() - vas->getHeight());
538   vas->draw();
539
540   // make vas != null and displayOSD will not set a timer or do any boxstack update
541   summary.setVisible(false);
542   if (osd.getVisible()) displayOSD(false);
543   else displayOSD(true);
544   draw();
545
546   BoxStack::getInstance()->add(vas);
547   BoxStack::getInstance()->update(this);        
548   BoxStack::getInstance()->update(vas);     
549 }      
550       
551 void VVideoLiveTV::doEPG()
552 {
553   if (osd.getVisible()) clearScreen();
554
555   video->setMode(Video::QUARTER);
556   video->setPosition(170, 5); //TODO need to deal with 4:3 switching
557
558   VEpg* vepg = new VEpg(this, currentChannelIndex, VDR::VIDEO);
559   vepg->draw();
560   boxstack->add(vepg);
561   boxstack->update(vepg);
562 }
563
564 void VVideoLiveTV::setNowNextData()
565 {
566   delData();
567   
568   Channel* currentChannel = (*chanList)[osdChannelIndex];
569
570   char formatChanNum[20];
571   SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
572   osdChanNum.setText(formatChanNum);
573   osdChanName.setText(currentChannel->name);
574
575   eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
576
577   if (!eventList)
578   {
579     sl.addOption(tr("No channel data available"), 0, 1);
580   }
581   else
582   {
583     sort(eventList->begin(), eventList->end(), EventSorter());
584
585     char tempString[300];
586     char tempString2[300];
587     struct tm* btime;
588     Event* event;
589     int eventListSize = eventList->size();
590     for(int i = 0; i < eventListSize; i++)
591     {
592       event = (*eventList)[i];
593
594       //btime = localtime((time_t*)&event->time);
595       time_t etime = event->time;
596       btime = localtime(&etime);
597 #ifndef _MSC_VER
598       strftime(tempString2, 299, "%0H:%0M ", btime);
599 #else
600       strftime(tempString2, 299, "%H:%M ", btime);
601 #endif
602       SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
603       
604       sl.addOption(tempString, (ULONG)event, (i==0));
605     }
606   }
607 }
608
609 void VVideoLiveTV::setSummaryData()
610 {
611   // If osd is not being displayed, sl will be filled with now, current channel
612   // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
613   Event* selectedEvent = (Event*)sl.getCurrentOptionData();
614   
615   if (!selectedEvent)
616   {
617     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  
618     textSummary.setText(tr("No summary available"));
619   }
620   else
621   {
622     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  
623     textSummary.setText(selectedEvent->description);
624   }
625 }
626
627 void VVideoLiveTV::displayOSD(bool newNowNextData)
628 {
629   osd.setVisible(true);
630   if (newNowNextData)
631   {
632     setNowNextData();
633     keying = 0;  
634   }
635   osd.draw();
636   
637   if (summary.getVisible())
638   {
639     setSummaryData();
640     summary.draw();
641     boxstack->update(this, &osdSummaryRegion);
642   }
643   else if (!vas)
644   {
645     boxstack->update(this, osd.getRegion());
646     Timers::getInstance()->setTimerD(this, 1, 4);
647   }
648 }
649
650 void VVideoLiveTV::clearScreen()
651 {  
652   if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
653
654   osd.setVisible(false);
655
656   if (summary.getVisible())
657   {
658     summary.setVisible(false);
659     draw();
660     boxstack->update(this, &osdSummaryRegion);
661   }
662   else
663   {
664     draw();
665     boxstack->update(this, osd.getRegion());
666   }
667 }
668
669 void VVideoLiveTV::setClock()
670 {
671   char timeString[20];
672   time_t t;
673   time(&t);
674   struct tm* tms = localtime(&t);
675   strftime(timeString, 19, "%H:%M", tms);
676   clock.setText(timeString);
677
678   time_t dt = 60 - (t % 60);  // seconds to the next minute
679   if (dt == 0) dt = 60; // advance a whole minute if necessary
680   dt += t;  // get a time_t value for it rather than using duration
681   // (so it will occur at the actual second and not second and a half)
682
683   Timers::getInstance()->setTimerT(this, 2, dt);
684 }
685
686 void VVideoLiveTV::timercall(int ref)
687 {
688   if (ref == 1)
689   {
690     if (keying)
691     {
692       // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
693       
694       UINT newChannel = 0;
695       for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
696       
697       Message* m = new Message();
698       m->message = Message::CHANNEL_CHANGE;
699       m->to = this;
700       m->parameter = newChannel;
701       m->tag = 1; // signal to call displayOSD();
702       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
703     }
704     else
705     {
706       osd.setVisible(false);
707       draw();
708       Message* m = new Message();
709       m->message = Message::REDRAW;
710       m->to = BoxStack::getInstance();
711       m->from = this;
712       m->parameter = (ULONG)osd.getRegion();
713       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
714     }
715   }
716   else if (ref == 2)
717   {
718     setClock();
719     if (osd.getVisible())
720     {
721       clock.draw();
722       Message* m = new Message();
723       m->message = Message::REDRAW;
724       m->to = BoxStack::getInstance();
725       m->from = this;
726       m->parameter = (ULONG)osd.getRegion();
727       Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.    
728     }
729   }
730 }
731
732 bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
733 {
734   UINT newChannel = 0;
735
736   if (changeType == INDEX)
737   {
738     newChannel = newData;
739   }
740   else if (changeType == NUMBER)
741   {
742     UINT i;
743     for(i = 0; i < chanList->size(); i++)
744     {
745       if ((*chanList)[i]->number == (UINT)newData)
746       {
747         newChannel = i;
748         break;
749       }
750     }
751
752     if (i == chanList->size())
753     {
754       // no such channel
755       return false;
756     }
757   }
758   else if (changeType == OFFSET)
759   {
760     if (newData == UP) newChannel = upChannel(currentChannelIndex);
761     else newChannel = downChannel(currentChannelIndex);
762   }
763   else if (changeType == PREVIOUS)
764   {
765     newChannel = previousChannelIndex;
766   }
767   else
768   {
769     return false; // bad input
770   }
771
772   if (newChannel == currentChannelIndex) return true;
773
774   previousChannelIndex = currentChannelIndex;
775   currentChannelIndex = newChannel;
776   
777   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
778   player->setChannel(currentChannelIndex);
779   Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
780
781   return true;
782 }
783
784 void VVideoLiveTV::processMessage(Message* m)
785 {
786   if (m->message == Message::MOUSE_LBDOWN)
787   {
788     //check if press is outside this view! then simulate cancel
789     int x=(m->parameter>>16)-osd.getScreenX();
790     int y=(m->parameter&0xFFFF)-osd.getScreenY();
791     if (osd.getVisible()) {
792     
793         if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
794             (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
795             BoxStack::getInstance()->handleCommand(Remote::RED);
796         } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
797             (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
798             BoxStack::getInstance()->handleCommand(Remote::GREEN);
799         } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
800             (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
801             BoxStack::getInstance()->handleCommand(Remote::YELLOW);
802         } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
803             (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
804             BoxStack::getInstance()->handleCommand(Remote::BLUE);
805         } else {
806             BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
807         }
808
809     } else {
810         BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
811     }
812   }
813   else if (m->message == Message::CHANNEL_CHANGE)
814   {
815     channelChange(NUMBER, m->parameter);
816     osdChannelIndex = currentChannelIndex;
817     if (m->tag == 1) displayOSD(true);
818   }
819   else if (m->message == Message::EPG_CLOSE)
820   {
821     video->setMode(videoMode);
822   }
823   else if (m->message == Message::CHILD_CLOSE)
824   {
825     if (m->from == vas)
826     {
827       vas = NULL;
828       displayOSD(false);
829     }
830   }
831   else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
832   {
833     Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
834     player->setAudioChannel(m->parameter);
835   }
836   else if (m->message == Message::PLAYER_EVENT)
837   {
838     switch(m->parameter)
839     {
840       case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
841       {
842         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
843         // I can't handle this, send it to command
844         Message* m2 = new Message();
845         m2->to = Command::getInstance();
846         m2->message = Message::CONNECTION_LOST;
847         Command::getInstance()->postMessageNoLock(m2);
848         break;
849       }
850       
851       /*
852       case PlayerLiveTV::STREAM_END:
853       {
854         // I can't handle this, send it to command - improve this
855         Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
856         m2->to = Command::getInstance();
857         m2->message = Message::STREAM_END;
858         Command::getInstance()->postMessageNoLock(m2);
859         break;
860       }
861       */
862       
863       case PlayerLiveTV::ASPECT43:
864       {
865         if (dowss)
866         {
867           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
868           wss.setWide(false);
869           wss.draw();
870           BoxStack::getInstance()->update(this, &wssRegion);
871         }
872         break;
873       }
874       case PlayerLiveTV::ASPECT169:
875       {
876         if (dowss)
877         {
878           Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
879           wss.setWide(true);
880           wss.draw();
881           BoxStack::getInstance()->update(this, &wssRegion);
882         }
883         break;
884       }
885     }
886   }
887 }
888
889 UINT VVideoLiveTV::upChannel(UINT index)
890 {
891   if (index == (chanList->size() - 1)) // at the end
892     return 0; // so go to start
893   else
894     return index + 1;
895 }
896
897 UINT VVideoLiveTV::downChannel(UINT index)
898 {
899   if (index == 0) // at the start
900     return chanList->size() - 1; // so go to end
901   else
902     return index - 1;
903 }
904
905 void VVideoLiveTV::toggleChopSides()
906 {
907   if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
908
909   if (videoMode == Video::NORMAL)
910   {
911     videoMode = Video::LETTERBOX;
912     video->setMode(Video::LETTERBOX);
913   }
914   else
915   {
916     videoMode = Video::NORMAL;
917     video->setMode(Video::NORMAL);
918   }
919 }
920