]> git.vomp.tv Git - vompclient.git/blob - vmediaview.cc
Teletext
[vompclient.git] / vmediaview.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
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 <time.h>
22
23 #include "vmediaview.h"
24
25 #include "vpicturebanner.h"
26 #include "vcolourtuner.h"
27 #include "audioplayer.h"
28 #include "timers.h"
29 #include "boxx.h"
30 #include "wselectlist.h"
31 #include "remote.h"
32 #include "wsymbol.h"
33 #include "boxstack.h"
34 #include "vdr.h"
35 #include "media.h"
36 #include "video.h"
37 #include "vinfo.h"
38 #include "i18n.h"
39 #include "message.h"
40 #include "command.h"
41 #include "mediaoptions.h"
42 #include "mediaplayer.h"
43 #include "log.h"
44
45 /**
46   * the combined user interface for pictures and audio
47   * has 2 surfaces to enable drawing in a separate thread
48   * the info display can either show a picture info or and audio info
49   * if the audio player comes on top it disables the picture info display
50   * basically we have 3 modes:
51   *   - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)
52   *     if justPlaying=true the audioplayer is still running
53   *   - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false
54   *     no AudioBanner visible
55   *     if justPlaying=true the audio player runs in bg
56   *   - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true
57   *     the picture viewer is currently halted (should be able to continue if no AudioInfo)
58   *     no picture banner (we should have an audio banner to indicate the audio player on top!)
59   * state transitions (via setPictureMode, setAudioMode)
60   *   - show Picture -> pictureEnabled=true, 
61   *     only called from command handler if audioEnabled=false
62   *     call from mediaList only possible if audioEnabled=false
63   *         *** TODO: would be better to have separate function for external call/internal call
64   *   - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)
65   *                     used for calls from medialist
66   *                     internal calls do not set activate!
67   *   - YELLOW key - toggle
68   *     if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)
69   *     if audioActive==false -> audioActive=true (new mode AUDIO)
70   *          *** open handling if no audio file there (ignore key???) - currently empty player
71   *   - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false
72   *   - BACK if mode PICTURE -> pictureEnabled=false;
73   *   - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)
74   * info/banner handling:
75   *   - AudioInfo - alternativ to pictureInfo
76   *     off when disabling audio or after timer or with OK in AUDIO mode
77   *     on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true
78   *     on on OK in AUDIO mode
79   *   - Picture Info
80   *     off when disabling Picture or after timer, OK, green
81   *     on only on green when pictureEnabled==true
82   *   - PictureBanner
83   *     2 modes: loading/normal
84   *       normal:
85   *       off when disabling picture, OK, after timer
86   *       on when enabling picture, with OK
87   *       loading:
88   *       off when disabling picture and when loading done
89   *       on on start loading
90   *          *** open: do not show when audio enabled and slide show running (currently slideshow is paused)
91   *   - AudioBanner
92   *       always shown when audioEnabled=true
93   *       on when enabling Audio
94   *       off when disabling audio
95   *       update in play
96   * timers: 1 - slide show
97   *         2 - pictureBanner
98   *         3 - info showtime
99   *         4 - audio short update
100   */
101
102 #define DRAWING_THREAD
103
104 Colour VMediaView::pictureBack=Colour(140,140,140);
105 Colour VMediaView::infoBack=Colour(110,110,110);
106 Colour VMediaView::audioBannerBack=Colour(110,110,110,20);
107 //the jpeg reader
108
109 //how long do we wait for a single picture chunk
110 //the unit is 100ms (the timeout on the server side)
111 #define MAXTRY 100 
112 class VPreader : public JpegReader {
113   private:
114     ImageReader *reader;
115     VMediaView * parent;
116     ULLONG size;
117     bool dobreak;;
118   public:
119   VPreader(VMediaView *p,ImageReader *r){ 
120     parent=p;
121     size=0;
122     reader=r;
123     dobreak=false;
124   };
125   virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
126      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
127         offset,len,*buf);
128      UINT numrec=0;
129      int rt=0;
130      for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {
131        if (dobreak) {
132          *buf=NULL;
133          rt=-1;
134        }
135        else {
136          rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);
137        }
138      }
139      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",
140         numrec,*buf,rt);
141      return numrec;
142      }
143   virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {
144      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());
145      Video* video = Video::getInstance();
146      dobreak=false;
147      int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);
148      if (rt < 0) *sz=0;
149      size=*sz;
150      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);
151      return rt;
152      }
153   virtual ULONG getSize() {return size;}
154   //seems to be thread safe (more or less...)
155   void setBreak() {
156     dobreak=true;
157   }
158 };
159
160 /**
161   * a separate thread for drawing pictures
162   * will be started with the sfc and the draw control
163   * will send a player event when done
164   */
165 class DrawingThread : public Thread_TYPE {
166   private:
167     VMediaView *_parent;
168     VPreader * _reader;
169     WJpeg::JpegControl *_ctl;
170     Surface *_sfc;
171     Colour _colour;
172     bool _interrupted;
173   public:
174     DrawingThread(VMediaView *parent) {
175       _parent=parent;
176       _reader=NULL;
177       _ctl=NULL;
178       _sfc=NULL;
179       _interrupted=false;
180     }
181     virtual ~DrawingThread(){}
182     bool isRunning() {
183       return (threadIsActive()!=0);
184     }
185     bool start(WJpeg::JpegControl *ctl,Surface *sfc,VPreader *reader,Colour &c) {
186       if (isRunning()) {
187         return false;
188       }
189       _interrupted=false;
190       _ctl=ctl;
191       _sfc=sfc;
192       _reader=reader;
193       _colour=c;
194       return (threadStart() == 1);
195     }
196     bool stop() {
197       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");
198       if (threadIsActive()) {
199         _interrupted=true;
200         if (_reader) _reader->setBreak();
201         threadStop();
202       }
203       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");
204       _reader=NULL;
205       return true;
206     }
207   protected:
208     virtual void threadMethod() {
209       Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");
210       bool rt=WJpeg::drawJpeg(_ctl,_sfc,_reader,_colour);
211       _reader=NULL;
212       if (! _interrupted) {
213         Message* m = new Message(); 
214         //we misuse PLAYER_EVENT here
215         m->message = Message::PLAYER_EVENT;
216         m->to = _parent;
217         m->from = _parent;
218         m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;
219         Command::getInstance()->postMessageFromOuterSpace(m);
220       }
221       Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);
222     }
223     virtual void threadPostStopCleanup() {}
224
225 };
226
227
228 VMediaView::VMediaView(VMediaList *p)
229 {
230   Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);
231   audioEnabled=false;
232   pictureEnabled=false;
233   parent=p;
234   ireader=new ImageReader(1,MediaPlayer::getInstance());
235   reader=new VPreader(this,ireader);
236   //the surface handling
237   Video* video = Video::getInstance();
238   setSize(video->getScreenWidth(), video->getScreenHeight());
239   createBuffer();
240   sfc2=getSurface();
241   surface=NULL;
242   //create the second surface
243   createBuffer();
244   sfc1=getSurface();
245   originalh=area.h;
246   originalw=area.w;
247   //disable the surface
248   area.h=1;
249   area.w=1;
250   //banners and infos
251   pictureBanner=NULL;
252   slideshow=false;
253   pictureError=NULL;
254   currentPicture=NULL;
255   info=NULL;
256   pictureLoading=false;
257
258   //picture settings
259   showtime=INITIAL_SHOWTIME;
260   rotate=WJpeg::ROT_0;
261   currentScale=1;
262   options=MediaOptions::getInstance();
263   VColourTuner::initFactors();
264   int st=options->getIntOption("SlideShowInterval");
265   if (st > 0) showtime=st;
266   ctl.area.w=originalw;
267   ctl.area.h=originalh;
268   ctl.enlarge=false;
269   ctl.scaleafter=options->getIntOption("ScaleFactor");
270   const char * mode=options->getStringOption("PictureMode");
271   if (strcmp(mode,"clip") == 0) ctl.mode=WJpeg::CROP;
272   else if (strcmp(mode,"letter") == 0) ctl.mode=WJpeg::LETTER;
273   else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpeg::CROPPERCENT;
274   ctl.scaleAmount=options->getIntOption("PictureSize");
275   if (ctl.scaleAmount < 10) ctl.scaleAmount=10;
276   if (ctl.scaleAmount > 200) ctl.scaleAmount=200;
277   ctl2=ctl;
278   cropmode=ctl.mode;
279   //current control is the one used for DISPLAY (not the one for drawing - this is the other one)
280   //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2
281   currentControl=&ctl;
282   bannerEnabled=true;
283   pictureShowing=false;
284
285   //audio player
286
287   barBlue.set(0, 0, 150, 150);
288   audioError=NULL;
289   currentAudio=NULL;
290   justPlaying=false;
291   playall=false;
292   retriggerAudioInfo=false;
293   audioBanner=NULL;
294   drawingThread=new DrawingThread(this);
295 }
296
297 VMediaView::~VMediaView()
298 {
299   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));
300   destroyPictureBanner();
301   if (currentPicture) delete currentPicture;
302   Timers::getInstance()->cancelTimer(this,1);
303   Timers::getInstance()->cancelTimer(this,2);
304   Timers::getInstance()->cancelTimer(this,3);
305   Timers::getInstance()->cancelTimer(this,4);
306   Timers::getInstance()->cancelTimer(this,5);
307   destroyInfo();
308   destroyAudioBanner();
309   if (getPlayer(false)) {
310     AudioPlayer::getInstance(NULL,false)->shutdown();
311   }
312   if (currentAudio) delete currentAudio;
313   drawingThread->stop();
314   ireader->shutdown();
315   delete ireader;
316   delete reader;
317   if (secondSurface()) {
318     delete sfc1;
319     sfc1=NULL;
320   }
321   else {
322     delete sfc2;
323     sfc2=NULL;
324   }
325   MediaPlayer::getInstance()->closeMediaChannel(1);
326   MediaPlayer::getInstance()->closeMediaChannel(2);
327   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);
328 }
329
330 void VMediaView::setPictureMode(bool act) {
331   Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
332   if ( act) {
333     if ( ! pictureEnabled && ! audioEnabled) {
334       area.h=originalh;
335       area.w=originalw;
336       showPictureBanner();
337       parent->updateAll();
338     }
339     if (! pictureEnabled) {
340       //we newly enable the picture - so clear the screen
341       draw();
342       BoxStack::getInstance()->update(this);
343       if (slideshow) startSlideshow();
344     }
345   }
346   else 
347   {
348     if ( pictureEnabled) {
349       destroyPictureBanner();
350       stopSlideshow(false);
351 #ifdef DRAWING_THREAD
352       drawingThread->stop();
353 #endif
354       if (! audioEnabled) {
355         destroyInfo();
356         area.w=1;
357         area.h=1;
358         draw();
359         parent->updateAll();
360       }
361     }
362     pictureShowing=false;
363   }
364   pictureEnabled=act;
365 }
366
367 //we can disable audio without automatically hiding us
368 //this will become strange - we are visible but do not handle
369 //keys - so if you call setAudioMode(false,false) be sure
370 //to call setAudioMode(false,true) afterwards
371 //it is only here to give the list a chance to start a new play
372 //when we call directoryDone
373 void VMediaView::setAudioMode(bool act,bool doHiding) {
374   Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode  %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);
375   if ( act) {
376     if (! audioEnabled) {
377       if (! pictureEnabled) {
378         area.w=originalw;
379         area.h=originalh;
380         draw(); //empty screen if no picture
381         parent->updateAll();
382       }
383       destroyPictureBanner();
384
385     }
386     audioEnabled=true;
387     showAudioBanner();
388     showAudioInfo();
389   }
390   else 
391   {
392     if ( audioEnabled) {
393       audioEnabled=false;
394       destroyInfo();
395       destroyAudioBanner();
396     }
397     if (! pictureEnabled  && doHiding) {
398       area.w=1;
399       area.h=1;
400       draw();
401       parent->updateAll();
402     }
403     else {
404       //picture now on top
405       if (havePictureBanner && ! pictureBanner) showPictureBanner();
406     }
407   }
408 }
409
410
411
412 void VMediaView::draw()
413 {
414   Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);
415   
416   if (pictureShowing ) fillColour(pictureBack);
417   else fillColour(Colour::BLACK);
418   if (pictureError) {
419     drawText(pictureError,100,area.h/2,Colour::LIGHTTEXT);
420     return;
421     }
422 }
423
424
425 int VMediaView::handleCommand(int command)
426 {
427   Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);
428   if ( !audioEnabled && ! pictureEnabled ) {
429     //only handle YELLOW
430     if (command == Remote::YELLOW) {
431       setAudioMode(true);
432       return 1;
433     }
434     return 0;
435   }
436   if ( ! audioEnabled) {
437     //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------
438     //picture on top
439     int rt=1;
440     switch(command)
441     {
442       case Remote::DF_UP:
443       case Remote::UP:
444       case Remote::SKIPBACK:
445         rotate=WJpeg::ROT_0;
446         showPicture(VMediaList::MV_PREV,slideshow,true);
447         rt= 2;
448         break;
449       case Remote::FORWARD:
450         if (showtime > 1) showtime--;
451         updatePictureBanner(true);
452         break;
453       case Remote::DF_DOWN:
454       case Remote::DOWN:
455       case Remote::SKIPFORWARD:
456         rotate=WJpeg::ROT_0;
457         showPicture(VMediaList::MV_NEXT,slideshow,true);
458         rt= 2;
459         break;
460       case Remote::REVERSE:
461         if (showtime < 50 ) showtime++;
462         updatePictureBanner(true);
463         break;
464       case Remote::OK:
465       {
466         if (pictureBanner) {
467           destroyPictureBanner();
468           destroyInfo();
469           havePictureBanner=false;
470           }
471         else {
472           havePictureBanner=true;
473           showPictureBanner(pictureLoading);
474         }
475         rt= 2;
476       }
477       break;
478       case Remote::PLAY:
479       {
480         slideshow=true;
481         rotate=WJpeg::ROT_0;
482         showPicture(VMediaList::MV_NEXT,slideshow,true);
483         rt= 2;
484       }
485       break;
486       case Remote::PAUSE:
487         if (slideshow) {
488           stopSlideshow(true);
489           updatePictureBanner();
490         }
491         else {
492           slideshow=true;
493           rotate=WJpeg::ROT_0;
494           showPicture(VMediaList::MV_NEXT,slideshow,true);
495         }
496         rt= 2;
497         break;
498       case Remote::STOP:
499         stopSlideshow(true);
500         showtime=INITIAL_SHOWTIME;
501         updatePictureBanner();
502         rt= 2;
503         break;
504       case Remote::RED:
505         switch(rotate) {
506           case WJpeg::ROT_0:
507             rotate=WJpeg::ROT_90;
508             break;
509           case WJpeg::ROT_90:
510             rotate=WJpeg::ROT_180;
511             break;
512           case WJpeg::ROT_180:
513             rotate=WJpeg::ROT_270;
514             break;
515           case WJpeg::ROT_270:
516             rotate=WJpeg::ROT_0;
517             break;
518           }
519         showPicture(VMediaList::MV_NONE,slideshow,true);
520         rt=2;
521         break;
522       case Remote::GREEN:
523         if (info) destroyInfo();
524         else showPictureInfo();
525         rt=2;
526         break;
527       case Remote::BLUE:
528         switch (cropmode) {
529           case WJpeg::CROP:
530             cropmode=WJpeg::LETTER;
531             break;
532           case WJpeg::LETTER:
533             cropmode=WJpeg::CROPPERCENT;
534             break;
535           default:
536             cropmode=WJpeg::CROP;
537             break;
538         }
539         showPicture(VMediaList::MV_NONE,slideshow,true);
540         rt=2;
541         break;
542       case Remote::MENU: {
543         stopSlideshow(true);
544         destroyPictureBanner();
545         destroyInfo();
546         VColourTuner *ct=new VColourTuner();
547         BoxStack::getInstance()->add(ct);
548         ct->draw();
549         BoxStack::getInstance()->update(ct);
550         rt=2;
551        
552                          } break;
553       case Remote::BACK:
554       {
555         setPictureMode(false);
556         rt= 2;
557       }
558       break;
559       case Remote::YELLOW:
560       {
561         setAudioMode(true);
562       }
563     }
564     return rt;
565   } 
566   else 
567   {
568     int rt=1;
569     bool updateInfo=false;
570     //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------
571     switch(command)
572     {
573       case Remote::YELLOW:
574         setAudioMode(false);
575         rt=2;
576         break;
577       case Remote::DF_UP:
578       case Remote::UP:
579         play(playall,false,VMediaList::MV_PREV);
580         rt= 2;
581         break;
582       case Remote::FORWARD:
583         if (! audioError) getPlayer()->fastForward();
584         updateInfo=true;
585         rt=2;
586         break;
587       case Remote::DF_DOWN:
588       case Remote::DOWN:
589         play(playall,false,VMediaList::MV_NEXT);
590         rt= 2;
591         break;
592       case Remote::SKIPFORWARD:
593         if (! audioError) getPlayer()->skipForward(10);
594         rt=2;
595         break;
596       case Remote::SKIPBACK:
597         if (! audioError) getPlayer()->skipBackward(10);
598         rt=2;
599         break;
600       case Remote::REVERSE:
601         rt=2;
602         break;
603       case Remote::ZERO:
604         if (! audioError) getPlayer()->jumpToPercent(0);
605         rt=2;
606         break;
607       case Remote::ONE:
608         if (! audioError) getPlayer()->jumpToPercent(10);
609         rt=2;
610         break;
611       case Remote::TWO:
612         if (! audioError) getPlayer()->jumpToPercent(20);
613         rt=2;
614         break;
615       case Remote::THREE:
616         if (! audioError) getPlayer()->jumpToPercent(30);
617         rt=2;
618         break;
619       case Remote::FOUR:
620         if (! audioError) getPlayer()->jumpToPercent(40);
621         rt=2;
622         break;
623       case Remote::FIVE:
624         if (! audioError) getPlayer()->jumpToPercent(50);
625         rt=2;
626         break;
627       case Remote::SIX:
628         if (! audioError) getPlayer()->jumpToPercent(60);
629         rt=2;
630         break;
631       case Remote::SEVEN:
632         if (! audioError) getPlayer()->jumpToPercent(70);
633         rt=2;
634         break;
635       case Remote::EIGHT:
636         if (! audioError) getPlayer()->jumpToPercent(80);
637         rt=2;
638         break;
639       case Remote::NINE:
640         if (! audioError) getPlayer()->jumpToPercent(90);
641         rt=2;
642         break;
643       case Remote::OK:
644       case Remote::GREEN:
645       {
646         if (info) {
647           destroyInfo();
648           retriggerAudioInfo=false;
649           }
650         else {
651           retriggerAudioInfo=true;
652           showAudioInfo();
653         }
654         if (getPlayer()->getState() == AudioPlayer::S_ERROR) {
655           if (playall) play(playall,false,VMediaList::MV_NEXT);
656         }
657         rt= 2;
658       }
659       break;
660       case Remote::PLAY:
661       {
662         if (! audioError) getPlayer()->unpause();
663         updateInfo=true;
664         if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;
665         else if (playall) play(playall,false,VMediaList::MV_NEXT);
666         rt= 2;
667       }
668       break;
669       case Remote::PAUSE:
670         if (! audioError) getPlayer()->pause();
671         updateInfo=true;
672         rt= 2;
673         break;
674       case Remote::STOP:
675         getPlayer()->stop();
676         justPlaying=false;
677         updateInfo=true;
678         rt= 2;
679         break;
680       case Remote::BACK:
681       {
682         getPlayer()->stop();
683         playall=false;
684         retriggerAudioInfo=false;
685         justPlaying=false;
686         setAudioMode(false);
687         if (! pictureShowing) setPictureMode(false); //could have been delayed
688         rt= 2;
689       }
690       break;
691     }
692     if (audioEnabled && updateInfo) updateAudioInfo();
693     return rt;
694   }
695 }
696
697 void VMediaView::processMessage(Message* m)
698 {
699   Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);
700   if (m->message == Message::MOUSE_MOVE)
701   {
702     ;
703   }
704   else if (m->message == Message::MOUSE_LBDOWN)
705   {
706     
707     //check if press is outside this view! then simulate cancel
708     int x=(m->parameter>>16)-getScreenX();
709     int y=(m->parameter&0xFFFF)-getScreenY();
710     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
711     {
712       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
713     }
714   }
715   else if (m->message = Message::PLAYER_EVENT) {
716     switch (m->parameter) {
717       case EVENT_SLIDESHOW:
718         if (! pictureEnabled) break; //old timer msg...
719         //if (! audioEnabled) {
720         if (true) {
721           if (slideshow) {
722             rotate=WJpeg::ROT_0;
723             showPicture(VMediaList::MV_NEXT,true,false);
724             startSlideshow();
725           }
726         }
727         break;
728       case EVENT_DRAWINGERROR:
729         drawingDone(true);
730         break;
731       case EVENT_DRAWINGDONE:
732         drawingDone(false);
733         break;
734       case EVENT_DIRECTORYDONE:
735         //just disable audio without (poetntially) hiding us
736         //this gives the list a chance to decide whether audio
737         //should be on top afterwards without showing the list
738         //immediately
739         setAudioMode(false,false);
740         parent->directoryDone();
741         if (! pictureShowing) setPictureMode(false);
742         if (! justPlaying) setAudioMode(false);
743         break;
744       case AudioPlayer::STREAM_ERR:
745       case AudioPlayer::STREAM_END:
746         if (playall) play(playall,false,VMediaList::MV_NEXT);
747         else {
748           setAudioMode(false);
749           justPlaying=false;
750         }
751         break;
752       case AudioPlayer::SHORT_UPDATE:
753                                 if (info && audioEnabled ) {
754                                         drawAudioClocks();
755                                         BoxStack::getInstance()->update(info,&clocksRegion);
756                                   BoxStack::getInstance()->update(info,&barRegion);
757                                         Timers::getInstance()->setTimerD(this, 4, 1);
758                                 }
759         break;
760       case AudioPlayer::NEW_SONG:
761         if (audioEnabled) updateAudioInfo();
762         break;
763       case AudioPlayer::CONNECTION_LOST:
764         if (audioEnabled) destroyInfo();
765         if (AudioPlayer *player=getPlayer(false)) {
766           player->shutdown();
767           player=NULL;
768         }
769         Command::getInstance()->connectionLost();
770         break;
771     }
772   }
773 }
774
775
776 VMediaView * VMediaView::createViewer(VMediaList * mparent) {
777    Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",
778         mparent);
779    VMediaView *vmn=new VMediaView(mparent);
780    BoxStack::getInstance()->add(vmn);
781    vmn->draw();
782    BoxStack::getInstance()->update(vmn);
783    return vmn;
784 }
785
786 void VMediaView::startSlideshow() {
787    slideshow=true;
788    if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);
789 }
790
791 void VMediaView::stopSlideshow(bool hard) {
792    if (hard) slideshow=false;
793    Timers::getInstance()->cancelTimer(this,1);
794 }
795
796
797 void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {
798   pictureShowing=true;
799   setPictureMode(true);
800   stopSlideshow(true);
801 #ifdef DRAWING_THREAD
802   drawingThread->stop();
803 #endif
804   slideshow=bslideshow;
805   Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);
806   if ( ! newPicture) {
807     pictureShowing=false;
808     if (!audioEnabled) {
809       //within the event handler first directoryDone is called
810       //and afterwards everything is stopped if nothing new
811       sendCommandMsg(EVENT_DIRECTORYDONE);
812     }
813     slideshow=false;
814   }
815   else 
816   {
817     pictureShowing=true;
818     if (currentPicture) {
819       delete currentPicture;
820       currentPicture=NULL;
821     }
822     currentPicture=newPicture;
823     loadPicture(currentPicture,activateBanner);
824   }
825 }
826
827 //the real picture drawing method
828 //will start drawing on a new surface and will switch it wehn done
829
830 int VMediaView::loadPicture(Media *md,bool activateBanner) {
831   pictureError=NULL;
832   if (! md) return 1;
833   if (! md->getURI()) {
834     pictureError=tr("No media found");
835     Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");
836     return 1;
837   }
838   Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
839         md->getURI()->getName(),this);
840   //do we have a pictureBanner?
841   havePictureBanner=pictureBanner!=NULL || activateBanner;
842   pictureLoading=true;
843 #ifdef DRAWING_THREAD
844   if (!audioEnabled && havePictureBanner ) showPictureBanner(true);
845   drawingThread->stop();
846 #else
847   showPictureBanner(true);
848 #endif
849   ireader->stop();
850   ULLONG size=0;
851   int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...
852   if (rtok == 0) {
853      //now we can really draw
854      //get the surface for drawing
855      Surface * drawSurface=NULL;
856      WJpeg::JpegControl *drawCtl=NULL;
857      getDrawingParam(drawSurface,drawCtl);
858      drawCtl->error[0]=0;
859      drawCtl->rotation=rotate;
860      drawCtl->mode=cropmode;
861      drawCtl->compressedSize=size;
862 #ifdef DRAWING_THREAD
863      bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);
864      if (! ok) {
865        Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");
866        pictureError=tr("JpegError");
867        pictureLoading=false;
868        destroyPictureBanner();
869        return 1;
870      }
871      return 0;
872 #else
873      //here we could hand this over to the drawing thread
874      bool ok=WJpeg::drawJpeg(drawCtl,drawSurface,reader,pictureBack);
875      drawingDone(!ok);
876      return ok?0:1;
877 #endif
878   }
879   pictureLoading=false;
880   return 1;
881 }
882
883 void VMediaView::drawingDone(bool hasError) {
884   pictureLoading=false;
885   destroyPictureBanner(); //disable loading indication (or real banner)
886   if (! hasError) {
887     switchSurface();
888     Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);
889     pictureError=NULL;
890     //only show the pictureBanner if it was there before
891     if (havePictureBanner && ! audioEnabled) showPictureBanner();
892     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );
893     updatePictureInfo(); //will only do somethng if pictureEnabled
894   }
895   else 
896   {
897     pictureError=tr("JpegError");
898     if (pictureEnabled) {
899       draw();
900       destroyInfo();
901     }
902   }
903   MediaPlayer::getInstance()->closeMediaChannel(1);
904 #ifndef DRAWING_THREAD
905   if (audioEnabled) showAudioBanner();
906 #endif
907   if (slideshow) startSlideshow();
908   BoxStack::getInstance()->update(this);
909 }
910
911 void VMediaView::showPictureBanner(bool loading) {
912   //we are in the main thread - so we can (and must) safely hard destroy/create the banner
913   Timers::getInstance()->cancelTimer(this,2);
914   if (! currentPicture) {
915     //hmm...
916     destroyPictureBanner(false);
917     return;
918     }
919   if (pictureBanner) destroyPictureBanner(false);
920   if (! pictureEnabled || ! bannerEnabled) return;
921   pictureBanner= new VPictureBanner(loading, slideshow);
922   pictureBanner->fillColour(infoBack);
923   if (! loading) {
924     int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;
925     char *buf=new char[len];
926     char tbuf[Media::TIMEBUFLEN];
927     SNPRINTF(buf,len,"%c%02ds%c %s %s " ,
928       slideshow?' ':'[',
929       showtime,
930       slideshow?' ':']',
931       currentPicture->getTimeString(tbuf),
932       currentPicture->getFileName()
933       );
934     pictureBanner->setText(buf);
935     delete [] buf;
936   }
937   else {
938     char *buf=new char[strlen(currentPicture->getDisplayName())+50];
939     SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());
940     pictureBanner->setText(buf);
941     delete buf;
942   }
943   pictureBanner->draw();
944   if (! loading )   Timers::getInstance()->setTimerD(this,2,8);
945   BoxStack::getInstance()->add(pictureBanner);
946   BoxStack::getInstance()->update(pictureBanner);
947   }
948
949 void VMediaView::destroyPictureBanner(bool fromTimer) {
950   if (pictureBanner) {
951     if (fromTimer) sendViewMsg(pictureBanner); 
952     else BoxStack::getInstance()->remove(pictureBanner);
953     pictureBanner=NULL;
954     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
955     }
956 }
957 void VMediaView::updatePictureBanner(bool loading) {
958   if (pictureBanner ) {
959     showPictureBanner(loading);
960     }
961 }
962 void VMediaView::timercall(int clientref) {
963    Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);
964    switch(clientref)
965    {
966       case 4:
967         {
968           sendCommandMsg(AudioPlayer::SHORT_UPDATE);
969           break;
970         }
971       case 3:
972         {
973           Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");
974           destroyInfo(true);
975           if (audioEnabled) {
976             //we only did show the audio error info if audio is enabled
977             bool stillError=false;
978             if (AudioPlayer * player=getPlayer(false)) {
979               stillError=player->getState()==AudioPlayer::S_ERROR;
980             }
981             if (stillError) {
982               sendCommandMsg(AudioPlayer::STREAM_END);
983             }
984           }
985           break;
986         }
987       case 1:
988         if (! slideshow) return;
989         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");
990         sendCommandMsg(EVENT_SLIDESHOW);
991         break;
992       case 2:
993         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");
994         destroyPictureBanner(true);
995         break;
996     }
997    
998   }
999
1000 #define INFOBUF 2000
1001 void VMediaView::showPictureInfo(){
1002   if (! pictureEnabled || audioEnabled) return;
1003   if (info) destroyInfo();
1004   if (! currentPicture) return;
1005
1006   info=new VInfo();
1007   info->setTitleText(currentPicture->getFileName());
1008   info->setDropThrough();
1009   info->setSize(500, 300);
1010   info->createBuffer();
1011   info->setBorderOn(1);
1012   info->setTitleBarOn(1);
1013
1014   if (Video::getInstance()->getFormat() == Video::PAL)
1015         info->setPosition(100, 180);
1016   else
1017         info->setPosition(100, 150);
1018   char buf[INFOBUF];
1019   char tbuf[Media::TIMEBUFLEN];
1020   //modes should come from mediaoptions...
1021   const char *mode=NULL;
1022   switch (currentControl->mode) {
1023     case WJpeg::CROPPERCENT:
1024       mode="clipfactor";
1025       break;
1026     case WJpeg::LETTER:
1027       mode="letter";
1028       break;
1029     default:
1030       mode="clip";
1031       break;
1032   }
1033   const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);
1034   int ldir=0;
1035   const char *prfx="";
1036   if (dirname) ldir=strlen(dirname);
1037   if (ldir > 35){
1038     dirname=dirname+ldir-35;
1039     prfx="...";
1040   }
1041   SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",
1042      tr("Directory"), prfx,dirname,
1043      tr("Format(px)"),currentControl->picw,currentControl->pich,
1044      tr("Filesize"),currentControl->compressedSize/1000,
1045      tr("Time"),currentPicture->getTimeString(tbuf),
1046      tr("Rotation"),90*currentControl->finalRotation,
1047      tr("Scale"),currentControl->scale,
1048      tr("Picture Mode"),mode );
1049   info->setMainText(buf);
1050   info->draw();
1051   BoxStack::getInstance()->add(info);
1052   BoxStack::getInstance()->update(info);
1053   Timers::getInstance()->setTimerD(this,3,8);
1054 }
1055 void VMediaView::updatePictureInfo(){
1056   if (info) {
1057     showPictureInfo();
1058     }
1059 }
1060 void VMediaView::destroyInfo(bool fromTimer){
1061   if (info) {
1062     if (! fromTimer) {
1063       Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);
1064       BoxStack::getInstance()->remove(info);
1065     }
1066     else {
1067       Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);
1068       sendViewMsg(info);
1069     }
1070     info=NULL;
1071     }
1072   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
1073   if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);
1074 }
1075
1076 void VMediaView::sendViewMsg(Boxx *v) {
1077   Message* m = new Message(); 
1078   m->message = Message::CLOSE_ME;
1079   m->to = BoxStack::getInstance();
1080   m->from = v;
1081   m->parameter=(ULONG)v;
1082   Command::getInstance()->postMessageFromOuterSpace(m);
1083 }
1084 void VMediaView::sendCommandMsg(int command) {
1085   Message* m = new Message(); 
1086   //we misuse PLAYER_EVENT here
1087   m->message = Message::PLAYER_EVENT;
1088   m->to = this;
1089   m->from = this;
1090   m->parameter= command;
1091   Command::getInstance()->postMessageFromOuterSpace(m);
1092 }
1093
1094 void VMediaView::enableBanner(bool enable) {
1095   bannerEnabled=false;
1096   updatePictureBanner();
1097 }
1098
1099 void VMediaView::getDrawingParam(Surface *&sfc,WJpeg::JpegControl *&c){
1100   if (secondSurface()) {
1101     //we currently display on sfc2
1102     sfc=sfc1;
1103     c=&ctl;
1104   }
1105   else {
1106     sfc=sfc2;
1107     c=&ctl2;
1108   }
1109 }
1110 void VMediaView::switchSurface(){
1111   if (secondSurface()) {
1112     //now we switch to sfc1
1113     surface=sfc1;
1114     currentControl=&ctl;
1115   }
1116   else {
1117     surface=sfc2;
1118     currentControl=&ctl2;
1119   }
1120 }
1121
1122 AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)
1123 {
1124   AudioPlayer* rt=AudioPlayer::getInstance(this,false);
1125   if (! createIfNeeded && rt == NULL) return NULL;
1126   if (rt == NULL) {
1127     rt=AudioPlayer::getInstance(this);
1128     rt->run();
1129   }
1130   return rt;
1131 }
1132
1133 bool VMediaView::isAudioPlaying() {
1134   Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");
1135   return justPlaying;
1136 }
1137
1138
1139
1140
1141
1142
1143 int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {
1144   int rt=0;
1145   if (getPlayer(false)) getPlayer(false)->stop();
1146   justPlaying=false;
1147   if (currentAudio) delete currentAudio;
1148   currentAudio=NULL;
1149   playall=all;
1150   currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);
1151   audioError=NULL;
1152   if ( ! currentAudio || ! currentAudio->getURI()) {
1153     Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");
1154     audioError=tr("no audio file");
1155     if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);
1156     rt= -1;
1157   }
1158   else {
1159     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",
1160       currentAudio->getURI()->getName(),this);
1161     int wseq=getPlayer()->play(currentAudio->getURI());
1162     if (getPlayer()->waitForSequence(5,wseq)<0) {
1163        audioError=tr("unable to open audio file");
1164        rt= -1;
1165     }
1166     else {
1167       justPlaying=true;
1168       rt=0;
1169     }
1170     Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());
1171   }
1172   if (activate && ! audioEnabled){
1173     if (showInfo) retriggerAudioInfo=true;
1174     setAudioMode(true);
1175   }
1176   else {
1177     //avoid duplicate creation of banner and info
1178     showAudioBanner();
1179     showAudioInfo();
1180   }
1181   if (activate && (! currentPicture || ! pictureShowing)) draw();
1182   BoxStack::getInstance()->update(this);
1183   return rt;
1184 }
1185
1186 void VMediaView::showAudioInfo() {
1187   if (! audioEnabled) return;
1188   Timers::getInstance()->cancelTimer(this,4);
1189   Timers::getInstance()->cancelTimer(this,3);
1190   if (info) destroyInfo();
1191   if (! retriggerAudioInfo) return;
1192   drawAudioInfo();
1193   bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;
1194   if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);
1195   else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);
1196         if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);
1197   BoxStack::getInstance()->update(info);
1198   }
1199
1200 void VMediaView::updateAudioInfo() {
1201   if (info) {
1202     showAudioInfo();
1203     }
1204 }
1205
1206 void VMediaView::drawAudioInfo(){
1207   Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);
1208   const char *title=NULL;
1209   char *playerTitle=NULL;
1210   bool playerError=false;
1211   int numlines=0;
1212   int len=0;
1213   int num=0;
1214   const char *pl=tr("Playlist");
1215   const char *first=NULL;
1216   char *playerInfo=NULL;
1217   if (audioError) {
1218     if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;
1219   }
1220   if (! currentAudio && ! audioError) audioError=tr("no audio file");
1221   if (audioError ) {
1222     title=tr("MediaError");
1223   }
1224   else {
1225     playerTitle=getPlayer()->getTitle();
1226     if (playerTitle) title=playerTitle;
1227     else title=currentAudio->getDisplayName();
1228     num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);
1229     playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;
1230     //1more line for long dirs
1231     numlines=playall?5:4;
1232   }
1233   if (playerError) {
1234     numlines=3;
1235     first=tr("Unable to play audio file");
1236     len=strlen(first)+3;
1237   }
1238   else if (audioError) {
1239     numlines=3;
1240     first=audioError;
1241     len=strlen(first)+3;
1242   }
1243   else {
1244     playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,Colour::LIGHTTEXT);
1245     len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;
1246     if (playerInfo) {
1247       for (UINT i=0;i<strlen(playerInfo);i++) 
1248         if (playerInfo[i] == '\n') numlines++;
1249       len+=strlen(playerInfo);
1250       first=playerInfo;
1251     }
1252     else {
1253       first="";
1254     }
1255   }
1256   destroyInfo();
1257   info=new VInfo();
1258   UINT height=numlines*30+60;
1259   UINT vheight=Video::getInstance()->getScreenHeight();
1260   UINT vwidth=Video::getInstance()->getScreenWidth();
1261   if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)
1262     height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;
1263   info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);
1264   info->createBuffer();
1265   if (Video::getInstance()->getFormat() == Video::PAL)
1266   {
1267     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1268   }
1269   else
1270   {
1271     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);
1272   }
1273
1274   info->setTitleBarOn(0);
1275   info->setDropThrough();
1276   //from vvideorec 
1277         //set the regions for the closcks and bars on banner
1278   barRegion.x = info->getWidth()-AUDIOBARLEN-20;
1279   barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?
1280   barRegion.w = info->getWidth()-AUDIOBARLEN+10;
1281   barRegion.h = 30;
1282
1283   clocksRegion.x = 130;
1284   clocksRegion.y = barRegion.y + 3;
1285   clocksRegion.w = 190;
1286   clocksRegion.h = surface->getFontHeight();
1287   Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);
1288   BoxStack::getInstance()->add(info);
1289   char *buf=new char [len];
1290   if (playerError || audioError) {
1291     SNPRINTF(buf,len,"%s",first);
1292   }
1293   else {
1294     char tbuf[Media::TIMEBUFLEN];
1295     if (playall) {
1296     SNPRINTF(buf,len,"%s\n"
1297         "%s:%s\n"
1298         "%s: %d/%d\n"
1299         "%s:%s\n"
1300         "%s:%s\n",
1301         first,
1302         tr("FileName"),currentAudio->getDisplayName(),
1303         pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),
1304         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1305         tr("Time"),currentAudio->getTimeString(tbuf));
1306     }
1307     else {
1308     SNPRINTF(buf,len,"%s\n"
1309         "%s:%s\n"
1310         "%s:%s\n"
1311         "%s:%s\n",
1312         first,
1313         tr("FileName"),currentAudio->getDisplayName(),
1314         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),
1315         tr("Time"),currentAudio->getTimeString(tbuf));
1316     }
1317   }
1318   Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);
1319   //now the real drawing functions
1320   info->draw();
1321   //title
1322   info->rectangle(0, 0, info->getWidth(), 30, Colour::TITLEBARBACKGROUND);
1323   info->drawText(title, 5, 5, Colour::LIGHTTEXT);
1324   info->drawPara(buf,5,32,Colour::LIGHTTEXT);
1325   delete [] buf;
1326   if (! audioError) {
1327     WSymbol w;
1328     info->TEMPADD(&w);
1329     int x=10;
1330     int ybottom=info->getHeight();
1331     info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, Colour::TITLEBARBACKGROUND);
1332     bool drawSymbol=true;
1333     switch(getPlayer()->getState()) {
1334       case AudioPlayer::S_PAUSE:
1335         w.nextSymbol = WSymbol::PAUSE;
1336         break;
1337       case AudioPlayer::S_PLAY:
1338         w.nextSymbol = WSymbol::PLAY;
1339         break;
1340       case AudioPlayer::S_DONE:
1341         if (playall) 
1342           w.nextSymbol = WSymbol::PLAY;
1343         else
1344           drawSymbol=false;
1345         break;
1346       case AudioPlayer::S_BACK:
1347         w.nextSymbol = WSymbol::FBWD ;
1348         break;
1349       case AudioPlayer::S_FF:
1350         w.nextSymbol = WSymbol::FFWD ;
1351         break;
1352       default:
1353         drawSymbol=false;
1354         break;
1355     }
1356     if (drawSymbol) {
1357       w.setPosition(x, ybottom-24);
1358       w.draw();
1359     }
1360     else {
1361       //stop symbol
1362       info->rectangle(x, ybottom - 23, 18, 16, Colour::LIGHTTEXT);
1363     }
1364     x+=30;
1365     drawAudioClocks();
1366   }
1367   if (playerInfo) delete playerInfo;
1368   if (playerTitle) delete playerTitle;
1369 }
1370
1371 void VMediaView::drawAudioClocks() {
1372         if (! info || ! audioEnabled) return;
1373         Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");
1374   //draw clocks and bar
1375   info->rectangle(clocksRegion, Colour::TITLEBARBACKGROUND);
1376
1377   time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());
1378   time_t lengthSec=(time_t)(getPlayer()->getSonglen());
1379         struct tm cpos;
1380         struct tm slen;
1381 /*      gmtime_r(&currentSec,&cpos);
1382         gmtime_r(&lengthSec,&slen);*/
1383     cpos.tm_hour=currentSec/3600;
1384     cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;
1385     cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);
1386     slen.tm_hour=lengthSec/3600;;
1387     slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;
1388     slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);
1389
1390   char buffer[100];
1391   if (currentSec >= lengthSec)
1392   {
1393     SNPRINTF(buffer,99, "-:--:-- / -:--:--  %03dk",getPlayer()->getCurrentBitrate()/1000);
1394   }
1395   else
1396   {
1397     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i  %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,
1398                                 getPlayer()->getCurrentBitrate()/1000);
1399                 //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);
1400   }
1401
1402   info->drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT);
1403   
1404         // Draw progress bar
1405   int progBarXbase = 0;
1406         int barlen=250;
1407
1408   info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, Colour::LIGHTTEXT);
1409   info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);
1410
1411   if (currentSec > lengthSec) currentSec=lengthSec;
1412   if (lengthSec == 0) return;
1413
1414   // Draw yellow portion
1415   int progressWidth = (barlen+2) * currentSec / lengthSec;
1416   info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, Colour::SELECTHIGHLIGHT);
1417
1418 }
1419
1420 void VMediaView::showAudioBanner() {
1421   destroyAudioBanner();
1422   if (! audioEnabled) return;
1423   audioBanner=new VInfo();
1424   Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);
1425   Video *v=Video::getInstance();
1426   audioBanner->setSize(v->getScreenWidth()-100, 36);
1427   audioBanner->createBuffer();
1428   audioBanner->setPosition(50, v->getScreenHeight()-50);
1429   audioBanner->fillColour(audioBannerBack);
1430   audioBanner->setTitleBarOn(0);
1431   audioBanner->setDropThrough();
1432   if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {
1433     audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,Colour::LIGHTTEXT);
1434   }
1435   else {
1436     char * buf=new char[strlen(currentAudio->getDisplayName())+50];
1437     SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());
1438     audioBanner->drawText(buf,5,3,Colour::LIGHTTEXT);
1439     delete buf;
1440   }
1441   BoxStack::getInstance()->add(audioBanner);
1442   BoxStack::getInstance()->update(audioBanner);
1443 }
1444
1445 void VMediaView::destroyAudioBanner() {
1446   if (audioBanner) {
1447     Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);
1448     BoxStack::getInstance()->remove(audioBanner);
1449     audioBanner=NULL;
1450   }
1451 }